Принудительное снижение

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

Это то, что у меня есть.

public class Ticket{
   public int number;
   public String description;
}

public class MyTicket extends Ticket{
   public String status;
}

Но в моем приложении я хочу использовать класс MyTicket, потому что я не хочу принудительно изменять исходный объект Ticket. Поэтому, когда объект Ticket возвращается из вызова (веб-сервис, БД и т. Д.), Я пытаюсь перейти на MyTicket, и он, очевидно, дает сбой.

MyTicket mt=(MyTicket)ws.getTicket(1234);

Поэтому я пытался обойти это. Я думал о том, чтобы написать метод "copyAttributes" или скопировать атрибуты в конструкторе класса MyTicket, что-то вроде этого:

MyTicket mt=new MyTicket(ws.getTicket(1234));

public class MyTicket extends Ticket {
    public String status;
    public MyTicket(Ticket tckt){
        //copy tckt attributes to MyTicket attributes
    }
}

Есть ли способ получить атрибуты класса и установить их в другой класс? Или есть совершенно другой способ уныния, и я скучаю по нему?

*РЕШЕНИЕ:* Итак, я взял решение ниже и придумал это. Мне нужно было изменить нулевое значение, если основной билет не найден до того, как произойдет перевод:

public class MyTicket extends Ticket {
    public String status;
    public MyTicket(){}
    public static MyTicket newInstance(Ticket tckt){
        MyTicket mytkt=null;
        if(tckt!=null){//copy tckt attributes to MyTicket attributes
            BeanUtilsBean.getInstance().getConvertUtils().register(false,true,-1);
            mytkt = new MyTicket();
            BeanUtils.copyProperties(mytkt, tckt);
        }
        return mytkt;
    }
}

7 ответов

Решение

Я думаю, что вы делаете правильно. Если ваш объект растет, вы можете использовать Apache BeanUtils чтобы помочь вам в копировании.

Даункастинг следует использовать только тогда, когда вы знаете, что ссылка на самом деле относится к типу подкласса. Похоже, что объект Ticket, возвращаемый веб-сервисом, на самом деле не является MyTicket, и, следовательно, переход на более раннюю версию ClassCastException во время выполнения.

Переходя к использованию Ticket, возвращаемого веб-службой при создании MyTicket, я бы определил конструктор копирования в классе Ticket, который будет принимать объект билета и копировать атрибуты. Этот конструктор копирования будет вызываться в конструкторе MyTicket, который принимает объект Ticket.

public class Ticket{
   public int number;
   public String description;

   public Ticket(Ticket ticket)
   {
       this.number = ticket.number;
       this.description = ticket.description;
   }
}

public class MyTicket extends Ticket{
   public String status;

   public MyTicket(Ticket ticket)
   {
       super(ticket);
   }

   public MyTicket(Ticket ticket, String status)
   {
       super(ticket);
       this.status = status;
   }
}

Почему бы просто не использовать агрегацию + геттеры / сеттеры в этом случае?

public class MyTicket {
  private Ticket ticket;
  private String status;

  public MyTicket(Ticket ticket) {
    this.ticket = ticket;
  }

  public int getNumber() { return ticket.number; }
  public void setNumber(int number) { ticket.number = number; }
  public String getDescription { return ticket.description; }
  public void setDescription { ticket.description = description; }
  public String getStatus() { return status; }
  public void setStatus(String status) { this.status = status; }
}

Затем вы можете создать свой объект так же, как вы предложили:

MyTicket mt = new MyTicket(ws.getTicket(1234));

Самый хороший способ, с наименее избыточным кодом, был бы для вашего MyTicket содержать оригинал Ticket экземпляр (агрегация) и использовать его атрибуты, где это необходимо, без предварительного копирования.

public class MyTicket extends Ticket {
  private final Ticket t;
  public MyTicket(Ticket t) {
    this.t = t;
  }
}

Если вам нужно выставить все свойства через геттеры, то это не будет иметь большого значения. Это только поможет, если вам нужно TicketВнутренние свойства для некоторых расчетов.

Наследование:

public class ThisIsASubClass extends ThisIsASuperClass{
{
    //declare stuff here
    Object o = "Let's presume a string is passed";
    super(o); //runs the super class (ThisIsASuperClass in this case), sending an object if needed (effectivly running the super class inside of the subclass)
    //put the subclass code here
 }

Хороший пример, который я нашел (он длинный, но у меня нет проблем с чтением длинных вещей. Если вы программист, вам тоже не следует.):

Вот пример кода для возможной реализации класса Bicycle, который был представлен на уроке Classes and Objects:

public class Bicycle {

// the Bicycle class has
// three fields
public int cadence;
public int gear;
public int speed;

// the Bicycle class has
// one constructor
public Bicycle(int startCadence, int startSpeed, int startGear) {
    gear = startGear;
    cadence = startCadence;
    speed = startSpeed;
}

// the Bicycle class has
// four methods
public void setCadence(int newValue) {
    cadence = newValue;
}

public void setGear(int newValue) {
    gear = newValue;
}

public void applyBrake(int decrement) {
    speed -= decrement;
}

public void speedUp(int increment) {
    speed += increment;
}

}

Объявление класса для класса MountainBike, который является подклассом Bicycle, может выглядеть следующим образом:

public class MountainBike extends Bicycle {

    // the MountainBike subclass adds
    // one field
    public int seatHeight;

    // the MountainBike subclass has one
    // constructor
    public MountainBike(int startHeight,
                    int startCadence,
                    int startSpeed,
                    int startGear) {
    super(startCadence, startSpeed, startGear);
    seatHeight = startHeight;
}   

// the MountainBike subclass adds
// one method
public void setHeight(int newValue) {
    seatHeight = newValue;
}   
}

MountainBike наследует все поля и методы Bicycle и добавляет поле seatHeight и метод для его установки. За исключением конструктора, вы как будто написали новый класс MountainBike с нуля, с четырьмя полями и пятью методами. Тем не менее, вам не нужно было делать всю работу. Это было бы особенно ценно, если бы методы в классе Bicycle были сложными и требовали значительного времени для отладки. Что вы можете сделать в подклассе

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

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

Следующие разделы этого урока будут расширены по этим темам. Частные Члены в Суперклассе

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

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

Мы видели, что объект относится к типу данных класса, из которого он был создан. Например, если мы напишем

public MountainBike myBike = new MountainBike();

тогда myBike имеет тип MountainBike.

MountainBike происходит от Bicycle and Object. Поэтому MountainBike - это Bicycle, а также Object, и его можно использовать везде, где требуются объекты Bicycle или Object.

Обратное не обязательно верно: велосипед может быть MountainBike, но это не обязательно. Точно так же Объект может быть Велосипедом или Горным Велосипедом, но это не обязательно.

Приведение показывает использование объекта одного типа вместо другого типа среди объектов, разрешенных наследованием и реализациями. Например, если мы напишем

Object obj = new MountainBike();

тогда obj является и объектом, и горным велосипедом (до тех пор, пока obj не будет назначен другой объект, который не является горным велосипедом). Это называется неявным приведением.

Если, с другой стороны, мы пишем

MountainBike myBike = obj;

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

MountainBike myBike = (MountainBike)obj;

Это приведение вставляет проверку времени выполнения, что obj назначен MountainBike, так что компилятор может смело предполагать, что obj является MountainBike. Если obj не Mountainbike во время выполнения, будет сгенерировано исключение. Примечание. Вы можете выполнить логический тест на тип определенного объекта, используя оператор instanceof. Это может спасти вас от ошибки во время выполнения из-за неправильного приведения. Например:

if (obj instanceof MountainBike) {
    MountainBike myBike = (MountainBike)obj;
}

Здесь оператор instanceof проверяет, что obj ссылается на MountainBike, чтобы мы могли выполнить приведение со знанием того, что не будет выброшено исключение во время выполнения.

TL; DR: если вы используете наследование, любой квадрат является прямоугольником, но не все прямоугольники являются квадратами.

http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html

Если возвращаемый вами объект был создан как объект Ticket, а не как MyTicket, я бы подошел к нему так, как вы предложили с помощью конструктора копирования.

Я бы посоветовал вам реализовать что-то вроде интерфейса Cloneable (но не стандартного Java, здесь было бы неплохо предоставить абстрактный метод в вашем суперклассе). Примерно так в классе MyTicket:

@Override
public Ticket clone() {
    // copying stuff by calling a "copy constructor"
    return new MyTicket(this);
}

private MyTicket(MyTicket t) {
}
Другие вопросы по тегам