Core Java Volume I 读书笔记---第五章: 继承

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiaoyaohuqijun/article/details/78056219

第五章: 继承

 

5.1 类,超类,子类

 

继承:通过扩展已存在的类来定义新的类,  Java 中使用关键字extends

“is a “   是继承关系的明显特性,  子类 is a 父类;

 

继承的本质是复用已有类的方法和域, 是聪明的偷懒。

 

子类一般拥有比超类更加丰富的功能

 超类中有些方法对子类不适用, 子类可以覆盖(override)超类中的方法

子类中可以增加域,增加方法或者覆盖超类的方法, 而不能删除继承的任何域和方法。

 

super  关键字作用:

1.      指示编译器调用超类的方法

2.      调用超类构造器(super 必须作为子类构造器的第一条语句)

 

一个对象变量可以指示多种实际类型的现象被称为多态

  运行时能自动选择调用哪个方法的现象称为动态绑定

 

“isa ” 规则的另一种表述法是置换法则:程序中超类对象出现的任何地方都可以用子类对象置换。

所以对象变量是多态的:一个对象变量即可以引用自己的类对象, 也可以引用它的类的任何一个子类的对象。

 

final 关键字作用:

1.      final 修饰类, 表示类不允许继承

2.      修饰方法, 表示方法不允许覆盖

3.      修改域或者变量, 不允许修改变量的值

 

抽象类不能被实例化, 如果将一个类声明为abstract,就不能创建这个类的对象。

可以定义抽象类的对象变量, 但它只能引用非抽象子类的对象。

包含一个或多个抽象方法的类本身必须被声明为抽象的。

 

 

访问控制修饰符

1.      private : 仅对本类可见

2.      public:  对所有类可见

3.      protected :  对本包和所有子类可见

4.      默认: 对本包可见

 一般不要使用protected的域, protected域能被子类或者本包中的所有类直接访问, 破坏了OOP的数据封装原则。

protected 的方法更有实际意义。

 

 

 

5.2 Object: 所有类的超类

 

Object 类是Java 中所有类的始祖, Java 中的每个类都是由Object扩展而来。

 

如果没有明确指出超类,Object 就是该类的超类。

 

Object 类型的对象变量可以引用任何对象。

 

equals 方法:

public boolean equals(Object obj) {
   
return(this== obj);
}

 

Object 类中,equals 判断两个对象是否有相同的引用。 对多数类来说, 这样判断没有意义。一般都会重写equals方法。

String 类重写equals判断字符串的内容 :

 public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

 

 

 

Java 语言规范要求equals方法具有以下特性:

1.      自反性: 对于任何非空引用x,  x.equals(x) 应该放回true;

2.      对称性:   对于任何引用x ,y ,   当且仅当y.equals(x) 返回true,  x.equals(y) 也应该放回true;

3.      传递性: 对于任何引用x,y和z, 如果x.equals(y)返回true,  y.equals(z)返回true, 那么x.equals(z) 也应该返回true;

4.      一致性: 如果x和y 引用的对象没有发生改变, 反复调用x.equals(y)应该返回同样的结果;

5.      对于任意非空引用x,   x.equals(null) 应该返回false.

 

 

 

hashCode 方法:

 public native int hashCode();

 

Object 类中hashCode默认返回对象的存储地址。

 

equals 与hashCode 的定义必须一致: 如果x.equals(y)返回true,那么x.hashCode必须等于y.hashCode.     所以如果重新定义equals , 就必须重新定义hashCode方法

 

 

toString 方法:

public StringtoString() {
   
returngetClass().getName() +"@" + Integer.toHexString(hashCode());
}

 

toString 在Object类中定义,默认用于打印类型和散列码。

 

 

现在的IDE(如IntelijIEDA ) 都可以自动生成Constructor, getter,setter, equals, hashCode,toString 等方法,  重写非常方便。

toString 方法在调试过程中非常有用,  可以使用反射写一个通用的toString 方法, 具体代码见: https://github.com/geekhuqijun/JavaCodePieces/blob/master/ObjectAnalyzer.java



5.3 泛型数组列表

 

ArrayList<T>()

构造一个空的数组列表

ArrayList<T>(intinitialCapacity)

用指定容量构造一个空的数组列表

boolean add(T obj)

在数组列表尾段添加一个元素,  永远放回true

        int size()

       返回存储在数组列表中的当前元素数量

      

ArrayList, Vector, LinkedList 三者区别:

 

1.    ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。

2.   VectorArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList

3.   LinkedList是用链表结构存储数据的很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用

 

 

 

5.4 对象包装器与自动装箱

 

JAVA的思想一切皆对象,  然后Java 中基本类型确实这一思想的例外。

所有基本类型都一个与之对应的类,称为包装器

Integer,Long,Float,Double,Short,Byte,Character,Void 和Boolean

 

基本类型和其对应的类型之间会自动的做类型转换。 从基本类型转换为类类型,称为“自动装箱”,  反之称为“自动拆箱”。

 

自动装箱规范要求boolean,byte, char<=127, 介于-128~127 之间的shor和int被包装到固定的对象中。

 

装箱和拆箱是编译器认可的,编译器在生成字节码时,插入必要的方法调用。

 

个人猜想,基本类型是Java 为了兼顾C/C++ 的使用习惯而留下来的, 明显不符合Java 强OOP的设计。 自动装箱和拆箱不过是一种自动类型转换的胶水。

 

 

 5.5 参数变量可变的方法

    

     public staticdouble max(double… values)

{

//

}

省略号表示可以接受可变数量个参数。

 

语法糖,  没什么价值,  因为一和多是相对的。   10 个参数可以被包装在一个对象中。

double…   等价于double[]数组

 

 

5.6 枚举类

 

所有枚举类型都是Enum类的子类

 

 

 

5.7 反射

 

能够分析类能力的程序称为反射

 

反射的作用:

1.      运行中分析类的能力

2.      运行中查看对象,例如,编写一个toString 供所有类使用

3.      实现通用的数组操作代码

4.      利用Method 对象, 类似C++ 中的函数指针

 

Class 类: Java 运行时系统为所有对象维护的运行时类型标识

(创建对象时,  对象头中的类型标识)

 

获取Class的方法:

1.      Object 类中的getClass() 方法

Class cl = e.getClass();

2.      静态方法forName 获取类名对应的Class 对象

String className = “java.util.Date”;

Class cl = Class.forName(className);

3.       如果T 是任意的Java类型,  T.class 代表匹配的类对象

 

 

反射说起来不复杂,  就是赋予了代码动态分析类能力的能力。  利用反射可以写出很多通用代码,可以参考这里的相关代码:

https://github.com/geekhuqijun/JavaCodePieces

 

 

 

5.8 继承设计的技巧

 

1.      将公共操作和域放在超类

2.      不要使用受保护的域

3.      使用继承实现 is-a 关系

4.      除非所有继承的方法都有意义,否则不要使用继承

5.      覆盖方法时, 不要改变预期的行为

6.      使用多态,而非类型信息

7.      不要过多的使用反射


没有更多推荐了,返回首页