第五章 继承
5.1 类 超类和子类
- 关键字extends 用来继承
- 关键字super在子类的方法中调用父类的方法,还可以用来调用父类的函数。
- 在子类中不能删除父类的域和方法
子类的构造器
- 使用super()方法调用父类的构造器,但必须是子类构造器的第一条。
- 若子类构造器没有显式调用超类的构造器,默认调用父类的无参数构造器,此时若父类中没有,报错。
继承的层次
- 一个祖先类可以拥有多个子孙继承链
多态
程序中任何出现超类对象的地方都可以用子类对象替换。(反过来不可以滴)
也就是说,对象变量是多态的。
方法调用的原理
注:虚拟机会预先为每个类创建方法表。
注意:子类方法不可低于超类方法的可见性。
阻止继承 final类和方法
- 父类中被final修饰的方法不能被子类覆盖、
- final类中所有方法自动成为final方法,但是不包括域(也就是说,域仍然是变量)
final的好处?
可以避免动态绑定带来的开销。
强制类型转换
明确:父类向子类的转换必然报错。
使用instanceof()函数预先检查,避免报错。
一般情况下,尽量少使用类型转换。
抽象类
把更具有通用性的属性放置在较高层次的通用超类中。
- 抽象类使用abstract关键字。
- 凡包含抽象方法的类都是抽象类。当然抽象类也可以包含具体数据和具体方法。
- 即使不含抽象方法,也可以是抽象类。
一些抽象类的注意点:
- 抽象类不可以实例化
- 可以定义抽象类的对象变量,但是必须引用非抽象 类的对象。
- 然而,必须注意,抽象类的对象变量只能调用抽象类中声明的方法。
受保护访问
- protected关键字:子类得到信任,但是其他类不行。
5.2 Object类:所有类的超类
- 该类的对象可以引用任何类型的对象
- 只有基本类型不是对象,其他的都是对象
- 在子类中定义equals方法需要先调用超类的equals方法,如果相等则继续比较子类的实例域。
if(!super.equals(otherObject)) return false;
相等测试与继承
如何编写一个完美的equals()方法?
1)显示参数命名为otherObject,稍后转化为一个叫other的变量。
2)检测this与otherObject是否引用同一个对象
3)检测Otherobject是否是null。
4)比较this与otherObject是否属于同一个类,如果equals的语义在每个子类中有所改变,那么使用getclass检测。
5)将otherObject转化为相应的类类型变量。
6)现在开始对所有的域进行比较。
注:数组的比较可以用Array.equals()方法进行检测,每一个数组元素是否相等。
hashCode方法
- 定义在Object类中,因此每一个对象都有默认的散列码。其值为对象的存储地址。
- 该方法返回整形数值,注意 合理组合各个实例域的散列码,让生成的hashCode()更加均匀。
- 静态的Objects.hashCode()方法,是null安全的。Double.hashcode()避免生成Double对象。
- 更好的做法,使用hash()组合多个散列值。
- Equals和hashCode的定义 必须一致。
- 数组类型的域有:Array.hashcode()
toString 方法
数组的打印使用Arrays.toString()的静态方法,而不用toSring
如果是多维数组,则需要使用Arrays.deepToString()
5.3 泛型数组列表
在使用ArrayList构造器时,可以使用:
1)ensureCapacity(100)预先分配空间。
2)也可以ArrayList<employee>staff=new ArrayList<>(100)
这两者是等价的。
在确认数组大小不发生变化之后 staff.trimTiSize()
可以去除空块。
一个扩展数组的小技巧:
X[]a=new X[list.size()]
list.toArray(a) 将数组元素拷贝到一个数组中。
类型化与原始数组列表的兼容性问题
兼容主要表现在函数的参数与返回值两个方面。
可以将类型化数组列表传递给原始数组列表参数
但是,反过来会有警告,在警告无严重后果时,可以加@suppress(“unchecked”)语句。
P183
5.4 对象包装器与自动装箱
- 自动装箱和自动拆箱是指Integer 和int两者之间的转化。
- 对象包装器类是final,因此不能被继承。
- 如何编写修改数值参数值的方法?使用IntHolder类的对象
5.5 参数数量可变的方法
- 只需要这样给函数传参:(double…values) 其中values是一个数组列表。
- 以prntf函数为例子,编译器需要对printf的每次调用进行转换,以便将参数绑定到数组上。并在必要的时候进行自动装箱。实际,printf()方法接受了两个参数,一个是格式字符串,一个是Object[]数组,其中保存着所有的参数。如果调用者提供的是整形数组或者是基本类型的值,那么自动装箱可以把他们转化成对象。
5.6枚举类
- 比较两个枚举类型的值时,直接==
- toString 方法的逆方法
Size s=Enum.valueOf(Size.class,"Stirng")
- compareTo比较的是枚举值的索引。