c语言sscanf函数的用法是什么
252
2023-04-08
深入分析JAVA 反射和泛型
从 JDK5 以后,java 的 Class 类增加了泛型功能,从而允许使用泛型来限制 Class 类,例如,String.class 的类型实际上是 Class
泛型和 Class 类
使用 Class
public class CrazyitObjectFactory {
public static Object getInstance(String clsName) {
try {
// 创建指定类对应的Class对象
Class cls = Class.forName(clsName);
// 返回使用该Class对象所创建的实例
return cls.newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
上面程序中两行粗体字代码根据指定的字符串类型创建了一个新对象,但这个对象的类型是 Object,因此当需要使用 Crhttp://azyitObjectFactory 的 getInstance() 方法来创建对象时,将会看到如下代码:
// 获取实例后需要强制类型转换
Date d = (Date)Crazyit.getInstance("java.util.Date");
甚至出现如下代码:
JFrame f = (JFrame)Crazyit.getInstance("java.util.Date");
上面代码在编译时不会有任何问题,但运行时将抛出 ClassCastException 异常,因为程序试图将一个 Date 对象转换成 JFrame 对象。
如果将上面的 CrazyitObjectFactory 工厂类改写成使用泛型后的 Class,就可以避免这种情况。
public class CrazyitObjectFactory2 {
public static
try {
return cls.newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
// 获取实例后无须类型转换
Date d = CrazyitObjectFactory2.getInstance(Date.class);
JFrame f = CrazyitObjectFactory2.getInstance(JFrame.class);
}
}
在上面程序的 getInstance() 方法中传入一个 Class
前面介绍使用 Array 类来创建数组时,曾经看到如下代码:
// 使用 Array 的 newInstance 方法来创建一个数组
Object arr = Array.newInstance(String.class, 10);
对于上面的代码其实使用并不是非常方便,因为 newInstance() 方法返回的确实是一个 String[] 数组,而不是简单的 Object 对象。如果需要将对象当成 String[] 数组使用,则必须使用强制类型转换——这是不安全的操作。
为了示范泛型的优势,可以对 Array 的 newInstance() 方法进行包装。
public class CrazyitArray {
// 对Array的newInstance方法进行包装
@SuppressWarnings("unchecked")
public static
return (T[]) Array.newInstance(componentType, length); // ①
}
public static void main(String[] args) {
// 使用CrazyitArray的newInstance()创建一维数组
String[] arr = CrazyitArray.newInstance(String.class, 10);
// 使用CrazyitArray的newInstance()创建二维数组
// 在这种情况下,只要设置数组元素的类型是int[]即可。
int[][] intArr = CrazyitArray.newInstance(int[].class, 5);
arr[5] = "疯狂Java讲义";
// intArr是二维数组,初始化该数组的第二个数组元素
// 二维数组的元素必须是一维数组
intArr[1] = new int[] { 23, 12 };
System.out.println(arr[5]);
System.out.println(intArr[1][1]);
}
}
上面程序中粗体字代码定义的 newInstance() 方法对 Array 类提供的 newInstance() 方法进行了包装,将方法签名改成了 public static
提示:程序在①行代码处将会有一个 unchecked 编译警告,所以程序使用了 @SuppressWarnings 来抑制这个警告信息。
使用反射来获取泛型信息
通过指定类对应的 Class 对象,可以获得该类里包含的所有成员变量,不管该成员变量是使用 private 修饰,还是使用 public 修饰。获得了成员变量对应的 Field 对象后,就可以很容易地获得该成员变量的数据类型,即使用如下代码即可获得指定成员变量的类型。
// 获取成员变量 f 的类型
Class> a = f.getType();
但这种方式只对普通类型的成员变量有效。如果该成员变量的类型是有泛型类型的类型,如 Map
为了http://获得指定成员变量的泛型类型,应先使用如下方法来获取该成员变量的泛型类型。
http://
// 获得成员变量 f 的泛型类型
Type gType = f.getGenericType();
然后将 Type 对象强制类型转换为 ParameterizedType 对象,ParameterizedType 代表被参数化的类型,也就是增加了泛型限制的类型。ParameterizedType 类提供了如下两个方法。
getRawType():返回没有泛型信息的原始类型。
getActualTypeArguments():返回泛型参数的类型。
下面是一个获取泛型类型的完整程序。
public class GenericTest {
private Map
public static void main(String[] args) throws Exception {
Class
Field f = clazz.getDeclaredField("score");
// 直接使用getType()取出的类型只对普通类型的成员变量有效
Class> a = f.getType();
// 下面将看到仅输出java.util.Map
System.out.println("score的类型是:" + a);
// 获得成员变量f的泛型类型
Type gType = f.getGenericType();
// 如果gType类型是ParameterizedType对象
if (gType instanceof ParameterizedType) {
// 强制类型转换
ParameterizedType pType = (ParameterizedType) gType;
// 获取原始类型
Type rType = pType.getRawType();
System.out.println("原始类型是:" + rType);
// 取得泛型类型的泛型参数
Type[] tArgs = pType.getActualTypeArguments();
System.out.println("泛型信息是:");
for (int i = 0; i < tArgs.length; i++) {
System.out.println("第" + i + "个泛型类型是:" + tArgs[i]);
}
} else {
System.out.println("获取泛型类型出错!");
}
}
}
上面程序中的粗体字代码就是取得泛型类型的关键代码。运行上面程序,将看到如下运行结果:
score的类型是:interface java.util.Map
原始类型是:interface java.util.Map
泛型信息是:
第0个泛型类型是:class java.lang.String
第1个泛型类型是:class java.lang.Integer
从上面的运行结果可以看出,使用 getType() 方法只能获取普通类型的成员变量的数据类型:对于增加了泛型的成员变量,应该使用 getGenericType() 方法来取得其类型。
提示:Type 也是 java.lang.reflect 包下的一个接口,该接口代表所有类型的公共高级接口,Class 是 Type 接口的实现类。Type 包括原始类型、参数化类型、数组类型、类型变量和基本类型等。
以上就是深入分析JAVA 反射和泛型的详细内容,更多关于JAVA 反射和泛型的资料请关注我们其它相关文章!
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~