文章目录
- 一、Object类
- 1.1Object类中的方法
- 1.1.1toString()方法
- 1.1.2equals()方法
- 1.1.3hashCode()方法
- 二、Java中内置的一些接口
- 2.1Comparable<T>接口
- 2.2Cloneable接口
一、Object类
Object类是所有类的父类
1.1Object类中的方法
1.1.1toString()方法
Object类中的toString()方法:
public String toString() {
return getClass().getName()+"@"+Integer.toHexString(hashCode());
}
要获取自定义类型对象的信息,可以在自定义类型(类)中重写toString方法
System.out.println(person);//在Person类中没有重写toString方法时,打印的是practice.Person@1b6d3586;在Person类中重写toString方法后,打印的是自定义类型对象的信息(但重写的toString方法要写对)
1.1.2equals()方法
比较自定义类型(类)对象中的内容是否相同时,要在自定义类型中重写equals方法,equals方法的返回值是true或fase。建议自定义类型要重写equals方法(使equals方法实现自己想要的比较逻辑)
Object类中的equals方法:
public boolean equals(Object obj) {
return (this == obj); // 使用引用直接来进行比较,谁调用equals,谁就是this
}
观察以下代码
Person p1 = new Person("ZhangSan", 20);
Person p2 = new Person("ZhangSan", 20);
int a = 10;
int b = 10;
System.out.println(a == b);//打印true
System.out.println(p1 == p2);//打印false
System.out.println(p1.equals(p2));//打印false
以上代码p1和p2两个人的名字和年龄相同,在这里我们希望System.out.println(p1.equals(p2))打印的是true
在Person类中没有重写equals方法时,下面两行代码没有区别
System.out.println(p1 == p2);
System.out.println(p1.equals(p2));
所以要在Person类中重写Object类中的equals方法,可以手动重写,也可以用idea生成,点击Generate和equals() and hashCode()
@Override
public boolean equals(Object obj) {
if(obj == null) {//p1可以调用equals方法,说明p1指向的人已经创建好,p2为null不指向任何对象,说明p2指向的人没有被创建好
return false ;
}
if(this == obj) {
return true ;
}
if(!(obj instanceof Person)) {//检查obj是否引用了Person类型的对象
return false ;
}
Person person = (Person)obj ;//向下转型,因为obj是父类引用
return this.name.equals(person.name) && this.age==person.age ;
}
1.1.3hashCode()方法
建议自定义类型要重写hashcode方法,可以简单地认为hashcode方法返回的是对象的地址,但这个地址是被处理过的
hashcode方法源码:
public native int hashCode();
hashcode方法由native修饰,底层是由C/C++代码写的,我们看不到
Person per1 = new Person("yixing", 20) ;
Person per2 = new Person("yixing", 20) ;
System.out.println(per1.hashCode());//打印460141958
System.out.println(per2.hashCode());//打印1163157884
以上代码p1和p2两个人的名字和年龄相同,在这里我们希望System.out.println(per1.hashCode())和System.out.println(per2.hashCode())打印的结果一样,所以要在Person类中重写Object类中的hashCode方法
下面是用idea生成重写的hashCode方法:
@Override
public int hashCode() {
return Objects.hash(name, age);
}
在Person类中重写Object类中的hashCode方法后,将p1和p2两个人的name和age传入重写的hashCode方法里的Objects.hash(name, age),Objects.hash(name, age)在逻辑上帮我们算出了这是同一个位置,返回这同一个人的地址
二、Java中内置的一些接口
2.1Comparable接口
(1)自定义类型的对象要比较大小,则在这个自定义类型(类)中实现Comparable接口,在这个自定义类型(类)中重写compareTo方法,来实现比较的逻辑,因为Comparable接口中的compareTo方法没有具体的实现,compareTo方法的返回值是int,Comparable的T是什么类型(如Person类型),compareTo的参数就是什么类型(如Person类型),因为Comparable源码的泛型是这样写的
class Person implements Comparable<Person>{
public String name ;
public int age ;
public Person(String name, int age) {
this.age = age ;
this.name = name ;
}
@Override
public int compareTo(Person o) {//重写compareTo方法后,compareTo用人的年龄来进行比较
return this.age - o.age;
}
}
public class Practice1 {
public static void main(String[] args) {
Person p1 = new Person("ZhangSan", 15) ;
Person p2 = new Person("LiSi", 20) ;
System.out.println(p1.compareTo(p2));//输出结果是-5
}
}
数组排序Arrays.sort(arrays)底层是将数组的内容拿出来,强制类型转换为Comparable类型再调用compareTo方法(((Comparable)a[runHi++]).compareTo(a[lo])),数组内容是整数时可以用sort直接比较,数组内容是对象的引用时,则要在数组内容的类型(类)中实现comparable接口和重写compareTo方法
comparable接口对类的侵入性比较强,较不灵活
(2)使用比较器,对类的侵入性不强,较灵活,比较器(重新定义一个类,在这个类实现Comparator接口,在这个重新定义的类中重写compare方法,要比较时new一个这个重新定义的类的对象,用这个对象调用重写的compare方法),Comparator的T是什么类型(如Student类型),compare的参数就是什么类型(如Student类型),因为Comparator源码的泛型是这样写的
class AgeComparator implements Comparator<Student>{
@Override
public int compare(Student o1,Student o2){
return o1.age-o2.age;
}
}
class NameComparator implements Comparator<Student> {
@Override
public int compare(Student o1,Student o2){
return o1.name.compareTo(o2.name);
}//o1.name是String类型的引用,String类中实现了Comparable接口和重写了compareTo方法
}
public class Test{
public static void main(String[] args) {
Person p1 = new Person("ZhangSan", 10);
Person p2 = new Person("LiSi", 15);
AgeComparator ageComparator = new AgeComparator();
System.out.println(ageComparator.compare(p1, p2));
NameComparator nameComparator = new NameComparator();
System.out.println(ageComparator.compare(p1, p2));
}
}
2.2Cloneable接口
(1)Object类中有clone方法
以下是浅拷贝:
class Person implements Cloneable{//克隆接口Cloneable(空接口/标记接口),证明当前类是可以被克隆的
public int age;
public Person(int age){
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException{//这里重写了Object类的clone方法,Object类的clone方法声明的异常是受查异常/编译时异常,必须是编译时处理
return super.clone();//clone()在Object类中是protected修饰的(不是public修饰),所以要在Test2类中用person1调用clone()来克隆person1指向的对象,则要在Person类中重写clone()方法,这个重写的clone()方法里面用super调用Object类的clone()方法
}
}
public class Test2{
public static void main (String[] args) throws CloneNotSupportedException{//声明clone方法会出现的异常
Person person1 = new Person(10);
Person person2 = (Person)person1.clone();//向下转型,要强制类型转换,因为clone()方法的返回值类型是Object类型,返回值类型是父类。这里person1调用克隆方法,克隆person1指向的对象
System.out.println(person1);//以下两个打印的结果相同
System.out.println(person2);
}
}
(2)浅拷贝:只克隆对象。深拷贝:克隆对象中的对象。
以下是深拷贝:
class Money implements Cloneable{
public double money = 10.0;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Money{"+"money="+money+'}';
}
}
class Person implements Cloneable{
public int age;
public Money m;//这里用了组合
public Person(int age){
this.age = age;
this.m = new Money();
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person tmp = (Person) super.clone();
tmp.m = (Money) this.m.clone();//clone()在Money类中虽然是protected修饰,但这里是同一个包下的不同类,所以可以在Person类中通过对象的引用调用Money类的clone()以克隆Money类对象
return tmp; //克隆this.m所指向的内容,谁调用这个方法谁就是this,p1调用了这个方法所以p1是this,克隆p1.m所指向的内容
}
@Override
public String toString() {
return "Person{"+"age="+age+",m="+m+'}';
}
}
class Test2 {
public static void main(String[] args) throws CloneNotSupportedException {
Person p1 = new Person(10);
Person p2 = (Person) p1.clone();
System.out.println(p1);
System.out.println(p2);
p2.m.money = 20.0;
System.out.println(p2);
}
}
打印结果是:
p2.m.money = 20.0改变了p2对象中的m对象里money的内容,说明p2对象中的m对象也被克隆出来了。