Java反射机制 详解

# 反射


是Java API


## 什么是反射


反射是Java提供的动态执行API, 能够动态加载类, 动态创建对象, 动态访问属性, 动态调用方法 ...


## 静态执行与动态执行


静态执行: 经过编译以后, 就确定了程序执行次序, 运行期间按照既定次序执行. 


如:


Foo foo = new Foo();
int n = foo.times;
System.out.println(n);


动态执行: 在"运行期间"才能确定加载那个类,创建那个对象,执行方法 ... 


利用 反射API可以实现动态执行.


### 动态加载类


API
Class cls = Class.forName("类名");


//如下两个方法可以获取 cls 对象, 但是不能体现动态特性
Class cls = Foo.class;
Class cls = foo.getClass();


案例:


Scanner in = new Scanner(System.in);
System.out.print("输入类名:");
String className=in.nextLine();
Class cls = Class.forName(className);
System.out.println(cls);


原理:





### 动态创建对象


在运行期间, 根据任意的类名创建对象.


API

Object obj = cls.newInstance()


> 提示: 利用类的无参数构造器创建对象, 反射的"构造器API" 可以调用有参数构造器创建对象.


举个栗子:


Scanner in = new Scanner(System.in);
System.out.print("输入类名:");
String className=in.nextLine();
Class cls = Class.forName(className);
System.out.println(cls);
Object obj = cls.newInstance();
System.out.println(obj);


### 动态访问属性


使用步骤:


1. 根据属性名找到"属性声明"信息Field
- Field fld=cls.getDeclaredField(属性名)  //age 属性声明
2. 属性的值在"对象"上, 找到/创建一个对象
3. 在对象当获取属性的值
- Object val = fld.get(对象)  //age的值


案例:


Scanner in = new Scanner(System.in);
System.out.print("输入类名:");
String className=in.nextLine();
Class cls = Class.forName(className);
System.out.println(cls);
Object obj = cls.newInstance();
System.out.println(obj);

//找到属性声明信息
System.out.print("属性名:");
String name = in.nextLine();
//动态找到属性声明信息
Field fld = cls.getDeclaredField(name);
System.out.println(fld); 
//读取对象的属性: 在一个对象上读取属性的值

//打开访问权限
fld.setAccessible(true);

Object val = fld.get(obj);
System.out.println(val); 


### 反射API可以 "未卜先知"


经典面试题: 


Eclipse的热键菜单, 用什么技术实现.


### 反射可以动态获取类的信息


反射全部的属性:


Field[] getDeclaredFields() 


反射全部的属性:


Method[] getDeclaredMethods() 


案例:
Scanner in = new Scanner(System.in);
System.out.print("输入类名:");
String className=in.nextLine();
Class cls = Class.forName(className);


//反射类的全部属性
Field[] fields=
cls.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
//反射类的全部方法
Method[] methods=
cls.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method); 
}


### 反射可以访问私有属性和方法!!


在访问private 成员之前使用


e.setAccessible(true); 


可以打开访问权限了


案例:


//打开访问权限
fld.setAccessible(true);

Object val = fld.get(obj);
System.out.println(val); 


面试题目:


1. Spring 如果给private属性注入值
2. 如果访问类的私有成员


### 动态访问方法(反射调用方法)


步骤


1. 找到方法的"声明"信息 Method
- Method getDeclaredMethod(方法名, 参数类型...) 
- Method getDeclaredMethod(方法名)

Method m1=cls.getDeclaredMethod("test")
Method m2=cls.getDeclaredMethod("test", int.class, String.class);
 
2. 创建或得到对象
3. 在对象上调用响应方法!
- Object method.invoke(对象, 参数...)


Object v = m1.invoke(对象);
Object v = m2.invoke(对象, 5, "666");


案例:


Scanner in = new Scanner(System.in);
//动态加载类
System.out.print("输入类名:");
String className=in.nextLine();
Class cls = Class.forName(className);
System.out.println(cls);

//动态创建对象
Object obj = cls.newInstance();
System.out.println(obj);

//动态找到一个方法
System.out.print("方法名:");
String name=in.nextLine();
Method m=cls.getDeclaredMethod(name);
System.out.println(m); 

//动态执行方法
m.setAccessible(true);//访问私有
Object val = m.invoke(obj);
System.out.println(val);




## 框架底层基本都是反射技术实现的


## 注解是利用反射进行解析的!


原理:





案例:


@Retention(RetentionPolicy.RUNTIME)
public @interface Test {

}




public class TestCase {

@Test
public void demo(){
System.out.println("demo");
}

@Test
public void test(){
System.out.println("test");
}
}



public class Demo03 {

public static void main(String[] args) 
throws Exception{
//JUnit 4 原型
Scanner in = new Scanner(System.in);
System.out.print("类名:");
String className = in.nextLine();
//Class 是反射的入口
Class cls = Class.forName(className);
//找到类中全部的方法
Method[] methods = 
cls.getDeclaredMethods();
Object obj = cls.newInstance();

for (Method method : methods) {
//动态解析注解
Object a = method
.getAnnotation(Test.class);
System.out.println(a); 
if(a!=null){
method.invoke(obj);
}
}
}

}













评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值