Java抽象类和接口

目录

1.抽象类

1.1 抽象类的语法

1.2 抽象类的特点

2.Object类

2.1 equals方法

3.接口

3.1 接口的语法

3.2 接口的使用及特性

3.3 Comparable接口和Comparator接口

3.3.1 Compapable接口

3.3.2 Comparator接口

3.4 Cloneable接口和深拷贝


1.抽象类

1.1 抽象类的语法

被abstract修饰的类称为抽象类,被abstract修饰的方法称为抽象方法

abstract class Draw {
    public Draw() {
        System.out.println("Draw的构造方法");
    }
    //抽象方法不能有主体
    public abstract void draw();
    public void func() {
        System.out.println("Draw::func()");
    }
}

抽象方法不可以有主体。

抽象类和其他类一样可以有自己的成员属性和方法,以及构造方法。

1.2 抽象类的特点

1.抽象类与普通类的区别就是:抽象类中可以有抽象方法(也可以没有)

2.抽象类不能直接实例化对象

public static void main(String[] args) {
        //Draw是抽象类
        Draw draw0 = new Draw(); //---Error---
        //会报错
    }

3.抽象方法不可以被private修饰符修饰,被final、static修饰的方法也不能成为抽象方法

abstract class Draw {
    public Draw() {
        System.out.println("Draw的构造方法");
    }
    //抽象方法不能有主体
    public abstract void draw();
    //private abstract void draw1(); ---Error---
    //public final abstract void draw2();   ---Error---
    //public static abstract void draw3();  ---Error---
    public void func() {
        System.out.println("Draw::func()");
    }
}

4.当抽象类被继承后,子类必须要重写父类(抽象类) 的抽象方法,如果子类不想重写抽象方法,那么子类必须是抽象类,但是当子类再次被继承时,子类的子类必须重写所有的抽象方法。

比如:类A是抽象类,抽象类 类B继承了类A,类C继承了类B,那么类C中必须重写类A和类B中的所有抽象方法。

5.抽象类也有多态性

2.Object类

Object类是所有类的父类,所以,所有类都可以重写或直接调用Object类中的方法

2.1 equals方法

equals方法是比较两个变量是否相等,范围boolean类型

原码如下:

public boolean equals(Object obj) { 
    return (this == obj); // 使用引用中的地址直接来进行比较
}

如果要比较的是像int、char这种基本类型的数值,可以直接使用原码的equals方法

如果要比较两个引用的地址,也可以直接使用equals方法

但是如果比较的两个对象,那么就需要重写equals方法

class Person1 {
    public String name;
    public int age;

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

    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof Person1)) {
            return false;
        }
        Person1 person = (Person1) obj;
        if (this.name.equals(person.name) && this.age == person.age) {
            return true;
        }
        return false;
    }
}
public class Test {

    public static void main(String[] args) {
        Person1 person1 = new Person1("张三", 18);
        Person1 person2 = new Person1("张三", 18);
        //System.out.println(person1.equals(person2)); // 没重写equals方法前是 false
        System.out.println(person1.equals(person2));//重写后是true
    }
}

3.接口

3.1 接口的语法

1.被interface修饰的是接口

2.接口中的成员变量默认是public static final类型

3.接口中的方法默认是public abstract类型

interface USB {
    //普通成员会默认为public static final类型
    public static final int ret = 10;
    int ret1 = 20;

    public abstract void open();

    void close();//默认public abstract类型
}

3.2 接口的使用及特性

1.接口与接口之间的使用时继承关系,接口可以继承另一个接口。

2.接口与类之间的使用要用 implements 实现关系,并且一个类可以同时接收多个接口。

3.类接收接口之后必须重写接口中的抽象方法,如果不想重写,那么类必须是抽象类。

4.接口不可以被实例化。

5.接口中的方法只能被 public abstract 修饰,且不能被实现,在 jdk1.8 及以后可以有 static 修饰或者被 default 修饰的方法且可以实现,除此之外,不可以被其他修饰符修饰。

6.接口中不能有静态代码块和构造方法

interface USB {
    //普通成员会默认为public static final类型
    public static final int ret = 10;
    int ret1 = 20;

    public abstract void open();//默认public abstract类型

    void close();

    public static void func() {
        System.out.println("jdk1.8及以后 接口中可以有 static 方法");
    }

    default void fun() {
        System.out.println("jdk1.8及以后 接口中可以有 default 修饰的方法");
    }
}
interface USB1 {

}
/**
 * 1.如果不想重写接口中的抽象类 必须被修饰成抽象类
 * 但是如果有其他类继承了这个类 那么仍然需要重写这些方法
 */
abstract class A implements USB {

}

/**
 * 1.重写的方法不能用默认的访问权限 因为重写后的范围要大于等于之前的范围
 * 2.类和接口之间用 implements 来实现多个接口
 */
class Mouse implements USB,USB1 {
    public void open() {
        System.out.println("打开鼠标");
    }

    public void close() {
        System.out.println("关闭鼠标");
    }

    public void use() {
        System.out.println("使用鼠标");
    }
}

3.3 Comparable接口和Comparator接口

3.3.1 Compapable接口

我们在进行自定义类型比较的时候,没办法直接通过简单的 大于、小于、等于 来判断,这时我们可以在类中添加一个Compapable接口,并重写里面的compareTo方法

compareTo方法中自己去设置比较的条件,下面举一个例子

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

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

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

    @Override
    public int compareTo(Student o) {
        return this.age - o.age;
    }
}
public static void main(String[] args) {
        Student student1 = new Student("bit", 10);
        Student student2 = new Student("hello", 40);
        if (student1.compareTo(student2) > 0) {
            System.out.println("student1 > student2");
        } else {
            System.out.println("student1 <= student2");
        }
    }

compareTo的返回是int类型,我们定义了一个Student类,里面有nameage属性,代码里面是用age的大小来做比较的条件,那么当我们想通name来做比较的条件就会变得很复杂,因为compareTo方法也叫被重写过了,这时就可以用到另一个接口Comparator

3.3.2 Comparator接口

当我们需要对一个自定义类型用多种方式来进行比较大小时,就可以再定义一个新的类,让新的类去继承Comparator接口,然后去实现里面的compare方法(返回值也是int),来达到用多种方式比较自定义类型大小的目的。

实例如下:

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

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

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

    @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 NameComparator implements Comparator<Student> {

    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}
public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("bit", 10);
        students[1] = new Student("hello", 40);
        students[2] = new Student("abc", 30);

        AgeComparator ageComparator = new AgeComparator();
        Arrays.sort(students, ageComparator);
        System.out.println(Arrays.toString(students));

        NameComparator nameComparator = new NameComparator();
        Arrays.sort(students, nameComparator);
        System.out.println(Arrays.toString(students));
    }

实例中分别用了两个类去实现Student类用name比较大小和用age比较大小,最后的结果大家可以自己去试一下。

3.4 Cloneable接口和深拷贝

当我们想将一个对象拷贝到另一个相同类型的对象里去时,需要调用Object类里的clone方法,但是要调用这个方法需要要先实现Cloneable接口,否则就会抛出 CloneNotSupportedException 异常。

举个例子:

class Money {
    public double m = 12.5;
}

/**
 * 调用Object类的clone方法 必须要接收Cloneable接口
 * 并且要重写clone()方法
 * 用protected修饰的 在不同包中访问 需要用super
 */
class Person implements Cloneable{
    public int id;
    public Money money = new Money();
    /**
     * 浅拷贝
     * 浅拷贝是将这个类对象拷贝过去,但是其里面的组合对象不会再拷贝一份,而是指向同一个对象
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                '}';
    }
}
public class Test3 {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1 = new Person();
        person1.id = 99;
        Person person2 = (Person)person1.clone();
    }
}

我们可以看到,在Person类中有一个组合对象money,当我们拷贝了person1给到person2后,money里面的数据并不会拷贝一份,而是两个Person类对象的money指向了同一块数据,当person1或者person2区修改money里面的数据时,另一个的money也会跟着修改,这是浅拷贝。

那么如果我们想要两个Person对象里面的money不指向同一块数据,就需要进行深拷贝。

实例如下:

class Money implements Cloneable{
    public double m = 12.5;

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

class Person implements Cloneable{
    public int id;
    public Money money = new Money();
    /**
     * 浅拷贝
     * 浅拷贝是将这个类对象拷贝过去,但是其里面的组合类对象不会再拷贝一份,而是指向同一个对象
     */
//    @Override
//    protected Object clone() throws CloneNotSupportedException {
//        return super.clone();
//    }
    /**
     * 深拷贝
     * 深拷贝是指将这个对象 及其里面的组合类对象 全部拷贝一份,
     * 与浅拷贝不同地方在于,拷贝出来的对象里面的组合对象不会和圆对象指向同一个
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp = (Person)super.clone();
        tmp.money = (Money)this.money.clone();
        return tmp;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                '}';
    }
}

public class Test3 {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1 = new Person();
        person1.id = 99;
        Person person2 = (Person)person1.clone();
        person2.money.m = 1999;
        System.out.println("person1: " + person1.money.m);
        System.out.println("person2: " + person2.money.m);
    }
}

我们先将person1的数据进行浅拷贝到一个的Person类对象,然后将person1的money拷贝到新对象中的money(Money类也序要实现clone接口),这时两个对象的money的指向就不同了,但是里面的数据时相同的,这就是深拷贝。

  • 17
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

追梦不止~

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值