Java中的Abstract类,终于弄明白了!

在Java中,抽象类(Abstract Class)是一种特殊的类,用于声明方法但不实现它们的类。抽象类不能被实例化,而是用作其他类的父类,提供一种抽象的模板或者接口,要求其子类实现特定的方法。那抽象类到底有什么用呢?

01.定义抽象类

定义抽象类的时候需要用到关键字 abstract.

abstract class AbstractPlayer {
}

可以看到类名前是以Abstract开头的,这是因为《阿里的 Java 开发手册》上有强调,“抽象类命名要使用 Abstract 或 Base 开头”,做到类名的要求:名如其意。

02.抽象类的特征

1.不能实例化

Java语法不允许直接实例化抽象类

2.抽象方法和普通方法

抽象类中既可以定义抽象方法并且抽象方法没有方法体!,也可以定义普通方法

public abstract class AbstractTeacher {
    abstract void type();//子类继承后必须要实现的方法,并且要加上方法体!
    
    public void teach() {
        System.out.println("每个老师都要上课");
    }
}
3.可以定义构造方法和定义成员变量

抽象类可以有构造方法,用于初始化抽象类的成员变量或执行必要的初始化操作。子类在实例化时会调用父类的构造方法。

抽象类可以包含成员变量、静态常量和静态方法。这些成员变量和方法可以被其子类继承和访问。

abstract class Animal {
    protected String name;//静态成员
    public static final int MAX_AGE = 100;//静态常量
    public static void makeSound();//静态方法
    // 抽象类的构造方法
    public Animal(String name) {
        this.name = name;
    }

子类如何继承父类呢?

class Dog extends Animal {
    private String breed;

    // 子类的构造方法,必须调用父类的构造方法
    public Dog(String name, String breed) {
        super(name); // 调用父类的构造方法进行初始化
        this.breed = breed;
    }

    // 实现抽象方法,实现代码的复用
    @Override
    public void makeSound() {
        System.out.println("Woof!");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("Buddy", "Labrador");
        dog.makeSound(); // 输出: Woof!
        System.out.println("Name: " + dog.name); // 输出: Name: Buddy
        System.out.println("Breed: " + dog.breed); // 输出: Breed: Labrador
    }
}

03.案例(转载)

假设现在有一个文件,里面的内容非常简单,只有一个“Hello World”,现在需要有一个读取器将内容从文件中读取出来,最好能按照大写的方式,或者小写的方式来读。

这时候,最好定义一个抽象类 BaseFileReader:

/**
 * 抽象类,定义了一个读取文件的基础框架,其中 mapFileLine 是一个抽象方法,具体实现需要由子类来完成
 */
abstract class BaseFileReader {
    protected Path filePath; // 定义一个 protected 的 Path 对象,表示读取的文件路径

    /**
     * 构造方法,传入读取的文件路径
     * @param filePath 读取的文件路径
     */
    protected BaseFileReader(Path filePath) {
        this.filePath = filePath;
    }

    /**
     * 读取文件的方法,返回一个字符串列表
     * @return 字符串列表,表示文件的内容
     * @throws IOException 如果文件读取出错,抛出该异常
     */
    public List<String> readFile() throws IOException {
        return Files.lines(filePath) // 使用 Files 类的 lines 方法,读取文件的每一行
                .map(this::mapFileLine) // 对每一行应用 mapFileLine 方法,将其转化为指定的格式
                .collect(Collectors.toList()); // 将处理后的每一行收集到一个字符串列表中,返回
    }

    /**
     * 抽象方法,子类需要实现该方法,将文件中的每一行转化为指定的格式
     * @param line 文件中的每一行
     * @return 转化后的字符串
     */
    protected abstract String mapFileLine(String line);
}
  • ilePath 为文件路径,使用 protected 修饰,表明该成员变量可以在需要时被子类访问到。

  • readFile() 方法用来读取文件,方法体里面调用了抽象方法 mapFileLine()——需要子类来扩展实现大小写的不同读取方式。

在我看来,BaseFileReader 类设计的就非常合理,并且易于扩展,子类只需要专注于具体的大小写实现方式就可以了。

小写的方式:

class LowercaseFileReader extends BaseFileReader {
    protected LowercaseFileReader(Path filePath) {
        super(filePath);
    }

    @Override
    protected String mapFileLine(String line) {
        return line.toLowerCase();
    }
}

大写的方法:

class UppercaseFileReader extends BaseFileReader {
    protected UppercaseFileReader(Path filePath) {
        super(filePath);
    }

    @Override
    protected String mapFileLine(String line) {
        return line.toUpperCase();
    }
}

从文件里面一行一行读取内容的代码被子类复用了。与此同时,子类只需要专注于自己该做的工作,LowercaseFileReader 以小写的方式读取文件内容,UppercaseFileReader 以大写的方式读取文件内容。

来看一下测试类 FileReaderTest:

public class FileReaderTest {
    public static void main(String[] args) throws URISyntaxException, IOException {
        URL location = FileReaderTest.class.getClassLoader().getResource("helloworld.txt");
        Path path = Paths.get(location.toURI());
        BaseFileReader lowercaseFileReader = new LowercaseFileReader(path);
        BaseFileReader uppercaseFileReader = new UppercaseFileReader(path);
        System.out.println(lowercaseFileReader.readFile());
        System.out.println(uppercaseFileReader.readFile());
    }
}

在项目的 resource 目录下建一个文本文件,名字叫 helloworld.txt,里面的内容就是“Hello World”。文件的具体位置如下图所示,我用的集成开发环境是 Intellij IDEA。

 

在 resource 目录下的文件可以通过 ClassLoader.getResource() 的方式获取到 URI 路径,然后就可以取到文本内容了。

输出结果如下所示:

[hello world]
[HELLO WORLD]

04.抽象类总结

好了,对于抽象类我们简单总结一下:

  • 抽象类不能被实例化。
  • 抽象类应该至少有一个抽象方法,否则它没有任何意义。
  • 抽象类中的抽象方法没有方法体。
  • 抽象类的子类必须给出父类中的抽象方法的具体实现,除非该子类也是抽象类
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值