`
bsr1983
  • 浏览: 1102129 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

第五章 继承

阅读更多
反射(reflection)是指在程序运行期间发现更多的类及其属性的能力。
5.1 类、超类和子类
关键字extends表明正在构造的新类派生于一个已存在的类。已存在的类被称为超类(superclass)、基类(base class)或父类(parent class);新类被称为子类(subclass)、派生类(derived class)或孩子类(child class)。
注意:前缀“超”和“子”来源于计算机科学和数学理论中的集合语言的术语。
注意:有些人认为super与this引用时类似的概念,实际上,这种类比并不恰当。这是因为super不是一个对象的引用,不能将super赋给另一个对象变量,它只是一个指示编译器调用超类方法的特有关键字。
注意:super关键字也有两个用途:一是调用超类的方法,二是调用超类的构造器。
一个对象变量可以引用多种实际类型的现象被称为多态(polymorphism)。在运行时能够自动地选择调用的适当方法的现象称为动态绑定(dynamic binding)。
5.1.1 继承层次
由一个公共超类派生处理的所有累的集合被称为继承层次(inheritance hierarchy)。在继承层次中,从摸个特定的类到其祖先的路径被称为该类的继承链。
5.1.2 多态
“is-a”规则的另一种表述法是置换法则。它表明程序中出现超类对象的任何地方都可以用子类对象置换。
警告:在Java中,子类数组的引用可以转换成超类数组的引用,而不需要采用强制类型转换。
5.1.3 动态绑定
弄清调用对象方法的执行过程十分重要。下面是调用过程的详细描述:
1)编译器查看对象的声明类型和方法名。
2)编译器将查看调用方法时提供的参数类型,如果在所有名为f的方法中存在一个其参数类型与提供的参数完全匹配,那么就调用这个方法,这个过程被称为重载解析(overloading resolution)
3)如果方法是private、static、final或者构造器,那边编译器将可以准确地知道应该调用哪个方法,这种调用方式称为静态绑定(static binding)。
4)当程序运行,并且采用动态绑定调用方法时,虚拟机一定调用与x所引用对象的实际类型最合适的那个类的方法。
虚拟机预先为名各类创建了一个方法表,其中列出了所有方法的签名和实际调用的方法。
动态绑定有一个非常重要的特性:无需对现存的代码进行修改,就可以对程序进行扩展。
警告:在覆盖一个方法的时候,子类方法不能低于超类方法的可见性。特别是,如果超类方法是public,那么子类方法一定要声明为public。
5.1.4 阻止继承:final类和final方法
不允许扩展的类被称为final类。
注意:如果将一个类声明为final,只有其中的方法自动地成为final,而不包括域。
5.1.5 强制类型转换
综上所述:
1、只能在继承层次内进行类型转换
2、在将超类转换成子类之前,应该使用instanceof进行检查。
5.1.6 抽象类
为了提高程序的清晰度,包含一个或多个抽象方法的类本市必须被声明为抽象的。
抽象方法充当着占位的角色,它们的具体实现在子类中。扩展抽象类可以有两种选择。一种是在子类中定义部分抽象方法或抽象方法也不定义,这样就必须将子类也标记为抽象类;另一种是定义全部的抽象方法,这样一来,子类就不是抽象的了。
需要注意,可以定义一个抽象类的对象变量,但是它只能引用非抽象子类的对象。
5.1.7 受保护的访问
Java用于控制可见性的4个访问修饰符:
1)仅对本类可见——private
2)对所有类都可见——public
3)对本包和所有子类都可见——protected
4)对本包可见——默认,所谓默认是指没有标明任何修饰符的情况,这是一种不太受欢迎的形式
5.2 Object:所有类的超类
如果没有明确地指出超类,Object就被认为是这个类的最终超类。
在Java中,只有基本类型(primitive type,如数值、字符和boolean)的值不是对象。而所有的数组类型,不管是对象数组还是基本类型的数组都扩展于Object类的类型。
5.2.1 equals方法
Object类中的equals方法用于检测一个对象是否等于另外一个对象。在Object类中,这个方法将判断两个对象是否具有相同的引用。
5.2.2 相等测试与继承
Java语言规范要求equals方法具有下面的特性:
1)自反性:对于任何非空引用x,x.equals(x)应该返回true。
2)对称性:对于任何引用x和y,如果x.equals(y)返回true,那么y.equals(x)也该返回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。
5.2.3 hashCode方法
散列码(hash code)是由对象导出的一个整型值。散列码是没有规律的。
由于hashCode方法定义在Object类中,因此每个对象都有一个默认的散列码,其值为对象的存储地址。
如果重新定义equals方法,就必须重新定义hashCode方法,以便用户可以将对象插入到散列表中。equals与hashCode的定义必须一致:如果x.equals(y)返回true,那么x.hashCode()就必须与y.hashCode()具有相同的值。
5.2.4 toString方法
提示:在调用x.toString()的地方可以用""+x替代。这条语句将一个空串与x的字符串表示相连接。这里的x就是x.toString()。与toString不同的是,如果x是基本类型,这条语句照样能执行。
5.3 泛型数组列表                              2010-09-07   169页
一旦能够确认数组列表的大小不再发生变化,就可以调用trimToSize方法。这个方法将存储区域的大小调整为当前元素数量所需要的存储空间数目。垃圾回收器将回收多余的存储空间。一旦整理了数组列表的大小,添加新元素就需要花时间再次移动存储块,所以在确认不会添加任何元素时,再调用trimToSize。
5.3.1 访问数组列表元素
使用add方法为ArrayList添加新元素,而不要使用set方法,它只能替换数组中已经存在的元素内容。
5.3.2 类型化与原始数组列表的兼容性
5.4 对象包装器与自动打包
对象包装器:Integer、Long、Float、Double、Short、Byte、Character、Void和Boolean。(前6个类派生于公共的超类Number。)对象包装器是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值。同时,对象包装器类还是final的,因此不能定义它们的子类。
注意:自动打包规范要求boolean、byte、char≤127,介于-128~127之间的short和int被包装到固定的对象中。
注意:如果想编写一个修改数值参数值的方法,就需要使用在org.omg.CORBA包中定义的持有者(holder)类型,包括IntHolder、BooleanHolder等等。每个持有者类型都包含一个公有(!)域value,通过它可以访问存储在其中的值。
参数数量可变的方法
在JDK5.0以前的版本中,每个Java方法都有固定数量的参数。然而,现在的版本提供了可以用可变的参数数量调用的方法。
5.5 反射
反射库(reflection library)提供了一个非常丰富且精心设计的工具集,以便编写能够动态操作Java代码的程序。
能够分析类能力的程序被称为反射(reflective)。反射机制的功能及其强大:
1、在运行时分析累的能力
2、在运行时查看对象
3、实现数组的操作代码
4、利用Method对象,这个对象很像C++这类语言中的函数指针
5.5.1 Class类
在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息保存着每个对象所属的类足迹。虚拟机利用运行时信息选择相应的方法执行。
5.5.2 使用反射分析类的能力
在java.lang.reflect包中有三个类:Field、Method、Constructor分别拥有描述类的域、方法和构造器。这三个类有一个叫做getModifiers的方法,它将返回一个整数值,用不同的位开关设置描述public和static这些修饰符的使用状况。
Class类中的getFields、getMethod和getConstructors方法将分别返回类支持的public域、方法和构造器数组,其中包括超类的共有成员。Class类的getDeclareFields、getDeclareMethods和getDeclaredConstructors方法将分别返回类中声明的全部域、方法和构造器组成的数组。其中包括私有和受保护成员,但不包括超类的成员。
5.5.3 在运行时使用反射分析对象
除非拥有访问权限,否则Java安全机制只允许查看任意对象有哪些域,而不允许读取他们的值。反射机制的默认行为受限于Java的访问控制。然而,如果一个Java程序没有受到安全管理器的控制,就可以覆盖访问控制。为了达到这个目的,需要调用Field、Method或Constructor对象的setAccessible方法。
setAccessible方法是AccessibleObject类中的一个方法,他是Field、Method和Constructor类的公用超类。这个特性是为调试、持久存储和相似机制提供的。
5.5.4 使用反射编写通用的数组代码
java.lang.reflect包中的Array类允许动态地创建数组。
5.5.5 方法指针
建议仅在必要的时候,才使用Method对象,而最好使用接口和内部类。特别要重申:建议Java开发者不要使用Method对象的回调功能。使用接口进行回调会使得代码的执行速度更快,更易于维护。
5.6 枚举类
在比较两个枚举类型的值时,永远不需要调用equals,而直接使用“= =”就可以了。
enum Size
{
SMALL("S"),MEDIUM("M"),LARGE("L"),EXTRA_LARGE("XL");
private Size(String abbreviation){this.abbreviation=abbreviation;}
public String getAbbreviation(){return abbreviation;}
private String abbreviation;
}
5.7 继承设计技巧
1)将公共操作和域放置在超类
2)不要使用受保护的域。
protected机制并不能够带来更好的保护,起源于主要有两点。第一,子类集合是无限制的,任何一个人都能够由某个类派生一个子类,并编写代码以直接访问protected的实例域,从而破坏了封装性。第二,在Java程序设计语言中,在同一个包中的所有类都可以访问protected域,而不管它是否为这个类的子类。
3)使用继承实现“is-a”关系
4)除非所有继承的方法都有意义,否则不要使用继承。
5)在覆盖方法的时候,不要改变预期的行为。
6)使用多态,而非类型信息。
使用多态方法或接口编写的代码比使用对多种类型进行检测的代码更加易于维护和扩展。
7)不要过多地使用反射
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics