Object
- Object类
- 一、 equals( )
- ● == 与 equals的对比(☆)
- 二、hashCode( )
- 三、toString( )
- 四、finalize( )
Object类
Object类:Java中lang包的类,是类层次结构的根类,每个类都使用Object作为超类。所有对象(包括数组)都实现这个类的方法。
Object类所含有的方法
- clone()
- equals(Object obj)
- finalize()
- getClass()
- hashCode()
- notify()
- notifyAll()
- toString()
- wait()
- wait(long timeout)
- wait(long timeout, int nanos)
一、 equals( )
boolen | equals(Object ob) : 指示其他某个对象是否与此对象"相等"。
● == 与 equals的对比(☆)
(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
- Object类中的方法,只能判断引用类型
- 默认判断的是地址值是否相等,子类中往往重写该方法,用于判断内容是否相等。比如:Integer,String
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
//判断如果比较的两个对象是同一个对象,则直接返回true
if(this == obj){ //这里的this指的是ps1
return 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,则直接返回false
return 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
- 提高具有哈希结构的容器的效率。
- 两个引用,如果指向的是同一个对象,则哈希值肯定相同,反之则不同(特殊情况除外)
- 哈希值主要根据地址号来的,不能完全将哈希值等价于地址!
- 后续在集合中介绍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( )
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()
- 当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作。
- 什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。
- 垃圾回收机制的调用,是由系统来决定(即有自己的GC算法),也可以通过System.gc()主动触发垃圾回收机制。
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;
}
}