В Java, почему я не могу объявить последний элемент (без его инициализации) в родительском классе и установить его значение в подклассе? Как я могу обойти? - PullRequest
10 голосов
/ 19 марта 2009

В программе на Java у меня есть несколько подклассов, наследующих от родителя (который является абстрактным). Я хотел выразить, что у каждого ребенка должен быть элемент, который устанавливается только один раз (что я планировал сделать из конструктора). Мой план состоял в том, чтобы кодировать s.th. как это:

public abstract class Parent {
    protected final String birthmark;
}

public class Child extends Parent {
    public Child(String s) {
        this.birthmark = s;
    }
}

Однако это, похоже, не радует богов Java. В родительском классе я получаю сообщение, что birthmark «возможно, не инициализирован», в дочернем классе я получаю «Последнее поле birthmark не доступно».

Так каков Java-способ для этого? Чего мне не хватает?

Ответы [ 8 ]

19 голосов
/ 19 марта 2009

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

public abstract class Parent {
    protected final String birthmark;
    protected Parent(String s) {
        birthmark = s;
    }
}

public class Child extends Parent {
    public Child(String s) {
        super(s);
        ...
    }
}
7 голосов
/ 19 марта 2009

Передайте его родительскому конструктору:

public abstract class Parent {
    private final String birthmark;
    public Parent(String s) {
        birthmark = s;
    }
}

public class Child extends Parent {
    public Child(String s) {
        super(s);
    }
}
2 голосов
/ 19 марта 2009

Я бы сделал это так:

public abstract class Parent 
{
    protected final String birthmark;

    protected Parent(final String mark)
    {
        // only if this makes sense.
        if(mark == null)
        {
            throw new IllegalArgumentException("mark cannot be null");
        }

        birthmark = mark;
    }
}

public class Child 
    extends Parent 
{
    public Child(final String s) 
    {
        super(s);
    }
}

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

Я добавил проверку на null, чтобы показать, что вы также получаете возможность проверять аргументы в одном месте, а не в каждом конструкторе.

2 голосов
/ 19 марта 2009

Другой способ сделать это на Java - это, вероятно, иметь родительский класс для определения абстрактного «получателя», а потомки его реализовать. Это не лучший способ сделать это в этом случае, но в некоторых случаях это может быть именно то, что вы хотите.

1 голос
/ 19 марта 2009

Почему бы не делегировать инициализацию методу. Затем переопределите метод в родительском классе.

public class Parent {
   public final Object x = getValueOfX();
   public Object getValueOfX() {
      return y;
   }
}
public class Child {
  @Override
  public Object getValueOfX() {
     // whatever ...
  }
}

Это должно позволить пользовательскую инициализацию.

0 голосов
/ 19 марта 2009

Возможно, вы захотите иметь конструктор Parent (String Birthmark), чтобы вы могли убедиться, что в вашем классе Parent всегда инициализируется final. Затем вы можете вызвать super (родимое пятно) из вашего конструктора Child ().

0 голосов
/ 19 марта 2009

Объявите конструктор в суперклассе, который вызывается подклассом. Вы должны установить поле в суперклассе, чтобы убедиться, что оно инициализировано, иначе компилятор не может быть уверен, что поле инициализировано.

0 голосов
/ 19 марта 2009

Да, финальные члены должны быть назначены в классе, в котором они объявлены. Вам нужно добавить конструктор с аргументом String в Parent.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...