【Java SE语法篇】9.抽象类和接口

简介: 【Java SE语法篇】9.抽象类和接口


1. 抽象类

1.1 抽象类的概念

在面向对象的概念中,所有的对象都是通过类来描绘的,但是放过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类

1.2 抽象类的语法

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

抽象类的定义格式如下:

abstract class 抽象类名{
    属性;
    
    // 普通方法
    访问权限 返回值类型 方法名称(参数){
        return [返回值];
    }
    
    // 抽象方法,无方法体
    访问权限 abstract 返回值类型 抽象方法名称(参数);
}

从以上格式可以看出,抽象类的定义比普通类多了抽象方法,类的其他功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样

1.3 抽象类的特性

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

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

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

  4. 抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也是抽象类,必须要使用 abstract 修饰,如果一个非抽象类继承了抽象类,那么这个子类必须实现抽象类中的全部抽象方法。
abstract class Shape {
    // 抽象方法
    public abstract  void draw();
}
abstract class A extends Shape {
    public abstract void testA();
}
class B extends A {
    @Override
    public void testA() {
    }
    @Override
    public void draw() {
    }
}
  1. 抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类
  2. 抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量

2. 接口

接口用来描述类应该做什么,而不指定它们具体应该如何做。一个类可以实现一个或多个接口。有些情况可能要求符合这些接口,主要有这种要求,就可以使用实现了这个接口的类(即实现类)的对象。

2.1 接口的概念

在Java程序设计语言中,接口不是类,而是对希望符合这个接口的类的一组需求。

接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用

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

2.2 接口的语法规则

接口的定义格式与定义类的格式基本相同,将class 关键字换成interface关键字,就定义了一个接口。

public interface 接口名称{
    // 抽象方法
}

注意事项:

  1. 创建接口时,接口的命名一般以大写字母I开头
  2. 接口命名一般使用“形容词”词性的单词。

2.3 接口的使用

接口不能直接被使用,必须有一个"实现类"来实现该接口,实现接口的所有的抽象方法。

public class 类名 interface 接口名称{ // 可以使用,分隔,实现多个接口
    // ...
}

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

2.4 接口的特性

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

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

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

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

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

  1. 接口中不能有静态代码块和构造方法(编译错误)

  2. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
  3. 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类

2.5 实现多个接口

在Java中,类和类之间是单继承的,一个类只能有一个父类,即Java中不支持多继承但是一个类可以实现多个接口。下面通过类来表示一组动物。

abstract public class Animal {
    public String name;
    public Animal(String name) {
        this.name = name;
    }
}

另外我们再提供一组接口, 分别表示 “会飞的”, “会跑的”, “会游泳的”。

interface IFly {
    void fly();
}
interface IRun {
    void run();
}
interface ISwim {
    void swim();
}

接下来我们创建几个具体的动物:

猫, 是会跑的。

public class Cat extends Animal implements IRun{
    public Cat(String name) {
        super(name);
    }
    @Override
    public void run() {
        System.out.println(this.name + "正在用四条腿跑");
    }
}

鱼,是会游泳的

public class Fish extends Animal implements ISwim{
    public Fish(String name) {
        super(name);
    }
    
    @Override
    public void swim() {
        System.out.println(this.name + "正在游泳");
    }
}

青蛙,既能跑,又能游泳(两栖动物)

public class Fish extends Animal implements IRun,ISwim{
    public Fish(String name) {
        super(name);
    }
    
    @Override
    public void run() {
        System.out.println(this.name + "正在用两条腿跑");
    }
    
    @Override
    public void swim() {
        System.out.println(this.name + "正在游泳");
    }
}

注意:一个类实现多个接口,每个接口的抽象方法都要实现,否则类必须设置为抽象类

而鸭子即可以飞,又能跑、还可以游泳。

public class Duck extends Animal implements IFly,IRun,ISwim{
    public Duck(String name) {
        super(name);
    }
    @Override
    public void fly() {
        System.out.println(this.name + "正在用两个翅膀飞");
    }
    @Override
    public void run() {
        System.out.println(this.name + "正在用两条腿跑");
    }
    @Override
    public void swim() {
        System.out.println(this.name + "正在用两条腿游泳");
    }
}

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

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

猫是一种动物,具有跑的特性。

鱼是一种动物,具有游泳的特性。

青蛙是一种,具有跑和游泳的特性。

鸭子是一种动物,具有跑、游泳和飞的特性。

这样设计有什么好处呢? 时刻牢记多态的好处, 让程序猿忘记类型. 有了接口之后, 类的使用者就不必关注具体类型,而只关注某个类是否具备某种能力.

例如:现在定义一个方法:testRun

public static void testRun(IRun iRun) {
    iRun.run();
}

在这个testRun方法内部, 我们并不关注到底是哪种动物, 只要参数是会跑的, 就行。

public static void main(String[] args) {
    testRun(new Bird("布谷"));
    testRun(new Duck("唐老鸭"));
    testRun(new Dog("旺财"));
}
// 运行结果
布谷正在用两条腿跑
唐老鸭正在用两条腿跑
旺财正在用四条腿跑

甚至参数可以不是 “动物”, 只要会跑!

class Roboot implements IRun{
    @Override
    public void run() {
        System.out.println("机器人正在用两条腿跑");
    }   
}
public class Test {
    public static void testRun(IRun iRun) {
    iRun.run();
  }
    
    public static void main(String[] args) {
        testRun(new Roboot());
    }
}
// 运行结果
机器人正在用两条腿跑

2.6 接口之间的继承

在Java中,类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承。即:用接口可以达到多继承的目的

接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字.

interface IRun {
    void run();
}
interface ISwim {
    void swim();
}
// 两栖的动物, 既能跑, 也能游
interface IAmphibious extends IRun,ISwim{
    
}
public class Frog extends Animal implements IAmphibious{
    ...
}

通过接口继承创建一个新的接口IAmphibious 表示 “两栖的”. 此时实现接口创建的 Frog 类, 就继续要实现 run 方法, 也需要实现 swim 方法.

接口间的继承相当于把多个接口合并在一起.

3. 抽象类和接口的区别

抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别。

核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法。

如之前写的 Animal 例子. 此处的 Animal 中包含一个 name 这样的属性, 这个属性在任何子类中都是存在的. 因此此处的 Animal 只能作为一个抽象类, 而不应该成为一个接口.

public class Animal {
    public String name;
    public Animal(String name) {
        this.name = name;
    }
}
区别 抽象类 接口
结构组成: 普通类 + 抽象方法 抽象方法 + 静态常量
权限: 各种权限 public
子类使用: 使用extends关键字继承抽象类 使用implements 关键字实现接口
关系: 一个抽象类可以实现若干接口 接口不能继承抽象类,但是接口可以使用extends 关键字继承多个父接口
子类权限: 一个子类只能继承一个抽象类 一个子类可以实现多个接口
相关文章
|
19天前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
|
10天前
|
Java
在Java中,接口之间可以继承吗?
接口继承是一种重要的机制,它允许一个接口从另一个或多个接口继承方法和常量。
36 1
|
20天前
|
Java
java线程接口
Thread的构造方法创建对象的时候传入了Runnable接口的对象 ,Runnable接口对象重写run方法相当于指定线程任务,创建线程的时候绑定了该线程对象要干的任务。 Runnable的对象称之为:线程任务对象 不是线程对象 必须要交给Thread线程对象。 通过Thread的构造方法, 就可以把任务对象Runnable,绑定到Thread对象中, 将来执行start方法,就会自动执行Runable实现类对象中的run里面的内容。
36 1
|
25天前
|
Java 开发者
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
44 4
|
1月前
|
Java
Java基础(13)抽象类、接口
本文介绍了Java面向对象编程中的抽象类和接口两个核心概念。抽象类不能被实例化,通常用于定义子类的通用方法和属性;接口则是完全抽象的类,允许声明一组方法但不实现它们。文章通过代码示例详细解析了抽象类和接口的定义及实现,并讨论了它们的区别和使用场景。
|
存储 算法 Java
Java8语法最佳实践-什么是对象(上)
计算机革命起源机器。编程语言就像是那台机器。它不仅是我们思维放大的工具与另一种表达媒介,更像是我们思想的一部分。语言的灵感来自其他形式的表达,如写作,绘画,雕塑,动画和电影制作。编程语言就是创建应用程序的思想结构。
164 0
Java8语法最佳实践-什么是对象(上)
|
存储 安全 Java
Java8语法最佳实践-什么是对象(下)
计算机革命起源机器。编程语言就像是那台机器。它不仅是我们思维放大的工具与另一种表达媒介,更像是我们思想的一部分。语言的灵感来自其他形式的表达,如写作,绘画,雕塑,动画和电影制作。编程语言就是创建应用程序的思想结构。
98 0
|
13天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
4天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
4天前
|
安全 Java 开发者
Java中的多线程编程:从基础到实践
本文深入探讨了Java多线程编程的核心概念和实践技巧,旨在帮助读者理解多线程的工作原理,掌握线程的创建、管理和同步机制。通过具体示例和最佳实践,本文展示了如何在Java应用中有效地利用多线程技术,提高程序性能和响应速度。
27 1