简体   繁体   English

多个通配符通用方法的正确语法?

[英]Correct syntax for mutiple wildcard generic method?

I'm having trouble getting the syntax correct for a generic method with multiple wildcards 我在为具有多个通配符的通用方法获取正确的语法时遇到麻烦

First off I need two different wildcards because (while I've seen that '?' can be used to denote two different types) how will the compiler know when I use '?' 首先,我需要两个不同的通配符,因为(虽然我已经看到'?'可以用来表示两种不同的类型),当我使用'?'时编译器将如何知道? ambiguously in the method. 在该方法中含糊不清。

So below I have my very illegal version where I use '*' as the second wildcard (is there some other wildcard character I can use???) 因此,下面有一个非常非法的版本,其中我使用“ *”作为第二个通配符(是否可以使用其他一些通配符???)

It may seem there is a programming error in the method but I can construct a type 'T' from a type '*' (I have constructors for that- basically taking a Google protocol buffer in and making a "full fledged object" out of it) 似乎该方法中存在编程错误,但我可以从类型'*'构造类型'T'(我有构造函数-基本上是将Google协议缓冲区放入其中,并从中制成“完整对象”它)

private <T, ? extends Database<*>, * extends GeneratedMessage> T getItem(String key, ? db, Hashtable<String, T> table, String message) throws GadsDataException {
    T returnValue = table.get(key);
    if (returnValue == null) {
        * temp = null;
        try {
            temp = db.get(key);
        }
        catch  (InvalidProtocolBufferException e) {
            throw new GadsDataException( message + key + " and hit: ", e);
        }
        if (temp != null) {
            returnValue = new T(temp);
            table.put(key, returnValue);
        }
    }
    return returnValue;
}

In desperation I tried a version without any wildcards (I don't like it as it does not preserve the type relations as the first did). 无奈之下,我尝试了一个没有通配符的版本(我不喜欢它,因为它不像第一个那样保留类型关系)。 But the compiler isn't too keen about it either. 但是编译器也不是很热衷。 I guess I should look at the "Transformer" thing another poster mentioned. 我想我应该看看另一个提到的“变形金刚”东西。

private <T, D, G> T getItem(String key, D db, Hashtable<String, T> table, String message) throws GadsDataException {
        T returnValue = table.get(key);
        if (returnValue == null) {
            G temp = null;
            try {
                temp = db.get(key);
            }
            catch  (InvalidProtocolBufferException e) {
                throw new GadsDataException( message + key + " and hit: ", e);
            }
            if (temp != null) {
                returnValue = new T(temp);
                table.put(key, returnValue);
            }
        }
        return returnValue;
    }

So I'm still stuck on the constructor (as other posters have indicated I would be). 因此,我仍然停留在构造函数上(正如其他张贴者所指出的那样)。 I tried making the compiler happy by making an 'artifical' base class 我试图通过制作“人工”基类使编译器满意

/**
 * This is created as a base class for all objects that can
 * construct themselves from a Google Protocol Buffer with one
 * parameter.
 * 
 * This is just done for the sake of templatizing the methods
 * inside of the GadsLite API
 *
 */
public class ConstructorOneParameter {

    ConstructorOneParameter(GeneratedMessage G) {
        // don't actually do anything... the derived
        // class does all the work
        // We're doing this just to templatize the GadsLite methods
    }
}

Then what I did was use that to identify the type in the template method. 然后我所做的就是使用它来识别模板方法中的类型。 Still the compiler wasn't happy. 编译器仍然不满意。

private <T extends ConstructorOneParameter, D extends Database<G>, G extends GeneratedMessage> T 
        getItem(String key, D db, Hashtable<String, T> table, String message) throws GadsDataException {
    T returnValue = table.get(key);
    if (returnValue == null) {
        G temp = null;
        try {
            temp = db.get(key);
        }
        catch  (InvalidProtocolBufferException e) {
            throw new GadsDataException( message + key + " and hit: ", e);
        }
        if (temp != null) {
            returnValue = new T(temp);
            table.put(key, returnValue);
        }
    }
    return returnValue;
}

Several people have suggested a factory so I changed the line "returnValue = new T(temp);" 几个人建议一家工厂,所以我更改了行“ returnValue = new T(temp);”。 into "returnValue = MessageObjectFactory create(temp);" 变成“ returnValue = MessageObjectFactory create(temp);” Then for the factory I have: 然后对于工厂,我有:

public class MessageObjectFactory {

    public static <G extends GeneratedMessage, R extends Object> R create(G message) {
        R returnValue = null;
        if (message instanceof ArtccData.Artcc) {
            returnValue = new Artcc((ArtccData.Artcc)message);
        }
        return returnValue;
    }

}

I'm just doing one type right now as a proof of concept. 我现在只是在做一种类型的概念证明。 Unfortunately even though everything is a subclass of Object the compiler isn't happy with the "returnValue = new Artcc(..." line complaining "cannot convert from Artcc to R". Is there a specific example of a "Transformer Factory"? 不幸的是,即使所有内容都是Object的子类,编译器也不满意“ returnValue = new Artcc(...)”行抱怨“无法从Artcc转换为R”。是否有“ Transformer Factory”的特定示例?

First off - there is absolutely zero point in declaring a wildcard ( ? ) in the generic parameter section. 首先-在通用参数部分中声明通配符( ?绝对为零 That section is for declaring type variables that you're going to refer to in the actual method signature & body. 该部分用于声明要在实际方法签名和主体中引用的类型变量。 If you put a wildcard there, you obvious can't refer to them - and if you don't refer to them, they don't belong in the generic parameters (since your method won't vary depending on their values). 如果在此处放置通配符,则显然无法引用它们-如果不引用它们,它们将不属于通用参数(因为您的方法不会因其值而异)。

You ask 你问

how will the compiler know when I use '?' 当我使用'时,编译器将如何知道? ambiguously in the method. 在该方法中含糊不清。

which I consider quite confusing. 我认为这很令人困惑。 Quite clearly it won't, which is exactly why you give the types names in the generic parameter block! 显然不会,这就是为什么要在通用参数块中输入类型名称!

So given that, what is it you're trying to accomplish with the wildcards in the first example? 因此,在第一个示例中,您要使用通配符完成什么工作? Why wouldn't it work if you replaced the ? 如果替换了,为什么它不起作用? with U and the * with V (obviously the actual letters are arbitrary names), as in: U*V (显然,实际字母是任意名称),如:

private <T, V extends GeneratedMessage, U extends Database<V>> T getItem(String key, U db, Hashtable<String, T> table, String message) throws GadsDataException {
    ...
    V temp = null;
    ...
}

(You may notice that I switched the order of the latter two parameters - forward references aren't allowed so the V has to appear before the U that depends on it). (您可能会注意到,我切换了后两个参数的顺序-不允许前向引用,因此V必须出现在依赖它的U之前)。

This is similar to your second example except it maintains the constraints on the database and message parameter types. 这与您的第二个示例相似,不同之处在于它维护了数据库和消息参数类型的约束。 What didn't the compiler like about your version? 编译器对您的版本不满意吗?

First you have to find a better way, than 首先,您必须找到一种比

new T(...)

as this is not allowed 因为这是不允许的

Since all my type T's do have a constructor of the form T(G) I don't understand why I can't do new T(temp) . 由于我所有的类型T都具有形式T(G)的构造函数,所以我不明白为什么我不能做new T(temp) Also I edited my original question to display the failed hack described in the previous comment. 我还编辑了原始问题,以显示上一条注释中描述的失败的hack。

Java generics is an instrument to guarantee type safety, not to create different code depending on parameter. Java泛型是一种保证类型安全的工具,而不是根据参数创建不同的代码。 The compiler erases most type variables, so at runtime the actual type T is not known at all - thus we can't invoke any of its constructors (or create arrays of this type, by the way). 编译器会擦除大多数类型变量,因此在运行时根本不知道实际的类型T因此我们无法调用其任何构造函数(顺便说一下,也不能创建此类型的数组)。 This way we can use the generic method (or class) with types which were not yet existent when the method was created. 这样,我们可以将泛型方法(或类)与创建该方法时尚不存在的类型一起使用。

And actually, the compiler could not guarantee that all possible classes have such constructors, as there always could be later subclasses without. 实际上,编译器无法保证所有可能的类都具有此类构造函数,因为以后总是会有子类不带。

So, in your case, you should think about using some kind of factory object, which takes a G and gives back the right T object, (for example a Transformer<G, T> type, like Andrzej proposed.) 因此,在您的情况下,您应该考虑使用某种工厂对象,该对象需要G并返回正确的T对象(例如,像Andrzej所建议的那样Transformer<G, T>Transformer<G, T>类型)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM