什么是反射 ?
Java反射就是在运行状态时,对任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。而这也是Java被视为动态语言的关键原因。
在具体的研发中,通过反射获取类的实例,大大提高系统的灵活性和扩展性,同时由于反射的性能较低,而且它极大的破坏了类的封装性(通过反射可以获取类的私有属性和方法),在大部分场景下并不适合使用反射,但是在大型的一些框架中,会大范围的使用反射来帮助架构完善一些功能。
反射所涉及到的一些类:
- Class :类的类
- Field : 属性
- Method :方法
- Constructor :构造方法
反射的实现:
首先准备一个 Student 类:
package com0911;
public class Student {
public String name;
protected int age;
private char sex;
public Student(){
}
public Student(String name,int age,char sex){
this.name = name;
this.age = age;
this.sex = sex;
}
public void getName(){
System.out.println("getName()方法被访问了!");
System.out.println(name);
}
protected void getAge(){
System.out.println("getAge()方法被访问了!");
System.out.println(age);
}
private void getSex(){
System.out.println("getSex()方法被访问了!");
System.out.println(sex);
}
private void A(String str,int a,char ch){
System.out.println(str);
System.out.println(a);
System.out.println(ch);
}
}
反射类:
(我们会在这个类中使用反射访问Student类中的属性和方法)
public class Reflect {
//反射访问属性和不带参数的方法
public void create_without_parameter(){
try {
//获取Class对象
Class cla = Class.forName("com0911.Student");
//获取类的构造方法
Constructor con = cla.getConstructor();
//创建对象
Object obj = con.newInstance();
//将属性存放在fields[]数组中
Field[] fields = cla.getDeclaredFields();
//输出属性
for(int i=0;i<fields.length;i++){
//获取类的属性
String name = fields[i].getName();
fields[i].setAccessible(true);
//访问类的属性
Object value = fields[i].get(obj);
System.out.println(name+" "+value);
//修改属性的值
value = "change!";
System.out.println("属性修改后: "+name+" "+value);
System.out.println("-------------------------");
}
//获取类的方法
Method[] methods = cla.getDeclaredMethods();
for(int i=0;i<methods.length;i++){
//对属性设置访问权限,当类中方法为Protected和private时必须设置此项为true
methods[i].setAccessible(true);
methods[i].invoke(obj);
System.out.println("-------------------------");
}
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//反射访问属性和带参数的方法
public void create_with_parameter(){
try {
//获取Class对象
Class cla = Class.forName("com0911.Student");
//参数类型数组
Class[] parameterTypes = {String.class,int.class,char.class};
//根据参数类型获取相应的构造函数
Constructor con = cla.getConstructor(parameterTypes);
//参数数组(初始化)
Object[] parameters = {"小明",19,'m'};
//创建对象
Object obj = con.newInstance(parameters);
//获取属性,将属性存放在fields[]数组中
Field[] fields = cla.getDeclaredFields(); //getField()获取一个类的public字段,getDeclaredField()获取一个类的所有字段
for(int i=0;i<fields.length;i++){
//获取类的属性
String name = fields[i].getName();
fields[i].setAccessible(true);
Object value = fields[i].get(obj);
System.out.println("初始化之后的属性值: "+name+": "+value);
System.out.println("-------------------------");
}
//getDeclaredMethod()方法中第一个参数表示方法名,第二个参数表示参数类型
Method method = cla.getDeclaredMethod("A",String.class,int.class,char.class);
method.setAccessible(true);
//调用方法时传入参数
method.invoke(obj, "小明",18,'m');
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args){
Reflect reflect = new Reflect();
reflect.create_with_parameter();
reflect.create_with_parameter();
}
}
reflect.create_without_parameter();
(不带参数)
样例输出:
name null
属性修改后: name change!
-------------------------
age 0
属性修改后: age change!
-------------------------
sex
属性修改后: sex change!
-------------------------
getName()方法被访问了!
null
-------------------------
getAge()方法被访问了!
0
-------------------------
getSex()方法被访问了
reflect.create_with_parameter();
(带参数)
样例输出:
初始化之后的属性值: name: 小明
-------------------------
初始化之后的属性值: age: 19
-------------------------
初始化之后的属性值: sex: m
-------------------------
A()方法被访问了!
小明
18
m
上面是总的代码的实现,但是在我们实现的过程中会遇到一些问题,下面我将我在实现过程中遇到的一些问题和大家分享一下,期待对大家有所帮助。
- getField()和 getDeclaredFields()方法的区别
getField ()方法是获取一个类的public字段,也就是它可以获取一个类中所有访问权限为public的属性和方法。而 getDeclaredFields()方法是获取一个类的所有字段。
- 关于setAccessible(true)的使用
在写代码的过程中,我们会发现如果要在类外访问里一个类的私有属性和方法时,系统会报错。这个时候就需要使用setAccessible()方法了。setAccessible()是对属性设置访问权限,当类中方法为Protected和private时必须设置此项为true。
总结:
在反射过程中,我们可能会遇到一下几种情况:
- 访问public、protected、private属性
- 访问public、protected、private方法
- 访问不带参数的方法
- 访问带有参数的方法
上述情况在上面的代码中都有涉及到,想深入了解的小伙伴可参考源码学习。
可承接各种项目,有意者加QQ:1217898975