> 文档中心 > JAVA反射----->看这篇就够了

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);    }    }

反射的作用-----总结

  1. 可以在运行时得到一个类的全部成分然后操作。
  2. 可以破坏封装性。(很突出)
  3. 也可以破坏泛型的约束性。(很突出)
  4. 更重要的用途是适合:做Java高级框架 基本上主流框架都会基于反射设计一些通用技术功能。

如果有错误,大哥们指出来,我会改的!!