0
点赞
收藏
分享

微信扫一扫

反射机制总结 - Java


文章目录

  • ​​一、反射的作用​​
  • ​​二、反射的用法​​
  • ​​2.1 类​​
  • ​​2.1.1 修饰符​​
  • ​​2. 1.2 类名​​
  • ​​2.1.3 继承的父类​​
  • ​​2.1.3 实现的接口​​
  • ​​2.1.4 包信息​​
  • ​​2.2 变量​​
  • ​​2.2.1 特定变量​​
  • ​​2.2.2 变量类型和变量名​​
  • ​​2.3 构造器​​
  • ​​2.3.1 获取Constructor对象以及对象的参数列表​​
  • ​​2.3.2 利用Constructor对象实例化一个类​​
  • ​​2.4 方法​​
  • ​​2.4.1 获取类中所有方法​​
  • ​​2.4.2 调用指定方法​​
  • ​​2.5 数组​​
  • ​​2.5.1 一维数组赋值​​
  • ​​2.5.1 多维数组赋值​​
  • ​​2.6 泛型​​
  • ​​2.6.1 方法的返回类型的泛型​​
  • ​​2.7 注解​​
  • ​​三、源码查看地址​​

一、反射的作用

可以通过反射来获取类的各个组成部分,还可以通过反射来创建对象,甚至构造器是私有的也可以;调用方法,传参以及获取方法的返回值;总体来说可以对构造器,字段,方法,注释等进行一系列操作。

二、反射的用法

下面将会通过对类,字段,构造器,方法,数组,泛型分别进行描述反射的使用

将对这个类进行案例分析
Animal类

package top.clearlight.coretech.reflect;

public abstract class Animal {
public abstract void move();
abstract void shout();

public void Help() {
System.out.println("Help Ohter");
}
}

People类

package top.clearlight.coretech.reflect;

public class People extends Animal implements Comparable<People> {

private String name;
public int age;
static String sex;

@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}

public String getName() {
return name;
}

public int getAge() {
return age;
}

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

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

public People() {
}

public People(String name) {
this.name = name;
}

private People(String name, int age) {
this.name = name;
this.age = age;
}

@Override
public int compareTo(People o) {
return Double.compare(this.age, o.age);
}

@Override
public void move() {
System.out.println("行走");
}

@Override
void shout() {
System.out.println("交流");
}

public List<String> getStringList() {
ArrayList<String> list = new ArrayList<>();
list.add("hhhh");
return list;
}
}

2.1 类

获取类对象的方式有三种.对象.

  1. 对象.getClass()
  2. Class.forName(“全限定类名”); (需要try-catch,类名有可能写错)
  3. 类名.class

2.1.1 修饰符

Class clazz = People.class;
int modifiers = clazz.getModifiers(); // modifiers : 1 (public)

反射机制总结 - Java_数组


Modifier源码 : ​​https://gitee.com/huangtianyu/jdk-source/blob/master/java/lang/reflect/Modifier.java​​

2. 1.2 类名

String name = clazz.getName(); // top.clearlight.coretech.reflect.People

String simpleName = clazz.getSimpleName(); // People

2.1.3 继承的父类

Class superclass = clazz.getSuperclass(); // class java.lang.Object



2.1.3 实现的接口

类可以实现多个接口,因此返回Class数组.且只会返回当前类所实现的接口 , 父类所实现的接口并不会在返回的Class数组中.

Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println(anInterface);
}

输出结果 : ​​interface java.lang.Comparable​

2.1.4 包信息

Package aPackage = clazz.getPackage(); // package top.clearlight.coretech.reflect

2.2 变量

获取一个类的成员变量

Field[] fields = clazz.getFields(); // 只能获取修饰符为public的变量

Field[] declaredFields = clazz.getDeclaredFields(); // 获取类中所有的变量,包括私有,默认,公有..

2.2.1 特定变量

通过变量名来获取指定变量,并且对该变量进行赋值

  • 获取指定变量

如果是public修饰的变量,可以使用​​getField(String)​​​来获取;但是对于其他修饰符需要使用​​getDeclaredField(String)​​方法

Field field = clazz.getDeclaredField("name");

  • 为特定对象的变量赋值
    首先创建对象

People p = new People();
field.setAccessible(true); // 将域设置为可访问的
field.set(p, "Jack"); // 若变量为static, 第一个参数设为null,即不需要传入对象,只需直接设置值即可.
System.out.println(p.getName()); // Jack

  • 为静态变量赋值

Field sex = clazz.getDeclaredField("sex");
sex.set(null, "girl"); // 当然,你传入类的实例效果相同
System.out.println(People.sex); // girl

若对私有变量使用getField(String)方法的话,将会抛出NoSuchFieldException ; 或者传入的String确实没有该字段同样会抛出该异常

2.2.2 变量类型和变量名

Field ageField = clazz.getField("age");
Class<?> type = ageField.getType(); // int

String name1 = ageField.getName(); // age

2.3 构造器

对于构造器,不仅可以获取所有Constructor对象,来列出参数列表,还可以获取指定参数列表的Constructor对象;同样可以通过获得的Constructor对象来实例化一个类

扩展阅读 : ​​Java反射 - 通过反射创建有参与无参构造函数的对象​​

2.3.1 获取Constructor对象以及对象的参数列表

Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); // 返回所有的Constructor对象
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("构造器:" + declaredConstructor);
Class<?>[] parameterTypes = declaredConstructor.getParameterTypes(); // 返回该Constructor对象的参数列表
for (Class<?> parameterType : parameterTypes) {
System.out.println(parameterType);
}
}

输出结果:

反射机制总结 - Java_java_02

2.3.2 利用Constructor对象实例化一个类

1、获取指定的构造器对象

Constructor<People> declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);

2、将私有构造器设为可访问的

declaredConstructor.setAccessible(true);

3、创建实例并为构造器传入相应的参数

People mary = declaredConstructor.newInstance("Mary", 18);

对于上述,获取构造器对象的方法有​​getConstructor​​​与​​getDeclaredConstructor​​,两者的区别与获取字段是的两个方法一样,一个只能获取public,而另一个还可以获取默认,甚至是private所修饰的,因此可以创建私有构造器的实例。

2.4 方法

与构造器的使用类似,其中不同的是获取所有方法:

  • getMethods返回的方法集是本类以及父类还有Object的所有​public​修饰的方法;
  • getDeclaredMethods返回的方法集只是本类所有的方法集合。

2.4.1 获取类中所有方法

Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("方法名:" + declaredMethod.getName());
int modifiers1 = declaredMethod.getModifiers();
System.out.println("修饰符:" + modifiers);
System.out.println("返回类型:" + declaredMethod.getReturnType());
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
System.out.println("参数列表:");
for (Class<?> parameterType : parameterTypes) {
System.out.println(parameterType);
}
System.out.println();
}

输出结果 :
方法名:move
修饰符:1
返回类型:void
参数列表:

方法名:getAge
修饰符:1
返回类型:int
参数列表:

… …

2.4.2 调用指定方法

Constructor<People> declaredConstructor1 = People.class.getDeclaredConstructor(String.class, int.class);
declaredConstructor1.setAccessible(true);
People p2 = declaredConstructor1.newInstance("Bob", 21);
p.setAge(23);


Method compareTo = clazz.getMethod("compareTo", People.class);
Object comPareMethod = compareTo.invoke(p, p2);
System.out.println(comPareMethod); // 1

  • ​getMethod​​​方法
    第一个参数 : 方法名
    第二个参数 : (可变参数)方法的参数类型
  • ​invoke​​​方法
    第一个参数 : 非静态方法的话传入调用该方法的实例对象 ; 若是静态方法的话传入 null
    第二个参数 : (可变参数) 对应类型的参数的值

2.5 数组

扩展阅读 :
​Java反射 - 创建数组实例​​Java中的反射机制(三) 反射与数组

Java反射机制通过​​java.lang.reflect.Array​​这个类来处理数组.

2.5.1 一维数组赋值

// 创建int类型的数组,长度为10
int[] ints = (int[]) Array.newInstance(int.class, 10);
System.out.println(Arrays.toString(ints));

Array.set(ints, 3, 18);
int i = (int) Array.get(ints, 3);
System.out.println(i);

输出结果:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
18

2.5.1 多维数组赋值

int[][] ints2 = (int[][]) Array.newInstance(int.class, 5, 10);
System.out.println(Arrays.toString(ints2));
int[] ints3 = (int[]) Array.get(ints2, 3);
Array.setInt(ints3, 5, 21);

for (int[] ints4 : ints2) {
System.out.println(Arrays.toString(ints4));
}

输出结果:

反射机制总结 - Java_数组_03


2.6 泛型

在一些情况下是可以在运行期获取到泛型的信息

2.6.1 方法的返回类型的泛型

Method getStringList = People.class.getMethod("getStringList", null);

Type genericReturnType = getStringList.getGenericReturnType();

if (genericReturnType instanceof ParameterizedType) {
ParameterizedType type1 = (ParameterizedType) genericReturnType;
Type[] actualTypeArguments = type1.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}

输出结果:
class java.lang.String




2.7 注解

获取注解的方式无论是获取类注解,方法注解还是参数注解,方式都是相似的,只要掌握一种就可以快速学会其他获取注解内容的方法.

关于注解的学习请看: ​​注解知识点总结 - Java​​

任意位置的自定义注解

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Container {
Person[] value();
}

自定义的变量注解

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Inherited
public @interface FieldAnnotation {
String value();
}

容器注解

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Container {
Person[] value();
}

通过@Repeatable修饰的注解

import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Container.class)
public @interface Person {
String role() default "artist";
}

定义方法来获取字段以及指定方法的注解

package top.clearlight.blog.annotation.reflecttest;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;


// @MyAnnotation(msg = "type annotation", id = 1)
public class ReflectTest1 extends SuperClass{
@FieldAnnotation(value = "file annotation")
private int age;

@Person(role = "student")
@Person(role = "cooker")
@Person(role = "superman")
public void test() {
System.out.println("用来测试Repeatable注解");
}

@MyAnnotation(id = 4)
public void test2() {
System.out.println("直接获取多个方法的注解");
}

public static void main(String[] args) {
Class<ReflectTest1> rt = ReflectTest1.class;

// 获得的父类的类注解,该注解已经通过@Inherited修饰
System.out.println("获取类注解");
Annotation[] typeAns = rt.getAnnotations();
for (Annotation typeAn : typeAns) {
if (typeAn instanceof MyAnnotation) {
MyAnnotation man = (MyAnnotation) typeAn;
System.out.println("msg(): " + man.msg());
System.out.println("id(): " + man.id());
}通过@Repeatable修饰的方法的注解
}

// 获取的字段的注解
System.out.println("\n获取字段注解");
try {
Field age = rt.getDeclaredField("age");
// 访问private修饰的字段, 需要修改访问权限
age.setAccessible(true);
// 获得指定的注解
FieldAnnotation fieldAn = age.getAnnotation(FieldAnnotation.class);
if (fieldAn != null) {
System.out.println("字段的value(): " + fieldAn.value());
}

} catch (NoSuchFieldException e) {
e.printStackTrace();
}

// 获取所有方法的注解
System.out.println("\n获取方法注解");
Method[] methodsAns = rt.getDeclaredMethods();
for (Method methodsAn : methodsAns) {
Annotation[] ans = methodsAn.getAnnotations();
System.out.println(methodsAn.getName() + "方法的注解:");
if (ans.length == 0) {
System.out.println("无");
}
for (Annotation an : ans) {
System.out.println(an);
}
}

// 获取通过@Repeatable修饰的方法的注解,
System.out.println("\n获取指定方法的注解");
try {
Method test = rt.getDeclaredMethod("test", null);
Container conAn = test.getAnnotation(Container.class);
System.out.println("人的角色: ");
for (Person person : conAn.value()) {
System.out.println(person.role());
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}

}
}

结果:
获取类注解
msg(): 由父类而得
id(): 2

获取字段注解
字段的value(): file annotation

获取方法注解
test2方法的注解:
@top.clearlight.blog.annotation.reflecttest.MyAnnotation(msg=“hhhh”, id=4)
main方法的注解:

test方法的注解:
@top.clearlight.blog.annotation.reflecttest.Container(value={@top.clearlight.blog.annotation.reflecttest.Person(role=“student”), @top.clearlight.blog.annotation.reflecttest.Person(role=“cooker”), @top.clearlight.blog.annotation.reflecttest.Person(role=“superman”)})

获取指定方法的注解
人的角色:
student
cooker
superman




举报

相关推荐

0 条评论