您的位置:首页 > 编程语言 > Java开发

《Java核心技术》复习笔记 - 第五章 继承

2014-03-03 20:20 183 查看
《Java核心技术》复习笔记 - 第五章 继承
1. 基本概念:父类和子类,超类和子类,基类和派生类
2. 继承体现的是is-a的关系,java中的所有继承都是公有继承,关键字为extends
3. 可以使用关键字super指示编译器调用超类中的方法,C++中采用Base::method()的方法。派生类的构造器不能访问子类的的私有域,必须利用基类的构造器对这部分私有域进行初始化,可以通过super实现对超类构造器的调用。使用super调用构造器的语句必须是子类构造器的第一条语句。C++中采用初始化列表初始化基类成员。
4. 多态:一个引用变量可以引用多种实际类型的现象称为多态。在运行时能够自动地选择调用哪个方法的现象称为动态绑定dynamic binding。在java中,不需要将方法声明为虚拟方法。动态绑定是默认的处理方式。如果不希望让一个方法具有虚拟特性,可以将它标记为final。C++中只有声明为virtual的函数,通过指针或引用调用时,才会触发动态绑定。
5. 如果方法是private,static,final的,编译器可以准确知道该调用哪个方法,即静态绑定。虚拟机为每一个类创建了一个方法表,列出了所有的方法签名和实际调用的方法(方法地址),动态绑定的时候,提取被引用变量实际类型,然后查找相应的方法表就行了。
6. 子类数组的引用可以直接赋值给父类数组的引用,不需要强制类型转换。但是应该避免一些错误,Manager[] managers = new Manager[10]; Employee[] staff= managers;staff[0] = new Employee(); 此时managers[0]和staff[0]引用同一个Employee对象,调用managers[0].setBonus()时,会发生意想不到的结果。
7. 子类复写父类的方法,要求保证返回类型的兼容性,即返回类型相同或为原返回类型的子类型。同时子类方法的可见性不能低于父类方法的可见性。
8. 阻止继承:final类和final方法。不允许扩展的类称为final类。类中的方法可以被声明为final类,这样子类就不能覆盖这个方法,final类中的所有方法自动地成为final方法。将一个类声明为final,不影响域。
9. 在继承链上进行向下转型时,要注意捕获ClassCastException,或者采用x instanceof Y。Java的类型转换类似C++中的dynamic_cast,但是转型失败时,抛出异常。
10. C++中用纯虚函数(尾部有=0标记)来声明一个抽象方法,而java中引入了abstract关键字。为了提高程序的清晰度,包含一个或多个抽象方法的类本身必须被声明为abstract。抽象类不能被实例化,类即使不含抽象方法,也可以被声明为抽象类。
11. Java的四种访问修饰符:private仅对本类可见,public对所有类可见,protected对本包和所有子类可见,默认对本包可见。注意java中的protected概念要比C++中的安全性差。
12. Object为所有类的超类,Object类中的equals方法用于比较两个对象状态是否相同。编写一个完美的equals方法的建议:
1) 显示参数命名为otherObject,稍后可能转换为叫做other的变量
2) 检测this和otherObject是否引用同一个对象,if(this == otherObject) return true;
3) 检测otherObject是否为null, 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比较对象域。

[code]import java.util.*;

/**
* This program demonstrates the equals method.
* @version 1.11 2004-02-21
* @author Cay Horstmann
*/
public class EqualsTest
{
public static void main(String[] args)
{
Employee alice1 = new Employee("Alice Adams", 75000, 1987, 12, 15);
Employee alice2 = alice1;
Employee alice3 = new Employee("Alice Adams", 75000, 1987, 12, 15);
Employee bob = new Employee("Bob Brandson", 50000, 1989, 10, 1);

System.out.println("alice1 == alice2: " + (alice1 == alice2));

System.out.println("alice1 == alice3: " + (alice1 == alice3));

System.out.println("alice1.equals(alice3): " + alice1.equals(alice3));

System.out.println("alice1.equals(bob): " + alice1.equals(bob));

System.out.println("bob.toString(): " + bob);

Manager carl = new Manager("Carl Cracker", 80000, 1987, 12, 15);
Manager boss = new Manager("Carl Cracker", 80000, 1987, 12, 15);
boss.setBonus(5000);
System.out.println("boss.toString(): " + boss);
System.out.println("carl.equals(boss): " + carl.equals(boss));
System.out.println("alice1.hashCode(): " + alice1.hashCode());
System.out.println("alice3.hashCode(): " + alice3.hashCode());
System.out.println("bob.hashCode(): " + bob.hashCode());
System.out.println("carl.hashCode(): " + carl.hashCode());
}
}

class Employee
{
public Employee(String n, double s, int year, int month, int day)
{
name = n;
salary = s;
GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day);
hireDay = calendar.getTime();
}

public String getName()
{
return name;
}

public double getSalary()
{
return salary;
}

public Date getHireDay()
{
return hireDay;
}

public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}

public boolean equals(Object otherObject)
{
// a quick test to see if the objects are identical
if (this == otherObject) return true;

// must return false if the explicit parameter is null
if (otherObject == null) return false;

// if the classes don't match, they can't be equal
if (getClass() != otherObject.getClass()) return false;

// now we know otherObject is a non-null Employee
Employee other = (Employee) otherObject;

// test whether the fields have identical values
return name.equals(other.name) && salary == other.salary && hireDay.equals(other.hireDay);
}

public int hashCode()
{
return 7 * name.hashCode() + 11 * new Double(salary).hashCode() + 13 * hireDay.hashCode();
}

public String toString()
{
return getClass().getName() + "[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay
+ "]";
}

private String name;
private double salary;
private Date hireDay;
}

class Manager extends Employee
{
public Manager(String n, double s, int year, int month, int day)
{
super(n, s, year, month, day);
bonus = 0;
}

public double getSalary()
{
double baseSalary = super.getSalary();
return baseSalary + bonus;
}

public void setBonus(double b)
{
bonus = b;
}

public boolean equals(Object otherObject)
{
if (!super.equals(otherObject)) return false;
Manager other = (Manager) otherObject;
// super.equals checked that this and other belong to the same class
return bonus == other.bonus;
}

public int hashCode()
{
return super.hashCode() + 17 * new Double(bonus).hashCode();
}

public String toString()
{
return super.toString() + "[bonus=" + bonus + "]";
}

private double bonus;
}

13. 使用@Override标记声明覆盖父类的方法,这样接口不一致时,编译器会报错。
14. 散列码hash code是由对象导出的一个整数值,不同对象其散列码一般不同。字符串散列码是由内容导出的,Object中提供的hashCode方法默认返回对象的存储地址。如果重新定义equals方法,就必须重新定义hashCode方法,以便用户可以将对象插入到散列表中。
15. Object的toString方法默认打印对象所属的类名和散列码。
16. Java中的对象包装器:Integer,Long,Float,Double,Short,Byte,Character,Void和Boolean,其中前6个派生自公共的超类Number。对象包装器是不可变的,一旦构造了包装器,就不允许更改包装在其中的值。同时,对象包装器还是final的,不能定义他们的子类。对象包装器会进行自动地打包和拆包。自动打包规范要求boolean、byte、char<=127,以及介于-128-127之间的short和int被包装到固定的对象中。
17. 可变参数:使用type ...,如printf(String fmt, Object... args); double max(double... values);
18. Java的反射机制:能够分析类能力的程序被称为反射。

[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: