反射是非常重要的知识
JAVA让我们运行时识别对象和类的信息,有俩个方式:一个是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息。另一种是反射机制,它允许我们运行时发现和使用类的信息。 –编程思想
反射的描述
JAVA反射机制是运行状态中,对于任意一个类,能够知道这个类的所有属性和方法,对于任意一个对象,能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用方法的功能称为java语言的反射机制。
要想达到这样的效果,必须先要获取到该类的字节码文件对象,而达到这样效果使用的是Class类中的方法,所以先要获取到每个字节码文对应的Class类型对象。
每个类都会产生一个对应的Class对象,且每个类只有一个,也就是保存在.class文件。所有类都是在对其第一次使用时,动态加载到JVM
JAVA中反射的实现过程: JAVA语言在编译之后会产生成一个.class文件,反射就是通过字节码文件找到某一个类,类中的方法以及属性等。 下图2中,就是找到Class文件并创建Class对象(摘自网上) 下面是jdk到解释,说明反射就是把类中的各个成分反映为一个个对象
Class类的类表示正在运行的Java应用程序中的类和接口。 枚举是一种类,一个注释是一种界面。 每个数组也属于一个反映为类对象的类,该对象由具有相同元素类型和维数的所有数组共享。 原始Java类型( boolean , byte , char , short , int , long , float和double ),和关键字void也表示为类对象。
类没有公共构造函数。 相反, 类对象由Java虚拟机自动构建,因为加载了类,并且通过调用类加载器中的defineClass方法。
我们不需要自己创建Class类,JVM自动帮我们创建好了。
反射的作用
JAVA反射的作用是什么: 反射机制指的是程序在运行时能够获取自身的信息。在JAVA中,只要给定类的名字,那么就可以通过反射机制来获取类的所有信息。
获取Class对象的三种方式
Class
cls1 = String
.class;
Class
cls2 = int.class;
Class
cls3 = Employee
.class; (Employee是一个类
)
Class
cls1 = Class
.forName("Employee");
Class
cls2 = Class
.forName("java.lang.String");
Employee employee
= new Employee();
Class
cls = employee
.getClass();
反射的实现主要借助以下四个类:class:类的对象,Constructor:类的构造方法,field:类中的属性对象,Method类中的方法对象。
通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问:
通过反射获取构造方法并使用
package fanshe
;
public class Student {
Student(String str
){
System
.out
.println("默认的构造方法 s= "+str
);
}
public Student() {
System
.out
.println("调用了公有,无参数构造方法执行了。。。");
}
public Student(char name
) {
System
.out
.println("姓名:"+name
);
}
public Student(String name
,int age
) {
System
.out
.println("姓名:"+name
+"年龄:"+age
);
}
protected Student(boolean n
) {
System
.out
.println("受保护的构造方法 n = "+n
);
}
private Student(int age
) {
System
.out
.println("私有的构造方法 年龄:"+age
);
}
}
package fanshe
;
import java
.lang
.reflect
.Constructor
;
import java
.lang
.reflect
.InvocationTargetException
;
public class Constructors {
public static void main(String
[] args
) throws ClassNotFoundException
, NoSuchMethodException
, SecurityException
, InstantiationException
, IllegalAccessException
, IllegalArgumentException
, InvocationTargetException
{
Class
cls = Class
.forName("fanshe.Student");
System
.out
.println("**********************所有公有构造方法*********************************");
Constructor
[] conArray
= cls
.getConstructors();
for(Constructor c
:conArray
) {
System
.out
.println(c
);
}
System
.out
.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
conArray
= cls
.getDeclaredConstructors();
for(Constructor c
: conArray
){
System
.out
.println(c
);
}
System
.out
.println("*****************获取公有、无参的构造方法*******************************");
Constructor con
= cls
.getConstructor(null
);
System
.out
.println("con = " + con
);
Object obj
= con
.newInstance();
System
.out
.println("******************获取私有构造方法,并调用*******************************");
con
= cls
.getDeclaredConstructor(char.class);
System
.out
.println(con
);
con
.setAccessible(true);
obj
= con
.newInstance('男');
}
}
输出
获取成员变量并调用
package fanshe
;
public class Employee {
public Employee() {
}
public String name
;
protected int age
;
char sex
;
private String phoneNum
;
@Override
public String
toString() {
return "Employee [name=" + name
+ ", age=" + age
+ ", sex=" + sex
+ ", phoneNum=" + phoneNum
+ "]";
}
}
package fanshe
;
import java
.lang
.reflect
.Field
;
public class Fields {
public static void main(String
[] args
) throws Exception
{
Class
cls = Class
.forName("fanshe.Employee");
System
.out
.println("***********获取所有公有字段************************");
Field
[]fieldArray
= cls
.getFields();
for(Field f
: fieldArray
) {
System
.out
.println(f
);
}
System
.out
.println("***********获取所有的字段(包括私有,受保护,默认的)*******");
fieldArray
= cls
.getDeclaredFields();
for(Field f
: fieldArray
) {
System
.out
.println(f
);
}
System
.out
.println("************获取所有的字段(包括私有、受保护、默认的)********************");
fieldArray
= cls
.getDeclaredFields();
for(Field f
: fieldArray
){
System
.out
.println(f
);
}
System
.out
.println("*************获取公有字段**并调用***********************************");
Field f
= cls
.getField("name");
System
.out
.println(f
);
Object obj
= cls
.getConstructor().newInstance();
f
.set(obj
, "刘德华");
Employee emp
= (Employee
)obj
;
System
.out
.println("验证姓名:" + emp
.name
);
System
.out
.println("**************获取私有字段****并调用********************************");
f
= cls
.getDeclaredField("phoneNum");
System
.out
.println(f
);
f
.setAccessible(true);
f
.set(obj
, "18888889999");
System
.out
.println("验证电话:" + emp
);
}
}
获取成员方法并调用
package fanshe
;
public class School {
public void show1(String s
){
System
.out
.println("调用了:公有的,String参数的show1(): s = " + s
);
}
protected void show2(){
System
.out
.println("调用了:受保护的,无参的show2()");
}
void show3(){
System
.out
.println("调用了:默认的,无参的show3()");
}
private String
show4(int age
){
System
.out
.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age
);
return "abcd";
}
}
package fanshe
;
import java
.lang
.reflect
.Method
;
public class MethodClass {
public static void main(String
[] args
) throws Exception
{
Class
cls = Class
.forName("fanshe.School");
System
.out
.println("***************获取所有的”公有“方法*******************");
cls
.getMethods();
Method
[] methodArray
= cls
.getMethods();
for(Method m
: methodArray
){
System
.out
.println(m
);
}
System
.out
.println("***************获取所有的方法,包括私有的*******************");
methodArray
= cls
.getDeclaredMethods();
for(Method m
: methodArray
){
System
.out
.println(m
);
}
System
.out
.println("***************获取公有的show1()方法*******************");
Method m
= cls
.getMethod("show1", String
.class);
System
.out
.println(m
);
Object obj
= cls
.getConstructor().newInstance();
m
.invoke(obj
, "刘德华");
System
.out
.println("***************获取私有的show4()方法******************");
m
= cls
.getDeclaredMethod("show4", int.class);
System
.out
.println(m
);
m
.setAccessible(true);
Object result
= m
.invoke(obj
, 20);
System
.out
.println("返回值:" + result
);
}
}
利用反射运行配置文件
在src目录下建一个pro.txt配置文件,用来更新操作 pro.txt内容:
ClassName=fanshe.Student1 MethodName=show
package fanshe
;
public class Student1 {
public void show() {
System
.out
.println("is show");
}
}
package fanshe
;
import java
.io
.FileReader
;
import java
.lang
.reflect
.Method
;
import java
.util
.Properties
;
public class Demo {
public static void main(String
[] args
) throws Exception
{
Class
cls = Class
.forName(getValue("ClassName"));
Method m
= cls
.getMethod(getValue("MethodName"));
m
.invoke(cls
.getConstructor().newInstance());
}
private static String
getValue(String key
) throws Exception
{
Properties pro
= new Properties();
FileReader in
= new FileReader("pro.txt");
pro
.load(in
);
in
.close();
return pro
.getProperty(key
);
}
}
运行后
is show
当我们需要更改类时,创建一个新类Student2,然后只需要更改pro.txt的内容,就可以运行了。
ClassName=fanshe.Student2 MethodName=show
package fanshe
;
public class Student2 {
public void show() {
System
.out
.println("is show2");
}
}
其他不用改 输出:
is show2
以前写过的一些方法,那时理解很浅 点我