java反射机制 知乎_这个是考点:Java反射机制

反射的定义

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

要获取一个类,必须先要获取到该类的字节码文件对象。而获取使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。

反射就是把java类中的各种成分映射成一个个的Java对象。

反射的作用通过反射可以使程序代码访问装载到JVM 中的类的内部信息;

获取已装载类的成员变量信息;

获取已装载类的方法;

获取已装载类的构造方法信息;

反射的应用场景

在编译时根本无法知道该对象或类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息。

Java中的两种类型:编译时类型/运行时类型。

// Person为p的编译时类型,Student为p的运行时类型Person p = new Student();

在一些极端的情况下,外部传入一个对象时,该对象的编译时类型是object,但程序又需要调用该类的 运行时类型的方法。

解决这个问题我们在编程时有两种方法解决。

我们知道传入的是类的运行时类型,就可以使用instanceof进行判断,再强制类型转换,就可以使用这个类的方法和变量。

我们不知道传入的对象的类型,也不了解该类的方法和属性,程序只能靠运行时信息来发现对象和类,这时候我们就必须使用反射。

绝大部分框架的AOP,如Spring,需要依托反射机制实现。

反射的实现

通过Class.forName

通过Class.forName()方法加载字符串,就可以得到该字符串做代表的Class对象。

例如:Class> clazz = Class.forName("java.lang.String")就可以得到String类的Class对象。值得注意的是,字符串必须是类的全名,即包名+类名。

下边的代码是Struts配置文件struts.xml中的一个action的配置。

/registeResult.jsp

/registe2.jsp

这里的class属性给出了一个类的全名的字符串,服务器是如何通过这个字符串得到类对象的呢?就是通过反射机制RegisteAction对象的。然后再去调用这个类中的默认的execute()方法。

通过类名调用class属性得到该类的Class对象

例如:Class> clazz = String.class也可以得到String类的Class对象。

调用实例的getClass()方法

例如:

Date date = new Date();

Class> clazz = date.getClass();

通过上边的两句代码就可以得到date实例的Class对象。

如果是基本类型的包装类,则可以通过调用包装类的Type属性来获得该包装类的Class对象

例如:

Class> clazz = Integer.TYPE;

无论使用哪种方法获得了Class对象,只要得到了Class对象,下来的操作方法都是相同的。

Field[] fields = clazz.getDeclaredFields();获取类中定义的属性,包括private的属性,但是不包括从父类继承下来的属性。

Method[] methods = clazz.getDeclaredMethods();获取了类中的方法,包括private的方法,但是不包括从父类继承下来的方法。

反射的步骤

获取目标对象的class,一般使用Class.forName(String clazzName);

通过class对象分别获得该类型的,构造函数,属性,方法。

通过获得的属性和方法,进行进一步操作。

反射类

反射的完成依赖了Java提供的反射类,Class,Constructor(构造器),Field(属性), Method(方法)。

Class

每一个类都有一个Class对象,每当编译一个新类就产生一个Class对象。

Class对象对应着java.lang.Class类,如果说类是对象抽象和集合的话,那么Class类就是对类的抽象和集合。

Class类没有公共的构造方法,Class对象是在类加载的时候由Java虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。

Java获取Class的三种方式

运用.class的方式来获取Class实例

对于基本数据类型的封装类,还可以采用.TYPE来获取相对应的基本数据类型的Class实例。例如,Integer.TYPE与 int.class是等效的,都是int。

利用对象调用getClass()方法获取该对象的Class实例

public class Test {

public static void main(String[] args) {

System.out.println("第一种实例化:");

System.out.println(int.class);

System.out.println(Integer.TYPE);

System.out.println("第二种实例化:");

Test test = new Test();

System.out.println(test.getClass().getName());

System.out.println(test.getClass().getSimpleName());

}

}

使用Class类的静态方法forName

使用Class类的静态方法forName(),用类的名字获取一个Class实例(static Class forName(String className) ),这种方式灵活性最高,根据类的字符串全名即可获取Class实例,可以动态加载类,框架设计经常用到。

结语

虽然反射看起来无所不能,但Java反射默认受限于Java的访问控制。

如:无法访问private私有的方法和字段,Java的安全机制不允许查看这些对象的直接值,若强制读取则抛出异常。

以上就是本篇全部内容,是很早的时候,在用反射机制做日志管理的时候写的,也是边学边总结,不是很全面或可能有错误。如果本文有任何错误或有什么看法,欢迎指出。原作者:东野啊

原文链接:这个是考点:Java反射机制

原出处:公众号

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值