2

我所说的类型是指可以让我执行以下操作的东西。

public class AnyObject{

    List<this.type> list;   

}

我知道以下内容不起作用。

public class AnyObject{

    List<this.getClass()> list;   

}

那么我将如何创建一个让我们说一个列表,例如清酒,不管是什么类型的?

- - - - - - - - 更新 - - - - - - - -

我很抱歉,我认为我没有说清楚。我似乎明白没有办法逃避类型擦除,但如果还有办法解决我的问题,我会更好地解释它。披露,这更像是一个客观化的问题。对不起,我现在才来看。

我们走吧,我尽可能地清楚......

对于我计划保留的每个实体,在使用 Objectiy 的 GAE 数据存储中,我希望有一种方法可以Key<?>使用 id 和 parent 字段生成 Objectify。让我们调用这个方法generateKey()。这是它的外观。

public Key<MyEntity> generateKey() {      
    Key<MyEntity> key = Key.create(this.parent, MyEntity.class, this.id);
    return key;
}

问题是我必须为我创建的每个实体或多或少地编写这个确切的代码。其实,还有其他的重码,但我的观点可以单用这段重码来说明。

所以我尝试了这个。我创建了一个名为 MyProjectEntity 的类,并让我的所有实体都扩展了它。然后generateKey()使用泛型实现了一个方法。

public abstract class MyProjectEntity<T, Y> {

    @Id     Long id;
    @Parent Key<T> parentKey;

    public Key<Y> generateKey() {
        Key<Y> key = Key.create(this.parentKey, this.getClass(), this.id);
        return key;
    }          

}

然后我用我创建的这个名为 MyProjectEntity 的新类扩展了我的所有实体类。像这样...

@Entity
public class MyEntity extends MyProjectEntity<MyEntityParent> {...}

听起来不错,现在我所有的实体都将有一个generateKey()方法,但这并不完全奏效。Objectify 对我大喊大叫,说 IllegalArgumentException,不能声明 T 类型的 Key。

然后我试了一下Key<Object>,Objectify还是不爽,Objectify说Object不是注册实体。我应该注册对象吗!?!?这有点失去了 Objectify 提供的键入密钥的全部意义。

有没有好的解决办法。谢谢!

-- 更新 2 --

既然有人指出 Key.create(myEntity) 我应该指出我的全部用途......

/**********************************************************************************************************************
 * Constructors END & Identification and Relationship Methods BEGIN
 **********************************************************************************************************************/

    @ApiSerializationProperty(name = "id")
    public String getWebSafeKey() {

        String webSafeKey = getKey().getString();

        return webSafeKey;

    }

    public void setWebSafeKey(String webSafeKey) throws BadRequestException {

        try {
            Key<MyEntity> key = Key.create(webSafeKey);
            setKey(key);

        } catch (IllegalArgumentException illegalArgumentException) {
            throw new BadRequestException(ErrorMessage.INVALID_ID);
        }

    }

    @ApiSerializationProperty(name = "parentId")
    public String getParentWebSafeKey() {
        String webSafeKey = parent.getString();
        return webSafeKey;
    }

    public void setParentWebSafeKey(String parentWebSafeKey) throws BadRequestException {

        if (id == null) {
            try {
                parent = Key.create(parentWebSafeKey);
            } catch (IllegalArgumentException illegalArgumentException) {
                throw new BadRequestException(ErrorMessage.invalidParentId("Property"));
            }

        } else {
            /* Do nothing. Only set parent here if setWebSafeKey is never called, such as during a create. */
        }

    }

    @ApiSerializationProperty(ignored = AnnotationBoolean.TRUE)
    public Key<MyEntity> getParentKey() {
        return parent;
    }

    public void setParentKey(Key<MyEntity> parentKey) {
        this.parent = parentKey;
    }

    @ApiSerializationProperty(ignored = AnnotationBoolean.TRUE)
    public Key<MyEntity> getKey() {

        Key<MyEntity> key = Key.create(parent, MyEntity.class, id);

        return key;

    }

    public void setKey(Key<MyEntity> key) {
        id = key.getId();
        parent = key.getParent();
    }

    public boolean webSafeKeyEquals(String webSafeKey) {

        boolean equals;

        if (id !=null & parent !=null) {
            equals = getWebSafeKey().equals(webSafeKey);
        } else {
            equals = false;
        }

        return equals;

    }

/**********************************************************************************************************************
 * Identification Methods END & Other Getters and Setters BEGIN
 **********************************************************************************************************************/

必须为我创建的每个实体插入所有这些,并将 MyEntity 替换为实际实体名称。这不仅仅是打字。这段代码不属于实体类,而是属于某个抽象父类。如果我只能拥有类中特定实体的唯一代码,我的模型会更简洁,更容易扩展。再次感谢。

4

5 回答 5

3

这没有意义List<this.getClass()> list;,因为类型参数是 java 中的编译时事物。此信息在运行时被删除

于 2013-10-28T23:24:39.370 回答
3

这是没有意义的。考虑一下:你永远不会知道类型list是什么。假设list在某个类的某个方法中使用它,它总是可能this是子类的一个实例。因此,永远不能在任何代码中假设List类型中的参数。list如果它永远无法知道,那它的意义何在?你只会使用List<?>.

泛型是纯粹的编译时事物。因此,依赖某个东西的运行时类是没有意义的。

我建议你有

public class AnyObject<T> {
    List<T> list;
}

例如,任何Foo想要list成为 a 的类都List<Foo>应该实现或继承自AnyObject<Foo>.

于 2013-10-28T23:06:42.980 回答
1

在不熟悉 Objectify 的情况下,只是泛型,我看到的是Key.create本身应该为<T>返回的 Key 的类型提供一个泛型参数。因此,当您在超类中调用该方法时,您应该执行以下操作:

Key<Y> key = Key.<Y>create(this.parentKey, this.getClass(), this.id);

您可能只需要这样做来修复错误(并且无论如何都应该这样做)。否则 Key.create 将尝试实例化一个新的Key<Y>,尽管当方法要求一个类型参数时不声明类型参数或多或少是有效的,但显然 Key.create 可能不喜欢那样。

我认为你还应该再看看你的 Ts 和 Ys,因为看起来你正在混合它们。现在您将 Key.create aKey<T>作为参数传递,但想要返回 a Key<Y>。此外,如果您声明您的类具有<T, Y>它应该是非法的扩展它<MyEntityParent>

查看您的代码,我认为您要做的是创建与您调用它的方法相同的类的 Key。MyEntity 中的 IE 类 generateKey 应该返回一个Key<MyEntity>. 我认为这样做的正确方法是这样的(这是有效的):

public abstract class MyProjectEntity<T, K> {
    Long id;
    Key<K> parentKey;

    public Key<K> generateKey() {
        return Key.<K>create(parentKey, this.getClass(), id);
    }
}

public class MyEntity extends MyEntityParent<MyEntityParent, MyEntity> {
    /*
     * K is now MyEntity and parentKey is a Key<MyEntity>
     * generateKey now does the following:
     *
     * public Key<MyEntity> generateKey() {
     *     return Key.<MyEntity>create(parentKey, MyEntity.class, id);
     * }
     *
     */
}

似乎您的示例不起作用是因为您没有正确声明类型而给出了错误。但很难说,因为不清楚你的 T 和 Y 应该是什么。您只显示一种正在声明的类型,并且至少在您的 generateKey 方法中您正在处理 Key.create aKey<T>但想要返回 a Key<Y>

或者您应该看看在Objectify API中注册实体。IE 似乎你可能应该做这样的事情,这可能是你收到错误的原因:

static {
    ObjectifyService.register(MyEntityParent.class);
}

但是无论如何,在 Java 泛型的世界里,你真的应该能够在没有任何体操的情况下做这样的事情,除非发生了其他事情。擦除的本质是您无法在运行时找出类型,但该类型本质上是“已知的”,因为 T 的所有实例都被替换为参数类型。

public abstract class MyProjectEntity<T> {
    Key<T> parentKey;
}

变成

public class MyEntity extends MyProjectEntity<MyEntityParent> {
    Key<MyEntityParent> parentKey;
}

您无法确定 parentKey 是否属于 Type<MyEntityParent>但它属于该类型。您显然可以通过 java.util.List 之类的东西看到这一点,如果您执行以下操作:

List<Double> doubleList = new ArrayList<Double>(0);
doubleList.add("a string");

如果您忽略编译器错误并尝试运行程序,您将得到以下信息:

Uncompilable source code - Erroneous sym type: java.util.ArrayList.add
java.lang.RuntimeException: Uncompilable source code - Erroneous sym type: java.util.ArrayList.add

因为该列表确实“仅包含” Double 的实例。这种情况可以与匿名类相比,其中 ArrayList 的 add 方法的实例现在正式将 Double 作为参数。它是不可编译的,因为我只是试图这样做:

public void add(Double element) {
    // add the element to the array
}

list.add("a string");

这显然是非法的。这个 ArrayList 的底层数组仍然是一个 Object[] 但方法将被更改以反映类型并安全地确保该数组在运行时仅包含 Double 元素。

因此,我建议您查看我提到的内容,因为除非您省略了相关代码,否则似乎存在不止一个问题。

于 2013-11-05T17:17:05.000 回答
0

我想我理解你的问题,这就是你可以做到的。诀窍是将子类作为父类的通用参数传递:

class Parent<T> {
    T doStuff() {
        T res = null;
        // res = ..... this.getClass() is ok...
        return res;
    }
}

public class SelfGerenic extends Parent<SelfGerenic> {
}

public class OtherSubClass extends Parent<OtherSubClass> {
}
于 2013-11-04T14:26:02.350 回答
0

如果我没听错,你正在寻找这样的东西:

public class Test {
private int id;

public Key<Test> getKey() {
    return createKey(id, this.getClass());
}

public static <T> Key<T> createKey(int id, Class<? extends T> clazz) {
    return new Key<T>(clazz, id);
}

private static class Key<T> {
    private final Class<? extends T> clazz;
    private final int id;

    private Key(Class<? extends T> clazz, int id) {
        this.clazz = clazz;
        this.id = id;
    }

    private int getId() {
        return id;
    }

    private Class<? extends T> getClazz() {
        return clazz;
    }
}

public int getId() {
    return id;
}
}

无法在此处替换测试public Key<Test> getKey() {!这是因为 getKey() 总是返回 Key。它不能返回测试。所以基本上没有,没有办法改变这种行为。也没有办法获得“当前”类的通用类型。这是java泛型的某种限制:P

您可以在此处删除泛型,因此您不必每次都实现 getKey()。

public class Test {
private int id;

public Key getKey() {
    return createKey(id, this.getClass());
}

public static  Key createKey(int id, Class clazz) {
    return new Key(clazz, id);
}

private static class Key {
    private final Class clazz;
    private final int id;

    private Key(Class clazz, int id) {
        this.clazz = clazz;
        this.id = id;
    }

    private int getId() {
        return id;
    }

    private Class getClazz() {
        return clazz;
    }
}

public int getId() {
    return id;
}
}
于 2013-11-05T21:07:42.090 回答