- HashCode
new Double(double d)
Double 类用来生成一个包含double数值的对象,可以进行许多操作,例如生成哈希码:
new Double(12,7).hashCode
注意:如果重定义equals(),则需要冲定义hashCode()
生成哈希码可以用x.hashCode(),不过更建议使用Object.hashCode(x)。其中x为要生成哈希码的对象。
Object.hashCode(x) : null安全的哈希码。如果对象是null,返回0,如果不是null,则调用hashCode
Object.hash(par 1, par 2, …)还可以组合多个哈希值,例如:
Object.hash(name, salary, hireDay)
equals与hashCode的定义必须一致,如果x.equals(y)返回true,则x.hashCode()与y.hashCode()的值必须一样。例如,如果定义Employee.equals比较雇员ID,则hashCode方法需要求ID的哈希码,而不是姓名,薪水的哈希码。
2.对于一个reference variable,Java编译器按照它声明的Type工作。如果a是SuperClass类型变量,b是subClass变量,将b赋值给a,则通过a不能调用b的方法。需要将b进行类型转换才可以。
3.类型转换
下转换,需要通过(Type)运算符,例如:
SubClass b = new SubClass();
SuperClass a = b;
SubClass c = (SubClass) a; //下转换
对于上转型,不需要强制类型转换符,因为子类对象肯定可以看做父类对象:
SubClass b =new SubClass();
SuperClass a = b;//上转换
4.多态:一个reference variable可以指示多种实际类型的现象。在运行时虚拟机能自动的选择调用哪个方法的现象称为动态绑定。
动态绑定: 实例方法(instance method)与引用变量(Reference variable)实际引用的对象的方法绑定,这种绑定是在运行时有Java虚拟机动态决定的。虚拟机一定调用reference variable所引用对象实际类型最合适的那个类的方法。例如:
public class A {
void method () {System.out.pritnln("Base");}
void test() {method();}
}
public class B extends A {
void method() {System.out.println("Sub");}
public static void main(String[] args) {
new A().test();//调用A的method方法
new B().test();//调用B的method方法
}
}
运行结果为:
Base
Sub
通过上例,可以体会到,在runtime时,当通过B类的instance去调用一系列instance method(包括一个方法调用另一个方法),将优先和B类本身包含的instance method动态绑定,如果B类没用定义这个instance method,才会与从父类A中继承来的实例方法动态绑定。
5.静态绑定:指在编译阶段就已经绑定。
(1) 静态方法与Reference variable所声明的类型的方法绑定,这种绑定属于静态绑定。
(2)成员变量(静态和实例变量)与引用变零所声明的类型的成员变量绑定。
6.子类中定义的方法不能访问父类的private域,可以通过继承父类中的方法来访问,例如:
class Employee {
private name;
public String getName() {
return name
}
}
class Manager {
System.out.println (name) //不可以直接访问name,因为name是Employee class的private field
System.out.println (getName());//通过调用继承的方法访问name,getName又称为接口
}
7.super和this
如果子类需要调用超类的方法,可以用super实现,super只是一个指示编译器调用超类方法的关键字。例如:
class Employee {
private double salary;
public double getSalary() {
return salary
}
}
class Manager extends Employee {
private double bonus;
public double getSalary() {
double baseSalary = super.getSalary();//调用Employee类的方法,获得salary的值
return baseSalary + bonus;
}
由于Manager类的构造器不能访问Employe类的私有域,所以必须利用Employee的构造器对私有域初始化,子类构造器第一行为:super()调用超类的构造器。
this是当前对象的引用,例如:
class Employee {
private double salary;
public void setSalary(double salary) {
this.salary = salary;//this.salary表示 class field, 等号右边的salary为method的参数
}
8.置换法则:程序中出现超类对象的任何地方都可以用子类对象替换,例如:
Employee e = new Employee();
e = new Manager();
9.equals方法:
(1) 为了防备比较对象可能为null的情况,需要使用Objects.equals方法,如果两个参数都为null,则Objects.equals(a, b)返回true,如果其中一个为null,则返回false; 如果两个参数都不为null,则调用a.equals(b)。程序示例:
return Object.equals(name, other.name)
&& salary == other.salary
&& Objects.equals(hireDay, other.hireDay);
在子类中定义equals方法,首先需要调用超类的equals,如果检测失败,对象肯定不相等,如果超类中的域都相等,就需要比较子类中的实例域。例如:
class Manager extends Employee {
public boolean equals (Object oherObject) {
if (!super.equals(otherObject) return false;
Manager other = (Manager) otherObject;
return bonus == other.bonus;
}
}
(2) 通过getClass()来获得对象所属的类。通过instanceof来判断对象是否类的实例,子类对象是超类的实例。
if ((new Manager()) instanceof Employee) //true,Manager是Employee的子类
if ((new Employee() instanceof Manager) //false, Employee是Manager的超类,不是Manager的实例
(3) 如果子类定义自己的equals方法,则通过getClass()方法判断是否属于同一类。如果equals方法由超类定义,则通过instanceof,判断子类是否继承于超类,然后调用equals方法。
(4)@Override判断是否进行覆盖,例如:
@Override public boolean equals (Object other)
如果没有覆盖超类方法,编译器会提示错误。
10.Override超类方法时,子类中方法的名称和参数必须和被覆盖方法相同,但是返回值可以不同。例如:
class Employee {
...
public Employee creatStaff () { //该方法返回一个Employee对象
}
class Manager {
...
public Manager creatStaff () { //覆盖Employee中的creatStaff方法,但是返回Manager对象
}
10.toString方法:将对象以字符串表示。
每个class都应该定义自己的toString方法,只要对象与一个字符串通过操作符 “+” 连接起来,Java编译器就会自动的调用toString方法,以便获得对象的字符串描述。toString方法例子如下:
class Employee {
...
@Override public String toString() {
return "Employee[name="
+ getName()
+ ",Salary="
+ getSalary()
+ ",hireDay="
+ getHireDay()
+ "]";
}
子类可以继承超类的toString,这样就不需要重复编写代码,例如:
class Manager extends Employee {
...
@Override public String() {
return super.toString() + "[bonus =" + getBonus() + "]";
}
}
Object类定义了toString方法,用来打印输出对象所属的类名和散列码。
数组的输出:数组继承了Object类的toString方法,如果直接打印数组,会输出数组的类名和散列码。例如:
int[] num = {1,2,3};
System.out.println ("" + num);
输出:[I@1a46e30
想要输出数组元素,需要调用Array类中的toSting方法,例如:
System.out.println(Arrays.toString(num));
输出:[1,2,3]
11.ArrayList类
初始化:ArrayList var = new Array<>();
例如:ArrayList staff = new Array<>();
可以指定初始内部数组的大小,例如:
ArrayList staff = new Array<>(100); //初始内部数组有容纳100个元素的潜力,但是如果没有元素加入,它是空的。
ArrayList的机制:ArrayList维护了一个内部数组,通过add方法往里面增加元素,如果内部数组满了,就会自动开辟一个更大的数组,将原内部数组的元素复制过去。如果知道元素的数量,事先指定内部数组的大小,以容纳全部元素,则可以省去新建数组和复制的操作。