【JAVA基础】反射


什么是反射

在java程序中,我们会在方法区中存储类信息,类信息包括变量、方法、对象、父类子类等等,那么我们如何获取这个类信息呢?就用到了反射

定义:反射(Reflection)是一种获取类信息的能力

我们一般会在Java程序运行期间,对某个实例对象一无所知的请情况下如何调用该对象内部方法的问题

原理:在Java程序运行的过程中,JVM加载完一个类之后,堆内存中就会产生一个该类的Class对象,这个对象有且只有一个,这个class对象包含了该类的完整结构信息(变量、方法…)

在这里插入图片描述

优缺点

  • 优点:可以动态的创建和使用对象,反射机制是Java框架的底层核心
  • 缺点:使用反射的基本是解释执行,对程序执行速度有影响

Class类

  1. Class也是一个类,类名就叫Class,因此也继承Object
  2. 又JVM在加载类时自动创建
  3. 堆内存中只存在某一个类的唯一Class对象,类只会加载一次
  4. 每个类的实例对象都会知道自己对应的Class对象
  5. 类的字节码二进制数据,是存放在方法区的,又称为类的元数据(包括方法代码、变量名、方法名、访问权限等等)

几个获取类信息的方法

创建一个Student类,包含一些不同修饰符修饰的变量和方法

public class Student {
    private String name = "zhangsan";
    public Integer age = 18;
    Character sex = '男';
    protected Double height = 180.5;
    public String color = "Blue";

    public void run(){}

    private int getAge(int age){
        return age;
    }
    
    void aaa(String name, Integer height){}
    
    protected  void hh(String name, int age){}
}

由于JVM为每个加载的类class创建了对应的Class类对象,并在实例中保存了该类class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,因此,如果获取了某个Class类对象,我们就可以通过这个Class类对象获取到其对应的类class的所有信息。这种通过Class实例获取类class信息的方法称为反射(Reflection)。

获取类信息的几个方法:

方法1:通过类class中的静态变量class直接获取

public class Test {
    public static void main(String[] args) throws Exception {
        // 想要获取类信息就必须先进入类对象阶段       
        Class class = Student.class; // class是Student类中的一个变量
    }
}

方法2:如果我们有一个类class对象。可以通过给对象引用提供的getClass()方法获取

Student student = new Student();
Class class = student,getClass();

方法3:如果知道一个类class的完整类名,可以通过Class类的静态方法Class.forName()获取

Class class = Class.forName("com.反射.Student");

方法4:对于基本数据类型(int、char、float等),通过基本数据类型的class获取

Class integerClass = int.class;
Class characterClass = char.class;
Class floatClass = float.class;
System.out.println(integerClass); // int

方法五:对于基本数据类型对应的包装类,可以通过类中的静态变量TYPE获取到Class类对象

Class type1 = Integer.TYPE;
Class type2 = Character.TYPE;
System.out.println(type1);// int
  • 因为Class类对象在JVM中是唯一的,所以上述方法中获取到的CLass类对象是同一个对象,可以用==比较两个类对象

Java类动态加载

反射机制是Java实现动态语言的关键,也就是通过反射实现类的动态加载

  1. 静态加载:编译时就加载的类,如果程序中不存在该类则编译报错,依赖性太强
  2. 动态加载:运行时加载相关的类,如果运行时未使用到该类,即使程序中不存在该类,也不会编译错误,依赖性较弱
  • 动态加载类class的特性对于 Java 程序非常重要。利用 JVM 动态加载class的特性,我们才能在运行期根据条件去加载不同的实现类。

访问字段

  • Field getField(name):根据字段名获取某个 public 的 field(包括父类)
  • Field getDeclaredField(name):根据字段名获取当前类的某个 field(不包括父类)
  • Field[] getFields():获取所有 public 的 field(包括父类)
  • Field[] getDeclaredFields():获取当前类的所有 field(不包括父类)
 // 获取全部的全局变量类信息,并且打印
        Field[] field = class1.getDeclaredFields();
        System.out.println(Arrays.toString(field));
        // 获取public修饰的全局变量,并且打印
        Field[] field1 = class1.getFields();
        System.out.println(Arrays.toString(field1));
        System.out.println("--------------------------------");
        Field nameField = class1.getDeclaredField("name");
        System.out.println(nameField);
        Field heightField = class1.getDeclaredField("height");
        System.out.println(heightField);
        Field ageField = class1.getDeclaredField("age");
        System.out.println(ageField);
        System.out.println("---------------------------------");
        // 会报错,无法获取不被publi修饰符修饰变量的类信息
        Field nameField1 = class1.getField("name");
        System.out.println(nameField1);
        Field heightField1 = class1.getField("height");
        System.out.println(heightField1);

        Field agetField1 = class1.getField("age");
        System.out.println(agetField1);

调用方法

  • Method getMethod(name, Class…):获取某个public的Method(包括父类)
  • Method getDeclaredMethod(name, Class…):获取当前类的某个Method(不包括父类)
  • Method[] getMethods():获取所有public的Method(包括父类)
  • Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
        // 获取方法信息
        Method[] declaredMethods = class1.getDeclaredMethods();
        System.out.println(Arrays.toString(declaredMethods));
        Method[] methods = class1.getMethods();
        System.out.println(Arrays.toString(methods));

        Method getAge = class1.getDeclaredMethod("getAge", int.class);
        Method aaa = class1.getDeclaredMethod("aaa", String.class, Integer.class);
        Method hh = class1.getDeclaredMethod("hh", String.class, int.class);
        Method run = class1.getDeclaredMethod("run");
        System.out.println(hh);
        System.out.println(aaa);
        System.out.println(run);
        System.out.println(getAge);

        Method run1 = class1.getMethod("run");
        System.out.println(run1);

调用构造方法

        // 获取构造方法类信息       
		Constructor[] constructors = class1.getConstructors();
        System.out.println(Arrays.toString(constructors));
        Constructor[] declaredConstructors = class1.getDeclaredConstructors();
        System.out.println(declaredConstructors);

        Constructor declaredConstructor = class1.getDeclaredConstructor(String.class, Integer.class);
        System.out.println(declaredConstructor);
        Constructor declaredConstructor1 = class1.getDeclaredConstructor();
        System.out.println(declaredConstructor1);
        Constructor declaredConstructor2 = class1.getDeclaredConstructor(String.class, String.class, Double.class, Character.class, Integer.class);
        System.out.println(declaredConstructor2);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值