Абстрактный класс на Java - PullRequest
261 голосов
/ 24 августа 2009

Что такое «абстрактный класс» в Java?

Ответы [ 14 ]

329 голосов
/ 24 августа 2009

Абстрактный класс - это класс, создание которого невозможно. Абстрактный класс используется путем создания наследующего подкласса, для которого может быть создан . Абстрактный класс делает несколько вещей для наследующего подкласса:

  1. Определить методы, которые могут использоваться наследующим подклассом.
  2. Определите абстрактные методы, которые должен реализовывать наследующий подкласс.
  3. Предоставляет общий интерфейс, который позволяет подклассу обмениваться со всеми другими подклассами.

Вот пример:

abstract public class AbstractClass
{
    abstract public void abstractMethod();
    public void implementedMethod() { System.out.print("implementedMethod()"); }
    final public void finalMethod() { System.out.print("finalMethod()"); }
}

Обратите внимание, что у abstractMethod () нет тела метода. Из-за этого вы не можете сделать следующее:

public class ImplementingClass extends AbstractClass
{
    // ERROR!
}

Нет метода, который реализует abstractMethod()! Таким образом, у JVM нет возможности узнать, что он должен делать, когда получает что-то вроде new ImplementingClass().abstractMethod().

Вот правильный ImplementingClass.

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
}

Обратите внимание, что вам не нужно определять implementedMethod() или finalMethod(). Они уже были определены AbstractClass.

Вот еще один правильный ImplementingClass.

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

В этом случае вы переопределили implementedMethod().

Однако из-за ключевого слова final следующее невозможно.

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
    public void finalMethod() { System.out.print("ERROR!"); }
}

Вы не можете сделать это, потому что реализация finalMethod() в AbstractClass помечена как окончательная реализация finalMethod(): никакие другие реализации не будут разрешены.

Теперь вы можете также реализовать абстрактный класс дважды:

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

// In a separate file.
public class SecondImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("second abstractMethod()"); }
}

Теперь где-нибудь вы могли бы написать другой метод.

public tryItOut()
{
    ImplementingClass a = new ImplementingClass();
    AbstractClass b = new ImplementingClass();

    a.abstractMethod();    // prints "abstractMethod()"
    a.implementedMethod(); // prints "Overridden!"     <-- same
    a.finalMethod();       // prints "finalMethod()"

    b.abstractMethod();    // prints "abstractMethod()"
    b.implementedMethod(); // prints "Overridden!"     <-- same
    b.finalMethod();       // prints "finalMethod()"

    SecondImplementingClass c = new SecondImplementingClass();
    AbstractClass d = new SecondImplementingClass();

    c.abstractMethod();    // prints "second abstractMethod()"
    c.implementedMethod(); // prints "implementedMethod()"
    c.finalMethod();       // prints "finalMethod()"

    d.abstractMethod();    // prints "second abstractMethod()"
    d.implementedMethod(); // prints "implementedMethod()"
    d.finalMethod();       // prints "finalMethod()"
}

Обратите внимание, что, хотя мы объявили тип b AbstractClass, он отображает "Overriden!". Это потому, что объект, который мы создали, на самом деле был ImplementingClass, чей implementedMethod(), конечно, переопределен. (Возможно, вы видели, что это называется полиморфизмом.)

Если мы хотим получить доступ к члену, специфичному для определенного подкласса, мы должны сначала привести к этому подклассу:

// Say ImplementingClass also contains uniqueMethod()
// To access it, we use a cast to tell the runtime which type the object is
AbstractClass b = new ImplementingClass();
((ImplementingClass)b).uniqueMethod();

Наконец, вы не можете делать следующее:

public class ImplementingClass extends AbstractClass, SomeOtherAbstractClass
{
    ... // implementation
}

Одновременно может быть продлен только один класс. Если вам нужно расширить несколько классов, они должны быть интерфейсами. Вы можете сделать это:

public class ImplementingClass extends AbstractClass implements InterfaceA, InterfaceB
{
    ... // implementation
}

Вот пример интерфейса:

interface InterfaceA
{
    void interfaceMethod();
}

Это в основном так же, как:

abstract public class InterfaceA
{
    abstract public void interfaceMethod();
}

Единственное отличие состоит в том, что второй способ не дает компилятору понять, что это на самом деле интерфейс. Это может быть полезно, если вы хотите, чтобы люди реализовывали только ваш интерфейс, а не другие Однако, как общее практическое правило для начинающих, если ваш абстрактный класс имеет только абстрактные методы, вы, вероятно, должны сделать его интерфейсом.

Недопустимо следующее:

interface InterfaceB
{
    void interfaceMethod() { System.out.print("ERROR!"); }
}

Вы не можете реализовать методы в интерфейсе. Это означает, что если вы реализуете два разных интерфейса, разные методы в этих интерфейсах не могут конфликтовать. Поскольку все методы в интерфейсе являются абстрактными, вы должны реализовать метод, и поскольку ваш метод является единственной реализацией в дереве наследования, компилятор знает, что он должен использовать ваш метод.

71 голосов
/ 24 августа 2009

Java-класс становится абстрактным при следующих условиях:

1. По крайней мере один из методов помечен как абстрактный:

public abstract void myMethod()

В этом случае компилятор заставляет вас пометить весь класс как абстрактный.

2. Класс помечен как абстрактный:

abstract class MyClass

Как уже говорилось: если у вас есть абстрактный метод, компилятор заставляет вас пометить весь класс как абстрактный. Но даже если у вас нет абстрактного метода, вы все равно можете пометить класс как абстрактный.

Общее использование:

Обычное использование абстрактных классов - предоставить схему класса, похожего на интерфейс. Но, в отличие от интерфейса, он уже может обеспечивать функциональность, то есть некоторые части класса реализованы, а некоторые просто обозначены объявлением метода. ( "Абстрактный") * * тысяча двадцать-одна

Абстрактный экземпляр не может быть создан, но вы можете создать конкретный класс на основе абстрактного класса, который затем можно создать. Для этого вы должны наследовать от абстрактного класса и переопределять абстрактные методы, то есть реализовывать их.

20 голосов
/ 16 августа 2017

Класс, который объявлен с использованием ключевого слова abstract , известен как abstract class. Абстракция - это процесс скрытия деталей реализации данных и отображения только функциональных возможностей для пользователя. Абстракция позволяет вам сосредоточиться на том, что делает объект, а не на том, как он это делает.

Основные вещи абстрактного класса

  • Абстрактный класс может содержать или не содержать абстрактные методы. Могут быть неабстрактные методы.

    Абстрактный метод - это метод, который объявлен без реализация (без фигурных скобок, после которой ставится точка с запятой), например:

    напр .: abstract void moveTo(double deltaX, double deltaY);

  • Если в классе есть хотя бы один абстрактный метод, этот класс должен быть абстрактным

  • Классы Abstract не могут быть созданы (вам не разрешено создавать объекты класса Abstract)

  • Чтобы использовать абстрактный класс, вы должны наследовать его от другого класса. Предоставить реализации для всех абстрактных методов в нем.

  • Если вы наследуете абстрактный класс, вы должны предоставить реализации для всех абстрактных методов в нем.

Объявить абстрактный класс Указание ключевого слова abstract перед классом во время объявления делает его абстрактным. Посмотрите на код ниже:

abstract class AbstractDemo{ }

Объявить абстрактный метод Указание ключевого слова abstract перед методом во время объявления делает его абстрактным. Посмотрите на код ниже,

abstract void moveTo();//no body

Почему нам нужно абстрагировать классы

В объектно-ориентированном приложении для рисования вы можете рисовать круги, прямоугольники, линии, кривые Безье и многие другие графические объекты. Все эти объекты имеют определенные состояния (например, положение, ориентация, цвет линии, цвет заливки) и общее поведение (например, перемещение, поворот, изменение размера, рисование). Некоторые из этих состояний и поведения одинаковы для всех графических объектов (например, цвет заливки, положение и перемещение). Другие требуют другой реализации (например, изменить размер или нарисовать). Все графические объекты должны уметь рисовать или изменять размеры сами, они просто отличаются тем, как они это делают.

Это идеальная ситуация для абстрактного суперкласса. Вы можете воспользоваться сходствами и объявить все графические объекты наследуемыми от того же абстрактного родительского объекта (например, GraphicObject), как показано на следующем рисунке. enter image description here

Сначала вы объявляете абстрактный класс GraphicObject для предоставления переменных-членов и методов, которые полностью используются всеми подклассами, такими как текущая позиция и метод moveTo. GraphicObject также объявлены абстрактные методы, такие как рисование или изменение размера, которые должны быть реализованы всеми подклассами, но должны быть реализованы по-разному. Класс GraphicObject может выглядеть примерно так:

abstract class GraphicObject {

  void moveTo(int x, int y) {
    // Inside this method we have to change the position of the graphic 
    // object according to x,y     
    // This is the same in every GraphicObject. Then we can implement here. 
  }

  abstract void draw(); // But every GraphicObject drawing case is 
                        // unique, not common. Then we have to create that 
                        // case inside each class. Then create these    
                        // methods as abstract 
  abstract void resize();
}

Использование абстрактного метода в подклассах Каждый неабстрактный подкласс GraphicObject, такой как Circle и Rectangle, должен предоставлять реализации для методов draw и resize.

class Circle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here   
  }
}
class Rectangle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here
  }
}

Внутри метода main вы можете вызывать все методы следующим образом:

public static void main(String args[]){
   GraphicObject c = new Circle();
   c.draw();
   c.resize();
   c.moveTo(4,5);   
}

Способы достижения абстракции в Java

Есть два способа достижения абстракции в Java

  • Абстрактный класс (от 0 до 100%)
  • Интерфейс (100%)

Абстрактный класс с конструкторами, членами данных, методами и т. Д.

abstract class GraphicObject {

  GraphicObject (){
    System.out.println("GraphicObject  is created");
  }
  void moveTo(int y, int x) {
       System.out.println("Change position according to "+ x+ " and " + y);
  }
  abstract void draw();
}

class Circle extends GraphicObject {
  void draw() {
    System.out.println("Draw the Circle");
  }
}

class TestAbstract {  
 public static void main(String args[]){

   GraphicObject  grObj = new Circle ();
   grObj.draw();
   grObj.moveTo(4,6);
 }
}

Выход:

GraphicObject  is created
Draw the Circle
Change position according to 6 and 4

Запомните два правила:

  • Если в классе мало абстрактных методов и мало конкретных методов, объявить его как abstract класс.

  • Если в классе есть только абстрактные методы, объявите его как interface.

Справочные материалы:

4 голосов
/ 24 августа 2009

Это класс, который не может быть создан, и заставляет реализацию классов, возможно, реализовывать абстрактные методы, которые он обрисовывает в общих чертах.

3 голосов
/ 28 февраля 2016

Из оракула Документация

Абстрактные методы и классы:

Абстрактный класс - это класс, который объявлен абстрактным - он может включать или не включать абстрактные методы

Абстрактные классы не могут быть созданы, но они могут быть разделены на подклассы

Абстрактный метод - это метод, который объявляется без реализации (без фигурных скобок и с точкой с запятой), следующим образом:

abstract void moveTo(double deltaX, double deltaY);

Если класс включает абстрактные методы, то сам класс должен быть объявлен абстрактным, как в:

public abstract class GraphicObject {
   // declare fields
   // declare nonabstract methods
   abstract void draw();
}

Когда абстрактный класс находится в подклассе, подкласс обычно обеспечивает реализации для всех абстрактных методов в своем родительском классе. Однако, если это не так, то подкласс также должен быть объявлен абстрактным .

Поскольку abstract classes и interfaces связаны между собой, взгляните на следующие вопросы SE:

В чем разница между интерфейсом и абстрактным классом?

Как мне объяснить разницу между интерфейсом и абстрактным классом?

3 голосов
/ 24 августа 2009

Получите ваши ответы здесь:

Абстрактный класс и интерфейс в Java

Может ли абстрактный класс иметь конечный метод?

Кстати - это вопрос, который вы задали недавно. Подумайте о новом вопросе для создания репутации ...

Изменить:

Только что понял, что постеры этого и упомянутых вопросов имеют одинаковое или, по крайней мере, похожее имя, но идентификатор пользователя всегда различен. Так что либо есть техническая проблема, у кейера возникают проблемы с повторным входом в систему и поиском ответов на его вопросы, или это своего рода игра для развлечения сообщества SO;)

3 голосов
/ 24 августа 2009

Проще говоря, вы можете думать об абстрактном классе как об интерфейсе с немного большими возможностями.

Вы не можете создать экземпляр интерфейса, который также подходит для абстрактного класса.

В вашем интерфейсе вы можете просто определить заголовки методов, и ВСЕ из реализаторов вынуждены реализовать всех из них. В абстрактном классе вы также можете определить заголовки вашего метода, но здесь - в отличие от интерфейса - вы также можете определить тело (обычно реализация по умолчанию) метода. Более того, когда другие классы расширяют (обратите внимание, не реализуют и, следовательно, вы также можете иметь только один абстрактный класс на дочерний класс) вашего абстрактного класса, они не будут вынуждены реализовывать все ваши методы вашего абстрактного класса, если только вы указали абстрактный метод (в этом случае он работает как для интерфейсов, вы не можете определить тело метода).

public abstract class MyAbstractClass{
  public abstract void DoSomething();
}

В противном случае для обычных методов абстрактного класса «наследники» могут либо просто использовать поведение по умолчанию, либо переопределить его, как обычно.

Пример:

public abstract class MyAbstractClass{

  public int CalculateCost(int amount){
     //do some default calculations
     //this can be overriden by subclasses if needed
  }

  //this MUST be implemented by subclasses
  public abstract void DoSomething();
}
1 голос
/ 24 августа 2009

Абстрактный класс не может быть напрямую создан, но должен быть получен из, чтобы его можно было использовать. Класс ДОЛЖЕН быть абстрактным, если он содержит абстрактные методы: либо напрямую

abstract class Foo {
    abstract void someMethod();
}

или косвенно

interface IFoo {
    void someMethod();
}

abstract class Foo2 implements IFoo {
}

Однако класс может быть абстрактным, не содержащим абстрактных методов. Это способ предотвратить прямую инстанцию, например

abstract class Foo3 {
}

class Bar extends Foo3 {

}

Foo3 myVar = new Foo3(); // illegal! class is abstract
Foo3 myVar = new Bar(); // allowed!

Последний стиль абстрактных классов может использоваться для создания "интерфейсоподобных" классов. В отличие от интерфейсов, абстрактный класс может содержать неабстрактные методы и переменные экземпляра. Вы можете использовать это для предоставления некоторых базовых функций расширению классов.

Другой частый шаблон - реализовать основные функции в абстрактном классе и определить часть алгоритма в абстрактном методе, который будет реализован расширяющим классом. Глупый пример:

abstract class Processor {
    protected abstract int[] filterInput(int[] unfiltered);

    public int process(int[] values) {
        int[] filtered = filterInput(values);
        // do something with filtered input
    }
}

class EvenValues extends Processor {
    protected int[] filterInput(int[] unfiltered) {
        // remove odd numbers
    }
}

class OddValues extends Processor {
    protected int[] filterInput(int[] unfiltered) {
        // remove even numbers
    }
}
1 голос
/ 24 августа 2009

Небольшое дополнение ко всем этим постам.

Иногда вы можете объявить класс и еще не знаю, как определить все методы, которые относятся к этому учебный класс. Например, вы можете захотеть объявить класс с именем Writer и включить в него метод-член запись () . Тем не менее, вы не знаете, как кодировать write () , потому что это разные для каждого типа писателя устройства. Конечно, вы планируете справиться это путем получения подкласса Writer, такие как принтер, диск, сеть и Консоль.

1 голос
/ 24 августа 2009

Решение - базовый класс (аннотация)

public abstract class Place {

String Name;
String Postcode;
String County;
String Area;

Place () {

        }

public static Place make(String Incoming) {
        if (Incoming.length() < 61) return (null);

        String Name = (Incoming.substring(4,26)).trim();
        String County = (Incoming.substring(27,48)).trim();
        String Postcode = (Incoming.substring(48,61)).trim();
        String Area = (Incoming.substring(61)).trim();

        Place created;
        if (Name.equalsIgnoreCase(Area)) {
                created = new Area(Area,County,Postcode);
        } else {
                created = new District(Name,County,Postcode,Area);
        }
        return (created);
        }

public String getName() {
        return (Name);
        }

public String getPostcode() {
        return (Postcode);
        }

public String getCounty() {
        return (County);
        }

public abstract String getArea();

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...