【问题标题】:Java Enum - Store Type For Later CastJava Enum - 存储类型以供以后转换
【发布时间】:2015-12-03 07:49:26
【问题描述】:

我有一个表示特定表中所有列值的枚举。现在我想为每个枚举元素存储一个类型,以便稍后进行查询。

public enum Value {

    MEMBER1(?...?),
    MEMBER2(?...?);

    private final ?...? type;

    Value(?...? type) {
        this.type = type;
    }

    public ?...? getType() {
        return type;
    }

}

我现在不用写什么来代替?...?。也许它的MyClassA.classClass 但是我如何使用这个值来进行这个操作:

MEMBER1.getType() instance = (MEMBER1.getType()) object;

对我来说,这对于与 java 的数据库通信非常重要。

更新:我的意思是这个操作。

结束更新:存在逻辑错误。如果我知道不同的类型,我可以简单地创建多个方法,因为我有一个 api 规范。

【问题讨论】:

  • "*我如何在这个操作中使用这个值:MyClassA instance = (MEMBER1.getType()) object;*" 你知道你想创建MyClassA 类型的变量吗?你以后将如何使用这个变量?为什么需要它的正确类型?
  • 还要查看 java.sql.Types 和 javax.sql.rowset.RowSetMetaDataImpl#getColumnClassName 映射。也许对你来说就足够了。

标签: java class types casting enums


【解决方案1】:

我怎样才能在这个操作中使用这个值:

MyClassA instance = (MEMBER1.getType()) object;

使用 instanceof 检查对象类型。

MyClassA instance;
if (object instanceof MyClassA && object instanceof MEMBER1.getType()){ 
 instance = (MyClassA) object;
}

【讨论】:

    【解决方案2】:

    您可以通过存储对象的 Class 并在必要时使用它来进行转换:

    class Test {
    
        public static void main(String[] arguments) throws Exception {
            Object object = new MyClassA();
            Class<MyClassA> clazz = Value.MEMBER1.getType();
            MyClassA instance = clazz.cast(object);
            System.out.println(instance);
        }
    
    }
    
    enum Value {
    
        MEMBER1(MyClassA.class),
        MEMBER2(MyClassB.class);
    
        private final Class<?> clazz;
    
        Value(Class<?> clazz) {
            this.clazz = clazz;
        }
    
        @SuppressWarnings("unchecked")
        public <T> Class<T> getType() {
            return (Class<T>) clazz;
        }
    
    }
    
    class MyClassA { }
    class MyClassB { }
    

    【讨论】:

    • 虽然这将编译并在一段时间后工作,但这仍然是不安全的。 @SuppressWarnings 可以说是不正确的,因为不存在保证强制转换是安全的或不会发生 ClassCastException 的逻辑。
    【解决方案3】:

    你是对的。枚举应定义如下

    public enum Value {
    
       MEMBER1(String.class),
       MEMBER2(Integer.class);
    
       private final Class<?> type;
       private Value(Class<?> type) {
           this.type = type;
       }
    
       public Class<?> getType(){
           return this.type;
       }
    }
    

    第二部分实际上是您不想做的事情,因为您已经知道要将对象转换为的类型(在您的情况下是 MyClassA),因此您可以像下面这样直接转换

    //I know what is the target type so I don't have to fetch the type from my enum
    MyClassA instance = (MyClassA) object;
    

    一旦您需要在未知数据类型上构建逻辑,您就可以执行类似的操作

    Object o = getTheObjectSomewhere();
    if(o.getClass().isAssignableFrom(MEMBER1.getType()){
        String s = (String) o;
        System.out.println("Target type is string!");
        doSomething();
    } else if (o.getClass().isAssignableFrom(MEMBER2.getType()){
        Integer i = (Integer) i;
        System.out.println("Target type is integer!");
        doSomethingElese();
    }
    

    也许您想稍后根据您的对象类型搜索该列。然后你可以创建一个方法来获取列

    public Value getColumnByObjectType(Object o){
        for(Value v : Value.values()){
            if(v.getType().equals(o.getClass()){
                return v;
            }
        }
        return null;
    }
    

    并用它来搜索列

    Object o = getObjectSomewhere();
    Value column = getColumnByObjectType(o);
    

    要根据下面的评论获取用户对象,您可以使用 JPA 执行以下操作

    public Object getUserObject(int id, Value v){
        TypedQuery<?> q = DBUtils.getEntityManager().createQuery("select u.:column from User u where u.id = :id",v.getType());
        q.setParameter("column", v.toString());
        q.setParameter("id", id);
        q.setMaxResult(1);
        return q.getSingleResult();
    }
    

    【讨论】:

    • 是的,我知道我想投到的班级。但是这个信息必须存储在枚举成员中。
    • 也许您可以指定从哪里获取对象以及为什么需要将类型存储在枚举中?
    • 我想获取存储在数据库中的用户值,例如:“getUserData(6, Value.NAME)”。 6 是 id,它应该返回枚举成员 NAME 中引用的类的实例。
    【解决方案4】:

    我有一个表示特定表中所有列值的枚举。现在 我想为每个枚举元素存储一个类型,以便稍后查询 铸造。

    一般来说,这不能按照您希望的方式完成。

    您想要的是让枚举保存 异构类型安全容器(Essential Java,第 2 版)的密钥。

    不幸的是,Java 类对象是泛型的(例如,String.classClass&lt;String&gt;)并且Java 枚举和泛型不能很好地配合使用

    虽然可以将 Class 对象存储为枚举中的字段,但您的 Class 对象将在此过程中丢失其类型信息。当您访问该字段时,您仍然需要手动重新声明类型链接......这将需要一个不安全的演员表。不知道有没有办法解决。

    例如,您的枚举可能有一个名为 colClassToken 的字段,您打算在其中存储表中关联列的类型:

    public enum TableColumn {
        MEMBER1(String.class),
        MEMBER2(Integer.class);
    
        private Class<?> e_colToken;
    
        TableColumn(Class<?> tok) { this.e_colToken = tok; }
    
        public Class<?> getColumnToken() { return this.e_colToken; }
    
        :
        :
    }
    

    您现在希望能够在访问表中的列时使用 Class 对象的 cast() 方法重新声明类型链接(例如,使用类似的习语):

    String myColumn = MEMBER1.getColumnToken().cast(myTable.getCol(MEMBER1));
    

    但是,这不会编译。由于枚举字段中已经丢失了 Class 对象的类型(并且无法生成枚举),因此编译器无法保证 cast() 操作的类型安全。

    【讨论】:

      猜你喜欢
      • 2014-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-06
      • 1970-01-01
      相关资源
      最近更新 更多