Java 反射

反射的概念
  • 程序中一般的对象的类型都是在编译期就确定下来的,而Java反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的,反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁
反射的作用
  • Java反射框架主要提供以下功能:
  1. 在运行时判断对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时判断任意一个类的成员变量的方法(甚至私有方法)
  4. 在运行时调用任意一个对象的方法
反射的主要用途
  • 反射最重要的用途是开发各种应用框架:
  1. Spring系列
  2. Hibernate,MyBatis等ORM框架
  3. ...
详解反射机制
类的组成

一个类组成通常包括以下几个部分:类名、构造器、方法、成员变量、注解等,所以为了能够实例化任意一个类的对象,需要能够获得类的全部组成。JDK中的Reflection包提供了以下对应类供我们获取类的各个对应组成部分:Class Constructor Method Field等

  • Class
  1. Class类是一个特殊的类,因为在每个对象加载到JVM后,都会产生一个Class的对象,用来跟踪Java对象代表的类,Class对象在JVm中只存在唯一一份
  2. 在Java中,万事万物皆对象,类也是对象,任何一个类都是java.lang.Class类的实例对象

示例代码一:

package com.whut.java;

class Foo{
    public void print(){
        System.out.println("foo...");
    }
}

public class ClassDemo {
    public static void main(String[] args){
        // 任何一个类都是Class类的实例对象,获取Class实例对象有三种方式

        // 1. 类名.class
        Class clazz = Foo.class;
        System.out.println(clazz.getName());

        // 2. 对象.getClass()
        Foo foo = new Foo();
        Class clazz2 = foo.getClass();
        System.out.println(clazz2.getName());

        // 3. Class.forName(完整类名)
        Class clazz3 = null;
        try {
            clazz3 = Class.forName("com.whut.java.Foo");
            System.out.println(clazz3.getName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // Class对象在JVM中只存在唯一一份
        System.out.println(clazz == clazz2);
        System.out.println(clazz2 == clazz3);
    }
}

复制代码

示例代码二:

package com.whut.java;

public class ClassDemo2 {
    public static void main(String[] args){
        Class clazz = int.class;
        System.out.println(clazz.getName());

        Class clazz2 = Integer.class;
        System.out.println(clazz2.getName());

        // 基本数据类型和对应包装类的Class对象不相同
        System.out.println(clazz == clazz2);

        Class clazz3 = void.class;
        System.out.println(clazz3.getName());

        /**
         output:
         int
         java.lang.Integer
         false
         void
         */
    }
}

复制代码
类的加载
  • Java中类的加载有两种方式:静态加载类和动态加载类
  1. 静态加载类:使用new关键词,编译时加载需要的类,如果类不存在则无法通过编译
  2. 动态加载类:编译时不会检查需要的类是否存在,在运行时才会检查
  • Method
    Method类:一个方法就是一个Method实例对象
    代码示例:
package com.whut.java;

import java.lang.reflect.Method;

public class ClassMethod {
    public static void main(String[] args){
        String str = "hello";
        printClassMethodMessage(str);
    }

    public static void printClassMethodMessage(Object object){
        // 获取类名
        Class clazz = object.getClass();
        System.out.println("class name: " + clazz.getName());

        /**
         * Method类,
         *一个成员方法就是一个Method对象
         * getMethods():获取类的所有public方法,包括从父类继承下来的方法
         * getDeclaredMethods():获取类自己声明的所有方法,不理会访问权限
         */
        Method[] methods = clazz.getMethods();
        for(Method method : methods){
            // 获取方法的返回值类型
            Class returnType = method.getReturnType();
            System.out.println("method return type:" + returnType.getName());
            // 获取方法的名称
            System.out.println("method name: " + method.getName());
            // 获取方法的所有参数
            Class[] paramTypes  = method.getParameterTypes();
            for (Class param : paramTypes ){
                System.out.println("method param type: " +param.getName());
            }
        }
    }
}


复制代码
  • Field
    一个成员变量就是一个Field对象
    示例代码:
package com.whut.java;

import java.lang.reflect.Field;

public class ClassMember {
    public static void main(String[] args){
        String str = "hello";
        printClassMemberMessage(str);
    }

    public static void printClassMemberMessage(Object object){
        // 获取类名
        Class clazz = object.getClass();
        System.out.println("class name: " + clazz.getName());

        /**
         * Field类,
         * 一个成员变量就是一个Field对象
         * getFields():获取类的所有public的成员变量
         * getDeclaredFields():获取类的所有自己声明的成员变量,不问权限
         */
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields){
            // 获取成员变量类型
            Class fieldType = field.getType();
            System.out.println("field type: " + fieldType.getName());

            // 获取成员变量名称
            String fieldName = field.getName();
            System.out.println("field name: " + fieldName);
        }
    }
}

复制代码
  • Constructor
    一个构造函数就是一个Constructor对象
    示例代码:
package com.whut.java;

import java.lang.reflect.Constructor;

public class ClassConstructor {
    public static void main(String[] args){
        String str = "hello";
        printClassConstructorMessage(str);
    }

    public static void printClassConstructorMessage(Object o){
        // 获取类名
        Class clazz = o.getClass();
        System.out.println("class name: " + clazz.getName());

        /**
         * Constructor类,
         * 构造函数也是对象,一个构造函数就是一个Constructor对象
         * getDeclaredConstructors得到所有的构造函数
         */
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for (Constructor constructor : constructors){
            // 获取构造函数的名称
            System.out.println("constructor name: " + constructor.getName());
            Class[] parameterTypes = constructor.getParameterTypes();
            for (Class param : parameterTypes){
                // 获取构造函数的参数列表类型
                System.out.println("param type: " + param.getName());
            }
        }
    }
}

复制代码
  • 方法反射
package com.whut.java;

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

public class MethodReflect {
    public static void main(String[] args){
        A a = new A();
        // 1. 要获取一个类的方法就是要获取类的信息,获取类的信息首先要获取类的类类型
        Class clazz = a.getClass();
        System.out.println("class name: " + clazz.getName());

        try {
            /**
             * 2. 获取方法
             * 方法有方法名称和参数列表决定
             * getMethod():获取的是public的方法
             * getDelcaredMethod(): 获取的是类自己声明的方法
             *
             * 方法的反射操作:
             * 方法对象(反)来调用方法(射) 和 实例对象.方法 效果完全一致
             * 方法如果有返回值,返回具体的返回值,否则返回null
             */
            Method method = clazz.getMethod("print", int.class, int.class);
            method.invoke(a, 10, 20);

            Method method1 = clazz.getMethod("print", new Class[]{String.class, String.class});
            method1.invoke(a, new String[]{"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 + b);
    }
}

复制代码

参考链接: 参考1 参考2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值