2010-06-03 3 views
19

Если у меня есть класс:Любой способ создания конструктора надстроек _not_ в Java?

class A { 
    public A() { } 
} 

и другой

class B extends A { 
    public B() { } 
} 

есть ли способ, чтобы получить B.B()не называть A.A()?

+0

Вы имеете в виду, что 'класс B расширяет A {'? BTW: Это не хорошие имена классов - они выглядят как общие параметры. –

+0

Вы все равно не вызываете конструктор A от B, B не наследуется от A –

+0

Спасибо всем. Я просто пытался расширить чужой класс из другого пакета. Я пошел с переписыванием его частей. См .: http://stackoverflow.com/questions/2962491/any-way-to-turn-off-quips-in-ooweb Спасибо! Misha –

ответ

0

Нет, и если бы вы могли, ваш производный объект на самом деле не был бы объектом, с которого он происходит сейчас? Принцип is-a будет нарушен. Поэтому, если вам это действительно нужно, полиморфизм - это не то, что вам нужно.

0

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

0

Я думаю, что единственный способ сделать это - испортить байт-код.
Я не уверен, что Classloader или JVM проверяет, вызывается ли super(), но, как писал Божо, вы, вероятно, закончите с непоследовательными объектами при этом.

26

В Java нет абсолютно никакого способа сделать это; это нарушит спецификацию языка.

JLS 12 Execution/12.5 Creation of New Class Instances

Непосредственно перед ссылкой на вновь созданный объект возвращается в качестве результата, указанный конструктор обрабатывается для инициализации нового объекта, используя следующую процедуру:

  1. Назначьте аргументы для конструктора [...]
  2. Если этот конструктор начинается с явного вызова конструктора другого конструктора в том же классе (с использованием), тогда [...]
  3. Этот конструктор не начинается с явного вызова конструктора другого конструктора в том же классе (с использованием this). Если этот конструктор предназначен для класса, отличного отObject, , тогда этот конструктор начнет с явного или неявного вызова конструктора суперкласса (с использованием super).
  4. выполнять экземпляр инициализаторы и экземпляр инициализаторы переменной для этого класса [...]
  5. Выполнить остальную часть тела этого конструктора [...]
+0

@reevesy ссылка сломана – earthdan

+1

@earthdan - fixed – reevesy

8

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

+1

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

+2

В ситуациях, когда класс обслуживает только как идентификатор типа и не предоставляет функциональность, например шаблон нулевого объекта, что не так с попыткой избежать накладных расходов на вызовы конструкторов по иерархии ?! –

16

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

public class A { 
    protected Writer writer; 

    public A() { 
    init(); 
    } 

    protected void init() { 
    writer = new FileWriter(new File("foo.txt")); 
    } 
} 

public class B extends A { 
    protected void init() { 
    writer = new PaperbackWriter(); 
    } 
} 

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

+6

«Эффективное Java 2nd Edition, пункт 17: дизайн и документ для наследования, а также запрет на это: конструкторы не должны ссылаться на переопределяемые методы, прямо или косвенно». – polygenelubricants

+3

Я не говорю, что это хорошо. Я просто говорю, что так ты и делал. – Adamski

+2

+1 за предоставление единственного полезного ответа;) –

0

Нет, вы не можете этого сделать и зачем вы хотите это делать? Это испортит вашу объектную модель.

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

Настоятельно рекомендуем не делать это ...

0

Каждый объект в Java является подклассом Object (объект с капиталом 'O'). при создании объекта подкласса вызывается конструктор суперкласса. Даже если ваш класс не наследует класс anyother, неявно он наследует Object, поэтому должен быть вызван конструктор Object. Поэтому для этой цели вызывается функция super().

0

Предполагая, что вы имеете в виду

class B extends A { 
    public B() { } 
} 

то, что вы можете

class B extends A { 
    public B() { 
     this(abort()); 
    } 
    private B(Void dummy) { 
     /* super(); */ 
    } 
    private static Void abort() { 
     throw null; 
    } 
} 

Не очень полезно. Интерфейс [не ключевое слово Java] для класса A говорит, что вам нужно запустить его конструктор, чтобы его построить, а не необоснованно. Исключение состоит в том, что сериализуемые классы строятся без вызова конструкторов сериализуемых классов.

0
  1. Как указано другим плакатом, B не расширяет A, поэтому он не будет называть конструктор A в любом случае.

  2. В Java нет возможности сделать это.

  3. Вы, вероятно, может выполнить то же самое, что вы хотите сделать следующим образом:

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

public class NoOp { 
} 

public class class1 { 
    class1() { 
     System.out.println("class1() called"); 
    } 
    class1(String x, String y) { 
     System.out.println("class1(String, String) called"); 
} 
    class1(NoOp x) { 
     System.out.println("class1(NoOp) called"); 
    } 
} 

public class class2 extends class1 { 
    class2() { 
     System.out.println("class2() called"); 
    } 
    class2(String x, String y) { 
     System.out.println("class2(String, String) called"); 
} 
    class2(NoOp x) { 
     super(x); 
     System.out.println("class2(NoOp) called"); 
    } 
} 

public class class3 extends class2 { 
    class3() { 
     System.out.println("class3() called"); 
    } 
    class3(String x, String y) { 
     super(new NoOp()); 
     System.out.println("class3(String, String) called"); 
    } 
    class3(NoOp x) { 
     super(x); 
     System.out.println("class3(NoOp) called"); 
    } 
    public static void main(String args[]) { 
     class3 x = new class3("hello", "world"); 
    } 
} 

При запуске этого вы получите выход

class1(NoOp) called 
class2(NoOp) called 
class3(String, String) called 

Таким образом, эффективно вы создали class3 конструктор, который вызывает только конструкторы, которые ничего не делают.

0

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

class SuperClass { 
    protected SuperClass() { 
     init(); 
    } 

    // Added for classes (like ChildClassNew) who do not want the init to be invoked. 
    protected SuperClass(boolean doInit) { 
     if (doInit) 
      init(); 
    } 

    // 
} 

class ChildClass1 extends SuperClass { 
    ChildClass1() { 
     // This calls default constructor of super class even without calling super() explicitly. 
     // ... 
    } 
    // .... 
} 

class ChildClass2 extends SuperClass { 
    ChildClass2() { 
     // This calls default constructor of super class even without calling super() explicitly. 
     // ... 
    } 
    // .... 
} 

class ChildClassNew extends SuperClass { 
    ChildClassNew() { 
     /* 
     * This is where I didn't want the super class' constructor to 
     * be invoked, because I didn't want the SuperClass' init() to be invoked. 
     * So I added overloaded the SuperClass' constructor where it diesn;t call init(). 
     * And call the overloaded SuperClass' constructor from this new ChildClassNew. 
     */ 
     super(false); 
     // 
     // ... 
    } 
    // .... 
} 
0

Java десериализация не вызывает конструктор, но кажется, что он основан на некоторых внутренних трюках JVM.

Однако, есть структура, которая позволяет сделать это в портативном образом: Objenesis (http://www.theserverside.com/discussions/thread/44297.html)

Я видел это в последнее время весной, при использовании CGLIB прокси, Spring создает два экземпляра класса, но конструктор вызывается только один раз: https://stackoverflow.com/a/11583641/2557118

Такое поведение добавляется в Spring 4:

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