Ánh xạ thuận tiện giữa enum và int / String


108

Khi làm việc với các biến / tham số chỉ có thể nhận một số giá trị hữu hạn, tôi cố gắng luôn sử dụng Java enum, như trong

public enum BonusType {
  MONTHLY, YEARLY, ONE_OFF
}

Miễn là tôi ở trong mã của mình, điều đó sẽ hoạt động tốt. Tuy nhiên, tôi thường cần giao tiếp với mã khác sử dụng các giá trị thuần túy int(hoặc String) cho cùng một mục đích hoặc tôi cần đọc / ghi từ / tới cơ sở dữ liệu nơi dữ liệu được lưu trữ dưới dạng số hoặc chuỗi.

Trong trường hợp đó, tôi muốn có một cách thuận tiện để liên kết mỗi giá trị enum với một số nguyên, để tôi có thể chuyển đổi cả hai cách (nói cách khác, tôi cần một "enum có thể đảo ngược").

Chuyển từ enum sang int rất dễ dàng:

public enum BonusType {
  public final int id;

  BonusType(int id) {
    this.id = id;
  }
  MONTHLY(1), YEARLY(2), ONE_OFF(3);
}

Sau đó, tôi có thể truy cập giá trị int dưới dạng BonusType x = MONTHLY; int id = x.id;.

Tuy nhiên, tôi thấy không có cách nào hay cho việc ngược lại, tức là đi từ int sang enum. Lý tưởng nhất là một cái gì đó như

BonusType bt = BonusType.getById(2); 

Các giải pháp duy nhất tôi có thể đưa ra là:

  • Đặt một phương thức tra cứu vào enum, sử dụng BonusType.values() để điền vào bản đồ "int -> enum", sau đó lưu vào bộ nhớ cache và sử dụng nó để tra cứu. Sẽ hoạt động, nhưng tôi phải sao chép phương thức này giống hệt nhau vào mỗi enum tôi sử dụng :-(.
  • Đặt phương thức tra cứu vào một lớp tiện ích tĩnh. Sau đó, tôi chỉ cần một phương thức "tra cứu", nhưng tôi sẽ phải tìm hiểu phản chiếu để làm cho nó hoạt động cho một enum tùy ý.

Cả hai phương pháp đều có vẻ rất khó xử cho một vấn đề (?) Đơn giản như vậy.

Bất kỳ ý tưởng / hiểu biết nào khác?


1
Tôi <3 java enums nhưng ghét chúng vì lý do này chính xác! Nó luôn luôn có vẻ như họ đang hoàn hảo dành từ một lỗ hổng thực sự xấu xí ...
Chris Thompson

8
cho enum-> int bạn có thể chỉ cần sử dụngordinal()
davin

1
Giá trị id của bạn có do bạn quyết định (nghĩa là bạn không thể chỉ sử dụng .ordinal()) hay do các thế lực bên ngoài quyết định?
Paŭlo Ebermann

2
@davin: Có, và mã của bạn bị hỏng khi ai đó sắp xếp lại khai báo enum hoặc xóa một giá trị ở giữa. Tôi e rằng đó không phải là một giải pháp mạnh: - /.
sleske

1
@davin sử dụng "ordinal ()" nên tránh bất cứ khi nào có thể, nó nằm trong thông số của ngôn ngữ
DPM

Câu trả lời:


37

http://www.javaspecialists.co.za/archive/Issue113.html

Giải pháp bắt đầu tương tự như giải pháp của bạn với giá trị int như một phần của định nghĩa enum. Sau đó, anh ấy tiếp tục tạo ra một tiện ích tra cứu dựa trên generic:

public class ReverseEnumMap<V extends Enum<V> & EnumConverter> {
    private Map<Byte, V> map = new HashMap<Byte, V>();
    public ReverseEnumMap(Class<V> valueType) {
        for (V v : valueType.getEnumConstants()) {
            map.put(v.convert(), v);
        }
    }

    public V get(byte num) {
        return map.get(num);
    }
}

Giải pháp này rất hay và không yêu cầu 'loay hoay với sự phản chiếu' vì nó dựa trên thực tế là tất cả các kiểu enum đều kế thừa một cách ngầm định giao diện Enum.


Điều này không sử dụng thứ tự? Sleske sử dụng một id chỉ vì thứ tự thay đổi khi các giá trị enum được sắp xếp lại.
extraneon

Không, nó không sử dụng thứ tự. Nó dựa trên một giá trị int được xác định rõ ràng. Giá trị int đó được sử dụng làm khóa bản đồ (được trả về bởi v.convert ()).
Jeff

2
Tôi thực sự thích giải pháp này; có vẻ như đây là cái chung nhất mà bạn có thể nhận được.
sleske

+1. Lưu ý duy nhất của tôi là tôi muốn sử dụng Numberthay vì Byte, vì giá trị hỗ trợ của tôi có thể có kích thước lớn hơn.
Ivaylo Slavov

3
Thực sự và thực sự đọc câu hỏi. Nếu bạn đang xử lý cơ sở dữ liệu kế thừa hoặc hệ thống bên ngoài đã xác định các số nguyên mà bạn không muốn phổ biến thông qua mã của riêng mình, thì đây chính xác là một trong những trường hợp đó. Thứ tự là một cách cực kỳ mong manh để duy trì giá trị của một enum, và hơn thế nữa, nó vô dụng trong trường hợp cụ thể được đề cập trong câu hỏi.
Jeff

327

enum → int

yourEnum.ordinal()

int → enum

EnumType.values()[someInt]

Chuỗi → enum

EnumType.valueOf(yourString)

enum → Chuỗi

yourEnum.name()

Một lưu ý phụ:
Như bạn đã chỉ ra một cách chính xác, ordinal()có thể là "không ổn định" giữa các phiên bản. Đây là lý do chính xác tại sao tôi luôn lưu trữ hằng số dưới dạng chuỗi trong cơ sở dữ liệu của mình. (Trên thực tế, khi sử dụng MySql, tôi lưu trữ chúng dưới dạng MySql enums !)


2
+1 Đây là câu trả lời chính xác rõ ràng. Lưu ý tuy nhiên, có một phương pháp luận duy nhất cho valueOf mà chỉ mất một String và tồn tại miễn là bạn đang sử dụng loại bê tông enum (ví dụ BonusType.valueOf("MONTHLY"))
Tim Bender

18
Sử dụng theo ordinal()tôi là một giải pháp có vấn đề, vì nó sẽ bị hỏng khi danh sách các giá trị enum được sắp xếp lại hoặc một giá trị bị xóa. Ngoài ra, điều này chỉ thực tế nếu các giá trị int là 0 ... n (mà tôi thường thấy không đúng như vậy).
sleske

4
@sleske, nếu bạn bắt đầu xóa các hằng số, bạn vẫn gặp rắc rối với dữ liệu liên tục hiện có. (Đã cập nhật câu trả lời của tôi về vấn đề này.)
aioobe

3
Sử dụng values()mảng sẽ chỉ hoạt động nếu tất cả các giá trị của bạn là 0 được lập chỉ mục cho id của chúng và được khai báo theo thứ tự. (Tôi đã thử nghiệm này để xác minh rằng nếu bạn khai báo FOO(0), BAR(2), BAZ(1);rằng values[1] == BARvalues[2] == BAZmặc dù id thông qua vào.)
corsiKa

2
@glowcoder, tất nhiên, đối số số nguyên chỉ là một trường trong đối tượng enum. Nó không liên quan gì đến hằng số thứ tự được liên kết với đối tượng enum (nó cũng có thể là a double).
aioobe

29

Tôi tìm thấy điều này trên web, nó rất hữu ích và đơn giản để thực hiện. Giải pháp này KHÔNG phải do tôi thực hiện

http://www.ajaxonomy.com/2007/java/making-the-most-of-java-50-enum-tricks

public enum Status {
 WAITING(0),
 READY(1),
 SKIPPED(-1),
 COMPLETED(5);

 private static final Map<Integer,Status> lookup 
      = new HashMap<Integer,Status>();

 static {
      for(Status s : EnumSet.allOf(Status.class))
           lookup.put(s.getCode(), s);
 }

 private int code;

 private Status(int code) {
      this.code = code;
 }

 public int getCode() { return code; }

 public static Status get(int code) { 
      return lookup.get(code); 
 }

}


s / EnumSet.allOf (Status.class) /Status.values ​​()
jelinson

8

Có vẻ như (các) câu trả lời cho câu hỏi này đã lỗi thời với việc phát hành Java 8.

  1. Không sử dụng thứ tự vì thứ tự không ổn định nếu vẫn tồn tại bên ngoài JVM chẳng hạn như cơ sở dữ liệu.
  2. Tương đối dễ dàng để tạo một bản đồ tĩnh với các giá trị chính.

public enum AccessLevel {
  PRIVATE("private", 0),
  PUBLIC("public", 1),
  DEFAULT("default", 2);

  AccessLevel(final String name, final int value) {
    this.name = name;
    this.value = value;
  }

  private final String name;
  private final int value;

  public String getName() {
    return name;
  }

  public int getValue() {
    return value;
  }

  static final Map<String, AccessLevel> names = Arrays.stream(AccessLevel.values())
      .collect(Collectors.toMap(AccessLevel::getName, Function.identity()));
  static final Map<Integer, AccessLevel> values = Arrays.stream(AccessLevel.values())
      .collect(Collectors.toMap(AccessLevel::getValue, Function.identity()));

  public static AccessLevel fromName(final String name) {
    return names.get(name);
  }

  public static AccessLevel fromValue(final int value) {
    return values.get(value);
  }
}

Tham số thứ hai không phải Collectors.toMap()Functions.identity()thay vì null?
Adam Michalik

vâng, tôi đã áp dụng điều này từ một lớp trợ giúp mà tôi sử dụng với ổi để chuyển null thành danh tính.
John Meyer

Đó là cách sử dụng gọn gàng các tính năng mới của Java 8. Tuy nhiên, nó vẫn có nghĩa là mã sẽ phải được lặp lại trong mọi enum - và câu hỏi của tôi là về việc tránh lặp lại (về mặt cấu trúc) này.
sleske

5

org.apache.commons.lang.enums.ValuedEnum;

Để tiết kiệm cho tôi việc viết vô số mã soạn sẵn hoặc mã trùng lặp cho mỗi Enum, tôi đã sử dụng Apache Commons Lang's ValuedEnumđể thay thế.

Định nghĩa :

public class NRPEPacketType extends ValuedEnum {    
    public static final NRPEPacketType TYPE_QUERY = new NRPEPacketType( "TYPE_QUERY", 1);
    public static final NRPEPacketType TYPE_RESPONSE = new NRPEPacketType( "TYPE_RESPONSE", 2);

    protected NRPEPacketType(String name, int value) {
        super(name, value);
    }
}

Sử dụng:

int -> ValuedEnum:

NRPEPacketType packetType = 
 (NRPEPacketType) EnumUtils.getEnum(NRPEPacketType.class, 1);

Ý tưởng hay, tôi đã không nhận ra rằng điều này tồn tại. Cám ơn vì đã chia sẻ!
Keith P

3

Bạn có thể sử dụng một cái gì đó như

interface EnumWithId {
    public int getId();

}


enum Foo implements EnumWithId {

   ...
}

Điều đó sẽ làm giảm nhu cầu phản chiếu trong lớp tiện ích của bạn.


Bạn có thể cho một ví dụ về cách sử dụng đoạn mã này không?
IgorGanapolsky

3

Trong mã này, để tìm kiếm thường xuyên và cường độ cao, có bộ nhớ hoặc quy trình để sử dụng, và tôi chọn bộ nhớ, với mảng chuyển đổi làm chỉ mục. Tôi hy vọng nó hữu ích

public enum Test{ 
VALUE_ONE(101, "Im value one"),
VALUE_TWO(215, "Im value two");
private final int number;
private final byte[] desc;

private final static int[] converter = new int[216];
static{
    Test[] st = values();
    for(int i=0;i<st.length;i++){
        cv[st[i].number]=i;
    }
}

Test(int value, byte[] description) {
    this.number = value;
    this.desc = description;
}   
public int value() {
    return this.number;
}
public byte[] description(){
    return this.desc;
}

public static String description(int value) {
    return values()[converter[rps]].desc;
}

public static Test fromValue(int value){
return values()[converter[rps]];
}
}

2

Sử dụng một giao diện để hiển thị ai là sếp.

public interface SleskeEnum {
    int id();

    SleskeEnum[] getValues();

}

public enum BonusType implements SleskeEnum {


  MONTHLY(1), YEARLY(2), ONE_OFF(3);

  public final int id;

  BonusType(int id) {
    this.id = id;
  }

  public SleskeEnum[] getValues() {
    return values();
  }

  public int id() { return id; }


}

public class Utils {

  public static SleskeEnum getById(SleskeEnum type, int id) {
      for(SleskeEnum t : type.getValues())
          if(t.id() == id) return t;
      throw new IllegalArgumentException("BonusType does not accept id " + id);
  }

  public static void main(String[] args) {

      BonusType shouldBeMonthly = (BonusType)getById(BonusType.MONTHLY,1);
      System.out.println(shouldBeMonthly == BonusType.MONTHLY);

      BonusType shouldBeMonthly2 = (BonusType)getById(BonusType.MONTHLY,1);
      System.out.println(shouldBeMonthly2 == BonusType.YEARLY);

      BonusType shouldBeYearly = (BonusType)getById(BonusType.MONTHLY,2);
      System.out.println(shouldBeYearly  == BonusType.YEARLY);

      BonusType shouldBeOneOff = (BonusType)getById(BonusType.MONTHLY,3);
      System.out.println(shouldBeOneOff == BonusType.ONE_OFF);

      BonusType shouldException = (BonusType)getById(BonusType.MONTHLY,4);
  }
}

Và kết quả:

C:\Documents and Settings\user\My Documents>java Utils
true
false
true
true
Exception in thread "main" java.lang.IllegalArgumentException: BonusType does not accept id 4
        at Utils.getById(Utils.java:6)
        at Utils.main(Utils.java:23)

C:\Documents and Settings\user\My Documents>

1
Cũng giống như câu trả lời của Turd Ferguson, đó là giải pháp không phù hợp mà tôi muốn tránh / cải thiện ...
sleske

Tôi thường tạo các ánh xạ ngược trong khối {} tĩnh để không phải lặp qua các giá trị () mỗi khi tôi yêu cầu một giá trị bằng id. Tôi cũng thường gọi phương thức valueOf (int) để làm cho nó có vẻ giống phương thức valueOf (String) đã có cho Strings (cũng là một phần câu hỏi của OP). Hơi giống như mục 33 trong Java hiệu quả: tinyurl.com/4ffvc38
Fredrik

@Sleske Đã cập nhật với một giải pháp tinh tế hơn. @Fredrik thú vị, mặc dù tôi nghi ngờ việc lặp lại sẽ là một vấn đề quan trọng.
corsiKa

@glowcoder Chà, việc không phải lặp lại nhiều lần có nghĩa là không thành vấn đề nếu bạn làm việc đó hàng nghìn lần mỗi giây, nơi nó có thể là một vấn đề rất quan trọng hoặc chỉ cần gọi nó hai lần.
Fredrik

@Fredrik Tôi thừa nhận rằng có những lúc cần phải tối ưu hóa. Tôi cũng nói rằng cho đến khi đó là một vấn đề hiệu suất được xác định, đừng tối ưu hóa nó.
corsiKa

2

Cả hai .ordinal()values()[i]đều không ổn định vì chúng phụ thuộc vào thứ tự của enum. Vì vậy, nếu bạn thay đổi thứ tự của enums hoặc thêm / xóa một số chương trình của bạn sẽ bị hỏng.

Đây là một phương pháp đơn giản nhưng hiệu quả để ánh xạ giữa enum và int.

public enum Action {
    ROTATE_RIGHT(0), ROTATE_LEFT(1), RIGHT(2), LEFT(3), UP(4), DOWN(5);

    public final int id;
    Action(int id) {
        this.id = id;
    }

    public static Action get(int id){
        for (Action a: Action.values()) {
            if (a.id == id)
                return a;
        }
        throw new IllegalArgumentException("Invalid id");
    }
}

Áp dụng nó cho chuỗi không khó.


Vâng, tôi nhận ra rằng tôi có thể làm điều đó - hoặc thậm chí tốt hơn, sử dụng bản đồ để tra cứu ngược, thay vì lặp lại tất cả các giá trị. Tôi đã đề cập đến vấn đề này trong câu hỏi của mình và tôi cũng đã đề cập rằng tôi đang tìm kiếm một giải pháp tốt hơn, để tránh có mã viết sẵn trong mỗi enum.
sleske

2

Một ví dụ sử dụng rất rõ ràng của Enum đảo ngược

Bước 1 Xác định interfaceEnumConverter

public interface EnumConverter <E extends Enum<E> & EnumConverter<E>> {
    public String convert();
    E convert(String pKey);
}

Bước 2

Tạo tên lớp ReverseEnumMap

import java.util.HashMap;
import java.util.Map;

public class ReverseEnumMap<V extends Enum<V> & EnumConverter<V>> {
    private Map<String, V> map = new HashMap<String, V>();

    public ReverseEnumMap(Class<V> valueType) {
        for (V v : valueType.getEnumConstants()) {
            map.put(v.convert(), v);
        }
    }

    public V get(String pKey) {
        return map.get(pKey);
    }
}

Bước 3

Chuyển đến Enumlớp của bạn và implementnó với EnumConverter<ContentType>và tất nhiên là ghi đè các phương thức giao diện. Bạn cũng cần khởi tạo một ReverseEnumMap tĩnh.

public enum ContentType implements EnumConverter<ContentType> {
    VIDEO("Video"), GAME("Game"), TEST("Test"), IMAGE("Image");

    private static ReverseEnumMap<ContentType> map = new ReverseEnumMap<ContentType>(ContentType.class);

    private final String mName;

    ContentType(String pName) {
        this.mName = pName;
    }

    String value() {
        return this.mName;
    }

    @Override
    public String convert() {
        return this.mName;
    }

    @Override
    public ContentType convert(String pKey) {
        return map.get(pKey);
    }
}

Bước 4

Bây giờ, hãy tạo một Communicationtệp lớp và gọi nó là phương thức mới để chuyển đổi một Enumthành StringStringđến Enum. Tôi chỉ đặt phương pháp chính cho mục đích giải thích.

public class Communication<E extends Enum<E> & EnumConverter<E>> {
    private final E enumSample;

    public Communication(E enumSample) {
        this.enumSample = enumSample;
    }

    public String resolveEnumToStringValue(E e) {
        return e.convert();
    }

    public E resolveStringEnumConstant(String pName) {
        return enumSample.convert(pName);
    }

//Should not put main method here... just for explanation purpose. 
    public static void main(String... are) {
        Communication<ContentType> comm = new Communication<ContentType>(ContentType.GAME);
        comm.resolveEnumToStringValue(ContentType.GAME); //return Game
        comm.resolveStringEnumConstant("Game"); //return GAME (Enum)
    }
}

Bấm để xem giải thích đầy đủ


1
Điều này tôi thực sự rất thích - Tôi đã tìm kiếm một giải pháp vững chắc cho vấn đề này trong một thời gian. Thay đổi duy nhất mà tôi thực hiện là tạo ContentType convert(String pKey)tĩnh, loại bỏ nhu cầu về Communicationlớp và nhiều hơn theo ý thích của tôi. +1
Chris Mantle

1

Tôi không chắc liệu nó có giống trong Java hay không, nhưng các kiểu enum trong C cũng được tự động ánh xạ thành số nguyên nên bạn có thể sử dụng kiểu hoặc số nguyên để truy cập nó. Bạn đã thử truy cập đơn giản bằng số nguyên chưa?


2
Enums trong Java không hoạt động theo cách đó. Họ là một loại rõ ràng.
Chris Thompson

Mỗi đối tượng enum sẽ có một số bên trong (cụ thể là vị trí mà nó được khai báo) và nó có thể được truy cập bằng .ordinal()phương thức. (Cách khác, sử dụng BonusType.values()[i].) Nhưng trong ví dụ được trích dẫn ở trên, các chỉ mục ở đây và các giá trị bên ngoài không trùng nhau.
Paŭlo Ebermann

1

Câu hỏi thực sự tuyệt vời :-) Tôi đã sử dụng giải pháp tương tự như Mr.Ferguson`s cách đây một thời gian. Enum được dịch ngược của chúng ta trông như thế này:

final class BonusType extends Enum
{

    private BonusType(String s, int i, int id)
    {
        super(s, i);
        this.id = id;
    }

    public static BonusType[] values()
    {
        BonusType abonustype[];
        int i;
        BonusType abonustype1[];
        System.arraycopy(abonustype = ENUM$VALUES, 0, abonustype1 = new BonusType[i = abonustype.length], 0, i);
        return abonustype1;
    }

    public static BonusType valueOf(String s)
    {
        return (BonusType)Enum.valueOf(BonusType, s);
    }

    public static final BonusType MONTHLY;
    public static final BonusType YEARLY;
    public static final BonusType ONE_OFF;
    public final int id;
    private static final BonusType ENUM$VALUES[];

    static 
    {
        MONTHLY = new BonusType("MONTHLY", 0, 1);
        YEARLY = new BonusType("YEARLY", 1, 2);
        ONE_OFF = new BonusType("ONE_OFF", 2, 3);
        ENUM$VALUES = (new BonusType[] {
            MONTHLY, YEARLY, ONE_OFF
        });
    }
}

Nhìn thấy điều này là rõ tại sao ordinal()không ổn định. Nó là itrong super(s, i);. Tôi cũng bi quan rằng bạn có thể nghĩ ra một giải pháp thanh lịch hơn những giải pháp mà bạn đã liệt kê. Sau khi tất cả các enums là các lớp như bất kỳ lớp cuối cùng nào.


1

Vì lợi ích của sự đầy đủ, đây là một cách tiếp cận chung để truy xuất các giá trị enum theo chỉ mục từ bất kỳ loại enum nào. Ý định của tôi là làm cho phương thức trông giống như Enum.valueOf (Class, String) . Fyi, tôi đã sao chép phương pháp này từ đây .

Các vấn đề liên quan đến chỉ mục (đã được thảo luận sâu ở đây) vẫn được áp dụng.

/**
 * Returns the {@link Enum} instance for a given ordinal.
 * This method is the index based alternative
 * to {@link Enum#valueOf(Class, String)}, which
 * requires the name of an instance.
 * 
 * @param <E> the enum type
 * @param type the enum class object
 * @param ordinal the index of the enum instance
 * @throws IndexOutOfBoundsException if ordinal < 0 || ordinal >= enums.length
 * @return the enum instance with the given ordinal
 */
public static <E extends Enum<E>> E valueOf(Class<E> type, int ordinal) {
    Preconditions.checkNotNull(type, "Type");
    final E[] enums = type.getEnumConstants();
    Preconditions.checkElementIndex(ordinal, enums.length, "ordinal");
    return enums[ordinal];
}

Đó thực sự không phải là những gì tôi đang tìm kiếm, vì điều này chỉ truy xuất các giá trị enum theo thứ tự của chúng, không phải bởi một id số nguyên được chỉ định (xem câu hỏi của tôi). Ngoài ra, nếu tôi muốn điều đó, tôi có thể sử dụng MyEnumType.values()- không cần phương thức trợ giúp tĩnh.
sleske

0
Int -->String :

public enum Country {

    US("US",0),
    UK("UK",2),
    DE("DE",1);


    private static Map<Integer, String> domainToCountryMapping; 
    private String country;
    private int domain;

    private Country(String country,int domain){
        this.country=country.toUpperCase();
        this.domain=domain;
    }

    public String getCountry(){
        return country;
    }


    public static String getCountry(String domain) {
        if (domainToCountryMapping == null) {
            initMapping();
        }

        if(domainToCountryMapping.get(domain)!=null){
            return domainToCountryMapping.get(domain);
        }else{
            return "US";
        }

    }

     private static void initMapping() {
         domainToCountryMapping = new HashMap<Integer, String>();
            for (Country s : values()) {
                domainToCountryMapping.put(s.domain, s.country);
            }
        }

0

Tôi cần một cái gì đó khác biệt vì tôi muốn sử dụng một cách tiếp cận chung. Tôi đang đọc enum đến và từ mảng byte. Đây là nơi tôi nghĩ ra:

public interface EnumConverter {
    public Number convert();
}



public class ByteArrayConverter {
@SuppressWarnings("unchecked")
public static Enum<?> convertToEnum(byte[] values, Class<?> fieldType, NumberSystem numberSystem) throws InvalidDataException {
    if (values == null || values.length == 0) {
        final String message = "The values parameter must contain the value";
        throw new IllegalArgumentException(message);
    }

    if (!dtoFieldType.isEnum()) {
        final String message = "dtoFieldType must be an Enum.";
        throw new IllegalArgumentException(message);
    }

    if (!EnumConverter.class.isAssignableFrom(fieldType)) {
        final String message = "fieldType must implement the EnumConverter interface.";
        throw new IllegalArgumentException(message);
    }

    Enum<?> result = null;
    Integer enumValue = (Integer) convertToType(values, Integer.class, numberSystem); // Our enum's use Integer or Byte for the value field.

    for (Object enumConstant : fieldType.getEnumConstants()) {
        Number ev = ((EnumConverter) enumConstant).convert();

        if (enumValue.equals(ev)) {
            result = (Enum<?>) enumConstant;
            break;
        }
    }

    if (result == null) {
        throw new EnumConstantNotPresentException((Class<? extends Enum>) fieldType, enumValue.toString());
    }

    return result;
}

public static byte[] convertEnumToBytes(Enum<?> value, int requiredLength, NumberSystem numberSystem) throws InvalidDataException {
    if (!(value instanceof EnumConverter)) {
        final String message = "dtoFieldType must implement the EnumConverter interface.";
        throw new IllegalArgumentException(message);
    }

    Number enumValue = ((EnumConverter) value).convert();
    byte[] result = convertToBytes(enumValue, requiredLength, numberSystem);
    return result;
}

public static Object convertToType(byte[] values, Class<?> type, NumberSystem numberSystem) throws InvalidDataException {
    // some logic to convert the byte array supplied by the values param to an Object.
}

public static byte[] convertToBytes(Object value, int requiredLength, NumberSystem numberSystem) throws InvalidDataException {
    // some logic to convert the Object supplied by the'value' param to a byte array.
}
}

Ví dụ về enum's:

public enum EnumIntegerMock implements EnumConverter {
    VALUE0(0), VALUE1(1), VALUE2(2);

    private final int value;

    private EnumIntegerMock(int value) {
        this.value = value;
    }

public Integer convert() {
    return value;
}

}

public enum EnumByteMock implements EnumConverter {
    VALUE0(0), VALUE1(1), VALUE2(2);

    private final byte value;

    private EnumByteMock(int value) {
        this.value = (byte) value;
    }

    public Byte convert() {
        return value;
    }
}

0

Chỉ vì câu trả lời được chấp nhận là không có:

Mã hỗ trợ:

public interface EnumWithCode<E extends Enum<E> & EnumWithCode<E>> {

    public Integer getCode();

    E fromCode(Integer code);
}


public class EnumWithCodeMap<V extends Enum<V> & EnumWithCode<V>> {

    private final HashMap<Integer, V> _map = new HashMap<Integer, V>();

    public EnumWithCodeMap(Class<V> valueType) {
        for( V v : valueType.getEnumConstants() )
            _map.put(v.getCode(), v);
    }

    public V get(Integer num) {
        return _map.get(num);
    }
}

Ví dụ sử dụng:

public enum State implements EnumWithCode<State> {
    NOT_STARTED(0), STARTED(1), ENDED(2);

    private static final EnumWithCodeMap<State> map = new EnumWithCodeMap<State>(
            State.class);

    private final int code;

    private State(int code) {
        this.code = code;
    }

    @Override
    public Integer getCode() {
        return code;
    }

    @Override
    public State fromCode(Integer code) {
        return map.get(code);
    }

}

0

được:

public enum BonusType {MONTHLY (0), YEARLY (1), ONE_OFF (2)}

Tiền thưởng BonusType = HÀNG NĂM;

System.out.println (bonus.Ordinal () + ":" + tiền thưởng)

Đầu ra: 1: HÀNG NĂM


0

Nếu bạn có một chiếc xe đẳng cấp

public class Car {
    private Color externalColor;
}

Và thuộc tính Màu là một lớp

@Data
public class Color {
    private Integer id;
    private String name;
}

Và bạn muốn chuyển Color thành Enum

public class CarDTO {
    private ColorEnum externalColor;
}

Chỉ cần thêm một phương thức trong lớp Màu để chuyển đổi Màu trong ColorEnum

@Data
public class Color {
    private Integer id;
    private String name;

    public ColorEnum getEnum(){
        ColorEnum.getById(id);
    }
}

và bên trong ColorEnum thực hiện phương thức getById ()

public enum ColorEnum {
...
    public static ColorEnum getById(int id) {
        for(ColorEnum e : values()) {
            if(e.id==id) 
                return e;
        }
    }
}

Bây giờ bạn có thể sử dụng một Bản đồ lớp

private MapperFactory factory = new DefaultMapperFactory.Builder().build();
...
factory.classMap(Car.class, CarDTO.class)
    .fieldAToB("externalColor.enum","externalColor")
    .byDefault()
    .register();
...
CarDTO dto = mapper.map(car, CarDTO.class);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.