JAVA反射

Java-反射

1.反射的概述:

反射(Reflection),Java反射机制是在运行状态时,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java的反射机制。

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

Class c = Class.forName(“Java.lang.String”)

流程示意图:

302415386d4040322023995504e552d

举例理解反射:

假设一个人意外死亡,法医需要解剖来查看他的死因,以及他的属性(年龄,体重,呼吸道,各类器官…)

因为人已经死亡,我们解剖的过程也可以形象的理解为“反射”。得到完整的“包类名称”就相当于解剖获得器官的过程。

反射相关的主要API:

  • java.lang.Class: 代表一个类
  • java.lang.reflect.Method: 代表类的方法
  • java.lang.reflect.Field: 代表类的成员变量
  • java.lang.reflect.Constructor: 代表类的构造器

Class类的常用方法:

方法名功能
static ClassforName(String name)返回指定类名name的Class对象
newInstance()在内存中生成一个实例
getName()返回当前Class对象所表示的实体(类,接口,数组类或void)的名称
Class getSuperClass()返回当前Class对象的父类的Class对象
Class[] getinterfaces()获取当前Class对象的接口
ClassLoader getClassLoader()返回该类的类加载器
Field[] getDeclaredFields返回Field对象的一个数组
Method getMethed(String name,Class… parameterTypes)返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。

2.获取Class对象的三种方式

1: 通过该实例变量提供的getClass()方法获取:

2: 通过静态方法Class.forName()获取(要先知道class的完整类名):

3: 直接通过一个class的静态变量class获取:

如图:

1664167464019

注意

运行期间,一个类中只有一个class对象产生,图中c1,c2,c3的hashCode都是相同的。

且平常最常用的方法就是第二种。

获取运行时类的完整结构

1:获取字段

package com.ke1r.reflection;

import java.lang.reflect.Field;

//获取类的信息
public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException,NoSuchFieldException {
        Class c1 = Class.forName("com.ke1r.reflection.User");

        //获得类的名字
        System.out.println(c1.getName());//获得包名+类名
        System.out.println(c1.getSimpleName());//获得类名
        //获得类的属性
        System.out.println("=========================");
        Field[] fields = c1.getFields();//只能找到public属性

        fields = c1.getDeclaredFields();//找到全部的属性
        for (Field field : fields) {
            System.out.println(field);
        }

        //获得指定属性的值
        Field name = c1.getDeclaredField("name");
        System.out.println(name);
    }
}

运行结果:

1664175020886

所有通过Class实例的方法可以获取Field实例,getField(),getFields(),getDeclaredField(),getDeclaredFields();

此外Field实例可以读取或设置某个对象的字段,如果存在访问限制,要首先调用setAccessible(true)来访问非public字段。

2:调用方法

package com.ke1r.reflection;

import java.lang.reflect.Method;
public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("com.ke1r.reflection.User");

        //获得类的方法
        System.out.println("==================");
        Method[] methods = c1.getMethods();//获得本类及其父类的全部public方法
        for (Method method : methods) {
            System.out.println("正常的:"+method);
        }//公共的
        methods = c1.getDeclaredMethods();//获得本类的所有方法
        for (Method method : methods) {
            System.out.println("getDeclaredMethods:"+method);
        }//全部的

        //获得指定方法
        //重载
        Method getName = c1.getMethod("getName", null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);
    }
}

运行结果:

1664175785733

通过Class实例的方法可以获取Method实例:getMethod(),getMethods(),getDeclaredMethod(),getDeclaredMethods();

调用指定方法:

通过getMethod(String name,Class…parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的类型。之后使用Object invoke(Object obj,Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。若原方法声明为private,则需要在调用此invoke()方法前,显示调用方法对象的setAccessible(true)方法,则可以访问private方法。

注意:Method、Field、Constructor对象都有**setAccessible()**方法。

setAccessible()作用是启用和禁用访问安全检查的开关。

3:获得构造器方法

通过反射来创建新的实例,我们可以调用Class提供的newInstance()方法:

Person p = Person.class.newInstance();

但是它只能调用该类的public无参数构造方法。如果想要调用任意构造方法,就需要用到API提供的Constructor对象,Constructor对象和Method很类似,但是不同之处仅在于它是一个构造方法,调用结果总是返回实例。

 package com.ke1r.reflection;

import java.lang.reflect.Constructor;

public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("com.ke1r.reflection.User");
//获得指定的构造器
        System.out.println("=====================");
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        constructors = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("###"+constructor);
        }
        //获得指定的构造器
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        System.out.println("指定:"+ declaredConstructor);
    }
}

运行结果:

1664177302531

通过Class实例方法可以获取Constructor实例:

getConstructor(),getConstructors(),getDeclaredConstructor(),getDeclaredConstructors()

Java反射的优缺点

优点:

可以实现动态创建对象和编译,有很大的灵活性。

缺点:

对性能有影响,使用反射机制基本上是一种解释操作,我们可以告诉JVM我们希望做什么并且它满足我们的要求,这类操作总是慢于直接执行相同的操作。

测试效果:

1664178340553

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值