Core Java Chapter 5

2016-10-18  本文已影响0人  akak18183

5.1 Classes, Superclasses, and Subclasses

继承是为了代码复用。

5.1.1 Defining Subclasses

使用extends superclass来继承。子类可以直接使用父类的方法和数据。

5.1.2 Overriding Methods

子类可以重写父类的方法。使用super可以调用父类的方法。
书里还讨论了super和this。有些人认为这两个词很像,但其实并不一样,因为this是具体指一个对象,而super其实没有具体的对象,而是直接指向父类。

5.1.3 Subclass Constructors

子类可以调用父类的构造器,也是通过super关键字。必须是构造器的第一行代码。
和this在构造器的用法很像。

5.1.4 Inheritance Hierarchies

继承结构。一个父类可以有多个子类。

5.1.5 Polymorphism

多态。一个对象可以指向本类的对象,也可以指向子类的对象。不过当指向子类的时候,这个对象对编译器而言还是原来那个类,并没有子类多余的方法和数据。而调用父类方法时,假如子类有重写该方法,会调用重写后的方法。
多态其实是一个很重要的概念:
多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

5.1.6 Understanding Method Calls

理解方法调用的流程。

  1. 编译器查看对象的类型和方法名。
  2. 编译器查看参数的个数和数据类型。
  3. 假如这个方法是private,static,final或者构造器,这时候编译器就知道应该调用哪个方法了。
    这个被称为静态绑定(static binding)。否则的话,就是多态的动态绑定(dynamic binding)了。
  4. 动态绑定的方法在运行时才最终确定。
5.1.7 Preventing Inheritance: Final Classes and Methods

用final修饰的方法或者类,无法被子类重写或者继承。

5.1.8 Casting

手动转换对象的类,适用于对象被当成父类而需要使用子类的特点时。这个功能在安卓开发里面非常常见。
建议在转换之前用instanceof检查。

5.1.9 Abstract Classes

抽象类不能被实例化,它就是为了被继承而创造的。
抽象类一般有一个或多个抽象方法,也可以没有。抽象方法不需要具体实现。
抽象对象的子类有两种选择,一种是只重写部分抽象方法,然后继续成为抽象类;另一种是重写所有抽象方法,成为普通的类。

5.1.10 Protected Access

private:仅本类可以访问。
protected:在之前的基础上,包内和子类可以访问。
public:在之前的基础上,外部类也可以访问。
default:包内可以访问。

5.2 Object: The Cosmic Superclass

Object(注意大小写)是默认的一切类的父类。
在Java中,只有基础数据类型不是对象。

5.2.1 The equals Method

equals函数是Object的一个方法,用来判断是不是和另一个对象相等。

5.2.2 Equality Testing and Inheritance

讨论了写equals方法的一些注意事项,主要是要求对称性,因此当有子类和父类出现的时候需要注意。

  1. 把要比较的Object命名为otherObject。
  2. 检查是不是同一个对象:if(this==otherObject) return true;
  3. 检查空:if(otherObject==null) return false;
  4. 检查类:
    假如子类不认为可以和父类比较:if(getClass()!=otherObject.getClass())return false;
    假如认为可以:if (!(otherObject instanceof ClassName)) return false;
  5. 转换:ClassName other = (ClassName) otherObject
  6. 比较变量:return field1 == other.field1&& Objects.equals(field2, other.field2)&& . . .;

假如父类有equals方法,加入super.equals(other)。

5.2.3 The **hashCode **Method

哈希码是对象产生的一个整型数据,两个不同的对象应该要有很大几率有不同的哈希码。
Object里面的哈希码是根据内存地址产生的。
假如重写了equals方法,那么也应该重写这个方法。
建议写法:把equals要检查的变量都放一起hash一下。
public int hashCode(){return Objects.hash(name, salary, hireDay);}

5.2.4 The **toString **Method

把对象以String形式输出。值得一提的是,假如直接用array,其只会返回一个看不懂的东西,需要用Arrays.toString(array)。假如是多维数组,用Arrays.deepToString()。

5.3 Generic Array Lists

介绍了ArrayList。这是一个最常用的数据结构之一。简单高效。
可以用staff.ensureCapacity(100);来先预留空间。
而初始化的时候,和数组有区别:
new ArrayList<>(100) // capacity is 100
new Employee[100] // size is 100
数组是真的占了那么多空间,而ArrayList只是有那个潜能,刚初始化的时候还是一个元素没有。
trimToSize方法可以去除多余空间。最好只在确定不会再加元素的时候使用。

5.3.1 Accessing Array List Elements

用get和set方法来获取和修改ArrayList的元素。remove删除。
有一个trick就是把ArrayList转化为数组
X[] a = new X[list.size()];
list.toArray(a);

5.3.2 Compatibility between Typed and Raw Array Lists

讨论了和古老的版本的ArrayList的兼容问题,会有warning。

5.4 Object Wrappers and Autoboxing

八个基础数据类型也有对应的类,分别为Integer, Long, Float, Double, Short, Byte, Character, and Boolean。它们被称为wrapper class,是final class而且不可变。
ArrayList初始化时只能接受这些wrapper class。同时要意识到直接使用基础数据类型的数组将会高效很多。
不过有一个方便的地方就是add和get的时候会自动转换。这个就是auto boxing和auto unboxing了。

5.5 Methods with a Variable Number of Parameters

例子:
public class PrintStream{public PrintStream printf(String fmt, Object... args) { return format(fmt, args); }}
方法变量里面的Object...意思就是可以接受任意数量的Object,可以理解为Object[]。

5.6 Enumeration Classes

详细介绍了enum的用法。
public enum Size { SMALL, MEDIUM, LARGE, EXTRA_LARGE };
用==来判断相等。
Size s = Enum.valueOf(Size.class, "SMALL");// set s 为SAMLL
Size[] values = Size.values();//获得所有Size的数组
ordinal方法返回序号,从0开始,例如Size.MEDIUM.ordinal()返回1.

5.7 Reflection

在网上查了一些资料来更好地理解反射:

  1. Java 反射机制主要提供了以下功能:
    在运行时判断任意一个对象所属的类。
    在运行时构造任意一个类的对象。
    在运行时判断任意一个类所具有的成员变量和方法。
    在运行时调用任意一个对象的方法
  2. Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces(例如Serializable),也包括fields和methods的所有信息,并可于运行时改变fields内容或调用methods
  3. 在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中
    –Class类:代表一个类(这个类很特殊,位于java.lang包下)。
    –Field 类:代表类的成员变量(成员变量也称为类的属性)。
    –Method类:代表类的方法。
    –Constructor 类:代表类的构造方法。
    –Array类:提供了动态创建数组,以及访问数组的元素的静态方法
5.7.1 The **Class **Class

用getClass()方法获得Class类。然后可以用getName获得名字。可以用forName给Class一个名字。
可以直接把一个type传给Class类,例如:
Class cl1 = Random.class; // if you import java.util.*;
Class cl2 = int.class;
Class cl3 = Double[].class;
int不是class,但是也可以传。

5.7.2 A Primer on Catching Exceptions

有两种异常(exception),checked和unchecked。
介绍了一下try catch,之后还会再详细说。

5.7.3 Using Reflection to Analyze the Capabilities of Classes

参考之前说的关于反射机制的第3点。

5.7.4 Using Reflection to Analyze Objects at Runtime

用getDeclaredField方法获得变量,然后再用get方法获得值,例如:
Employee harry = new Employee("Harry Hacker", 35000, 10, 1, 1989);
Class cl = harry.getClass();// the class object representing EmployeeField
f = cl.getDeclaredField("name");// the name field of the Employee class
Object v = f.get(harry);// the value of the name field of the harry object, i.e., the String object "Harry Hacker"
但是有两个问题需要解决。
其一是访问权限问题。假如name是private的,访问就会有问题。
解决方法:f.setAccessible(true); // now OK to call f.get(harry);
其二,假如返回的不是Object而是基础数据类型呢?反射机制已经解决了,自动会转换成为wrapper class。

5.7.5 Using Reflection to Write Generic Array Code

Object newArray = Array.newInstance(componentType, newLength);
然后一段复制array的方法:

public static Object goodCopyOf(Object a, int newLength)
{
    Class cl = a.getClass();
    if (!cl.isArray()) return null;
    Class componentType = cl.getComponentType();
    int length = Array.getLength(a);
    Object newArray = Array.newInstance(componentType, newLength);
    System.arraycopy(a, 0, newArray, 0, Math.min(length, newLength));
    return newArray;
}
5.7.6 Invoking Arbitrary Methods

Object invoke(Object obj, Object... args)
Method getMethod(String name, Class... parameterTypes)

5.8 Design Hints for Inheritance

  1. 把通用的数据和方法放在父类里面;
  2. 不要使用protected。
  3. 用继承去解决'is-a'关系。
  4. 除非继承有意义,否则不要使用。
  5. 重写方法的时候不要改变其预期的效果。
  6. 使用多态。
  7. 不要滥用反射。
上一篇下一篇

猜你喜欢

热点阅读