Java反射学习笔记

反射

描述:按自己的理解是运行时加载的类其本身可以作为java.lang.Class类的实例,通过一些方法来获取类本身的属性,方法,构造方法,注解等所有类的要素。

类的加载器

类加载器的作用,就是把class文件装进虚拟机。一共有三种加载器:

  1. 系统类加载器进行加载:加载自定义类
  2. 扩展类加载器:加载的是jre/lib/ext目录下的扩展包
  3. 引导类加载器:主要负责加载java的核心类库,无法加载自定义类的,且无法获取。
@Test
public void test1(){
    //对于自定义类,使用系统类加载器进行加载
    ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
    System.out.println(classLoader);
    //调用系统类加载器的getParent():获取扩展类加载器
    ClassLoader classLoader1 = classLoader.getParent();
    System.out.println(classLoader1);
    //调用扩展类加载器的getParent():无法获取引导类加载器
    //引导类加载器主要负责加载java的核心类库,无法加载自定义类的。
    ClassLoader classLoader2 = classLoader1.getParent();
    System.out.println(classLoader2); // null

    ClassLoader classLoader3 = String.class.getClassLoader();
    System.out.println(classLoader3); // null
}
  • 使用类加载器读取配置文件
    与之前通过流读取配置文件将比不同的是读取文件默认的相对路径
@Test
public void test2() throws Exception {

    Properties pros =  new Properties();
    //此时的文件默认在当前的module下。
    //读取配置文件的方式一:
    //FileInputStream fis = new FileInputStream("jdbc.properties");
    //FileInputStream fis = new FileInputStream("src\\jdbc1.properties");
    //pros.load(fis);

    //读取配置文件的方式二:使用ClassLoader
    //配置文件默认识别为:当前module的src下
    ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
    InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
    pros.load(is);

    String user = pros.getProperty("user");
    String password = pros.getProperty("password");
    System.out.println("user = " + user + ",password = " + password);
}

java.lang.Class

类的加载方式

  1. 类的加载过程:
    程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。
  2. Class的实例就对应着一个运行时类
  3. 加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式
    来获取此运行时类
package com.test.java;
@MyAnnotation(value="hi")
public class Person extends Creature<String> implements Comparable<String>,MyInterface{
    private String name;
    int age;
    public int id;

    public Person(){}

    @MyAnnotation(value="abc")
    private Person(String name){
        this.name = name;
    }

     Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    @MyAnnotation
    private String show(String nation){
        System.out.println("我的国籍是:" + nation);
        return nation;
    }

    public String display(String interests,int age) throws NullPointerException,ClassCastException{
        return interests + age;
    }

    @Override
    public void info() {
        System.out.println("我是一个人");
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }

    private static void showDesc(){
        System.out.println("我是一个可爱的人");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }
}
@Test
public void test3() throws ClassNotFoundException {
    //方式一:调用运行时类的属性:.class
    Class clazz1 = Person.class;
    System.out.println(clazz1);
    //方式二:通过运行时类的对象,调用getClass()
    Person p1 = new Person();
    Class clazz2 = p1.getClass();
    System.out.println(clazz2);

    //方式三:调用Class的静态方法:forName(String classPath)
    Class clazz3 = Class.forName("test.java.Person");
    //clazz3 = Class.forName("java.lang.String");
    System.out.println(clazz3);

    System.out.println(clazz1 == clazz2);
    System.out.println(clazz1 == clazz3);

    //方式四:使用类的加载器:ClassLoader
    ClassLoader classLoader = ReflectionTest.class.getClassLoader();
    Class clazz4 = classLoader.loadClass("test.java.Person");
    System.out.println(clazz4);

    System.out.println(clazz1 == clazz4);   // true
}

通过反射创建类实例

  • 一般为了通用性都使用newInstance()来创建实例
    1. 运行时类必须提供空参的构造器
    2. 空参的构造器的访问权限得够。通常,设置为public。
@Test
public void test1() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
    Class<Person> clazz = Person.class;
    // Person obj = clazz.newInstance(); java9之后舍弃
    Person obj = clazz.getDeclaredConstructor().newInstance();
    System.out.println(obj);
}

常用方法

方法描述
public reflect.Field getDeclaredField(String name)获取运行时类中指定变量名的属性
public reflect.Method getDeclaredMethod(String name,Class<?>… parameterTypes)获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
@Test
public void testField1() throws Exception {
    Class clazz = Person.class;
    //创建运行时类的对象
    Person p = (Person) clazz.newInstance();
    //1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
    Field name = clazz.getDeclaredField("name");
    //2.保证当前属性是可访问的
    name.setAccessible(true);
    //3.获取、设置指定对象的此属性值
    name.set(p,"Tom");
    System.out.println(name.get(p));
}

@Test
public void testMethod() throws Exception {

    Class clazz = Person.class;

    //创建运行时类的对象
    Person p = (Person) clazz.newInstance();

    /*
    1.获取指定的某个方法
    getDeclaredMethod():参数1 :指明获取的方法的名称  参数2:指明获取的方法的形参列表
     */
    Method show = clazz.getDeclaredMethod("show", String.class);
    //2.保证当前方法是可访问的
    show.setAccessible(true);

    /*
    3. 调用方法的invoke():参数1:方法的调用者  参数2:给方法形参赋值的实参
    invoke()的返回值即为对应类中调用的方法的返回值。
     */
    Object returnValue = show.invoke(p,"CHN");
    System.out.println(returnValue);

    System.out.println("*************如何调用静态方法*****************");
    // private static void showDesc()
    Method showDesc = clazz.getDeclaredMethod("showDesc");
    showDesc.setAccessible(true);
    //如果调用的运行时类中的方法没有返回值,则此invoke()返回null
    //Object returnVal = showDesc.invoke(null);
    Object returnVal = showDesc.invoke(Person.class);
    System.out.println(returnVal);//null
}

@Test
public void testConstructor() throws Exception {
    Class clazz = Person.class;

    //private Person(String name)
    /*
    1.获取指定的构造器
    getDeclaredConstructor():参数:指明构造器的参数列表
     */
    Constructor constructor = clazz.getDeclaredConstructor(String.class);

    //2.保证此构造器是可访问的
    constructor.setAccessible(true);

    //3.调用此构造器创建运行时类的对象
    Person per = (Person) constructor.newInstance("Tom");
    System.out.println(per);
}

获取类中元素

Field类获取属性

方法描述
public reflect.Field[] getFields()获取当前运行时类及其父类中声明为public访问权限的属性
public reflect.Field[] getDeclaredFields()获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
@Test
public void test1(){

    Class clazz = Person.class;
    //获取属性结构
    Field[] fields = clazz.getFields();
    for(Field f : fields){
        System.out.println(f);
    }
    System.out.println();

    Field[] declaredFields = clazz.getDeclaredFields();
    for(Field f : declaredFields){
        System.out.println(f);
    }
}
//权限修饰符  数据类型 变量名
@Test
public void test2(){
    Class clazz = Person.class;
    Field[] declaredFields = clazz.getDeclaredFields();
    for(Field f : declaredFields){
        //1.权限修饰符
        int modifier = f.getModifiers();
        System.out.print(Modifier.toString(modifier) + "\t");

        //2.数据类型
        Class type = f.getType();
        System.out.print(type.getName() + "\t");

        //3.变量名
        String fName = f.getName();
        System.out.print(fName);
        System.out.println();
    }
}

Method获取方法

方法描述
public reflect.Method[] getMethods()获取当前运行时类及其所有父类中声明为public权限的方法
public reflect.Method[] getDeclaredMethods()获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
@Test
public void test1(){
    Class clazz = Person.class;

    Method[] methods = clazz.getMethods();
    for(Method m : methods){
        System.out.println(m);
    }
    System.out.println();
    Method[] declaredMethods = clazz.getDeclaredMethods();
    for(Method m : declaredMethods){
        System.out.println(m);
    }
}

// 权限修饰符  返回值类型  方法名(参数类型1 形参名1,...) throws XxxException{}
@Test
public void test2(){
    Class clazz = Person.class;
    Method[] declaredMethods = clazz.getDeclaredMethods();
    for(Method m : declaredMethods){
        //1.获取方法声明的注解
        Annotation[] annos = m.getAnnotations();
        for(Annotation a : annos){
            System.out.println(a);
        }

        //2.权限修饰符
        System.out.print(Modifier.toString(m.getModifiers()) + "\t");

        //3.返回值类型
        System.out.print(m.getReturnType().getName() + "\t");

        //4.方法名
        System.out.print(m.getName());
        System.out.print("(");

        //5.形参列表
        Class[] parameterTypes = m.getParameterTypes();
        if(!(parameterTypes == null && parameterTypes.length == 0)){
            for(int i = 0;i < parameterTypes.length;i++){
                if(i == parameterTypes.length - 1){
                    System.out.print(parameterTypes[i].getName() + " args_" + i);
                    break;
                }
                System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
            }
        }

        System.out.print(")");
        //6.抛出的异常
        Class[] exceptionTypes = m.getExceptionTypes();
        if(exceptionTypes.length > 0){
            System.out.print("throws ");
            for(int i = 0;i < exceptionTypes.length;i++){
                if(i == exceptionTypes.length - 1){
                    System.out.print(exceptionTypes[i].getName());
                    break;
                }
                System.out.print(exceptionTypes[i].getName() + ",");
            }
        }
        System.out.println();
    }
}

其他元素获取

public class OtherTest {

    /*
    获取构造器结构
     */
    @Test
    public void test1(){

        Class clazz = Person.class;
        //getConstructors():获取当前运行时类中声明为public的构造器
        Constructor[] constructors = clazz.getConstructors();
        for(Constructor c : constructors){
            System.out.println(c);
        }

        System.out.println();
        //getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        for(Constructor c : declaredConstructors){
            System.out.println(c);
        }

    }

    /*
    获取运行时类的父类
     */
    @Test
    public void test2(){
        Class clazz = Person.class;
        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);
    }

    /*
    获取运行时类的带泛型的父类
     */
    @Test
    public void test3(){
        Class clazz = Person.class;
        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);
    }

    /*
    获取运行时类的带泛型的父类的泛型
     */
    @Test
    public void test4(){
        Class clazz = Person.class;

        Type genericSuperclass = clazz.getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) genericSuperclass;
        //获取泛型类型
        Type[] actualTypeArguments = paramType.getActualTypeArguments();
        System.out.println(((Class)actualTypeArguments[0]).getName());
    }

    /*
    获取运行时类实现的接口
     */
    @Test
    public void test5(){
        Class clazz = Person.class;

        Class[] interfaces = clazz.getInterfaces();
        for(Class c : interfaces){
            System.out.println(c);
        }

        System.out.println();
        //获取运行时类的父类实现的接口
        Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
        for(Class c : interfaces1){
            System.out.println(c);
        }
    }
    /*
        获取运行时类所在的包

     */
    @Test
    public void test6(){
        Class clazz = Person.class;

        Package pack = clazz.getPackage();
        System.out.println(pack);
    }

    /*
        获取运行时类声明的注解
     */
    @Test
    public void test7(){
        Class clazz = Person.class;
        Annotation[] annotations = clazz.getAnnotations();
        for(Annotation annos : annotations){
            System.out.println(annos);
        }
    }
}

动态代理中反射的使用

使用代理实现动态代理,即在运行时创建自己所需要的代理类

interface Human{

    String breathe();
    void eat(String food);
}

//被代理类
class SuperMan implements Human{

    @Override
    public String breathe() {
        return "超人需要呼吸";
    }

    @Override
    public void eat(String food) {
        System.out.println("超人不吃" + food);
    }
}

// 该类提供被代理类的公用方法
class HumanUtil{

    public void method1(){
        System.out.println("====================通用方法一====================");
    }

    public void method2(){
        System.out.println("====================通用方法二====================");
    }
}

// 所有代理类的统一模板,可以用于代理任意的被代理类
class ProxyFactory{
    //调用此方法,返回一个代理类的对象。解决问题一
    public static Object getProxyInstance(Object obj){//obj:被代理类的对象
        // 自定义类,需要实现java.lang.reflect.InvocationHandler接口
        MyInvocationHandler handler = new MyInvocationHandler();
        
        // 绑定被代理类
        handler.bind(obj);
        
        // 通过java.lang.reflect.Proxy类动态返回代理类对象实例,需要自定义参数handler
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
    }

}

class MyInvocationHandler implements InvocationHandler{

    private Object obj;//需要使用被代理类的对象进行赋值,不再拘泥于某一种代理类了

    public void bind(Object obj){
        this.obj = obj;
    }

    //当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()
    //将被代理类要执行的方法a的功能就声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        HumanUtil util = new HumanUtil();
        util.method1();

        //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
        //obj:被代理类的对象
        Object returnValue = method.invoke(obj,args);

        util.method2();

        //上述方法的返回值就作为当前类中的invoke()的返回值。
        return returnValue;
    }
}

public class ProxyTest {

    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        //proxyInstance:代理类的对象,实际生成的不是Human类,需要类型强转
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
        //当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
        String str = proxyInstance.breathe();
        System.out.println(str);
        proxyInstance.eat("汉堡");

        System.out.println("***********也可以利用ProxyFactory创建一个其他代理类**********");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值