【Java基础知识4】反射

一、反射机制

Java反射机制是指在程序的运行过程中,对于任意一个类,都能够知道它的所有属性和方法;对于任意一个对象,都能够知道调用它的任意属性和方法,这种动态获取信息以及动态调用对象方法的功能称为JAVA语言的反射机制

二、反射的核心内容

反射的核心内容是 JVM 在运行时动态加载类或调用方法/访问属性,不需要事先知道运行对象是谁

举例说明:

一般情况下,我们在使用某个类时必定知道它是什么类,是用来做什么的。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作

//实例化对象
Apple apple = new Apple();
//调用方法
apple.setPrice(4);

而反射则是一开始并不知道我们要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象,这时候,需要我们使用 JDK 提供的反射 API 进行反射调用:

//获取类的 Class 对象实例
Class clz = Class.forName("com.demo.reflect.Apple");
//获取方法的 Method 对象
Method method = clz.getMethod("setPrice", int.class);
//根据 Class 对象实例获取 Constructor 对象
Constructor constructor = clz.getConstructor();
//使用 Constructor 对象的 newInstance 方法获取反射类对象
Object object = constructor.newInstance();
//利用 invoke 方法调用方法
method.invoke(object, 4);

三、反射的底层原理

众所周知,Java的Object 类,是所有Java 类的父类,其内声明了hashCode()、equals()、clone()、toString()、getClass()等方法,其中就包括getClass()方法。

当一个class被加载,或当类加载器(class loader)的defineClass()方法被JVM调用时,JVM 便自动产生一个Class 对象。

四、反射的主要功能

  • 在运行时判断任意一个对象所属的类

  • 在运行时构造任意一个类的对象

  • 在运行时判断任意一个类所有的成员变量和方法

  • 在运行时调用任意一个对象的方法

    注:运行时,而不是编译时

五、反射的主要用途

  • 反编译 .class---->.java;

  • 通过反射机制访问Java对象的属性、方法、构造方法等;

  • 当我们在使用IDEA或者Eclipse等开发工具的时候,当我们实例化对象后,并想调用它的属性和方法时,一按点号,编译器就会自动列出它的属性和方法,这里就是用到了反射机制;

  • 反射最重要的用途就是开发各种通用框架,很多框架(比如 Spring)都是配置化的(比如通过 XML 文件配置 Bean),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射,运行时动态加载需要加载的对象。

六、反射常用API

  • Java.lang.Class

  • Java.lang.reflect.Constructor

  • Java.lang.reflect.Field

  • Java.lang.reflect.Method

  • Java.lang.reflect.Modifier

七、反射的基本运用

1.获取Class对象

  • 调用运行时类的属性:.class

前提:若已知具体的类,通过类的class属性获取,该方法最为安全可靠, 程序性能最高
示例: Class clazz1 = String.class;
  • 通过运行时类的对象,调用getClass()

前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
示例:
Student  student = new Student();
Class<? extends Student> c1 = student.getClass();
  • 调用Class的静态方法:forName(String classPath)

前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName() 获取,可能抛出ClassNotFoundException
示例: Class clazz = Class.forName(“java.lang.String”);
  • 使用类的加载器:ClassLoader

示例:
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass("reflect.Teacher");

2.判断是否为某个类的实例

一般可以通过使用instanceof 关键字来判断是否为某个类的实例,当然也可以通过反射Class对象中的isInstance()来判断是否为某个类的实例

public static void main(String[] args) {
        // 通过反射Class.isInstance判断
        String reflect = "reflect";
        Class<String> stringClass = String.class;
        boolean instance = stringClass.isInstance(reflect);
        System.out.println(instance); // true

        // 通过instanceof关键字判断
        boolean result = reflect instanceof String;
        System.out.println(result);  // true
}

3.创建实例

  • 使用Class对象的newInstance()方法来创建Class对象对应类的实例。
Class<?> c = String.class;
Object str = c.newInstance();
  • 先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。
//获取String所对应的Class对象
Class<?> c = String.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
Object obj = constructor.newInstance("reflect");
System.out.println(obj);

4.获取属性

方法作用
public Field[] getFields()返回此Class对象所表示的类或接口的publicField
public Field[] getDeclaredFields()返回此Class对象所表示的类或接口的全部Field
public int getModifiers()以整数形式返回此Field的修饰符
public Class<?> getType()得到Field的属性类型
public String getName()返回Field的名称
    @Test
    public void demo(){

        Class clazz = ReflectDemo.class;

        //获取属性结构
        //getFields():获取当前运行时类及其父类中声明为public访问权限的属性
        Field[] fields = clazz.getFields();
        for(Field f : fields){
            System.out.println(f);
        }
        System.out.println();

        //getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field f : declaredFields){
            System.out.println(f);
        }
    }

    //权限修饰符  数据类型 变量名
    @Test
    public void demo2(){
        Class clazz = ReflectDemo.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();
        }
    }
}

5.获取方法

方法作用
public Method[] getMethods()返回此Class对象所表示的类或接口的public的方法
public Method[] getDeclaredMethods()返回此Class对象所表示的类或接口的全部方法
public Class<?> getReturnType()取得全部的返回值
public Class<?>[] getParameterTypes()取得全部的参数
public int getModifiers()取得修饰符
public Class<?>[] getExceptionTypes()取得异常信息
    @Test
    public void demo(){

        Class clazz = ReflectDemo.class;

        //getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
        Method[] methods = clazz.getMethods();
        for(Method m : methods){
            System.out.println(m);
        }
        System.out.println();
        //getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for(Method m : declaredMethods){
            System.out.println(m);
        }
    }
  /*
    @Xxxx
    权限修饰符  返回值类型  方法名(参数类型1 形参名1,...) throws XxxException{}
     */
    @Test
    public void demo2(){
        Class clazz = ReflectDemo.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();
        }



    }
}

6.获取构造器

方法作用
public Constructor<T>[] getConstructors()返回此 Class 对象所表示的类的所有public构造方法。
public Constructor<T>[] getDeclaredConstructors()返回此 Class 对象表示的类声明的所有构造方法。
public int getModifiers()取得修饰符
public String getName()取得方法名称
public Class<?>[] getParameterTypes()取得参数的类型
    /*
    获取构造器结构

     */
    @Test
    public void demo(){

        Class clazz = ReflectDemo.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 demo2(){
        Class clazz = ReflectDemo.class;

        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);
    }

    /*
    获取运行时类的带泛型的父类

     */
    @Test
    public void demo3(){
        Class clazz = ReflectDemo.class;
        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);
    }

    /*
    获取运行时类的带泛型的父类的泛型


    代码:逻辑性代码  vs 功能性代码
     */
    @Test
    public void demo4(){
        Class clazz = ReflectDemo.class;

        Type genericSuperclass = clazz.getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) genericSuperclass;
        //获取泛型类型
        Type[] actualTypeArguments = paramType.getActualTypeArguments();
        //System.out.println(actualTypeArguments[0].getTypeName());
        System.out.println(((Class)actualTypeArguments[0]).getName());
    }
    /*
    获取运行时类实现的接口
     */
    @Test
    public void demo5(){
        Class clazz = ReflectDemo.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 demo6(){
        Class clazz = ReflectDemo.class;

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

    /*
        获取运行时类声明的注解

     */
    @Test
    public void demo7(){
        Class clazz = ReflectDemo.class;

        Annotation[] annotations = clazz.getAnnotations();
        for(Annotation annos : annotations){
            System.out.println(annos);
        }
    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值