1.对象数组的排序
数组我们有一个现成的 sort 方法就是可以拿来对数组进行排序操作的,但是能不能对一个对象数组进行排序呢?答案是不可以的!对象数组中的每个元素都是一个实例化的对象,对象中的成员属性复杂,你直接调用sort对数组进行排序是不行的。
此时就需要实现Comparable接口,并且重写compareTo方法。compareTo方法定义了对象之间的比较规则,sort会根据compareTo方法的返回值来进行排序。然后就可以使用Arrays类的sort方法对对象数组进行排序了。
下面是一个示例:
————————————————
class Student implements Comparable<Student>{ public String name; public int age; public int souce; public Student(String name, int age, int souce) { this.name = name; this.age = age; this.souce = souce; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", souce=" + souce + '}'; } @Override public int compareTo(Student o) { return this.age - o.age; } } class AgeComparator implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { return o1.age - o2.age; } } class SouceComparator implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { return o1.souce - o2.souce; } } class NameComparator implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { return o1.compareTo(o2); } } public class Exercise { public static void sort(Comparable[] array) { for (int i = 0; i < array.length; i++) { for (int j = 0; j < array.length-i-1; j++) { if(array[j].compareTo(array[j+1])>0){ Comparable tmp = array[j]; array[j] = array[j+1]; array[j+1] = tmp; } } } } public static void main(String[] args) { Student[] student = new Student[3]; student[0] = new Student("zhangsan",11,55); student[1] = new Student("lisi",8,41); student[2] = new Student("wangwu",13,12); NameComparator nameComparator = new NameComparator(); AgeComparator ageComparator = new AgeComparator(); SouceComparator souceComparator = new SouceComparator(); Arrays.sort(student); System.out.println(Arrays.toString(student)); //比较器 Arrays.sort(student,souceComparator); System.out.println(Arrays.toString(student)); Arrays.sort(student,nameComparator); System.out.println(Arrays.toString(student)); Arrays.sort(student,ageComparator); System.out.println(Arrays.toString(student)); //sort重新 sort(student); System.out.println(Arrays.toString(student)); } }
此段代码中对sotr中的Comparable接口中的compareTo进行了重写,但是这么写有一个很大的问题,因为这个方法一旦写死了,后续调用sort排序都是以这一成员属性来排序。
所以在代码中,我们运用了构造器,这样使用者就可以根据自己的实际需求调用不同的比较器,来对数组进行排序。
另外可以对sort方法进行重写,这样就可以选择调用自己的sort方法。
2.Clonable 接口和深拷贝
Java 中内置了一些很有用的接口, Clonable 就是其中之一。Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 "拷贝"。 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常。
下面是一段代码示例:
import java.util.Objects; class Money implements Cloneable{ public double money = 6.6; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Student implements Cloneable{ public String name = "zxhangsan"; Money m = new Money(); @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", m=" + m.money + '}'; } @Override protected Object clone() throws CloneNotSupportedException { Student student = (Student) super.clone(); student.m = (Money) this.m.clone(); return student; } } public class Exercise { public static void main(String[] args) throws CloneNotSupportedException{ Student student1 = new Student(); Student student2 = (Student) student1.clone(); System.out.println(student1); System.out.println(student2); System.out.println("============="); student2.m.money = 88; System.out.println(student1); System.out.println(student2); System.out.println("=============="); } }
这段代码展示了如何使用`Cloneable`接口和拷贝来创建对象的副本。
首先,`Cloneable`接口是一个标记接口,用于指示该类的对象可以被拷贝。在类中实现`Cloneable`接口,表示该类的对象可以使用`clone()`方法进行拷贝。
在`Money`类和`Student`类中,都实现了`Cloneable`接口,并重写了`clone()`方法。在`clone()`方法中,都调用了`super.clone()`来创建对象的浅拷贝。
在`Student`类中,还对`m`对象进行了深拷贝。在`clone()`方法中,首先调用了`super.clone()`来创建对象的浅拷贝,然后将`m`对象进行深拷贝。深拷贝是为了确保副本对象和原始对象中的引用类型成员变量不共享同一个引用,而是拥有各自独立的拷贝。
在`Exercise`类的`main`方法中,创建了一个`Student`对象`student1`。然后通过调用`clone()`方法创建了`student1`的副本`student2`。使用`println`方法打印`student1`和`student2`对象的信息,可以看到它们的内容是相同的。
接着,修改了`student2`副本对象中的`m`对象的`money`属性,将其修改为88。再次打印`student1`和`student2`对象的信息,可以看到`student1`的`m`对象的`money`属性没有改变,而`student2`的`m`对象的`money`属性被修改为88。这表明副本对象和原始对象中的引用类型成员变量是独立的,互不影响。
综上所述,`Cloneable`接口和拷贝可以用于创建对象的副本。通过实现`Cloneable`接口,并重写`clone()`方法,可以实现对象的浅拷贝。如果对象中包含引用类型成员变量,需要进行深拷贝,确保副本对象和原始对象中的引用类型成员变量不共享同一个引用。
3.获取对象信息
如果要打印对象中的内容,可以直接重写Object类中的toString()方法。
toString()方法是Object类中的一个方法,它返回一个包含对象内容的字符串表示。默认情况下,toString()方法返回的是对象的类名和哈希码。
结合上个例子中的代码,在Student类中,重写了toString()方法,以便返回一个包含name和m.money属性的字符串表示。通过重写toString()方法,可以自定义打印对象的内容,使其更加有意义和可读性。
在Exercise类的main方法中,通过调用System.out.println()方法打印student1和student2对象,实际上是调用了对象的toString()方法来获取字符串表示,并将其输出到控制台。
所以,通过重写toString()方法,可以方便地打印对象的内容。
4.对象比较equals 方法
在Java中,对象比较通常使用`equals()`方法。`equals()`方法是`Object`类中的一个方法,用于比较两个对象是否相等。
默认情况下,`equals()`方法比较的是对象的引用是否相等,即比较两个对象是否指向同一个内存地址。这可以通过`==`运算符进行比较。
然而,有时候我们需要比较对象的内容是否相等,而不仅仅是比较引用。在这种情况下,我们需要重写`equals()`方法。
重写`equals()`方法时,通常需要满足以下几个条件:
自反性:对于任何非空引用值`x`,`x.equals(x)`应该返回`true`。
对称性:对于任何非空引用值`x`和`y`,如果`x.equals(y)`返回`true`,则`y.equals(x)`也应该返回`true`。
传递性:对于任何非空引用值`x`、`y`和`z`,如果`x.equals(y)`返回`true`,`y.equals(z)`返回`true`,则`x.equals(z)`也应该返回`true`。
一致性:对于任何非空引用值`x`和`y`,多次调用`x.equals(y)`应该始终返回相同的结果。
非空性:对于任何非空引用值`x`,`x.equals(null)`应该返回`false`。
在重写`equals()`方法时,通常需要比较对象的属性是否相等。可以使用`instanceof`运算符检查对象类型,然后比较属性的值。在比较引用类型的属性时,可以使用`equals()`方法递归比较。
另外,如果重写了`equals()`方法,通常也需要重写`hashCode()`方法,以确保相等的对象具有相同的哈希码。这是因为在使用一些集合类(如`HashSet`、`HashMap`等)时,会依赖对象的哈希码来进行快速查找和比较。
总之,通过重写`equals()`方法,可以自定义对象的相等性比较。在比较对象时,应该根据对象的属性进行比较,并满足`equals()`方法的约定。
下面是一个示例:
public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } // 重写equals()方法来比较对象的相等性 @Override public boolean equals(Object obj) { if (this == obj) { // 检查对象引用是否相等 return true; } if (obj == null || getClass() != obj.getClass()) { // 检查对象类型是否相同 return false; } Person person = (Person) obj; // 强制转换为Person类型 return age == person.age && name.equals(person.name); // 比较属性值是否相等 } public static void main(String[] args) { Person p1 = new Person("Alice", 20); Person p2 = new Person("Alice", 20); Person p3 = new Person("Bob", 25); System.out.println(p1.equals(p2)); // 输出true,因为p1和p2的属性值相等 System.out.println(p1.equals(p3)); // 输出false,因为p1和p3的属性值不相等 } }
在上面的示例中,`Person`类重写了`equals()`方法来比较两个`Person`对象的相等性。在`main`方法中,我们创建了三个`Person`对象,并使用`equals()`方法进行比较。根据`name`和`age`属性的值,我们可以确定两个对象是否相等。
在`equals()`方法中,我们首先检查对象的引用是否相等,如果相等则直接返回`true`。然后,我们检查对象的类型是否相同,如果不同则返回`false`。最后,我们将对象强制转换为`Person`类型,并比较`name`和`age`属性的值是否相等。如果属性值相等,则返回`true`,否则返回`false`。
在`main`方法中,我们分别比较了`p1`和`p2`,以及`p1`和`p3`的相等性。根据属性的值,`p1`和`p2`的相等性为`true`,而`p1`和`p3`的相等性为`false`。
5.hashcode方法
在Java中,hashCode()方法是Object类的一个方法,用于返回对象的哈希码(hash code)。哈希码是一个整数值,用于在哈希表等数据结构中快速查找和比较对象。
hashCode()方法的默认实现是根据对象的内存地址计算哈希码。但是,如果我们需要将对象用作集合类(如HashSet、HashMap等)的键或在自定义的哈希表中使用,则通常需要重写hashCode()方法。
在重写hashCode()方法时,应该遵循以下原则:
如果两个对象使用equals()方法比较相等,则它们的哈希码应该相等。
如果两个对象的哈希码相等,它们不一定相等。
以下是重写hashCode()方法的示例代码:
import java.util.Objects; public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } // 重写hashCode()方法 @Override public int hashCode() { return Objects.hash(name,age); } public static void main(String[] args) { Person p1 = new Person("Alice", 20); Person p2 = new Person("Alice", 20); System.out.println(p1.hashCode()); // 输出哈希码 System.out.println(p2.hashCode()); // 输出哈希码 } }
代码中hashCode()方法将name和age作为参数传递给Objects.hash()方法,然后返回计算得到的哈希码。
在main方法中,我们创建了两个Person对象,并分别输出它们的哈希码。根据属性的值,p1和p2的哈希码是相等的。
使用Objects.hash()方法可以简化重写hashCode()方法的过程,并且可以处理多个属性的哈希码。这样可以提高代码的可读性和维护性。
以上就是本期的全部内容啦,希望看完后能够对你有所帮助。希望小伙伴们可以点赞收藏加关注,学习知识不迷路。