1.什么是反射?---描述类的编译阶段
1.1 如何获取Person类的字节码文件对象呢?1.2 如何通过字节文件对象获取构造器对象Constructor,创建类的实例!1.3 如何通过反射的方式,获取带参数的构造方法,创建当前类的实例!1.4 如何通过类的字节码文件对象获取成员变量所在的Field类对象,并对成员属性赋值! 2.反射的应用
2.1 有一个ArrayList集合,ArrayList,里面添加一些字符串元素 如何给ArrayList添加Integer类型的元素?2.2 已知两个类Student/Worker类,里面都有一个love()方法 在测试类Test2中,测试的时候,当需要学生类的时候,调用love->爱学习,爱生活,啥都爱!"
1.什么是反射?—描述类的编译阶段反射:
通过获取类或者接口的字节码文件对象,(正在运行的类)Class类对象,
然后获取类中构造方法所在的对象java.lang.reflect.Constructor,创建当前类实例
然后还可以获取类中的成员方法所在的java.lang.reflect.Field对象,然后去给成员变量赋值
还可以获取类中的成员方法所在的java.lang.reflect.Method对象,可以调用成员方法了!
Object类的getClass()方法;
任意Java类型的class属性
在Class类中有一个静态功能(使用居多:参数为String类型–>可以放在配置文件中)
public static Class> forName(String className) throws ClassNotFoundException
参数是所需类的全限定名称(包名.类名)
public class PersonDemo {
public static void main(String[] args) throws ClassNotFoundException {
Person p1 = new Person() ;
System.out.println(p1);
Person p2 = new Person() ;
System.out.println(p2);
System.out.println(p1 == p2); //false,都需要在堆内存中开辟空间
System.out.println("===========================================");
//方法1:Object类的getClass()方法
Class c1 = p1.getClass();
System.out.println(c1);
Class c2 = p2.getClass() ;
System.out.println(c2);
System.out.println(c1 == c2);
System.out.println("============================================");
//方法2:任意Java类型的class属性(最直接的)
Class c3 = Person.class ;
System.out.println(c3);
System.out.println(c1 == c3);
System.out.println(c2 == c3);
System.out.println("===========================================");
//方法3:
//forName()所需类的完全限定名称(包名.类名)
Class c4 = Class.forName("com.qf.reflect.Person") ;
System.out.println(c4);//class com.qf.reflect.Person
System.out.println(c1 == c4);
System.out.println("=============================================");
//public String getName();获取字节码文件对象中的全限定名称
String name = c4.getName() ;
System.out.println(name);//com.qf.reflect.Person
}
}
1.2 如何通过字节文件对象获取构造器对象Constructor,创建类的实例! 之前的写法:
创建一个Person类对象,无参构造方法公共的 类名 对象名 = new 类名() ;
现在:
使用反射的方式来创建Person类的实例
1)获取Person类的字节码文件对象Class
2)获取构造方法Constructor类对象
getConstructors() :获取类中所有的公共的构造方法的类对象
getDeclaredConstructors() :获取当前类中所有的构造方法的类对象(包括私有)
3)通过构造方法Construcotr类对象来创建当前类的实例!
4)输出对象名称
import java.lang.reflect.Constructor;
public class ReflectDemo {
public static void main(String[] args) throws Exception {
//之前的写法
Person p = new Person() ;//Person{name='null', age=0, gender='null'}
System.out.println(p);
System.out.println("=====================");
//1)获取字节码文件对象
Class c = Class.forName("com.qf.reflect.Person") ;
//2)获取指定的公共的无参构造方法
Constructor constructor = c.getConstructor() ;
//3) 通过构造方法Constructor类对象来创建当前类的实例!
//public T newInstance(Object... initargs):创建当前类的实例 ,参数可变参数, 描述给构造方法的实际参数
Object obj = constructor.newInstance();
System.out.println(obj); //obj---->相当上面的p对象
}
}
1.3 如何通过反射的方式,获取带参数的构造方法,创建当前类的实例! import java.lang.reflect.Constructor;
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
//1)获取Person类的字节码文件对象
Class personClazz = Class.forName("com.qf.reflect.Person") ;
//2)获取指定的构造方法的类对象Constructor
//获取指定的构造方法,参数是参数类型的字节码文件对象
// private Person(String name,int age)
Constructor constructor = personClazz.getDeclaredConstructor(String.class,int.class,String.class) ;
//参数为true,取消java语言访问检查
constructor.setAccessible(true);
Object obj = constructor.newInstance("张三",23,"女") ;
System.out.println(obj);
//Person{name='张三', age=23, gender='女'}
}
}
1.4 如何通过类的字节码文件对象获取成员变量所在的Field类对象,并对成员属性赋值! import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class ReflectDemo3 {
public static void main(String[] args) throws Exception{
//1)获取字节码文件对象
Class clazz = Class.forName("com.qf.reflect.Person") ;
//通过字节码文件对象获取公共的空参构造方法类对象
Constructor con = clazz.getConstructor() ;
//通过con构造方法类对象创建当前类实例(Person)
Object obj = con.newInstance();//
//System.out.println(obj);
//2)通过字节码文件对象获取指定的公共的字段的类对象Field
Field nameField = clazz.getField("name");
//field的特有的方法-->给成员变量赋值
//参数1:当前指定的实例
//参数2:给成员变量实际参数
nameField.set(obj,"高圆圆");
//获取指定的字段类对象(包括私有,受保护的,默认的修饰符)
//getDeclaredField(String name)
Field ageField = clazz.getDeclaredField("age");
//取消java语言访问检查
ageField.setAccessible(true);
//赋值
ageField.set(obj,43) ;
System.out.println(obj);
}
}
import java.lang.reflect.Method;
import java.util.ArrayList;
public class ReflectArrayListDemo {
public static void main(String[] args) throws Exception {
//创建一个ArrayList
ArrayList arrayList = new ArrayList<>() ;
arrayList.add("hello") ;
arrayList.add("world") ;
arrayList.add("javaEE") ;
System.out.println(arrayList);
//通过反射获取ArrayList集合的字节码文件对象
//一共三种方式
Class clazz = arrayList.getClass() ;
System.out.println(clazz);
//获取当前的这个成员方法所在Method类对象
Method m = clazz.getMethod("add",Object.class) ;
//调用方法
m.invoke(arrayList,100) ;
m.invoke(arrayList,200) ;
System.out.println(arrayList);
}
}
2.2 已知两个类Student/Worker类,里面都有一个love()方法 在测试类Test2中,测试的时候,当需要学生类的时候,调用love->爱学习,爱生活,啥都爱!"
//学生类
public class Student {
public void love(){
System.out.println("爱学习,爱生活,啥都爱!");
}
}
// 工人类
public class Worker {
public void love(){
System.out.println("爱生活,爱java");
}
}
//classname.properties文件
className=com.qf.reflect_02.Worker
methodName=love
//测试类
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
public class Test2 {
public static void main(String[] args) throws Exception {
//1)读取src下面的配置文件classname.properties ---->获取src类路径下的资源文件所在的输入流
InputStream inputStream = Test2.class.getClassLoader() .getResourceAsStream("classname.properties") ;
//2) 创建一个属性列表集合类对象:Properties
Properties prop = new Properties() ;
//将配置文件中的内容加载到属性列列表集合中
prop.load(inputStream);
//3)获取className键对应的值
String className = prop.getProperty("className") ;
String methodName = prop.getProperty("methodName") ;
//4)获取当前className键对应的类型的字节码文件对象
Class clazz = Class.forName(className);
//直接创建当前类的实例
Object obj = clazz.newInstance();
//5)通过字节码文件对象获取成员方法Method对象
Method method = clazz.getMethod(methodName);
//6)调用方法
method.invoke(obj) ;
}
}



