• 第5章 继承


    1. 父类和子类

      扩展父类时,仅需要指出子类与父类的不同之处,也可以通过重写(动态(单)分派:根据调用者的实际类型决定调用的方法)覆盖父类方法。

      子类可以继承父类的私有域,但是只能通过父类方法访问此私有域,若本身覆盖了父类的访问方法,则通过关键字 super 表示调用的是父类方法。 super 两个用途:1、调用父类方法 2、调用父类构造器

      

    public class father {
        private int age = 40;
        String name = "jj"; 
        
        public int getAge() {
            return age;
        }
    }
    
    class son extends father{
        public int getAge() {
           return age; // error 字段 father.age 不可视
            // return super.getAge();
        }
            
            public String getName(){
                 return name;  
            }
    }   

      在子类中可以增加域,增加/覆盖方法,但绝对不能删除继承的域和方法。

    2. 多态

      静态类型为父类的对象引用既可以引用本身的对象,也可以引用子类对象。反之不成立。

    class Father{};
    class Son extends Father{};
    
    Father father = new Son();      // Yes
    Son son = new Father();     // No

      (JVM)在确定方法调用的版本时:

      非虚方法(invokespecial, invokestatic指令调用的方法,例如静态方法,私有方法,父类方法,实例初始化方法 以及 final修饰的方法)编译期可知,运行期不可变,所以编译器确定类型,在类加载的解析阶段就会把符号引用转化为直接引用,称为静态调用(解析)。

      虚方法(invokevirtual等指令)在运行期才会确定调用方法的版本(根据接受者的实际类型)此时称为(分派)。

      分派分为静态分派和动态分派:

    • 静态分派:依据接受者方法参数静态类型确定调用方法的版本,属于多分派。静态分派发生在编译期  
    • 动态分派:依据接受者实际类型确定调用方法的版本,属于单分派。动态分派发生在执行期

      invokevirtual指令执行过程:

    1. 找到操作数栈顶的第一个元素所指向的对象的实际类型,记作C。
    2. 如果在类型C中找到与常量中的描述符和简单名称都相符的方法,则进行访问权限校验,如果通过则返回这个方法的直接引用,查找过程结束;如果不通过,则返回java.lang.IllegalAccessError异常。
    3. 否则,按照继承关系从下往上依次对C的各个父类进行第2步的搜索和验证过程。
    4. 如果始终没有找到合适的方法,则抛出java.lang.AbstractMethodError异常。

    3. 方法表

      每次调用方法都要进行搜索,为此,虚拟机预先为每个类创建了方法表,列出了方法的签名和实际调用的方法。  

    4. 阻止继承

      不允许扩展的类称为 final 类,类中方法声明为 final 表示子类不能覆盖这个方法。若将一个类声明为 final ,类中方法自动成为 final 方法, 但不包括域。

    5. 抽象类

      包含一个或多个抽象方法的类本身必须声明是抽象的,当然,抽象类也可以包含具体的方法和具体的数据。子类继承抽象类后,除非定义全部的抽象方法,否则,依然需要声明为抽象类。

      类即使不包含抽象方法,也可以声明为抽象类。

      抽象类不能实例化。但可以定义一个抽象类的对象引用,引用非抽象的子类实例。

    public abstract class person{
        public int age;
        public abstract int getAge(){}
    }
    
    public student extends person{
        public int getAge(){
            return age;
        }
    }
    
    
    person p = new person(); // error
    person p = new student(); // true

    6. 访问修饰符

    1. private 仅对本类可见
    2. protect 对本包和所有子类可见
    3. public 对所有类可见
    4. default (默认)对包可见,不需要修饰符

    7. equals

      Object 类的equals()方法判断两个对象引用是否指向同一个对象。

    public boolean equals (Object x){
        return this == x;
    }
    // java 中 == 判断两个引用是否指向同一对象

    8. hash code

      hashCode 方法定义在Object类中,因此每个对象都有一个默认的散列码,其值为对象的存储地址。

      此外,equals() 与 hashCode() /*必须结果统一(有误)*/,如果 x.equals(y) 返回 true, 则 x.hashCode() 和 y.hashCode() 必须相同。 (2018-03-30) 

    1. 如果两个对象equals比较返回true,则两个对象的hashCode必须相同
    2. 如果equals返回false,两个对象的hashCode可以相同,例如 HashMap

    9. toString

      Object类定义了 toString 方法, 用来打印输出对象所属的类名和散列码。

    10. 对象包装器与自动装箱

      Integer、Long、Float、Double、Short、Byte、Character、Void、Boolean

      包装器类是不可变的,同时,包装器类修饰关键字为final。

      ArrayList<Integer> list not ArrayList<int> list ,尖括号中的参数类型不允许是基本类型。

      自动装箱:list.add(3); ==> list.add(Integer.valueOf(3));

      自动拆箱:int a = list.get(i);  ==> int a = list.get(i).intValue();   

    Integer a = 1000;
    Integer b = 1000;
    System.out.printlen(a==b);  // return false
    
    Integer a = 100;
    Integer b = 100;
    System.out.printlen(a==b);  // return true

      介于 -128~127 之间的 short 和 int 被包装到固定的对象中,即指向同一个对象。

    11. Class类

      在程序运行期间,java运行时系统始终为所有对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。保存这些信息的类称为Class。

    12. 继承的技巧

    1. 将公共操作和域放在超类
    2. 不要使用受保护的域
    3. 除非所有继承的方法都有意义,否则不要使用继承

    13. 多继承

      Java不允许类的多继承,是为了避免菱形继承的问题。设想两个类定义了签名(方法名和入参及入参顺序)相同的方法,那么同时继承这两个类,调用这个方法的时候,编译期犯迷糊了,到底想要哪个父类的方法呢。在C++中,使用虚继承解决这个问题,Java秉持简单的原则,放弃了类的多继承。

      那Java中有多继承吗?

      有的,Java中接口是可以多继承的。

      那会产生菱形问题吗?

      会也不会,在Java8之前,接口只能定义方法,具体的实现交给实现类完成,如果多个接口定义了签名相同的方法,没有关系,反正只是定义而已,实现类只需要实现一次即可。而在Java8中,接口可以定义default方法,即在接口中定义方法实现。这种情况就跟类的多继承一样,会出现菱形继承问题了。

      我们引申一下,为什么Java8需要引入default方法机制呢?

      试想一下,一个接口有千万的实现类,或者打成jar包,提供给别人使用。突然有一天,接口添加了一个新方法,所有的实现类都需要实现这个方法,这将是灾难性的。而default方法正如其名,是一个默认方法,接口添加后,实现类可以不实现。不实现则使用接口的默认实现。

    人生就像蒲公英,看似自由,其实身不由己。
  • 相关阅读:
    build、host和target选项
    第一篇博客
    C++中的new和delete
    新分类:C++复习笔记
    泛读英文小说推荐
    借助查询分析器对遗留项目进行分析
    程序员等级(非本人观点)
    线程并发时的四种数据同步方法
    单元测试之什么是优秀的单元测试
    多线程之进度条
  • 原文地址:https://www.cnblogs.com/walker993/p/8666094.html
Copyright © 2020-2023  润新知