1、概述
类层次的根类,每个类直接或间接继承Object类,所有对象(包括数组)都实现了这个类的方法(java.lang)
2、构造方法
public Object(){}
//所有子类都默认访问父类的无参构造,是因为所有子类的共同父类Object,只有一个构造方法,并且是一个空构造
3、成员方法
以下方法均用此代码作为示例:
class Student{
public String name;
public int age;
public Student(){};
public Student(String name,int age){
this.name = name;
this.age = age;
}
}
public int hashCode()
//返回对象的哈希码
注意:hashcode是对象的内部地址经过地址计算法转换过来的,并不是实际地址
Student s1 = new Student();
Student s2 = new Student();
Student s3 = d1;
System.out.println(s1.hashCode()+"--"+s2.hashCode()+"--"+s3.hashCode());
//这里s1和s3的哈希地址值一样,这两个引用指向的是一个对象
public final Class getClass()
//返回此Object的运行时类,返回值是一个类名,其实返回的是该类的对象
注意:Class:保存字节码文件的类
Student s1 = new Student();
Class c = s1.getClass();
String str = c.getName(); //getName()方法是Class类的,public String getClass
System.out.println(str); //打印出的是当前正在运行类的全路径名称(包名和类名)
等效于
//用链式编程改进
String str =d1.getClass.getName(); //对象调完方法后的结果仍是一个对象,可继续调用
System.out.println(str);
public String toString()
//返回该对象的字符串表示
源码:
public String toString(){
return getClass().getName()+'@'+Interger.toHexString(hashCode);
}
从源码种可以看出,返回的是一个对象的运行时全路径+@+以十六进制输出的哈希地址,
其实这个结果是没有什么意义的。建议所有的子类都重写此方法。
//重写此方法,就是把类中所有的成员变量值组成返回
public boolean equals(Object obj)
//默认比较的是对象的地址值是否相同,意义不大,一般子类要重写此方法
源码:
public boolean equals(Object obj){
return this == obj;
}
子类重写比较对象的内容:
第一版:
public boolean equals(Object obj){
//在本类中比较的是对象的name和age,而name又是引用类型的,不能用==
//通过查手册,String中重写了equals,比较的是字符串内容
//由于obj是父类的引用,要调用的是子类特有的name和age,所以必须要向下转型
Student s = (Student)obj;
if (this.name.equals(s.name) && this.age == s.age){
return true;
} else {
return false;
}
}
问题:考虑到如果接收的是同一对象的引用,其实没必要浪费转型的时间
第二版:提高效率
public boolean equals(Object obj){
if(this == obj){
return true;
}
Student s = (Student) obj;
return this.name.equals(s.name) && this.age == s.age;
}
问题:如果传过来的独享不是Student类里的呢?转型就会报错啊,也就是
Demo d = new Demo();
s1.equals(d);//由于Object类是所有类的父类,所以什么类型的独享都可以传过来(多态),这样下一步转型就会有问题,
第三版:提高程序的健壮性
public boolean equals(Object obj){
if(this == obj){
return true;
}
//为了提高健壮性
//先判断以下,该对象是否是该类的:对象名 instanceof 类名
if(! (obj instanceof)Student)){
return false;
}
Student s = (Student) obj;
return this.name.equals(s.name) && this.age == a.age;
}
对比底层的实际实现
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(obj == null){
return false;
}
//同一个类的字节码文件只有一个并且只加载一次
if(getClass() != obj.getClass)){
return false;
}
Student other = (Student) obj;
if(age != other){
return false;
}
if(name == null){
if(other.name != null)
return false;
} else if(!name.equals(other.name)){
return false;
}
return true;
}
protected void finalize()
//当垃圾回收器确定不存在对该对象的更多引用时,由
对象的垃圾回收器调用此方法,用于垃圾回收,但是什么时候回收并不确定
protected Object clone()
//创建并返回对象的一个副本(protected修饰的方法可以在其子类访问,不能在其他类访问,所以要用这个方法需要重写的)
//重写该方法必须实现 Cloneable接口,以指示Object.clone()方法可以合法的对该类实例进行字段复制
//并且这个接口是标记接口,并没有方法,告诉我们实现该接口的类就可以实现对对象的复制了。
eg:
//创建学生对象
Student s = new Student();
s.setName("小黑");
s.setage(20);
//克隆学生对象
Student obj = s.clone();
Student s2 = (Student)obj;
//以前的做法
student s3 = s;
//这两种做法有区别哦(一个是两个引用指向一个对象,另外一个是浅克隆,其实还有一个深克隆,因为一个类有子父关系、接口,继承体系很庞大)