Java基础-理解抽象类和接口

本文详细介绍了Java中的抽象类和接口。抽象类主要用于被继承,提供了一种强制子类重写特定方法的方式,防止误用。接口则是抽象类的进一步抽象,所有方法默认为抽象,字段只能是静态常量。文中提到了Comparable、Comparator和Cloneable三个常用的接口及其应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、抽象类

class Shape {
    public void draw() {

    }
}

class Rect extends Shape{
    @Override
    public void draw() {
        System.out.println("♦");
    }
}

class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println("○");
    }
}

class Flower extends Shape {
    @Override
    public void draw() {
        System.out.println("❀");
    }
}
class Triangle extends Shape {
    @Override
    public void draw() {
        System.out.println("△");
    }
}


1.1 语法规则

我们从以上的代码可以发现,父类Shape中的draw方法是一个空方法,没有什么实际的功能,具体的实现都是通过子类重写draw方法来实现的,因此像这种没有什么实际功能的方法可以将其设计为抽象方法,而包含抽象方法的类叫抽象类。

abstract class Shape {
abstract public void draw();
}
  1. 在方法前加abstrcat关键字,表示这是一个抽象方法,同时抽象方法没有方法体;
  2. 在类名前面加abstract关键字,表示这是一个抽象类

1.2 注意事项

  1. 抽象类不能直接实例化.
Shape shape = new Shape();
// 编译出错

像这样的代码会报错,抽象类不能直接实例化

  1. 抽象类中可以和普通类一样拥有成员变量和方法,这个非抽象方法和普通方法的规则都是一样的, 可以被重写,也可以被子类直接调用
abstract class shape{
    public int age;
    public static int count;
    public void func() {
      }
    public abstract void draw();
}
  1. 抽象类是可以被继承的,并且可以发生向上转型
public class TestDemo {
    public static void drawMap(Shape shape) {
        shape.draw();
    }
    public static void main(String[] args) {
        drawMap(new Rect());
        drawMap(new Circle());
    }
}
  1. 当一个普通类继承的抽象类,当前普通类一定要重写抽象类当中的抽象方法
class Shape {
    public void draw() {

    }
}

class Rect extends Shape{
    @Override
    public void draw() {
        System.out.println("♦");
    }
}
  1. 抽象方法不能是私有的,因为抽象方法就是通过继承来实现细节的,而将抽象方法设置为私有的,将不能被继承
abstract class Shape {
abstract private void draw();
}
// 编译出错

1.3 抽象类的作用

抽象类存在的最大意义就是为了被继承。
使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类了,使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 因此可以让我们尽早发现问题.充分利用编译器的校验, 在实际开发中是非常有意义的。

二、接口

接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含静态常量.

2.1 语法规则

我们可以将刚才的抽象类Shape设计为一个接口

interface IShape {
void draw();
}
class Cycle implements IShape {
@Override
public void draw() {
System.out.println("○");
}
}

使用关键字interface 来标记为一个接口

2.2 注意事项

  1. 接口当中的方法 一定是抽象方法,因此不能有具体实现,接口当中的方法默认是:public abstract
interface IShape {
    public abstract void draw();
    //也可以简写为
    void draw();
}
  1. 接口当中的成员变量,默认是 public static final,在定义的时候必须赋初值。
interface Ishape{
    public static final int age=10;
    //也可以简写为
    int age=10;
}
  1. 使用default修饰的方法可以有具体的实现
interface IShape {
    default void func() {
        System.out.println("hahaha!");
    }
   
}
  1. 接口不可以进行实例化
public class TestDemo {
    public static void main(String[] args) {
       IShape shape = new  IShape();
        // 编译出错
    }
}

  1. 类和接口之间通过implements实现
interface Ishape{
    void draw();
}

class Rect implements Ishape{
    @Override
    public void draw() {
        System.out.println("♦");
    }
}

class Circle implements Ishape{
    @Override
    public void draw() {
        System.out.println("⚪");
    }
}

  1. 一个类可以继承类,同时实现多个接口
interface A{
    void funcA();
}

interface B{
    void funcB();
}

interface C{
    void funcC();
}

abstract class TestAbstract{
    public abstract void funcTestAbstract();
}
class Test extends TestAbstract implements A,B,C{
    @Override
    public void funcA() {
    }

    @Override
    public void funcB() {
    }

    @Override
    public void funcC() {
    }

    @Override
    public void funcTestAbstract() {
    }
}
  1. 一个接口可以扩展多个接口,解决了多继承的问题
interface A{
    void funcA();
}

interface B{
    void funcB();
}

interface C{
    void funcC();
}

interface D extends A,B,C{
    void funcD();
}


2.3 常用的三个接口

class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "[" + this.name + ":" + this.score + "]";
}
}

Student[] students = new Student[] {
new Student("张三", 95),
new Student("李四", 96),
new Student("王五", 97),
new Student("赵六", 92),
};

现在想要给这个学生对象数组排序,而在数组中我们有一个现成的 sort 方法, 能否直接使用这个方法呢?

Arrays.sort(students);
System.out.println(Arrays.toString(students));
// 运行出错, 抛出异常.
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to
java.lang.Comparable
  1. Comparable接口

让Student 类实现 Comparable 接口, 并实现其中的 compareTo 方法

class Student implements Comparable {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "[" + this.name + ":" + this.score + "]";
}
@Override
public int compareTo(Object o) {
Student s = (Student)o;
if (this.score > s.score) {
   return -1;
} else if (this.score < s.score) {
   return 1;
} else {
   return 0;
}
}
}

当实现Comparable接口并重写compareTo方法后,在 sort 方法中会自动调用 compareTo 方法. compareTo 的参数是 Object , 其实传入的就是 Student 类型的对象.然后比较当前对象和参数对象的大小关系(按分数来算)

// 执行结果
[[王五:97], [李四:96], [张三:95], [赵六:92]]
  1. Comparator接口
class Student2 {
    public String name;
    public int score;

    public Student2(String name, int score) {
        this.name = name;
        this.score = score;
    }

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

}
public class TestDemo2 {

    public static void main(String[] args) {
        Student2[] students = new Student2[3];
        students[0] = new Student2("aaa",89);
        students[1] = new Student2("abc",19);
        students[2] = new Student2("def",59);
        System.out.println(Arrays.toString(students));
        System.out.println("===============根据分数排序==============");
        ScoreComparator scoreComparator = new ScoreComparator();
        Arrays.sort(students,scoreComparator);
        System.out.println(Arrays.toString(students));
    }
}

在类外写一个分数比较的接口实现Comparator接口,并重写Compare方法

public class ScoreComparator implements Comparator<Student2> {
    @Override
    public int compare(Student2 o1, Student2 o2) {
        if(o1.score > o2.score) {
            return 1;
        }else if(o1.score == o2.score) {
            return 0;
        }else {
            return -1;
        }    
    }
}
// 执行结果
[[aaa:89], [def:59], [abc:19]]
  1. Cloneable接口
    在Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常.
    如何使用Cloneable 接口实现 “深拷贝”?
class Money implements Cloneable{
    public double money = 12.8;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Person implements Cloneable{
    public String name;

    public Money m = new Money();

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

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

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


    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("张三");
        Person person2 = (Person)person1.clone();
        System.out.println(person1.m.money);
        System.out.println(person2.m.money);
        person2.m.money = 99.99;
        System.out.println(person1.m.money);
        System.out.println(person2.m.money);
    }


// 执行结果
12.8
12.8
12.8
99.99

在重写clone方法的时候,首先需要将person1克隆一份得到person2,然后再将当前对象的m克隆一份给person2.m,此时就实现了深拷贝。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值