反射
1、类加载基础知识
2、类加载器
//类加载器基础知识
public class ClassLoaderDemo1 {
public static void main(String[] args) {
//获取委派的系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);//结果:AppClassLoader
//获取AppClassLoader父类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);//结果:ExtClassLoader
//获取ExtClassLoader父类加载器
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);//结果:null,它是虚拟机的内置加载器,通常表示null
}
}
3、反射概述
4、获取Class类的对象
//获取Class类的对象
public class ClassLoaderDemo2 {
public static void main(String[] args) throws ClassNotFoundException{
//第一种方式:使用Class类的属性获取该类的Class对象
//这种方式最便捷,适合测试代码
Class<Student> c1 = Student.class;
System.out.println(c1);
Class<Student> c2 = Student.class;
System.out.println(c1==c2);
System.out.println("------------");
//第二种方式:调用对象的getClass()方法,返回该对象所属类对应的Class对象
Student stu = new Student();
Class<? extends Student> c3 = stu.getClass();
System.out.println(c1==c3);
System.out.println("------------");
//第三种方式:使用Class类中的静态方法forName(String className)
//这个方式可以把路径配置到一个文件里面,灵活性更高
Class<?> c4 = Class.forName("ClassLoader.Student");
System.out.println(c1==c4);
}
}
5、反射获取构造方法并使用
//反射获取构造方法并使用
public class ClassLoaderDemo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException,
IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<?> c = Class.forName("ClassLoader.Student");
/*获取公共方法:Constructor<?>[] getConstructors()
获取私有、默认方法:Constructor<?>[] getDeclaredConstructors()
*/
//Constructor<?>[] cons = c.getConstructors();//获取Class类中的所有公共方法用这个
Constructor<?>[] cons = c.getDeclaredConstructors();//获取Class类中的所有私有方法、默认方法没用这个
for(Constructor con:cons){
System.out.println(con);
}
System.out.println("----------------");
//获取Class类中的单个方法getConstructor(Class<?>...parameterType)
//getDeclaredConstructor(Class<?>...parameterType)
//参数表示的意思是:需要获取的构造方法的参数个数和数据类型对应的字节码文件对象
Constructor<?> con = c.getConstructor();//获取无参构造方法
Object obj = con.newInstance();//Constructor中创建对象的方法
System.out.println(obj);//结果:Student{name='null', age=0, address='null'}
}
}
6、反射获取构造方法并使用的练习
/*练习一:反射获取构造方法并使用的练习
* Student s = new Student("林小小",30,"西安");
* System.out.println(s);
* 练习二:Student s = new Student("林大小");
* System.out.println(s);
* */
public class ClassLoaderDemo4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<?> c = Class.forName("ClassLoader.Student");
//基本数据类型也可以通过.class获取到对应的Class类型
Constructor<?> con = c.getConstructor(String.class, int.class, String.class);//公共方法
//能Class类的成员变量赋值
Object obj = con.newInstance("林小小", 30, "西安");
System.out.println(obj);
System.out.println("--------------");
Constructor<?> con1 = c.getDeclaredConstructor(String.class);//私有方法
//暴力反射:setAccessible(boolean flag);值为true就取消访问检查,否则会抛异常
con1.setAccessible(true);
Object obj1 = con1.newInstance("林大小");
System.out.println(obj1);
}
}
7、反射获取成员变量并使用
//反射获取成员变量并使用
public class ClassLoaderDemo5 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<?> c = Class.forName("ClassLoader.Student");
//Field[] fields = c.getFields();//获取公共成员变量
Field[] fields = c.getDeclaredFields();//获取所有成员变量
for (Field field: fields) {
System.out.println(field);
}
System.out.println("--------");
Field addressField = c.getField("address");//获取单个的,公共的成员变量
//获取无参构造方法,创建对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
addressField.set(obj,"深圳");//给obj的成员变量addressField赋值为深圳
System.out.println(obj);
//获取单个的,非公共的成员变量
........
}
}
8、反射获取成员变量的练习
//通过反射给成员变量赋值小练习
public class ClassLoaderDemo6 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException,
IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class<?> c = Class.forName("ClassLoader.Student");
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
//ield nameField = c.getField("name");//获取公共方法
Field nameField = c.getDeclaredField("name");//获取私有方法
nameField.setAccessible(true);//暴力反射
nameField.set(obj,"林小小");
System.out.println(obj);
Field ageField = c.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj,30);
System.out.println(obj);
Field addressField = c.getDeclaredField("address");
addressField.setAccessible(true);
addressField.set(obj,"深圳");
System.out.println(obj);
}
}
9、反射获取成员方法并使用
//反射获取成员方法并使用
public class ClassLoaderDemo7 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//第一步
Class<?> c = Class.forName("ClassLoader.Student");
//Method[] methods = c.getMethods();//获取公共方法,返回对象方法的数组。包含继承的父类方法
Method[] methods = c.getDeclaredMethods();//获取私有方法,只有本类的私有方法
for(Method method: methods){
System.out.println(method);
}
System.out.println("---------------");
//第二步
Method m = c.getMethod("method1");//获取单个成员方法
//获取无参构造方法,创建对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
/*Object invoke(Object obj,Object...args )在具有指定参数的指定对象上调用此方法表示的基础方法
Object:是返回值类型
obj: 是调用方法的对象
Object...args: 是方法需要的参数
* */
//第三步:其实就是调用obj对象的成员方法m,实际就是调用的成员方法method1
m.invoke(obj);//调用了Student类中的method1方法,无参
//getConstructor()与之对应的还有c.getDeclaredMethod("");
}
}
10、反射获取成员方法并使用小练习
//反射获取成员方法并使用小练习
/*Student = new Student();
s.method1();
s.method2("林小小");
String ss = s.method3("林大小",32);
System.out.println(ss);
s.function();
*/
public class ClassLoaderDemo8 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> c = Class.forName("ClassLoader.Student");//获取Class对象
Constructor<?> con = c.getConstructor();//通过无参构造方法创建一个对象
Object obj = con.newInstance();
Method m1 = c.getMethod("method1");//通过对象获取method1方法,无参
m1.invoke(obj);
Method m2 = c.getMethod("method2", String.class);//通过对象获取method2方法,有参
m2.invoke(obj,"林小小");
Method m3 = c.getMethod("method3", String.class, int.class);//通过对象获取method2方法,有参,有返回值
Object ob = m3.invoke(obj, "林大小", 32);
System.out.println(ob);
Method m4 = c.getDeclaredMethod("function");//通过对象获取调用function()私有方法,无参,无返回值
m4.setAccessible(true);//暴利反射,针对私有方法
m4.invoke(obj);
}
}
11、反射练习之越过泛型检查
注:1、通过反射可以反问类的私有成员
2、通过反射也可以给指定数据类型集合中添加其它类型数据
//反射练习2: ArrayList<Integer>集合,在集合中香港一个String类型的字符串数据
//反射可以越过检查,获取原始参数类型,原始的方法参数类型Object就可以存储任意类型的数据
public class ClassLoaderDemo9 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ArrayList<Integer> array = new ArrayList<>();
array.add(10);
array.add(20);
Class<? extends ArrayList> c = array.getClass();//首先要获取该集合的Class对象
Method m = c.getMethod("add", Object.class);//类型是Object类型,并没有指定是Integer类型
m.setAccessible(true);//暴利反射
m.invoke(array,"林小小");//往集合中添加String类型的字符串
m.invoke(array,"林大小");
m.invoke(array,"林小");
System.out.println(array);
}
}
12、 反射练习之运行配置文件指定内容
//通过配置文件,运行类中的方法
public class ClassLoaderDemo10 {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { /*配置文件运行类中的方法,解决问题是主方法中如果需要来回切换调用不同类的方法问题
Student s = new Student();
s.study();
Teacher t = new Teacher();
t.teach();*/
//创建一个txt文件,文件中配置有一个className= 类名,methodName= 方法名字
Properties p = new Properties();//第一步:加载数据
FileReader fr = new FileReader("F:\\test\\class.txt");//获取配置文件地址
p.load(fr);//拿到配置文件中的数据
fr.close();
//第二步:根据对应的键,获取对应的值
String className = p.getProperty("className");
String methodNmae =p.getProperty("methodName");
//通过反射来使用
Class<?> c = Class.forName(className);//这一步获取的是ClassLoader.Student
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();//创建对象
Method m = c.getMethod(methodNmae);//这一步拿的是study
m.setAccessible(true);//暴力反射
m.invoke(obj);
}
}