褚橙的网站建设,软文写作范例大全,网站建设的过程,网站建设业务拓展思路个人主页#xff1a;兜里有颗棉花糖 欢迎 点赞#x1f44d; 收藏✨ 留言✉ 加关注#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【JavaSE_primary】 本专栏旨在分享学习JavaSE的一点学习心得#xff0c;欢迎大家在评论区交流讨论#x1f48c; 上篇#xff08;【Ja… 个人主页兜里有颗棉花糖 欢迎 点赞 收藏✨ 留言✉ 加关注本文由 兜里有颗棉花糖 原创 收录于专栏【JavaSE_primary】 本专栏旨在分享学习JavaSE的一点学习心得欢迎大家在评论区交流讨论 上篇【Java基础篇 | 面向对象】—— 聊聊什么是接口上篇中我们已经对Java接口中有了一定的了解。本篇中我们将对Java接口进行更进一步的学习。加油吧 目录 一、接口使用实例比较器Comparator 二、Clonable接口和深拷贝浅拷贝深拷贝 三、Object类对象比较equals()方法hashcode()方法 一、接口使用实例
首先我们要使用记住一句话对象与对象之间进行比较的话一定要实现对应的接口。只有我们实现了对应的接口之后才能证明这两个对象是可比较的。
现在有一个整数数组我们当然可以使用sort()方法来对这个整数数组进行升序或者降序排序。但是如果我们现在有一个学生类对象呢我们是无法直接拿两个学生类对象进行直接排序的。此时我们应该参照学生类中的某个属性来对这个学生类对象进行排序以达到我们想要的排序效果。
现在我们就以学生类中的年龄属性来进行排序吧
我们在进行自定义类型的对象比较的时候一定要实现可以比较的接口。比如如果我们的Student类实现Comparable接口, 并实现其中的compareTo方法。否则的话自定义类型的对象是无法进行比较的。 如下图就是我们实现的Comparable接口中的compareTo方法。 如果我们要比较两个对象的引用的话两个学生类对象按照年龄来进行排序我们可以这样来写请看 如果我们要比较的是一个学生类对象数组的话按照年龄来进行比较我们可以这样请看 运行结果如下 现在我们来试着使用自己写一个排序方法冒泡排序来对学生类对象进行排序。 请看下面我们自己实现的冒泡排序来对学生类对象按照年龄进行排序。代码如下 运行结果如下 现在我们来对上述冒泡排序中的代码进行解释 排序的时候我们排序的是一个学生数组按照年龄来进行排序所以我们在进行排序的时候底层一定会去调用compareTo方法所以冒泡排序中的参数一定为Comparable[] comparables即接口数组。另外array数组即学生类对象数组中的每个元素都是一个学生类对象而且每个学生类对象都实现了compareTo方法。 比较器Comparator 好了现在我们换一种排序的写法。上述学生类中有年龄也有分数如果我们一会想依据年龄进行排序一会又想用分数进行排序的话如果按照compareTo()方法完成上述排序的话那么根据我们比较依据的不同那么compareTo()方法中的内容也是不一样的即我们需要修改compareTo方法中的内容。 请看上图上图中的compareTo()只能对学生类对象中的年龄进行排序而无法对学生类中的成绩进行排序所以排序的内容就比较单一。此时我们就需要Comparator接口。 好了现在我们利用Comparator接口来实现学生类对象的排序工作代码如下图请看 具体代码如下请看
import com.sun.javaws.IconUtil;
import java.util.Comparator;class Student{public String name;public int age;public double score;public Student(String name, int age, double score) {this.name name;this.age age;this.score score;}Overridepublic String toString() {return Student{ name name \ , age age , score score };}
}
// 这里我们利用了解耦的思想
class AgeComparator implements ComparatorStudent {Overridepublic int compare(Student o1, Student o2) {return o1.age - o2.age;}
}
class ScoreComparator implements ComparatorStudent{Overridepublic int compare(Student o1,Student o2) {return (int)(o1.score - o2.score);}
}
public class Test {public static void main(String[] args) {Student student1 new Student(jkl,1,87.3);Student student2 new Student(ajk,2,87.3);// 依据年龄进行比较AgeComparator ageComparator new AgeComparator();int ret ageComparator.compare(student1,student2);System.out.println(ret ret);// 依据成绩进行比较ScoreComparator scoreComparator new ScoreComparator();int ret2 scoreComparator.compare(student1,student2);System.out.println(ret ret2);}
}运行结果如下 对比一下这两种接口Comparator接口和Comparable接口经过上述的演示我们不难发现Comparator接口更加的灵活。 二、Clonable接口和深拷贝
浅拷贝
浅拷贝概念浅拷贝是指在对一个对象进行拷贝时只拷贝对象本身和其中的基本数据类型而不拷贝对象内部的引用类型。因此在浅拷贝的对象中引用类型的变量指向的依旧是原始对象中的引用。
下面来进行举例。 现在我们有一个Student学生类如下图 同时新创建了一个学生类对象student1该对象对应的内存结构图如下 现在我们想要把student引用所指向的对象克隆出来一份如下图的克隆方式是错误的 要解决上述错误的话我们需要修改三个地方。如下图 好了现在重新运行一下程序发现还是会报错请看 我们需要实现一个接口以证明当前的类是可以进行克隆的。 运行结果如下 浅拷贝的对象中引用类型的变量指向的依旧是原始对象中的引用。请看举例 运行结果如下 解释通过调用clone()方法创建了student1的一个克隆对象student2。克隆的实现是通过调用Object类的clone()方法来完成的。 输出结果显示了两次student1.m.money和student2.m.money的值分别为52.0。这是因为浅拷贝只是简单地复制字段的值而对于引用类型的字段只复制了引用地址并没有复制该引用指向的实际对象。因此student1和student2的m字段引用同一个Money对象。 深拷贝
深拷贝是指在对一个对象进行拷贝时不仅拷贝对象本身和其中的基本数据类型同时也拷贝对象内部的引用类型。因此在深拷贝的对象中引用类型的变量指向的是全新的对象。
好了现在来总结一下clone方法是Object类中的一个方法调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法必须要先实现Clonable接口, 否则就会抛出CloneNotSupportedException异常.
下面是深拷贝的代码举例
class Money implements Cloneable {public double money;Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
class Student implements Cloneable {public int age;public Money m new Money();public Student(int age) {this.age age;}Overridepublic String toString() {return Student{ age age };}Overrideprotected Object clone() throws CloneNotSupportedException {//return super.clone();Student tmp (Student)super.clone();tmp.m (Money)this.m.clone();return tmp;}
}
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Student student1 new Student(21);student1.m.money 52.0;Student student2 (Student)student1.clone();System.out.println(student1.m.money);System.out.println(student2.m.money);System.out.println(分割线--------------);student1.m.money 18.8;System.out.println(student1.m.money);System.out.println(student2.m.money);}
}运行结果如下 好了现在我们再来回顾一下什么是深拷贝深拷贝就是在拷贝对象的同时创建一个新的对象并将原对象中的所有数据逐个拷贝到新对象中去包括成员变量引用的其他对象。这样可以确保原对象和拷贝对象之间的数据相互独立互不影响。
三、Object类
在Java中所有的类都直接或间接地继承自java.lang.Object类。Object类是Java类层次结构中的根类它提供了一些通用的方法和功能可以在所有类中使用。可以这么认为Object类是所有类的父类。所以在Java中即使我们不显式地在类声明中使用extends关键字继承Object类所有的类仍然会隐式地继承Object类。这是因为Object类是Java类层次结构中的根类所有的类都直接或间接继承自它。
对象比较equals()方法 如上图使用equals()方法来比较两个对象是否相等。 如果在Student类中没有重写equals()方法则默认会使用Object类中的equals()方法它执行的是比较对象引用的相等性即比较两个对象在内存中的地址是否相同。 因此上图中的代码的最终结果就是False。但是如果我想要按照我们自己的方式来比较这两个对象是否相等的话我们就需要自己去重写equals()方法。 现在如果以两个对象的年龄是否相等为依据来判断两个对象是否相等的话重写的equals()方法如下 如果我们相比较对象中的内容是否相等的话我们需要根据自己的判断依据来重写Object类中的equals()方法。 hashcode()方法 hashcode()方法用于返回对象的hash码相当于对象的标识符它可以将对象转换为整数以便更好的比较、存储对象。 好了现在来举个栗子假设当两个对象的年龄是一样的话那么我们认为这两个对象存储的位置是相同的请看代码 运行结果如下 如上图中的运行结果虽然两个对象的年龄是不同的但是这两个对象存储的位置确实相同的这与我们判断两个对象是否相同的判断依据发生了冲突。 此时我们就需要自己重写hashcode()方法。 最终代码如下请看
import java.util.Objects;class Money implements Cloneable {public double money;Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}Overridepublic boolean equals(Object o) {if (this o) return true;if (o null || getClass() ! o.getClass()) return false;Money money1 (Money) o;return Double.compare(money1.money, money) 0;}Overridepublic int hashCode() {return Objects.hash(money);}
}
class Student implements Cloneable {public int age;public Money m new Money();public Student(int age) {this.age age;}Overridepublic String toString() {return Student{ age age };}Overrideprotected Object clone() throws CloneNotSupportedException {//return super.clone();Student tmp (Student)super.clone();tmp.m (Money)this.m.clone();return tmp;}Overridepublic boolean equals(Object obj) {Student student (Student)obj;return age student.age;}Overridepublic int hashCode() {return Objects.hash(age, m);}
}
public class Test {public static void main(String[] args) {Student student1 new Student(19);Student student2 new Student(19);System.out.println(student1.hashCode());System.out.println(student2.hashCode());}
}运行结果如下 此时就说明这两个对象的位置是相同的。 小总结
hashcode()方法用来确定对象在内存中存储的位置是否相同。实际上hashcode()在散列表中才会用到在散列表中hashcode()的作用就是获取对象的散列码进而确定该对象在散列表中的位置然而hashcode()在其它情况下没多大用。如果一个类没有重写hashCode()和equals() 方法那么它将使用从Object类继承而来的默认实现。如果默认实现的hashCode()和equals()方法不符合我们的需求此时我们就需要自己重写hashCode()和equals()方法。定义一个自定义类型时应该养成重写hashCode()和equals()方法的习惯。
好了本文到这里就结束了再见啦友友们