反射是一种机制,利用该机制可以在程序运行过程中对类进行解剖并操作类中的所有成员(成员变量,成员方法,构造 方法)。
要获得该类字节码文件对象,就是Class对象
代码演示: 这里的Person类就不在提供了,就是一个普通的类。
//获取Person类的Class对象
Class c1 = Person.class;
//根据对象名获取Person类的Class对象
Person p = new Person();
Class c2 = p.getClass();
//根据Class类的静态方法获取 static Class forName(全限定类名)
Class c3 = Class.forName("cn.it.FanShe.Person");
代码演示:
//获取Person类的Class对象
Class c1 = Person.class;
//获取类名
System.out.println("类名为:" + c1.getSimpleName());
//获取全限定类名
System.out.println("全限定类名为:" + c1.getName());
//通过反射创建Person对象 只能获取public修饰的空参构造
Person person = (Person) c1.newInstance();
person.setName("李四");
person.setAge(20);
System.out.println(person);
结果:
类名为:Person
全限定类名为:cn.it.FanShe.Person
Person{name='李四', age=20}
概述:反射构造方法的目的是为了获取Constructor对象来创建类的对象, 每一个构造方法都是一个Constructor类的对象。
代码演示:
//Person类
public class Person extends ApeMan {
public String name;
private int age;
public Person() {
}
private Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("人要吃饭!");
}
private void work(){
System.out.println("工人要工作!");
}
private void game(String name){
System.out.println(name + "会玩游戏!");
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//----------------------------------演示-------------------------------------------
//获取Person类的Class对象
Class c1 = Person.class;
//获取无参 public 修饰的构造器
Constructor con1 = c1.getConstructor();
//获取有参 public 修饰的构造器
Constructor con2 = c1.getConstructor(String.class, int.class);
//获取有参 任意修饰符的构造器
Constructor con3 = c1.getDeclaredConstructor(String.class);
//暴力反射
con3.setAccessible(true);
//创建对象 在操作获取的构造器前必须进行暴力反射,因为该构造器是私有的
//根据有参构造创建Person对象
Person p1 = (Person) con3.newInstance("A");
//获取所有public修饰的构造器
Constructor[] cons1 = c1.getConstructors();
for (Constructor c : cons1) {
System.out.println(c);
}
//结果:public cn.it.FanShe.Person(java.lang.String,java.lang.Integer)
// public cn.it.FanShe.Person()
//获取任意权限修饰符的所有构造器
Constructor[] cons2 = c1.getDeclaredConstructors();
for (Constructor c : cons2) {
System.out.println(c);
}
//结果: public cn.it.FanShe.Person(java.lang.String,java.lang.Integer)
// private cn.it.FanShe.Person(java.lang.String)
// public cn.it.FanShe.Person()
//根据构造器创建Person对象
Person person1 = (Person) con1.newInstance();
person1.setName("王五");
person1.setAge(20);
System.out.println(person1);
//结果:Person{name='王五', age=20}
概述:通过操作Method对象来调用成员方法,每一个成员方法都是一个Method类的对象。
代码演示:
public class ApeMan {
public void cry(){
System.out.println("猿人会叫!");
}
}
public class Person extends ApeMan {
private String name;
private int age;
public Person() {
}
private Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("人要吃饭!");
}
private void work(){
System.out.println("工人要工作!");
}
private void game(String name){
System.out.println(name + "会玩游戏!");
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//-------------------------------------------演示---------------------------------------------------
//获取Person类的Class对象
Class c = Person.class;
//获取Person对象
Person p = (Person) c.newInstance();
//获取public修饰的指定方法
Method method = c.getMethod("eat");
//执行invoke方法必须传入相应的对象,有参数后面还要写参数
//如果方法有返回值,可以用参数接收
method.invoke(p);
//结果:人要吃饭!
//获取私有方法
Method work = c.getDeclaredMethod("work");
//开启暴力反射
work.setAccessible(true);
//执行invoke方法必须传入相应的对象,有参数后面还要写参数
//如果方法有返回值,可以用参数接收
work.invoke(p);
//结果:工人要工作!
//获取所有的public修饰的方法(包含父类中public修饰的方法)
Method[] methods = c.getMethods();
for (Method m : methods) {
//展示方法的名称
System.out.println(m.getName());
}
/*
因为Object是顶级父类,所以也获取了Object中的public修饰的方法,但是这里面的 eat cry 是我们自定义的public方法,其中cry是父类的public方法。
结果:toString getName setName getAge eat setAge cry wait wait wait equals hashCode getClass notify notifyAll
*/
//获取所有权限修饰符修饰的方法(不包含父类的)
Method[] methods1 = c.getDeclaredMethods();
for (Method m : methods1) {
//展示方法的名称
System.out.println(m.getName());
}
//因为Object是顶级父类,所以也获取了Object中的方法,但是我们自定义的私有的方法game work public的方法eat都出来了,但是父类的cry没有显示。
//结果:toString getName setName game work getAge eat setAge
概述:通过Field对象给对应的成员变量赋值和取值,每一个成员变量都是一个Field类的对象。
设置:
获取:
代码演示:
//获取Person的Class对象
Class c = Class.forName("cn.it.FanShe.Person");
//获取Person对象
Person p = (Person) c.newInstance();
//获取公有的name
Field name1 = c.getField("name");
//给name设置值
name1.set(p,"张三");
//输出name,如果单一输出name是一个字符串值,所以要使用gei方法
System.out.println(name1.get(p));
//结果:张三
//获取私有的age
Field age = c.getDeclaredField("age");
//暴力反射,因为age是私有的
age.setAccessible(true);
//输出变量 int类型默认值是0
System.out.println(age.getInt(p));
//结果:0
我们通过一个简单的例子来演示一下:
需求:在不改动源码的情况下,执行不同类中不同的方法。
分析:我们可以通过配置properties文件的方式,指定所要加载的类路径和要执行的方法的名称,然后通过反射创建该类的对象,并且获取该类的方法并执行,这样就可以做到不改动源码的情况下,运行不同类中的不同方法了。
这是测试中使用到的两个实体类
public class Person {
public void sleep(){
System.out.println("睡觉!");
}
public void eat(){
System.out.println("吃饭!");
}
}
public class Student {
public void study(){
System.out.println("学生要学习!");
}
}
这是主代码:
public class TestDemo {
public static void main(String[] args)throws Exception {
//读取配置文件
InputStream in = TestDemo.class.getClassLoader().getResourceAsStream("pro.properties");
//创建Properties对象
Properties pro = new Properties();
//把读取到的内容存储到Properties集合中
pro.load(in);
//获取配置文件中的value
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//通过反射获取Person的Class对象
Class c = Class.forName(className);
//通过Class对象获取Person中的方法对象
Method m = c.getMethod(methodName);
//创建对象反射的对象
Object o = c.newInstance();
//执行该方法
m.invoke(o);
}
}
当properties文件中配置的是这些时:结果就是运行的Person类中的eat方法,如果想运行其他方法,直接改properties文件中的value值就行,不需要动源代码了,这样就减少了该动源代码的频率。
className=cn.it.Demo.Person
methodName=eat
有不对的地方请各位指点!觉得还行的话就给个支持吧!