概述
- 反射是框架设计的灵魂。框架是半成品软件。在框架的基础上进行软件开发,简化编码。
- 将类的各个组成部分封装为其他对象,称为反射机制
- java代码在计算机中的三个阶段:Source源代码阶段、Class类对象阶段、Runtime运行时阶段
- 反射的优点:
- 在程序运行过程中,操作这些对象
- 降低程序的耦合性,提高程序可扩展性
获取字节码Class对象
- Class.forName(“全类名”):将字节码文件加载进内存,返回class对象。
- 类名.class:通过类名的属性class获取
- 对象.getClass:这个方法在Object类中定义
try { // Person类对象 Class cls1 = Class.forName("Person"); // 第一种方式:多用于配置文件 System.out.println(cls1); // class Person // 第二种方式:多用于参数的传递 Class cls2 = Person.class; System.out.println(cls2); // class Person // 第三种方式:多用于对象的获取字节码 Person p = new Person(); Class cls3 = p.getClass(); System.out.println(cls3); // class Person System.out.println(cls1==cls2); // true System.out.println(cls1==cls3); // true // 同一个字节码文件(*.class)在一次程序的运行过程中,只会被加载一次,不管哪一种方式获取的class对象都是同一个 } catch (ClassNotFoundException e) { e.printStackTrace(); }
使用class对象
-
获取成员变量
Field[] getFields() 返回一个包含 Field对象的数组, Field对象反映由该 Class对象表示的类或接口的所有可访问的公共字段。 Field getField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定公共成员字段。 Field getDeclaredField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定声明字段。 Field[] getDeclaredFields() 返回一个 Field对象的数组,反映了由该 Class对象表示的类或接口声明的所有字段。获取所有的成员变量,不考虑修饰符
Filed操作:成员变量操作 1、设置值,set(Object obj,Object value) 2、获取值,get(Object obj) 3、忽略权限修饰符的安全检测,称为暴力反射,setAccessible(true)
public class PersonTwo { private String name; private int age; public String a; public String b; public String c; public String d; public PersonTwo() { } public PersonTwo(String name, int age, String a, String b, String c, String d) { this.name = name; this.age = age; this.a = a; this.b = b; this.c = c; this.d = d; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getA() { return a; } public void setA(String a) { this.a = a; } public String getB() { return b; } public void setB(String b) { this.b = b; } public String getC() { return c; } public void setC(String c) { this.c = c; } public String getD() { return d; } public void setD(String d) { this.d = d; } @Override public String toString() { return "PersonTwo{" + "name='" + name + '\'' + ", age=" + age + ", a='" + a + '\'' + ", b='" + b + '\'' + ", c='" + c + '\'' + ", d='" + d + '\'' + '}'; } public void eat(){ System.out.println("chifan"); } }
Class<PersonTwo> personClass = PersonTwo.class; Field[] fields = personClass.getFields(); for (Field field : fields) { System.out.println(field); // public java.lang.String Person.a, // public java.lang.String Person.b, // public java.lang.String Person.c // public java.lang.String Person.d } System.out.println("+++++++++++"); try { Field a = personClass.getField("a"); System.out.println(a);// public java.lang.String Person.a PersonTwo p1 = new PersonTwo(); Object obj1 = a.get(p1); // 获取成员变量a的值 System.out.println(obj1); // null a.set(p1,"hello"); // 对象p1,设置成员变量a的值 System.out.println(p1); } catch (Exception e) { e.printStackTrace(); }
-
获取构造方法
Constructor<T> getConstructor(Class<?>... parameterTypes) 返回一个 Constructor对象,该对象反映由该 Class对象表示的类的指定公共构造函数。 Constructor<?>[] getConstructors() 返回一个包含 Constructor对象的数组, Constructor对象反映了由该 Class对象表示的类的所有公共构造函数。 Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回一个 Constructor对象,该对象反映由此 Class对象表示的类或接口的指定构造函数。 Constructor<?>[] getDeclaredConstructors() 返回反映由该 Class对象表示的类声明的所有构造函数的 Constructor对象的数组。
Class<PersonTwo> personClass = PersonTwo.class; Constructor<?>[] constructors = personClass.getConstructors(); Constructor<PersonTwo> constructor = null; try { constructor = personClass.getConstructor(String.class,int.class,String.class,String.class,String.class,String.class); } catch (NoSuchMethodException e) { e.printStackTrace(); } System.out.println(constructor); System.out.println(Arrays.toString(constructors)); PersonTwo person2 = null; try { // 创建对象 person2 = constructor.newInstance("hello", 12, "a", "b", "c", "d"); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } System.out.println(person2); // PersonTwo{name='hello', age=12, a='a', b='b', c='c', d='d'} }
-
获取成员方法
方法 getMethod(String name, Class<?>... parameterTypes) 返回一个 方法对象,该对象反映由该 Class对象表示的类或接口的指定公共成员方法。 获取所有public修饰的成员变量 方法[] getMethods() 返回一个包含 方法对象的数组, 方法对象反映由该 Class对象表示的类或接口的所有公共方法,包括由类或接口声明的对象以及从超类和超级接口继承的类。 方法 getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 Class对象。 方法[] getDeclaredMethods() 返回一个包含 方法对象的数组, 方法对象反映由 Class对象表示的类或接口的所有声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承方法。
Class<PersonTwo> personClass = PersonTwo.class; try { Method eat = personClass.getMethod("eat"); try { eat.invoke(new PersonTwo("hello",13,"","","","")); // eat方法执行,结果式chifan } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (NoSuchMethodException e) { e.printStackTrace(); }
-
获取类名
String getName() 返回由该 Class对象表示的实体(类,接口,数组类,原始类型或无效)的 Class ,作为 String 。
Class<PersonTwo> personClass = PersonTwo.class; String name = personClass.getName(); System.out.println(name);
案例
/*
需求:写一个"框架",可以帮我们创建任意类的对象,并且执行其中任意方法
实现:1、配置文件;2、反射
步骤:1、将需要创建的对象的全类名和需要执行的方法定义在配置文件中
2、在程序中加载读取配置文件
3、使用反射技术加载类文件进内存
4、创建对象
5、执行方法
*/
// 1.加载配置文件
// 1.1 创建properties对象
Properties pro = new Properties();
// 1.2 加载配置文件,转为一个集合
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("properties.properties");
pro.load(resourceAsStream);
// 2.获取配置文件中的数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
// 3.加载该类进内存,
Class cls=Class.forName(className);
System.out.println(cls);
// 4.创建对象
Constructor constructor = cls.getConstructor(String.class);
System.out.println(constructor);
Object obj = constructor.newInstance(className);
// 5.获取方法对象
Method method = cls.getMethod(methodName);
// 6.执行方法
method.invoke(obj);
package cn.reflecttest;
// 学生类文件
public class Student {
private String name;
public Student() {
}
public Student(String name) {
this.name = name;
}
public void sleep(){
System.out.println("sleeping....");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
package cn.reflecttest;
// 工人类文件
public class Worker {
private String name;
public Worker() {
}
public Worker(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Worker{" +
"name='" + name + '\'' +
'}';
}
public void work(){
System.out.println("working....");
}
}
// .properties配置文件
className=cn.reflecttest.Worker
methodName=work