反射

程序在运行阶段可以拿到某个对象的所有信息

Class类

  • Class 是 Java 中“描述一个类本身的对象”

  • JVM为每个加载的class及interface创建了对应的Class实例来保存class及interface的所有信息;

  • 获取一个class对应的Class实例后,就可以获取该class的所有信息;

  • 通过class实例获取class信息的过程就叫“反射”
    获取class实例Class的方法

方法1:通过类的静态方法

    Class<?> clazz =  String.class;

方法2:通过对象实例的getClass()方法

    String word = "Hollo,World!";
    Class<?> clazz = word.getClass();

方法3:知道完整类名的情况下使用Class.forName()来获取

    class<?> clazz =  Class.forName("java.lang.String");

访问字段

通过Class实例获取字段(成员变量)的常用方法

Field getField(name):根据字段名获取某个public的field(包括父类)

Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)

Field[] getFields():获取所有public的field(包括父类)

Field[] getDeclaredFields():获取当前类的所有field(不包括父类)

:::warning

注意:对于使用Field getDeclaredField(name)``Field[] getDeclaredFields()或获取的private 修饰的Field在获取详细的内容时需要先设置 setAccessible(true)

:::

获取字段内容

public class Main {
    public static void main(String[] args) throws Exception {
        User user = new User("小明",18);
        Class<?> clazz =  user.getClass();
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(user,"李白");
        int modifiers = name.getModifiers();
        //System.out.println(Modifier.isPublic(modifiers));
        Object o = name.get(user);
        System.out.println(o);
    }
}

调用方法

Method getMethod(name, Class...):获取某个public的Method(包括父类)

Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)

Method[] getMethods():获取所有public的Method(包括父类)

Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)

(name, Class...)中的Class...代表参数的Class

public class Main {
    public static void main(String[] args) throws Exception {
        User user = new User("小明",18);

        Class<?> clazz =  user.getClass();
        Method getName = clazz.getDeclaredMethod("getName");
        Object result = getName.invoke(user);
        System.out.println(result);


    }
}

调用构造方法

getConstructor(Class...):获取某个public的Constructor;

getDeclaredConstructor(Class...):获取某个Constructor;

getConstructors():获取所有public的Constructor;

getDeclaredConstructors():获取所有Constructor。

通过反射获取构造器构造User对象

public class Main {
    public static void main(String[] args) throws Exception {
        Class<?> clazz =  User.class;
        Constructor<?> constructor = clazz.getConstructor(String.class,int.class);
        Object object = constructor.newInstance("小王",19);
        User u = (User)object;
        System.out.println(u.getName() + " " + u.getAge());
    }
}

获取继承关系

Class getSuperclass():获取父类类型;

Class[] getInterfaces():获取当前类实现的所有接口。

通过Class对象的isAssignableFrom()方法可以判断一个向上转型是否可以实现。
:::warning

当我们判断一个实例是否是某个类型时,正常情况下,使用instanceof操作符

:::

    //判断B的类型能否转成A A.class.isAssignableFrom(B.class)
    父类.class.isAssignableFrom(子类.class)

动态代理

可以在运行期动态创建某个interface的实例。

:::warning

不要在 invoke 里调用 proxy.xxx(),因为调用proxy.xxx()会进入invoke(),一直递归

:::

简单例子

public class Main {
    public static void main(String[] args) throws Exception {

        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                System.out.println("Hello World" + " " + args[0]);
                return null;
            }
        };
        Hello hello = (Hello)Proxy.newProxyInstance(Hello.class.getClassLoader(), new Class[]{Hello.class}, handler);
        hello.morning("李白");

    }
}
public interface Hello {
    void morning(String name);
}

动态代理的参数

    //接口的类加载器,接口Class,InvocationHandler
    Proxy.newProxyInstance(Interface.getClassLoader(), new Class[]{Hello.class}, handler)