zoukankan      html  css  js  c++  java
  • JAVA基础知识之JVM-——反射和泛型

    泛型和Class类

    在反射中使用泛型Class<T>可以避免强制类型转换,下面是一个简单例子,如果不使用泛型的话,需要显示转换,

     1 package aop;
     2 
     3 import java.util.Date;
     4 
     5 import javax.swing.JFrame;
     6 
     7 public class ObjectFactory {
     8     public static Object getInstance(String clsName) {
     9         try {
    10             Class cls = Class.forName(clsName);
    11             return cls.newInstance();        
    12         } catch (Exception e) {
    13             e.printStackTrace();
    14             return null;
    15         }
    16     }
    17     
    18     public static void main(String[] args) {
    19         Date d = (Date)ObjectFactory.getInstance("java.util.Date");
    20         JFrame f = (JFrame)ObjectFactory.getInstance("java.util.Date");
    21     }
    22 }

    上面的例子第19行和20行都需要将Class的newInstance返回的Object结果强制转换成目标类型,这不仅麻烦,更重要的是有些情况下无法发现错误,

    例如第20行,强制转换可以通过编译的,但是运行期间可能会报错,原因是强制将Date类型转换成JFrame类型,类型不匹配,下面是执行结果,

    1 Exception in thread "main" java.lang.ClassCastException: java.util.Date incompatible with javax.swing.JFrame
    2     at aop.ObjectFactory.main(ObjectFactory.java:20)

    下面用泛型来实现getInstance,  即  public static <T> T getInstance(Class<T> cls)

     1 package aop;
     2 
     3 import java.util.Date;
     4 
     5 import javax.swing.JFrame;
     6 
     7 public class ObjectFactory2 {
     8     public static <T> T getInstance(Class<T> cls) {
     9         try {
    10             return cls.newInstance();        
    11         } catch (Exception e) {
    12             e.printStackTrace();
    13             return null;
    14         }
    15     }
    16     
    17     public static void main(String[] args) {
    18         Date d = ObjectFactory2.getInstance(Date.class);
    19         JFrame f = ObjectFactory2.getInstance(JFrame.class);
    20     }
    21 }

    上面的第19行如果类型不符,例如写成了JFrame f = ObjectFactory2.getInstance(Date.class); , 则无法通过编译,

    必须要修改成匹配的类型才能通过编译, 很好地编码了隐形错误。

    泛型和数组

    泛型中的数组虽然也使用了泛型编程,但却没有实现泛型功能, 泛型数组的newInstance方法签名是这样的,

    1 public static Object newInstance(Class<?> componentType, int... dimensions)

    虽然上面的定义也使用了泛型,但是却没有真正实现泛型,所以这个方法返回的对象arr依然是个Object类型,要当成数组使用的话还是需要强制转换成数组类型。

    如果将上面的方法签名改成这样,

    1 public static <T> T[] newInstance(Class<T> componentType, int length)

    这样返回的arr就是个数组类型了,无需强制转换就可以当作数组用。

    下面是一个将反射(reflect)中的Array的newInstance包装成泛型之后再使用的例子,

     1 package aop;
     2 
     3 import java.lang.reflect.Array;
     4 
     5 public class MyArray {
     6     public static <T> T[] newInstance(Class<T> componentType, int length) {
     7         return (T[])Array.newInstance(componentType, length);
     8     }
     9     
    10     public static void main(String[] args) {
    11         //使用MyArry的newInstance创建数组
    12         String[] arr = MyArray.newInstance(String.class, 10);
    13         //使用MyArray的newInstance创建二维数组
    14         int[][] intArr = MyArray.newInstance(int[].class, 5);
    15         arr[5] = "天王盖地虎";
    16         intArr[1] = new int[]{23,12};
    17         System.out.println(arr[5]);
    18         System.out.println(intArr[1][1]);
    19     }
    20 }

    输出结果, 可以看到上面已经刻在无需强制转换成数组的情况下,直接将arr和intArr作为数组来使用了,

    1 天王盖地虎
    2 12

     使用反射来获取泛型信息

    通过反射可以获取指定类的成员变量, 方法是 Field f = clazz.getDeclaredField("成员变量名称");

    之后,可以用f对象获取它的类型,对于普通类型的成员变量,可以用Class<?> a = f.getType(); 方式获取

    但是对于泛型的成员变量,例如 Map<String, Integer> score; getType()只能获取原始类型,这里是Map

    如果要获取泛型类型(即尖括号里面的参数类型),

    1. 首先需要获取成员变量的泛型类型, 通过Type gType = f.getGenericType();
    2. 然后将泛型对象gType强制转换成参数化类型ParameterizedType的对象pType;  (ParameterizedType包含两个方法,getRawType(), 返回原始类型,和上面的getType一样。getActualTypeArguments(), 返回泛型参数的类型,也就是Map<String, Integer> 括号里的类型)
    3. 使用getActualTypeArguments()返回泛型信息

    下面来演示一下使用反射来获取泛型信息,

     1 package aop;
     2 
     3 
     4 import java.lang.reflect.Field;
     5 import java.lang.reflect.ParameterizedType;
     6 import java.lang.reflect.Type;
     7 import java.util.Map;
     8 
     9 public class GenericTest {
    10     private Map<String, Integer> score;
    11     public static void main(String[] args) throws Exception {
    12         Class<GenericTest> clazz = GenericTest.class;
    13         Field f = clazz.getDeclaredField("score");
    14         //getType只能取出普通类型,因此下面的a只能得到java.util.Map类型
    15         Class<?> a = f.getType();
    16         System.out.println("score的类型是: " + a);
    17         //获取泛型类型
    18         Type gType = f.getGenericType();
    19         // 如果gType类型是ParameterizedType对象
    20         if (gType instanceof ParameterizedType) {
    21             //泛型对象强制转换成参数化类型对象
    22             ParameterizedType pType = (ParameterizedType)gType;
    23             //获取原始类型,即java.util.Map
    24             Type rType = pType.getRawType();     
    25             System.out.println("原始类型: "+rType);
    26             //获取泛型括号里面参数的类型
    27             System.out.println("泛型参数类型:");
    28             Type[] tArgs = pType.getActualTypeArguments();
    29             for (int i = 0; i < tArgs.length; i++ ) {
    30                 System.out.println("第["+i+"]个参数的泛型类型是: "+tArgs[i]);
    31             }
    32         } else {
    33             System.out.println("获取泛型类型错误");
    34         }
    35     }
    36 }

    输出结果,

    1 score的类型是: interface java.util.Map
    2 原始类型: interface java.util.Map
    3 泛型参数类型:
    4 第[0]个参数的泛型类型是: class java.lang.String
    5 第[1]个参数的泛型类型是: class java.lang.Integer
  • 相关阅读:
    _allow_resetlogs_corruption打开数据库
    增量备份恢复DATAGUARD(出现gap并后续有新增数据文件,主从数据文件路径一致)
    dataguard环境破坏后采用rman备份集重新部署
    表空间数据文件迁移到另外的位置(backup as copy tablespace)
    pl/sql无法登录12c问题
    ORA-00845: MEMORY_TARGET not supported on this system
    dataguard主库添加的数据文件路径在从库不存在
    12c expdp
    表进行加密(redact)实验
    创建触发器启动pdb
  • 原文地址:https://www.cnblogs.com/fysola/p/6112706.html
Copyright © 2011-2022 走看看