Java-инициализация переменных суперкласса в подклассах?

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

код:

public abstract class Vehicle {
    static int wheels; //number of wheels on the vehicle
}

но ниже не работает:

public class Motorcycle extends Vehicle {
    wheels = 2;
}

есть ли способ сделать это эффективно?

изменить: Спасибо всем, кто ответил до сих пор. Я понимаю, что создание экземпляров, вероятно, лучший способ пойти, чем поместить их все в отдельные классы, но я не получаю "статическую" часть java отлично, поэтому мне нужна небольшая помощь здесь.

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

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

public abstract class Vehicle {
//Other coding
}

public class Motorcycle extends Vehicle {
static BufferedImage sprite = //initialize image
//Other coding
}

public class Truck extends Vehicle {
static BufferedImage sprite = //initialize image
//Other coding
}

7 ответов


Если "колеса" статические, есть только один, и он будет применяться ко всем транспортным средствам одновременно. Таким образом, трицикл, мотоцикл, 18-колесный грузовик и Ford будут иметь одинаковое количество колес.

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

но вы можете попробовать

Vehicle.wheels = 2;

примечание: Я добавляю к своему ответу, так как вы добавили к своему вопрос.

мне нравится ваша идея иметь статику в каждом из подклассов. Но вы должны сделать их частными. Затем поместите абстрактный метод в родительский класс (транспортное средство), например

public abstract BufferedImage getSprite();

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

сделайте переменную статической, поэтому вам нужно загрузить их только один раз. Сделайте их частными, чтобы код вне самого класса не мог обманывать его и вводить ошибки. Ты мог бы ... сделайте их "окончательными", если это возможно, чтобы код в самом классе не мог изменить его после факта и ввести ошибки. ("Конечная" переменная не может иметь измененного значения, но содержимое ее значения может измениться. Так что "финал" - это не так замечательно, как могло бы быть.)


то, что вы пытаетесь сделать, имеет фундаментальные недостатки. Вы мог бы сделать Motorcycle инициализации wheels после:

// Static initializer
static
{
    wheels = 2;
}

... или каждый раз, когда был создан экземпляр:

// Instance initializer
{
    wheels = 2;
}

но есть просто одной переменной - не Motorcycle, для Truck etc. Если вы сделали то же самое как Truck и Motorcycle, то, что инициализируется последним, будет "win".

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


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

public abstract class Vehicle {
    private int _wheels; //number of wheels on the vehicle
    public int getWheels(){return _wheels;}

    protected Vehicle(int wheels){
        _wheels = wheels;
    }
}

public class Motorcycle extends Vehicle {
    public Motorcycle(){
        super(2);
    }
}

public class Car extends Vehicle {
    public Car(){
        super(4);
    }
}

Я думаю, что есть гораздо более элегантный способ сделать это

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

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

то, что вам нужно, это пользовательская аннотация, как это:

@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface VehicleMetadata{
    int wheels();
}

затем вы аннотируете Motorcyle следующим образом:

@VehicleMetadata(2)
public class Motorcycle extends Vehicle {}

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

обратите внимание на использование this чтобы получить экземпляр:

private String wheelsValue;

public String getWheels() {
    if (this.wheelsValue== null) {

        VehicleMetadatane = null;
        for (Annotation annotation : this.getClass().getAnnotations()) {
            if (annotation instanceof VehicleMetadata) {
                ne = (VehicleMetadata) annotation;
                break;
            }
        }

        wheelsValue = ne.wheels();
    }
    return wheelsValue ;
}

на мой взгляд, это самое изящное решение.


оригинальное объявление класса:

public abstract class Vehicle {
    static int wheels; //number of wheels on the vehicle
}

public class Motorcycle extends Vehicle{...}
public class Truck extends Vehicle{...}

не работает, потому что статическая переменная идет с классом, в котором она была объявлена. Статические переменные класса создают память только для одного экземпляра переменной для каждого класса, а не для каждого объекта класса. Когда компилятор (jvm) видит статическую переменную в транспортном средстве класса, он выделяет память этой переменной, и это местоположение памяти является статическим (не изменяется). Каждое последующее использование класса транспортного средства, независимо от того, является ли оно расширенным или экземпляр как объект будет указывать на то же место в памяти для статической переменной.

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

class Motorcycle extends Vehicle{
    public Motorcycle(){
        wheels = 2;
    }
}

и он будет компилироваться, однако, вы можете не получить результаты, которые вы ожидаете. Например, если вы делаете это в своем коде (предполагая, что класс грузовика объявлен как класс мотоцикла и назначает 4 колесам и есть метод getter для возврата значения колес).

Motorcycle cycle = new Motorcycle();
Truck pickup = new Truck();
...
System.out.println("Motorcycle has " + cycle.getWheels() + " wheels.");

выведет:

мотоцикл имеет 4 колеса.


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

public Vehicle(int wheels) {
    this.wheels = wheels; 
}

public Motorcycle(int wheels) {
    super(wheels);
}

public Motorcycle cycle = new Motorcycle(2);

Мотоцикл использует супер конструктор, который знает, что делать с параметром. Он автоматически устанавливает колеса 2.


Если вы сделаете статическую переменную в своих объектах, она будет одинаковой для каждого класса транспортного средства, который вы сделаете, даже если вы сделаете другой подкласс для своего абстрактного класса транспортного средства. Это из-за "природы" любой статической переменной.

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

public abstract class Vehicle {
    public int wheels; //number of wheels on the vehicle
}

и любой подкласс:

public foo extends Vehicle{

     public void someMethode(){
         this.wheels = 2;
     }
}

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

надеюсь, я помог вам