当前位置: 首页 > article >正文

JavaSE之抽象类和接口

文章目录

  • 抽象类
    • 抽象类概念
    • 抽象类语法
    • 抽象类要点总结
  • 接口
    • 接口的概念
    • 接口实例
    • 接口间的多继承
    • 接口要点总结
    • Comparable接口
    • Comparator接口
    • Clonable接口
      • 深拷贝的代码实现
    • 抽象类和接口的区别

        在这里插入图片描述

                                           给个关注叭
      在这里插入图片描述

  个人主页

  JavaSE专栏

前言:本篇文章主要整理了抽象类的概念及语法、抽象类要点总结.接口的概念,通过实例进一步理解接口、接口间的多继承、接口要点总结、Comparable接口、Comparator接口、Cloneable接口、浅拷贝和深拷贝代码实现及其堆栈图、抽象类和接口的区别。

抽象类

抽象类概念

  在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,那么这样的类就是抽象类。
比如:
在这里插入图片描述

  1. Animal类是动物类,其内部有一个bark方法,每个动物都有不同叫的方法,但是由于Animal类不是一个具体的动物,因此其内部bark()方法无法具体实现
  2. Dog是狗类,与Animal类是继承关系,其次狗是一种具体的动物,其bark方法有具体的叫法,“汪汪汪”
  3. Cat是猫类,与Animal类是继承关系,其次猫是一种具体的动物,其bark方法有具体的叫法,“喵喵喵”
  4. 所以这种Animal类中的bark()方法不需要有具体的实现,那么可以把Animal类设置为抽象类,只需让其具体的子类根据需要去重写这个抽象方法

在打印图形例子中, 我们发现, 父类 Shape 中的 draw 方法好像并没有什么实际工作, 主要的绘制图形都是由 Shape的各种子类的 draw 方法来完成的. 像这种没有实际工作的方法, 我们可以把它设计成一个 抽象方法, 包含抽象方法的类我们称为 抽象类


抽象类语法

  抽象类需要用abstract的关键字来修饰类,同时abstract关键字也可以修饰方法,被abstract修饰的方法称为抽象方法,抽象方法可以没有具体的实现。代码示例如下:

// 抽象类:被abstract修饰的类
public abstract class Shape {
// 抽象方法:被abstract修饰的方法,没有方法体
    abstract public void draw();
    abstract void calcArea();
// 抽象类也是类,也可以增加普通方法和属性
    public double getArea(){
        return area;
    }
    protected double area; // 面积
}

抽象类首先是一个类,和普通类一样,可以有普通方法和变量,甚至构造方法,可以被继承,唯一不同的是抽象类不能实例化对象

抽象类要点总结

  1. abstract修饰的类称为抽象类,被abstract修饰的方法称为抽象方法,抽象方法可以没有具体的实现
  2. 抽象类和普通类一样,可以定义普通类中的成员变量和成员方法,构造方法
  3. 抽象类不能实例化对象
  4. 如果一个类中包含抽象方法,那么这个类一定是抽象类(被abstract修饰)
  5. 抽象类就是用来被继承的,继承后,子类一定要重写抽象类中的所有抽象方法,不然会有红线

在这里插入图片描述
在子类B中要重写抽象类A中的所有抽象方法,代码示例如下:

   @Override
   public void func1() {
      
  }
  1. 如果不想重写抽象类的抽象方法,那么可以同样用abstract修饰子类;但是“出来混迟早是要还的”,如果再有一个类继承了这个类(已经继承了抽象类的类),那么必须重写这两个类中所有的抽象方法。

在这里插入图片描述
这里虽然B类使用abstract关键字修饰来避免了重写父类A中的抽象方法,但是C类继承了B类,C类还是要把A类和B类中的所有抽象方法全部重写
代码示例如下:

class C extends B {

   @Override
   public void func1() {
       
   }

   @Override
   public void func2() {

   }
}
  1. 抽象方法既然要被重写,就要遵循重写的规则,抽象方法不能被final、private、static修饰
  • 被private关键字修饰后,说明这个变量或方法只能在当前类中被访问。有关private关键字的更多介绍,请移步 封装.访问限定符
  • 被static关键字修饰后,说明这个变量或方法是当前类的变量或方法,不属于某一个具体的对象,是所有对象共享的;随类的加载而创建,随类的销毁而卸载;而且只随类的创建加载一次,再次加载类或者new一个对象时,不会再次加载。有关static关键字的更多介绍,请移步 封装.static

接口

接口的概念

  接口类似一种功能,只要某个事物具备这样的功能,都可以实现这个接口。(公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。)
在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。


接口实例

  实例一、
     定义IShpe接口,Rect、Triangle、Cycle三个类实现IShape接口

public interface IShape {
    void draw();//默认被public abstract修饰,建议不加,代码更简洁
}
public class Rect implements IShape{
    @Override
    public void draw() {
        System.out.println("画一个矩形...");
    }
}
public class Triangle implements IShape{
    @Override
    public void draw() {
        System.out.println("画一个三角形...");
    }
}
public class Cycle implements  IShape{
    @Override
    public void draw() {
        System.out.println("画一个圆...");
    }
}
public class Test {
    public static void drawShape(IShape shape) {
        shape.draw();
    }
    public static void main(String[] args) {
        IShape rect = new Rect();
        IShape triangle = new Triangle();
        IShape cycle = new Cycle();
        drawShape(rect);
        drawShape(triangle);
        drawShape(cycle);
    }
}

运行结果:
画一个矩形…
画一个三角形…
画一个圆…

结果表明,向上转型也可以体现在类实现接口的关系上(同时也体现出了动态绑定和多态)

  实例二、
     实现笔记本电脑使用USB鼠标、USB键盘

  1. USB接口:包含打开设备、关闭设备功能
public interface IUsb {
    void openDevice();
    void closeDevice();
}
  1. 鼠标类:实现USB接口,并具备点击功能
public class Mouse implements IUsb{
    @Override
    public void openDevice() {
        System.out.println("连接鼠标...");
    }

    @Override
    public void closeDevice() {
        System.out.println("关闭鼠标...");
    }
    public void click() {
        System.out.println("点击鼠标...");
    }
}
  1. 键盘类:实现USB接口,并具备输入功能
public class KeyBoard implements IUsb{

    @Override
    public void openDevice() {
        System.out.println("连接键盘...");
    }

    @Override
    public void closeDevice() {
        System.out.println("关闭键盘...");
    }
    public void input() {
        System.out.println("输入数据...");
    }
}
  1. 笔记本类:包含开机功能、关机功能、使用USB设备功能
public class Computer {
    public void openPower() {
        System.out.println("打开电脑...");
    }

    public void closePower() {
        System.out.println("关闭电脑...");
    }

    public void IUsbService(IUsb usb) {
        usb.openDevice();
        if(usb instanceof Mouse) {
            Mouse mouse = (Mouse) usb;
            mouse.click();
        }else if(usb instanceof KeyBoard) {
            KeyBoard keyBoard = (KeyBoard) usb;
            keyBoard.input();
        }
        usb.closeDevice();
    }
}
  1. 测试类
public class Test {
    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.openPower();
        //使用鼠标
        computer.IUsbService(new Mouse());
        //使用键盘
        computer.IUsbService(new KeyBoard());
        computer.closePower();
    }
}

运行结果:
打开电脑…
连接鼠标…
点击鼠标…
关闭鼠标…
连接键盘…
输入数据…
关闭键盘…
关闭电脑…

  实例三、
    一个类实现多个接口,定义Animal、Dog、Bird、Duck类,定义IRunable、ISwimable、IFlyable接口。让这些动物类实现合适的一个或多个接口
接口定义:

public interface IRunning {
    void run();
}

public interface ISwimming {
    void swim();
}

public interface IFlying {
    void fly();
}

各种类的定义

public class Animal {
    String name;
    int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println("正在吃...");
    }
}

下面的代码展示了 Java 面向对象编程中最常见的用法: 一个类继承一个父类, 同时实现多种接口.

public class Dog extends Animal implements IRunning,ISwimming{
    public Dog(String name,int age) {
        super(name,age);
    }

    @Override
    public void run() {
        System.out.println(this.name + " 正在跑...");
    }

    @Override
    public void swim() {
        System.out.println(this.name + " 正在游...");
    }
}
public class Bird extends Animal implements IFlying{
    public Bird(String name,int age) {
        super(name,age);
    }

    @Override
    public void fly() {
        System.out.println(this.name + " 正在飞...");
    }
}
public class Duck extends Animal implements IRunning,ISwimming,IFlying{
    public Duck(String name,int age) {
        super(name,age);
    }

    @Override
    public void run() {
        System.out.println(this.name + " 正在跑...");
    }

    @Override
    public void swim() {
        System.out.println(this.name + " 正在游...");
    }

    @Override
    public void fly() {
        System.out.println(this.name + " 正在飞...");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog("旺财",3);
        Bird bird =  new Bird("小飞飞",1);
        Duck duck = new Duck("唐老鸭",5);
        walk(dog);
        walk(duck);

        fly(bird);
        fly(duck);
    }
    public static void walk(IRunning iRunning) {
        iRunning.run();
    }

    public static void fly(IFlying iFlying) {
        iFlying.fly();
    }
}

运行结果:
旺财 正在跑…
唐老鸭 正在跑…
小飞飞 正在飞…
唐老鸭 正在飞…

run方法和fly方法,使用接口这种引用类型作为参数,可以不用关注类的调用者的具体类型,只要这个类具备这个功能特性(实现了这个接口),就可以使用


接口间的多继承

  在Java中,类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承。即:用接口可以达到多继承的目的.比如接口C 继承接口A和接口B,那C就具A和B的功能特性,当一个类实现这个接口C时,就要重写A、B、C接口中所有的方法

interface A {
    void testA();
}
interface B {
    void testB();
}
interface C extends A,B{
    void testC();
}
public class Test implements C{
    @Override
    public void testA() {

    }
    @Override
    public void testB() {

    }
    @Override
    public void testC() {

    }
}

接口要点总结

  • 接口的定义格式与定义类的格式基本相同,将class关键字换成 interface 关键字,就定义了一个接口
  • 创建接口时, 接口的命名一般以大写字母 I 开头.
  • 接口的命名一般使用 “形容词” 词性的单词.
  • 阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性
  • 接口中不能定义构造方法,也不能定义有具体实现的方法(否则会有红线)
  • 接口中如果要定义有具体实现的方法,要用static 或 default 关键字修饰
  • 接口中可以定义变量,默认被public static final 修饰,为静态常量(如果用默认值以外的修饰符修饰,会有红线)
  • 接口中可以定义没有具体实现的方法,默认被public abstract修饰,为抽象方法(如果用默认值以外的修饰符修饰,会有红线)
  • 接口中变量 或 方法可以不加任何限定修饰符,它们都有自己的默认修饰符
  • 接口和抽象类一样,不能直接实例化对象,接口是用来被类实现的
  • 一个类实现接口,使用 implements关键字,代表类实现了接口
  • 实现接口的类,要在类中重写接口中所有的(抽象)方法
  • 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类
  • 一个类可以实现多个接口,中间用逗号隔开
  • 接口与接口之间也可以存在继承关系,接口与接口之间可以多继承

Comparable接口

在Comparable接口源码中,有一个compareTo方法
在这里插入图片描述
  现有一个学生类,需要对两个学生对象 按照年龄 进行比较。不能使用直接使用 >、<或== 来比较两个学生引用。
  应该让Student类实现Comparable接口,然后在Student中 按照比较需求 重写这个接口中的compareTo方法。代码示例如下:

public class Student implements Comparable<Student>{
    String name;
    int age;
    public Student(String name,int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Student o) {
        if(this.age > o.age) {
            return 1;
        }else if(this.age == o.age) {
            return 0;
        }else {
            return -1;
        }
    }//可以把上面一堆代码是换成 return this.age-o.age
}

测试类:

public class Test {
    public static void main(String[] args) {
        Student student1 = new Student("zhangSan",18);
        Student student2 = new Student("liSi",17);
        int ret = student1.compareTo(student2);
        if(ret > 0) {
            System.out.println("student1 > student2");
        }else if(ret == 0) {
            System.out.println("student1 == student2");
        }else {
            System.out.println("student1 < student2");
        }

    }
}

运行结果:
student1 > student2


  使用Arrays.sort() 对学生类数组students进行排序,下图是Arrays.sort() 的源码,可以看出Arrays.sort() 的底层也是使用了comparable接口,所以Student类必须要实现comparable接口,并根据比较需求重写compareTo方法。
【students数组中的每个元素都是学生对象,比较时也是通过冒泡排序的方式,源码中要对学生对象强转为comparable接口,并且使用compareTo方法,所以Student类必须实现comparable接口】
在这里插入图片描述
Student 类实现comparable接口,重写compareTo方法,使用Arrays.sort(students)对学生数组按照年龄排序,代码示例如下:

public class Student implements Comparable<Student>{
    String name;
    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 class Test {
    public static void main(String[] args) {
        Student student1 = new Student("zhangSan",18);
        Student student2 = new Student("liSi",17);
        Student student3 = new Student("aBao",13);
        Student[] students = new Student[3];
        students[0] = student1;
        students[1] = student2;
        students[2] = student3;
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
    }
}

运行结果:
[Student{name=‘aBao’, age=13}, Student{name=‘liSi’, age=17}, Student{name=‘zhangSan’, age=18}]

Student 类实现comparable接口,重写compareTo方法,使用Arrays.sort(students)对学生数组按照姓名排序,代码示例如下:

public class Student implements Comparable<Student>{
    String name;
    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.name.compareTo(o.name);
    }
}

运行结果:
[Student{name=‘aBao’, age=13}, Student{name=‘liSi’, age=17}, Student{name=‘zhangSan’, age=18}]
只需改动compareTo方法的比较方式,测试类Test不变
【点进String类的源码,其实String类中也实现了Comparable接口,所以String类也重写了compareTo方法,因此对于String这种类的引用是可以调用compareTo方法,来比较两个引用类型的大小的】

使用冒号排序BubbleSort()实现 Arrays.sort(),按照姓名进行比较排序,代码示例如下:

public class Student implements Comparable<Student>{
    String name;
    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.name.compareTo(o.name);
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student("zhangSan",18);
        Student student2 = new Student("liSi",17);
        Student student3 = new Student("aBao",13);
        Student[] students = new Student[3];
        students[0] = student1;
        students[1] = student2;
        students[2] = student3;
        bubbleSort(students);
        System.out.println(Arrays.toString(students));
        
    public static void bubbleSort(Student[] students) {
        for (int i = 0; i < students.length-1; i++) {
            for (int j = 0; j < students.length-1-i; j++) {
                if(students[j].compareTo(students[j+1]) > 0) {
                    Student tmp = students[j];
                    students[j] = students[j+1];
                    students[j+1] = tmp;
                }
            }
        }
    }
}

运行结果:
[Student{name=‘aBao’, age=13}, Student{name=‘liSi’, age=17}, Student{name=‘zhangSan’, age=18}]
students[j].compareTo(students[j+1]能够使用compareTo()比较的原因是,数组的每个元素都是Student类对象,而学生类实现了comparable接口,同时重写了compareTo方法

使用冒号排序BubbleSort()实现 Arrays.sort(),按照年龄从小到大进行比较排序,只需更改compareTo方法里面的比较方式。代码示例如下:

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

如果想要按照年龄从大到小排序,只需将 return this.age - o.age改为return o.age - this.age


Comparator接口

Comparable接口的缺点:如果一个类已经实现了Comparable接口,并且根据需要已经重写了compareTo抽象方法,那么一般这个已经改写的抽象方法就不会再变了,比如说之前的业务都是使用年龄age来比较,但是如果确实需要通过姓名比较,也不能把原来已经重写好的方法再次改写按照姓名比较,这样一来以前使用年龄age比较的所有业务都会出错。那么我们可以使用一个新的接口Comparator接口,可以设置两种不同比较方式的类,让两个类都实现Comparator接口,分别按照比较需求重写Comparator中的抽象方法。

以下是comparator接口的源码,可以看到有两个抽象方法

这个接口里面有两个抽象方法,但是一个类实现了这个接口后只重写compare()方法就可以了,也不会报错。这是为啥子呢?解释:我们知道Object类是所有类的父类,其实在Object类中就有equals()方法的具体实现,而作为子类的AgeComparator也实现了Comparator接口,可以认为子类已经从父类继承了equals方法,近似认为已经重写了equals()方法,所以不需要再次重写equals()方法。
在这里插入图片描述

使用AgeComparator类中重写的compare()方法按照年龄比较,代码示例如下:

public class AgeComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.age - o2.age;
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student("zhangSan",18);
        Student student2 = new Student("liSi",17);
        AgeComparator ageComparator = new AgeComparator();
        int ret = ageComparator.compare(student1,student2);
        if(ret > 0) {
            System.out.println("student1 > student2");
        }else if(ret == 0) {
            System.out.println("student1 == student2");
        }else {
            System.out.println("student1 < student2");
        }
    }
}

运行结果:
student1 > student2

使用NameComparator类中重写的compare()方法按照姓名比较,代码示例如下:

public class NameComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student("zhangSan",18);
        Student student2 = new Student("liSi",17);
        NameComparator nameComparator = new NameComparator();
        int ret = nameComparator.compare(student1,student2);
        if(ret > 0) {
            System.out.println("student1 > student2");
        }else if(ret == 0) {
            System.out.println("student1 == student2");
        }else {
            System.out.println("student1 < student2");
        }
    }

运行结果:
student1 > student2


Clonable接口

现通过一个实例总结使用clone()的注意事项;有一个Goods类,代码示例如下:

class Money {
    public double money = 9.9;
}
public class Goods {
    public String name;
    public Money money;

    public Goods(String name) {
        this.name = name;
        this.money = new Money();
    }
}

现需要创建一个Goods对象,并克隆这个对象。在Test类中,创建好了一个goods对象,当用这个对象的引用通过 点 访问clone()方法时,但实际 点 不出来clone()方法,此时可以在子类Goods中重写clone()方法,这时候就能 点出来了。这是因为Object类中已经实现了clone()方法,所以作为子类的Goods类,重写这个方法后一定可以被访问。
但是我们发现还是会有红线,此时阅读Cloneable的源代码可以发现:
在这里插入图片描述

1 . 返回值是Object,所以要把Object类型的赋值给左边Goods类型的,必须要对右边进行强转为(Goods)。

    public static void main(String[] args) {
        Goods goods = new Goods("苹果");
        Goods goods1 = (Goods)goods.clone();
    }
  1. 强转之后发现还会有红线,这是因为throw CloneNotSuppurtedException是一个不支持克隆的异常,需要在编译时解决异常,解决异常的方法是:main()方法后 加throw CloneNotSuppurtedException
    public static void main(String[] args) throws CloneNotSupportedException {
        Goods goods = new Goods("苹果");
        Goods goods1 = (Goods)goods.clone();
    }
  1. 解决当前类是否能被克隆,编译通过但运行时报错,是因为没有实现Cloneable接口,实现Cloneable接口后才能真正实现拷贝,

阅读Cloneable接口的源码发现,其内部没有任何方法,
那么实现这个接口有什么用呢?它只是用来标记当前类是可以被拷贝的

完整代码示例如下:

class Money {
    public double money = 9.9;
}
public class Goods implements Cloneable{
    public String name;
    public Money money;

    public Goods(String name) {
        this.name = name;
        this.money = new Money();
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Goods goods = new Goods("苹果");
        Goods goods1 = (Goods)goods.clone();
    }
}


public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Goods goods = new Goods("苹果");
        Goods goods1 = (Goods)goods.clone();
        System.out.println("改变前goods money = " +goods.money.money );
        System.out.println("改变前goods1 money = " +goods1.money.money );

        goods1.money.money = 66.6;
        System.out.println("改变后goods money = " +goods.money.money );
        System.out.println("改变后goods1 money = " +goods1.money.money );
    }
}

运行结果:
改变前goods money = 9.9
改变前goods1 money = 9.9
改变后goods money = 66.6
改变后goods1 money = 66.6

通过以上测试类的结果说明,Money这个类的对象并没有被真正拷贝,新拷贝的goods1中的money这个引用还是指向了原来的地址,这是浅拷贝

使用堆栈图更能清晰的表示:

在这里插入图片描述
此时的goods1 和 goods 中的money引用所指向的对象是同一个对象(引用所存放的地址相同),所以在通过goods.money.money = 66.6这条语句改变money的值时,goods中的money也会改变,money引用指向的地址都是同一个地址

深拷贝的代码实现

以下是实现深拷贝的具体代码实现:

class Money implements Cloneable{
    public double money = 9.9;

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

    public Goods(String name) {
        this.name = name;
        this.money = new Money();
    }


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

}
public class Test {
    public static void main(String[] args)
            throws CloneNotSupportedException {
        Goods goods = new Goods("苹果");
        Goods goods1 = (Goods)goods.clone();
        System.out.println("改变前goods money = " +goods.money.money );
        System.out.println("改变前goods1 money = " +goods1.money.money );

        goods1.money.money = 66.6;
        System.out.println("改变后goods money = " +goods.money.money );
        System.out.println("改变后goods1 money = " +goods1.money.money );
    }
}

运行结果:
改变前goods money = 9.9
改变前goods1 money = 9.9
改变后goods money = 9.9
改变后goods1 money = 66.6

操作的堆栈图:

在这里插入图片描述先拷贝一份goods 给 tmp,然后再对money这个引用的对象进行拷贝,把拷贝好的money对象的地址 给 tmp.money。这里money引用也进行拷贝,所以Money也要实现Cloneable接口,重写clone()方法。


注意:从代码层次上,浅拷贝或深拷贝 是由具体的代码实现来决定的,不能说某个clone()方法是浅拷贝或深拷贝


抽象类和接口的区别

  • 抽象类中可以有普通成员变量和普通成员方法,构造方法,也可以有抽象方法;接口中可以定义变量,不能定义构造方法 和 有具体实现的方法(如果想有具体实现,使用static或default修饰),接口中的方法默认是被public abstract 修饰(抽象方法),变量默认是被 public static final 修饰(静态常量)
  • 抽象类使用 abstract 关键字;接口使用 interface 关键字
  • 抽象类 用来被继承,,关键字 extends;接口用来被实现,关键字 implements
  • 类与类之间不支持多继承;接口可以实现多继承,一个类可以实现多个接口,接口与接口之间也可以继承,甚至继承多个接口


http://www.kler.cn/news/354646.html

相关文章:

  • C++ OpenCV实现简单的自瞄脚本(OpenCV实战)
  • 永恒之蓝漏洞
  • 毕业设计之—基于ManTra-Net的图像篡改检测方法研究与应用实现
  • uni-app关闭底部系统导航栏的控制按钮BUG
  • SSTI模板注入+CTF实例
  • TS学习——type与interface的异同点
  • c++基础知识复习(1)
  • pdf删除几个页面怎么操作?PDF页面删除的快捷方法
  • Unity UGUI SuperScrollView介绍
  • ETL技术在金蝶云星空与旺店通WMS集成中的应用
  • 期货交易程序化,哪些API可供选择及如何使用?
  • taro小程序如何全局监听路由变化?
  • 基于SpringBoot+Vue+uniapp微信小程序的乡村政务服务系统的详细设计和实现(源码+lw+部署文档+讲解等)
  • AI学习指南深度学习篇-生成对抗网络的变体及扩展
  • 02 go语言(golang) - 包和模块
  • 什么是 SQL 命令?SQL 如何工作?
  • Maven基于构建阶段分析多余的依赖
  • Linux 下find常用命令整理(更新ing)
  • HCIP-HarmonyOS Application Developer 习题(十二)
  • 阿加犀构建开发者生态的全链路赋能之旅