Анотація класу на Java


274

Що таке "абстрактний клас" на Java?


35
+1 Це питання настільки основне та принципове, що класичне для ТА. Я здивований, що його тут раніше не просили.
Ювал

6
-1 за коментар Климента (якщо я міг); lmgtfy - це не корисна відповідь. А чому, наприклад , прочитати цю meta.stackexchange.com/questions/5280/embrace-the-non-googlers
Jonik

26
@tuergeist. Неважливо, чи легко це Google, якщо його раніше не запитували на SO. Крім того, хто каже, що питання початківців щодо мов програмування не належать до програми SO?
Джонік

12
Одне, що мені подобається у ЗП, це те, що ви отримаєте відповідь, яка є стислою, чітко кажучи, і без будь-якого звичного BS, що знаходиться в решті Інтернету ... Ну, щось подібне все одно. +1 за запитання!
Андерс Хансон

1
Так що не просто повинен мати довгий хвіст! J&J навіть говорять про це навколо подкасту 56 ...
kwutchak

Відповіді:


342

Абстрактний клас - це клас, який неможливо встановити. Абстрактний клас використовується шляхом створення спадкового підкласу, який можна інстанціювати. Абстрактний клас робить кілька речей для підзакладу, що спадкує:

  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!"); }
}

Ви не можете реалізувати методи в інтерфейсі. Це означає, що якщо ви реалізуєте два різних інтерфейси, різні методи в цих інтерфейсах не можуть зіткнутися. Оскільки всі методи в інтерфейсі абстрактні, ви повинні реалізувати метод, і оскільки ваш метод є єдиною реалізацією в дереві спадкування, компілятор знає, що він повинен використовувати ваш метод.


5
@Imagist -1 за неправильний опис для твердження c.implementedMethod (); // друкує "implemenMethod ()", він надрукує "Overriden!" завжди
Сахін Кумар

2
@Sachin я витратив півгодини набирання тексту, щоб зрозуміти, чому він надрукує "implemenMethod ()", і тоді я побачив ваш коментар. Щось змінилося з java чи інші просто помилилися на помилку?
Рунак

@SachinKumar Через відсутність відповіді автора я взяв на себе рішення, щоб виправити цю помилку. CMIIW.
Матін Ульхак

@SachinKumar Я трохи запізнююсь на грі тут, але ви б сказали, що хорошою аналогією було б декларування методу (але не реалізація) у файлі заголовка C ++?
Швайц

5
@SachinKumar навіщо c.implementedMethod()надрукувати " Переоцінений !"? SecondImplementingClassне перекриває implementedMethod().
Джон Ред

75

Клас Java стає абстрактним за таких умов:

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

public abstract void myMethod()

У такому випадку компілятор змушує вас позначити весь клас абстрактним.

2. Клас позначений як абстрактний:

abstract class MyClass

Як уже було сказано: Якщо у вас є абстрактний метод, компілятор змушує вас позначити весь клас абстрактним. Але навіть якщо у вас немає абстрактного методу, ви все одно можете позначати клас абстрактним.

Загальне використання:

Поширене використання абстрактних класів - це надання контуру класу, подібного інтерфейсу. Але на відміну від інтерфейсу він вже може забезпечити функціональність, тобто деякі частини класу реалізовані, а деякі частини просто окреслені декларацією методу. ("реферат")

Абстрактний клас не може бути ініційований, але ви можете створити конкретний клас на основі абстрактного класу, який потім можна інстанціювати. Для цього вам слід успадкувати від абстрактного класу і перекрити абстрактні методи, тобто реалізувати їх.


1
Нітпік: друга "умова" є зайвою, оскільки ви можете оголосити абстрактний метод лише у класі, який явно оголошується абстрактним.
Стівен С

2
Погоджено, порада насправді не правильна, або добре написана, вона просто добре відформатована.
Шовковий полудень

Але ваша порада "зробити клас конкретним" також сформульована неправильно. Ви не робите конкретний клас, він або є, чи ні, залежно від того, абстрактний він чи ні.
Полудень Шовк

1
Це просто неправильно. Абстрактний клас не повинен мати абстрактних методів. Можна скласти абстрактний клас без методів або лише з конкретними методами.
Jorn

1
10 років запізнюється на гру, але це найточніша відповідь. @Jorn ви плутаєте відповідь, я думаю. Я впевнений, що мається на увазі, що abstractключове слово - це все, що необхідно, щоб клас був абстрактним. Але конкретний клас не може містити abstract метод . Таким чином, якщо у вашого класу є abstractметод, він повинен бути оголошений abstractкомпілятором як клас.
Ракіб

24

Клас, який оголошується за допомогою абстрактного ключового слова, відомий як abstract class. Абстракція - це процес приховування деталей реалізації даних та показу користувачам лише функціональних можливостей. Абстракція дозволяє зосередитись на тому, що робить об’єкт, а не на тому, як він це робить.

Основні речі абстрактного класу

  • Абстрактний клас може містити або не містити абстрактних методів. Не можуть бути абстрактні методи.

    Абстрактний метод - це метод, який оголошується без реалізації (без дужок і слідує крапкою з комою), наприклад:

    колишній: abstract void moveTo(double deltaX, double deltaY);

  • Якщо в класі є хоча б один абстрактний метод, то цей клас повинен бути абстрактним

  • Абстрактні класи можуть бути невідомими (Вам не дозволяється створювати об'єкт класу "Анотація")

  • Щоб використовувати абстрактний клас, потрібно успадкувати його від іншого класу. Забезпечте реалізацію всіх абстрактних методів у ній.

  • Якщо ви успадковуєте абстрактний клас, ви повинні надати реалізації для всіх абстрактних методів у ньому.

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

abstract class AbstractDemo{ }

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

abstract void moveTo();//no body

Чому нам потрібні абстрактні заняття

У об’єктно-орієнтованому додатку для малювання можна малювати кола, прямокутники, лінії, криві Безьє та багато інших графічних об’єктів. Усі ці об'єкти мають спільні певні стани (наприклад, положення, орієнтація, колір лінії, колір заливки) та поведінку (наприклад, для переміщення, переміщення, зміни розміру, малювання). Деякі з цих станів і поведінки однакові для всіх графічних об'єктів (наприклад, колір заповнення, положення та переміщенняTo). Для інших потрібна інша реалізація (наприклад, розмір чи малюнок). Усі графічні об’єкти повинні вміти малювати чи змінювати розміри, вони просто відрізняються тим, як це роблять.

Це ідеальна ситуація для абстрактного суперкласу. Ви можете скористатися подібністю та оголосити всі графічні об'єкти успадкованими від того самого абстрактного батьківського об'єкта (наприклад:), GraphicObjectяк показано на наступному малюнку. введіть тут опис зображення

По-перше, ви оголошуєте абстрактний клас, 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

Є два способи досягти абстракції в яві

  • Абстрактний клас (від 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.

Список літератури:


Чому порядок параметрів x і y у переміщенніTo відрізняється у наведеному вище прикладі, наведеному нижче прикладі та висновку з прикладу нижче? Якщо ми намагаємось проілюструвати важливість таких понять, як інтерфейси та абстрактні класи, чи не повинні ми використовувати ті ж підписи функцій, що й інтерфейси чи абстрактні класи, які послідовно реалізуємо чи розширюємо?
Джонатан Ріс

обидва правила дають це
LiNKeR

4

Це клас, який неможливо створити, і змушує реалізувати класи, можливо, реалізувати абстрактні методи, які він окреслює.


3

Простіше кажучи, ви можете мислити абстрактний клас як інтерфейс, який має трохи більше можливостей.

Ви не можете створити інтерфейс, який також має відношення до абстрактного класу.

У своєму інтерфейсі ви можете просто визначити заголовки методу, і ВСІ реалізатори змушені реалізувати їх усі . На абстрактному класі ви також можете визначити заголовки методів, але тут - на відміну інтерфейсу - ви також можете визначити тіло методу (як правило, за замовчуванням). Більше того, коли інші класи поширюються (зверніть увагу, не реалізуйте, і тому ви також можете мати лише один абстрактний клас на дочірній клас) ваш абстрактний клас, вони не змушені застосовувати всі ваші методи вашого абстрактного класу, якщо ви не вказали абстрактний метод ( у такому випадку він працює як для інтерфейсів, ви не можете визначити тіло методу).

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();
}

Ця відповідь не корисна, якщо ОП не знає, що таке інтерфейс. Оскільки абстрактні класи та інтерфейси взаємопов'язані, навряд чи ОП знає одне, не знаючи іншого.
Imagist

Але це могло бути. Можливо, він просто знає, що таке інтерфейс і як він працює, а потім наштовхується на абстрактні класи і замислюється, навіщо їм вони потрібні. Не могло це бути?
Юрі

3

З документації oracle

Абстрактні методи та заняття:

Абстрактний клас - це клас, який оголошується абстрактним - він може включати або не включати абстрактні методи

Абстрактні класи не можуть бути екземплярами, але вони можуть бути підкласами

Абстрактний метод - це метод, який оголошується без реалізації (без дужок і слідує крапкою з комою), наприклад:

abstract void moveTo(double deltaX, double deltaY);

Якщо клас включає абстрактні методи, то сам клас повинен бути оголошений абстрактним, як у:

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

Коли абстрактний клас є підкласом, підклас зазвичай забезпечує реалізацію для всіх абстрактних методів у своєму батьківському класі. Однак якщо цього немає, підклас також повинен бути оголошений абстрактним .

Оскільки abstract classesі interfacesпов'язані між собою, дивіться нижче питання SE:

Чим відрізняється інтерфейс від абстрактного класу?

Як я повинен пояснити різницю між класом інтерфейсу та абстрактним?


3

Отримайте відповіді тут:

Абстрактний клас проти інтерфейсу на Java

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

BTW - це питання, які ви задали нещодавно. Подумайте над новим питанням для формування репутації ...

Редагувати:

Щойно зрозумів, що афіші цього та посилань на них мають однакове або принаймні подібне ім'я, але ідентифікатор користувача завжди відрізняється. Отже, або є технічна проблема, що у клавіатури виникають проблеми з входом знову і пошуку відповідей на його запитання, або це якась гра для розваги спільноти SO;)


І тому я перевірив "Вікі спільноти" - не слід підвищувати репутацію, реагуючи на ці питання;)
Андреас Долк,

1

Невелике доповнення до всіх цих постів.

Іноді ви можете оголосити клас, але ще не знаєте, як визначити всі методи, що належать до цього класу. Наприклад, ви можете оголосити клас під назвою Writer і включити до нього метод-член, який називається write () . Однак ви не знаєте, як кодувати write (), оскільки це різне для кожного типу пристроїв Writer. Звичайно, ви плануєте це впоратися, вивівши підклас програми Writer, наприклад, принтер, диск, мережа та консоль.


1

Абстрактний клас не може бути безпосередньо інстанційним, але повинен бути похідним від того, щоб бути корисним. Клас ОБОВ'ЯЗКОВО бути абстрактним, якщо він містить абстрактні методи: або безпосередньо

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

Рішення - базовий клас (реферат)

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();

}

1
спробуйте відформатувати весь код як код, і будь ласка, додайте пояснення, зараз це навряд чи можна вважати відповіддю.
NomeN

3
до тих пір, поки ви не надали пояснення свого коду. Вас вважали б поганим відповідачем. Тож, будь ласка, поясніть тут
девсда

0

Абстрактний клас - це клас, який оголошується абстрактним - він може включати або не включати абстрактні методи. Абстрактні класи не можуть бути екземплярами, але вони можуть бути підкласами.

Іншими словами, клас, який оголошується абстрактним ключовим словом, відомий як абстрактний клас у java. Він може мати абстрактні (метод без тіла) та неабразивні методи (метод з тілом).

Важлива примітка: - Абстрактні класи не можуть бути використані для створення об'єктів, вони можуть бути використані для створення посилань на об'єкти, оскільки підхід Java до поліморфізму під час виконання реалізується за допомогою посилань на суперкласи. Таким чином, необхідно створити посилання на абстрактний клас, щоб його можна було використовувати для вказівки на об'єкт підкласу. Ви побачите цю функцію на прикладі нижче

abstract class Bike{  
  abstract void run();  
}  

class Honda4 extends Bike{  
    void run(){
        System.out.println("running safely..");
    }  

    public static void main(String args[]){  
       Bike obj = new Honda4();  
       obj.run();  
    }  
} 

0

Абстрактний клас - це той, який не повністю реалізований, але забезпечує щось підґрунтя для підкласів. Це може бути частково реалізовано тим, що воно містить повністю визначені конкретні методи, але воно може також містити абстрактні методи. Це методи з підписом, але немає методу. Будь-який підклас повинен визначати тіло для кожного абстрактного методу, інакше він також повинен бути оголошений абстрактним. Оскільки абстрактні класи не можуть бути ініціативними, їх слід подовжити хоча б одним підкласом, щоб їх використовувати. Подумайте про абстрактний клас як про загальний клас, а підкласи є там, щоб заповнити відсутні дані.


0

Клас, який може мати як конкретні, так і не конкретні методи, тобто з тілом і без нього.

  1. Методи без реалізації повинні містити "абстрактне" ключове слово.
  2. Абстрактний клас не можна створити.

-1

Це нічого не робить, просто надайте загальний шаблон, яким буде надано спільний доступ до його підкласу

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.