【问题标题】:Conveniently map between enum and int / String方便地在 enum 和 int / String 之间映射
【发布时间】:2011-06-28 14:52:42
【问题描述】:

当使用只能取有限数量值的变量/参数时,我尝试始终使用 Java 的 enum,如

public enum BonusType {
  MONTHLY, YEARLY, ONE_OFF
}

只要我留在我的代码中,就可以正常工作。但是,我经常需要与其他使用纯int(或String)值的代码进行交互以达到相同目的,或者我需要读取/写入数据存储为数字或字符串的数据库.

在这种情况下,我希望有一种方便的方法将每个枚举值与一个整数相关联,这样我就可以两种方式进行转换(换句话说,我需要一个“可逆枚举”)。

从 enum 到 int 很容易:

public enum BonusType {
  public final int id;

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

然后我可以以BonusType x = MONTHLY; int id = x.id; 访问int 值。

但是,我看不出相反的好方法,即从 int 到 enum。理想情况下,像

BonusType bt = BonusType.getById(2); 

我能想到的唯一解决方案是:

  • 将查找方法放入枚举中,该方法使用BonusType.values() 填充映射“int -> enum”,然后将其缓存并用于查找。可以,但我必须将此方法完全相同地复制到我使用的每个枚举中:-(。
  • 将查找方法放入静态实用程序类中。然后我只需要一个“查找”方法,但我必须摆弄反射以使其适用于任意枚举。

对于这样一个简单的 (?) 问题,这两种方法似乎都非常尴尬。

还有其他想法/见解吗?

【问题讨论】:

  • 对于 enum->int 你可以使用ordinal()
  • 你的 id 值是由你决定的(意思是,你不能只使用.ordinal()),还是由外部力量决定?
  • @davin:是的,当有人重新排列枚举声明或删除中间的值时,让您的代码中断。恐怕这不是一个强大的解决方案:-/。
  • @davin 应尽可能避免使用“ordinal()”,它在语言规范中

标签: java enums coding-style


【解决方案1】:

我不确定它在 Java 中是否相同,但 C 中的枚举类型也会自动映射到整数,因此您可以使用类型或整数来访问它。您是否尝试过简单地使用整数访问它?

【讨论】:

  • Java 中的枚举并非如此。它们是显式类型。
  • 每个枚举对象都有一个内部编号(即声明它的位置),可以通过.ordinal()方法访问。 (另一种方式,使用BonusType.values()[i]。)但是在上面引用的示例中,这里的索引和外部值不重合。
【解决方案2】:

使用界面显示谁是老板。

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);
  }
}

结果:

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>

【讨论】:

  • 就像 Turd Ferguson 的回答一样,这是我想避免/改进的不优雅的解决方案......
  • 我通常在 static{ } 块中创建反向映射,这样每次我通过 id 请求值时都不必遍历 values()。我通常还调用该方法 valueOf(int) 以使其看起来有点像 Strings 已经存在的 valueOf(String) 方法(也是 OP 问题的一部分)。有点像 Effective Java 中的第 33 项:tinyurl.com/4ffvc38
  • @Sleske 更新了更完善的解决方案。 @Fredrik 很有趣,尽管我怀疑迭代是否会成为一个重大问题。
  • @glowcoder 好吧,不必重复多次意味着每秒执行一千次都没关系,这可能是一个非常重要的问题,或者只是调用两次。
  • @Fredrik 我承认有时可能需要优化。我还说,在确定性能问题之前,不要针对它进行优化。
【解决方案3】:

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

该解决方案与您的解决方案类似,将 int 值作为枚举定义的一部分。然后他继续创建一个基于泛型的查找实用程序:

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);
    }
}

这个解决方案很好,不需要“摆弄反射”,因为它基于所有枚举类型都隐式继承 Enum 接口的事实。

【讨论】:

  • 这不使用序数吗? Sleske 使用 id 只是因为当枚举值重新排序时序号会发生变化。
  • 不,它不使用序数。它依赖于明确定义的 int 值。该 int 值用作映射键(由 v.convert() 返回)。
  • 我真的很喜欢这个解决方案;看来这是你能得到的最一般的了。
  • +1。我唯一要注意的是我会使用Number 而不是Byte,因为我的支持值可能更大。
  • 真正地阅读这个问题。如果您正在处理的旧数据库或外部系统定义了您不想通过自己的代码传播的整数,那么这正是其中一种情况。序数是保持枚举值的一种极其脆弱的方式,除此之外,它在问题中提到的特定情况下毫无用处。
【解决方案4】:

枚举 → 整数

yourEnum.ordinal()

int → 枚举

EnumType.values()[someInt]

字符串 → 枚举

EnumType.valueOf(yourString)

枚举 → 字符串

yourEnum.name()

旁注:
正如您正确指出的那样,ordinal() 在版本之间可能“不稳定”。这就是为什么我总是将常量作为字符串存储在我的数据库中的确切原因。 (其实在使用MySql的时候,我把它们存储为MySql enums!)

【讨论】:

  • +1 这是显而易见的正确答案。但请注意,valueOf 有一个参数方法,只要您使用具体的枚举类型(例如BonusType.valueOf("MONTHLY"),它就只需要一个字符串并且存在
  • 使用ordinal() 让我觉得这是一个有问题的解决方案,因为它会在枚举值列表重新排列或删除值时中断。此外,这仅在 int 值为 0...n 时才实用(我经常发现情况并非如此)。
  • @sleske,如果您开始删除常量,无论如何您都会遇到现有持久数据的问题。 (在这方面更新了我的答案。)
  • 使用values() 数组仅在您的所有值的 id 索引为 0 并按顺序声明时才有效。 (我对此进行了测试,以验证如果您声明 FOO(0), BAR(2), BAZ(1);values[1] == BARvalues[2] == BAZ,尽管传入了 id。)
  • @glowcoder,当然,整数参数只是枚举对象中的一个字段。它与与枚举对象关联的序数常数无关(它也可以是double)。
【解决方案5】:

你也许可以使用类似的东西

interface EnumWithId {
    public int getId();

}


enum Foo implements EnumWithId {

   ...
}

这将减少您的实用程序类中对反射的需求。

【讨论】:

  • 你能举个例子说明如何使用这个sn-p吗?
【解决方案6】:

非常好的问题 :-) 前段时间我使用了类似于 Mr.Ferguson 的解决方案。我们反编译的枚举如下所示:

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
        });
    }
}

看到这一点,ordinal() 不稳定的原因就很明显了。它是super(s, i); 中的i。我也很悲观,你能想到一个比你已经列举的更​​优雅的解决方案。毕竟枚举和任何最终类一样都是类。

【讨论】:

    【解决方案7】:

    为了完整起见,这里有一种通用方法,可以通过索引从任何枚举类型中检索枚举值。我的目的是使该方法看起来和感觉像Enum.valueOf(Class, String)。仅供参考,我从here复制了这个方法。

    索引相关问题(已在此处深入讨论)仍然适用。

    /**
     * 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];
    }
    

    【讨论】:

    • 这不是我真正想要的,因为它只按序号检索枚举值,而不是按分配的整数 id(请参阅我的问题)。此外,如果我确实需要,我可以使用 MyEnumType.values() - 不需要静态辅助方法。
    【解决方案8】:

    我在网上找到了这个,它非常有用且易于实现。 这个解决方案不是我做的

    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()
    【解决方案9】:

    .ordinal()values()[i] 都不稳定,因为它们依赖于枚举的顺序。因此,如果您更改枚举的顺序或添加/删除一些您的程序会中断。

    这是一个简单而有效的在 enum 和 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");
        }
    }
    

    将它应用于字符串应该不难。

    【讨论】:

    • 是的,我意识到我可以做到这一点 - 或者更好的是,使用映射进行反向查找,而不是遍历所有值。我在我的问题中提到了这一点,我还提到我正在寻找一个更好的解决方案,以避免在每个枚举中都有样板代码。
    【解决方案10】:
    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);
                }
            }
    

    【讨论】:

      【解决方案11】:

      一个非常简洁的反向枚举使用示例

      第 1 步 定义一个interface EnumConverter

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

      第 2 步

      创建类名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);
          }
      }
      

      第 3 步

      去你Enum 类和implement 它与EnumConverter&lt;ContentType&gt;,当然覆盖接口方法。您还需要初始化一个静态 ReverseEnumMap。

      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);
          }
      }
      

      第 4 步

      现在创建一个Communication 类文件并调用它的新方法,将Enum 转换为StringString 转换为Enum。我只是为了解释的目的而放置了主要方法。

      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)
          }
      }
      

      Click for for complete explanation

      【讨论】:

      • 我真的非常非常喜欢 - 我一直在寻找一个可靠的解决方案来解决这个问题。我所做的唯一更改是将ContentType convert(String pKey) 设为静态,这消除了对Communication 类的需求,并且更符合我的喜好。 +1
      【解决方案12】:

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

      为了避免我为每个 Enum 编写大量样板代码或重复代码,我改用了 Apache Commons Lang 的 ValuedEnum

      定义

      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);
          }
      }
      

      用法:

      int -> ValuedEnum:

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

      【讨论】:

      • 好主意,我没有意识到这存在。感谢分享!
      【解决方案13】:

      我需要一些不同的东西,因为我想使用通用的方法。我正在从字节数组中读取枚举。这是我想出的:

      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.
      }
      }
      

      枚举示例:

      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;
          }
      }
      

      【讨论】:

        【解决方案14】:

        在这段代码中,为了永久和密集的搜索,有内存或进程供使用,我选择内存,以转换器数组作为索引。 希望对你有帮助

        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]];
        }
        }
        

        【讨论】:

          【解决方案15】:

          随着 Java 8 的发布,这个问题的答案似乎已经过时了。

          1. 不要使用序数,因为如果在 JVM,例如数据库。
          2. 创建静态地图相对容易 键值。

          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);
            }
          }
          

          【讨论】:

          • Collectors.toMap()的第二个参数不应该是Functions.identity()而不是null吗?
          • 是的,我从一个帮助器类中采用了这个,我使用 guava 将 null 转换为标识。
          • 这是对 Java 8 新特性的巧妙使用。但是,这仍然意味着代码必须在每个枚举中重复 - 我的问题是关于避免这种(结构上)重复的样板。
          【解决方案16】:

          仅仅因为接受的答案不是自包含的:

          支持代码:

          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);
              }
          }
          

          使用示例:

          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);
              }
          
          }
          

          【讨论】:

            【解决方案17】:

            给定:

            公共枚举 BonusType { 每月(0)、每年(1)、一次关闭(2) }

            BonusType 奖金 = YEARLY;

            System.out.println(bonus.Ordinal() + ":" + bonus)

            输出: 1:每年

            【讨论】:

              【解决方案18】:

              如果你有一门课汽车

              public class Car {
                  private Color externalColor;
              }
              

              并且属性Color是一个类

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

              并且您想将 Color 转换为 Enum

              public class CarDTO {
                  private ColorEnum externalColor;
              }
              

              只需在 Color 类中添加一个方法即可在 ColorEnum

              中转换 Color
              @Data
              public class Color {
                  private Integer id;
                  private String name;
              
                  public ColorEnum getEnum(){
                      ColorEnum.getById(id);
                  }
              }
              

              ColorEnum内部实现了getById()方法

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

              现在你可以使用类映射

              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);
              

              【讨论】:

                猜你喜欢
                • 2011-04-24
                • 2012-01-20
                • 1970-01-01
                • 2018-01-22
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-05-19
                • 1970-01-01
                相关资源
                最近更新 更多