说明
继承的二个关键点:
- 子类继承了其父类中所有非私有的成员变量和成员方法,并作为自己的成员变量和方法
- 子类中定义的成员变量和父类中定义的成员变量相同时,则父类中的成员变量会被【隐藏】
子父类成员同名情况
- 对于成员变量:父类的成员变量在子类中是存在的,即使是私有的或者和子类中定义的成员变量同名;但是子类中能看到的只有子类中定义的变量和从父类继承的非私有的变量,并且如果子类中定义的变量和从父类中继承过来的变量重名,则会隐藏从父类继承的成员变量。
- 对于成员方法:同名的非静态方法则是我们常说的实实在在的覆盖,覆盖后子类中仅有此一个方法(而隐藏实际上两个都是存在的,只是看不到也不能用而已),也即我们看到的那个重写的方法。
例如 Fu f= new Zi();
- 那么调用方法时,是根据对象的实际类型调用的,实际类型是 Zi,所以永远调用子类的方法,这就是所谓的多态。
- 而访问成员变量就不同了,它是 Zi 时,访问的是子类的成员变量,向上转型为 Fu 后,访问的就是父类的成员变量。
- 实际上,多态仅仅是针对【非静态的成员方法】的,成员变量和静态的成员方法在子父类中都不应该出现同名的情况!
继承示例
class Fu { int num = 1; //这是父类的 public int getNum() { return num; //num其实为this.num; } } class Zi extends Fu { int num = 2; //这是子类自己定义的 } public class Test { public static void main(String[] args) { System.out.println(new Zi().num + " ");//2 System.out.println(new Zi().getNum() + " "); //1,不管num是用什么修饰的都不影响结果。注意:这里是极易出错的地方! } } 根据原则2,父类中的int num变量被隐藏,因为子类中没有同名的getNum()方法,所以子类的getNum()是继承自父类的,父类中的getNum()调用的是它本身的num,所以结果为:1。
class Fu { int num = 1; //这是父类的 public int getNum() { return num; //num其实为this.num; } } class Zi extends Fu { int num = 2; //这是子类自己定义的 public int getNum() { return num; //这里当然调用的是子类自己的num } } public class Test { public static void main(String[] args) { System.out.println(new Zi().num + " ");//2 System.out.println(new Zi().getNum() + " ");//2 } } 此例中与上个例子的不同之处在于,子类中定义了同名的getNum()方法覆盖了父类中的同名方法,所以这里调用的是子类中的方法,又因为子中的getNum()方法引用的是子类自己的num,所以结果为: 2
多态示例
class Fu { public int num = 1; //这是父类的 public int getNum() { return num; //num其实为this.num; } } class Zi extends Fu { public int num = 2; //这是子类自己定义的 public int getNum() { return num; //num其实为this.num; } } public class Test { public static void main(String[] args) { Fu fu = new Zi(); System.out.println(fu.getNum() + " ");//2,多态! System.out.println(fu.num + " ");//1 } } 这就不用过多解释了吧,就是一个标准的多态示例
class Fu { public int num = 1; //这是父类的 public int getNum() { return num; //num其实为this.num; } } class Zi extends Fu { public int num = 2; //这是子类自己定义的 } public class Test { public static void main(String[] args) { Fu fu = new Zi(); System.out.println(fu.getNum() + " ");//1。本来是多态,但因为子类没有重写此方法,所以…… System.out.println(fu.num + " ");//1,成员变量调用的肯定是自己的 System.out.println(((Zi) fu).getNum() + " ");//1 System.out.println(((Zi) fu).num + " ");//2,成员变量调用的肯定是自己的 } } 根据多态的原则,fu.getNum()调用的是子类的getNum()方法,但是因为子类没有此方法,所以……(原因和上面"继承示例"一样)
继承+构造示例
class Fu { public int num = 1; //这是父类的 public int getNum() { return num; //num其实为this.num; } } class Zi extends Fu { public Zi() { num = 3; } } public class Test { public static void main(String[] args) { System.out.println(new Zi().num + " ");//3 System.out.println(new Zi().getNum() + " "); //3 System.out.println(((Fu) new Zi()).num + " ");//3 System.out.println(((Fu) new Zi()).getNum() + " ");//3 } } 此例中,子类继承了父类的num变量和getNum()方法,所以子类中的构造函数对num的赋值实际上是对继承自父类的变量num的赋值。由于没有覆盖,子类的getNum()调用的也是继承自父类的方法。输出结果是 :3 这本来是最简单的,但是在这几个试验中却变成最难理解的了。
class Fu { public int num = 1; //这是父类的 public int getNum() { return num; //num其实为this.num; } } class Zi extends Fu { public int num = 2; //这是子类自己定义的,不是从父类继承的 public Zi() { num = 3;//这是对子类自己定义的num重新赋值 } } public class Test { public static void main(String[] args) { System.out.println(new Zi().num + " ");//3 System.out.println(new Zi().getNum() + " "); //1 System.out.println(((Fu) new Zi()).num + " ");//1 System.out.println(((Fu) new Zi()).getNum() + " ");//1 } } 此例中,子类的构造函数中对num的赋值实际上是对自己定义的num变量的赋值,所以自己的num变成了:3 由于没有覆盖,所以子类的getNum()方法……
继承--成员变量
class Fu { String a = "父类的成员变量"; static String b = "父类的静态成员变量"; Fu() { System.out.println("父类的构造方法"); } } class Zi extends Fu { String a = "子类的成员变量"; static String b = "子类的静态成员变量"; Zi() { super();//默认是有这么一行代码的,所以才会先调用父类的构造方法 System.out.println("子类的构造方法"); } }
public class Test { @SuppressWarnings("static-access") //eclipse直接来个黄色的提醒:The static field Zi.b should be accessed in a static way public static void main(String[] args) { Fu f = new Zi(); //父类的构造方法--> 子类的构造方法 System.out.println("***************************************"); System.out.println(((Zi) f).a); //子类的成员变量 System.out.println(((Zi) f).b); //子类的静态成员变量。其实根本就不应该这么用,既然是静态的,肯定是和具体的对象没有任何关系,你拿对象去调用是什么意思?静态成员(包括成员变量和成员方法)都是直接以【Zi.b】的形式调用的! System.out.println(f.a); //父类的成员变量 System.out.println(f.b); //父类的静态成员变量 } }
继承--成员方法
class Fu { Fu() { System.out.println("父类的构造方法"); method(); staticMethod(); } void method() { System.out.println("父类的普通方法"); } static void staticMethod() { System.out.println("父类的静态方法"); } } class Zi extends Fu { Zi() { super();//默认是有这么一行代码的,所以才会先调用父类的构造方法 System.out.println("子类的构造方法"); } void method() { System.out.println("子类重写的父类的普通方法"); } static void staticMethod() { //隐藏父类的静态方法 System.out.println("子类的静态方法"); } }
public class Test { public static void main(String[] args) { Fu f = new Zi();//父类的构造方法-->【子类】重写的父类的普通方法(多态) -->【父类】的静态方法(非多态) --> 子类的构造方法。注意了,第二第三都是极易出错的地方 f.method();//子类重写的父类的普通方法,多态! } }
时间: 2024-07-29 10:19:19