Java反射机制学习总结(通过简单代码带你认识反射的特性和它的功能)

这是我的第三篇博客
本篇旨在记录和分享对于Java的反射机制的学习和理解,也希望本篇可以对正在学习的小伙伴有一定的帮助

反射机制是Java最重要的机制之一,是java.lang包下的java.lang.Class类

在Java程序的运行状态中,对于任意一个类,都能知道这个类的属性和方法,对于任意一个对象,都能调用它的任意属性和方法;这种动态获取信息和动态调用对象的方法的功能,就是Java语言的反射机制

Class类的实例表示正在运行的Java程序中的类或接口,每个类或接口都会产生且只会产生一个Class实例对象,这是在JVM对类进行加载的时候就会自动创建出来的

首先创建两个用来测试的普通类

/**
 * @author Gavin
 * @Description 定义一个Person类,拥有两个public属性,一个无参构造方法,一个两个参数的构造方法,以及
 * toString()方法和一个用来测试的方法
 */
public class Person {
    public int id;
    public String name;

    public Person() {
    }

    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
    
 	public void eatting(){
        System.out.println("eatting");
    }
}

/**
 * @author Gavin
 * @description 定义一个Student类,从Person类中继承
 * 有一个public的属性和一个private的属性
 * 一个空参构造器,一个两个参数的构造器,还有一个私有的调用了父类构造器的构造器
 * 以及一个用来做加法的私有方法
 */
public class Student extends Person{
    public String grade;
    private String className;

    public Student() {
        super();
    }

    private Student(String grade,String className){
        this.grade = grade;
        this.className = className;
    }

    public Student(int id, String name, String grade, String className) {
        super(id, name);
        this.grade = grade;
        this.className = className;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    @Override
    public String toString() {
        return "Student{" +
                "grade='" + grade + '\'' +
                ", className='" + className + '\'' +
                '}';
    }

    private Integer add(Integer a,Integer b){
        return a + b;
    }
}

一、获取一个类的Class实例对象

1、通过Class.forName()的方式来获取

//Class.forName()方法里的参数必须是类的完全限定名,及包名+类名
Class clazz = Class.forName("com.gavin.reflect.Person");

2、通过 T.class 的方式来获取,T表示你要获取的类名

Class clazz = Person.class;

3、通过对象的.getClass()方式来获取

//Person person= new Person();
//Class clazz = person.getClass();
Class clazz = new Person().getClass();
//这种方式严格来说是非常不推荐的,因为每个类的Class实例在JVM加载这个类的.class文件的时候就已经被创建了
//所以没有必要再去new这个类的对象了

4、对于基本数据类型的包装类来说,它们还有第四种方式可以获取,即通过类名.TYPE的方式获取

Class clazz = Integer.TYPE;
clazz = Character.TYPE;
clazz = Boolean.TYPE;
//这里要注意的一点是,这种方式获取到的Class对象和它们的基本数据类型.class的防暑获取到的内容是一样的
//即 Integer.TYPE == int.class

以上的四种方法中,通常推荐使用第一种和第二种,下面两种方式一般不推荐使用

当我们获取到了一个类的Class实例之后,接下来就是获取它的具体信息

二、获取该类的成员变量

获取类的成员变量有三种方式
1、获取该类及其父类的所有公共的属性

Field[] fields = clazz.getFields();
for (Field field : fields) {
	System.out.println(field.getName());
}

运行结果:

grade
id
name

2、获取该类本身的所有属性,包括其私有的属性

Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
	System.out.println(declaredField.getName());
}

运行结果:

grade
className

3、根据其属性的名称获取对应的属性

Field field = clazz.getDeclaredField("className");
System.out.println(field.getName());

运行结果:

className

获取到该类的属性之后,我们可以对其属性进行赋值
以第三种方法为例

//因为Student类中的className属性是私有的,所以这里需要调用Field类中的setAccessible方法将其设置为外部可以访问的
field.setAccessible(true);
Object o = clazz.newInstance();//通过clazz.newInstance方法创建该类的实例对象
field.set(o,"Java反射班");//对其进行赋值,这里需要传入其实例对象
System.out.println(((Student)o).getClassName());

运行结果:

Java反射班

三、获取该类的成员方法

和获取该类的成员变量一样,获取成员方法也有三种方法
1、获取该类及其父类的所有方法(不包括私有方法和构造方法)

Method[] methods = clazz.getMethods();
for (Method method : methods) {
    System.out.println(method.getName());
}

运行结果:

toString
getClassName
setClassName
eatting
wait
wait
wait
equals
hashCode
getClass
notify
notifyAll
//可以看到,这里获取了该类以及该类的父类和Object类的所有的公共方法

2、获取该类本身的所有方法(包括其自身的私有方法)

Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
	System.out.println(declaredMethod.getName());
}

运行结果:

add
toString
getClassName
setClassName

3、根据方法名获取对应的方法

Method method = clazz.getDeclaredMethod("add", Integer.class, Integer.class);
//在使用这种方式的时候,除了需要传入方法的名称之外,还需要传入其参数列表的Class对象

获取到该类的方法之后,接下来就是方法调用了,依然以第三种方法为例

method.setAccessible(true);//允许访问该类的私有方法
Object o = clazz.newInstance();//创建该类的实例
Object invoke = method.invoke(o, 123,123);//通过method.invoke()方法进行调用,参数分别是该类的实例和要调用方法的参数列表,多个用,隔开
System.out.println(invoke);

运行结果:

246

四、获取该类的构造方法

同样,获取构造器也有三种方式
1、获取其自身的公共构造方法

Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
    System.out.println(constructor.getName());
}

运行结果:

com.gavin.reflect.Student
com.gavin.reflect.Student

2、获取该类的所有构造器

Constructor<?>[] declaredConstructor = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : declaredConstructor) {
    System.out.println(constructor.getName());
}

运行结果:

com.gavin.reflect.Student
com.gavin.reflect.Student
com.gavin.reflect.Student

3、根据构造器的参数列表来获取对应的构造器

Constructor<?> constructor = clazz.getDeclaredConstructor(String.class,String.class);

运行结果:

com.gavin.reflect.Student

接下来就是根据反射得到的构造方法来进行对象的创建了
还是以第三种为例

Student student = (Student)constructor.newInstance("一年级", "Java反射班");
//constructor.newInstance()方法的返回值是Object类型,这里是将Object强转为Student
System.out.println(student);

运行结果:

Student{grade='一年级', className='Java反射班'}

杂言:Java的反射机制在整个Java生态中无比重要,很多的框架都是用到反射机制,比如Mybatis,比如Spring的AOP等等
反射的内容非常之多,本篇介绍的只是它最基础、最常用的一些用法,更多的内容请参考JDK API中的Class类,其中有完整的内容。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值