Java反射学习(一)

原文地址
题主刚学Java的时候就了解过Java反射,但是在实践开发中使用的并不是很多,所以也一直未深入了解过,最近在看一些公司内部框架的源码,发现了很多功能都是通过Java反射来实现的。 本篇文章主要介绍Java反射的基本知识,以供自己日后查阅。先介绍一下Java反射的定义

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它在编译期不需要知道运行的对象是谁,Java反射实际操作对象是.class文件(字节码文件)

获得Class对象

1.通过Class类的forName静态方法,JDBC开发中常用此方法加载驱动

Class<?> c1 = Class.forName("java.lang.Integer");

2.通过调用对象的getClass()方法

Integer i1 = 1;
Class<?> c2 = i1.getClass();

3.直接获取类的class

Class<?> c3 = Integer.class;

判断是否为某个类的实例

判断是否是某个类的实例一般用instanceof关键字,同时我们也可借助Class对象的isInstance()方法来判断,如下面的代码

Object obj = "Java";
// 使用instanceof关键字
System.out.println(obj instanceof  String);
// 使用isInstance方法
System.out.println(String.class.isInstance(obj));

isInstance()方法是一个native方法,它的方法签名如下:

public native boolean isInstance(Object obj);

创建实例

通过Java反射创建对象有两种方法:
1.通过Class对象的newInstance方法来创建Class对象对应的实例

Class<?> c = String.class;
Object s = c.newInstance();

2.先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance方法来创建对象的实例,通过这种方法可以指定构造器来构造对象。

Class<?> cc = String.class;
Constructor constructor =  cc.getConstructor(String.class);
Object ss = constructor.newInstance("Java");
System.out.println(ss);

获取类名及变量

直接调用Class对象的getName()即可获取类名(包含package)

Class<?> c = String.class;
System.out.println(c.getName());

获取类的变量有下面两种方法
1.通过Class对象的getField方法获取类的所有变量,需要注意是getField()会获取该类及其父类的全部公有变量

// Book是自定义的类
Class<?> c = Book.class;
Field[] fields = c.getFields();

2.如果还想获取对象的私有变量,可以通过getDeclaredFields()方法,该方法会返回该类的所有变量,不论访问权限

// Book是自定义的类
Class<?> c = Book.class;
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
    // 获取访问权限
    System.out.println(field.getModifiers());
    // 获取变量类型及名称
    System.out.println(field.getType() + " " + field.getName());
}

获取方法

获取某个Class对象的方法,主要有以下几种方法:
1.getDeclaredMethods方法返回类或接口声明的所有方法,包括公共、保护、默认访问和私有方法,但不包括继续的方法。

public Method[] getDeclaredMethods() throws SecurityException

2.getMethods,返回该类所有的公共的方法以及继续的类公用方法

public Method[] getMethods() throws SecurityException 

3.getMethod返回一个特定的方法,第一个参数为方法名称,后面的参数是方法参数对应的Class对象

public Method getMethod(String name, Class<?>... parameterTypes)

获取Class对象的具体列子

Class<?> cc = Book.class;
Method[] methods = cc.getMethods();
for (Method method : methods) {
    //获取并输出方法的访问权限(Modifiers:修饰符)
    int modifiers = method.getModifiers();
    System.out.print(Modifier.toString(modifiers) + " ");
    //获取并输出方法的返回值类型
    Class returnType = method.getReturnType();
    System.out.print(returnType.getName() + " " + method.getName() + "( ");
    //获取并输出方法的所有参数
    Parameter[] parameters = method.getParameters();
    for (Parameter parameter: parameters) {
        System.out.print(parameter.getType().getName() + " " + parameter.getName() + ",");
    }
    //获取并输出方法抛出的异常
    Class[] exceptionTypes = method.getExceptionTypes();
    if (exceptionTypes.length == 0){
        System.out.println(" )");
    } else {
        for (Class c : exceptionTypes) {
            System.out.println(" ) throws " + c.getName());
        }
    }
}

获取构造器

通过getConstructor方法可以获取Class对象的构造器,具体的例子在上文创建实例中已经介绍过,在此不再赘述

调用方法

当我们从一个类获取到方法之后,可以用invoke()方法来调用这个方法。invoke方法的签名如下:

public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException

invoke具体的例子:

public class Client {
    public static void main(String[] args) throws Exception {
        Class<?> c = Calculation.class;
        Object obj = c.newInstance();
        Method method = c.getMethod("add", int.class, int.class);
        int res = (int) method.invoke(obj, 1, 2);
        System.out.println(res);
    }
}
class Calculation {
    public int add(int x, int y) {
        return x + y;
    }
}

获取注解

首先介绍一下注解,注解是Java5中的新特性,它是插入你代码中的一种注释或者说是一种元数据(meta data)。这些注解信息可以在编译期使用预编译工具进行处理,也可以在运行期使用Java反射机制进行处理。注解可以分为以下四种:

  • 类注解
  • 方法注解
  • 变量注解
  • 参数注解
    由于篇幅限制,在此只介绍获取类的注解,其它注解的获取可以参考:Java Reflection(八):注解
public class Client {
    public static void main(String[] args) throws Exception {
        Class<?> c = Calculation.class;
        // 获取所有注解
        // Annotation[] annotations = c.getAnnotations();
        // 指定获取MyAnnotation注解
        Annotation annotation = c.getAnnotation(MyAnnotation.class);
        if (annotation instanceof MyAnnotation) {
            MyAnnotation myAnnotation = (MyAnnotation) annotation;
            System.out.println(myAnnotation.id());
            System.out.println(myAnnotation.desc());
        }
    }
}

@MyAnnotation(id ="1", desc = "calc")
class Calculation {
    public int add(int x, int y) {
        return x + y;
    }
}

// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
    public String id();
    public String desc();
}

Java反射用途

上文都是介绍java反射的基本用法,在业务开发确实很少使用反射,但是优秀的框架必然会使用到反射来实现很多复杂的功能,比如Spring的IOC(控制反转),通过解析bean的xml文件,Spring在运行期根据xml配置,通过Java反射生成相应的bean,放入到Spring容器中。

Java反射的功能

  • 获取一个对象的类信息.
  • 获取一个类的访问修饰符、成员、方法、构造方法以及超类的信息.
  • 检获属于一个接口的常量和方法声明.
  • 创建一个直到程序运行期间才知道名字的类的实例.
  • 获取并设置一个对象的成员,甚至这个成员的名字是在程序运行期间才知道.
  • 检测一个在运行期间才知道名字的对象的方法

参考资料

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容