目录
==和equals的对比
1.==:既可以判断基本类型,又可以判断引用类型
2.==:如果判断基本类型,判断的是值是否相等。示例:inti=10;double d=10.0;
3.==:如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象
equals方法
4.equals:是Object类中的方法,只能判断引用类型,
5.默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比Integer,String
代码演示:
package idea.object_;
/**
* 演示equals方法和==
*/
public class equals01 {
public static void main(String[] args) {
A a = new A();
//==和equals的对比
//1.==:既可以判断基本类型,又可以判断引用类型
//2.==:如果判断基本类型,判断的是值是否相等。示例:inti=10;double d=10.0;
//3.==:如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象
//比如
int i = 10;
double d = 10.0;
//判断基本数类型
System.out.println(i == d);//因为int 和 double 都是基本数据类型,所以判断的是值是否相等,因此返回true
//判断引用类型
A b = a;
A c = b;
//因为把a赋值给了 b 因此b也指向a所指向的空间,因此返回true
System.out.println(a == c);
//因为把a赋值给了 c 因此c也指向a所指向的空间,因此返回true
System.out.println(b == c);
B bObj = a;
//因为把a赋值给了 bObj 因此bObj也指向a所指向的空间,因此返回true,即使bObj的编译类型是B,但是指向的还是a所指向的空间,所以返回true
System.out.println(bObj == a);
//equals方法
//4.equals:是Object类中的方法,只能判断引用类型,如何看Jdk源码,看老师演示
//5.默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比Integer,String
//equals 方法,源码怎么查看.
//把光标放在equals方法,直接输入ctrl+b
//如果你使用不了. 自己配置. 即可使用.
/*
//看看Jdk的源码 String类的 equals方法
//String类把Object的equals方法重写了,变成了比较两个字符串值是否相同
public boolean equals(Object anObject) {
if (this == anObject) {//判断,如果当前对象和传入进来的是同一个对象
return true;//返回true
}
if (anObject instanceof String) {//判断你传入进来的数据类型的运行类型,是不是String类型或者是String类的子类型型
String anotherString = (String)anObject;//如果是String类型或者是String类的子类型,那么就向下转型
int n = value.length;
if (n == anotherString.value.length) {//如果长度相同
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {//然后一个一个的比较字符
if (v1[i] != v2[i])//如果发现两个数组中,有一个字符不相同那么就返回false
return false;
i++;
}
return true;//如果两个字符串的所有字符都相等,则返回true
}
}
return false;//如果比较的不是字符串(也就是传入的数据类型,不是String类型或者不是String类型的子类型),则直接返回false
}
*/
//String
//因为String类重写了Object的equals方法,因此判断的是内容是否相同,因此返回false
System.out.println("hello".equals("abc"));
//Object
//看看Object类的 equals()方法是怎么样的
/*
Object 的equals 方法默认就是比较对象地址是否相同
也就是判断两个对象是不是同一个对象.
public boolean equals(Object obj) {
return (this == obj);//直接判断当前对象和我们传入的对象是否相同,因为==在判断引用类型的时候,判断的是地址是否相同
}
*/
//Integer
/*
//从源码可以看到 Integer 也重写了Object的equals方法,
//变成了判断两个值是否相同
public boolean equals(Object obj) {
if (obj instanceof Integer) {//判断你传入进来的数据类型的运行类型,是不是Integer类型或者是Integer类的子类型型
return value == ((Integer)obj).intValue();
}
return false;//如果不是Integer的类型或者不是Integer的子类型就返回false
}
*/
//创建了两个Integer对象
Integer integer1 = new Integer(1000);
Integer integer2 = new Integer(1000);
//这里==判断在判断引用类型的时候,判断的是地址是否相等,因此 integer1 和 integer2 都是new出来的,在堆中会有两块不同的空间,因此返回的是false
System.out.println(integer1 == integer2);//false
//因为Integer重写了,equals方法,所以判断的是值是否相同,所以返回的是true
System.out.println(integer1.equals(integer2));//true
String str1 = new String("jack");
String str2 = new String("jack");
//这里==判断在判断引用类型的时候,判断的是地址是否相等,因此 str1 和 str2 都是new出来的,在堆中会有两块不同的空间,因此返回的是false
System.out.println(str1 == str2);//false
//因为String重写了,equals方法,所以判断的是值是否相同,所以返回的是true
System.out.println(str1.equals(str2));//true
}
}
class A extends B {
}
class B {//父类
}
String类的equals的源码分析
源码分析:
1.首先我们要知道,该equals方法是重写了,Object的equals方法
2.在已进入到方法就去判断,如果当前对象和传入进来的是同一个对象,那么直接返回true
3.判断你传入进来的数据类型的运行类型,是不是String类型或者是String类的子类型型如果是String类型或者是String类的子类型,那么就向下转型
4.如果长度相同,就把字符串,拆成两个不同的字符数组,然后循环的比较数组的值是否先相同,如果其中有一个不相同就返回一个false
5.如果都不成立,说明传入的数据类型的运行类型不是String类型或者不是String类型的子类型
//看看Jdk的源码 String类的 equals方法
//String类把Object的equals方法重写了,变成了比较两个字符串值是否相同
public boolean equals(Object anObject) {
if (this == anObject) {//判断,如果当前对象和传入进来的是同一个对象
return true;//返回true
}
if (anObject instanceof String) {//判断你传入进来的数据类型的运行类型,是不是String类型或者是String类的子类型型
String anotherString = (String)anObject;//如果是String类型或者是String类的子类型,那么就向下转型
int n = value.length;
if (n == anotherString.value.length) {//如果长度相同
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {//然后一个一个的比较字符
if (v1[i] != v2[i])//如果发现两个数组中,有一个字符不相同那么就返回false
return false;
i++;
}
return true;//如果两个字符串的所有字符都相等,则返回true
}
}
return false;//如果比较的不是字符串(也就是传入的数据类型,不是String类型或者不是String类型的子类型),则直接返回false
}
Object类的equals的源码分析
源码分析:
1.直接判断当前对象和我们传入的对象是否相同,因为==在判断引用类型的时候,判断的是地址是否相同
//Object 的equals 方法默认就是比较对象地址是否相同
//也就是判断两个对象是不是同一个对象.
public boolean equals(Object obj) {
return (this == obj);//直接判断当前对象和我们传入的对象是否相同,因为==在判断引用类型的时候,判断的是地址是否相同
}
Integer类的equals的源码分析
源码分析:
1.先判断你传入进来的数据类型的运行类型,是不是Integer类型或者是Integer类的子类型型,如果不是就之间返回false
2.Integer重写了Object类中的方法后,判断的是值是否相同
//从源码可以看到 Integer 也重写了Object的equals方法,
//变成了判断两个值是否相同
public boolean equals(Object obj) {
if (obj instanceof Integer) {//判断你传入进来的数据类型的运行类型,是不是Integer类型或者是Integer类的子类型型
return value == ((Integer)obj).intValue();
}
return false;//如果不是Integer的类型或者不是Integer的子类型就返回false
}
equals例题
第一题
思路分析:
1.因为==在判断引用类型的时候,判断的是地址是否相同而person1 和 person2 都是new出来的在堆中也各自的空间,所以返回的是false
2.因为我们重写了equals方法,所以判断的是,两个对象中的值是否相同所以返回true,如果没有重写equals方法,那么默认调用的就是Object的equals方法,判断的就是地址是否相同了
package idea.object_;
import java.util.Objects;
/**
* equals例题1
*/
public class equalsExercise01 {
public static void main(String[] args) {
//判断两个Person对象的内容是否相等,如果两个Person对象各个属性的值都一样就返回true反之返回false
Person person1 = new Person("jack", 12);
Person person2 = new Person("jack", 12);
//因为==在判断引用类型的时候,判断的是地址是否相同而person1 和 person2 都是new出来的在堆中也各自的空间,所以返回的是false
System.out.println(person2 == person1);//false
//因为我们重写了equals方法,所以判断的是,两个对象中的值是否相同所以返回true,如果没有重写equals方法,那么默认调用的就是Object的equals方法,判断的就是地址是否相同了
System.out.println(person1.equals(person2));//true
}
}
class Person {
//定义了两个私有的属性
private String name;
private int age;
//构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
//重写了equals方法
@Override
public boolean equals(Object o) {
if (this == o) {//判断当前对象的地址,和传入的对象的地址是否相同,如果相同返回true
return true;
}
if (o instanceof Person) {//判断我们传入的对象的运行类型是不是Person类型或者是Person类型的子类型
Person p = (Person) o;//如果是就向下转型
return p.age == this.age && p.name.equals(this.name);
}
return false;//说明不是Person类型,返回false
}
}
第二题
思路分析:
1.在判断p1==p2时,因为==判断引用类型时 默认判断地址是否相等,所以返回false
2.在判断p1.name.equals(p2.name));时 ,因为p1.name是字符串已经重写了equals方法所以这里判断的 是内容是否相等,因此返回true
3.在判断p1.equals(p2));时因为Person_ 没有重写equals方法所以还是判断的是地址 因为p1是创建的对象并没有重写equals方法所以返回的是false
4.在判断s1.equals(s2));时,因为s1已经是字符串了 已经重写了equals方法,判断的是值是否相同,所以为true
5.在s1 == s2);时,因为String是引用类型所以==判断的还是地址,所以返回false
package idea.object_;
/**
* equals例题1
*/
public class equalsExercise02 {
public static void main(String[] args) {
Person_ p1 = new Person_();
p1.name = "jack";
Person_ p2 = new Person_();
p2.name = "jack";
System.out.println(p1 == p2);//False==判断引用类型时 默认判断地址是否相等,所以返回false
System.out.println(p1.name.equals(p2.name));//T 因为p1.name是字符串已经重写了equals方法所以这里判断的 是内容是否相等
System.out.println(p1.equals(p2));//False 没有重写所以还是判断的是地址 因为p1是创建的对象并没有重写equals方法所以返回的是false
String s1 = new String("asdf");
String s2 = new String("asdf");
System.out.println(s1.equals(s2));//T因为s1已经是字符串了 已经重写了,所以为true
System.out.println(s1 == s2);//F String是引用类型所以==判断的还是地址
}
}
class Person_ {
public String name;
}
hashCode方法
1)提高具有哈希结构的容器的效率!
2)两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!
3)两个引用,如果指向的是不同对象,则哈希值是不一样的
4)哈希值主要根据地址号来的!,不能完全将哈希值等价于地址。
思路分析:
1.因为aa 和aa2都是new出来的,在堆中有不同的空间,所以他们的hashCode不同,aa3是aa赋给给他的,因此指向的是同一块空间,因此,aa和aa3的hashCode相同
package idea.object_;
public class HashCode_ {
public static void main(String[] args) {
AA aa = new AA();
AA aa2 = new AA();
AA aa3 = aa;
//因为aa 和aa2都是new出来的,在堆中有不同的空间,所以他们的hashCode不同,aa3是aa赋给给他的,因此指向的是同一块空间,因此,aa和aa3的hashCode相同
System.out.println("aa.hashCode()=" + aa.hashCode());
System.out.println("aa2.hashCode()=" + aa2.hashCode());
System.out.println("aa3.hashCode()=" + aa3.hashCode());
}
}
class AA {
}
toString方法
基本介绍
默认返回:全类名+@+哈希值的十六进制,子类往往重写toString方法,用于返回对象的属性信息
重写toString方法,打印对象或拼接对象时,都会自动调用该对象的toString形式
当直接输出一个对象时,toString方法会被默认的调用,比如 System.out.println(monster);就会默认调用 monster.toString()
代码演示:
1.如果不重写toString()方法,那么在输出的时候,输出的就是包名,类名,加上地址
package idea.object_;
public class ToString_ {
public static void main(String[] args) {
/*
Object的toString() 源码
(1)getClass().getName() 类的全类名(包名+类名 )
(2)Integer.toHexString(hashCode()) 将对象的hashCode值转成16进制字符串
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
*/
Monster monster = new Monster("jack", "公司领导", 1000);
System.out.println(monster.toString() + " hashcode=" + monster.hashCode());
//如果不重写toString()方法,那么在输出的时候,输出的就是包名,类名,加上地址
System.out.println(monster); //等价 monster.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方法, 输出对象的属性
@Override
public String toString() { //重写后,一般是把对象的属性值输出,当然程序员也可以自己定制
return "Monster{" +
"name='" + name + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
'}';
}
}
finalize方法
1.当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作
2.什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用 finalize方法。
3.垃圾回收机制的调用,是由系统来决定(即有自己的GC算法),也可以通过System.gc()主动触发垃圾回收机制,测试:Car [name]
代码演示:
1.当把bmw置成null时,这是bmw原来指向堆中的空间就没有在指向了,因此这时 car对象就是一个垃圾,垃圾回收器就会回收(销毁)对象, 在销毁对象前,会调用该对象的finalize方法
2.注意是在我们程序退出后,才去执行finalize中的代码
package idea.object_;
/**
* 演示 Finalize的用法
*/
public class Finalize_ {
public static void main(String[] args) {
//创建了一个car对象
Car bmw = new Car("宝马");
//当把bmw置成null时,这是bmw原来指向堆中的空间就没有在指向了,因此这时 car对象就是一个垃圾,垃圾回收器就会回收(销毁)对象, 在销毁对象前,会调用该对象的finalize方法
//,我们就可以在 finalize中,写自己的业务逻辑代码(比如释放资源:数据库连接,或者打开文件..)
//,如果程序员不重写 finalize,那么就会调用 Object类的 finalize, 即默认处理
//,如果程序员重写了finalize, 就可以实现自己的逻辑
bmw = null;
System.gc();//主动调用垃圾回收器
System.out.println("程序退出....");
//注意是在我们程序退出后,才去执行finalize中的代码
}
}
//定义了一个汽车类
class Car {
//定义了一个 属性
private String name;
//构造器
public Car(String name) {
this.name = name;
}
//为了看到效果,我们重写finalize方法
@Override
protected void finalize() throws Throwable {
System.out.println("我们销毁了一辆" + name + "汽车");
}
}