Если у меня есть класс:
class A {
public A() { }
}
и другой
class B extends A {
public B() { }
}
есть ли любой способ добраться B.B()
не звонить A.A()
?
Как указал другой автор, B не расширяет A, поэтому он в любом случае не будет вызывать конструктор A.
В 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
Таким образом, вы фактически создали конструктор class3, который вызывает только конструкторы, которые не я ничего не делаю.
Нет, вы не можете этого сделать, и зачем вам это делать? Это испортит вашу объектную модель.
В любом случае - я считаю, что если вы все еще хотите это сделать, тогда вам придется манипулировать сгенерированным байтовым кодом ... есть несколько доступных библиотек, которые упрощают инструментирование байтового кода.
Настоятельно не рекомендую делать это ...
Нет, и если бы вы могли, ваш производный объект на самом деле не был бы объектом, из которого он выводится сейчас, не так ли? Принцип is-a будет нарушен. Поэтому, если вам это действительно нужно, то полиморфизм — это не то, к чему вы ищете.
В Java нет абсолютно никакого способа сделать это; это нарушит спецификацию языка.
Выполнение JLS 12 / 12.5 Создание экземпляров нового класса
Непосредственно перед тем, как в качестве результата будет возвращена ссылка на вновь созданный объект, указанный конструктор обрабатывается для инициализации нового объекта с использованием следующей процедуры:
- Назначить аргументы для конструктора [...]
- Если этот конструктор начинается с явного вызова конструктора другого конструктора в том же классе (используя
this
), то [...]- Этот конструктор не начинается с явного вызова конструктора другого конструктора в том же классе (используя
this
). Если этот конструктор предназначен для класса, отличного отObject
, , то этот конструктор начнется с явного или неявного вызова конструктора суперкласса (с использованиемsuper
).- Выполнить инициализаторы экземпляра и инициализаторы переменных экземпляра для этого класса [...]
- Выполнить остальную часть тела этого конструктора [...]
Каждый объект в java является подклассом Object (объект с большой буквы 'O'). когда вы создаете объект подкласса, вызывается конструктор суперкласса. Даже если ваш класс не наследует никакой другой класс, неявно он наследует Object, поэтому конструктор Object должен быть вызван. Поэтому для этой цели вызывается super().
Если вы имеете в виду
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
говорит о том, что вам нужно запустить его конструктор, чтобы построить его, и не без оснований. Исключением является то, что сериализуемые классы создаются без вызова конструкторов сериализуемых классов.
Каждый суперкласс требует создания , и нет другого способа, кроме вызова конструктора.
Самое близкое к желаемому поведению, которое вы можете достичь, - это делегирование инициализации, обычно выполняемой в конструкторе, методу шаблона, который вы затем переопределяете в реализации вашего подкласса. Например:
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
в качестве параметра.
Если вы не хотите вызывать конструктор суперкласса, значит в вашей объектной модели что-то еще не так.
Я думаю, что единственный способ сделать это - испортить байт-код.
Я не уверен, проверяет ли загрузчик классов или JVM, вызывается ли super()
, но, как написал Божо, вы, вероятно, получите в итоге несовместимые объекты.