一、this
什么是 this?
this 是 java 中的一个关键字,它代表当前对象的引用
简单来说
this 就是汉字中的 “ 我 ”
我们先来看看它有哪些用法:
1、this 五种基本用法
1> 区分成员变量和局部变量
这是 this 最常见的用法
当 成员变量 和 局部变量 同名时
用 this 明确指定访问的是成员变量
public class Student {
private String name; // 成员变量
public void setName(String name) { // 参数name是局部变量
this.name = name; // this.name指成员变量,name指参数
}
}
就好比你有一只小狗
当你说“小狗”的时候,可能指的是你的小狗,也可能指别的小狗
这时如果你说的是“我的小狗”,那这就显而易见了
2> 调用当前类的构造方法
this() 可以在构造方法中调用同一个类的其他构造方法
public class Dog {
private String breed;
private int age;
public Dog() {
this("未知品种", 0); // 调用另一个构造方法
}
public Dog(String breed, int age) {
this.breed = breed;
this.age = age;
}
}
点餐时,你可以说“我要和隔壁桌一样的套餐”,而不需要重复说一遍套餐内容。
3> 返回当前对象
在方法中返回 this 可以返回当前对象的引用,常用于方法链式调用
public class Book {
private String title;
private String author;
public Book setTitle(String title) {
this.title = title;
return this; // 返回当前对象
}
public Book setAuthor(String author) {
this.author = author;
return this; // 返回当前对象
}
}
// 使用方式
Book book = new Book().setTitle("Java编程").setAuthor("张三");
就像你在填写一张表格时,填完一项后把表格递回给你,让你继续填写下一项。
4> 作为参数传递
可以将当前对象作为参数传递给其他方法
public class Person {
private String name;
public void introduce() {
printInfo(this); // 把当前对象传递给方法
}
private void printInfo(Person p) {
System.out.println("我叫" + p.name);
}
}
类似于你拿着自己的身份证去办理业务,把“自己”的信息交给工作人员
5> this 调用方法的三种场景
①调用本类普通方法
在类内部方法相互调用时使用
class Calculator {
void add(int a, int b) {
System.out.println(a + b);
}
void calculate() {
this.add(5, 3); // 显式调用本类方法
}
}
②实现方法链式调用
即刚才提到的“返回当前对象”
③区分父子类方法
当子类重写父类方法时,可用 this 明确调用本类实现
2、内存图解
public static void main(String[] args){
Student stu1 = new Student("jack",21);
stu1.sayHello();
Student stu2 = new Student("Tom".18);
stu2.sayHello();
}
显而易见,this 指向的是堆内存中的 对象 本身。
3、构造方法中 this 的正确使用
在 java 中,构造方法中正确使用 this 关键字主要涉及两种场景:
调用同类其他构造方法
区分成员变量与参数(前面提到过,这里就不讨论了)
——调用同类其他构造方法
使用 this 可以在一个构造方法中调用同类中的另一个构造方法,这种调用必须放在构造方法的第一行
public class Person {
private String name;
private int age;
// 无参构造方法
public Person() {
this("无名氏", 0); // 调用有参构造方法
}
// 单参构造方法
public Person(String name) {
this(name, 0); // 调用有参构造方法
}
// 全参构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
二、super
什么是 super 呢?
super 也是 java 的关键字,代表当前对象的直接父类部分
1、super 的三种核心用法
①访问父类成员变量
当子类和父类有同名成员变量时,使用 super.变量名 可以明确指定访问父类的变量
class Parent {
String name = "父类名称";
}
class Child extends Parent {
String name = "子类名称";
void printNames() {
System.out.println(super.name); // 输出"父类名称"
System.out.println(this.name); // 输出"子类名称"
}
}
②调用父类方法
当子类重写父类方法后,仍可通过 super.方法名() 调用父类的原始实现
class Phone {
void call() {
System.out.println("基础通话功能");
}
}
class SmartPhone extends Phone {
@Override
void call() {
super.call(); // 先执行父类通话功能
System.out.println("新增视频通话功能");
}
}
③调用父类构造方法
在子类构造方法中使用 super() 或 super(参数) 调用父类构造方法
class Vehicle {
String type;
Vehicle(String type) {
this.type = type;
}
}
class Car extends Vehicle {
int wheels;
Car(String type, int wheels) {
super(type); // 必须放在第一行
this.wheels = wheels;
}
}
2、super 的正确使用
①构造方法调用必须在第一行
super() 调用必须是子类构造方法的第一条语句
②隐式调用规则
如果子类构造方法没有显示调用 super()
编译器会自动插入父类无参构造方法的调用
public class Parent{
public Parent(){
System.out.println("父类无参构造器");
}
}
public class Child extends Parent{
public Child(){
//这里隐式提供了super();
System.out.println("子类无参构造器")
}
}
public class Test{
Child c = new Child();
}
结果为:
父类无参构造器
子类无参构造器
③继承链要求
最终必须调用到 Object类 的构造方法(所有类的顶级父类)
这个等下我们和 this 一起使用的时候解释
④静态上下文禁用
不能在 static 方法中使用 super
为什么呢?
看到下面的内存图大家就理解了
3、内存图解
public class Person{
private String name;
private int age;
public Person(){}
}
public class Student extends Person{
private int id;
public Student(){}
}
public class Test{
Student s = new Student();
}
super 不是独立的对象,它和 this 指向同一个对象的不同部分
上一期我们提到了,static 不依赖对象,所以没有this
而现在 super 指向的是 this 指向的一部分,连 this 没有,哪来的 super 呢?
所以 static 中也不能使用 super
三、this 和 super 的构造方法调用规则
1、基本调用规则
①必须作为构造方法的第一条语句
②二者不能同时存在
基于第一条规则,如果二者同时出现
就会左右脑互搏
谁都想占据第一行的位置
③隐式 super() 调用
如果子类构造方法没有显式调用 this() 或 super() ,编译器会自动插入父类无参构造方法的 super() 调用
2、详细执行机制
当构造方法中使用 this() 调用本类其他构造方法时,编译器就不会再隐式调用 super() 了
但是,这条调用链调用到最后时,都是由 super() 结尾,显示隐式都可以
public class Fu {
private int f;
public Fu(){
//隐式调用了 super();
System.out.println("父类的无参构造器");
}
}
public class Zi extends Fu{
private int z;
public Zi(){
System.out.println("子类的无参构造器");
}
public Zi(int z){
this();
this.z = z;
System.out.println("子类的单参构造器");
}
public Zi(int f,int z){
this(z);
this.z = z;
setF(f);
System.out.println("子类的全参构造器");
}
}
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
Zi z1 = new Zi(1);
Zi z2 = new Zi(3,1);
}
}
结果为:
父类的无参构造器
子类的无参构造器
父类的无参构造器
子类的无参构造器
子类的单参构造器
父类的无参构造器
子类的无参构造器
子类的单参构造器
子类的全参构造器
四、易踩坑的点
1、当父类没有无参构造时,必须显示调用 super() 指向父类的有参构造,或者给父类写上无参构造
// 必须确保父类有相应的构造方法
class Parent {
Parent(String s) { } // 没有无参构造方法
}
class Child extends Parent {
Child() {
// super(); // 编译错误:父类没有无参构造方法
super("default"); // 必须显式调用
}
}
2、链式调用忘记返回 this
要实现方法链式调用,每个方法必须都返回 this
不要忘记写 return this;
否则对象不能正常返回
3、多层继承中的 super 调用限制
super 只能访问 直接父类,不能跨级访问爷爷类
4、关于 static
再次强调,static 方法中不能使用 this 和 super
5、方法重写时忽略 super 调用
重写方法时,若需要保留父类功能,必须调用 super.方法名();
否则会完全覆盖父类方法,导致功能缺失
6、思维误区
this 和 super 是同一个对象的不同视图,不是两个独立的对象
this 指向当前对象整体,super 指向当前对象的父类部分
7、链式调用的返回值类型
不能是void!
一般情况有三种:
①返回类本身:
public class Student {
private String name;
private int age;
public Student setName(String name) {
this.name = name;
return this; // 返回当前对象
}
public Student setAge(int age) {
this.age = age;
return this; // 返回当前对象
}
}
// 使用
Student student = new Student()
.setName("张三")
.setAge(18);
②返回父类类型
class Animal {
public Animal eat() {
System.out.println("动物在吃东西");
return this;
}
}
class Dog extends Animal {
public Dog bark() {
System.out.println("狗在叫");
return this;
}
@Override
public Animal eat() {
super.eat();
return this; // 可以返回this(Dog类型),但声明为Animal类型
}
}
// 使用
Dog dog = new Dog();
Animal animal = dog.eat().eat(); // 返回的是Dog对象,但类型是Animal
③返回接口类型
interface Builder {
Builder addElement(String element);
}
class XMLBuilder implements Builder {
private StringBuilder xml = new StringBuilder();
@Override
public Builder addElement(String element) {
xml.append("<").append(element).append(">");
return this;
}
public XMLBuilder setAttribute(String attr) {
xml.append(" ").append(attr);
return this;
}
}
其他特殊情况遇到了再特殊讨论
今天的分享就到这里,欢迎大家补充 斧正