对象访问成员变量时,会先在子类中查找有没有定义对应的变量,若子类中存在就会就近使用子类中的变量,若子类中没有定义就会沿着继承关系往上找有没有定义相应的变量,若父类中也没有则编译不通过。代码示例:
class Fu { // Fu类中的成员变量。 int num = 5; int num2 = 7; } class Zi extends Fu { // Zi类中的成员变量 int num = 6; public void show() { // 访问父类中的num2 System.out.println("num2=" + num2); // 访问子类中的num System.out.println("num=" + num); } } public class ExtendsDemo0 { public static void main(String[] args) { // 创建子类对象 Zi z = new Zi(); // 调用子类中的show方法 z.show(); } } 演示结果: num2=7 num=6
子父类中出现了同名的成员变量时,在子类中访问父类中非私有成员变量,需要使用 super 关键字,用法类似于 this 。
super
this
使用格式:
super.父类成员变量名
代码如下:
class Zi extends Fu { // Zi类中的成员变量 int num = 6; public void show() { //访问父类中的num System.out.println("Fu num2=" + num2); //访问父类中的num System.out.println("Fu num=" + super.num); } } 演示结果: Fu num = 7 Zi num = 5
Fu 类中的私有成员变量,子类是不能直接访问的。编码时,遵循封装的原则,使用private修饰成员变量,可以在父类中提供公共的getXxx方法和setXxx方法来访问。
在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员。代码体现在子类的构造方法调用时,一定先调用父类的构造方法。理解图解如下:
super :代表父类的 存储空间标识 (可以理解为父类的引用)。
this :代表 当前对象的引用 (谁调用就代表谁)。
this.成员变量 -- 本类的 super.成员变量 -- 父类的
this.成员方法名() -- 本类的 super.成员方法名() -- 父类的
代码示例:
class Animal { public void eat() { System.out.println("animal : eat"); } } class Cat extends Animal { public void eat() { System.out.println("cat : eat"); } public void eatTest() { this.eat(); // this 调用本类的方法 super.eat(); // super 调用父类的方法 } } public class ExtendsDemo08 { public static void main(String[] args) { Animal a = new Animal(); a.eat(); Cat c = new Cat(); c.eatTest(); } } 输出结果为: animal : eat cat : eat animal : eat
注意:
通过super引用属性、方法、构造器时,都要求该成员是可见的,即该成员的修饰符不能是private的,跨包的话还不能是缺省的。
super的追溯不仅限于直接父类
如果某个属性或方法前面使用“this.”,那么先从本类中查找,如果未找到,会沿着继承关系往上找
如果某个属性或方法前面使用“super.”,那么先从直接父类中查找,如果未找到,会沿着继承关系往上找
如果某个属性或方法前面既没有“this.”,也没有“super.”,遵循就近原则,先从本类中查找,如果未找到,会沿着继承关系往上找
如果子、父类中的方法不重名,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有定义对应的方法,若子类中存在就执行子类中定义的方法,若子类中没有定义就会沿着继承关系往上找有没有定义相应的方法,若父类中也没有则编译不通过。代码示例:
class Fu{ public void show(){ System.out.println("Fu类中的show方法执行"); } } class Zi extends Fu{ public void show2(){ System.out.println("Zi类中的show2方法执行"); } } public class ExtendsDemo04{ public static void main(String[] args) { Zi z = new Zi(); //子类中没有定义show方法,但是可以找从父类继承的show方法去执行 z.show(); z.show2(); } }
如果子、父类中出现 重名 的成员方法,这时的访问是一种特殊情况,叫做 方法重写 (Override)。
class Fu { public void show() { System.out.println("Fu show"); } } class Zi extends Fu { //子类重写了父类的show方法 public void show() { System.out.println("Zi show"); } } public class ExtendsDemo05{ public static void main(String[] args) { Zi z = new Zi(); // 子类中有show方法,只执行重写后的show方法 z.show(); // Zi show } }
子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。比如新的手机增加来电显示头像的功能,代码如下:
class Phone { public void sendMessage(){ System.out.println("发短信"); } public void call(){ System.out.println("打电话"); } public void showNum(){ System.out.println("来电显示号码"); } } //智能手机类 class NewPhone extends Phone { //重写父类的来电显示号码功能,并增加自己的显示姓名和图片功能 public void showNum(){ //调用父类已经存在的功能使用super super.showNum(); //增加自己特有显示姓名和图片功能 System.out.println("显示来电姓名"); System.out.println("显示头像"); } } public class ExtendsDemo06 { public static void main(String[] args) { // 创建子类对象 NewPhone np = new NewPhone(); // 调用父类继承而来的方法 np.call(); // 调用子类重写的方法 np.showNum(); } }
重写时,用到super.父类成员方法,表示调用父类的成员方法。
方法名:必须完全一致
形参列表:必须完全一致
返回值类型:
如果是基本数据类型和void,必须一致
如果是引用数据类型,重写的方法的返回值类型 < = 被重写方法的返回值类型,Student<Person
修饰符:重写的方法的修饰符范围 > = 被重写方法的修饰符范围(public > protected > 缺省 > private)
被重写方法不能被 private、static、final 修饰,如果跨包的话,修饰符缺省的也不能被重写,因为缺省的跨包不可见
private
static
final
首先我们要回忆两个事情,构造方法的定义格式和作用:
class Father{ public Father(){ System.out.println("父类的无参构造"); } } class Son extends Father{ private String str; private int num; public Son(){ //隐含调用了super(); 子类的构造器中一定会调用父类的构造器,默认调用父类的无参构造 System.out.println("子类的无参构造"); } public Son(String str){ //隐含调用了super() this.str = str; System.out.println("子类的有参构造1"); } public Son(String str,int num){ //调用重载的构造器,隐含调用了super() this(str); this.num = num; System.out.println("子类的有参构造2"); } } public class ConstructorTest { public static void main(String[] args) { Son s1 = new Son(); /* 父类的无参构造 子类的无参构造 */ //Son s2 = new Son("java"); /* 父类的无参构造 子类的有参构造1 */ Son s3 = new Son("java", 10); /* 父类的无参构造 子类的有参构造1 子类的有参构造2 */ } }
原文链接:https://www.cnblogs.com/sun10367/p/13514776.html