如果我使用原始类型作为参数调用泛型方法,将使用什么类型参数?

发布于 2024-12-06 19:45:44 字数 334 浏览 0 评论 0原文

我只是好奇将原始数据传递给 T 类型时生成的推断 T 类型是什么。它确实可以编译,但有一个警告。

public class GenericMethodInference {

    static <T> void test5(List<T t>){} // clause (5)

    public static void main(String [] args) {

    List e = new ArrayList<Integer>();
    test5(e);  // clause (6) // ok but with warning.

}

I'm just curious what's the generated inferred T type when passing a raw to a T type. It does compile but with a warning.

public class GenericMethodInference {

    static <T> void test5(List<T t>){} // clause (5)

    public static void main(String [] args) {

    List e = new ArrayList<Integer>();
    test5(e);  // clause (6) // ok but with warning.

}

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

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

发布评论

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

评论(5

独孤求败 2024-12-13 19:45:44

将原始类型分配给泛型类型将假定没有泛型约束(默认为对象),但会删除任何可能存在的编译时类型安全保证。

但是您不能将原始数据分配给List ,因为它已被
已删除

这里对类型擦除存在一个根本性的误解。原始类型是泛型类型的最终结果。您指定了 List,编译器会根据该类型信息进行验证,然后删除其中的 部分,根据需要从针对该类型的操作中插入对 Integer 的强制转换列表的原始类型。

这意味着这两个检索操作完全相同。

List<Integer> integerList = new ArrayList<Integer>();
integerList.add(5);

Integer i = integerList.get(0); 
Integer ii = (Integer)((List)integerList).get(0);

例如,以下内容是合法的。这只会发出警告(而不是导致编译器错误或运行时错误),因为我们正在对 Object 进行操作,并且仍在所包含类型的适当范围内。

List<Object> objects = (List)integerList;
Object value = objects.get(0);
System.out.println(value);

它将打印出 5。如果您尝试做这样的事情,类型系统会有所帮助。

List<String> badStringList = integerList;

它会给你一个编译器错误,指出存在类型不匹配。然而,直接使用原始类型将抛弃所有类型安全性,并且仅依赖于您对应该使用的正确类型的判断。如果你做错了,这会让你很容易搬起石头砸自己的脚。

List<String> badStringList = (List)integerList;
String badValue = badStringList.get(0); //ClassCastException is thrown at runtime

Assigning a raw type to a generic type will assume no generic constraint (which will default to Object) but remove any compile-time type safety guarantees that might otherwise have existed.

But you cannot assign a raw to a List <Object> since it has been
erased

It sounds like there is a fundamental misunderstanding of type erasure here. The raw type is the end result of a generic type. You specified List<Integer>, the compiler verifies against that type information and then removes the <Integer> portion of that, inserting casts to Integer as appropriate from actions against the raw type of List.

That means that these two retrieval operations are exactly the same.

List<Integer> integerList = new ArrayList<Integer>();
integerList.add(5);

Integer i = integerList.get(0); 
Integer ii = (Integer)((List)integerList).get(0);

For example, the following is legal. This only gives a warning (instead of causing a compiler error or runtime error) because we're acting on Object and are still within the appropriate bounds of the contained type.

List<Object> objects = (List)integerList;
Object value = objects.get(0);
System.out.println(value);

It will print out 5. Where the type system helps is if you try to do something like this.

List<String> badStringList = integerList;

It will give you a compiler error stating that there is a type mismatch. Using the raw type directly, however, will throw all of that type safety away and rely solely on your judgement for the correct types that should be used. This allows you to easily shoot yourself in the foot if you get it wrong.

List<String> badStringList = (List)integerList;
String badValue = badStringList.get(0); //ClassCastException is thrown at runtime
冷月断魂刀 2024-12-13 19:45:44

这样做是为了向后兼容。在泛型之前,

static void test5(List t){}

List e = ...;
test5(e);  

当泛型被引入时,他们需要泛化 List 和诸如 test5() 之类的方法,而不询问诸如 test5(e) 之类的所有用法被重写和重新编译。因此 test5(e) 必须仍然有效。

这是通过放宽类型推断规则和方法签名匹配规则来实现的。

推论:List << List 这不能在子类型意义上保持;然而推理规则只是忽略它; T 没有约束,只是选择为 Object

方法签名:List e 不是方法参数类型的子类型 List< ;Object>,但是“方法调用转换”可以接受,它允许从 ListList 的“未经检查的转换”; “未经检查的转换”会触发强制编译器警告。


这仅具有历史意义;今天没有程序员应该关心。由于显然 List 不可能成为 List 的子类型,无论 T 是什么,我们实际上应该将其视为错误,并且永远不要编写这样的代码(即使它可以编译)。 列表 e 可以工作。

This is done for backward compatibility. Before generics,

static void test5(List t){}

List e = ...;
test5(e);  

When generics was introduced, they need to generify List and methods like test5(), without asking all usages like test5(e) to be rewritten and recompiled. So test5(e) must still be valid.

This is achieved by relaxing type inference rules and method signature matching rules.

Inference: List << List<T> this can't hold in the subtyping sense; however inference rules just ignore it; T has no constraints, and simply picked to be Object

Method signature: List e is is not subtype of the method parameter type List<Object>, however it is acceptable by "method invocation conversion", which allows "unchecked conversion" from List to List<Whatever>; the "unchecked conversion" triggers the mandatory compiler warning.


This is only of historical interest; no programmer today should care. Since obviously there's no way for List to be a subtype of List<T> whatever T is, we should practically treat it as error, and never write code like that (even though it compiles). A List<?> e would work.

赠佳期 2024-12-13 19:45:44

我想说推断的类型是 Object

I would say that the inferred type would be Object

維他命╮ 2024-12-13 19:45:44
    public class GenericMethodInference {

    static <T> void test5(List<T> xx) {
        System.out.println(xx.getClass());  //class java.util.ArrayList
        System.out.println(xx.get(0).getClass()); //class java.lang.Integer
        System.out.println(xx.get(1).getClass()); //class java.lang.String
    } // clause (5)

    public static void main(String[] args) {

        List e = new ArrayList<Long>();
        e.add(1);
        e.add("2");
        test5(e); // clause (6) // ok but with warning.
    }
}

这确认了推断的类型是 Object 类型。

    public class GenericMethodInference {

    static <T> void test5(List<T> xx) {
        System.out.println(xx.getClass());  //class java.util.ArrayList
        System.out.println(xx.get(0).getClass()); //class java.lang.Integer
        System.out.println(xx.get(1).getClass()); //class java.lang.String
    } // clause (5)

    public static void main(String[] args) {

        List e = new ArrayList<Long>();
        e.add(1);
        e.add("2");
        test5(e); // clause (6) // ok but with warning.
    }
}

This confirms that the type inferred is Object type.

哥,最终变帅啦 2024-12-13 19:45:44

T 是一个通用的。它可以接受任何对象。

T is a generic one. It can accept any object.

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