反射的好处

  • 反射不仅可以让我们获得隐藏的方法和属性,还可以让对象的实例化从编译时转化为运行时,因为我们可以通过Class.forName(“cc.abto.demo.Book”).newInstance()的方法来生成新的实例

反射的弊端

  • 反射带来的两大弊端可能就是安全和性能问题

类类型,类的动态加载

package com.zhangyu;

public class ClassTest {
    public static void main(String[] args) {
        //Test的实例对象如何表示
        Test test1 = new Test();//test1就表示出来了
        //Test这个类也是一个实例对象,Class类的实例对象
        //任何一个类都是Class的实例对象,这个实例对象有三种表示方法
        //方式1,任何一个类都有一个隐含的静态成员变量
        Class c1 = Test.class;
        //方式2,已知该类的对象通过getClass方法
        Class c2 = test1.getClass();
        //c1,c2表示了Test类的类类型class type
        System.out.println(c1 == c2);//true
        //方式3,动态加载类(编译时刻加载类是静态加载,运行时刻加载类是动态加载)
        Class c3 = null;
        try {
            c3 = Class.forName("com.zhangyu.Test");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(c2 == c3);//true
        //可以通过类的类类型来创建该类的对象实例。通过c1,c2,c3创建Test的实例
        try {
            Test test = (Test) c1.newInstance();
            test.print();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

}

class Test {
    void print(){
        System.out.println("test");
    }
}

获取方法信息、成员变量信息、构造方法信息

package com.zhangyu;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ClassUtil {
    public static void main(String[] args) {
        String s = "hello";
        printMethodInfo(s);
        printFieldInfo(s);
        printConstructorInfo(1);
    }

    /**
     * 获取成员函数信息 public
     *
     * @param object
     */
    public static void printMethodInfo(Object object) {
        //首先获取类类型
        Class<?> clazz = object.getClass();
        //获取类的名称
        System.out.println("类的名称是:" + clazz.getName());
        /**
         * 获取类中的方法
         * 每一个方法成员就是一个Method对象
         * getMethods()获取所有public方法,包括父类继承来的
         * getDeclaredMethods()获取的是该类中所有自己声明的方法(pulic、private、protect)(不包括父类继承来的)
         */
        //getMethods获取所有public方法
        Method[] methods = clazz.getMethods();
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];
            System.out.println("-----------");
            //得到方法名称
            String methodName = method.getName();
            System.out.println("方法名:" + methodName);
            //得到方法的返回值类型
            Class<?> returnType = method.getReturnType();
            System.out.println("返回值类型:" + returnType.getName());
            //获取参数类型
            Class<?>[] parameterTypes = method.getParameterTypes();
            System.out.print("参数类型:");
            for (int j = 0; j < parameterTypes.length; j++) {
                Class<?> parameterType = parameterTypes[j];
                System.out.print(parameterType.getName() + " ");
            }
            System.out.println("");
        }
    }

    /**
     * 获取成员变量信息
     * 成员变量也是对象
     * java.lang.reflect.Field
     * Field封装了关于成员变量的操作
     * getFields()方法获取的是所有的public的成员变量的信息
     * getDeclaredField()获取的是该类自己声明的成员变量的信息
     */
    public static void printFieldInfo(Object object) {
        Class<?> clazz = object.getClass();
        Field[] fields = clazz.getDeclaredFields();
        System.out.println("-----------");
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            //得到成员变量的类类型
            Class<?> classType = field.getType();
            String typeName = classType.getName();
            //得到成员变量名称、
            String fieldName = field.getName();
            System.out.println(typeName + " " + fieldName);
        }
    }

    /**
     * 获取构造方法的信息
     * getConstructors()
     * getDeclaredConstructors()
     *
     * @param object
     */
    public static void printConstructorInfo(Object object) {
        Class<?> clazz = object.getClass();
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        System.out.println("-----------");
        for (int i = 0; i < constructors.length; i++) {
            Constructor<?> constructor = constructors[i];
            System.out.print(constructor.getName() + "(");
            Class<?>[] parameterTypes = constructor.getParameterTypes();
            for (int j = 0; j < parameterTypes.length; j++) {
                Class<?> parameterType = parameterTypes[j];
                System.out.print(parameterType.getName()+",");
            }
            System.out.println(")");
        }
    }

}
类的名称是:java.lang.String
-----------
方法名:equals
返回值类型:boolean
参数类型:java.lang.Object 
-----------
方法名:length
返回值类型:int
参数类型:
-----------
方法名:toString
返回值类型:java.lang.String
参数类型:
-----------
方法名:hashCode
返回值类型:int
参数类型:
-----------
[B value
byte coder
int hash
boolean hashIsZero
long serialVersionUID
boolean COMPACT_STRINGS
[Ljava.io.ObjectStreamField; serialPersistentFields
java.util.Comparator CASE_INSENSITIVE_ORDER
byte LATIN1
byte UTF16
-----------
java.lang.Integer(java.lang.String,)
java.lang.Integer(int,)

方法的反射

  1. 如何获取某个方法?
    方法的名称和方法的参数列表才能唯一决定某个方法
  2. 方法的反射如何操作?
    method.invoke(参数列表)
package com.zhangyu;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MethodTest {
    public static void main(String[] args) {
        //获取A类中的print方法
        //print(int a, int b)
        //获取A的类类型
        A a1 = new A();
        Class<? extends A> clazz = a1.getClass();
        //获取类的信息
        //Method method = clazz.getMethod("print", new Class[]{int.class, int.class});
        try {
            System.out.println("-----------");
            Method method = clazz.getMethod("print", int.class, int.class);
            //方法的反射操作,用method对象来进行方法的调用,和a1.print的效果相同
            Object invoke = method.invoke(a1,1, 2);

            System.out.println("-----------");
            method = clazz.getMethod("print", String.class, String.class);
            //方法的反射操作,用method对象来进行方法的调用,和a1.print的效果相同
            invoke = method.invoke(a1,"hello", "world");
        } catch (NoSuchMethodException | IllegalAccessException | 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());
    }
}
-----------
3
-----------
HELLO,WORLD

通过反射了解Java泛型的本质

package com.zhangyu;

import java.lang.reflect.Method;
import java.util.ArrayList;

public class GenericsTest {
    public static void main(String[] args) {
        ArrayList list1 = new ArrayList();

        ArrayList<String> list2 = new ArrayList<>();
        list2.add("hello");
//        list2.add(1);//错误,因为限定了String类型

        //得到两个类类型
        Class c1 = list1.getClass();
        Class c2 = list2.getClass();
        System.out.println(c1 == c2);//两个类类型相同,true

        //反射的操作都是在编译之后进行的
        //c1==c2结果返回true说明编译后是去泛型化的
        //Java中集合的泛型,是防止错误输入的,只在编译阶段有效
        //我们可以用通过方法的反射来向list2中加入int类型
        Method add = null;
        try {
            add = c2.getMethod("add", Object.class);
            add.invoke(list2,"hello");
            add.invoke(list2,100);
            System.out.println(list2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
true
[hello, hello, 100]