你知道反射吗?

Java的反射:(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键

  1. 反射机制允许程序在执行期间借助于ReflectionAPI取得任何类的内部信息,比如成员变量,构造器,成员方法等,并能操作对象的属性及其方法,反射在设计模式和框架底层都会用到
  2. 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象)这个对象包含了类的完整信息结构,通过这个对象,就可以了解全部信息,Class对象犹如镜子的反射人物对象,在镜子中能获取全部的Class信息

Java加载示意图:

简单来说反射就犹如人照镜子一样,能通过一个Class对象了解全部信息

为什么要使用反射:

  1. 反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力。
  2. 通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类。
  3. 使用反射机制能够在运行时构造一个类的对象,判断一个类所具有的成员变量和方法,调用一个对象方法。
  4. 反射机制还是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中。正因为反射,Java才被称为动态语言。

Class类:

  1. Class也是类,因此也继承Object类
  2. Class类对象不是new出来的,而是系统创建的
  3. 对于某个Class对象,在内存中只存在一份,因为只类加载一次
  4. 每个类的实例对象都会记得自己是有哪个Class实例所构成的
  5. 通过Class对象可以完整的得到一个类的完整结构
  6. Class对象是存放在堆区的
  7. 类的字节码二进制数据,是在方法区的,有的地方称为类的元数据

几种获取Class的方式:

import org.testng.annotations.Test;
public class TestReflection01 {
   @Test
   public void Test() throws ClassNotFoundException {
      /*
      1:通过配置文件获取Class对象
       */
      Class<?> aClass = Class.forName("TestStudent");
      System.out.println("第一种方法通过配置文件:"+aClass.getName());
      /*
      2:通过类名.Class获取Class对象
       */
      Class<TestStudent> testStudentClass = TestStudent.class;
      System.out.println("第二种通过类名.class获取Class对象:"+testStudentClass.getName());
      /*
      3:通过实例对象,来获取Class对象
       */
      TestStudent testStudent = new TestStudent();
      System.out.println("第三种通过实例获取Class对象:"+testStudent.getClass().getName());
      /*
      4:通过类加载器获取Class对象
       */
      Class<?> testStudent1 = TestStudent.class.getClassLoader().loadClass("TestStudent");
      System.out.println("第四种通过类加载器:"+testStudent.getClass().getName());
   }
}
class TestStudent{
   /*
   四个不同的属性
    */
   private String name;
   protected int age;
   double height;
   public char sex ;
   public TestStudent(){}
}

运行结果:

 哪些类型有Class对象:

  1. 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
  2. interface:接口
  3. 数组
  4. Enum:枚举
  5. Annotation:注解
  6. 基本数据类型
  7. 方法(void)等

运用Class,通过反射获取属性:

@Test
   public void TestGetFileds() throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
      //获取一个Class对象
      Class<?> aClass = Class.forName("TestStudent");
      //使用newInstance实例化一个对象
      TestStudent student = (TestStudent) aClass.newInstance();//转成TestStudents类型

      //通过反射获取属性
      //使用.getField()获取公有Sex的属性
      Field sex = aClass.getField("sex");
      System.out.println(sex.getName());
      System.out.println(sex.get(student));//取得该student实例化对象的sex值
      /*
      通过反射获取私有的属性需要进行一步暴破操作,因为私有的属性反射不能够直接获取,需要使用
       */
      Field name = aClass.getDeclaredField("name");
      name.setAccessible(true);//将私有的属性设置为可得到的,也就是暴破操作
      System.out.println(name+"\t"+name.get(student));
      //修改属性
      name.set(student,"Jerry");//传入的参数为修改的对象,已经修改的参数值
      System.out.println(name.get(student));
   }
@SuppressWarnings("ALL")
class TestStudent{
   /*
   四个不同的属性
    */
   private String name = "Tom";
   protected int age = 20;
   double height = 177;
   public char sex  = '男';
   public TestStudent(){}

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public int getAge() {
      return age;
   }

   public void setAge(int age) {
      this.age = age;
   }

   public double getHeight() {
      return height;
   }

   public void setHeight(double height) {
      this.height = height;
   }

   public char getSex() {
      return sex;
   }

   public void setSex(char sex) {
      this.sex = sex;
   }
}

运行结果:

通过反射获取方法:

@Test
   public void TestGetMethod() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
      //获取一个Class对象
      Class<?> aClass = Class.forName("TestStudent");
      //使用newInstance实例化一个对象
      TestStudent student = (TestStudent) aClass.newInstance();//转成TestStudents类型
      //获取公有的方法1
      Method method1 = aClass.getMethod("method1");
      method1.invoke(student);//调用该student对象的方法1

      //获取私有的方法2 ,3 ,4,也要使用setAccessible(true)进行暴破操作
      Method method4 = aClass.getDeclaredMethod("method4");
      method4.setAccessible(true);
      method4.invoke(student);
      //剩下的还有一些方法就自己去测试吧
   }

@SuppressWarnings("ALL")
class TestStudent{
   /*
   四个不同的属性
    */
   private String name = "Tom";
   protected int age = 20;
   double height = 177;
   public char sex  = '男';
   public TestStudent(){}

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public int getAge() {
      return age;
   }

   public void setAge(int age) {
      this.age = age;
   }

   public double getHeight() {
      return height;
   }

   public void setHeight(double height) {
      this.height = height;
   }

   public char getSex() {
      return sex;
   }

   public void setSex(char sex) {
      this.sex = sex;
   }

   public void method1(){
      System.out.println("这是public的方法1");
   }
   void method2(){
      System.out.println("这是default的方法2");
   }
   protected void method3(){
      System.out.println("这是protected方法3");
   }
   private void method4(){
      System.out.println("这是private方法4");
   }
   @Override
   public String toString() {
      return "TestStudent{" +
            "name='" + name + '\'' +
            ", age=" + age +
            ", height=" + height +
            ", sex=" + sex +
            '}';
   }
}

通过反射获取构造器创建实例:

 @Test
   public void TestGetConstructor() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
      //获取一个Class对象
      Class<?> aClass = Class.forName("TestStudent");
      Constructor<?> constructor = aClass.getConstructor();//获得一个public空参构造器
      TestStudent testStudent = (TestStudent) constructor.newInstance();//实例化对象
      System.out.println("这是公有的无参构造器:"+testStudent.toString());

      //获得一个公有的带参构造器
      Constructor<?> constructor1 = aClass.getConstructor(String.class,int.class,double.class);//传入参数的class对象
      TestStudent testStudent1 = (TestStudent) constructor1.newInstance("Jerry",25,178.9);//实例化对象,传入参数
      System.out.println("这是公有的有参构造器:"+testStudent1.toString());

      //获取私有构造器
      Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class, int.class);
      declaredConstructor.setAccessible(true);//暴破操作
     TestStudent testStudent2 = (TestStudent) declaredConstructor.newInstance("Frank", 44);
      System.out.println("这是私有的有参构造器:"+testStudent2.toString());
   }
@SuppressWarnings("ALL")
class TestStudent{
   /*
   四个不同的属性,分别赋予不同初始值
    */
   private String name = "Tom";
   protected int age = 20;
   double height = 177;
   public char sex  = '男';
   public TestStudent(){}//空构造器
   //带参构造器
   public TestStudent(String name,int age,double height)
   {
      this.name =name;
      this.age =age;
      this.height = height;
   }
   //私有构造器
   private TestStudent(String name,int age){
      this.name = name;
      this.age = age;
   }


   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public int getAge() {
      return age;
   }

   public void setAge(int age) {
      this.age = age;
   }

   public double getHeight() {
      return height;
   }

   public void setHeight(double height) {
      this.height = height;
   }

   public char getSex() {
      return sex;
   }

   public void setSex(char sex) {
      this.sex = sex;
   }
   @Override
   public String toString() {
      return "TestStudent{" +
            "name='" + name + '\'' +
            ", age=" + age +
            ", height=" + height +
            ", sex=" + sex +
            '}';
   }
}

运行结果:

总结:

public void AllMethod(){
      /**
       * 主要方法有这些
       * Class.forName()通过配置路径获取一个Class对象
       * 使用newInstance()实例化一个对象
       * :getName:获取全类名
       * :getSimpleName:获取简单类名
       * :getPackage()取得相应的包
       * :getSuperClass:以Class形式返回父类信息
       * getInterfaces:以Class[形式返回接口信息
       * getAnnotations:以Annotation[]形式返回注解信息
       *
       *
       * setAccessible(true),反射暴破操作,将私有的属性或者方法变为反射可得到的,因为私有的属性反射不能够直接获取,会发生NoSuchFieldException异常
       * Field
       * :getField:获取一个本类或者父类的属性,传入参数为属性名
       * :getDeclaredField:获取本类中的一个属性,传入参数为属性名
       * :getFields:获取所有public修饰的属性,包含本类以及父类的
       * :getDeclaredFields:获取本类中所有属性
       * :getFields:获取所有public修饰的属性,包含本类以及父类的
       *
       * Method
       * :getMethod:获取一个本类或者父类的方法,传入参数为属性名
       * :getDeclaredMethod:获取本类中一个方法,传入参数为属性名
       * :getMethods:获取所有public修饰的方法,包含本类以及父类的
       * :getDeclaredMethods:获取本类中所有方法
       * :method.invoke(Object o)调用方法
       *
       * Constructor
       * getConstructor()获取一个公有的构造器
       * getDeclaredConstructor()获取一个本类的构造器,根据传入参数的不同去匹配相应的构造器
       * getConstructors: 获取所有public修饰的构造器,包含本类以及父类
       * getDeclaredConstructors:获取本类中所有构造器
       * constructor.newInstance()实例化对象
       * 还有很多很多方法,这里就不一一列举了
       */

   }

以上就是全部内容啦,如有错误,请多海涵,谢谢啦。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爆可达鸭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值