ArrayList перечислений с пользовательским атрибутом - PullRequest
0 голосов
/ 13 января 2019

У меня есть класс enum, который описывает возможные типы билетов и имеет собственный атрибут для сохранения ticketId. Когда я пытаюсь добавить несколько билетов в ArrayList, все билеты типа X имеют один и тот же ticketId. Почему это так и что важнее, как я могу это решить?

Упрощенный перечислимый класс:

public enum Ticket {
    FirstClass(0),
    PremiumClass(1),
    EconomyClass(2);

    private int elementId;
    private Long ticketId;

    Ticket(int elementId) {
        this.elementId=elementId;
    }

    public Long getTicketId() {
        return ticketId;
    }

    public void setTicketId(Long ticketId) {
        this.ticketId = ticketId;
    }
}

Упрощенный метод:

public void myMethod() {
    ArrayList<Ticket> tickets = new ArrayList<>();
    Ticket ticket = Ticket.FirstClass;
    ticket.setTicketId(1L);
    tickets.add(ticket);
    ticket = Ticket.FirstClass;
    ticket.setTicketId(2L);
    tickets.add(ticket);
}

Ответы [ 6 ]

0 голосов
/ 13 января 2019

Каждое значение enum (у вас есть три) существует только один раз, и каждый раз, когда вы используете одно из них, вы просто повторно используете одно из этих трех значений, создавая ссылку, копий нет.

Это означает, что если вы измените ticketId на значение FirstClass, оно будет изменено везде, где указано это значение.

Кажется, вы хотите смоделировать небольшую систему билетов. Каждый объект, имеющий собственную идентичность, должен быть смоделирован как class, который имеет свойство для типа и идентификатора:

public class Ticket {
    private Long ticketId;
    private TicketType type;

    public Long getTicketId() {
        return ticketId;
    }

    public void setTicketId(Long ticketId) {
        this.ticketId = ticketId;
    }

    public TicketType getType() {
        return type;
    }

    public void setType(TicketType type) {
        this.type = type;
    }
}

public enum TicketType {
    FirstClass(0),
    PremiumClass(1),
    EconomyClass(2);

    private final int elementId;

    Ticket(int elementId) {
        this.elementId = elementId;
    }

    public int getElementId() {
        return elementId;
    }
}

Тогда вы можете использовать это следующим образом:

public void myMethod() {
    ArrayList<Ticket> tickets = new ArrayList<>();
    Ticket ticket = new Ticket();
    ticket.setType(TicketType.FirstClass);
    ticket.setTicketId(1L);
    tickets.add(ticket);

    ticket = new Ticket();
    ticket.setType(TicketType.FirstClass);
    ticket.setTicketId(2L);
    tickets.add(ticket);
}

Я не знаю, зачем вам нужен elementId для типа билета, поэтому я просто оставил его там (не используя). Возможно, вам следует переименовать ticketId в id, чтобы все было просто.

Если type или ticketId заявки никогда не меняются после их назначения, вы можете удалить сеттеры и присвоить значения в конструкторе Ticket (и сделать атрибуты final).

Даже если это нормально, что они изменяемы, вы можете ввести такой конструктор, чтобы иметь код, который лучше читается:

In Ticket.java:

public Ticket(Long ticketId, TicketType type) {
    this.ticketId = ticketId;
    this.type = type;
}

Тогда вы можете написать:

tickets.add(new Ticket(1L, TicketType.FirstClass));

Если тикет является персистентной сущностью (которая проверяется фреймворком, таким как Hibernate), вам, возможно, придется оставить конструктор без аргументов, чтобы сделать его инстанцируемым при загрузке из базы данных.

0 голосов
/ 13 января 2019

Ничего не отличается от других ответов, просто добавить несколько цветов. Reference in list Когда вы получаете firstClass, вы фактически получаете тот же объект и добавляете его снова.

0 голосов
/ 13 января 2019

FirstClass является экземпляром Ticket, поэтому, когда вы вызываете его, он всегда один и тот же, вы берете ссылку на один и тот же объект.

Вам понадобится модель с Ticket и TicketType

enum TicketType {
    FirstClass,
    PremiumClass,
    EconomyClass
}

class Ticket {
    private TicketType type;
    private Long ticketId;

    Ticket(TicketType type, long ticketId) {
        this.type = type;
        this.ticketId = ticketId;
    }
}
// ---------------------------------------------------------
// And
public void myMethod() {
    ArrayList<Ticket> tickets = new ArrayList<>();

    Ticket ticket = new Ticket(TicketType.FirstClass, 1L);
    tickets.add(ticket);

    ticket = new Ticket(TicketType.FirstClass, 2L);
    tickets.add(ticket);
}
0 голосов
/ 13 января 2019

Не используйте перечисления для динамических значений, см. поля сонара "enum" не должны быть публично изменяемыми

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

См. пример о том, как сделать enum динамическим, реализуя интерфейс

0 голосов
/ 13 января 2019

В действительности существует только один экземпляр Ticket.FirstClass, и будет только один экземпляр.

То, что у вас действительно есть, это не Ticket, а TicketType. У вас должен быть отдельный класс для Ticket.

0 голосов
/ 13 января 2019

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

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