反射详解(实用版)
1. Class 类介绍
1.1 概念:
当我们写的.java 文件经过编译后,会生成包含若干个.class 文件。 每个 class 文件是一个二进制文件,包含这个类的一些信息。例如有几个成员变量,几个成 员方法等。 当我们程序运行期间,需要根据实例化某个类的对象时,会将硬盘中的.class 文件在内存中 初始化成 Class 类型的对象。 我们可以利用这个 Class 类型的对象,进行一些后续工作。 例如反射实例化,或者反射拿到一些特定的成员方法,变量等。eg: 类—>.class—>Class 类型的对象—>实例化 类对应的对象
1.2 Class对象的获取方法
本文的实体类例子
public class Person {
String name;
int id;
Person(){
}
public Person(String name){
this.name=name;
}
public Person(String name,int id){
this.name=name;
this.id=id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
void test(){
System.out.println("这是一个"+Person.class+"测试方法");
};
static void staticTest(int a,String b){
System.out.println("这是一个静态成员方法");
System.out.println("a:"+a+" "+"b:"+b);
}
}
三种: 静态成分,Class.forName()方法和 getClass()方法
Class person1 = Class.forName("Person");
Person personInstance = new Person();
Class person2 = personInstance.getClass();
Class person3 = Person.class;
2. Class 对象获取后的操作
2.1.构造方法的遍历
Constructor[] constructors = person.getConstructors();//获取所有构造方法
//遍历构造函数
for (int i = 0; i < constructors.length; i++) {
System.out.println(constructors[i].getName());//
System.out.println(Modifier.toString(constructors[i].getModifiers()));//获取构造方法的权限
//获取每个构造方法的参数列表,第一个是0
Class[] parameterTypes = constructors[i].getParameterTypes();
for(int j=0;j<parameterTypes.length;j++){
System.out.println(parameterTypes[j].getName()+"--");
}
}
2.2 获取制定的构造方法
Class[] classes={String.class,int.class};//构造方法的参数类型
Constructor declaredConstructor = person.getDeclaredConstructor(classes);
Class[] parameterTypes = declaredConstructor.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
ystem.out.println(parameterTypes[i].getName());//获取构造方法的类型
2.3 实例化对象
//生成对象
//通过默认构造函数生成对象
Person pInstance1 = (Person) person3.newInstance(); System.out.println(pInstance1.name);
//通过指定构造函数生成对象
Class[] classes = {String.class,int.class};
Constructor declaredConstructor = person3.getDeclaredConstructor(classes);
declaredConstructor.setAccessible(true);
Person lbw = (Person) declaredConstructor.newInstance("卢本伟", 29);
System.out.println(lbw.name);
2.4成员方法
getMethods():该方法是获取本类以及父类或者父接口中所有的公共方法(public 修饰符 修饰的)
getDeclaredMethods():该方法是获取本类中的所有方法,包括私有的(private、protected、 默认以及 public)的方法。
2.4.1 得到全部成员方法
Class p = Person.class;
Method[] declaredMethods = p.getDeclaredMethods();
System.out.println(declaredMethods.length);
2.4.2获得指定成员方法并调用
Person pInstance = (Person) p.newInstance();
Class[] classes = {};
Method method = p.getDeclaredMethod("test",classes);
method.setAccessible(true);//避免权限问题
method.invoke(pInstance);
2.5 成员变量
2.5.1遍历成员变量
Person person = new Person();
Class p = person.getClass();
//获取所有的成员变量
//遍历成员变量
Field[] declaredFields = p.getDeclaredFields();
for (Field f : declaredFields) {
System.out.println(f);
}
2.5.2获取制定成员变量并且修改它的值
Person instance = (Person) p.newInstance();
Field field = p.getDeclaredField("name");
field.setAccessible(true);
field.set(instance, "lbw");
System.out.println(instance.name);
###2.5.3 获取指定成员变量的值
System.out.println(field.get(instance));
2.6 静态成员方法
2.6.1获取静态成员方法并修改
Class personClass = Person.class;
//创建实例,但这里是静态方法,不创建也可以
Person person = (Person) personClass.newInstance();
//获取指定的静态方法并且调用
Class[] classes={int.class,String.class};
Method staticTest = personClass.getDeclaredMethod("staticTest", classes);
staticTest.setAccessible(true);
staticTest.invoke(null,2,"lbw");
静态成员变量
//(和正常的new对象一样调用即可)
System.out.println(person.name);
3.反射的作用
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
void test(String name,Object object)throws Exception{
//name="a";
//name="b";
Method method=object.getClass().getDeclaredMethod(name);
method.invoke(object);
}
public static void main(String[] args){
Test t=new Test();
try {
t.test("a",new A());
} catch (Exception e) {
e.printStackTrace();
}
}
}
class A{
void a(){
System.out.println("AAAA");
}
}
例题
一.完成下述代码要求
1.有三个成员变量和三个成员方法。(权限都分别为prive,default和public)
2. 有一个无参private构造函数和有参public构造函数
3.通过反射两个不同的构造函数生成两个对象
4.通过反射打印3中任意一个对象的三个成员变量的值
5.通过反射调用3中任意一个对象的三个成员方法
6.通过反射更改3中任意一个对象的三个成员变量的值
public class Person {
private int age;
String name;
public String sex;
private Person(){}
public Person(int age,String name,String sex){
this.age=age;
this.name=name;
this.sex=sex;
}
private void sing(String name){
System.out.println(name+"调用"+"这是私有权限的sing方法");
}
void dance(){
System.out.println("这是默认权限的dance方法");
}
public void rap(){
System.out.println("这是公共权限的rap方法");
}
}
public class Entrance {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class personClass = Person.class;
Constructor c1 = personClass.getDeclaredConstructor();
c1.setAccessible(true);//因为无参构造前面设置的权限是private
Person p1= (Person) c1.newInstance();
Class[] classes={int.class,String.class,String.class};
Constructor constructor1 = personClass.getDeclaredConstructor(classes);
// constructor1.setAccessible(true);
Person p2 = (Person) constructor1.newInstance(20, "lbw", "男");
Field age = personClass.getDeclaredField("age");
age.setAccessible(true);
Field name = personClass.getDeclaredField("name");
Field sex = personClass.getDeclaredField("sex");
System.out.println(age.get(p2));
System.out.println(name.get(p2));
System.out.println(sex.get(p2));
Method sing = personClass.getDeclaredMethod("sing",String.class);
sing.setAccessible(true);
Method dance = personClass.getDeclaredMethod("dance");
Method rap = personClass.getDeclaredMethod("rap");
sing.invoke(p2,name.get(p2));
dance.invoke(p2);
rap.invoke(p2);
age.set(p2,30);
System.out.println(age.get(p2));
}
}
二.在一中的类中添加一个public权限的静态方法,并利用反射调用。说明为什么invoke的第一个参数可以为null?如果invoke的第一个参数传入一大题3中生成的任意一个对象是否可以调用成功?
public static void fly(){
System.out.println("这是静态的fly方法");
}
因为fly是静态方法,静态方法不需要对象调用,有类即可
可以调用成功
三.请简述反射的两个作用,并说明为什么这两个作用 不利用反射无法实现。
1.可以动态的调用对象成员
2.可以获取一些类的信息(xml,spring框架等),绕过创建对象
四. 利用b这个对象和反射,调用test方法打印“I am A”。
提示:查阅getSuperClass相关资料
Class A{
private void test(){
System.out.println(“I am A”)
}
}
Class B extends A{
}
主方法:
B b=new B();
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
B b = new B();
Class bClass = B.class;
Class aClass = bClass.getSuperclass();
Method test = aClass.getDeclaredMethod("test");
test.setAccessible(true);
test.invoke(b);//不需要创建A类,因为是B是A的子类,且设置了权限
}
五.如何通过反射去获取所依靠的外部类对象的某个成员变量并打印出来。
public class A {
int age=10;
class B{
void test(){
System.out.println("这是内部类的方法test");
}
}
}
主方法:
A a = new A();
A.B b = a.new B();
Class bClass = b.getClass();
Field age = bClass.getDeclaredField("this$0");//this$0就是内部类所自动保留的一个指向所在外部类的引用
A age1=(A) age.get(b);
Field age2 = age1.getClass().getDeclaredField("age");
System.out.println(age2.get(a));