继承
一. 继承的第一步
1. 语法:
class child extends father{
}
2. 关于super()
除非子类构造函数满足于超类缺省构造函数的设置,否则它必须用适当参数显式调用super方法。调用super必须位于子类构造函数的第一行。
public void raiseSalary(double byPercent){
Day today = new Day();
double bonus = 0.5 * (today.getYear() – hireYear() );
super.raiseSalary(byPercent + bonus);
}
3. C++注释:
Java 和 C++ 中的继承相类似。
Java 不支持多继承。
4. 使用子类
可以将子类对象赋值给超类变量
如:
Employee[] staff = new Employee[3];
Manager boss = new Manager(“Cral Cracker” , 75000 , new Day(1987,12,15));
staff[0] = boss;
// Employee 是父类 ,Manager 是子类 ,staff[0] 和 boss 指向内存的同一区域。然而,编译器只认为staff[0]是雇员对象。
子类对象可以传给任何以超类为参数的方法。一般反过来不成立,通常不能把超类对象赋给子类对象。
如,下列赋值不合法:
boss = staff[0] ; //错
子类对象至少和超类对象有一样多的数据项。因为继承时,只能增加域,不能删除域。
5. 多态性
(1)子类检查是否具有同名和完全相同参数的方法。如有,就调用该方法。否则,Java 将到父类中寻找同名和同参数的方法。如果有,就调用该方法。
(2)如果子类中定义的方法与祖先类中的方法同名,并且参数表也相同。则该子类方法隐藏了祖先类中的同名方法。
(3)方法的名字和参数表通常称为方法的签名。在Java 中,若类的方法或者超类和子类方法具有相同的签名而返回类型不同,将造成编译时错误。
例如,不能在雇员类(父类)中有个void raiseSalary(double) 而在经理类(子类)又有int raiseSalary(double) 方法
(4)实现多态性的关键是late binding 即后期绑定。
(5)C++ 注释:在Java中,不必将方法声明为虚方法,这是缺省行为。如果不想让某方法为虚方法,可给该方法加上final修饰符。
6.禁止继承:final
(1)有时候,用户需要防止别人从自己的类中派生出新类。不能成为父类的类叫做最终类。
final class Card{
}
(2) 也可以把类的方法说明为最终的方法。若这样作的话,任何子类都不能覆盖该方法(最终类的所有方法都是自动成为最终方法)。
(3) 一个类或方法被说明为最终的原因如下:
高效性 ――― 动态联编比静态联编需要更多的额外开销,因此虚方法运行得比较慢。
安全性
(4) 在C++ 中,没有办法阻止派生类覆盖成员函数。在C++ 中,可编写出不能再被派生的类,但这需要很难的技巧。
二.类型转换
1. 语法
Manager boss = (Manager) staff[0];
良好的编程风格是在类型转换之前验证某对象是否是另一个类的对象实例。这由instanceof操作符完成。例如:
if (staff[1] instanceof(Manager)) {
boss = (Manager) staff[[1];
}
Window w = (Window) staff[1]; 将不成功,因为窗口类不是雇员类的子类。
2. 注意
实际上,进行类型转换通常不是个好主意。
三.抽象类
1. 语法
public abstract class Message{
public abstract void play( ){
}
}
抽象类可有某些具体数据和方法。关键是,除普通方法外,抽象类至少应含有一个抽象方法。抽象方法要求所有从抽象类派生的非抽象类都将实现该抽象类方法。
******关于捕捉异常******
语法:
try{
可能抛出异常的代码
}
catch(异常类型 e){
应急操作
}
说明:
异常是个复杂的问题,发生异常时,忽略异常并不是好的作法,Java 和 C++ 的异常机制是相似的。
四. 接口
1. 使用接口的原因:
Java 设计者选择接口而非多继承是因为多继承使编译器变得非常复杂(如C++), 或效率非常低(如Eiffel), 接口还允许在Java 中实现”回调函数”。
2. 定义接口:
例如:要创建一个名为可排序类的接口,任何要排序的类均可使用该接口。
public interface Sortable{
public int compare(Sortable b);
}
3. 实现接口:
继承在前,接口在后
class Title extends Rectangle implements Sortable{
public int compare(Sortable b){
Tile tb = (Tile) b;
Return z – tb.z
}
private int z;
}
4.接口特性:
接口不能用new 来实例化
Sortable x = new Tile(……);
Tile y = new Tile(……);
还可以扩展接口以创建另一个接口。这就形成多个接口的继承链。
public interface Moveable{
public void move(double x , double y);
}
public interface Powered extends Moveable{
public String poweredSource();
}
尽管不能在接口里定义实例域,但可定义常量。
如:
public interface Powered extends Moveable{
public String poweredSource(PoweredVehicle);
public final int speedLimit = 95;
}
类可实现多个接口。这在定义类行为时,极为方便,适应性极强。
Java 有个内带重要接口,名为可复制类(Cloneable)接口。如果某类实现了可复制接口,对象类中的clone 方法就可对该类的对象进行位拷贝。若要让类具有可复制性,则应实现接口Sortable.
5. 接口和回调
在Java 里,接口是实现回调函数的唯一方式
五.原始超类 Object类
1. Object 类
对象类是最原始的基类,Java 里的每个类都扩展对象类, 一般不必写下面代码:
class Employee extends Object
如果未显式声明某类的父类,则其父类即为Object类。
2. API 关于Object类的描述
boolean equals(Object obj)
方法测试某对象是否等于另一对象,即判断两个对象是否指向内存的同一区域
Java 层中的其他类为了有效地比较,可自由覆盖equals 方法。用户类中经常需要覆盖equals 方法
Object clone( )
创建对象的复本。 Java 为新实例分配内存,并且将当前类所占内存中的内容拷贝到新实例的内存中。
String toString( )
返回表示当前对象值的字符串。为了打印类的当前状态,几乎所有的类都覆盖该方法。
可以用 ”” + x 代替x.toString( )两者效果完全相同。
3. 对象包装类
所有的基本类型都有相应的类。例如,整数类Integer 与基本类型int 相对应。这些类型常称为对象包装类。
包装类:
4个由数字类Number派生:整数类Integer 长整数类 Long 浮点数类 Float 双精度类Double
字符类 Character 布尔类 Boolean
包装类是最终类,即不能再被继承。
将字符串转化成整数int x = Integer.parseInt(s);
将字符串转化成双精度 double x = new Double(s).doubleValue( );
注意:
在实际编程中,必须处理字符串中的前导或结尾空格,或者字符串中的非数字字符。正确用法如下:
try{
x = new Double(s).doubleValue( );
}
catch(NumberFormatException e){
x = 0;
}
java.lang.Integer
int intValue( ) 返回该整数类对象的整数值
static String toString(int i) 返回代表10进制整数i的新字符串对象。
static int parseInt(String s) 返回整数的值
static Integer valueOf(String s) 返回新的整数对象
六.类定义类, 即Class 类
1. 联合使用forname 和newInstance 方法,可根据存储在字符串里的类名创建一个对象。
String s = “Manager”;
Manager m = (Manager)Class.forName(s).newInstance();
2. System.out.println(e.getClass().getName() + “ ” + e.getName());
如果e是雇员,则打印 Employee Harry Hacker
如果e是经理,则打印 Manager ssHarry Hacker
3. API 注释:java.lang.Class
String getName() 返回类名
Class getSuperclass() 返回该类的超类,也是个Class对象
Class [] getInterfaces() 返回Class 对象的数组,该数组指定了该类实现的接口
boolean isInterface() 如果该类是个接口,则返回真,否则返回假。
String toString() 返回类或接口的名字。
Static Class forName(String className) 返回该类的新实例
七.受保护的访问protected
1. C++注释:
在C++中,只有子类才可以访问protected 域,而Java 中,所有子类以及在同一包中的其他类是可以访问protected域的。
2. clone方法是protected方法
3.下面列出Java的四种访问修饰符,它们控制可见性。
(1)只有类能看见 ------------ 私有private
(2)Java 环境可见 ------------ 公有public
(3)包和所有子类可见 ------------ 保护protected
(4)包可见 ------------ 缺省情况,没有修饰符
八.关于继承的设计提示
1. 公共操作和公共域归入超类
2. 用继承模拟“是“关系
3. 不要用继承,除非所有的继承方法都可用
4. 使用多态性,而不用类型信息
每当发现下列代码时,
if(x is of type1) action1(x);
else if (x is of type2) action2(x);
就应考虑使用多态性。给type1和type2定义一个公共父类或者接口,action( )为方法,然后只需调用:
x.action( );