一、反射的概念
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;
这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
二、获取字节码对象的三种方式
- 使用类名调用.class属性(.class不是只有类能调用)
- 使用一个类的对象调用.getClass()方法
- 使用Class类的静态方法forName("类全名")
/获取字节码对象的三种方式
//1.使用类名调用.class属性(.class不是只有类能调用)
Class c1 = String.class;
//2.使用一个类的对象调用.getClass()方法
Class c2 = "abd".getClass();
//3.使用Class类的静态方法forName("类全名")
Class c3 = Class.forName("java.lang.String");
System.out.println(c1 == c2);//true
System.out.println(c2 == c3);//true
三、反射操作构造方法
1、反射获取构造方法
Class类的方法:
-
getConstructor(Class... c) 可以获取某一个构造方法(公共的)
-
getConstructors() 可以获取所有的构造方法(公共的)
反射执行构造方法
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test02 {
public static void main(String[] args) throws Exception{
//获取类的字节码对象
Class c = Class.forName("com.itheima_02.Student");
//- getConstructors() 可以获取所有的构造方法(公共的)
//获取学生类的所有公共构造方法
//Constructor[] cons = c.getConstructors();
//遍历数组
//for (Constructor con : cons) {
// System.out.println(con);
//}
//- getConstructor(Class... c) 可以获取某一个构造方法(公共的)
//获取空参构造
Constructor con1 = c.getConstructor();
//获取有参构造
Constructor con2 = c.getConstructor(String.class,int.class);
//newInstance(Object... obj) : 执行当前构造方法创建对象。
//使用空参构造创建对象
Object o1 = con1.newInstance();
System.out.println(o1);
//o1就是一个空参创建的学生对象,显示的是父类Object,可以向下转型
//使用有参构造创建对象
Object o2 = con2.newInstance("石原里美",28);
System.out.println(o2);
//上面的反射和下面的创建对象功能一模一样,为什么要反射呢?一会说。
//Student stu = new Student("石原里美",28);
}
}
Constructor类的方法:
-
newInstance(Object... obj) : 执行当前构造方法创建对象。
Object... obj 表示的是创建对象时的实际参数。
四、反射操作成员方法
1、反射获取成员方法
Class类的方法:
getMethod(String name, Class... c) :获取一个成员方法(公共的)
String name 表示方法名称
Class... c 表示的是方法的参数的类型
getMethods() : 获取类中的所有方法(公共的)
反射执行成员方法
import java.lang.reflect.Method;
public class Test04 {
public static void main(String[] args) throws Exception{
//反射获取成员方法并执行
//获取类的字节码对象
Class c = Class.forName("com.itheima_02.Student");
//- getMethods() : 获取类中的所有方法(公共的)
//Method[] ms = c.getMethods();
//遍历数组
//for (Method m : ms) {
// System.out.println(m);
//}
//- getMethod(String name, Class... c) :获取一个成员方法(公共的)
//获取睡觉方法
Method m1 = c.getMethod("sleep");
//获取吃饭方法
Method m2 = c.getMethod("eat", String.class);
//Object invoke(Object obj , Object... o) :让方法执行
//第一个参数是对象,第二个参数是方法的实际参数,返回值是方法的实际返回值
//创建对象
Student s = new Student("石原里美",28);
// 返回值 = s.sleep(参数);
//执行睡觉方法
m1.invoke(s);
//执行吃饭方法
m2.invoke(s, "汉堡");
//需求:通过反射调用toString()
//获取方法
Method m3 = c.getMethod("toString");
//执行方法
Object o3 = m3.invoke(s);
System.out.println("o3是toString方法的返回值" + o3);
//上面的三行代码相当于
//String s3 = s.toString();
//System.out.println(s3);
//为什么要反射?一会说。
}
}
Method类的方法:
Object invoke(Object obj , Object... o) :让方法执行
第一个参数表示执行的对象
第二个参数表示方法的实际参数
返回值表示方法的实际返回值
五、暴力反射
反射正常情况下遵从java权限修饰的规则。
如果使用暴力反射就可以打破权限修饰符的规则。
写法: 在所有的获取方法之间加declared词就可以了,然后调用setAccessable(true)就表示可以访问了。
暴力反射一般不要用。
import java.lang.reflect.Constructor;
public class Test03 {
public static void main(String[] args) throws Exception{
//获取类的字节码对象
Class c = Class.forName("com.itheima_02.Student");
//获取有参构造
Constructor con2 = c.getDeclaredConstructor(String.class,int.class);
//设置可以访问
con2.setAccessible(true);
//使用有参构造创建对象
Object o2 = con2.newInstance("石原里美",28);
System.out.println(o2);
}
}
六、反射操作成员变量【了解】
import java.lang.reflect.Field;
public class Test05 {
public static void main(String[] args) throws Exception{
//获取字节码对象
Class c = Class.forName("com.itheima_02.Student");
//获取成员变量
//变量是私有的所以不能这么获取
//Field f1 = c.getField("age");
//System.out.println(f1);
//如果获取需要暴力反射
Field f2 = c.getDeclaredField("age");
System.out.println(f2);
//类中的成员变量因为遵从面向对象的语法,都会使用private修饰
//不让在外界直接使用
}
}
七、反射的作用案例演示
反射是框架的灵魂。
反射代码虽然复杂,但是可以配合配置文件,代码不需要修改,把灵活修改的部分放在配置文件中。
1、案例演示
配置文件
className=com.itheima_03.Cat
methodName=sleep
代码
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;
public class Test02使用反射 {
public static void main(String[] args) throws Exception {
//Properties配置文件
Properties prop = new Properties();
//读取文件的键值对
prop.load(new FileReader("day14\\abc.properties"));
//根据键获取值
String cn = prop.getProperty("className");
String mn = prop.getProperty("methodName");
//System.out.println(cn); //com.itheima_03.Dog
//System.out.println(mn); //eat
//反射获取字节码对象
Class c = Class.forName(cn);
//字节码获取构造方法
Constructor con = c.getConstructor();
//创建对象
Object o = con.newInstance(); //o其实是一个子类对象
//获取方法
Method m = c.getMethod(mn);
//执行方法
m.invoke(o);
}
}