简体   繁体   English

在转换为泛型类型时,Java中的警告

[英]Warnings in Java when casting to a generic type

I have some generic code which I cannot figure out how to legitimately prevent getting warnings from; 我有一些通用代码,我无法弄清楚如何合法地阻止警告; I am using @SuppressWarnings("unchecked") for the moment, since it seems that casting a generic type can't be done without warnings. 我目前正在使用@SuppressWarnings(“unchecked”),因为似乎在没有警告的情况下无法完成转换泛型类型。

How can I get rid of the annotation? 我怎样才能摆脱注释?

What I have is: 我有的是:

public MyObject(SharedContext<Object> ctx) {
    super(ctx); // set protected field 'context'
    ...
    context.set("Input Fields"  ,Collections.synchronizedMap(new TreeMap<String,Pair<String,Boolean>>(String.CASE_INSENSITIVE_ORDER)));
    context.set("Output Fields" ,Collections.synchronizedMap(new TreeMap<String,String>              (String.CASE_INSENSITIVE_ORDER)));
    context.set("Event Registry",new EventRegistry(log)                                                                              );
    }

@SuppressWarnings("unchecked")
protected void startup() {
    inputFields     =(Map<String,Pair<String,Boolean>>)context.get("Input Fields"  ,null);
    outputFields    =(Map<String,String>              )context.get("Output Fields" ,null);
    eventRegistry   =(EventRegistry                   )context.get("Event Registry",null);
    ...
    }

The protected variable context is type SharedContext<Object> . 受保护的变量上下文是SharedContext<Object>类型。

Without the annotation the compiler gives warnings: 如果没有注释,编译器会发出警告:

...\MyClass.java:94: warning: [unchecked] unchecked cast
found   : java.lang.Object
required: java.util.Map<java.lang.String,com.mycompany.Pair<java.lang.String,java.lang.Boolean>>
    inputFields     =(Map<String,Pair<String,Boolean>>)context.get("Input Fields"  ,null);
                                                                  ^
...\MyClass.java:95: warning: [unchecked] unchecked cast
found   : java.lang.Object
required: java.util.Map<java.lang.String,java.lang.String>
    outputFields    =(Map<String,String>              )context.get("Output Fields" ,null);

After some further research I believe I have found a reasonable alternative, which at least limits the suppression annotation to just one global static utility method to do an unchecked cast. 经过一些进一步的研究后,我相信我找到了一个合理的替代方案,它至少将抑制注释限制为一个全局静态实用方法来进行未经检查的强制转换。

The self contained test program which follows should be clear enough: 随后的自包含测试程序应该足够清楚:

public class Generics
{

static public void main(String[] args) {
    Generics.test();
    }

static private void test() {
    Map<String,Object> ctx=new TreeMap<String,Object>();
    Map<String,Object> map=new TreeMap<String,Object>();
    Map<String,Object> tst;

    ctx.put("Test",map);
    tst=uncheckedCast(ctx.get("Test"));
    }

@SuppressWarnings({"unchecked"})
static public <T> T uncheckedCast(Object obj) {
    return (T)obj;
    }

}

Another blog suggested an improvement to this utility method: 另一篇博客建议改进这种实用方法:

@SuppressWarnings("unchecked") 
public static <T, X extends T> X uncheckedCast(T o) {
    return (X) o;
    }

forcing what is returned to be a subclass of the parameter passed in. 强制返回的内容是传入的参数的子类。

Assuming I put uncheckedCast into public utility class GenUtil, my startup method in the question would have no (useless) warnings emitted and look like: 假设我将uncheckedCast放入公共实用程序类GenUtil中,我在问题中的启动方法将没有(无用的)警告发出,看起来像:

protected void startup() {
    inputFields  =GenUtil.uncheckedCast(context.get("Input Fields"  ,null));
    outputFields =GenUtil.uncheckedCast(context.get("Output Fields" ,null));
    eventRegistry=GenUtil.uncheckedCast(context.get("Event Registry",null));
    ...
    }

The first unchecked cast can be eliminated by defining a non-generic class that extends the generic Map<String, Pair<String, Boolean>> and storing that in the SharedContext instead of a generic TreeMap , eg (using ForwardingMap from Guava ): 可以通过定义扩展泛型Map<String, Pair<String, Boolean>>并将其存储在SharedContext而不是通用TreeMap的非泛型类来消除第一个未经检查的强制转换,例如(使用来自Guava的 ForwardingMap ):

class InputFieldMap extends ForwardingMap<String,Pair<String,Boolean>> {

    private final Map<String,Pair<String,Boolean>> delegate =
        Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER);
    protected Map<String,Pair<String,Boolean>> delegate() { return delegate; }

}

// ...

context.set("Input Fields"  ,Collections.synchronizedMap(new InputFieldMap()));

// ...

inputFields     =(InputFieldMap)context.get("Input Fields"  ,null);
outputFields    =(Map<?,?>     )context.get("Output Fields" ,null);

You could make the second cast safe in the same way, or (assuming you are only reading the map not modifying it) use the map as is (with wildcard parameters) and convert the value to a string with each lookup: 您可以以相同的方式使第二个强制转换安全,或者(假设您只是读取不修改它的映射)按原样使用映射(使用通配符参数)并将值转换为每个查找的字符串:

String bar = String.valueOf(outputFields.get("foo"));

or wrap the map: 或包裹地图:

Map<?, String> wrappedOutputFields    =
    Maps.transformValues(outputFields, Functions.toStringFunction());

// ...

String bar = wrappedOutputFields.get("foo");

Is the SharedContext object one that you wrote? SharedContext对象是您编写的对象吗? If so, is it possible to replace the generic String->Object mapping with specific fields? 如果是这样,是否可以用特定字段替换通用String-> Object映射?

eg. 例如。

context.setInputFields(...)
context.setOutputFields(...)
context.setEventRegistry(...)
context.getInputFields()
etc.

The generic hold-all context object always seems a less-than-perfect solution to me. 对我来说,通用的hold-all上下文对象似乎总是不太完美。 Especially with generics and the unchecked cast messages that results. 特别是使用泛型和未经检查的强制转换消息。

Alternatively, you could create a wrapper object called SoftwareMonkeyContext that has the specific setter/getter methods as above, and internally uses your GenUtil.uncheckedCast method. 或者,您可以创建一个名为SoftwareMonkeyContext的包装器对象,该对象具有上述特定的setter / getter方法,并在内部使用您的GenUtil.uncheckedCast方法。 This would prevent you needing to use GenUtil.uncheckedCast at multiple spots in your code. 这可以防止您需要在代码中的多个位置使用GenUtil.uncheckedCast。

How is the context variable being assigned? 如何分配context变量? Is it from the parameter ctx, which is of type : 它来自参数ctx,它的类型是:

SharedContext<Object>

?

If so, thats your problem because when you do a get you haven't effectively typed what you are getting. 如果是这样,那就是你的问题,因为当你做了一个让你没有有效输入你得到的东西。

Which version of compiler you are using? 您使用的是哪个版本的编译器? With Java 6 compiler(Sun JDK windows) I did not see detailed warning. 使用Java 6编译器(Sun JDK windows),我没有看到详细的警告。 I am getting warning information only when I use '-Xlint:unchecked' flag. 我只在使用'-Xlint:unchecked'标志时才收到警告信息。

Try -Xlint:-unchecked and let us know if it resolves your issue. 尝试-Xlint:-unchecked并告诉我们它是否可以解决您的问题。 For more on flags, 有关旗帜的更多信息,

http://java.sun.com/javase/6/docs/technotes/tools/windows/javac.html http://java.sun.com/javase/6/docs/technotes/tools/windows/javac.html

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

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