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

《抽象类和接口》

目录

 

一、抽象类

1.1 什么是抽象类

1.2 抽象类的语法

1.3 抽象类的特点

1.4 抽象类的用途

二、接口

2.1 接口的概念

2.2 语法规则

2.3 接口的使用

2.4 接口的特性

2.5 实现多个接口

2.6 接口间的继承

2.7 接口的使用实例

2.8 Clonable 接口和深拷贝

2.9 抽象类和接口的区别


 

一、抽象类

1.1 什么是抽象类

抽象类是一种不能被实例化的类,它通常用于为其他类提供一个通用的模板或规范。

1.2 抽象类的语法

在java中一个类如果被abstract修饰被称为抽象类,抽象类中被abstract修饰的方法称为抽象方法,抽象方法不用给出具体的实现体。

//抽象类 被abstract修饰的类
public abstract class Animal {//抽象方法 被abstract修饰的方法 不用实现public abstract void eat();//abstract也可以写到前面abstract public void work();//抽象类也是类所以也可以有普通方法public void sleep(){System.out.println("正在睡觉!");}//也可以定义属性public int age;private String name;protected int id;
}

1.3 抽象类的特点

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

abstract class Shape {public abstract void draw();
}
public class Main {public static void main(String[] args) {Shape shape = new Shape();//报错}
}

7b9b8cdc34554b9bbb174dba6164ba04.png

2.抽象方法不能被private修饰

public abstract class Shape {public abstract void draw();private abstract void func();//报错
}

fe11f04209344a5390e9e9474e54059e.png

3.抽象方法不能被final和static修饰,因为抽象方法要被子类重写

public abstract class Shape {public abstract void draw();public final abstract void func1();//报错public static abstract void func2();//报错
}

02ec1053dba542c898e89714849a99d1.png036f1dfe6a774884b84f7b2ba48ccaaf.png

 4.抽象类必须被继承,并且继承后子类要重写父类中的抽象方法

abstract class Shape {public abstract void draw();
}
class Circle extends Shape{@Overridepublic void draw() {System.out.println("画一个圆形");}
}

如果子类也是抽象类则不用重写

abstract class Shape {public abstract void draw();
}
abstract class Rect extends Shape{public abstract void func();
}

但是最终肯定会被重写,只要有人继承这个抽象子类

abstract class Shape {public abstract void draw();
}
abstract class Rect extends Shape{public abstract void func();
}
class Square extends Rect{@Overridepublic void draw() {System.out.println("画一个正方形");}@Overridepublic void func() {System.out.println("11111");}
}

5. 抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类

6. 抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量

1.4 抽象类的用途

抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法.

1.提供通用的行为和属性

抽象类可以为一组相关的类提供通用的行为和属性。子类可以继承这些通用的特性,并根据自己的需要进行特定的实现。例如,在图形绘制的场景中,Shape抽象类可以为各种具体的图形类(如圆形、矩形、三角形等)提供通用的属性(如颜色)和方法(如设置颜色的方法)。

2.强制子类实现特定的方法

通过定义抽象方法,抽象类可以强制子类实现这些方法,确保子类具有特定的行为。这有助于实现代码的规范性和可维护性。例如,Animal抽象类中的makeSound方法要求所有的动物子类都必须实现自己独特的发声行为。

二、接口

2.1 接口的概念

接口是一种特殊的抽象类型,它只包含抽象方法和常量(在 Java 8 之前只能包含抽象方法和常量,Java 8 及以后可以包含默认方法和静态方法)。

在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。

2.2 语法规则

public interface Shape /*接口名字*/ {//抽象方法public abstract void func1();//public abstract是固定搭配可以不写void func2();public void func3();abstract void func4();//在接口中上述写法都是抽象方法 更推荐方法二的写法 代码简洁}

提示:

1. 创建接口时, 接口的命名一般以大写字母 I 开头.

2. 接口的命名一般使用 "形容词" 词性的单词.

3. 阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性

2.3 接口的使用

public  class 类名称 implements 接口名称{// ...}

注意:子类和父类之间是extends 继承关系,类与接口之间是 implements 实现关系。

举例使用接口

//IUSB接口
public interface IUSB {void openDevice();void closeDevice();
}
//键盘类
public class KeyBoard implements IUSB{@Overridepublic void openDevice() {System.out.println("打开键盘服务...");}public void input(){System.out.println("键盘输入数据...");}@Overridepublic void closeDevice() {System.out.println("关闭键盘服务...");}
}
//鼠标类
public class Mouse implements IUSB{@Overridepublic void openDevice() {System.out.println("打开鼠标服务...");}public void click(){System.out.println("点击鼠标...");}@Overridepublic void closeDevice() {System.out.println("关闭鼠标服务...");}
}
//电脑类
public class Computer{public void powerOn(){System.out.println("打开电脑...");}public void powerOff(){System.out.println("关闭电脑...");}public void useDevice(IUSB iusb){iusb.openDevice();//因为向下转型不安全 要用 instanceof 来判断//instanceof 返回一个布尔值,表示对象是否为某个构造函数的实例if(iusb instanceof KeyBoard){KeyBoard keyBoard = (KeyBoard) iusb;keyBoard.input();}if (iusb instanceof Mouse){Mouse mouse = (Mouse) iusb;mouse.click();}iusb.closeDevice();}
}
//测试类
public class Test {public static void main(String[] args) {Computer computer = new Computer();computer.powerOn();computer.useDevice(new KeyBoard());computer.useDevice(new Mouse());computer.powerOff();}
}

输出结果:

b264630e9f354fa7aef420f1df060107.png

2.4 接口的特性

1. 接口类型是一种引用类型,但是不能直接new接口的对象

interface IUSB {void openDevice();void closeDevice();
}
public class Test {public static void main(String[] args) {IUSB iusb = new IUSB();//报错}
}

d1bdb9dfa515428ab9163aa755950677.png

2. 接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。

97fbcdca548b4d1cb2542ae21a50150a.png

3. 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现。

0c342b3f9d3749ae87e748fd30bdea8e.png

4. 重写接口中方法时,不能使用默认的访问权限。

0c2cfacfd27d41e1843ad87f8d1dba96.png

5. 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量

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

7. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class

8. 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类

9. jdk8中:接口中还可以包含default方法

2.5 实现多个接口

在Java中只能单继承,一个类只能有一个父类,所以Java不支持多继承。但是一个类可以实现多个接口。

interface ISleep {void sleep();
}interface IEat {void eat();
}interface IWork {void  work();
}class Person implements ISleep,IEat,IWork{@Overridepublic void sleep() {System.out.println("去睡觉!!!");}@Overridepublic void eat() {System.out.println("去吃饭!!!");}@Overridepublic void work() {System.out.println("去工作!!!");}
}public class Test {public static void main(String[] args) {Person person = new Person();person.eat();person.sleep();person.work();}
}

7dde4d7b0c23432d8b93eab1484db2b3.png

上面的例子,person类实现了 IEat,ISleep,IWork这三个接口。

继承表达的含义是 is - a 语义, 而接口表达的含义是 具有 xxx 特性

2.6 接口间的继承

在Java中,类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承。即:用接口可以达到 多继承的目的。 接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字.

class Animal {public String name;public Animal(String name) {this.name = name;}
}interface ISwim {void swim();
}interface IRun {void run();
}//鸭子可以游泳也可以跑 还可以飞  继承了IRun,ISwim 还有自己的功能 实现了接口之间的继承interface IAmphibious extends IRun,ISwim{void fly();
}//Duck继承了Animal类 并且实现了IAmphibious接口
class Duck extends Animal implements IAmphibious{public Duck(String name) {super(name);}@Overridepublic void swim() {System.out.println(this.name+"正在游泳.....");}@Overridepublic void run() {System.out.println(this.name+"正在跑.....");}@Overridepublic void fly() {System.out.println(this.name+"正在飞.....");}
}public class Test5 {public static void main(String[] args) {Duck duck = new Duck("嘎嘎");duck.fly();duck.run();duck.swim();}
}

1b684230293d45fa84856cdbe2dc0e8d.png

2.7 接口的使用实例

Comparable接口的使用

class Student implements Comparable<Student>{public String name;public int age;public int score;public Student(String name, int age, int score) {this.name = name;this.age = age;this.score = score;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", score=" + score +'}';}@Overridepublic int compareTo(Student o) {return  this.age - o.age;}
}public class Test6 {public static void main(String[] args) {Student student1 = new Student("zhangsan",18,88);Student student2 = new Student("lisi",21,77);if(student1.compareTo(student2)>0){System.out.println("student1.age>student2.age");}else {System.out.println("student1.age<student2.age");}}}

ba7e56f716074e6fb39fd69e338128d8.png

这样写会很不方便,在Student类中我们把比较写死了,后面使用只能用年龄来比较。

Comparator接口的使用

我们用Comparator接口实现几个比较器这样就比较灵活了,我们可以调用比较器来比较。

import java.util.Comparatorclass Student{public String name;public int age;public int score;public Student(String name, int age, int score) {this.name = name;this.age = age;this.score = score;}}class AgeComparator implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {return o1.age - o2.age;}
}//名字要通过comperTo方法来比较
class NameComparator implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {return o1.name.compareTo(o2.name);}
}class ScoreComparator implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {return o1.score - o2.score;}
}public class Test7 {public static void main(String[] args) {Student student1 = new Student("zhangsan",18,88);Student student2 = new Student("lisi",21,77);//通过年龄比较AgeComparator ageComparator = new AgeComparator();if(ageComparator.compare(student1,student2)>0){System.out.println("student1.age>student2.age");}else {System.out.println("student1.age<student2.age");}//通过分数比较ScoreComparator scoreComparator = new ScoreComparator();if(scoreComparator.compare(student1,student2)>0){System.out.println("student1.score>student2.score");}else {System.out.println("student1.score<student2.score");}//通过姓名比较NameComparator nameComparator = new NameComparator();if(nameComparator.compare(student1,student2)>0){System.out.println("student1.name>student2.name");}else {System.out.println("student1.name<student2.name");}}
}

9d1752416b384f3cbde90fe6a593de62.png

这样使用起来就比较方便了,我们想通过什么比较就实例一个比较器来比较。

2.8 Clonable 接口和深拷贝

Java 中内置了一些很有用的接口, Clonable 就是其中之一. Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 "拷贝". 但是要想合法调用 clone 方法, 必须要 先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常。

class Person implements Cloneable{public String name;protected Object clone() throws CloneNotSupportedException{return super.clone();}public Person(String name) {this.name = name;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +'}';}
}public class Test8 {public static void main(String[] args) throws CloneNotSupportedException{Person person1 = new Person("aaaa");Person person2 = (Person)person1.clone();System.out.println(person2);person2.name = "bbbbbb";System.out.println(person2);}
}

f2c3a70ed111460e89c01e746b3569c3.png

这里是把person1这个引用所指向的对象克隆了一份。

4a21fc08065c46d9956c9b6201ddb23e.png

浅拷贝

class Money implements Cloneable{public double money = 15.8;protected Object clone() throws CloneNotSupportedException{return super.clone();}
}class Person implements Cloneable{public String name;public Money m;protected Object clone() throws CloneNotSupportedException{return super.clone();}public Person(String name) {this.name = name;this.m = new Money();}
}public class Test8 {public static void main(String[] args) throws CloneNotSupportedException{Person person1 = new Person("cy");Person person2 = (Person)person1.clone();System.out.println(person1.m.money);System.out.println(person2.m.money);person2.m.money = 16.8;System.out.println(person1.m.money);System.out.println(person2.m.money);}

4281253ebbe24a1dac7afc259fabff71.png

这里我们只改了person2对象中m的money属性 但是person1的也改变了。

0af5d3172a8e41aa9cf9f7784ec40308.png

深拷贝

class Money implements Cloneable{public double money = 15.8;protected Object clone() throws CloneNotSupportedException{return super.clone();}
}
class Person implements Cloneable{public String name;public Money m;protected Object clone() throws CloneNotSupportedException{Person temp = (Person) super.clone();temp.m = (Money) this.m.clone();return temp;}public Person(String name) {this.name = name;this.m = new Money();}
}public class Test8 {public static void main(String[] args) throws CloneNotSupportedException{Person person1 = new Person("cy");Person person2 = (Person)person1.clone();System.out.println(person1.m.money);System.out.println(person2.m.money);person2.m.money = 16.8;System.out.println(person1.m.money);System.out.println(person2.m.money);}

9c7479081f9f4fb6952cb1a4643f439c.png

37248eae2b27426d9ed3cbd26af0020d.png

2.9 抽象类和接口的区别

1. 语法区别

在 Java 中,抽象类使用abstract关键字来定义。在 Java 中,接口使用interface关键字来定义。

2.方法实现差异

抽象类中可以有抽象方法和非抽象方法。抽象方法必须在子类中被实现,非抽象方法可以被继承并直接使用。

接口中的所有方法都是抽象的(在 Java 8 之前),实现接口的类必须实现接口中的所有方法。

3.变量的区别

抽象类可以包含成员变量,这些变量可以是各种访问修饰符并且可以有初始值。

在接口中定义的变量默认是public static final 的,也就是说它们是常量。

4.继承和实现的规则区别

一个类只能继承一个抽象类。

一个类可以实现多个接口。这使得类可以遵循多种契约。

5.使用场景区别

抽象类:当有一组相关的类,它们有一些共同的属性和方法,但又有一些方法需要根据具体的子类来实现时,适合使用抽象类。抽象类可以提供部分实现,减少代码重复。

接口:当需要定义一组规范,让不同的类来实现这些规范,并且这些类可能没有共同的父类或继承层次关系时,适合使用接口。

 

 


http://www.mrgr.cn/news/76368.html

相关文章:

  • 计算机网络 (38)TCP的拥塞控制
  • 【STM32-学习笔记-6-】DMA
  • Cline(原Claude Dev)开源的IDE AI插件,如何搭配OpenRouter实现cursor功能,Cline怎么使用
  • 【漫话机器学习系列】043.提前停止训练(Early Stopping)
  • Unity3D仿星露谷物语开发20之道具简介弹出窗
  • mv指令详解
  • 渗透测试之信息收集 DNS主机发现探测方式NetBIOS 协议发现主机 以及相关PorCheck scanline工具的使用哟
  • 跳房子(弱化版)
  • 芯原科技嵌入式面试题及参考答案
  • cMake编译github中源码
  • flink cdc 应用
  • 重建大师跑空三,出现进度条回退是什么原因?
  • 城市轨道交通数据可视化的应用与优势
  • Intelligent Transportation Scheduling
  • IT框架与库:理解它们的不同与共同点
  • 用友YonBIP-R5旗舰版 yonbiplogin 任意文件读取漏洞复现
  • Rust 语言学习笔记(一)
  • uniapp luch-request 使用教程+响应对象创建
  • C++ 20的条件判断语句的增强
  • Docker 容器常见故障排查及处理
  • JavaWeb后端开发知识储备1
  • 大型网站架构演进过程
  • Istio分布式链路监控搭建:Jaeger与Zipkin
  • MT4 编程—DLL编程的整个流程以及案例分析
  • STM32外设应用:深入探索STM32微控制器的强大功能
  • 【AlphaFold3】开源本地的安装及使用