目录
反射概述
反射是指对于任何一个Class类,在”运行的时候”都可以直接得到这个类全部成分。
在运行时,可以直接得到这个类的构造器对象:Constructor
在运行时,可以直接得到这个类的成员变量对象:Field
在运行时,可以直接得到这个类的成员方法对象:Method
这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制。
反射的关键: 反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分。 例如:Class c = People.class;
反射的核心思想和关键就是:得到编译以后的class文件对象。
反射的作用:反射是在运行时获取类的字节码文件对象:然后可以解析类中的全部成分
反射获取类对象
反射的第一步:获取Class类的对象
方法一:Class c1 = Class.forName(“全类名”);
方法二:Class c2 = 类名.class
方法三:Class c3 = 对象.getClass();
public class People {
private String name;
private int age;
}
public class TestPeople0 {
public static void main(String[] args) throws Exception {
// 1.Class类中的静态方法
Class c = Class.forName("one.People");
System.out.println(c);
// 2.类名.class
Class c0 = People.class;
System.out.println(c0);
// 3.获取对象对应类的Class对象
People p = new People();
Class c1 = p.getClass();
System.out.println(c1);
}
}
反射获取构造器对象
获得class对象 ===》 获取构造器 ===》 创建对象
第二步:获得Constructor对象
提取构造器,具体使用在代码中:
1.Constructor[] constructors = c.getConstructors();
2.Constructor[] constructors = c.getDeclaredConstructors();
3.Constructor constructor = c.getConstructor();
4.Constructor constructor = c.getDeclaredConstructor();
Constructor<?>[] getConstructors() |
返回所有构造器对象的数组(只能拿public的) |
Constructor<?>[] getDeclaredConstructors() |
返回所有构造器对象的数组,存在就能拿到 |
Constructor<T> getConstructor(Class<?>… parameterTypes) |
返回单个构造器对象(只能拿public的) |
Constructor<T> getDeclaredConstructor(Class<?>… parameterTypes) |
返回单个构造器对象,存在就能拿到 |
public class People {
private String name;
private int age;
public People(){
System.out.println("无参构造!");
}
private People(String name, int age){
this.name = name;
this.age = age;
System.out.println("有参构造!");
}
public class TestPeople1 {
public void getConstructors(){
//1.获取类对象
Class c = People.class;
//2.提取类中的全部构造器对象----私有的拿不到,只能拿public的
Constructor[] constructors = c.getConstructors();
//遍历构造器
for(Constructor constructor : constructors)
System.out.println(constructor.getName()+"--->"+constructor.getParameterCount()); //名字--->参数个数
}
public void getDeclaredConstructors(){
//1.获取类对象
Class c = People.class;
//2.提取类中的全部构造器对象----私有的也能拿到
Constructor[] constructors = c.getDeclaredConstructors();
//遍历构造器
for(Constructor constructor : constructors)
System.out.println(constructor.getName()+"--->"+constructor.getParameterCount()); //名字--->参数个数
}
public void getConstructor() throws NoSuchMethodException {
//1.获取类对象
Class c = People.class;
//2.提取类中的一个构造器对象--根据参数拿对应构造器---只能拿public的
Constructor constructor = c.getConstructor();
//名字--->参数个数
System.out.println(constructor.getName()+"--->"+constructor.getParameterCount());
}
public void getDeclaredConstructor() throws NoSuchMethodException {
//1.获取类对象
Class c = People.class;
//2.提取类中的一个构造器对象--根据参数拿对应构造器---私有的也能拿到
Constructor constructor = c.getDeclaredConstructor(String.class, int.class);
//名字--->参数个数
System.out.println(constructor.getName()+"--->"+constructor.getParameterCount());
}
public static void main(String[] args) throws Exception {
TestPeople1 a = new TestPeople1();
a.getConstructors();
a.getDeclaredConstructors();
a.getConstructor();
a.getDeclaredConstructor();
}
}
第三步创建对象:
constructor.setAccessible(true); 暴力开权限,反射可以破坏其封装性–私有的才需要开权限,公有的不需要
Object p = constructor.newInstance(); 根据对应的构造器,创建对象—可强制转换
以下代码是在上面的基础上进行增添,具体使用在代码中:
import java.lang.reflect.Constructor;
public class TestPeople2 {
public void getObject() throws Exception {
//1.获取类对象
Class c = People.class;
//2.提取类中的一个构造器对象--根据参数拿对应构造器---私有的也能拿到
Constructor constructor = c.getDeclaredConstructor(String.class, int.class);
//名字--->参数个数
System.out.println(constructor.getName()+"--->"+constructor.getParameterCount());
//私有构造器报错,不能创建对象,,需要暴力反射--开权限--setAccessible(true)
constructor.setAccessible(true); //只针对这一次有效
Object p = constructor.newInstance("小明", 18); //创建对象People,18岁的小明
}
public static void main(String[] args) throws Exception {
TestPeople2 p = new TestPeople2();
p.getObject();
}
}
反射获取成员变量对象
获得class对象 ===》 获取成员变量 ===》 取值或赋值
第一步:获得class对象
第二步:获得Field对象
Field[] fields = c.getDeclaredFields(); 获取全部成员变量 Field field = c.getDeclaredField("name"); 获取其中一个成员变量----根据变量名称获取
Field[] getFields() |
返回所有成员变量对象的数组(只能拿public的) |
Field[] getDeclaredFields() |
返回所有成员变量对象的数组,存在就能拿到 |
Field getField(String name) |
返回单个成员变量对象(只能拿public的) |
Field getDeclaredField(String name) |
返回单个成员变量对象,存在就能拿到 |
第三步:获取值或赋值
Field field = c.getDeclaredField(“age”);
get方法,取值 field.get(对象);
set方法,赋值 field.set(对象, 值);
void set(Object obj, Object value): |
赋值 |
Object get(Object obj) |
获取值。 |
具体使用在代码中:
import java.lang.reflect.Field;
public class TestPeople3 {
public void getDeclaredFields(){
//1.获取class对象
Class c = People.class;
//2.获取全部成员变量
Field[] fields = c.getDeclaredFields();
//遍历
for(Field field : fields)
System.out.println(field.getName() + "--->" + field.getType()); //名字--->类型
}
public void getDeclaredField() throws Exception {
//1.获取class对象
Class c = People.class;
//2.获取其中一个成员变量----根据名称获取某个成员变量
Field field = c.getDeclaredField("age");
//输出 名字--->类型
System.out.println(field.getName() + "--->" + field.getType());
//3.赋值
field.setAccessible(true); //暴力开权限---private成员变量不能直接操作
People p = new People();
field.set(p, 18);
System.out.println("赋值age:"+p.getAge());
//4.取值
int age = (int)field.get(p);
System.out.println("取值age:"+age);
}
public static void main(String[] args) throws Exception {
TestPeople3 p = new TestPeople3();
p.getDeclaredFields();
p.getDeclaredField();
}
}
反射获取方法对象
获得class对象 ===》 获取方法 ===》 触发执行方法
第一步:获得class对象
第二步:获得Method对象
Method[] getMethods() |
返回所有成员方法对象的数组(只能拿public的) |
Method[] getDeclaredMethods() |
返回所有成员方法对象的数组,存在就能拿到 |
Method getMethod(String name, Class<?>… parameterTypes) |
返回单个成员方法对象(只能拿public的) |
Method getDeclaredMethod(String name, Class<?>… parameterTypes) |
返回单个成员方法对象,存在就能拿到 |
第三步:Method类中用于触发执行的方法
成员方法是非public的,需要打开权限(暴力反射),然后再触发执行—-setAccessible(boolean)
Object invoke(Object obj, Object… args) |
运行方法 参数一:用obj对象调用该方法 参数二:调用方法的传递的参数(如果没有就不写) 返回值:方法的返回值(如果没有就不写) |
具体使用在代码中:
import java.lang.reflect.Method;
public class TestPeople4 {
public void getDeclareMethods(){
//1.获取类对象
Class c = People.class;
//2.提取全部方法,包括私有的
Method[] methods = c.getDeclaredMethods();
//遍历
for (Method method : methods) //名字--->返回类型--->参数个数
System.out.println(method.getName()+"--->"+method.getReturnType()+"--->"+method.getParameterCount());
}
public void getDeclareMethod() throws Exception {
//1.获取类对象
Class c = People.class;
//2.提取某一个方法,根据名字
Method method1 = c.getDeclaredMethod("setAge", int.class);
Method method2 = c.getDeclaredMethod("getAge");
//名字--->返回类型--->参数个数
System.out.println(method1.getName()+"--->"+method1.getReturnType()+"--->"+method1.getParameterCount());
System.out.println(method2.getName()+"--->"+method2.getReturnType()+"--->"+method2.getParameterCount());
//3.方法的触发执行
//如果方法不是public的,需要打开权限(暴力反射),然后再触发执行----setAccessible(boolean)
People p = new People();
Object a1 = method1.invoke(p, 20);
Object a2 = method2.invoke(p);
//若方法是无返回结果的,则返回的是null
System.out.println(a1);
System.out.println(a2);
}
public static void main(String[] args) throws Exception {
TestPeople4 p = new TestPeople4();
p.getDeclareMethods();
p.getDeclareMethod();
}
}
反射的作用-绕过编译阶段为集合添加数据
1.反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素
2.泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList了,泛型相当于被擦除了。
具体使用在代码中:
import java.lang.reflect.Method;
import java.util.ArrayList;
public class TestDemo5 {
public static void main(String[] args) throws Exception {
// 需求:反射实现泛型擦除后,加入其他类型的元素
//编译成Class文件进入运行阶段的时候,泛型会自动擦除。反射是作用在运行时的技术,此时已经不存在泛型了。
//故反射不受泛型的约束
ArrayList<String> lists1 = new ArrayList<>();
ArrayList<Integer> lists2 = new ArrayList<>();
System.out.println(lists1.getClass());
System.out.println(lists2.getClass());
System.out.println(lists1.getClass() == lists2.getClass()); //ArrayList.class
ArrayList<Integer> lists3 = new ArrayList<>();
lists3.add(11);
lists3.add(22);
// list3.add("小孩"); 类型不符合,错误
Class c = lists3.getClass(); //ArrayList.class
//获取c类中的add方法------不受泛型Integer的约束
Method add = c.getDeclaredMethod("add", Object.class);
//判断添加是否成功
boolean ans = (boolean) add.invoke(lists3, "小孩");
System.out.println(ans);
System.out.println(lists3);
}
}
反射的作用-通用框架的底层原理
下面是一个实例:
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
// 提供一个通用框架,支持保存所有对象的具体信息。
public class TestDemo2 {
//保存任意类型的对象 Object
public static void save(Object obj){
try (//文件输出到data.txt中
PrintStream ps = new PrintStream(new FileOutputStream("demo1/src/data.txt", true));
){
//1.获取该类对象
Class c = obj.getClass();
ps.println("---------------> " + c.getSimpleName() + " <---------------");
//2.提取该对象的全部成员变量
Field[] fields = c.getDeclaredFields();
for (Field field: fields){
//暴力开权限
field.setAccessible(true);
//获取成员变量名字
String name = field.getName();
//取值
String value = field.get(obj) + "";
ps.println(name + "=" + value);
}
}catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
Worker w = new Worker(22, '男', "张三");
save(w);
}
}
反射的作用—–总结
- 可以在运行时得到一个类的全部成分然后操作。
- 可以破坏封装性。(很突出)
- 也可以破坏泛型的约束性。(很突出)
- 更重要的用途是适合:做Java高级框架 基本上主流框架都会基于反射设计一些通用技术功能。
如果有错误,大哥们指出来,我会改的!!