008-反射

  • JVM已经加载过这个类: 给JVM一个类名,可以通过反射得到类的具体信息。

Java Reflection

  • 反射被视为动态语言的关键,反射机制允许程序在执行期借助与Reflection API取得任何类的内部信息,并能直接操作人意对象的内部属性及方法。

Java反射机制提供的功能

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的成员变量和方法
  • 生成动态代理

Class

  • 在Object类定义了以下方法,此方法被所有子类继承:
public final Class getClass();
  • 以上的方法返回值的类型是一个Class类,此类是Java反射的源头。
  • 反射可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE都为其保留一个不变的Class类型的对象,一个Class对象包含了特定某个类的有关信息。
  • Class本身也是一个类
  • Class对象只能由系统建立对象
  • 一个类在JVM中只会有一个Class实例
  • 一个Class对象对应的是一个记载到JVM中的一个.class文件
  • 每个类的实例都会记得自己是由哪个Class实例所生成的。
  • 通过Class可以完整地得到一个类中的完整结构
  • 常用方法
    008-反射
  • 创建Class对象的几种方法
 		Person person = new Person();
        //通过类名.class创建
        Class<Person> c0 = Person.class;
        //通过类的实例对象创建
        Class<? extends Person> c1 = person.getClass();
        //通过forName()方法创建,参数是类的全路径:包名 + 类名
        Class<?> c2 = Class.forName("day_14.Person");
        //通过ClassLoader获取
        ClassLoader classLoader = this.getClass().getClassLoader();
        Class<?> c3 = classLoader.loadClass("day_14.Person");

通过反射调用类的完整结构

package day_14;

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

public class Test1 {
    public static void main(String[] args) throws Exception{
        Class<?> c1 = Class.forName("day_14.Student");
        //获取父类
        Class<?> superclass = c1.getSuperclass();
        System.out.println(superclass);
        //获取当前类实现的所有接口
        Class<?>[] interfaces = c1.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            System.out.println(anInterface);
        }
        //获取所有public类型的构造方法
        Constructor<?>[] constructors = c1.getConstructors();
        for (Constructor<?> constructor : constructors) {
            //获取方法的修饰符(return value: 1 -> public,2 -> private),以及方法名
            System.out.println(constructor.getModifiers()+" "+constructor.getName());
            //获取构造方法的参数类型
            Class<?>[] parameterTypes = constructor.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println(parameterType.getName());
            }
        }
        System.out.println("------------------------------------------");
        //获取所有类型的构造的方法,包括private类型的。
        Constructor<?>[] declaredConstructors = c1.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor.getModifiers()+" "+declaredConstructor.getName());
            //获取构造方法的参数类型
            Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println(parameterType.getName());
            }
        }
        System.out.println("------------------------------------------");
        //通过反射创建对象
        Object object = c1.newInstance();//调用无参构造
        Student stu = (Student) object;
        //调用有参数的构造方法
        Constructor<?> c = c1.getConstructor(String.class);
        Student sdu = (Student) c.newInstance("sdu");
        System.out.println(sdu.school);
        //调用私有的构造方法
        Constructor<?> constructor_private = c1.getDeclaredConstructor(String.class,int.class);
        constructor_private.setAccessible(true);
        Student stu_1 = (Student) constructor_private.newInstance("yyy", 12);
        System.out.println("------------------------------------------");
        //获取所有public类型的方法,包含父类的方法
        Method[] methods = c1.getMethods();
        //获取所有方法,包括private类型的方法,不包含父类的方法
        Method[] declaredMethods = c1.getDeclaredMethods();
        for (Method method : declaredMethods) {
            System.out.println("method name :"+method.getName()+",return type:"+method.getReturnType()+",Modifier:"+method.getModifiers());
            Class<?>[] parameterTypes = method.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println("parameter type: "+parameterType.getName());
            }
        }
        System.out.println("------------------------------------------");
        //获取public的属性
        Field[] fields = c1.getFields();
        //获取所有属性,不包括父类
        Field[] declaredFields = c1.getDeclaredFields();
        for (Field field : declaredFields) {
            System.out.println(field.getName() + " " + field.getModifiers() + " " + field.getType());
        }
        //获取类所在的包
        Package aPackage = c1.getPackage();
        System.out.println(aPackage);
        // 调用public类型的方法
        Method setInfo = c1.getMethod("setInfo", String.class, String.class);
        Constructor<?> constructor = c1.getConstructor();
        Object o = constructor.newInstance();
        setInfo.invoke(o,"yss","sdu");
        //调用私有方法
        Method test = c1.getDeclaredMethod("test", String.class);
        test.setAccessible(true);
        test.invoke(o,"yss");
        // 调用有返回值的的方法
        Method getSchool = c1.getMethod("getSchool");
        String school = (String) getSchool.invoke(o);
        System.out.println(school);
        //设置并获取public类型的属性
        Constructor<?> constructor1 = c1.getConstructor();
        Student student = (Student) constructor1.newInstance();
        Field school1 = c1.getField("school");
        school1.set(student,"sdu");
        String s = (String) school1.get(student);
        System.out.println(s);
        //获取私有属性
        Field privateField = c1.getDeclaredField("privateField");
        privateField.setAccessible(true);
        privateField.set(student,"xxx");
        String s1 = (String) privateField.get(student);
        System.out.println(s1);
    }
}

动态代理

  • Proxy:专门完成代理的操作类,是所有动态代理类的父类,通过此类为一个或多个接口动态地生成实现类。
  • 首先我们创建一个接口:
public interface ITestDemo {
    void test1();
    void test2();
}
  • 创建一个接口的实现类
public class TestDemoImpl implements ITestDemo {
    @Override
    public void test1() {
        System.out.println("执行test1()方法");
    }

    @Override
    public void test2() {
        System.out.println("执行test2()方法");
    }
}
  • 创建代理类
public class ProxyDemo implements InvocationHandler {
    //obj为被代理的对象
    Object obj;
    public ProxyDemo(Object obj)
    {
        this.obj = obj;
    }
    @Override
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName() + "开始执行!!");
        Object result = method.invoke(this.obj, args);
        System.out.println(method.getName() + "方法执行完毕");
        return result;
    }
}

  • 创建一个测试类进行测试:
public class Test2 {
    public static void main(String[] args) {
        ITestDemo testDemo = new TestDemoImpl();
        testDemo.test1();
        testDemo.test2();

        InvocationHandler handler = new ProxyDemo(testDemo);
        /*
        * parameter 1 : 代理对象的类加载器
        * parameter 2 : 被代理的对象的接口
        * parameter 3 : 代理对象
        * return type: 返回值就是成功被代理后的对象,返回的是Object类型,需要根据当时的情况进行转换
        * */
        ITestDemo iTestDemo = (ITestDemo) Proxy.newProxyInstance(testDemo.getClass().getClassLoader(), testDemo.getClass().getInterfaces(), handler);
        iTestDemo.test1();
        iTestDemo.test2();
    }
}
  • 如果一个对象想要通过Proxy.newProxyIntance方法被代理,那么这个对象的类一定要有相应的接口,就像被类中的ITestDemo接口和实现类TestDemoImpl。
上一篇:(008)从键盘输入N个学生的有关数据,然后把它们转出到磁盘文件中去并且从磁盘输出到屏幕显示。


下一篇:初学链表———单向链表创建