Since xiaobai wrote two articles of the nature of popular science, I have a bit out of control, feel it is necessary to continue to write. Because some readers left messages “encouraging” me to say, “brother, you are really worried about the small white heart ah!” Am I easy? I.

Java’s abstract classes come in handy when the task we want to accomplish is certain, but the specific way to do it requires a vote at a later meeting. How to understand this sentence? Take a little bench and let me tell you something.

Five key points about abstract classes

1) When you define an abstract class, you need to use the keyword abstract.

public abstract class AbstractPlayer {

}

Copy the code

As for the naming of Abstract classes, the Java development manual produced by Ali emphasizes that “Abstract class names should start with Abstract or Base”, remember that.

2) Abstract classes cannot be instantiated, but can have subclasses.

If you try to instantiate using the new keyword, the compiler will report an error saying “class is abstract and cannot be instantiated”.

Abstract classes can be inherited using the extends keyword, and the BasketballPlayer class is a subclass of AbstractPlayer.

public class BasketballPlayer extends AbstractPlayer {

}

Copy the code

3) If a class defines one or more abstract methods, the class must be abstract.

When an abstract method is defined in a normal class without the abstract keyword modifier, the compiler gets two errors.

The first is at the class level, which tells you that “this class must be defined by the abstract keyword.” The or message is not necessary, as shown in the figure below.

The second is at the method level, which reminds you that “the class in which an abstract method resides is not abstract,” as shown in the figure below.

4) An abstract class may declare both abstract and concrete methods, or none at all, but it is not necessary. Like this:

public abstract class AbstractPlayer {

    abstract void play(a);



    public void sleep(a) {

        System.out.println("Athletes should rest instead of pushing the envelope.");

    }

}

Copy the code

5) Subclasses derived from an abstract class must implement the abstract methods defined in the parent class. For example, if the play() method is defined in an abstract class, it must be implemented in a subclass.

public class BasketballPlayer extends AbstractPlayer {

    @Override

    void play(a) {

        System.out.println("I'm Wilt Chamberlain. I scored 100 points on the basketball court.");

    }

}

Copy the code

If there is no implementation, the compiler will remind you that “subclasses must implement abstract methods”, as shown below.

02. When to Use Abstract classes

Another concept closely related to abstract classes is interfaces, which we’ll save for the next article because there’s a lot more to cover. All you need now is the notion that an interface is an abstraction of behavior, and an abstract class is an abstraction of the entire class (including its member variables and behavior).

(Don’t worry, just wait for the next article to come out)

In addition to interfaces, there is also the concept of concrete classes, which are ordinary classes that are not decorated with Abstract, as defined in the following code.

public class BasketballPlayer {

   public void play(a) {

        System.out.println("I'm James, the first man alive.");

    }

}

Copy the code

You have interfaces, you have concrete classes, so when should you use abstract classes?

1) We want some common functionality to be reused by multiple subclasses. For example, the AbstractPlayer abstract class has a common method called sleep() that indicates that all athletes need to rest, and this method can be reused by subclasses.

public abstract class AbstractPlayer {

    public void sleep(a) {

        System.out.println("Athletes should rest instead of pushing the envelope.");

    }

}

Copy the code

Although AbstractPlayer classes may not be abstract — removing the abstract modifier can satisfy this scenario. But AbstractPlayer classes may also have one or more abstract methods.

BasketballPlayer inherits AbstractPlayer class, and thus has the sleep() method.

public class BasketballPlayer extends AbstractPlayer {

}

Copy the code

A BasketballPlayer object can call the sleep() method directly:

BasketballPlayer basketballPlayer = new BasketballPlayer();

basketballPlayer.sleep();

Copy the code

FootballPlayer inherits AbstractPlayer class and has the sleep() method.

public class FootballPlayer extends AbstractPlayer {

}

Copy the code

FootballPlayer objects can also call sleep() directly:

FootballPlayer footballPlayer = new FootballPlayer();

footballPlayer.sleep();

Copy the code

2) We need to define the API in an abstract class and extend the implementation in subclasses. For example, the AbstractPlayer abstract class has an abstract method play() that defines that all athletes can play a sport, but requires subclasses to extend the implementation.

public abstract class AbstractPlayer {

    abstract void play(a);

}

Copy the code

BasketballPlayer extends the AbstractPlayer class to implement its own play() method.

public class BasketballPlayer extends AbstractPlayer {

    @Override

    void play(a) {

        System.out.println("I'm Wilt Chamberlain, I've scored 100 points on the basketball court,");

    }

}

Copy the code

FootballPlayer extends the AbstractPlayer class to implement its own Play () method.

public class FootballPlayer extends AbstractPlayer {

    @Override

    void play(a) {

        System.out.println("I'm Cristiano Ronaldo. I can catch a header from any height.");

    }

}

Copy the code

3) If the relationship between the parent class and the child class conforms to the hierarchy of IS-A, we can use abstract classes, such as basketball players are athletes, football players are athletes.

03. Specific examples

To further illustrate the nature of abstract classes, let’s look at a concrete example. Suppose you have a file with a very simple “Hello World” in it, and now you need a reader to read it out, preferably in uppercase or lowercase.

In this case, it is best to define an abstract class, such as BaseFileReader:

public abstract class BaseFileReader {

    protected Path filePath;



    protected BaseFileReader(Path filePath) {

        this.filePath = filePath;

    }



    public List<String> readFile(a) throws IOException {

        return Files.lines(filePath)

                .map(this::mapFileLine).collect(Collectors.toList());

    }



    protected abstract String mapFileLine(String line);

}

Copy the code

FilePath is the filePath, protected, indicating that the member variable can be accessed by subclasses if needed.

The readFile() method is used to read files, and the abstract method mapFileLine() is called inside the method body — which requires subclasses to extend the way capitalization is implemented.

As you can see, BaseFileReader is designed to be reasonable and easy to extend, and subclasses just need to focus on the specific case implementation.

Lower case:

public class LowercaseFileReader extends BaseFileReader {

    protected LowercaseFileReader(Path filePath) {

        super(filePath);

    }



    @Override

    protected String mapFileLine(String line) {

        return line.toLowerCase();

    }

}

Copy the code

Uppercase:

public class UppercaseFileReader extends BaseFileReader {

    protected UppercaseFileReader(Path filePath) {

        super(filePath);

    }



    @Override

    protected String mapFileLine(String line) {

        return line.toUpperCase();

    }

}

Copy the code

You see, the code that reads from a file line by line is reused by subclasses — the ordinary method readFile() defined in the abstract BaseFileReader class. In the meantime, subclasses just focus on what they do, LowercaseFileReader reads files in lower case and UppercaseFileReader reads files in upper case.

Next, let’s create a new test class 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());

    }

}

Copy the code

The project has a text file in the resource directory called helloworld.txt.

You can get the URI path of the file using classLoader.getResource (), and then use LowercaseFileReader and UppercaseFileReader to read the text.

The following output is displayed:

[hello world]

[HELLO WORLD]

Copy the code

Well, my dear readers, that’s all for this article. Does it feel like learning again? I am silent King 2, an interesting programmer. If you find this article helpful, please search “Silent King ii” on wechat and read it for the first time.

Interview on GitHub

Original is not easy, do not want a free ticket, please point a praise for this article, it will be the strongest power FOR me to write more high-quality articles.