继承 多态 构造 易错点

说明


继承的二个关键点:
  • 子类继承了其父类中所有非私有的成员变量和成员方法,并作为自己的成员变量和方法
  • 子类中定义的成员变量和父类中定义的成员变量相同时,则父类中的成员变量会被【隐藏】

子父类成员同名情况
  • 对于成员变量:父类的成员变量在子类中是存在的,即使是私有的或者和子类中定义的成员变量同名;但是子类中能看到的只有子类中定义的变量和从父类继承的非私有的变量,并且如果子类中定义的变量和从父类中继承过来的变量重名,则会隐藏从父类继承的成员变量。
  • 对于成员方法:同名的非静态方法则是我们常说的实实在在的覆盖,覆盖后子类中仅有此一个方法(而隐藏实际上两个都是存在的,只是看不到也不能用而已),也即我们看到的那个重写的方法。

例如 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();//子类重写的父类的普通方法,多态!     } }  

来自为知笔记(Wiz)

时间: 2024-07-29 10:19:19

继承 多态 构造 易错点的相关文章

细节!重点!易错点!--面试java基础篇(一)

今天来给大家分享一下java的重点易错点部分,也是各位同学面试需要准备的,欢迎大家交流指正. 1.java中的main方法是静态方法,即方法中的代码是存储在静态存储区的. 2.任何静态代码块都会在main方法之前执行. 3.java程序的初始化顺序:原则:静态优先于非静态,且只初始化一次:父类优先于子类:按照成员定义顺序初始化.例顺序:父类静态变量,父类静态代码块,子类静态变量,子类静态代码块,父类非静态变量,父类非静态代码块,父类构造函数,子类非静态变量,子类非静态代码块,子类构造函数. 4.

细节!重点!易错点!--面试java基础篇(二)

今天来给大家分享一下java的重点易错点第二部分,也是各位同学面试需要准备的,欢迎大家交流指正. 1.字符串创建与存储机制:当创建一个字符串时,首先会在常量池中查找是否已经有相同的字符串被定义,其判断的依据是String类型equals的返回值,若已经定义,则直接获取对其的引用.此时不需要创建新的对象,如果没有定义,首先创建这个对象,然后把它加入到字符串池中,再将它的引用返回.(例:new String(”aaa“)可能创建了1个或者2个对象,如果常量池中原来有aaa那么之创建了一个对象,如果没

黑马程序员---C基础3【变量的易错】【程序结构】【if语句】【Switch语句】

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- [变量的易错] 1.变量为什么要初始化为0 int  sum,a=3: sum = sum+a 如果未初始化则会成为一个不确定的变量,结果也会不确定,容易出错. 2.不同类型的变量之间的转换 切记int  a=1,b=0:b=1-1.5:其中b为一个整型所有结果是保留整数部分的0,而不是-0.5,又因为0没有正负之分,所有保存结果为b=0: 3.关于Xcode的一个快速注释的插件 快捷键://

(1) 深入理解Java面向对象三大特性 封装 继承 多态

转眼已经工作快6年了,最开始做了2年J2EE:然后整了2年的数据仓库,主要是Cognos的报表开发:现在从事4G LTE核心网的开发,用的语言任然是Java,但写代码的机会不多,基本都是看代码找BUG,偶尔做点new feature也是在比较成熟的框架上复制.粘贴.修改,大部分时间还是在理解业务,钱多.事少.离家近,当时来这家公司图的是后面2点,2年过去了,英文水平有所提升,对敏捷开放也有一定的了解,但技术方面明显退步了或者说没有进步吧,本来以前也不怎么好,因为工作上用不到,自己也没怎么学习,所

Swift学习——类的定义,使用,继承,构造等(五)

Swift学习--类的定义,使用.继承,构造等(五) 类的使用说明 1 使用class和类名来创建一个类名,比如: class student 2 类中属性的声明和常量和变量一样,唯一的差别就是他们的上下文是类 3 方法和函数声明也一样 // 1 ---- 简单的类介绍 class Student{ //变量学号初始化为0 var num = 0; //成员函数 func GetNum()->Int{ return num } } //创建类的实例对象 var student = Student

java基础之【继承--->多态】内存图

执行流程 1:Animal a = new Cat(); 1.1:在栈中创建区域,类型为Animal,变量名:a; 1.2:在堆中new Cat();占用一块区域.地址值:[0x3a4] 1.3:spuer()实例化父类Animal. 1.3.1:new Animal();占用一块区域,地址值:0x3ab; 1.3.2:引用着在方法区中初始化[Animal中的所有方法,该引用为:[0x754]]. 1.3.3:将Animal()引用赋给spuer();spuer引用着Animal(); 1.4:

初识JAVA(【面向对象】:pub/fri/pro/pri、封装/继承/多态、接口/抽象类、静态方法和抽象方法;泛型、垃圾回收机制、反射和RTTI)

JAVA特点: 语法简单,学习容易 功能强大,适合各种应用开发:J2SE/J2ME/J2EE 面向对象,易扩展,易维护 容错机制好,在内存不够时仍能不崩溃.不死机 强大的网络应用功能 跨平台:JVM,字节码 两个命令: javac helloworld.java:将Java文件编译为字节码的.class文件 java helloworld:运行Java程序...??暂时这么认为 数据类型: 普通数据类型:int a=3; 对象数据类型:使用关键字new,String s=new String("

集合框架中,引用数据类型对象集合的构建,易错点分析

先来个完整的效果代码:其目的创建5个学生对象,录入姓名与年龄的对象,并用集合将其遍历出来.易错点:1.如果不在学生对象中重写toString方法,那么在集合中就会出现,遍历出来后的arr{i}全部都是引用的对象地址,并不是对象.2.引用数据类型与基本数据类型最大的区别,引用数据类型要事先定义好各项属性与方法.要知道有参构造的作用是初始化方法里的属性.3.定义setname().getname().setage().getage()这四个方法,通过这四个方法来实现对name和age的操作.这样一来

Javascript易错知识点

? JS易错知识点总结: == 和 === 的区别: ==:判断两个变量的值是否相等. ===:判断两个变量的类型和值是否都相等,两个条件同时满足时,表达式为True. switch中break的作用: 如果一个case后面的语句,没有写break,那么程序会向下执行,而不会退出: 例如:当满足条件的case 2下面没有break时,case 3也会执行 1 var num = 2; 2 switch(num){ 3 case 1: 4 alert('case 1'); 5 break; 6 c