Подтвердить что ты не робот

Любой путь к конструктору _not_ вызывает суперкласс в Java?

Если у меня есть класс:

class A {
   public A() { }
}

и еще

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

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

4b9b3361

Ответ 1

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

JLS 12 Execution/12.5 Создание экземпляров нового класса

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

  • Назначить аргументы для конструктора [...]
  • Если этот конструктор начинается с явного вызова конструктора другого конструктора в том же классе (используя this), тогда [...]
  • Этот конструктор не начинается с явного вызова конструктора другого конструктора в том же классе (используя this). Если этот конструктор для класса, отличного от Object, то этот конструктор начнется с явного или неявного вызова конструктора суперкласса (используя super).
  • Выполнить инициализаторы экземпляра и инициализаторы переменных экземпляра для этого класса [...]
  • Выполнить оставшуюся часть этого конструктора [...]

Ответ 2

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

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 в качестве параметра.

Ответ 3

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

Ответ 4

Возможно, вы можете вызвать конструктор суперкласса по вашему выбору. Это возможно, если явно вызвать конструктор суперкласса как:

super(para_1, para_2,........);

class BaseA {
    BaseA(){
        System.out.println("This is BaseA");
    }
    BaseA(int a){
        System.out.println("This is BaseA a");
    }


}

class A extends BaseA {

    A(){
        super(5);
        System.out.println("This is A");
    }

    public static void main(String[] args) {
        A obj=new A();

    }
}


Output will be:
This is BaseA a
This is A

Ответ 5

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

Ответ 6

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

Ответ 7

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

Ответ 8

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

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

Настоятельно предлагайте против этого...

Ответ 9

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

Ответ 10

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

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 говорит о необходимости запускать его конструктор для его создания, а не необоснованно. Исключение состоит в том, что сериализуемые классы строятся без вызова конструкторов сериализуемых классов.

Ответ 11

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

  • В Java нет способа сделать это.

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

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

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

Итак, вы создали конструктор класса 3, который только вызывает конструкторы, которые ничего не делают.

Ответ 12

У меня было аналогичное требование, когда мне понадобился мой дочерний класс 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);
        // 
        // ...
    }
    // ....
}

Ответ 13

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

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

Я видел это недавно в Spring, при использовании прокси CGLIB, Spring создает два экземпляра класса, но конструктор вызывается только один раз: fooobar.com/info/268217/...

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

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