美文网首页Java世界
Java类加载与反射

Java类加载与反射

作者: Cool_Pomelo | 来源:发表于2020-01-16 16:34 被阅读0次

    Java类加载与反射

    类加载、连接、初始化

    JVM和类

    当运行某个Java程序时,将会启动一个Java虚拟机进程,不管Java程序里面多么复杂,都处于该Java虚拟机进程里面。

    当Java程序运行结束,JVM进程结束,该进程在内存中的状态将丢失

    
    public class A {
    
        // 定义该类的类变量
        public static int a = 6;
    
        
    }
    
    

    接下来创建A类的实例

    public class ATest1 {
    
        public static void main(String[] args)
        {
            // 创建A类的实例
            A a = new A();
            // 让a实例的类变量a的值自加
            a.a ++;
            System.out.println(a.a);
        }
    
    
    }
    
    

    下面这个也进行同样操作

    public class ATest2 {
    
        public static void main(String[] args) {
    
            // 创建A类的实例
            A b = new A();
            // 输出b实例的类变量a的值
            System.out.println(b.a);
    
        }
    }
    
    

    当运行第二个ATest2时,程序再次创建了A对象,并输出a的值,为6,这是因为运行ATest1和ATest2是两次运行JVM进程,第一次JVM结束后,对A类的修改全部丢失

    类加载

    当主动使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始化三个步骤来对该类进行初始化

    类加载是将类的class文件读入内存,并为之创建一个java.lang.Class对象

    类的加载由类加载器完成,类加载器通常由JVM提供

    类连接

    当类被加载后,系统为之生成一个对应的Class对象,接着进入连接阶段,类连接又分为:

    • 验证

    • 准备

    • 解析

    类初始化

    虚拟机负责对类进行初始化,主要是对类变量进行初始化

    public class Test {
    
        static
        {
            // 使用静态初始化块为变量b指定出初始值
            b = 6;
            System.out.println("----------");
        }
        // 声明变量a时指定初始值
        static int a = 5;
        static int b = 9;         // ①
        static int c;
        public static void main(String[] args)
        {
            System.out.println(Test.b);
        }
    }
    
    

    类初始化时机

    当Java程序首次通过下面6钟方式来使用某个类或接口,系统就会初始化该类或接口

    • 创建类实例(通过new操作符、反射、反序列化)

    • 调用某个类的类方法(静态方法)

    • 访问某个类或接口的类变量

    • 反射强制创建

    • 初始化某个类的子类

    • 直接使用java.exe运行某个主类

    class MyTest
    {
        static
        {
            System.out.println("静态初始化块...");
        }
        // 使用一个字符串直接量为static final的类变量赋值
        static final String compileConstant = "Java";
    }
    public class CompileConstantTest
    {
        public static void main(String[] args)
        {
            // 访问、输出MyTest中的compileConstant类变量
            System.out.println(MyTest.compileConstant);   // ①
        }
    }
    
    
    

    System.out.println(MyTest.compileConstant)不会导致初始化MyTest类

    类加载器

    类加载器负责将.class文件加载到内存,并为之生成对应的java.lang.Class对象

    类加载机制

    类加载器负责加载所有类,系统为载入内存的类生成实例,一旦一个类被载入JVM,同一个类就不会被再次载入

    JVM启动,会形成三个类加载器组成的初始类加载器层次结构

    • 根类加载器

    • 扩展类加载器

    • 系统类加载器
    
    public class ClassLoaderPropTest {
        public static void main(String[] args)
                throws IOException
        {
            // 获取系统类加载器
            ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
            System.out.println("系统类加载器:" + systemLoader);
            /*
            获取系统类加载器的加载路径——通常由CLASSPATH环境变量指定
            如果操作系统没有指定CLASSPATH环境变量,默认以当前路径作为
            系统类加载器的加载路径
            */
            Enumeration<URL> em1 = systemLoader.getResources("");
            while(em1.hasMoreElements())
            {
                System.out.println(em1.nextElement());
            }
            // 获取系统类加载器的父类加载器:得到扩展类加载器
            ClassLoader extensionLader = systemLoader.getParent();
            System.out.println("扩展类加载器:" + extensionLader);
            System.out.println("扩展类加载器的加载路径:"
                    + System.getProperty("java.ext.dirs"));
            System.out.println("扩展类加载器的parent: "
                    + extensionLader.getParent());
        }
    }
    

    反射

    Java中许多对象在运行时都会出现两种类型

    • 编译时类型

    • 运行时类型

    有时我们需要在运行时发现对象和类的真实信息

    • 假设在编译和运行时都完全知道了类型的具体信息,这样可以先使用instanceof运算符进行判断,再进行强制类型转换
    • 编译时无法预知该对象和类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息,这就要使用反射了

    获取Class对象

    每个类被加载后,系统会为该类生成一个对应的Class对象,通过该Class对象就可以访问到JVM中的这个类,获取Class对象有三种方式:

    • Class类的forName()静态方法,传入字符串参数

    • 调用某个类的class属性来获取,如Person.class将会返回Person类对应的class对象

    • 调用某个对象的getClass()

    从Class获取信息

    例子:

    
    // 定义可重复注解
    @Repeatable(Annos.class)
    @interface Anno {}
    @Retention(value= RetentionPolicy.RUNTIME)
    @interface Annos {
        Anno[] value();
    }
    // 使用4个注解修饰该类
    @SuppressWarnings(value="unchecked")
    @Deprecated
    // 使用重复注解修饰该类
    @Anno
    @Anno
    public class ClassTest
    {
        // 为该类定义一个私有的构造器
        private ClassTest()
        {
        }
        // 定义一个有参数的构造器
        public ClassTest(String name)
        {
            System.out.println("执行有参数的构造器");
        }
        // 定义一个无参数的info方法
        public void info()
        {
            System.out.println("执行无参数的info方法");
        }
        // 定义一个有参数的info方法
        public void info(String str)
        {
            System.out.println("执行有参数的info方法"
                    + ",其str参数值:" + str);
        }
        // 定义一个测试用的内部类
        class Inner
        {
        }
    
    
        public static void main(String[] args)
                throws Exception
        {
            // 下面代码可以获取ClassTest对应的Class
            Class<ClassTest> clazz = ClassTest.class;
            // 获取该Class对象所对应类的全部构造器
            Constructor[] ctors = clazz.getDeclaredConstructors();
            System.out.println("ClassTest的全部构造器如下:");
            for (Constructor c : ctors)
            {
                System.out.println(c);
            }
    
    
            System.out.println("");
            System.out.println("======================================================");
            System.out.println("");
    
    
    
            // 获取该Class对象所对应类的全部public构造器
            Constructor[] publicCtors = clazz.getConstructors();
            System.out.println("ClassTest的全部public构造器如下:");
            for (Constructor c : publicCtors)
            {
                System.out.println(c);
            }
    
    
            System.out.println("");
            System.out.println("======================================================");
            System.out.println("");
    
    
    
            // 获取该Class对象所对应类的全部public方法
            Method[] mtds = clazz.getMethods();
            System.out.println("ClassTest的全部public方法如下:");
            for (Method md : mtds)
            {
                System.out.println(md);
            }
    
    
            System.out.println("");
            System.out.println("======================================================");
            System.out.println("");
    
    
            // 获取该Class对象所对应类的指定方法
            System.out.println("ClassTest里带一个字符串参数的info()方法为:"
                    + clazz.getMethod("info" , String.class));
    
    
    
            System.out.println("");
            System.out.println("======================================================");
            System.out.println("");
    
    
    
            // 获取该Class对象所对应类的上的全部注解
            Annotation[] anns = clazz.getAnnotations();
            System.out.println("ClassTest的全部Annotation如下:");
            for (Annotation an : anns)
            {
                System.out.println(an);
            }
    
            System.out.println("");
            System.out.println("======================================================");
            System.out.println("");
    
    
            System.out.println("该Class元素上的@SuppressWarnings注解为:"
                    + Arrays.toString(clazz.getAnnotationsByType(SuppressWarnings.class)));
    
            System.out.println("");
            System.out.println("======================================================");
            System.out.println("");
    
    
            System.out.println("该Class元素上的@Anno注解为:"
                    + Arrays.toString(clazz.getAnnotationsByType(Anno.class)));
    
            System.out.println("");
            System.out.println("======================================================");
            System.out.println("");
    
    
            // 获取该Class对象所对应类的全部内部类
            Class<?>[] inners = clazz.getDeclaredClasses();
            System.out.println("ClassTest的全部内部类如下:");
            for (Class c : inners)
            {
                System.out.println(c);
            }
    
    
            System.out.println("");
            System.out.println("======================================================");
            System.out.println("");
    
    
            // 使用Class.forName方法加载ClassTest的Inner内部类
            Class inClazz = Class.forName("C_2.c_2_3.ClassTest$Inner");
            // 通过getDeclaringClass()访问该类所在的外部类
            System.out.println("inClazz对应类的外部类为:" +
                    inClazz.getDeclaringClass());
    
    
            System.out.println("");
            System.out.println("======================================================");
            System.out.println("");
    
    
            System.out.println("ClassTest的包为:" + clazz.getPackage());
    
            System.out.println("");
            System.out.println("======================================================");
            System.out.println("");
    
    
            System.out.println("ClassTest的父类为:" + clazz.getSuperclass());
    
            System.out.println("");
            System.out.println("======================================================");
            System.out.println("");
        }
    }
    
    

    Java 8 新增方法参数反射

    
    class Test_1
    {
        public void replace(String str, List<String> list){}
    }
    public class MethodParameterTest
    {
        public static void main(String[] args)throws Exception
        {
            // 获取String的类
            Class<Test_1> clazz = Test_1.class;
    
    
            // 获取String类的带两个参数的replace()方法
            Method replace = clazz.getMethod("replace"
                    , String.class, List.class);
    
    
            // 获取指定方法的参数个数
            System.out.println("replace方法参数个数:" + replace.getParameterCount());
    
    
            // 获取replace的所有参数信息
            Parameter[] parameters = replace.getParameters();
    
    
            int index = 1;
            // 遍历所有参数
            for (Parameter p : parameters)
            {
                if (p.isNamePresent())
                {
                    System.out.println("---第" + index++ + "个参数信息---");
                    System.out.println("参数名:" + p.getName());
                    System.out.println("形参类型:" + p.getType());
                    System.out.println("泛型类型:" + p.getParameterizedType());
                }
            }
        }
    }
    
    

    使用反射生成并操作对象

    创建对象

    通过反射生成对象需要先使用Class对象获取指定的Constructor对象,再用Constructor对象的newInstance()创建该Class对象对应类的实例

    public class ObjectPoolFactory {
    
        // 定义一个对象池,前面是对象名,后面是实际对象
        private Map<String ,Object> objectPool = new HashMap<>();
        // 定义一个创建对象的方法
        // 该方法只要传入一个字符串类名,程序可以根据该类名生成Java对象
        private Object createObject(String clazzName)
                throws Exception
                , IllegalAccessException , ClassNotFoundException
        {
            // 根据字符串来获取对应的Class对象
            Class<?> clazz = Class.forName(clazzName);
            // 使用clazz对应类的默认构造器创建实例
            return clazz.getConstructor().newInstance();
        }
        // 该方法根据指定文件来初始化对象池
        // 它会根据配置文件来创建对象
        public void initPool(String fileName)
                throws InstantiationException
                , IllegalAccessException ,ClassNotFoundException
        {
            try(
                    FileInputStream fis = new FileInputStream(fileName))
            {
                Properties props = new Properties();
                props.load(fis);
                for (String name : props.stringPropertyNames())
                {
                    // 每取出一对key-value对,就根据value创建一个对象
                    // 调用createObject()创建对象,并将对象添加到对象池中
                    objectPool.put(name ,
                            createObject(props.getProperty(name)));
                }
            }
            catch (Exception ex)
            {
                System.out.println("读取" + fileName + "异常");
            }
        }
        public Object getObject(String name)
        {
            // 从objectPool中取出指定name对应的对象
            return objectPool.get(name);
        }
        public static void main(String[] args)
                throws Exception
        {
            ObjectPoolFactory pf = new ObjectPoolFactory();
            pf.initPool("obj.txt");
            System.out.println(pf.getObject("a"));      // ①
            System.out.println(pf.getObject("b"));      // ②
        }
    }
    
    
    

    调用方法

    获取某个类对应的Class对象后,就可以通过该Class对象的getMethods()获取全部方法

    Method里面有一个invoke()方法:

    Object invoke(Object obj,Object...args);

    obj是执行方法的主调,args是执行该方法时传入该方法的实参

    
    public class ExtendedObjectPoolFactory {
    
    
        // 定义一个对象池,前面是对象名,后面是实际对象
        private Map<String ,Object> objectPool = new HashMap<>();
        private Properties config = new Properties();
        // 从指定属性文件中初始化Properties对象
        public void init(String fileName)
        {
            try(
                    FileInputStream fis = new FileInputStream(fileName))
            {
                config.load(fis);
            }
            catch (IOException ex)
            {
                System.out.println("读取" + fileName + "异常");
            }
        }
        // 定义一个创建对象的方法
        // 该方法只要传入一个字符串类名,程序可以根据该类名生成Java对象
        private Object createObject(String clazzName)
                throws Exception
        {
            // 根据字符串来获取对应的Class对象
            Class<?> clazz =Class.forName(clazzName);
            // 使用clazz对应类的默认构造器创建实例
            return clazz.getConstructor().newInstance();
        }
        // 该方法根据指定文件来初始化对象池
        // 它会根据配置文件来创建对象
        public void initPool()throws Exception
        {
            for (String name : config.stringPropertyNames())
            {
                // 每取出一个key-value对,如果key中不包含百分号(%)
                // 这就表明是根据value来创建一个对象
                // 调用createObject创建对象,并将对象添加到对象池中
                if (!name.contains("%"))
                {
                    objectPool.put(name ,
                            createObject(config.getProperty(name)));
                }
            }
        }
        // 该方法将会根据属性文件来调用指定对象的setter方法
        public void initProperty()throws InvocationTargetException
                ,IllegalAccessException,NoSuchMethodException
        {
            for (String name : config.stringPropertyNames())
            {
                // 每取出一对key-value对,如果key中包含百分号(%)
                // 即可认为该key用于控制调用对象的setter方法设置值
                // %前半为对象名字,后半控制setter方法名
                if (name.contains("%"))
                {
                    // 将配置文件中的key按%分割
                    String[] objAndProp = name.split("%");
                    // 取出调用setter方法的参数值
                    Object target = getObject(objAndProp[0]);
                    // 获取setter方法名:set + "首字母大写" + 剩下部分
                    String mtdName = "set" +
                            objAndProp[1].substring(0 , 1).toUpperCase()
                            + objAndProp[1].substring(1);
                    // 通过target的getClass()获取它的实现类所对应的Class对象
                    Class<?> targetClass = target.getClass();
                    // 获取希望调用的setter方法
                    Method mtd = targetClass.getMethod(mtdName , String.class);
                    // 通过Method的invoke方法执行setter方法
                    // 将config.getProperty(name)的值作为调用setter方法的参数
                    mtd.invoke(target , config.getProperty(name));
                }
            }
        }
        public Object getObject(String name)
        {
            // 从objectPool中取出指定name对应的对象
            return objectPool.get(name);
        }
        public static void main(String[] args)
                throws Exception
        {
            ExtendedObjectPoolFactory epf = new ExtendedObjectPoolFactory();
            epf.init("extObj.txt");
            epf.initPool();
            epf.initProperty();
            System.out.println(epf.getObject("a"));
        }
    }
    
    

    访问成员变量值

    通过Class对象的getFields()可以获取该类全部成员变量

    
    class Person
    {
        private String name;
        private int age;
        public String toString()
        {
            return "Person[name:" + name +
                    " , age:" + age + " ]";
        }
    }
    public class FieldTest
    {
        public static void main(String[] args)
                throws Exception
        {
            // 创建一个Person对象
            Person p = new Person();
            // 获取Person类对应的Class对象
            Class<Person> personClazz = Person.class;
            // 获取Person的名为name的成员变量
            // 使用getDeclaredField()方法表明可获取各种访问控制符的成员变量
            Field nameField = personClazz.getDeclaredField("name");
            // 设置通过反射访问该成员变量时取消访问权限检查
            nameField.setAccessible(true);
            // 调用set()方法为p对象的name成员变量设置值
            nameField.set(p , "Yeeku.H.Lee");
            // 获取Person类名为age的成员变量
            Field ageField = personClazz.getDeclaredField("age");
            // 设置通过反射访问该成员变量时取消访问权限检查
            ageField.setAccessible(true);
            // 调用setInt()方法为p对象的age成员变量设置值
            ageField.setInt(p , 30);
            System.out.println(p);
        }
    }
    
    

    操作数组

    java.lang.reflect下有一个Array类,Array对象可以代表所有数组,可以使用Array动态创建数组

    
    public class ArrayTest1 {
    
        public static void main(String[] args) {
    
            try
            {
                // 创建一个元素类型为String ,长度为10的数组
                Object arr = Array.newInstance(String.class, 10);
                // 依次为arr数组中index为5、6的元素赋值
                Array.set(arr, 5, "Java");
                Array.set(arr, 6, "Java EE");
                // 依次取出arr数组中index为5、6的元素的值
                Object book1 = Array.get(arr , 5);
                Object book2 = Array.get(arr , 6);
                // 输出arr数组中index为5、6的元素
                System.out.println(book1);
                System.out.println(book2);
            }
            catch (Throwable e)
            {
                System.err.println(e);
            }
    
        }
    }
    
    

    下面创建一个三维数组

    
    public class ArrayTest2 {
    
        public static void main(String[] args) {
    /*
              创建一个三维数组。
              根据前面介绍数组时讲的:三维数组也是一维数组,
              是数组元素是二维数组的一维数组,
              因此可以认为arr是长度为3的一维数组
            */
            Object arr = Array.newInstance(String.class, 3, 4, 10);
            // 获取arr数组中index为2的元素,该元素应该是二维数组
            Object arrObj = Array.get(arr, 2);
            // 使用Array为二维数组的数组元素赋值。二维数组的数组元素是一维数组,
            // 所以传入Array的set()方法的第三个参数是一维数组。
            Array.set(arrObj , 2 , new String[]
                    {
                            "Java",
                            "Java EE"
                    });
            // 获取arrObj数组中index为3的元素,该元素应该是一维数组。
            Object anArr  = Array.get(arrObj, 3);
            Array.set(anArr , 8  , "Android");
            // 将arr强制类型转换为三维数组
            String[][][] cast = (String[][][])arr;
            // 获取cast三维数组中指定元素的值
            System.out.println(cast[2][3][8]);
            System.out.println(cast[2][2][0]);
            System.out.println(cast[2][2][1]);
    
    
        }
    }
    
    
    

    动态代理

    java.lang.reflect提供了一个Proxy类和一个InvocationHandler接口

    用Proxy和InvocationHandler创建动态代理

    Proxy是所有动态代理的父类,可以使用它创建动态代理类以及动态代理实例

    Proxy提供了下面两个方法创建动态代理类以及动态代理实例

    • static Class < ? > getProxyClass ( Cl assLoader loader , Class < ? > . . .
      interfaces ) 返回实现指定接口的代理类
    • staticObject newProxyInstance ( ClassLoader loader , Class < ? > [ ]
      interfaces , InvocationHandler handler ) 构造实现指定接口的代理类的一个新实例 所有方法会调用给定处理器对象的 invoke 方法

    系统生成的每个代理对象都有一个与之关联的InvocationHandler对象

    例子:

    interface Person
    {
        void walk();
        void sayHello(String name);
    }
    class MyInvokationHandler implements InvocationHandler
    {
        /*
        执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法
        其中:
        proxy:代表动态代理对象
        method:代表正在执行的方法
        args:代表调用目标方法时传入的实参。
        */
        public Object invoke(Object proxy, Method method, Object[] args)
        {
            System.out.println("----正在执行的方法:" + method);
            if (args != null)
            {
                System.out.println("下面是执行该方法时传入的实参为:");
                for (Object val : args)
                {
                    System.out.println(val);
                }
            }
            else
            {
                System.out.println("调用该方法没有实参!");
            }
            return null;
        }
    }
    public class ProxyTest
    {
        public static void main(String[] args)
                throws Exception
        {
            // 创建一个InvocationHandler对象
            InvocationHandler handler = new MyInvokationHandler();
            // 使用指定的InvocationHandler来生成一个动态代理对象
            Person p = (Person) Proxy.newProxyInstance(Person.class.getClassLoader()
                    , new Class[]{Person.class}, handler);
            // 调用动态代理对象的walk()和sayHello()方法
            p.walk();
            p.sayHello("孙悟空");
        }
    }
    
    

    动态代理和AOP

    假设有三个模块需要用到一个公共的代码段,我们可以把该公共代码段定义成一个方法,然后让这三个模块直接调用就可以了,但是这三个模块又和一个特定的方法耦合了,最好的情况就是模块可以使用到这段公共代码,但又不需要在三个模块中以硬编码的方式直接调用这段公共代码,这个时候就可以使用动态代理了

    先上一个Dog接口

    public interface Dog {
    
        // info方法声明
        void info();
        // run方法声明
        void run();
    
    
    }
    
    

    再来一个猎狗实现类

    public class GunDog implements Dog{
    
        // 实现info()方法,仅仅打印一个字符串
        public void info()
        {
            System.out.println("我是一只猎狗");
        }
        // 实现run()方法,仅仅打印一个字符串
        public void run()
        {
            System.out.println("我奔跑迅速");
        }
    
    
    }
    
    
    

    现在需求来了,假设info和run就是前面例子中的三个模块中的两个,我们想在这两个方法中实现一段公共代码,但又不想以硬编码方式直接调用,怎么做呢?

    假设下面这个就是需要插入的公共代码

    
    public class DogUtil {
    
        // 第一个拦截器方法
        public void method1()
        {
            System.out.println("=====模拟第一个通用方法=====");
        }
        // 第二个拦截器方法
        public void method2()
        {
            System.out.println("=====模拟通用方法二=====");
        }
    
        
    }
    

    关键实现:

    public class MyInvokationHandler implements InvocationHandler {
    
        // 需要被代理的对象
        private Object target;
        public void setTarget(Object target)
        {
            this.target = target;
        }
        // 执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Exception
        {
            DogUtil du = new DogUtil();
            // 执行DogUtil对象中的method1。
            du.method1();
            // 以target作为主调来执行method方法
            Object result = method.invoke(target , args);
            // 执行DogUtil对象中的method2。
            du.method2();
            return result;
        }
    }
    
    
    

    接下来:

    
    public class MyProxyFactory {
    
        // 为指定target生成动态代理对象
        public static Object getProxy(Object target)
                throws Exception
        {
            // 创建一个MyInvokationHandler对象
            MyInvokationHandler handler =
                    new MyInvokationHandler();
            // 为MyInvokationHandler设置target对象
            handler.setTarget(target);
            // 创建、并返回一个动态代理
            return Proxy.newProxyInstance(target.getClass().getClassLoader()
                    , target.getClass().getInterfaces() , handler);
        }
    }
    
    

    测试:

    
    public class Test {
    
        public static void main(String[] args)
                throws Exception
        {
            // 创建一个原始的GunDog对象,作为target
            Dog target = new GunDog();
            // 以指定的target来创建动态代理
            Dog dog = (Dog)MyProxyFactory.getProxy(target);
            dog.info();
            dog.run();
        }
    }
    
    

    dog对象实际是动态代理对象,只是该动态代理对象也实现了Dog接口

    反射与泛型

    从Java5开始允许使用泛型来限制Class类,如:String.class的类型实际上就是CLass< Sring >

    泛型与Class类

    使用Class< T >可以避免强制类型转换

    下面创建一个简单对象工厂,该对象工厂可以根据指定类来提供该类的实例

    
    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;
            }
        }
    }
    

    将上面的改写成使用泛型的Class:

    public class CrazyitObjectFactory2 {
    
        public static <T> T getInstance(Class<T> cls)
        {
            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);
        }
    }
    
    

    对Array的newInstance()进行包装

    public class CrazyitArray {
    
        // 对Array的newInstance方法进行包装
        @SuppressWarnings("unchecked")
        public static <T> T[] newInstance(Class<T> componentType, int length)
        {
            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]);
        }
    }
    
    

    反射获取泛型信息

    public class GenericTest {
    
        private Map<String , Integer> score;
        public static void main(String[] args)
                throws Exception
        {
            Class<GenericTest> clazz = GenericTest.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("获取泛型类型出错!");
            }
        }
    
    }
    
    

    相关文章

      网友评论

        本文标题:Java类加载与反射

        本文链接:https://www.haomeiwen.com/subject/zmofzctx.html