如何让 Java 为我的类型安全映射文字推断正确的通用映射类型?

发布于 2024-11-28 05:34:55 字数 674 浏览 2 评论 0原文

我正在尝试在 java 中编写一个类型安全的映射文字帮助程序类,它可以生成任何类型的映射,并让编译器检查所​​有给定的键和值是否符合映射的类型。对于具有两个值的映射,将有一个具有以下签名的函数:

public static <KEY, VALUE> Map<KEY, VALUE> make(final KEY key1,
        final VALUE value1,
        final KEY key2,
        final VALUE value2)

现在我预计类似的事情是可能的:

    Map<Integer, Object> map = make(1, "bla", 3, 17);

但是我收到编译器错误:

Type mismatch: cannot convert from Map<Integer,Object&Serializable&Comparable<?>> to 
 Map<Integer,Object>

有没有办法解决这个问题?当然,用签名 make(Object...keysAndValues) 定义一个函数是可行的,但我会失去编译时类型安全性。 :-(

I am trying to write a typesafe map literal helper class in java that can generate maps of any type and have the compiler check that all given keys and values conform to the type of the map. For a map with two values there would be a function with the following signature:

public static <KEY, VALUE> Map<KEY, VALUE> make(final KEY key1,
        final VALUE value1,
        final KEY key2,
        final VALUE value2)

Now I would have expected that something like this would be possible:

    Map<Integer, Object> map = make(1, "bla", 3, 17);

However I get an compiler error:

Type mismatch: cannot convert from Map<Integer,Object&Serializable&Comparable<?>> to 
 Map<Integer,Object>

Is there a way to fix this? Of course, defining a function with signature make(Object... keysAndValues) would work, but I would loose the compile time typesafety. :-(

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

琴流音 2024-12-05 05:34:55

错误可能在这里:

Map<Integer, Object> map = make(1, "bla", 3, 17);
                                   ^^^^^     ^^

VALUE >无法从 StringInteger 推断对象

请尝试以下任一操作:

// Helping the compiler to infer Object for VALUE
Map<Integer, Object> map = make(1, (Object)"bla", 3, 17);

// Explicitly bind VALUE to Object
Map<Integer, Object> map = MyClass.<Integer, Object>make(1, "bla", 3, 17);

// If you don't need to write into "map" (as user pmnt also suggested)
Map<Integer, ?> map = make(1, "bla", 3, 17);

The error is probably here:

Map<Integer, Object> map = make(1, "bla", 3, 17);
                                   ^^^^^     ^^

VALUE > Object can't be inferred from both String and Integer

Try any of these:

// Helping the compiler to infer Object for VALUE
Map<Integer, Object> map = make(1, (Object)"bla", 3, 17);

// Explicitly bind VALUE to Object
Map<Integer, Object> map = MyClass.<Integer, Object>make(1, "bla", 3, 17);

// If you don't need to write into "map" (as user pmnt also suggested)
Map<Integer, ?> map = make(1, "bla", 3, 17);
扛刀软妹 2024-12-05 05:34:55

如果您在调用方法中修改地图的签名,您的代码将起作用:

make 无需进行任何更改

public static <A, B> Map<A, B> make(final A key1, final B value1,
        final A key2, final B value2) {
    Map<A, B> map = new HashMap<A, B>();
    map.put(key1, value1);
    map.put(key2, value2);
    return map;
}

Make 的调用方

您必须将 Map 更改为 Map

public static void main(String[] args) {

    @SuppressWarnings("unused")
    Map<String, ? extends Object> m = make("a", new Integer(1), "2", "efg");

}

编辑1:OpenJDK 1.6 + Eclipse Indigo编译器

编辑2:在构建这样的通用映射时,您必须接受在检索值时必须进行向下转换。

EDIT3:有办法解决这个问题吗?当然,用签名 make(Object...keysAndValues) 定义一个函数是可行的,但我会失去编译时类型安全性。

在某个时刻,你总是会失去编译时安全性。至少在检索方面是这样。

Your code will work if you modify the Map's signature in the calling method:

No changes required to make

public static <A, B> Map<A, B> make(final A key1, final B value1,
        final A key2, final B value2) {
    Map<A, B> map = new HashMap<A, B>();
    map.put(key1, value1);
    map.put(key2, value2);
    return map;
}

Make's caller

You must change Map<String, Object> to Map<String, ? extends Object>:

public static void main(String[] args) {

    @SuppressWarnings("unused")
    Map<String, ? extends Object> m = make("a", new Integer(1), "2", "efg");

}

EDIT1: OpenJDK 1.6 + Eclipse Indigo compiler

EDIT2: When building generic maps like that, you must accept that you have to downcast when it comes to retrieving the values.

EDIT3: Is there a way to fix this? Of course, defining a function with signature make(Object... keysAndValues) would work, but I would loose the compile time typesafety.

You will always loose compile time safety at a certain point. At least when it comes to retrieval.

伴我老 2024-12-05 05:34:55

这确实可以编译:

Map<Integer, ? extends Serializable> map = make(1, "bla", 3, 17);

这就是 Java 的泛型类型推断为您提供的功能。不是你所期望的吗?

您有几个选择,要么在方法上使用澄清符:

Map<Integer, Object> map = Util.<Integer, Object>make(1, "bla", 3, 17);

或者您可以使用没有公共父接口的对象。

Map<Integer, Object> map = make(1, "bla", 3, new Object());

This does compile:

Map<Integer, ? extends Serializable> map = make(1, "bla", 3, 17);

This is what Java's generic type inference is giving you. Not what you expected?

You have a couple of options, either use a clarifier on the method:

Map<Integer, Object> map = Util.<Integer, Object>make(1, "bla", 3, 17);

Or you can use objects that don't have a common parent interface.

Map<Integer, Object> map = make(1, "bla", 3, new Object());
南街女流氓 2024-12-05 05:34:55

编译器必须根据给定的参数“猜测”类型 KEYVALUE(存储返回值的 Map 类型为忽略)。 VALUE 的“猜测”是最严格的适合 Integer 和 String 的类型:任何实现 Comparable 和 Serialized (Object&Serialized&Comparable) 的类型。

您有两种选择:将至少一个 VALUE 转换为对象:

Map<Integer, Object> map = make(1, (Object)"bla", 3, 17);

或在映射中使用通配符

Map<Integer, ?> map = make(1, "bla", 3, 17);

The compiler has to "guess" the types KEY and VALUE from the parameters given (the types of your Map where you store the return value are ignored). The "guess" for VALUE is the strictest type fitting to both Integer and String: anything that implements Comparable and Serializable (Object&Serializable&Comparable<?>).

You have two options: casting at least one VALUE to Object:

Map<Integer, Object> map = make(1, (Object)"bla", 3, 17);

or using a wildcard in your map

Map<Integer, ?> map = make(1, "bla", 3, 17);
若无相欠,怎会相见 2024-12-05 05:34:55

String 实际上实现了 SerializableComparable 接口,而 Object 没有..所以它说的 Object 没有实现,但它的隐式 typeCasted String 却实现了...

String actually implements both Serializable and Comparable interface and Object does't.. so its saying Object does't implement but Its implicict typeCasted String does...

睫毛溺水了 2024-12-05 05:34:55

下面的解决方案看起来应该可以工作,但奇怪的是它只能在 Eclipse 编译器中工作,而不能在普通的 Java 6 编译器上工作。 8-{为什么???

方法声明非常复杂,但在创建映射时允许使用最简单的语法:

public static <KEY, AKEY extends KEY, VALUE, AVALUE extends VALUE> Map<KEY, VALUE> make2(final AKEY key1,
        final AVALUE value1,
        final AKEY key2,
        final AVALUE value2)

这里,编译器从上下文中推断

Map<Integer, Object> map = make(1, "bla", 3, 17);

KEY 应该是 Integer,VALUE 应该是 Object; AKEY 是从给定参数推断为 Integer 和 AVALUE 为 Object&Serialized&Comparable ,编译器可以验证 AKEY 符合 KEY 且 AVALUE 符合 VALUE 。

The following solution looks like it should work, but strangely it does only work in the Eclipse compiler, but not on a plain Java 6 compiler. 8-{ Why???

The method declaration is annoyingly complicated but allows the simplest syntax when creating maps:

public static <KEY, AKEY extends KEY, VALUE, AVALUE extends VALUE> Map<KEY, VALUE> make2(final AKEY key1,
        final AVALUE value1,
        final AKEY key2,
        final AVALUE value2)

Here, the compiler infers from the context in

Map<Integer, Object> map = make(1, "bla", 3, 17);

that KEY should be Integer and VALUE should be Object; AKEY is inferred from the given parameters as Integer and AVALUE as Object&Serializable&Comparable , and the compiler can verify that AKEY conforms to KEY and AVALUE to VALUE.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文