2014-09-05 3 views
5

Может иметь абстрактный класс , реализующий все его методы - без абстрактных методов в нем.В чем смысл абстрактного класса без абстрактных методов?

Например .:

public abstract class someClass { 
    int a; 
    public someClass (int a) { this.a = a; } 
    public void m1() { /* do something */ } 
    private void m2() { /* do something else */ } 
} 

В чем преимущество, если таковые имеются, имеющие такой абстрактный класс по сравнению с наличием того же класса, как конкретный один вместо этого?

Один я могу думать о том, что, когда я объявляю его абстрактным, он не будет создан. Однако я могу иметь такой же эффект, делая его конкретным и его конструктором (-ами) частным.

TIA.

// ==================

EDIT: Один другого использования я могу думать:

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

+2

Вы можете предоставить никому из инстанцировании этого класса. – Kon

+0

Если вы сделаете конструктор закрытым, тогда вы превратите его в одноэлементный или вам понадобится публичный статический метод, чтобы получить экземпляр класса, который в качестве абстрактного класса поможет вам в наследовании ... – StackFlowed

+0

Создание всех конструкторов 'protected' (следите за дефолтом) имеет очень похожий эффект и на самом деле является моим предпочтительным способом сделать это. Возможно, это опечатка в OP. – 5gon12eder

ответ

2

У этого есть концептуальное значение: у этого класса есть поведение, которое не имеет никакого смысла само по себе.

Конечно, трудно представить такой сценарий без четко определенных точек расширения (т. Е. Абстрактных методов), но иногда это будет достаточно точная модель вашей проблемы.

Вы можете иметь что-то вроде этого:

public abstract class ObjectWithId { 
    private final String id; 

    public ObjectWithId(String id) { 
     this.id = id; 
    } 

    public final String getId() { 
     return id; 
    } 
} 

И тогда вы можете продлить его, чтобы объявить различные типы объектов, которые имеют идентификаторы. Здесь у вас есть полностью определенное и внедренное поведение, но никаких ограничений на какие-либо другие подклассы поведения могут не проявляться.

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

public final class ObjectWithId<T> { 
    private final String id; 
    private final T ob; 

    public ObjectWithId(String id, T ob) { 
     this.id = id; 
     this.ob = ob; 
    } 

    public String getId() { 
     return id; 
    } 

    public T getObject() { 
     return ob; 
    } 
} 

Но прежде чем были введены дженериков (до Java версии 1.4), то это не было бы так элегантно, и, очевидно, лучше, чем решение абстрактного класса, потому что вы должны были бы торговать в безопасности типа.

+0

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

+0

Принимая первый ok ans, когда позволяет. другой получает вверх. – user3880721

2
  • вы можете объявить реализовать интерфейс и не обеспечивают реализацию, а затем каждый ребенок неявно получает интерфейс расширен

  • предотвратить создание экземпляра этого класса

  • вы в будущем обеспечить общий осуществление для всех детей
1

Полезно, если вы считаете это полезный класс.

2

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

1

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

Что касается ПОЧЕМУ, вы бы хотели сделать это на практике ... Мне трудно думать о хорошей причине. Можно сказать, что класс имеет смысл только в том случае, если кто-то создает подкласс, который реализует некоторую функцию. Но почему бы не сделать эту функцию абстрактной в суперклассе?

Я бы не исключил, что кто-то может придумать пример, где это имеет смысл, но я не могу думать об этом. Просто потому, что можно написать кусок кода и успешно выполнить компиляцию кода, это не значит, что это имеет смысл. Я имею в виду, я могу написать «total_price = item_price * zip_code + customer_height_in_cubits - 7.879», но это не значит, что такая строка кода будет иметь смысл.

1

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

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

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

2

Мы обычно используем Abstraction concept with inheritance

Рассмотрите возможность использования абстрактных классов, если любой из этих утверждений относится к вашей ситуации:

  • Вы хотите поделиться кодом из нескольких тесно связанных классов.

Чтобы ответить на ваш вопрос,

Why declare a class with concrete methods Abstract?

Одной из возможных причин для поддержки наследования без фактического создания объектов


Предположим, у вас есть два CLA ГСЭС один абстрактный и других бетонных

Абстрактный класс: AbsClass

abstract class AbsClass { 
    int a = 5; 

    //Constructor 
    public AbsClass() { 
    System.out.println(a); 
    } 

    void methodA() { 
    System.out.println(a + 10); 

    } 

} 

и Класс бетона: ConcreteClass

class ConcreteClass { 
    int a = 10; 

//Made the constructor Private to prevent from creating objects of this class 
    private ConcreteClass() { 
    System.out.println(a); 

    } 

    void methodA() { 
    System.out.println(a + 10); 
    } 

}

Вышеуказанные два класса должны функционировать так же, пока не попробуешь подклассу их

class AbsImplementer extends AbsClass { 
//Works fine 

} 

class ConcImplementer extends ConcreteClass { 
//Compilation Error Implicit super constructor ConcreteClass() is not visible 


} 
1

Рассмотрим что-то похожее на NVI pattern (не уверен, что вы бы назвали его в Java) (?):

public abstract class A { 
    public final void doSomething() { 
     System.out.println("required"); 
     doOptional(); 
    } 

    protected void doOptional() { 
     System.out.println("optional"); 
    } 
} 

public class B extends A { 
    @Override 
    protected void doOptional() { 
     System.out.println("overridden"); 
    } 
} 

Для вашего общедоступного API вы можете открыть публичный окончательный метод, который нельзя переопределить. Он выполняет некоторые необходимые работы внутри и дополнительный метод. При расширении этого класса вы можете переопределить doOptional().

Вызов B.doSomething() всегда будет печатать «требуется» до его продолжения.

Поскольку doOptional() не является абстрактным, нет чисто кодовой причины, что класс A должен быть абстрактным. Но это может быть желательно для вашего конкретного проекта. Например, базовая услуга, которая всегда распространяется на конкретные подпроекты.

1

Это может быть полезно в тех случаях, когда классы, полученные от абстрактного базового класса должны иметь некоторое поведение, которое отличается друг от друга но, что поведение не может быть забранной как находящиеся внутри метода, который имеет ту же сигнатуру для всех классов. Невозможность обмена сигнатурой может произойти, если для другого поведения требуются методы, которые передаются с помощью разных примитивных типов. Поскольку они используют примитивные типы, вы не можете использовать generics для выражения сходства.

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

Например:

abstract class Sender { 
    protected final void beginMessage() { 
     ... 
    } 

    protected final void endMessage() { 
     ... 
    } 

    protected final void appendToMessage(int x) { 
     ... 
    } 
} 

final class LongSender extends Sender { 
    public void send(int a, int b, int c) { 
     beginMessage(); 
     appendToMessage(a); 
     appendToMessage(b); 
     appendToMessage(c); 
     endMessage(); 
    } 
} 

final class ShortSender extends Sender { 
    public void send(int a) { 
     beginMessage(); 
     appendToMessage(a); 
     endMessage(); 
    } 
} 
Смежные вопросы