zoukankan      html  css  js  c++  java
  • java反射简解

    1、首先一个问题,什么是类,类是不是对象?

    我们总是说我们new一个对象出来

    那么我们还没有new的时候,建造的那个java类是不是对象呢?

    它是java.lang.Class的对象

    对于反射我们首先要知道的就是什么是Class类

    java.lang.Class到底是什么,有啥用。

    首先我们要得到Class,我们有三种可以得到的方法,代码如下,c1,c2,c3就是我们需要的Class

    //任何一个类都有一个隐含的成员变量叫做calss
    Class c1 = Man.class;
            
    //通过对象的getClass方法获取class
    Class c2 = man1.getClass();
            
    //c1和c2表示了Man的类类型,也就是class type
            
    Class c3 = null;
    c3 = Class.forName("com.clazz.test.Man");

    需要知道的是类的类类型是一样的,都指的是一个,所以c1,c2,c3都是一样的。都是相等的。

    那我们现在已经拿到了Class,可以用它来干嘛呢?

    我们可以通过类的类类型直接创建一个对象,也就是说,没有new了。

    需要注意的是下面的代码中newInstance方法会调用类的无参构造方法

    //通过类的类类型创建对象。
    Man man2 = (Man) c1.newInstance();

    下面是所有的测试代码

    package com.clazz.test;
    
    /**
     * Class类的描述测试
     * @author XX
     *
     */
    public class ClazzDemo1 {
    
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException
        {
            //Man是java.lang.Class的对象
            //任何一个类都是class类的实例对象
            
            Man man1 = new Man();
            //man1是Man类的实例对象
            
            //任何一个类都有一个隐含的成员变量叫做calss
            Class c1 = Man.class;
            
            //通过对象的getClass方法获取class
            Class c2 = man1.getClass();
            
            //c1和c2表示了Man的类类型,也就是class type
            
            Class c3 = null;
            c3 = Class.forName("com.clazz.test.Man");
            
            //通过类的类类型创建对象。
            Man man2 = (Man) c1.newInstance();
        }
    }
    
    
    class Man{
        public Man(){
            System.out.println("创建了这个类");
        }
    }

    2、静态加载类和动态加载类

    new创建对象是静态加载,在编译时刻就需要加载所有可能使用到的类。

    通过动态加载类,可以在运行时刻加载使用到的类

    也就是我们的c3使用的方法

    package com.clazz.test;
    
    public class DynamicLoadClass {
    
        public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException
        {
            //静态加载类,直接new出对象,调用方法,一般都是使用这个,但是一旦没有Student类,编译就会报错
            //而且如果需要使用老师对象那么代码需要重新写过很多,要把new对象重新写过,
            Student s1 = new Student();
            s1.speck();
            
            //通过动态加载类,编译时刻,无论学生还是老师类存不存在,都可以编译通过,只有当运行时刻才进行加载
            //好处是如果你需要新增一个类,直接实现IPeople接口,只要forName的名字正确即可,而且这个名字可以
            //作为一个参数传进来然后进行修改
            Class c1 = Class.forName("com.clazz.test.Student");
            IPeople p1 = (IPeople) c1.newInstance();
            p1.speck();
        }
    }
    package com.clazz.test;
    
    public class Student implements IPeople{
    
        public void speck()
        {
            System.out.println("我是学生");
        }
    }
    package com.clazz.test;
    
    public interface IPeople {
    
        public void speck();
    }

    3通过反射拿到一个类的所有的信息

    下面这个就是反射最基本的用法,也是反射最神奇的地方

    package com.clazz.util;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    import com.clazz.test.Student;
    
    /**
     * calss类的测试工具类
     * @author XX
     *
     */
    public class ClazzUtil {
    
        public static void main(String args[])
        {
            //通过反射能拿到类的所有方法信息
            printAll(new Student());
        }
        
        /**
         * 获取这个对象的信息并打印出来
         */
        public static void printAll(Object object)
        {
            Class c = object.getClass();
            
            //打印该类的名字
            System.out.println("类的名字" + c.getName());
            
            //打印该类的所有方法(包含从父类继承来的)(不包含私有的方法)
            Method[] ms = c.getMethods();
            for (Method method : ms) {
                System.out.println("方法:" + method.getName() + "          方法的返回值:" + method.getReturnType().getName());
                
                //获取方法的参数
                Class<?>[] par = method.getParameterTypes();
                for (Class<?> class1 : par) {
                    System.out.println("方法的入参:" + class1.getName());
                }
            }
            
            //打印该类的方法(不包含从父类继承来的)包含私有方法
            Method[] ms2 = c.getDeclaredMethods();
            for (Method method : ms2) {
                System.out.println("方法1:" + method.getName() + "          方法的返回值:" + method.getReturnType().getName());
            }
            
            //获取成员变量(不包含私有变量)
            Field[] fs = c.getFields();
            for (Field field : fs) {
                System.out.println("成员变量: " + field.getName());
            }
            
            //获取成员变量(包含私有变量)
            Field[] fs1 = c.getDeclaredFields();
            for (Field field : fs1) {
                System.out.println("成员变量: " + field.getName());
            }
            
            //获取构造方法
            Constructor[] con = c.getDeclaredConstructors();
            for (Constructor constructor : con) {
                System.out.println("构造方法:" + constructor.getName());
            }
        }
    }
    package com.clazz.test;
    
    public class Student implements IPeople{
    
        private int a1;
        public int a12;
        
        public void speck()
        {
            System.out.println("我是学生");
        }
        
        private void speck2()
        {
            System.out.println("我是学生");
        }
    }

    4通过反射调用类的方法

    这个是反射的应用,通过反射调用一个类的方法

    package com.clazz.test;
    
    import java.lang.reflect.Method;
    
    /**
     * @author XX
     *
     */
    public class ReflectMethod {
    
        public static void main(String args[]) throws Exception
        {
            A a = new A();
            
            Class c = a.getClass();
            
            Method m = c.getMethod("add", int.class,int.class);
            
            System.out.println(m.invoke(a, 1,2));
        }
    }
    
    
    class A{
        public int add(int a,int b)
        {
            return a+b;
        }
        private int minus(int a,int b)
        {
            return a-b;
        }
    }

     

    5利用反射解释ArrayList的泛型

    package com.clazz.test;
    
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    
    public class ArrayListRflect {
    
        
        public static void main(String args[]) throws Exception
        {
            /**
             * 下面的代码用于证明,在ArrayList中,泛型只在编译之前有效,编译之后泛型对于list的限制
             * 是无效的。利用反射就能绕过编译这个阶段在ArrayList添加本不属于该泛型的值
             */
            ArrayList<String> list = new ArrayList<String>();
            
            list.add("哈哈");
            //list.add(1);如果原来这么写,编译会报错的
            
            //那么怎么在list放个int的1呢?
            
            //获取list的类类型
            Class c = list.getClass();
            //通过类类型拿到方法
            Method m = c.getMethod("add",Object.class);
            //通过反射调用方法
            m.invoke(list, 1);
            
            System.out.println(list);
            //结果为:[哈哈, 1]
            
            //所以证明了上面的观点,也同时很好的证明了反射多神奇
        }
    }
  • 相关阅读:
    第八周编程总结
    第五周课程总结&试验报告三
    第四周课程总结&实验报告二
    第三周课程总结&实验报告一
    课程学习总结
    2019春第四次课程设计实验报告
    2019春 总结作业
    2019春第三次课程设计实验报告
    2019春第二次课程设计实验报告
    2019春第一次课程设计实验报告
  • 原文地址:https://www.cnblogs.com/linkstar/p/5744444.html
Copyright © 2011-2022 走看看