Core Java笔记—第5章 继承

5.1 类、超类和子类

在Java中使用关键字super调用超类的方法,而在C++中则采用超类名加上::操作符的形式.

使用super调用构造器的语句必须是子类构造器第一条语句.

如果子类的构造器没有显式地调用超类的构造器,则将自动地调用超类默认(没有参数)的构造器.如果超类没有不带参数的构造器,并且在子类的构造器中又没有显式地调用超类的其他构造器,则Java编译器将报告错误.

子类覆盖父类的方法时,在JDK 5.0以前要求返回类型必须和父类是一样的,而现在允许子类将覆盖方法的返回类型定义为原返回类型的子类型.

如果方法是private、static、final或者构造器,那么编译器将可以准确地知道应该调用哪个方法,这种调用方式称为静态绑定.

在覆盖一个方法时,子类方法不能低于超类的可见性.特别是,如果超类方法是public,那么子类方法一定要声明为public.

被声明为final的类不允许被继承.被声明为final的方法不能被子类覆盖.

final类的所有方法自动地成为final方法,但成员变量不会自动变final.

在将超类转换成子类之前,应该使用instanceof进行检查.

包含一个或多个抽象方法的类本身必须被声明为abstract的.除了抽象方法外,抽象类还可以包含具体数据和具体方法.即使不含有抽象方法,也可以将类声明为抽象类.抽象类不能被实例化.需要注意,可以定义一个抽象类的对象变量,但是它只能引用非抽象子类的对象.

Java中的受保护部分对所有子类以及同一个包中的所有其他类可见.这与C++中的保护机制稍有不同.Java中的protected概念要比C++中的安全性差.

Java用于控制可见性的4个访问修饰符
1.仅对本类可见—private
2.对所有类都可见—public
3.对本包和所有子类都可见—protected
4.对本包可见—没有修饰符时的默认情况


在Java中,只有基本类型的值不是对象,而所有的数组类型,不管是对象数组还是基本类型的数组都扩展于Object类的类型.

编写一个完美的equals方法的建议
1.显式参数命名为otherObject,稍后需要将它转换成另一个叫other的变量

2.检测this域otherObject是否引用同一个对象

if(this == otherObject) return true;
3.检测otherObject是否为null,如果为null,返回false
if(otherObject == null) return false;
4.比较this与otherObject是否属于同一个类.
如果equals的语义在每个子类中有所改变,就使用getClass检测
if(getClass() != otherObject.getClass()) return false;
如果所有的子类都拥有统一的语义,就使用instanceof检测
if(!(otherObject instanceof ClassName)) return false;
5.将otherObject转换为相应的类类型变量
ClassName other = (ClassName)otherObject;
6.对所有需要比较的域进行比较,使用==比较基本类型,使用equals比较对象域.如果在子类中重新定义equals,就要在其中包含调用super.equals(other).

5.2 Object:所有类的超类

如果存在数组类型的域,那么可以使用静态的Arrays.hashCode方法计算一个散列码,这个散列码由数组元素的散列码组成.

随处可见toString方法的主要原因是:只要对象与一个字符串通过操作符“+”连接起来,Java编译器就会自动调用toString方法,以便获得这个对象的字符串描述.

5.3 泛型数组列表

JDK 5.0以前的版本没有提供泛型类,而是有一个ArrayList类,其中报错的是类型为Object的元素.

如果已经清除或能够估计出数组可能存储的元素数量,可以在填充数组之前调用ensureCapacity方法.另外还可以把初始容量传递给ArrayList构造器.

一旦能够确认数组列表的大小不再发生变化,就可以调用trimToSize方法,这个方法将存储区的大小调整为当前元素数量所需的存储空间数目,垃圾回收器将回收多余的存储空间.

5.4 对象包装器与自动打包

所有的基本类型都有一个与之对应的类,这些类称为包装器.对象包装器类是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值.同时,对象包装器类还是final的,因此不能定义它们的子类.

包装器类作为函数参数传递时,也不能使实参的值发生改变.

5.5 参数数量可变的方法

在Java SE 5.0以前的版本,每个Java方法都有固定数量的参数.现在的版本提供了可以用可变参数数量调用的方法,如printf.其定义为public PrintStream printf(String fmt,Object... args);这里的省略号...是Java代码的一部分,表明这个方法可以接收任意数量的对象(除fmt参数之外).

允许将一个数组传递给可变参数方法的最后一个参数.因此,可以将已经存在且最后一个参数是数组的方法重新定义为可变参数的方法,而不会破坏已经存在的代码.

5.6 枚举

在比较两个枚举类型的值时,永远不需要调用equals,而直接使用“==”就行.

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

枚举类的toString方法能够返回枚举常量名.其逆方法是静态方法valueOf.
Size s = (Size)Enum.valueOf(Size.class, "SMALL");将s设置成Size.SMALL.

每个枚举方法都有一个静态的values方法,返回一个包含全部枚举值的数组.

ordinal方法返回enum声明中枚举常量的位置,位置从0开始计数.

5.7 反射

Object类中的getClass方法将会返回一个Class类型的实例.一个Class对象表示一个特定类的属性.最常用的Class方法是getName,这个方法会返回类的名字.

还可以利用静态方法forName获得字符串对应的Class对象.
Class cl = Class.forName("java.util.Date");

获取Class类对象的第三种方法非常简单,如果T是任意的Java类型,那么T.class将代表匹配的类对象.例如
Class cl1 = Date.class;
Class cl2 = int.class;
Class cl3 = Double[].class;
注意,一个Class对象实际上表示的是一个类型,而这个类型未必是一定是一种类.如int不是类,但int.class是一个Class类型的对象.

从JDK 5.0开始,Class类被参数化.如Class<Employee>的类型是Employee.class,它将已经抽象的概念更加复杂化了,在大多数实际问题中,可以忽略类型参数,而使用原始的Class类.

虚拟机为每个类型管理一个Class对象.因此可以利用==运算符实现两个类对象比较的操作.如
if(e.getClass() == Employee.class) ...

还有一个很有用的方法newInstance(),可以用来快速地创建一个类的实例.如e.getClass().newInstance();创建了一个与e具有相同类类型的实例.newInstance调用默认的构造器初始化新创建的对象,如果这个类没有默认的构造器,就会抛出一个异常.如果希望为构造器提供参数,可以使用Constructor类中的newInstance方法.

异常有两种类型:未检查异常和已检查异常.对于已检查异常,编译器会检查是否提供了异常处理器,然后很多常见的异常如访问null引用都属于未检查异常.

在java.lang.reflect包中有三个类Field、Method和Constructor分别描述类的域、方法和构造器.

Class类中的getFileds、getMethods和getConstructors方法将返回类支持的public域、public方法和public构造器数组,其中包括超类的共有成员.Class类中的getDeclaredFileds、getDeclaredMethods和getDeclaredConstructors方法将返回类中声明的全部域、全部方法和全部构造器数组,其中包括私有和受保护的成员,但不包括超类的成员.

//内容待完善
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值