java核心技术总结四
第五章总结:
1、java用关键字extends代替了C++中的冒号(:),在java中所有的继承都是公有继承,没有c++中的私有继承和保护继承。
2、super和this两个关键字的比较
super和this的引用不是类似的概念,因为super不是一个对象的引用,它只是一个指示编译器调用超类方法的特有关键字。
3、多态定义:一个对象变量可以引用多种实际类型的现象。
??? 动态绑定:在运行时能够自动地选择调用哪个方法的现象。
在java中不需要将方法声明为虚拟方法,动态绑定就是默认的处理方法
4、可以将一个子类的对象赋给超类变量,但是不能将一个超类的引用赋给子类变量。
在java中,子类数组的引用可以转换为超类数组的的引用,但是这是非常忌讳的,最好不要这样用。至于为什么,下面代码:
Manager类是Employee类的子类。
Manager[] managers=new Manager[10];Employee[] staff=managers;staff[0]=new Employee("aa","123");上面的操作会使staff和manager引用同一个对象。这显然会发生问题。因为当调用managers[0].setBonus(100)的时候会导致调用一个不存在的实例域,进而搅乱相邻存储空间的内容。
5、动态绑定的操作过程:
(1)、编译器查看对象的声明类型和方法名;
(2)、编辑器查看调用方法时提供的参数类型;
(3)、如果是private方法,static方法final方法或者构造器,编译器可以准确的指导应该调用哪一个方法,即所谓的静态调用。
(4)、当程序运行,并且采用动态绑定调用方法时,虚拟机一定调用与x所引用对象的实际类型最合适的那个类的方法。
(5)、如果将一个类声明为final,只有其中的方法会自动地成为final,而不包含域。
6、如果一个方法没有被覆盖并且很短,编译器就能够对它进行优化处理,这个过程被称为内联。例如内联调用e.getName()可以替换为e.name域。
7、抽象:
包含一个或多个抽象方法的类本身必须被声明为抽象的;
类即使不含抽象方法,也可以将类声明为抽象类;
抽象类不能实例化,但是可以创建一个ie具体子类的对象。即可以定义一个抽象类的对象变量,但是只能引用非抽象子类的对象。
在c++中,有一种在尾部用=0标记的抽象方法,被称为纯虚函数。
8、java中的protected概念要比c++中的安全性差。
java中的默认和protected的概念不一样
protected是对本包和所有的子类可见
默认是只对本包可见。
9、在C++中没有根类,不过,每个指针都可以转换为void*。
在java中Object类是所有类的最终祖先。
10、equals方法
(1)、在Object类中,equals方法判断两个对象是否具有相同的引用。
(2)、java语言规范要求equals方法具有特性:自反性,对称性,传递性,一致性,对于任何的非空引用,调用x.equals(null)应该返回false。
(3)、编写完美的equals的步骤:
1)、显式参数命名为otherObject,
2)、检测this与otherObject是否引用同一个对象 if(this == otherObject) return true;
3)、检测ohterObject是否为null,如果为null,则返回false。
4)、比较this和otherObject是否属于同一个类。if(getClass() !=otherObject.getClass()) return false;
5)、将otherObject转换为相应的类类型变量
6)、使用==比较基本类型,使用equals比较对象域。==也可以应用于对象包装器对象,只不过检测的是对象是否指向同一块存储区域。
(4)、要覆盖equals方法采用的方式是public boolean equals(Object obj){}
?11、Hashcode()方法
(1)、如果x和y是两个不同的对象,则x.hashcode()和y.hashcode()基本上不会相同。
(2)、String字符串的散列码是由内容导出的,StringBuffer类中没有定义hashCode方法,它的散列码由Object类的默认hashCode方法导出的对象存储地址。
(3)、如果重新定义了equals方法,就必须重新定义hashCode方法。
12、toString方法
(1)、强烈建议为自定义的每一个类增加toString方法。有助于调试。更好的方式是采用日志。比如:Logger.global.info("Current position = "+position);
(2)、写一个toString方法的例子
class Manager extends Employee{ public String toString(){ return super.toString()+getClass().getName+"[bonus="+bonus+"]"; } }(3)、数组的toString()方法: Arrays.toString();Arrays.deepToString()?
13、ArrayList泛型数组列表
(1)、ArrayList是一个采用类型参数的泛型类,它是"自适应大小"的集合,在java se 5.0后的版本中,没有后缀<...>仍然可以使用ArrayList,它被认为是一个删去了类型参数的"原始"类型。
? 在java的老式版本中,程序员使用Vector类实现动态数组,不过ArrayList类更加有效。
(2)、一旦能够确认数组列表的大小不再发生变化,就可以采用trimToSize方法,这个方法将存储区域的大小调整为当前元素数量所需要的存储空间数目。
(3)、ensureCapacity方法是在确保数组列表在不重新分配存储空间的情况下就能够保存给定数量的元素时采用。
(4)、Arraylist类的尖括号中的类型参数不允许是基本类型。因而由于每个值分别包装在对象中,所有ArrayList<Object>的效率远远低于int[]数组。所以应该使用ArrayList构造小型集合。
int n=list.get(i)等价于int n=list.get(i).intValue();
(5)、打包和拆包是编译器认可的,而不是虚拟机。
(6)、包装器类型不能实现修改数值参数。如果想编写一个修改数值参数值的方法,需要使用org.omg.CORBA包中定义的持有者类型,包括IntHolder、BooleanHolder等等。
14、枚举类
(1)Size.SMALL.toString()方法返回字符串"SMALL",(Size)Enum.valueOf(Size.class,"SMALL")返回SMALL。
也就是说toString()方法和valueOf方法是两个相逆的方法
(2)、ordinal方法返回enum声明中枚举常量的位置,位置从0开始计数。
15、反射
(1)、能够分析类能力的程序被称为反射。
(2)、获得类名的方法有:
1)、使用Object类中的getClass方法
2)、使用getName方法
3)、调用静态方法forName
Double[].class.getName()返回"[Ljava.lang.Double;"
(3)、在java.lang.reflect包中有三个类Filed,Method和Constructor分别用于描述类的域,方法和构造器。
(4)、可以采用method对象实现C语言中函数指针的所有操作。如果在调用方法的时候提供了一个错误的参数,则invoke方法将会抛出一个异常。
16、继承设计的技巧
(1)、将公共操作和域放在超类
(2)、不要使用受保护的域
(3)、使用继承实现"is-a"?关系
(4)、除非所有继承的方法都有意义,否则不要使用继承
(5)、在覆盖方法时,不要修改预期的行为
(6)、使用多态,而非类型信息
(7)、不要过多地使用反射