天天看点

Java基础篇:反射机制详解

目录

​​一、什么是反射​​

​​二、为什么反射这项技术会出现​​

​​三、反射的原理​​

​​类加载机制与双亲委派模型​​

​​四、反射的优缺点​​

​​五、反射的用途​​

​​六、反射机制常用的类​​

​七、反射的基本使用​

​​1、获得class对象​​

​​2、判断一个对象是否为某个类的实例​​

​​3、创建实例:通过反射来生成对象主要有两种方法​​

​​4、通过反射获取构造方法并使用​​

​​例子​​

​​测试​​

​​5、获取成员变量并调用​​

​​6、获取成员方法并调用​​

​​7、反射入口main方法​​

​​8、利用反射创建数组​​

​​9、反射方法的其他使用--通过反射运行配置文件内容​​

​​10、反射方法的其他使用--通过反射越过泛型检查​​

​​本文参考自​​

​​大佬博客地址​​

​​推荐阅读​​

java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是jvm得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到jvm。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

下图是类的正常加载过程、反射原理与class对象:

class对象的由来是将.class文件读入内存,并为之创建一个class对象

Java基础篇:反射机制详解
​​javascript:void(0)​​

优点:

在运行时获得类的各种内容,进行反编译,对于java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

缺点:

反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;

反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

1、反编译:.class-->.java

2、通过反射机制访问java对象的属性,方法,构造方法等

3、开发时在使用ide,比如ecplise时,当在编辑器中输入一个对象或者类,并想调用它的属性和方法时,一按点号,编译器就会自动列出它的属性或者方法,这里就是用到反射。

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

5、例如,在使用strut2框架的开发过程中,一般会在struts.xml里去配置action

比如我们请求login.action时,那么strutsprepareandexecutefilter就会去解析struts.xml文件,从action中查找出name为login的action,并根据class属性创建simpleloginaction实例,并用invoke方法来调用execute方法,这个过程离不开反射。配置文件与action建立了一种映射关系,当view层发出请求时,请求会被strutsprepareandexecutefilter拦截,然后strutsprepareandexecutefilter会去动态地创建action实例。

在比如,加载数据库驱动的,用到的也是反射。

java.lang.class;

java.lang.reflect.constructor;

java.lang.reflect.field;

java.lang.reflect.method;

java.lang.reflect.modifier;

主要有三种方法:

(1)object-->getclass

(2)任何数据类型(包括基本的数据类型)都有一个“静态”的class属性

(3)通过class类的静态方法:forname(string classname)(最常用,通过类的全类名获得类对象)

注意,在运行期间,一个类,只有一个class对象产生,所以打印结果都是true;

三种方式中,常用第三种,第一种对象都有了还要反射干什么,第二种需要导入类包,依赖太强,不导包就抛编译错误。一般都使用第三种,一个字符串可以传入也可以写在配置文件中等多种方法。

一般在需要判断某个对象是否为某个类的实例时,可以使用instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中class对象的isinstance()方法来判断时候为某个类的实例,这是一个native方法。

使用class对象的newinstance()方法来创建class对象对应类的实例。

先通过class对象获取指定的constructor对象,再调用constructor对象的newinstance()方法来创建对象,这种方法可以用指定的构造器构造类的实例。

批量获取的方法:

单个获取的方法,并调用:

调用构造方法:

​<code>​constructor--&gt;newinstance(object... initargs)​</code>​

​<code>​newinstance​</code>​是​<code>​constructor​</code>​类的方法(管理构造函数的类)

api的解释为:​<code>​newinstance(object... initargs)​</code>​ ,使用此​<code>​constructor​</code>​对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

它的返回值是t类型,所以newinstance是创建了一个构造方法的声明类的新实例对象,并为之调用。

student类:共六个构造方法

student类

测试

控制台结果

测试类

控制台输出

数组在java里是比较特殊的一种类型,它可以赋值给一个object reference。

配置文件以​<code>​txt文件​</code>​为例子:

需求

之后升级这个系统时,不要student类,而需要新写一个student2的类时,这时只需要更改pro.txt的文件的类名就可以了。客户端代码就一点不用改动。

配置文件更改为:

泛型用在编译期,编译过后泛型擦除(泛型全部消失掉,都是object),所以是可以通过反射越过泛型检查的