反射是什么
Posted 好多个码农
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射是什么相关的知识,希望对你有一定的参考价值。
一、什么是反射
在程序运行状态中,对于任意一个类或对象,都能够获取到这个类的所有属性和方法(包括私有属性和方法),这种动态获取信息以及动态调用对象方法的功能就称为反射机制。简单来讲,通过反射,类对我们是完全透明的,想要获取任何东西都可以。一句话定义反射:反射就是把java类(成员变量、方法、构造方法、包等等信息)中的各种成分映射成一个个的Java对象。
二、反射的用途
1.当我们输入一个对象或者类,并想调用他的属性和方法是,一按点号,编译器就会自动列出他的属性或者方法,这里就是用到反射。
2.通过反射机制访问java对象的属性,方法,构造方法等
反射最重要的用途就是开发各种通用框架。比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,他们可能需要根据配置文件加载不同的类或者对象,调用不同的方法,这个时候就必须使用到反射了,运行时动态加载需要的加载的对象。反射可以赋予jvm动态编译的能力
三、为啥要用它?它有什么优缺点?
java的反射机制就是增加程序的灵活性,解耦。反射就是一种机制,可以让你仅知道类的名字的情况下,可以了解整个类的内部的结构,并且访问内部的成员和方法等。
解释:对于大型的软件,一个大公司的各个小组都有自己的分工,去实现不同的模块,那么各个小组之间如何协作就非常关键。例如A小组完成IPolicy接口的实现,而B小组需要使用A的实现,这时候就可以使用反射机制,B小组完全不用知道IPolicy是如何实现的,只需要知道实现后的类名即可,或者说,类名完全保存在一个xml或者属性中,由A小组去填充,这样B小组的代码看上去就和A毫无瓜葛。
1、优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
2、缺点:(1)反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
(3)相较直接调用在量大的情景下反射性能下降
Java代码在计算机中所经历的三个阶段:
Source源代码阶段:.java被编译成*.class字节码文件。
Class类对象阶段:.class字节码文件被类加载器加载进内存,并将其封装成Class对象(用于在内存中描述字节码文件),Class对象将原字节码文件中的成员变量抽取出来封装成数组Field[],将原字节码文件中的构造方法抽取出来封装成数组Construction[],将成员方法封装成数组Method[]。
RunTime运行时阶段:使用new创建对象的过程。
四、反射机制常用的类:
Java.lang.Class;
Java.lang.reflect.Constructor;
Java.lang.reflect.Field;
Java.lang.reflect.Method;
Java.lang.reflect.Modifier;
五、获取Class对象三种方式
【Source源代码阶段】 Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象;多用于配置文件,将类名定义在配置文件中,通过读取配置文件加载类。
【Class类对象阶段】 类名.class:通过类名的属性class获取;多用于参数的传递
【Runtime运行时阶段】对象.getClass():此方法是定义在Objec类中的方法,因此所有的类都会继承此方法。 多用于对象获取字节码的方式
public class Test {
public static void main(String[] args) {
//第一种方式获取Class对象
Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
Class stuClass = stu1.getClass();//获取Class对象
System.out.println(stuClass.getName());
//第二种方式获取Class对象
Class stuClass2 = Student.class;
System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
//第三种方式获取Class对象
try {
Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
运行结果:一个类,只有一个Class对象产生,所以打印结果都是true;
六、 Class对象的功能
6.1、判断是否为某个类的示例:
一般的,我们使用instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()方法来判断时候为某个类的实例,他是一个native方法。
public native boolean isInstance(Object obj);
6.2、创建实例:通过反射来生成对象主要有两种方法:
(1)使用Class对象的newInstance()方法来创建Class对象对应类的实例。
Class<?> c = String.class;
Object str = c.newInstance();
(2)先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建对象,这种方法可以用指定的构造器构造类的实例。
//获取String的Class对象
Class<?> str = String.class;
//通过Class对象获取指定的Constructor构造器对象
Constructor constructor=c.getConstructor(String.class);
//根据构造器创建实例:
Object obj = constructor.newInstance(“hello reflection”);
6.3、通过反射获取构造方法并使用:
(1)批量获取的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
(2)单个获取的方法,并调用:
public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
(3) 调用构造方法:
Constructor-->newInstance(Object... initargs)
6.4、获取成员变量并调用:
1.批量获取的:
1).Field[] getFields():获取所有的"公有字段"
2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
2.获取单个的:
1).public Field getField(String fieldName):获取某个"公有的"字段;
2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
设置字段的值:
Field --> public void set(Object obj,Object value):
参数说明:
1.obj:要设置的字段所在的对象;
2.value:要为字段设置的值;
6.5、获取成员方法并调用:
1.批量的:
public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
2.获取单个的:
public Method getMethod(String name,Class<?>... parameterTypes):
参数:
name : 方法名;
Class ... : 形参的Class类型对象
public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
调用方法:
Method --> public Object invoke(Object obj,Object... args):
参数说明:
obj : 要调用方法的对象;
args:调用方式时所传递的实参;
以上是关于反射是什么的主要内容,如果未能解决你的问题,请参考以下文章