前言
本篇博客主要讲解Java基础语法中的 面向对象系列之 this和super关键字的详解:为什么要使用this、有this和无this的区别、this的深度理解、this为什么是引用、this的用法、用this访问对象的属性、用this调用构造方法、用this调用成员方法、super的用法、面试题:super和this的区别。有关super关键字在继承的文章中也有说明。
大家好,本人是普通一本的在校大学生一枚,目前在学习java。之前也学了一段时间,但是没有发布博客。本人现在已经大二结束了,开学就大三了,时间过的真的很快。我会利用好这个暑假,来复习之前学过的内容,并整理好之前写过的博客进行发布。如果博客中有错误或者没有读懂的地方。热烈欢迎大家在评论区进行讨论!!! 喜欢我文章的兄弟姐妹们可以点赞,收藏和评论我的文章。喜欢我的兄弟姐妹们以及也想复习一遍java知识的兄弟姐妹们可以关注我呦,我会持续更新滴,并且追求完整。 望支持!!!!!!一起加油呀!!!!
语言只是工具,不能决定你好不好找工作,决定你好不好找工作的是你的能力!!!!!
学历本科及以上就够用了!!!!!!!!!!!!!!!!!!!!!!!!!!!!
我们首先通过代码来看看有this和没有this的区别
我们依然用PetDog这个类来解释说明
一、为什么要有this引用
1. 用代码看有this与无this的区别
构造方法中
在参数名与成员变量名不相同的情况下。我们是可以成功赋值的。
但是在参数名与成员变量名相同的情况下。我们并不能成功赋值 由于局部变量优先原则,此时的赋值时参数传给参数。而不会对成员变量进行赋值。我们需要用到this引用才能成功赋值,完成初始化。
1.1 代码示例
代码语言:javascript复制class PetDog {
//成员变量
public String name;//名字
public String color;//颜色
public int age; //年龄
// 狗的属性
//构造方法
public PetDog(String name, String color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
//成员方法
// 狗的行为
public void barks() {
System.out.println(name ": 旺旺旺~~~");
}
public void wag() {
System.out.println(name ": 摇尾巴~~~");
}
}
public class Test {
public static void main(String[] args) {
//在主函数中,我们进行实例化这个类。并对实例化出的类进行使用。
PetDog dog1 = new PetDog("阿黄","黄色",15);
System.out.println("姓名:" dog1.name);
System.out.println("颜色:" dog1.color);
System.out.println("年龄:" dog1.age);
dog1.barks();
dog1.wag();
}
}
1.2 输出结果:
姓名:阿黄 颜色:黄色 年龄:15 阿黄: 旺旺旺~~~ 阿黄: 摇尾巴~~~
1.3 代码示例:
代码语言:javascript复制class PetDog {
//成员变量
public String name;//名字
public String color;//颜色
public int age; //年龄
// 狗的属性
//构造方法
public PetDog(String name, String color, int age) {
name = name;
color = color;
age = age;
}
//成员方法
// 狗的行为
public void barks() {
System.out.println(name ": 旺旺旺~~~");
}
public void wag() {
System.out.println(name ": 摇尾巴~~~");
}
}
public class Test {
public static void main(String[] args) {
//在主函数中,我们进行实例化这个类。并对实例化出的类进行使用。
PetDog dog1 = new PetDog("阿黄","黄色",15);
System.out.println("姓名:" dog1.name);
System.out.println("颜色:" dog1.color);
System.out.println("年龄:" dog1.age);
dog1.barks();
dog1.wag();
}
}
1.4 输出结果:
姓名:null 颜色:null 年龄:0 null: 旺旺旺~~~ null: 摇尾巴~~~
我们发现在没有使用this的情况下,并没有给成员属性赋值成功,这是因为就近原则。局部变量会优先给自己赋值。也就是参数创建的局部变量自己给自己赋值,并没有影响到成员属性当中的变量。
而通过this引用,编译器会明白这个变量是成员属性的变量。而不是传入参数时创建的变量。因此this代表当前对象的引用。建议大家习惯使用this,这样就能更好的区分这个变量是谁的。
若有多个对象,那么哪个对象调用了这个方法,那么这个this就是哪个对象的引用。
2. this深度理解
再往深了说,其实在构造方法中隐藏了PetDog this这个参数,而谁调用了这个方法,那么这个this就指的是谁。如上面: PetDog dog1 = new PetDog("阿黄","黄色",15);我们虽然只传了三个参数进去实际上我们传入的是
PetDog dog1 = new PetDog(
dog1,"阿黄","黄色",15);
而接收这个参数的方法实际上也是这样的
public PetDog(
PetDog this,String name, String color, int age) { this.name = name; this.color = color; this.age = age; }
其中用删除线划的部分来代表编译器隐藏的部分。这是我们看不到但是实际存在的。因此用了this我们的编译也可以顺利通过。
注意:静态的成员变量不支持
我们建议所有的地方都加上this
3. 什么是this引用
3.1 this引用的概念
this引用指向当前对象:( 成员方法运行时调用该成员方法的对象 ) 例如:PetDog dog1 = new PetDog("阿黄","黄色",15);。那么在这个构造方法中,this就同dog1一样指向PetDog这个对象。除了构造方法,成员方法也是可以这样用的。
在成员方法中所有成员变量的操作,都是通过该this 引用去访问 。
用户不需要来传递,编译器自动完成。
注意:this引用的是调用成员方法的对象。
4. this引用的特性
1. this 的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型 2. this 只能在 " 成员方法 " 中使用(构造方法相当于成员方法中的一种) 3. 在 " 成员方法 " 中, this 只能引用当前对象,不能再引用其他对象 4. this 是 “ 成员方法 ” 第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法 对象的引用传递给该成员方法,this 负责来接收
二、this的用法(在没有继承关系时)
2.1 this.访问当前对象的属性
我们在上述讲到的有无this的区别就是在用this.去访问当前对小区的属性,要记得是只能在构造方法和成员方法中才能使用,因为别的地方没有隐藏的这个参数。并且我们最好习惯性使用this这样更方便我们去理解代码。
2.2 用this()调用其他构造方法
代码示例:
代码语言:javascript复制class PetDog {
//成员变量
public String name;//名字
public String color;//颜色
public int age; //年龄
// 狗的属性
//构造方法,//我们在这里创建了多个构造方法,方便后面的使用。
public PetDog(){
this("阿花","花色",25);//用this()直接调用其他构造方法传参,
//传入什么参数类型就与哪个构造方法相匹配。
System.out.println("构造方法1");
}//因此是调用了构造方法2而不是构造方法3.
public PetDog(String name, String color, int age) {
this.name = name;
this.color = color;
this.age = age;
System.out.println("构造方法2");
}
public PetDog(String name, String color) {
this.name = name;
this.color = color;
System.out.println("构造方法3");
}
//成员方法
// 狗的行为
public void barks() {
System.out.println(this.name ": 旺旺旺~~~");
}
public void wag() {
System.out.println(this.name ": 摇尾巴~~~");
}
}
public class Test {
//在主函数中,我们进行实例化这个类。并对实例化出的类进行使用。
public static void main(String[] args) {
PetDog dog1 = new PetDog();
System.out.println("姓名:" dog1.name);
System.out.println("颜色:" dog1.color);
System.out.println("年龄:" dog1.age);
dog1.barks();
dog1.wag();
}
}
输出结果:
构造方法2 构造方法1 姓名:阿花 颜色:花色 年龄:25 阿花: 旺旺旺~~~ 阿花: 摇尾巴~~~
由此我们看出,程序从 new PetDog();这里直接进入构造方法1这个无参的构造方法,再执行this();由参数匹配到了构造方法2这个方法并传入了参数,初始化了对象。执行完构造方法2再回来,打印出构造方法1。再输出姓名.....颜色....年龄...和调用的成员方法。
值得注意的是:
可见this();需要放在当前类的构造方法中的第一行才可以,不然会编译报错不能通过。
总结:
1.this(); 是只能在当前类构造方法中使用,去调用当前类的其他构造方法。不能在普通的成员方法中使用。 2.只能放在第一行。如果不放在第一行,就不能通过编译。
2.3 用this.在成员方法中调用其他成员方法
代码示例:
代码语言:javascript复制class PetDog {
//成员变量
public String name;//名字
public String color;//颜色
public int age; //年龄
// 狗的属性
//构造方法,//我们在这里创建了多个构造方法,方便后面的使用。
public PetDog(){
this("阿花","花色",25);
System.out.println("构造方法1");
this.wag();//在构造方法中用this.来调用成员方法
}
public PetDog(String name, String color, int age) {
this.name = name;
this.color = color;
this.age = age;
System.out.println("构造方法2");
}
//成员方法
// 狗的行为
public void barks() {
System.out.println(this.name ": 旺旺旺~~~");
}
public void wag() {
this.barks();//在成员方法中用this.来调用成员方法
System.out.println(this.name ": 摇尾巴~~~");
}
}
public class Test {
//在主函数中,我们进行实例化这个类。并对实例化出的类进行使用。
public static void main(String[] args) {
PetDog dog1 = new PetDog();
System.out.println("姓名:" dog1.name);
System.out.println("颜色:" dog1.color);
System.out.println("年龄:" dog1.age);
dog1.wag();
}
}
输出结果:
构造方法2 构造方法1 阿花: 旺旺旺~~~ 阿花: 旺旺旺~~~ 阿花: 摇尾巴~~~ 姓名:阿花 颜色:花色 年龄:25 阿花: 旺旺旺~~~ 阿花: 摇尾巴~~~
我们看到this.既可以在构造方法中去调用其他成员方法,也可以在成员方法中去调用其他成员方法。而且可以写在方法中的任意一行。
三、this和super的用法(继承关系的情况下)
注:在 《JavaSE》---12.<面向对象系列之(继承)>
的文章中讲了this和super用作调用构造方法。
this(...)用于调用本类构造方法, super(...)用于调用父类构造方法, 两种调用不能同时在构造方法中出现
大家要知道: 有父类才会用到super关键字!!!
3.1 当父类成员变量、方法与子类成员变量、方法不同时
实例化对象后,用对象的引用.点号 变量名 或 方法 引用到哪个成员变量或者成员方法,那么访问的就是哪个成员变量或成员方法。
3.2 当父类成员变量、方法与子类成员变量、方法相同时
如果单纯用对象的引用. 成员变量 或 成员方法那么只能访问到子类自己的哪个变量或方法。如果想访问到从父类继承下来的成员变量或成员方法,那么我们需要用关键字super点号 成员变量 或 成员方法来引用。这样我们就可以访问到从父类继承下来的那个与子类成员变量或成员方法了
口说无凭:
3.1、3.2代码示例:
代码语言:javascript复制class Animal{//这是我们创建的父类Animal
//父类成员变量
public String name = "父类name";
public int age = 99;
//父类成员方法
public void eat(){
System.out.println(this.name "父类正在吃饭");
}
public void sleep(){
System.out.println(this.name "父类正在睡觉");
}
}
class Dog extends Animal{//这是我们创建的子类狗类。让它去继承Animal
public String name = "子类name";
public int height = 30;
public void show(){
System.out.println(name); //1.
System.out.println(this.name); //2.
System.out.println(super.name); //3.
System.out.println("父类成员变量age:" age); //4.
System.out.println("父类成员变量age:" this.age); //5.
System.out.println("子类成员变量height:" height); //6.
System.out.println("子类成员变量height:" this.height); //7.
eat(); //8.
this.eat(); //9.
super.eat(); //10.
sleep(); //11.
this.sleep(); //12.
super.sleep(); //13.
wangWang(); //14.
this.wangWang(); //15.
}
public void eat(){
System.out.println(this.name "子类正在吃饭");
}
void wangWang(){
System.out.println(this.name "子类喜欢汪汪叫!");
}
}
public class GJiCheng {
public static void main(String[] args) {
//用Dog类实例化一个对象
System.out.println("--------------------------------");
Dog dog1 = new Dog();
dog1.show();
System.out.println("--------------------------------");
}
}
输出结果:
-------------------------------- 1.子类name 2.子类name 3.父类name 4.父类成员变量age:99 5.父类成员变量age:99 6.子类成员变量height:30 7.子类成员变量height:30 8.子类name子类正在吃饭 9.子类name子类正在吃饭 10.父类name父类正在吃饭 11.父类name父类正在睡觉 12.父类name父类正在睡觉 13.父类name父类正在睡觉 14.子类name子类喜欢汪汪叫! 15.子类name子类喜欢汪汪叫! --------------------------------
让我们再详细对比并分析一下打印输出的结果:
1. System.out.println(name); 输出:子类name 2. System.out.println(this.name); 输出:子类name 3. System.out.println(super.name); 输出:父类name 分析: ①②这个成员变量,父类有一个,子类也有一个。有两个name,一个是从父类继承的,一个是自己的。结果打印出了自己的。是因此我们可以知道,如果父类和子类成员变量相同时,会优先在子类中找变量。子类有就先输出子类自己的成员变量。如果子类没有这样成员变量才会输出父类的成员变量。因此1.和2.打印出来的是子类当中的name ③由super引用的成员变量只会在继承父类的成员变量中找。因此会访问从父类继承过来的那个成员变量,因此③打印出来的是父类name
4. System.out.println("父类类成员变量height:" age); 输出:父类成员变量age:99 5. System.out.println("父类成员变量height:" this.age); 输出:父类成员变量age:99 分析:由于子类中只有一个从父类继承来的成员变量age,因此会输出父类成员变量age:99,合情合理
6. System.out.println("子类成员变量height:" height); 输出:子类成员变量height:30 7. System.out.println("子类成员变量height:" this.height); 输出:子类成员变量height:30 分析:这是子类自己的成员变量,输出这个结果合情合理
8. eat(); 输出:子类name子类正在吃饭 9. this.eat(); 输出:子类name子类正在吃饭 10. super.eat(); 输出:父类name父类正在吃饭 分析:这个成员方法,父类有一个,子类也有一个。
11. sleep(); 输出:父类name父类正在睡觉 12. this.sleep(); 输出:父类name父类正在睡觉 13. super.sleep(); 输出:父类name父类正在睡觉 分析:这是从父类继承来的成员方法。这样输出合情合理。既可以用this,也可以用super,也可以什么都不加。
14. wangWang(); 输出:子类name子类喜欢汪汪叫! 15. this.wangWang(); 输出:子类name子类喜欢汪汪叫! 分析:这是子类自己的成员方法,这样输出合情合理, 注意:这个就不能用super关键字引用了
小结:
1.this访问的时候,既可以访问从父类继承下来的,也可以访问子类自己的
2.super只能访问从父类继承过来的。
3.当父类和子类有相同的成员变量或成员方法时,可以用super去访问从父类继承过来的,不用super则访问的是子类自己的那个成员变量或成员方法。
4.super只是一个关键字。提高代码的可读性,让别人轻松知道这是访问父类中的
注意: 当父类与子类有相同的方法名但是参数不同的情况下,我们传入什么参数匹配到那个方法,那么就会访问到哪个方法.(方法的重载)
方法的重写
5.当父类与子类都有一个方法名相同,参数列相同,返回值相同的方法时,这其实就构成了方法的重写.在此情况下,如果不用super,那么最终访问到的方法就是子类的方法.与父类的方法无关.
6.super在当前类中使用那么super一定是子类.
注意:super只能在非静态方法中使用,不能在static方法中使用,因为super,this是一样的,是依赖于对象的,而static不依赖于对象,而是类被加载时就被创建出来了.
四、面试题:总结super和this的区别
他们之间有什么区别呢?
【 相同点 】
1. 都是 Java 中的关键字
2. 都可以在成员方法中用来访问:成员变量和调用其他的成员方法
3. 都可以作为构造方法的第一条语句
4. 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
5. 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在
【 不同点 】
1. this 是当前对象的引用,当前对象即调用实例方法的对象, super 相当于是子类对象中从父类继承下来部分成员的引用
2. 在非静态成员方法中, this 用来访问本类的方法和属性, super 用来访问父类继承下来的方法和属性
3. 在构造方法中: this(...) 用于调用本类构造方法, super(...) 用于调用父类构造方法,两种调用不能同时在构造方法中出现
4. 在父类有有带参构造方法时。一定会存在 super(...) 的调用,用户没有写编译器也会增加,但是 this(...) 用户不写则没有。