目录
一、关键词:this
1.定义
2.作用
(1)实例方法或构造器中使用当前对象的成员
(2)同一个类中构造器互相调用
二、方法的重写
1.定义
2.要求
3.代码
4.区分重载和重写
三、关键字:super
1.定义
2.子类中调用父类被重写的方法
3.子类中调用父类中同名的成员变量
4.子类构造器中调用父类构造器
5.区分:this与super
1.this和super的意义
2.this和super的使用格式
总结
一、关键词:this
1.定义
- 在Java中,this关键字不算难理解,它的作用和其词义很接近。
- 它在方法(准确的说是实例方法或非static的方法)内部使用,表示调用该方法的对象
- 它在构造器内部使用,表示该构造器正在初始化的对象。
- this可以调用的结构:成员变量、方法和构造器
2.作用
(1)实例方法或构造器中使用当前对象的成员
- 在实例方法或构造器中,如果使用当前类的成员变量或成员方法可以在其前面添加this,增强程序的可读性。不过,通常我们都习惯省略this。
- 但是,当形参与成员变量同名时,如果在方法内或构造器内需要使用成员变量,必须添加this来表明该变量是类的成员变量。即:我们可以用this来区分成员变量和局部变量。
class Person{ // 定义Person类private String name ; private int age ; public Person(String name,int age){ this.name = name ; this.age = age ; }public void setName(String name){this.name = name;}public void setAge(int age){this.age/*成员变量*/ = age/*局部变量*/;}public void getInfo(){ System.out.println("姓名:" + name) ;this.speak();}public void speak(){System.out.println(“年龄:” + this.age); }
}
(2)同一个类中构造器互相调用
this可以作为一个类中构造器相互调用的特殊格式。
- this():调用本类的无参构造器
- this(实参列表):调用本类的有参构造器
public class Person {private String name;private int age;// 无参构造器public Person() {// 调用带有两个参数的构造器,传递默认值 "Unknown" 和 0this("Unknown", 0);}// 一个参数的构造器public Person(String name) {// 调用带有两个参数的构造器,传递给定的 name 和默认值 0this(name, 0);}// 两个参数的构造器public Person(String name, int age) {// 初始化成员变量this.name = name;this.age = age;}// 获取姓名的方法public String getName() {return name;}// 获取年龄的方法public int getAge() {return age;}public static void main(String[] args) {// 使用不同的构造器创建对象Person person1 = new Person();Person person2 = new Person("Alice");Person person3 = new Person("Bob", 30);// 打印信息System.out.println("Person1: 姓名 - " + person1.getName() + ", 年龄 - " + person1.getAge());System.out.println("Person2: 姓名 - " + person2.getName() + ", 年龄 - " + person2.getAge());System.out.println("Person3: 姓名 - " + person3.getName() + ", 年龄 - " + person3.getAge());}
}
-
不能出现递归调用。比如,调用自身构造器。
推论:如果一个类中声明了n个构造器,则最多有 n - 1个构造器中使用了"this(形参列表)" -
this()和this(实参列表)只能声明在构造器首行。
推论:在类的一个构造器中,最多只能声明一个"this(参数列表)"
(3)补充:递归方法
①递归方法调用:方法自己调用自己的现象就称为递归。递归的分类:直接递归、间接递归。
②直接递归:方法自身调用自己。
public void eat(){eat();
}
③间接递归:可以理解为A()方法调用B()方法,B()方法调用C()方法,C()方法调用A()方法。
public static void A(){B();
}public static void B(){C();
}public static void C(){A();
}
④说明
- 递归方法包含了一种 隐式的循环 。
- 递归方法会 重复执行 某段代码,但这种重复执行无须循环控制。
- 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,停不下来,类似于死循环。最终发生栈内存溢出 。
二、方法的重写
1.定义
父类的所有方法子类都会继承,但是当某个方法被继承到子类之后,子类觉得父类原来的实现不适合于自己当前的类,该怎么办呢?子类可以对从父类中继承来的方法进行改造,我们称为方法的重写也称为方法的重置、覆盖。
在程序执行时,子类的方法将覆盖父类的方法。
2.要求
(1)子类重写的方法必须和父类被重写的方法具有相同的方法名称、参数列表。
(2)子类重写的方法的返回值类型不能大于父类被重写的方法的返回值类型。(例如:Dog< Animal)。
注意:如果返回值类型是基本数据类型和void,那么必须是相同
(3)子类重写的方法使用的访问权限不能小于
父类被重写的方法的访问权限。(public > protected > 缺省 > private)
注意:① 父类私有方法不能重写 ② 跨包的父类缺省的方法也不能重写
(4)子类方法抛出的异常不能大于父类被重写方法的异常。
(5)此外,子类与父类中同名同参数的方法必须同时声明为非static的(即为重写),或者同时声明为static的(不是重写)。因为static方法是属于类的,子类无法覆盖父类的方法。
3.代码
class Animal {// 父类中的方法public void makeSound() {System.out.println("动物发出声音");}
}class Dog extends Animal {// 子类重写父类中的方法@Overridepublic void makeSound() {System.out.println("狗叫:汪汪");}
}public class Main {public static void main(String[] args) {Animal myAnimal = new Animal(); // 创建一个 Animal 对象Animal myDog = new Dog(); // 创建一个 Dog 对象,但是引用类型是 AnimalmyAnimal.makeSound(); // 调用父类的方法myDog.makeSound(); // 调用子类重写的方法}
}
4.区分重载和重写
方法的重载:方法名相同,形参列表不同。不看返回值类型。
方法的重写:对父类方法进行重置和覆盖。
三、关键字:super
1.定义
在Java类中使用super来调用父类中的指定操作:
- super可用于访问父类中定义的属性
- super可用于调用父类中定义的成员方法
- super可用于在子类构造器中调用父类的构造器
注意:
- 尤其当子父类出现同名成员时,可以用super表明调用的是父类中的成员
- super的追溯不仅限于直接父类
- super和this的用法相像,this代表本类对象的引用,super代表父类的内存空间的标识
2.子类中调用父类被重写的方法
- 如果子类没有重写父类的方法,只要权限修饰符允许,在子类中完全可以直接调用父类的方法。
- 如果子类重写了父类的方法,在子类中需要通过
super.
才能调用父类被重写的方法,否则默认调用的子类重写的方法。
public class Animal {public void makeSound() {System.out.println("动物发出声音");}public void move() {System.out.println("动物移动");}
}// 定义Dog类,继承自Animal类
public class Dog extends Animal {// 重写父类的makeSound方法@Overridepublic void makeSound() {// 新增功能:狗发出吠叫声System.out.println("狗吠叫");// 保留父类发出声音的功能super.makeSound(); // 此处必须加super.,否则就是无限递归,导致栈内存溢出}// 主方法测试public static void main(String[] args) {// 创建Dog实例Dog dog = new Dog();// 调用Dog的makeSound方法dog.makeSound();// 输出:// 狗吠叫// 动物发出声音}
}
总结:
-
方法前面没有super.和this.
-
先从子类找匹配方法,如果没有,再从直接父类找,再没有,继续往上追溯
-
-
方法前面有this.
-
先从子类找匹配方法,如果没有,再从直接父类找,再没有,继续往上追溯
-
-
方法前面有super.
-
从当前子类的直接父类找,如果没有,继续往上追溯
-
3.子类中调用父类中同名的成员变量
- 如果实例变量与局部变量重名,可以在实例变量前面加this.进行区别
- 如果子类实例变量和父类实例变量重名,并且父类的该实例变量在子类仍然可见,在子类中要访问父类声明的实例变量需要在父类实例变量前加super.,否则默认访问的是子类自己声明的实例变量
- 如果父子类实例变量没有重名,只要权限修饰符允许,在子类中完全可以直接访问父类中声明的实例变量,也可以用this.实例访问,也可以用super.实例变量访问
class Animal {int age = 5;int weight = 15;
}class Dog extends Animal {int age = 3;public void showAttributes() {// 子类与父类的属性同名,子类对象中就有两个ageSystem.out.println("子类的age:" + age); // 3 先从本类成员变量找System.out.println("子类的age:" + this.age); // 3 先从本类成员变量找System.out.println("父类的age:" + super.age); // 5 直接从父类成员变量找// 子类与父类的属性不同名,是同一个weightSystem.out.println("weight = " + weight); // 15 先找本类成员变量,没有再从父类找System.out.println("weight = " + this.weight); // 15 先找本类成员变量,没有再从父类找System.out.println("weight = " + super.weight); // 15 直接从父类成员变量找}public void displayAttributes(int age, int weight) {// 子类与父类的属性同名,子类对象中就有两个成员变量age,此时方法中还有一个局部变量ageSystem.out.println("局部变量的age:" + age); // 10 先找局部变量System.out.println("子类的age:" + this.age); // 3 先从本类成员变量找System.out.println("父类的age:" + super.age); // 5 直接从父类成员变量找System.out.println("局部变量的weight = " + weight); // 20 先找局部变量System.out.println("子类的weight = " + this.weight); // 15 先从本类成员变量找System.out.println("父类的weight = " + super.weight); // 15 直接从父类成员变量找}
}class TestAttributes {public static void main(String[] args) {Dog dog = new Dog();dog.showAttributes();dog.displayAttributes(10, 20);}
}
总结:起点不同(就近原则)
-
变量前面没有super.和this.
-
在构造器、代码块、方法中如果出现使用某个变量,先查看是否是当前块声明的
局部变量
-
如果不是局部变量,先从当前执行代码的
本类去找成员变量
-
如果从当前执行代码的本类中没有找到,会往上找
父类声明的成员变量
(权限修饰符允许在子类中访问的)
-
-
变量前面有this.
-
通过this找成员变量时,先从当前执行代码的本类去找成员变量
-
如果从当前执行代码的本类中没有找到,会往上找==父类声明的成员变量(权限修饰符允许在子类中访问的)
-
-
变量前面super.
-
通过super找成员变量,直接从当前执行代码的直接父类去找成员变量(权限修饰符允许在子类中访问的)
-
如果直接父类没有,就去父类的父类中找(权限修饰符允许在子类中访问的)
-
4.子类构造器中调用父类构造器
① 子类继承父类时,不会继承父类的构造器。只能通过“super(形参列表)”的方式调用父类指定的构造器。
② 规定:“super(形参列表)”,必须声明在构造器的首行。
③ 我们前面讲过,在构造器的首行可以使用"this(形参列表)",调用本类中重载的构造器, 结合②,结论:在构造器的首行,"this(形参列表)" 和 "super(形参列表)"只能二选一。
④ 如果在子类构造器的首行既没有显示调用"this(形参列表)",也没有显式调用"super(形参列表)", 则子类此构造器默认调用"super()",即调用父类中空参的构造器。
⑤ 由③和④得到结论:子类的任何一个构造器中,要么会调用本类中重载的构造器,要么会调用父类的构造器。 只能是这两种情况之一。
⑥ 由⑤得到:一个类中声明有n个构造器,最多有n-1个构造器中使用了"this(形参列表)",则剩下的那个一定使用"super(形参列表)"。
⑦如果子类构造器中既未显式调用父类或本类的构造器,且父类中又没有空参的构造器,则编译出错
。
5.区分:this与super
1.this和super的意义
this:当前对象
-
在构造器和非静态代码块中,表示正在new的对象
-
在实例方法中,表示调用当前方法的对象
super:引用父类声明的成员
2.this和super的使用格式
-
this
-
this.成员变量:表示当前对象的某个成员变量,而不是局部变量
-
this.成员方法:表示当前对象的某个成员方法,完全可以省略this.
-
this()或this(实参列表):调用另一个构造器协助当前对象的实例化,只能在构造器首行,只会找本类的构造器,找不到就报错
-
-
super
-
super.成员变量:表示当前对象的某个成员变量,该成员变量在父类中声明的
-
super.成员方法:表示当前对象的某个成员方法,该成员方法在父类中声明的
-
super()或super(实参列表):调用父类的构造器协助当前对象的实例化,只能在构造器首行,只会找直接父类的对应构造器,找不到就报错
-
总结
本篇对Java面向对象编程的this、super以及方法的重写进行了梳理总结,便于理解与复习。部分内容源自网路,如有侵权,请联系作者删除,谢谢!