【Java】抽象类&接口

目录

1.抽象类

2.接口

2.1实现多个接口

2.2接口之间的关系

2.3接口使用实例

2.3.1Comparable接口

2.3.2Comparator接口

2.3.2Clone接口

2.4抽象类与接口的区别


1.抽象类

定义:抽象方法:这个方法没有具体的实现;

           抽象类:不能完全代表一个具体的对象。

注意

1> 使用 abstract 修饰;

2> 抽象类不能进行实例化,但普通类可以;

3> 抽象类中不一定包含抽象方法,但包含抽象方法的类一定是抽象类;

4> 抽象类中可以定义普通的成员变量和成员方法;

5> 抽象类存在的最大意义就是为了被继承,且多了一层编译器的校验;

6> 普通类继承抽象类后要重写抽象类中的抽象方法;

7> 抽象类A继承抽象类B后不需要重写,但当普通类C再继承抽象类A后,要重写所有没被重写的抽象方法;

8> 要满足重写的要求(如static和private不能被重写);

9> final关键字不可能和abstract同时作用在一个类或方法上;

10> 抽象类当中可以存在构造方法,在子类实例化时,会帮助父类的成员进行初始化。

abstract class Shape { //抽象类
    public int a;//普通成员变量
    public void print() { //普通成员方法
        System.out.println("Shape");
    }
    public abstract void draw(); //抽象方法
}
class Cycle extends Shape { //普通类
    @Override //普通类继承抽象类后要重写抽象类中的抽象方法
    public void draw() {
        System.out.println("○");
    }
}
abstract class Flower extends Shape {
    //抽象类继承抽象类,可以不重写父类的抽象方法
    abstract public void printf();//抽象方法
}
class Square extends Flower {
    @Override //见注意事项6
    public void draw() {
        System.out.println("□");
    }
    @Override
    public void printf() {
        System.out.println("❀");
    }
}

2.接口

定义:对公共行为的规范标准,是一种引用数据类型。相当于抽象类的进一步抽象。

注意

1> 使用 interface 定义;

2> 接口中不能有实现的方法,但是静态方法和被default修饰的方法可以实现;

3> 接口中的成员方法默认是public abstract修饰的;

4> 接口中的成员变量默认是public static final 修饰的;

5> 不能通过关键字new来实例化;

6> 类和接口之间使用implement进行关联;

7> 类实现接口后要重写接口中的抽象方法

8> 接口中存在default方法时可重写可不重写,具体看业务需求;

9> 不论是接口还是抽象类,都有向上转型

10> 子类实现接口方法时,这个方法一定要public修饰;

11> 接口中没有构造方法和代码块

12> 当一个类不想实现接口当中的方法时,这个类可以被定义为抽象类;

13> 接口的修饰符可以为abstract、public,不能为protected、private、final

interface IShape { //接口
    //成员方法默认为public abstract修饰,顾下列方法均为抽象方法
    public abstract void draw1();//抽象方法不可实现,public abstract可省略
    public void draw2();//抽象方法不可实现,public可省略
    public static void draw3() { //静态方法可以实现
        System.out.println("draw3");
    }
    default public void draw4() { //被default修饰的方法可以实现
        System.out.println("draw4");
    }
}
class Cycle implements IShape { //Cycle类实现了IShape接口
    @Override //重写接口中的抽象方法
    public void draw1() {
        System.out.println("○");
    }
    @Override //重写接口中的抽象方法
    public void draw2() {
        System.out.println("□");
    }
}
class Rect implements IShape { //同上
    @Override
    public void draw1() {
        System.out.println("□");
    }
    @Override
    public void draw2() {
        System.out.println("○");
    }
}
public class Test {
    public static void drawMap(IShape shape) { //多态
        shape.draw1();
    }

    public static void main(String[] args) {
        //IShape iShape = new IShape();//接口无法实例化自己
        IShape iShape1 = new Cycle();
        IShape iShape2 = new Rect();//向上转型

        drawMap(new Cycle());
        drawMap(new Rect());
    }
}

2.1实现多个接口

意义:一个类实现多个接口,可以解决Java中多继承的问题

注意:先继承类,再实现接口。

interface IFlying { //接口1
    void fly();
}
interface ISwimming { //接口2
    void swim();
}
interface IRunning { //接口3
    void run();
}
abstract class Animal { //抽象父类
    public String name;
    public int age;
    public Animal(String name, int age) { //带两个参数的构造方法
        this.name = name;
        this.age = age;
    }
    public abstract void eat(); //抽象方法
}
class Dog extends Animal implements IRunning,ISwimming{ //子类1
    public Dog(String name, int age) { //子类的构造方法
        super(name, age);
    }
    @Override //重写父类和接口的抽象方法
    public void swim() {
        System.out.println(this.name+"正在狗刨");
    }
    @Override
    public void run() {
        System.out.println(this.name+"正在跑");
    }
    @Override
    public void eat() {
        System.out.println(this.name+"正在吃狗粮");
    }
}
class Bird extends Animal implements IFlying { //子类2
    public Bird(String name, int age) { //子类的构造方法
        super(name, age);
    }
    @Override //重写父类和接口的抽象方法
    public void fly() {
        System.out.println(this.name+"正在飞");
    }
    @Override
    public void eat() {
        System.out.println(this.name+"正在吃虫子");
    }
}
public class Test {
    public static void testEat(Animal animal) { //多态
        animal.eat();
    }
    public static void testFly(IFlying iFlying) { //多态
        iFlying.fly();
    }
    public static void testRun(IRunning running) { //多态
        running.run();
    }
    public static void testSwim(ISwimming iSwimming) { //多态
        iSwimming.swim();
    }
    public static void main(String[] args) {
        testEat(new Bird("小鸟",3));
        testEat(new Dog("小狗",3));
        testFly(new Bird("小小鸟",2));
        testRun(new Dog("小小狗",2));
        testSwim(new Dog("小小小狗",1));
    }
}

2.2接口之间的关系

接口与接口之间关联用 extends,意为拓展,非继承。相当于把接口合并在一起。

interface A {
    void testA();
}
interface B {
    void testB();
}
interface C extends A,B { //此时C接口不仅有自己的功能,还有A接口和B接口的功能
    void testC();
}
class D implements C { //ABC中的抽象方法都要重写
    @Override
    public void testA() {
    }
    @Override
    public void testB() {
    }
    @Override
    public void testC() {
    }
}

2.3接口使用实例

2.3.1Comparable接口

//只根据年龄或成绩比较:

import java.util.Arrays;
class Student implements Comparable{ //当对自定义类型进行比较时,一定要实现可比较的接口
    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;
    }
    @Override //重写Comparable接口中的抽象方法
    public int compareTo(Student o) { //按年龄排序
        /*if (this.age - o.age > 0) {
            return 1;
        } else if (this.age - o.age == 0) {
            return 0;
        }else {
            return -1;
        }*/
        return this.age - o.age;
    }
}
public class Test {
    //模拟实现冒泡排序
    public static void bubbleSort(Comparable[] comparables) { //传入Comparable类型(实现了可比较接口)的数组
        for (int i = 0; i < comparables.length-1; i++) {
            for (int j = 0; j < comparables.length-1-i; j++) {
                //if (comparables[j]>comparables[j+1]) //无法直接比较
                if(comparables[j].compareTo(comparables[j+1]) > 0) { //使用重写的compareTo方法比较
                    Comparable tmp = comparables[j];
                    comparables[j] = comparables[j+1];
                    comparables[j+1] = tmp;
                }
            }
        }
    }
    public static void main(String[] args) {
        Student[] array = new Student[2];
        array[0] = new Student("zhangsan",20,88.8);
        array[1] = new Student("lisi",18,90);
        bubbleSort(array); //冒泡排序
        System.out.println("排序后:"+Arrays.toString(array));
    }
    public static void main2(String[] args) {
        Student student1 = new Student("xiaoming",14,98.5);
        Student student2 = new Student("xiaohong",16,59.9);
        int ret = student1.compareTo(student2);
        System.out.println(ret); //-1
    }
    public static void main1(String[] args) {
        Student[] array = new Student[3];
        array[0] = new Student("zhangsan",20,88.8);
        array[1] = new Student("lisi",18,90);
        array[2] = new Student("wangwu",21,68.9);
        System.out.println("排序前:"+ Arrays.toString(array));
        Arrays.sort(array); //Java自带的方法
        System.out.println("排序后:"+ Arrays.toString(array));
    }
}

2.3.2Comparator接口

//年龄成绩均可比较: 更加灵活

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;
    }
}
class AgeComparator implements Comparator { //比较年龄
    @Override
    public int compare(Student o1, Student o2) {
        return o1.age - o2.age;
    }
}
class ScoreComparator implements Comparator { //比较成绩
    @Override
    public int compare(Student o1, Student o2) {
        return (int)(o1.score - o2.score);//score为double类型,需要强转为int类型
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student("xiaoming",14,98.5);
        Student student2 = new Student("xiaohong",16,59.9);

        AgeComparator ageComparator = new AgeComparator();
        int ret = ageComparator.compare(student1,student2);
        System.out.println(ret);//-2

        ScoreComparator scoreComparator = new ScoreComparator();
        int ret2 = scoreComparator.compare(student1,student2);
        System.out.println(ret2);//38
    }
}

2.3.2Clone接口

class Student implements Cloneable { //实现Cloneable接口
    public int age;
    public Student(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                '}';
    }
    @Override
    protected Object clone() throws CloneNotSupportedException { //异常
        return super.clone();//子类重写的Object只是调用了父类的clone方法
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1 = new Student(18);
        Student student2 = (Student) student1.clone();//向下转型,clone类型为Object,需强转为Student
        System.out.println(student1);//Student{age=18}
        System.out.println(student2);//Student{age=18} 克隆成功
    }
}

【Java】抽象类&接口_第1张图片

Ctrl+点击进入Cloneable接口后发现,该接口内什么东西都没有,why??

:这个接口被叫做标记接口,实现该接口证明当前的类是可以被克隆的。

//浅拷贝 

class Money {
    public double money;
}
class Student implements Cloneable { 实现Cloneable接口
    public int age;
    public Money m = new Money();
    public Student(int age) {
        this.age = age;
    }
    @Override //重写接口中的抽象方法
    protected Object clone() throws CloneNotSupportedException { 
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1 = new Student(18);
        student1.m.money = 9.15;
        Student student2 = (Student) student1.clone();//克隆student1

        System.out.println(student1.m.money);//9.15
        System.out.println(student2.m.money);//9.15

        student1.m.money = 10;//更改student1
        System.out.println(student1.m.money);//10 按理说只有student1变
        System.out.println(student2.m.money);//10 但是实际上两个都变了
                                             //这就是浅拷贝,没有克隆当前对象内更深层的变量
    }
}

//深拷贝

class Money implements Cloneable { //实现Cloneable接口
    public double money;
    @Override //重写接口中的抽象方法
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Student implements Cloneable { //实现Cloneable接口
    public int age;
    public Money m = new Money();
    public Student(int age) {
        this.age = age;
    }
    @Override //重写接口中的抽象方法
    protected Object clone() throws CloneNotSupportedException {
       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(18);
        student1.m.money = 9.15;
        Student student2 = (Student) student1.clone();//克隆student1

        System.out.println(student1.m.money);//9.15
        System.out.println(student2.m.money);//9.15

        student1.m.money = 10;//更改student1
        System.out.println(student1.m.money);//10    深拷贝,只修改了student1
        System.out.println(student2.m.money);//9.15  不影响student2内的值
    }
}

2.4抽象类与接口的区别

区别

抽象类(abstract) 接口(interface)
结构组成 普通成员变量+抽象方法 抽象方法+全局变量
权限 各种权限 public
子类使用 使用extends继承抽象类 使用implement实现接口
关系 一个抽象类可以实现若干接口 借口不能继承抽象类,但可使用extends拓展多个父接口
子类限制 一个子类只能继承一个抽象类 一个子类可以实现多个接口

Over!五一结束啦~~

你可能感兴趣的:(Java,抽象类,接口,深拷贝,浅拷贝,Clone接口)