Java 再学习 模糊的知识 (三)

继承

1. super 不是一个对象的引用,不能将 super 赋给另一个对象变量,它只是一个指示编译器调用超类方法的特殊关键字。
2. 继承并不仅限于一个层次。由一个公共超类派生出来的所有类的集合被称为继承层次。在继承层次中,从某个特定的类到其祖先的路径被称为该类的继承链。
3. 一个用来判断是否应该设计为继承关系的简单规则,就是“is-a”规则,它表明子类的每个对象也是超类的对象。“is-a”规则的另一种表述法是置换法则。它表明程序中出现超类对象的任何地方都可以用子类对象置换。
4. 不允许扩展的类被称为 final 类。如果在定义类的时候使用了final 修饰符就表明这个类是 final 类。类中的特定方法也可以被声明为 final 。如果这样做,子类就不能覆盖这个方法( final 类中的所有方法自动地成为 final 方法,域不会自动成为 final 域)。
5. 进行类型转换的原因:在暂时忽视对象的实际类型之后,使用对象的全部功能。因此,要养成这样一个良好的程序设计习惯:在进行类型转换之前,先查看一下是否能够成功地转换。这个过程简单地使用 instanceof 运算符就可以实现。
//只能在继承层次内进行类型转换
//在将超类转换为子类之前,应该使用 instanceof 进行检查
//在一般情况下,应该尽量少用类型转换和 instanceof 运算符
if (staffs[0] instanceof Manager) {
	Manager manager2 = (Manager) staffs[0];
	System.out.println(manager2.getBonus());
}
6. 抽象类不能被实例化。但可以定义一个抽象类的对象变量,但是它只能引用非抽象子类的对象。
7. Java 语言规范要求 equals() 方法具有的特性:
  • 自反性: 非空引用 x,x.equals(x) 为 true;
  • 对称性: 引用 x,y,若 x.equals(y) 为 true 则 y.equals(x) 也为 true;
  • 传递性: 引用 x,y,z,若 x.equals(y) 为 true ,y.equals(z) 为 true ,则 x.equals(z) 也为 true ;
  • 一致性: 如果 x 和 y 引用的对象没有发生变化,反复调用 x.equals(y) 应该返回同样的结果;
  • 对于任意非空引用 x ,x.equals(null) 应该返回 false 。
8. 编写一个完美的 equals() 方法的建议:

1)显式参数命名为 otherObject ,稍后需要将它转换成另一个叫做 other 的变量;
2)检测 this 与 otherObject 是否引用同一个对象:if ( this == otherObject ) return true; 这条语句只是一个优化。实际上,这是一种经常采用的形式。因为计算这个等式要比一个一个地比较类中的域所付出的代价小得多。
3)检测 otherObject 是否为null ,如果为 null ,返回 false 。这项检测是很必要的。if (other0bject = 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) other0bject;
6)现在开始对所有需要比较的域进行比较了。使用 == 比较基本类型域,使用 equals 比
较对象域。如果所有的域都匹配,就返回true;否则返回false。
return field1 == other. field1
&& 0bjects. equals(field2, other. field2)

如果在子类中重新定义 equals ,就要在其中包含调用 super. equals(other)

9. 有关 hashCode 的几个知识点:
  • 散列码 (hashcode) 是由对象导出的一个整型值。是没有规律的。如果 x 和 y 是两个不同的对象,x.hashCode( ) 与 y.hashCode( ) 基本上不会相同。
  • 字符串的散列码是由内容导出的。
//hashCodeDisplay
//2225373   2225373
//80223657   2225373
public static void hashCodeDisplay() {
	String a = "Good";
	String b = "Good";
	System.out.println(a.hashCode()+"   "+b.hashCode());
	a = "Study";
	System.out.println(a.hashCode()+"   "+b.hashCode());
}
  • Object 类的默认 hashCode 方法导出的是对象存储地址
  • 如果重新定义 equals 方法,就必须重新定义 hashCode 方法,以便用户可以将对象插入到散列表中。equals 与 hashCode 的定义必须一致:如果 x.equals(y) 返回true,那么 x.hashCode( ) 就必须与 y.hashCode( ) 具有相同的值。例如,如果用定义的Employee.equals 比较雇员的 ID ,那么 hashCode 方法就需要散列 ID ,而不是雇员的姓名或存储地址。
  • 需要组合多个散列值时,可以调用 Objects.hash 并提供多个参数,这个方法会对各个参数调用 Objects.hashCode ,并组合这些散列值。
10. 有关 toString() 的几个知识点:
  • 通过调用 getClass( ).getName( ) 获得类名的字符串,而不要将类名硬加到 toString 方法中。
  • 随处可见 toString 方法的主要原因是:只要对象与一个字符串通过操作符“+”连接起来,Java 编译就会自动地调用 toString 方法,以便获得这个对象的字符串描述。在调用 x.toString( ) 的地方可以用 “”+x 替代。这条语句将一个空串与 x 的字符串表示相连接。这里的 x 就是x.totring()。与 toString 不同的是,如果 x 是基本类型,这条语句照样能够执行。
11. 一旦能够确认数组列表(ArrayList)的大小不再发生变化,就可以调用 trimToSize 方法。这个方法将存储区域的大小调整为当前元素数量所需要的存储空间数目。垃圾回收器将回收多余的存储空间。一旦整理了数组列表的大小,添加新元素就需要花时间再次移动存储块,所以应该在确认不会添加任何元素时,再调用 trimToSize。
12. 装箱和拆箱是编译器认可的,而不是虚拟机。编译器在生成类的字节码时,插入必要的方法调用。虚拟机只是执行这些字节码。
13. 参数数量可变的方法
//Nicholas is a Java Programmer.
//He is a greenhand.
public static void main(String[] args) {
	//parameter variable method
	sentenceDisplay("Nicholas ","is ","a ","Java ","Programmer.");
	sentenceDisplay("He ","is ","a ","greenhand.");
}

//parameter variable method
public static void sentenceDisplay(String...args) {
	StringBuilder sb = new StringBuilder();
	for (String string : args) {
		sb.append(string);
	}
	System.out.println(sb.toString());
}
14. 枚举类及其常用方法

enum

15. 继承设计的技巧:
  • 将公共操作和域放在超类
  • 不要使用受保护的域(非绝对)
  • 使用继承实现 “is-a” 关系
  • 除非所有继承的方法都有意义,否则不要使用继承
  • 在覆盖方法时,不要改变预期的行为
  • 使用多态,而非类型信息
  • 不要过多地使用反射

学习整理自《Java 核心技术 卷一 基础知识》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章