Java SE 常用接口的使用

1.Compare方法比较大小

(1)我们想比较两个引用对象的大小,直接比较是不可以的。

package demointerface;

class Student{
    public String name ;
    public int age ;
    public Student(String name ,int age){
        this.name = name ;
        this.age = age ;
    }
    public String toString(){
        return "Student{"+"name=" + name +'\'' + ", age=" + age +'}';
    }
}
public class Test {
    Student student1 = new Student("zhangsan",10);
    Student student2 = new Student("lisi",3);
    if(student1 > student2){
        
    }else{}


}

代码会报错,编译器不知道你要比较对象的哪个参数。用name进行比较?还是用age进行比较?编译器并不知道。

 那么我们如何只选择一个参数进行比较呢??

(2)定义两个引用类型,str1和str2,放入if语句中进行比较,可以看到还是会报错,就是说引用类型是不可以直接比较的!

可以借助String类中的compareTo方法进行比较

代码

str1的字符串比str2大那么输出true反之输出false。

 String str1 = "zhnagsan";
        String str2 = "lisi";
        if(str1.compareTo(str2) > 0){
            System.out.println("str1 > str2");
        }else {
            System.out.println("str1 < str2");
        }

 1.1compareTo方法源码详细讲解

1.1.1 compareTo使用图片

 1.1.2compareTo方法源码图片(Ctrl+鼠标右键点击就可以进入compare源码

    在这里只截取了一部分的源码图片(详细大家想看可以自己操作观看全部源码)

1.2.3 .详细讲解(结合1.1.1和1.1.2中的两张图片)

(1)在1.1.1图片中调用了conpare方法对str1和str2进行比较,用str1调用了conpare方法,将str2作为参数传进compare方法中。

(2)1.1.2图片中的String antherString 拿到的是str2参数,理解为(String antherString = str2)

(3)注意:谁调用这个方法谁和这个传过去的参数做比较,就是说在图1.1.1中str1调用的compare,str2作为参数,就是str1和str2比较大小,

1.如果str1小于str2,则返回一个负整数。

2.如果str1等于str2,则返回零。

3.如果str1大于str2,则返回一个正整数。

(4)字符串比较是通过数据字典(Ascll表)进行比较的,字典大小一样就看谁的字符串长度比较谁长谁大。

(5)String之所以可以比较大小是因为使用了Compareable接口并且重写了Compareable接口中的compareTo()方法

1.2.4compareTo 接口源码讲解

点击进入Compareable接口源码

在这里就可以看到Compareable接口和ComareTo方法。 

(6)伏笔:这个Comparable<T>是什么?

 在数据结构准备阶段会进行详细讲解,这是一个很nb的语法,非常nb,大家到时候一定要好好看我的文章,会详细的讲解给大家。大厂有一年问过这个的底层原理。这篇文章讲解中会在代码中写<T>,大家先不用知道这段代码的意思是什么。

2.使用Compareable接口详细讲解

 2.1 使用Compareable接口

(1).在1.2.3中讲解了String类接入Compareable接口实现对CompareTo这个方法重写,那么我们举一反三,我们的定义的类想要使用Compareable接口是不是也要像源码一样的书写方式!

(2)定义的Student类实现了Compareable接口在源码中有<T>

 那么在使用接口的时候参照源码,把<T>中的T改成Student(因为要比较的是Student)

Student类中设置name和age两个成员变量。

用快捷键生成name 和age的构造方法。

重写toString方法(在调用一个类的时候toString方法会自动调用)

(2) 实例化student1和student2两个对象,传入两个参数name分别为zhangsan和lisa,age分别为10和

 (3)在调用这个接口以后就要对接口中的抽象方法进行重写。(使用接口就要对接口中的抽象方法进行重写)

 (4)通过编译器生成重写的compareTo方法要对它进行改进,

           较name的大小对compareTo方法改进。

         注意: 谁调用comparreTo方法谁就是this.。

public int compareTo(Student o) {
        return this.name.compareTo(o.name);//是字母o不是数字0
    }

(5)name是String类型String类型就要用compare方法进行比较因为他是引用类型。 

(6)最终代码

package demointerface;

class Student implements Comparable<Student>{
    public String name ;
    public int age ;
    public Student(String name ,int age){
        this.name = name ;
        this.age = age ;
    }
    public String toString(){
        return "Student{"+"name=" + name +'\'' + ", age=" + age +'}';
    }

    @Override
    public int compareTo(Student o) {
        return this.name.compareTo(o.name);//是字母o不是数字0
    }
}
public class Test {


    public static void main(String[] args) {
        Student student1 = new Student("zhangsan",10);
        Student student2 = new Student("lisi",3);
    if(student1.compareTo(student2) > 0 ){
        System.out.println("Student1 > Student2");

    }else{
        System.out.println("Student1 <= Student2");
    }
//        String str1 = "zhnagsan";
//        String str2 = "lisi";
//        if(str1.compareTo(str2) > 0){
//            System.out.println("str1 > str2");
//        }else {
//            System.out.println("str1 <= str2");
//        }
    }
}




运行结果

(7)比较年龄compare重写成这样

1. 代码

 public int compareTo(Student o) {
        
    return this.age - o.age;
//        if (this.age - o.age > 0) {
//            return 1;
//        } else if (this.age - o.age == 0) {
//            return 0;
//        } else if (this.age - o.age < 0) {
//            return -1;
//        }
//        return 0;
//    }    //第二行代码可以理解为注释这段代码,这段代码是为了让你更好的理解
//        

}

2.全部代码

package demointerface;

class Student implements Comparable<Student> {
    public String name;
    public int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return "Student{" + "name=" + name + '\'' + ", age=" + age + '}';
    }

    @Override
    public int compareTo(Student o) {
        return this.age - o.age;
    }

}

public class Test {
    public static void main(String[] args) {
        Student student1 = new Student("zhangsan", 10);
        Student student2 = new Student("lisi", 3);
        if (student1.compareTo(student2) > 0) {
            System.out.println("Student1 > Student2");
        } else {
            System.out.println("Student1 <= Student2");
        }
    }
}

2.2compare接口使用的升华 

1.定义一个Student类型的数组,长度为三,对这个数组进行赋值。Student是一个普通的类,通过Arrays.sort对数组进行排序,最后排序完进行输出。(大体思路)

2.在数组中存入了两种类型的参数,这时候编译器就会报错,编译器不知道用哪一个值进行比较就会报错。

代码

package demointerface;

import java.util.Arrays;

class Student {
    public String name;
    public int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }


}

public class Test {
    public static void main(String[] args) {
        Student [] students = new Student[3];
        students[0] = new Student("zhangsan",50);
        students[0] = new Student("lisi",31);
        students[0] = new Student("abc",59);
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
    }
}

运行结果 

 3.可以看到这里爆出一个错误是类型转换错误,这段报错可以看到它的意思是要将这个类型转换为Compareable,灰色的是源码中的报错,我们可以点击灰色进入源码查看错误。

(这里不详细讲解感兴趣,自己点看进行解读)

4.从异常中可以看出,我们的数组要想比较大小就必须要实现compare接口。

5.注意:使用排序的时候要排序的数据一定是可以比较的(明确告知元素和哪些进行比较)。

6.代码改进

(1)将Student类实现compareable接口

(2)重写toString方法和compare方法,这会让其覆盖原来接口的方法和object类中的方法。

(不用tostring方法输出的将会是地址)

(3)使用Arrays.sout方法进行排序(使用这个方法会自动使用compare方法指定的比较我们这里比较的是age)

最终代码

package demointerface;

import java.util.Arrays;

class Student implements Comparable<Student> {
    public String name;
    public int age;


    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }


    public int compareTo(Student o) {
        return this.age - o.age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';

    }


    public static class Test {
        public static void main(String[] args) {
            Student[] students = new Student[3];
            students[0] = new Student("zhangsan", 50);
            students[1] = new Student("lisi", 31);
            students[2] = new Student("abc", 59);
            Arrays.sort(students);
            System.out.println(Arrays.toString(students));
        }
    }
}






 运行结果

1.24.15//不用管一个记号,后续会加入新的内容

    这时候就引出一个疑问?在实际开发中,突然要用name进行排序而不用age进行排序,那么我就要改非常多的代码这时候我该如何处理呢?这时就引入了新的接口来解决这个问题。在标题3中会详细讲解。

3 Comparator接口(比较器)

3.1使用Comparator接口

1.compareable接口使用以后一般情况是不进行修改的,要想修改一般用comparator<>接口,

2.通过年龄比较

(1)定义一个Agecompare类使用Comparator接口

class  Agecompare implements Comparator<Student>{

    }

摁住Ctrl点击Comparator接口进入源代码,我们可以看到有非常多的方法。

其中有一个方法是Compare方法,一个equals方法是能够实现的其他方法都是default修饰的。

其实重写Compare方法就行了,在这里我们用年龄进行比较。

 class  Agecompare implements Comparator<Student>{

        @Override
        public int compare(Student o1, Student o2) {
            return o1.age - o2.age;
        }
    }

 全部代码

package demointerface;

import java.util.Arrays;
import java.util.Comparator;

class Student implements Comparable<Student> {
    public String name;
    public int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }



    public int compareTo(Student o) {
        return this.age - o.age;
    }



    static class AgeComparator implements Comparator<Student> {

        @Override
        public int compare(Student o1, Student o2) {
            return o1.age - o2.age;
        }
    }


    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }


    public static class Test {
        public static void main(String[] args) {
           Student student1 = new Student("zhangsan",10);
           Student student2 = new Student("Lisi",31);

            AgeComparator ageComparator = new AgeComparator();
            System.out.println(ageComparator.compare(student1, student2));

        }
    }
}

由于减完是小于0,所以返回一个小于0的数。

运行结果

3.通过姓名进行比较

(1)由年龄比较转变为姓名比较

(2)定义一个类 Namecompator实现Comparator接口

(3)重写compare方法

 class NameComparator implements Comparator<Student> {

        @Override
        public int compare(Student o1, Student o2) {
            return o1.name.compareTo(o2.name) ;
        }
    }

(4)全部代码
package demointerface;

import java.util.Arrays;
import java.util.Comparator;

class Student implements Comparable<Student> {
    public String name;
    public int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }



    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;
        }
    }

     static class NameComparator implements Comparator<Student> {

        @Override
        public int compare(Student o1, Student o2) {
            return o1.name.compareTo(o2.name) ;
        }
    }


    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }


    public static class Test {
        public static void main(String[] args) {
           Student student1 = new Student("zhangsan",10);
           Student student2 = new Student("Lisi",31);

            NameComparator nameComparator = new NameComparator();
            System.out.println(nameComparator.compare(student1,student2));

        }
    }
}

(5)运行结果是一个正数。(大家把类定义到外面,就不用static修饰了,不要学我!!这样是为了演示方便,找个借口)。

这样哈这样。

 3.2 使用comparator接口使用的升华

(1)定义Students数组,默认使用的Compareable接口中的Compare方法,而我们在Cpmpareable接口重写了Compare方法使其是对年龄进行比较,所以用数组来排序的时候用的还是默认的方法对年龄进行比较。

代码

package demointerface;

import java.util.Arrays;
import java.util.Comparator;
class NameComparator implements Comparator<Student> {

    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name) ;
    }
}
class Student implements Comparable<Student> {
    public String name;
    public int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }



    public int compareTo(Student o) {
        return this.age - o.age;
    }



  static class AgeComparator implements Comparator<Student> {
        

        @Override
        public int compare(Student o1, Student o2) {
            return o1.age - o2.age;
        }
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }


    public static class Test {
        public static void main(String[] args) {

            Student [] students = new Student[3] ;
            students[0] = new Student("zhangsan",18);
            students[1] = new Student("Lisa",31);
            students[2] = new Student("abc",59);
            AgeComparator ageComparator = new AgeComparator();
            Arrays.sort(students,ageComparator);
            System.out.println(Arrays.toString(students));

        }
    }
}

运行结果

 可以看到是对年龄进行比较。

要想用name比较

package demointerface;

import java.util.Arrays;
import java.util.Comparator;
class NameComparator implements Comparator<Student> {

    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name) ;
    }
}
class Student implements Comparable<Student> {
    public String name;
    public int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }



    public int compareTo(Student o) {
        return this.age - o.age;
    }



  static class AgeComparator implements Comparator<Student> {


        @Override
        public int compare(Student o1, Student o2) {
            return o1.age - o2.age;
        }
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }


    public static class Test {
        public static void main(String[] args) {

            Student [] students = new Student[3] ;
            students[0] = new Student("zhangsan",18);
            students[1] = new Student("Lisa",31);
            students[2] = new Student("abc",59);


            Arrays.sort(students);
            System.out.println(Arrays.toString((students)));//默认方法比较comparable接口

            AgeComparator ageComparator = new AgeComparator();//comparator接口用age比较
            Arrays.sort(students,ageComparator);
            System.out.println(Arrays.toString(students));//



            NameComparator nameComparator = new NameComparator();//comparator接口用name比较
            Arrays.sort(students,nameComparator);
            System.out.println(Arrays.toString(students));


        }
    }
}

 可以看出comparator接口是非常灵活的,想重新定义一个比较规则重新写一个就好,再调用这个重新写好的方法就可以了。

compareable接口是只要定义了以后就不修改了,默认了。(也可以修改只不过非常麻烦)

4.Clonable 接口和拷贝

4.1概念

1.java中内置了一些很有用的接口,Clonable接口就是其中之一。

Object类中存在一个clone方法,调用这个方法可以去创建一个对象的“拷贝”,但是要想合法调用clone方法,必须要先实现Clonable接口,否则会抛出一个CloneNotSupporException异常。

4.2Clonable接口的实现

4.2.1Clone方法

1.Colone方法默认继承在Object类,在实现代码的时候不能调用Colone方法。

可以看到并不能调用clone方法 

2 .疑问:为什么无法访问clone方法?

(1)clone方法是被protected修饰的(被protected在不同包只能在子类中访问),要用super进行访问。

3.借助idea快捷键使用clone方法。(Alt+insert+点击Overried Methods)选择clone方法点击ok。

 代码

在Person子类中重写了父类clone()方法。发生向上转型。(底层是c++写的我看不到就不讲解源码了,要是能看到就好了吐槽一下)

class Person{
    public String name ;

    public Person(String name){
        this.name = name ;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

4.在main函数中,通过person1调用clone方法,可以发现报错了,这是为什么?? 

(1) clone是父类类型需要向下转型。

 5.通过强制转换将person1强制转换为Person类型,向下转型后使用clone方法。还是会报错这是为什么??

(1)在这里的thows CloneNotSupportedException是一个异常。(异常篇章会专门写,这里先当你会)链接在这里(javaSE异常)CSDN

6.声明一下代码就报错了。

代码

class Person{
    public String name ;

    public Person(String name){
        this.name = name ;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}


public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("zhangsan");
        //通过person这个引用来克隆一个对象//
        Person person2 = (Person)person1.clone();
    }
}

7.克隆相当于,开辟一个空间将这个克隆完以后的对象放入这个空间。

8.增加输出克隆对象代码,点击运行这段代码的时候发现报错了,这是为什么??

(1)这个异常的意思是,不支持克隆。

(2)这时候就引出了Clonable接口这个概念

4.2.2 Clonable接口的实现

1.代码

Person类实现Cloneable接口,就支持克隆了

class Person implements Cloneable{
    public String name ;

    public Person(String name){
        this.name = name ;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}


public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("zhangsan");
        //通过person这个引用来克隆一个对象//
        Person person2 = (Person)person1.clone();
        System.out.println(person2.name);
    }
}

2.运行结果

 3.Cloneable接口实现后就不报错了,但是我并没有重写Cloneable接口中的抽象方法啊?

(1)进入Cloneale接口的源码

(2)发现这个接口是空的

(3)这个接口是空,称之为,标记接口(如果一个类实现了接口,说明当前个类是可以克隆的,如果没有就是不支持克隆的)

(4)java中有许多able修饰的接口(adj形容词的意思)

 5.深度克隆

5.1.深度克隆前情提要

1.定义一个类是Money,定义一个double类型的成员变量

2. 在Person类中实现Cloneable接口,定义一个Money类型的成语变量m,在构造方法中让这个成员变量等于new Money

3.在Test类中实例化Person1对象

4.将Person1克隆再用Person2指向Person1克隆出的对象

5.将person2中克隆的m.money的money的值为99.9

6.对修改前和修改后的money的值进行输出

代码

class Money{
    public double money =12.5 ;
}
class Person implements Cloneable{
    public String name ;

    public Money m ;

    public Person(String name){
        this.name = name ;
        m = new Money() ;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("zhangsan");
        //通过person这个引用来克隆一个对象//
        Person person2 = (Person)person1.clone();
        System.out.println("修改之前"+person1.m.money);//12.5
        System.out.println("修改之前"+person2.m.money);//12.5
        person2.m.money = 99.99 ;
        System.out.println("修改之后"+person1.m.money);//?99.99
        System.out.println("修改之后"+person2.m.money);//99.99
    }
}


// class Test2 {
//    public static void main1(String[] args) throws CloneNotSupportedException {
//        Person person1 = new Person("zhangsan");
//        //通过person这个引用来克隆一个对象//
//        Person person2 = (Person)person1.clone();
//        System.out.println(person2.name);
//    }
//}

运行结果

7.可以看到无论是person1还是克隆person1的person2的money的大小都被修改成了99.99.

5.1.2疑问?

我明明修改的是person2克隆person1中的money大小为什么全部都被修改了?

5.1.3疑问的解决(引出深拷贝)

1.这张图结合代码进行分析,不进行讲解,这张图非常详细。

 这个就是浅拷贝。(只克隆了person没克隆m)

那么深拷贝就是把m这个对象在克隆一次,(也就是把所有对象拷贝了。完全克隆出一个独立于原来对象的对象)

5.3深度克隆详细讲解

1.代码

​
class Money implements Cloneable {
    public double money = 12.5 ;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Person implements Cloneable {
    public String name ;
    public Money m ;

    public Person(String name){
        this.name = name ;
        m = new Money() ;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp = (Person) super.clone();
        tmp.m = (Money) this.m.clone();
        return tmp ;
    }
}

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("zhangsan");
        //通过person这个引用来克隆一个对象//
        Person person2 = (Person)person1.clone();
        System.out.println("修改之前"+person1.m.money);//12.5
        System.out.println("修改之前"+person2.m.money);//12.5
        person2.m.money = 99.99 ;
        System.out.println("修改之后"+person1.m.money);//12.5
        System.out.println("修改之后"+person2.m.money);//99.99
    }
}

​

2.代码详细讲解

(1)定义了一个 Money 类,实现了 Cloneable 接口,表示可以克隆该对象。

(2)Money 类中定义了一个 double 类型的属性 money,并对其进行了初始化。

(3)重写了 Money 类的 clone() 方法,调用了 super.clone() 方法并返回结果。

(4)定义了一个 Person 类,实现了 Cloneable 接口,表示可以克隆该对象。

(5)Person 类中定义了一个 String 类型的属性 name 和一个 Money 类型的属性 m,分别表示名字和钱数,并对钱数进行了初始化。

(6)定义了 Person 类的构造方法,通过参数设置名字,并实例化了 Money 对象。

(7)重写了 Person 类的 clone() 方法,在其中调用了 super.clone() 方法,并将克隆后的对象进行了类型转换,再将当前对象的 Money 实例也克隆一份并赋值给克隆后的 Person 对象。

(8)定义了一个 Test 类,并实现了 main 方法。

(9)在 main 方法中,实例化了 Person 类对象 person1,传递了名字参数。并打印了 person1 的 Money 属性的初始值。

(10)通过调用 person1 的 clone() 方法克隆了一个 person2 对象,并打印其 Money 属性的初始值。

(11)修改 person2 的 Money 属性的值为 99.99。

(12)分别打印 person1 和 person2 的 Money 属性的值,验证是否发生了修改。

(这十二条拍张照片对着我的代码一行一行看)

3.图解

tmp后面被回收了

 4.深拷贝就看程序员的用法了。

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Frank1-0-2-4

我会继续努力的,十分感谢谢谢你

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值