Java反射机制学习

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
booleanBoolean.TYPE
charCharacter.TYPE
shortShort.TYPE
intInteger.TYPE
longLong.TYPE
floatFloat.TYPE
doubleDouble.TYPE
voidVoid.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,则表示这个类包含这个修饰符。

常用修饰符、对应位、修饰符是否使用方法对应关系如下:

修饰符对应位判断方法
public0x00000001Modifier.isPublic(modifiers)
private0x00000002Modifier.isPrivate(modifiers)
protected0x00000004Modifier.isProtected(modifiers)
static0x00000008Modifier.isStatic(modifiers)
final0x00000010Modifier.isFinal(modifiers)
synchronized0x00000020Modifier.isSynchronized(modifiers)
volatile0x00000040Modifier.isVolatile(modifiers)
transient0x00000080Modifier.isTransient(modifiers)
native0x00000100Modifier.isNative(modifiers)
interface0x00000200Modifier.isInterface(modifiers)
abstract0x00000400Modifier.isAbstract(modifiers)
strict0x00000800Modifier.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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值