2009-12-07 3 views
0

Может кто-то указать, что я недопонимаю?Java: абстрактные конструкторы классов и это()

У меня есть два класса, реферат и бетон, а именно:

public abstract class Abstract 
{ 
    protected static int ORDER = 1; 

    public static void main (String[] args) 
    { 
     Concrete c = new Concrete("Hello"); 
    } 

    public Abstract() 
    { 
     Class c = this.getClass(); 
     System.out.println(ORDER++ + ": Class = " 
      + c.getSimpleName() 
      + "; Abstract's no-arg constructor called."); 
    } 

    public Abstract(String arg) 
    { 
     this(); 
     Class c = this.getClass(); 
     System.out.println(ORDER++ + ": Class = " 
      + c.getSimpleName() 
      + "; Abstract's 1-arg constructor called."); 
    } 
} 

и

public class Concrete extends Abstract 
{ 
    public Concrete() 
    { 
     super(); 
     Class c = this.getClass(); 
     System.out.println(ORDER++ + ": Class = " 
      + c.getSimpleName() 
      + "; Concrete's no-arg constructor called."); 
    } 

    public Concrete(String arg) 
    { 
     super(arg); 
     Class c = this.getClass(); 
     System.out.println(ORDER++ + ": Class = " 
      + c.getSimpleName() 
      + "; Concrete's 1-arg constructor called."); 
    } 
} 

Когда я запускаю это я получаю следующий результат:

1) Класс = Бетон; Вызов конструктора no-arg .
2) Класс = Бетон; Создан конструктор 1-arg абстрактного объекта .
3) Класс = Бетон; Конкретный конструктор 1-arg Concrete.

Мой вопрос заключается в следующем: почему не вызов этого() из конструктора args String от String вызывает этот конструктор no-arg на Concrete? Или, возможно, более уместно, есть ли какой-либо способ заставить конструктор arg String ссылаться на конструктор no-arg на Concrete, позволяя «правильную» цепочку конструкторов?

ответ

7

Нет - цепь конструктора всегда идет либо боком (в том же виде), либо вверх (к родительскому типу).

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

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

Что вы на самом деле пытаетесь сделать? Обычно я считаю, что лучше иметь множество «боковых» цепей, ведущих к одному конструктору, который имеет «восходящую» цепочку.

+0

Спасибо Jon. Тот факт, что getClass знает Object isa Concrete, но это() вызывает абстрактный конструктор no-arg, что кажется мне немного неестественным. Цепочка, которую я пыталась достичь, показала бы мне, что позволила бы более естественное разделение ответственности между конструкторами. Я думаю, что мне придется дублировать код в конструкторах Concrete или переместить его в новый метод, но поскольку я не пишу всех реализаций Concrete этого абстрактного класса, это то, что мне придется документировать для других разработчиков , –

+1

Итак, вы пытались рассматривать конструкторы, как если бы они были виртуальными методами? Да, это не сработает. –

1

Это просто так, как есть (подробно описано Джоном Скитом).

Вы можете добавить блок инициализации к бетону, хотя:

{ 
    Class c = this.getClass(); 
    System.out.println(ORDER++ + ": Class = " 
    + c.getSimpleName() 
    + "; Concrete's init block called."); 
} 

В отличие от конструктора по умолчанию, блок inizializer всегда называется:

1: Class = Concrete; Abstract's no-arg constructor called. 
2: Class = Concrete; Abstract's 1-arg constructor called. 
3: Class = Concrete; Concrete's init block called. 
4: Class = Concrete; Concrete's 1-arg constructor called. 
0

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

public Abstract() { 
    this(null); 
} 
public Abstract(String arg) { 
    // do all Abstract init here 
} 

public Concrete() { 
    this(null); 
} 
public Concrete(String arg) { 
    super(arg); 
    // do all Concrete init here 
} 
1

Вот post, которые сосредоточены на том, что необходимость в абстрактном классе и как он works.May это поможет вам.

1

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

Смежные вопросы