Java反射机制学习
一、定义
反射机制是在运行状态中,对于任意一个类,都能获取这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
二、用途
- 运行时获取任意一个对象所属的类;
- 运行时动态生成任意一个类的对象;
- 运行时获取任意一个类所具有的字段和方法;
- 运行时动态调用任意一个对象的方法;
- 运行时获取注解信息;
- 生成动态代理
三、具体功能实现
1、准备工作
为了更好的介绍反射机制功能的实现,我们先定义了一些类作为分析对象,利用它们进行更好的说明,如下:
首先,是我们自己定义了一些注解:
//用于注解类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassAnno {
}
//用于注解变量
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldAnno {
String name() default "sfw";
}
//用于注解方法
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodAnno {
}
//用于注解方法的参数
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParaAnno {
}
//用于注解方法的d参数
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParaAnno {
}
然后,定义了一些类,用于说明反射机制。
interface Animal {
}
class Person implements Animal {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
@ClassAnno
class Student extends Person {
@FieldAnno
public String name;
@FieldAnno
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@MethodAnno
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@MethodAnno
public void setNameAndAge(@ParaAnno @ParaAnno2 String name, @ParaAnno @ParaAnno2 int age) {
this.setName(name);
this.setAge(age);
}
private void ceshi(){
System.out.println("private方法调用");
}
}
好了,接下来正式进行反射机制的分析:
2、获取Class对象
在反射中,常用的获取Class对象的方法有三种
(1) 通过类的对象调用getClass()方法的方式:
Class pClass1 = person.getClass();
(2) 通过Class类的静态方法forName():
Class pClass2 = null;
pClass2 = Class.forName("com.sfw.anno.reflectiondemo.Person");
注:forName方法的参数必须为完全限定类名(包名+类名)。
(3) 通过类字面常量获得:
Class pClass3 = Person.class;
类字面常量不仅可以应用于普通的类、接口、数组、基本数据类型。
(4) 基本数据类型也可以通过TYPE字段获得:
Class longClass2 = Long.TYPE;
Java中常用的基本数据类型和TYPE的对应关系:
基本数据类型 | TYPE |
---|---|
boolean | Boolean.TYPE |
char | Character.TYPE |
short | Short.TYPE |
int | Integer.TYPE |
long | Long.TYPE |
float | Float.TYPE |
double | Double.TYPE |
void | Void.TYPE |
3、通过Class对象获取类名
常用的有两个方法:
方法 | 作用 | 示例 |
---|---|---|
getName() | 获取完全限定类名 | String personName = pClass1.getName(); |
getSimpleName() | 仅获取类名,不包含包名 | String personName = pClass1.getSimpleName(); |
4、通过Class对象获取类修饰符
获取类的public、private、static等修饰符的方法:
int modifiers = pClass1.getModifiers();
getModifiers()方法的返回值是int类型,每种修饰符就是这个返回值的其中一位,如果对应位为1,则表示这个类包含这个修饰符。
常用修饰符、对应位、修饰符是否使用方法对应关系如下:
修饰符 | 对应位 | 判断方法 |
---|---|---|
public | 0x00000001 | Modifier.isPublic(modifiers) |
private | 0x00000002 | Modifier.isPrivate(modifiers) |
protected | 0x00000004 | Modifier.isProtected(modifiers) |
static | 0x00000008 | Modifier.isStatic(modifiers) |
final | 0x00000010 | Modifier.isFinal(modifiers) |
synchronized | 0x00000020 | Modifier.isSynchronized(modifiers) |
volatile | 0x00000040 | Modifier.isVolatile(modifiers) |
transient | 0x00000080 | Modifier.isTransient(modifiers) |
native | 0x00000100 | Modifier.isNative(modifiers) |
interface | 0x00000200 | Modifier.isInterface(modifiers) |
abstract | 0x00000400 | Modifier.isAbstract(modifiers) |
strict | 0x00000800 | Modifier.isStrict(modifiers) |
5、通过Class对象获取类的包信息
通过getPackage()方法获取指定类的包信息:
Package pkg = pClass1.getPackage();
String packageName = pkg.getName();
6、通过Class对象获取父类
通过getSuperclass()方法获取指定类的的父类:
Class studentClass = Student.class;
Class superStudentClass = studentClass.getSuperclass();
7、通过Class对象获取类实现的接口
getInterfaces()方法获取类实现的接口,返回值是一个Class数组,即类可能实现多个接口。
Class[] interfaces1 = pClass1.getInterfaces();
Class[] interfaces2 = studentClass.getSuperclass().getInterfaces();
8、通过Class对象获取类构造器生成实例
- 获取类无参数构造器并生成实例:
Constructor constructor1 = studentClass.getConstructor();
Student student1 = (Student) constructor1.newInstance();
- 获取类有参数构造器并生成实例:
Constructor constructor2 = studentClass.getConstructor(String.class, int.class);
Student student2 = (Student) constructor2.newInstance("sfw", 27);
9、通过Class对象获取类的方法
获取所有public方法,包括子类和父类的public方法:
Method[] methods1 = studentClass.getMethods();
获取指定的public方法:
Method method1 = studentClass.getMethod("setAddress", String.class);
调用参数为空的public方法:
Method getage = student2.getClass().getMethod("getAge");
int age = (int) getage.invoke(student2);
调用多参数的public方法:
Method setNameAndAge = student2.getClass().getMethod("setNameAndAge", String.class, int.class);
setNameAndAge.invoke(student2, "wsf", 18);
获取方法的参数类型
Class[] paraTypes = setNameAndAge.getParameterTypes();
获取本类所有方法
Method[] declaredMethods = student2.getClass().getDeclaredMethods();
调用本类方法,如果方法为private,需要调用setAccessible(true)后,才能调用。
Method ceshi =student2.getClass().getDeclaredMethod("ceshi");
ceshi.setAccessible(true);
ceshi.invoke(student2);
10、变量
获取所有public变量,包括本类和父类的public变量:
Field [] fields = student2.getClass().getFields();
获取指定public变量,并设置变量值,读取变量值:
Field field = student2.getClass().getField("name");
field.set(student2,"shufengwu");
String name = field.get(student2);
获取本类变量,包括私有变量,访问私有变量调用setAccessible(true):
Field[] declaredFields = student2.getClass().getDeclaredFields();
for (Field declaredField:declaredFields){
field.setAccessible(true);
System.out.println(declaredField.getName());
}
获取本类指定变量:
Field declaredField = student2.getClass().getDeclaredFields("age");
11、获取注解
获取类上注解:
Annotation [] annotations = Student.class.getAnnotations();
获取类上指定注解:
ClassAnno classAnno = Student.class.getAnnotation(ClassAnno.class);
获取指定字段上指定注解及参数值:
FieldAnno fieldAnno = Student.class.getField("name").getAnnotation(FieldAnno.class);
System.out.println(fieldAnno +" "+ fieldAnno.name());
获取指定方法的注解:
Method method = Student.class.getMethod("setNameAndAge",String.class,int.class);
MethodAnno methodAnno = method.getAnnotation(MethodAnno.class);
System.out.println(methodAnno);
获取指定方法的参数的注解:
Method method = Student.class.getMethod("setNameAndAge",String.class,int.class);
//一个方法可能有多个参数,一个参数可能有多个注解
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
//遍历每个参数
for (int i=0;i<parameterAnnotations.length;i++){
Annotation[] annotations2 = parameterAnnotations[i];
//遍历参数的每个注解
for (int j = 0;j<annotations2.length;j++){
System.out.print(annotations2[j]+" ");
}
System.out.println();
}
参考文献
【1】 Java反射机制详解
http://baike.xsoftlab.net/view/209.html#1
【2】 Java反射详解
http://blog.csdn.net/a15286856575/article/details/53330821?locationNum=1&fps=1