JAVA反射----->看这篇就够了
目录
反射概述
反射获取类对象
反射获取构造器对象
反射获取成员变量对象
反射获取方法对象
反射的作用-绕过编译阶段为集合添加数据
反射的作用-通用框架的底层原理
反射的作用-----总结
反射概述
反射是指对于任何一个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 getConstructor(Class... parameterTypes) |
返回单个构造器对象(只能拿public的) |
Constructor 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 lists1 = new ArrayList(); ArrayList lists2 = new ArrayList(); System.out.println(lists1.getClass()); System.out.println(lists2.getClass()); System.out.println(lists1.getClass() == lists2.getClass()); //ArrayList.class ArrayList 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高级框架 基本上主流框架都会基于反射设计一些通用技术功能。
如果有错误,大哥们指出来,我会改的!!