Java: конструкторы абстрактных классов и this () - PullRequest
0 голосов
/ 07 декабря 2009

Может кто-нибудь указать, что я неправильно понимаю?

У меня есть два класса, абстрактный и конкретный, следующим образом:

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) Класс = Бетон; Аннотация без аргументов конструктор называется.
2) Класс = Бетон; 1-аргументный конструктор тезисов называется.
3) Класс = Бетон; 1-arg конструктор бетона называется.

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

Ответы [ 5 ]

7 голосов
/ 07 декабря 2009

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

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

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

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

1 голос
/ 30 апреля 2013

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

1 голос
/ 25 августа 2011

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

1 голос
/ 07 декабря 2009

Это просто так (как подробно описал Джон Скит).

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

{
  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 голосов
/ 07 декабря 2009

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

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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...