java基础-反射

1.Class类

任何一个类都是Class的实例对象,但是Class类的构造方法是私有的,必须由jvm创建对象

1.1 获取Class类的对象

(1) 任何一个类都有一个隐含的静态成员变量

Class clazz = Foo.class;

(2) 通过已知该类的对象通过getclass()方法

Class c2 = foo.getClass();

以上的c1,c2为Foo类的类类型

也就是说万事万物都是对象,类也是对象,是Class类的实例对象,这个对象我们称为该类的类类型,一个类就是Class的一个实例对象

(3) 

Class c3 = Class.forName("com.freeht.Foo");

我们可以通过类的类类型创建该类的对象实例,可以通过c1,c2,c3创建Foo的实例对象

Foo foo1 = (Foo) c2.newInstance();

 

2.静态加载和动态加载

静态加载

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

动态加载

在运行时加载的类,通过Class.forName(...)来动态加载

上面的强制类型转换如果想要使用动态加载,那么需要写一个接口,并且强制类型转换成的类需要实现那个接口

 

3.基本数据类型都存在类类型

 

4.Class类的基本api

4.1 获取方法的信息

public class ClassUtil {

    /**
     * 打印类的信息,包括类的成员变量和信息
     * @param o 该对象所属类的信息
     */
    public static void printClassMessage(Object o) {
        //要获取类的信息,首先要获取类的类类型
        Class c = o.getClass();     //传递的是哪个子类的对象,c就是该子类的类类型
        //获取类的名称
        System.out.println("类的名称是:" + c.getName());
        //获取类的方法
        //getMethods方法获取的是所有public的函数,包括从父类继承而来的方法
        //getDeclaredMethods获取的是自己声明的方法
        Method[] methods = c.getMethods();  //c.getDeclaredMethods()
        for(int i = 0; i < methods.length; i++) {
            //得到方法的名称
            System.out.println(methods[i].getName());
            //等到返回值类型
            Class retureType = methods[i].getReturnType();
            System.out.println(retureType);
            System.out.println(methods[i].getName());
            //获取参数类型
            Class[] paramsTypes = methods[i].getParameterTypes();
            for(Class clazz : paramsTypes){
                System.out.println(clazz);
            }
        }
    }
}

4.2 获取成员变量的信息

public static void printFieldMessage(Object o) {
          Class c = o.getClass();
         /**
         * 成员变量也是对象
         * java.lang.reflect.Field
         * Field类封装了关于成员变量的信息
         * getFields()方法获取的是所有public的成员变量的信息
         * getDeclaredFields()方法获取的是自己声明的成员变量的信息
         */
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            //得到成员变量的类型的类类型
            Class fieldType = field.getClass();
            String typeName = field.getName();      //得到成员变量的名字
            String fileName = fieldType.getName();  //得到成员变量的类型
            System.out.println(typeName + fileName);
        }
}

4.3 打印构造函数的信息

    /**
     * 获取构造函数信息
     * 构造函数也是对象
     * @param o
     */
    public static void printConMessage(Object o) {
        Class c = o.getClass();
        Constructor[] constructors = c.getConstructors();       //c.getDeclaredConstructors()
        for(Constructor constructor : constructors) {
            Class[] classes = constructor.getParameterTypes();      //得到构造函数的类类型
            for (Class c1 : classes) {
                System.out.println(c1.getName());
            }
        }
    }

  

5.方法的反射

方法的名称和方法的参数列表才能决定某个列表

5.1 方法反射的操作

method.invoke(对象,参数列表)

public class MethodDemo1 {
    public static void main(String[] args) {
        //要获取print(int a, int b)
        //1.要获取一个方法就是获取类的信息,获取类的信息首先要获取类的类类型
        A a1 = new A();
        Class c1 = a1.getClass();
        /**
         * getMethod() 获得的是public的方法
         */
        try {
            //Method method = c1.getMethod("print", new Class[]{int.class, int.class});
            Method method = c1.getMethod("print", int.class, int.class);
            //方法的反射操作
            //是指method对象来进行方法调用,和a1.print()的调用相同
            //方法如果没有返回类型,那么就是null,如果有返回值类型,那么就是具体的返回值类型
            Object o = method.invoke(a1, new Object[]{10,20});
            Method method1 = c1.getMethod("print", String.class, String.class);
            Object o1 = method1.invoke(a1, "hello", "world");

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

class A{
    public void print(int a, int b) {
        System.out.println(a + b);
    }

    public void print(String a, String b) {
        System.out.println(a.toUpperCase() + b.toUpperCase());
    }
}

  

6.泛型的本质

反射的操作都是编译之后的操作

编译之后的集合是去泛型化的,也就是说java中集合泛型,是防止错误输入的,只在编译阶段有效,绕过编译就无效了

public class MethonDemo2 {
    public static void main(String[] args) {
        List list = new ArrayList();
        List<String> list1 = new ArrayList<String>();
        list1.add("hello");
        Class c1 = list.getClass();
        Class c2 = list1.getClass();
        System.out.println(c1 == c2);
        try {
            Method method = c1.getMethod("add", Object.class);
            method.invoke(list1, 100);  //绕过了编译就绕过了泛型
            System.out.println(list1.size());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

 

posted @ 2020-04-12 21:11  豆莱浆渠  阅读(159)  评论(0编辑  收藏  举报