java泛型的解释

本文详细探讨了Java泛型的工作原理,特别是在编译阶段的作用及其限制。通过具体示例展示了如何利用反射绕过泛型检查,并讨论了在运行时泛型的实际行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看视频的时候曾经看到过说java的泛型只是模拟出来的,只在编译阶段有效。对此很不理解,后来经过摸索发现了一点规律:

定义了泛型的限定之后,编译器会在编译阶段对实现了参数化的类型实例进行检查,例如:

ArrayList<String> al=new ArrayList<String>();
al.add(10);

这样在编译阶段他就会将这个错误检查出来,告诉你add()中的参数应该是String类型的。

后来碰到问题如何向参数化类型为String的集合中添加其他类型的数据。然后是用反射解决的:

al.getClass().getMethod("add",Object.class).invoke(al,10);

这样就可以向刚刚那个参数化类型String的集合中添加Integer型的数据了。

通过这个例子可以发现al这个对象他所对应的在内存中的加载的类型依然是ArrayLIst.class。

这个我进行了一下验证发现是的:

System.out.println(al.getClass()==ArrayList.class);

输出结果是true,也就是说声明的参数化类型为String的类型在内存中跟原始类型是同一个。

Integer i=al.get(0);

但是像上面的代码提取的时候会发现这个问题,他会在编译阶段就告诉你al.get(0),返回的是一个String。哪怕我们知道它里面装的是一个Integer,

但是通过前面的参数化类型的声明,编译器就认定了他存进去的是个String,所以返回的也是一个String,所以不能用Integer类型的变量去接受。

String str=al.get(0);
System.out.println(str);
这样用一个String类型的变量去接受了他然后将他打印出来,依然碰到问题,它报告异常:无法从Integer转换到String。这是因为str是一个String类型,打印的时候调用它的toString()方法,但是这个对象却是一个Integer的对象,他无法调用String的toString()方法。所以他JVM会将他强制转换成一个String的对象,但是他们之间没有继承关系,所以出现转换异常。所以由上我们可以直到,泛型限定的只是在编译阶段,只要能通过编译,在运行时候的内存中,我们可以将那个参数化类型当作Object来看待。


Java是一种让编程语言具有类安全性的功能,它允许在数据类(或更具体的概念,如集合类)中使用参数来表示期望的数据类。这种参数通常被标记为尖括号<>中的字母,并且被指定为T,K,V等。这种特性在Java中主要应用于类和方法。 具体来说,Java主要有以下几个用途: 1. 增强类安全性:在Java中,使用可以避免在编译时出现类错误。当你在代码中使用时,编译器会检查类是否正确,而不会等到运行时才发现错误。 2. 类擦除:在Java中,由于Java的动态类系统,在使用时会被擦除。这意味着参数的类在运行时会被替换为实际类。这使得代码更简洁,但也降低了类安全性。 3. 增强代码复用:使用可以使代码更具有可重用性。例如,你可以创建一个通用的列表或集合类,然后为它添加不同的方法来处理不同的数据类。 使用的方法通常是这样的: ```java public class Box<T> { T t; public void set(T t) { this.t = t; } public T get() { return t; } } ``` 在这个例子中,"T"就是一个参数。我们可以用不同的具体类(比如String, Integer, MyClass等)来实例化这个类。这使得Box可以适应各种不同类的数据,而不需要为每种类编写一个单独的类。 总的来说,Java是一种强大的工具,它可以帮助我们编写更安全、更可重用的代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值