- Абстрактные классы Java и методы
- Объявление
- Абстрактные методы
- Цель
- Шаблона проектирования Template
- Abstract Methods and Classes
- Abstract Classes Compared to Interfaces
- An Abstract Class Example
- When an Abstract Class Implements an Interface
- Class Members
- Java Abstraction
- Example
- Why And When To Use Abstract Classes and Methods?
Абстрактные классы Java и методы
Это класс, который не может быть создан, то есть вы не можете создавать новые экземпляры абстрактного класса. Целью является функционирование в качестве базы для подклассов.
Объявление
Нужно добавить ключевое слово abstract в объявление класса:
public abstract class MyAbstractClass
Теперь вы не можете создавать экземпляры MyAbstractClass. Таким образом, следующий код больше не действителен:
MyAbstractClass myClassInstance = new MyAbstractClass(); //not valid
Если вы попытаетесь скомпилировать код выше, компилятор сгенерирует ошибку, сказав, что вы не можете создать экземпляр MyAbstractClass, потому что это абстрактный класс.
Абстрактные методы
Вы объявляете их, добавляя ключевое слово abstract перед объявлением метода:
public abstract class MyAbstractClass
Информация об абстрактных методах:
- Не имеет реализации.
- У него просто есть подпись метода. Так же, как методы в интерфейсе.
- Если у класса есть абстрактный метод, весь класс должен быть объявлен как абстрактный.
- Не все методы в абстрактном классе должны быть абстрактными, может иметь и неабстрактные.
- Подклассы абстрактного класса должны реализовывать (переопределять) все абстрактные методы его абстрактного суперкласса. Неабстрактные методы суперкласса просто наследуются как есть. Они также могут быть отменены, если это необходимо.
public class MySubClass extends MyAbstractClass < public void abstractMethod() < System.out.println("My method implementation"); >>
Обратите внимание, как MySubClass должен реализовывать абстрактный метод abstractMethod() из своего абстрактного суперкласса MyAbstractClass.
Единственный раз, когда подкласс абстрактного класса не вынужден реализовывать все абстрактные методы своего суперкласса – когда также является абстрактным.
Цель
Цель – функционировать как базовые классы, которые могут быть расширены подклассами для создания полной реализации. Например, представьте, что определенный процесс требует 3 шага:
Если шаги до и после действия всегда одинаковы, трехэтапный процесс может быть реализован в абстрактном суперклассе с помощью следующего кода:
public abstract class MyAbstractProcess < public void process() < stepBefore(); action(); stepAfter(); >public void stepBefore() < //implementation directly in abstract superclass >public abstract void action(); // implemented by subclasses public void stepAfter() < //implementation directly in abstract superclass >>
Обратите внимание, как метод action() является абстрактным. Подклассы MyAbstractProcess теперь могут расширять MyAbstractProcess и просто переопределять метод action().
Когда вызывается метод process() подкласса, выполняется полный процесс, включая stepBefore() и stepAfter() абстрактного суперкласса и метод action() подкласса.
Конечно, MyAbstractProcess не должен был быть абстрактным, чтобы функционировать как базовый класс. Метод action() также не должен быть абстрактным. Вы могли бы просто использовать обычный класс. Однако, создав метод для реализации абстрактного, а значит и класса, вы четко дадите понять его пользователям, что он не должен использоваться как есть. Вместо этого его следует использовать в качестве базового класса для подкласса, а абстрактный метод должен быть реализован в подклассе.
В приведенном выше примере не было реализации по умолчанию для метода action(). В некоторых случаях ваш суперкласс может ее иметь. Тогда вы можете не делать метод абстрактным. Вы все равно можете сделать суперкласс абстрактным, даже если он не содержит абстрактных методов.
Вот более конкретный пример, который открывает URL-адрес, обрабатывает его и впоследствии закрывает соединение с URL-адресом.
public abstract class URLProcessorBase < public void process(URL url) throws IOException < URLConnection urlConnection = url.openConnection(); InputStream input = urlConnection.getInputStream(); try< processURLData(input); >finally < input.close(); >> protected abstract void processURLData(InputStream input) throws IOException; >
Обратите внимание, что processURLData() является абстрактным методом, а URLProcessorBase – абстрактным классом. Подклассы URLProcessorBase должны реализовывать processURLData(), потому он абстрактный.
Подклассы URLProcessorBase могут обрабатывать данные, загруженные с URL-адресов, не беспокоясь об открытии и закрытии сетевого подключения к URL-адресу. Это делается с помощью URLProcessorBase. Подклассам нужно только беспокоиться об обработке данных из InputStream, переданных методу processURLData(). Это облегчает реализацию классов, обрабатывающих данные из URL.
public class URLProcessorImpl extends URLProcessorBase < @Override protected void processURLData(InputStream input) throws IOException < int data = input.read(); while(data != -1)< System.out.println((char) data); data = input.read(); >> >
Обратите внимание, как подкласс реализует только метод processURLData(), и ничего более. Остальной код унаследован от суперкласса URLProcessorBase.
Вот пример того, как использовать класс URLProcessorImpl:
URLProcessorImpl urlProcessor = new URLProcessorImpl(); urlProcessor.process(new URL("https://java-blog.ru"));
Вызывается метод process(), который реализован в суперклассе URLProcessorBase. Этот метод, в свою очередь, вызывает processURLData() в классе URLProcessorImpl.
Шаблона проектирования Template
Пример, который я показал вам выше с классом URLProcessorBase, на самом деле является примером шаблона проектирования Template. Он обеспечивает частичную реализацию некоторого процесса, который подклассы могут выполнять при расширении базового класса Template.
Abstract Methods and Classes
An abstract class is a class that is declared abstract it may or may not include abstract methods. Abstract classes cannot be instantiated, but they can be subclassed.
An abstract method is a method that is declared without an implementation (without braces, and followed by a semicolon), like this:
abstract void moveTo(double deltaX, double deltaY);
If a class includes abstract methods, then the class itself must be declared abstract , as in:
public abstract class GraphicObject < // declare fields // declare nonabstract methods abstract void draw(); >
When an abstract class is subclassed, the subclass usually provides implementations for all of the abstract methods in its parent class. However, if it does not, then the subclass must also be declared abstract .
Note: Methods in an interface (see the Interfaces section) that are not declared as default or static are implicitly abstract, so the abstract modifier is not used with interface methods. (It can be used, but it is unnecessary.)
Abstract Classes Compared to Interfaces
Abstract classes are similar to interfaces. You cannot instantiate them, and they may contain a mix of methods declared with or without an implementation. However, with abstract classes, you can declare fields that are not static and final, and define public, protected, and private concrete methods. With interfaces, all fields are automatically public, static, and final, and all methods that you declare or define (as default methods) are public. In addition, you can extend only one class, whether or not it is abstract, whereas you can implement any number of interfaces.
Which should you use, abstract classes or interfaces?
- Consider using abstract classes if any of these statements apply to your situation:
- You want to share code among several closely related classes.
- You expect that classes that extend your abstract class have many common methods or fields, or require access modifiers other than public (such as protected and private).
- You want to declare non-static or non-final fields. This enables you to define methods that can access and modify the state of the object to which they belong.
- You expect that unrelated classes would implement your interface. For example, the interfaces Comparable and Cloneable are implemented by many unrelated classes.
- You want to specify the behavior of a particular data type, but not concerned about who implements its behavior.
- You want to take advantage of multiple inheritance of type.
An example of an abstract class in the JDK is AbstractMap , which is part of the Collections Framework. Its subclasses (which include HashMap , TreeMap , and ConcurrentHashMap ) share many methods (including get , put , isEmpty , containsKey , and containsValue ) that AbstractMap defines.
An example of a class in the JDK that implements several interfaces is HashMap , which implements the interfaces Serializable , Cloneable , and Map . By reading this list of interfaces, you can infer that an instance of HashMap (regardless of the developer or company who implemented the class) can be cloned, is serializable (which means that it can be converted into a byte stream; see the section Serializable Objects), and has the functionality of a map. In addition, the Map interface has been enhanced with many default methods such as merge and forEach that older classes that have implemented this interface do not have to define.
Note that many software libraries use both abstract classes and interfaces; the HashMap class implements several interfaces and also extends the abstract class AbstractMap .
An Abstract Class Example
In an object-oriented drawing application, you can draw circles, rectangles, lines, Bezier curves, and many other graphic objects. These objects all have certain states (for example: position, orientation, line color, fill color) and behaviors (for example: moveTo, rotate, resize, draw) in common. Some of these states and behaviors are the same for all graphic objects (for example: position, fill color, and moveTo). Others require different implementations (for example, resize or draw). All GraphicObject s must be able to draw or resize themselves; they just differ in how they do it. This is a perfect situation for an abstract superclass. You can take advantage of the similarities and declare all the graphic objects to inherit from the same abstract parent object (for example, GraphicObject ) as shown in the following figure.
Classes Rectangle, Line, Bezier, and Circle Inherit from GraphicObject
First, you declare an abstract class, GraphicObject , to provide member variables and methods that are wholly shared by all subclasses, such as the current position and the moveTo method. GraphicObject also declares abstract methods for methods, such as draw or resize , that need to be implemented by all subclasses but must be implemented in different ways. The GraphicObject class can look something like this:
abstract class GraphicObject < int x, y; . void moveTo(int newX, int newY) < . >abstract void draw(); abstract void resize(); >
Each nonabstract subclass of GraphicObject , such as Circle and Rectangle , must provide implementations for the draw and resize methods:
class Circle extends GraphicObject < void draw() < . >void resize() < . >> class Rectangle extends GraphicObject < void draw() < . >void resize() < . >>
When an Abstract Class Implements an Interface
In the section on Interfaces , it was noted that a class that implements an interface must implement all of the interface’s methods. It is possible, however, to define a class that does not implement all of the interface’s methods, provided that the class is declared to be abstract . For example,
abstract class X implements Y < // implements all but one method of Y >class XX extends X < // implements the remaining method in Y >
In this case, class X must be abstract because it does not fully implement Y , but class XX does, in fact, implement Y .
Class Members
An abstract class may have static fields and static methods. You can use these static members with a class reference (for example, AbstractClass.staticMethod() ) as you would with any other class.
Java Abstraction
Data abstraction is the process of hiding certain details and showing only essential information to the user.
Abstraction can be achieved with either abstract classes or interfaces (which you will learn more about in the next chapter).- Abstract class: is a restricted class that cannot be used to create objects (to access it, it must be inherited from another class).
- Abstract method: can only be used in an abstract class, and it does not have a body. The body is provided by the subclass (inherited from).
An abstract class can have both abstract and regular methods:
From the example above, it is not possible to create an object of the Animal class:
Animal myObj = new Animal(); // will generate an error
To access the abstract class, it must be inherited from another class. Let’s convert the Animal class we used in the Polymorphism chapter to an abstract class:
Remember from the Inheritance chapter that we use the extends keyword to inherit from a class.
Example
// Abstract class abstract class Animal < // Abstract method (does not have a body) public abstract void animalSound(); // Regular method public void sleep() < System.out.println("Zzz"); >> // Subclass (inherit from Animal) class Pig extends Animal < public void animalSound() < // The body of animalSound() is provided here System.out.println("The pig says: wee wee"); >> class Main < public static void main(String[] args) < Pig myPig = new Pig(); // Create a Pig object myPig.animalSound(); myPig.sleep(); >>
Why And When To Use Abstract Classes and Methods?
To achieve security — hide certain details and only show the important details of an object.
Note: Abstraction can also be achieved with Interfaces, which you will learn more about in the next chapter.