Object类:Java中lang包的类,是类层次结构的根类,每个类都使用Object作为超类。所有对象(包括数组)都实现这个类的方法。
Object类所含有的方法
- clone()
- equals(Object obj)
- finalize()
- getClass()
- hashCode()
- notify()
- notifyAll()
- toString()
- wait()
- wait(long timeout)
- wait(long timeout, int nanos)
boolen | equals(Object ob) : 指示其他某个对象是否与此对象"相等"。
(1)== 运算符
例如:
public static void main(String[] args){A a = new A();A b = a;A c = b;System.out.println( a == c);System.out.println( b == c);
}class B{}
class A extends B{}
创建了一个A对象,现在有一个a引用,指向了A对象,再有一个b引用,指向了A对象,最后再创建一个c引用也指向A对象,现在用 == 号来比较a与c,而由上述概念得知:== 符号在比较引用类型时,比较的是它们所指向的地址值,而明显a与c指向的都是A对象,即地址值相同,所以a与c比较后返回的是true,同理b == c返回的也是true。
现在增加一个判断
B bObj = a;
Sysout.println(bObj == c);
这时创建一个向上转型的对象,而此时bObj指向的也是A对象,所以最后比较的地址值与c依然相等,最后输出的结果也是true。
(2)equals方法
equals
String类的equals方法(JDK源码)
//把Object的equals方法重写了,变成了比较两个字符串值是否相同
if(anObject instanceof String){//判断类型String anotherString = (String)anObject; //向下转型int n = value.lenghth;if(n == anotherString.value.length){ //如果长度相同char v1[] = value;char v2[] = anotherString.value;int i = 0;while(n-- ! = 0){ //一个一个比较字符if(v1[i] != v2[i])return false;i++;}return true; //如果两个字符串的所有字符都相等,则返回true}
}
return false //如果比较的不是字符串,则直接返回false
Object类的equals方法(JDK源码)
//Object 的 equals 方法默认就是比较对象地址是否相同
//也就是判断两个对象是不是同一个对象。
public boolean equals(Object obj){return (this == obj);
}
Integer类的equals方法(JDK源码)
public boolean equals(Object obj){if(obj instanceof Integer){return value == ((Integer)obj).intValue();}return false;
}Integer integer1 = new Integer(1000);
Integer integer2 = new Integer(1000);
System.out.println(integer1 == integer2); //false
System.out.println(integer1.equals(integer2)); //true
● equals方法练习
实例1
判断两个Person对象的内容是否相等,如果两个Person对象的各个属性值都一样,则返回true,反之false。
创建Person类
class Person{private String name;private int age;private char gender;public Person(String name, int age, char gender) {this.name = name;this.age = age;this.gender = gender;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public char getGender() {return gender;}public void setGender(char gender) {this.gender = gender;}
}
创建test类
如果现在在主方法里直接调用equals方法,则调用的是Object类中的equals方法,因为Person没有继承任何类,默认继承的是Object类,而Object类中的equals方法相当于 “==” 来判断,比较的是地址值,很明显现在创建了两个对象,ps1和ps2,直接对比的话肯定返回的值是false,显然和我们想要的true不同。
public class test {public static void main(String[] args) {Person ps1 = new Person("jack",19,'男');Person ps2 = new Person("jack",19,'男');System.out.println(ps1.equals(ps2)); //false}
}
那如何得到正确的结果?那就是在Person中重写Object 的 equals方法。
在Person中重写Object的equals方法
//重写Object的equals方法public boolean equals(Object obj){ //这里的Object obj指的是输出语句中传入的ps2//判断如果比较的两个对象是同一个对象,则直接返回trueif(this == obj){ //这里的this指的是ps1return true;}//类型判断if(obj instanceof Person){ //是Person,才进行比较//向下转型,因为现在需要得到obj的各个属性Person p = (Person) obj;return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;}//如果不是Person,则直接返回falsereturn false;}
实例2
看下列代码,分析输出的值为多少?
class Person{ //类 public String name; }
主方法
Person p1 = new Person();
p1.name = "ccc";Person p2 = new Person();
p2.name = "CCC";System.out.println(p1 == p2);
System.out.println(p1.name.equals(p2.name));
System.out.println(p1.equals(p2));String s1 = new String("asdf");String s2 = new String("asdf");
System.out.println(s1.equals(s2));
System.out.println(s1 == s2);
第一个输出语句
p1与p2的比较,由于是使用"==",所以比较的是地址值,而此时p1、p2分别是new出来的,并不是同一个对象,所以最后的结果为false
System.out.println(p1 == p2); //false
第二个输出语句
p1.name是字符串,已经把equals方法重写了,所以p1与p2比较的就是内容,显然内容一直,所以得到的结果应为true
System.out.println(p1.name.equals(p2.name)); //true
第三个输出语句
由于p1与p2都是自定义的类(Person),而此时的Person类中并没有重写equals方法,那么使用的就是他的父类Object的equals方法,所以比较的还是两者的地址值,显然最后的结果为false
System.out.println(p1.equals(p2)); //false
第四个输出语句
由于创建的是String类型的对象,必然使用的是String类重写的equals方法,所以两者比较的是内容的差异,显然二者都是一致的,最后的结果为true
System.out.println(s1.equals(s2)); //true
第五个输出语句
显然两者比较的是地址值,指向的不是同一个对象,所以最后的结果为false
System.out.println(s1 == s2); //false
运行结果
● 实例3
看下面的代码输出的是什么值?
int it = 65;
float fl = 65.0f;
System.out.println("65和65.0f是否相等? " + (it == fl));
char ch1 = 'A'; char ch2 = 12;
System.out.println("65和 'A' 是否相等? " + (it == ch1));
System.out.println("12和ch2是否相等? " + (12 == ch2));String st1 = new String("hello");
String st2 = new String("hello");
System.out.println("str1和str2是否相等? " + (str1 == str2));System.out.println("str1是否equals str2?" + (str1.equals(str2)));
System.out.println("hello" == new java.sql.Date());
false,false,true,true,true,true
第一个输出语句
由于是"==",所以判断的是值是否相等,而一个是int类型,一个是float类型,判断时自动转换,所以为true。
System.out.println("65和65.0f是否相等? " + (it == fl)); // true
第二个输出语句
同样是双等号,所以判断值是否相等,而 A 的ascll码值就为65,所以输出结果为true。
System.out.println("65和 'A' 是否相等? " + (it == ch1)); //true
第三个输出语句
同样是比较值,显然相等,所以输出结果为true。
System.out.println("12和ch2是否相等? " + (12 == ch2)); //true
第四个输出语句
两个对象str1、str2都是被new出来的新对象,所以地址值不同,结果为false
System.out.println("str1和str2是否相等? " + (str1 == str2)); //false
第五个输出语句
String类的equals方法必然重写,比较两者的值,相等,所以输出true。
System.out.println("str1是否equals str2?" + (str1.equals(str2))); //true
最后一个输出语句
编译器报错,因为编译器无法识别这两个对象的关系,它们既不是同一个类型,也没有继承关系,所以报错。
System.out.println("hello" == new java.sql.Date()); //报错
hashCode( ) :返回该对象的哈希码值。
hashCode
hashCode的使用
现创建三个对象,一个aa1、aa2、aa3,其中aa1与aa2是新创建的对象,而aa3是指向aa1创建的对象。
public class test {public static void main(String[] args) {AA aa1 = new AA();AA aa2 = new AA();AA aa3 = aa1;System.out.println("aa1.hashCode() = " + aa1.hashCode());System.out.println("aa2.hashCode() = " + aa2.hashCode());System.out.println("aa3.hashCode() = " + aa3.hashCode());}
}class AA{}
现在看通过hashCode输出的结果:
显然aa1与aa3是同一个对象,所以输出的值一致。
toString( ) : 返回该对象的字符串表示。
默认返回:全类名(包名 + 类名) + @ + 哈希值的十六进制(通过hashCode得到的整数),子类往往重写toString方法,用于返回对象的属性信息。
重写toString方法,打印对象或拼接对象时,都会自动调用该对象的toString形式。
当直接输出一个对象时,toString方法会被默认的调用。
Object的toString( ) 原码
Object的toString() 原码(1) getClass().getName() 类的全类名(包名 + 类名)
(2) Integer.toHexString(hashCode()) 将对象的hashCode值转成16进制字符串public String toString(){return getClass().getName() + "@" + Integer.toHexString(hashCode())
}
hashcode使用案例
创建Monster[name,job,sal]
直接使用toString
public class test {public static void main(String[] args) {Monster monster = new Monster("章鱼哥","恰人",1000);System.out.println(monster.toString() + "hashCode值 = " + monster.hashCode());}
}class Monster{private String name;private String job;private double sal;public Monster(String name, String job, double sal) {this.name = name;this.job = job;this.sal = sal;}
}
运行效果
重写toString方法
class Monster{private String name;private String job;private double sal;public Monster(String name, String job, double sal) {this.name = name;this.job = job;this.sal = sal;}//重写toString方法,输出对象的属性//使用快捷键 alt + insert - >@Override//重写后,一般是把对象的属性值输出,当然程序员也可以自定义内容public String toString() {return "Monster{" +"name='" + name + '\'' +", job='" + job + '\'' +", sal=" + sal +'}';}
}
重写后继续调用monster,运行的结果如下所示:
当直接输出一个对象时,toString方法会被默认的调用。
还是以上面的代码为例,直接在输出语句中传入monster,实际上等价于monster.toString:
System.out.println(monster);//等价 monster.toString()
得到的结果如下所示:
但是可以注意到一个问题,那就是输出语句并没有重写hashcode,所以并没有输出哈希值。
finalize() :当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
finalize()
finalize使用实例
public class test {public static void main(String[] args) {Car bmw = new Car("宝马");//把bmw置空,此时Car现在就没人使用,就变为了垃圾对象//这时垃圾回收器就会回收(销毁)这个对象(堆释放)//在销毁对象前,会调用该对象的finalize方法// 此时程序员就可以在finalize中,写自己的业务逻辑代码(比如释放资源:数据库链接,或者打开文件等等)//如果程序员不重写finalize,那么就会默认调用Object类的finalize方法,如果程序员重写了finalize,就可以实现自己的逻辑。bmw = null;}
}class Car{private String name;public Car(String name){this.name = name;}
}