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;
}
}
вы также можете сделать это для статической переменной, но затем вы измените ее для каждого экземпляра любого подкласса транспортного средства
надеюсь, я помог вам