Java 反射 (Class、ClassLoader、Constructor、Method、Field)

反射是Java中一个非常重要、非常强大的机制。曾看到一句话“反射是框架的灵魂”,初学时不懂,等到学完框架之后才慢慢理解其意。

什么是反射?我们先通过几个类和示例来初步体会一下反射

一、ClassLoader类

什么是类加载器?

ClassLoader是一个抽象类,它的实例是类加载器。磁盘上存在的xxx.class文件需要被加载进JVM才能执行。类加载器则是负责加载.class文件的对象,然后在JVM中生成该类的Class对象。每一个Class对象都关联着定义它的那个类加载器。数组的类加载器与其元素的加载器是同一个,如果元素类型是基本类型,则数组没有类加载器。

类加载器工作原理

类加载器都有一个与之关联的父加载器,当加载器需要加载一个文件时,它首先将该任务”委派”给父加载器,如果父加载器无法加载该文件,再自己进行加载。JVM的引导加载器(bootstrap class loader)没有父加载器,但可作为父加载器。关于类加载器更详细的分析 点击这里

二、Class类

什么是Class<T>类?

Class不是我们平常声明类时所用的关键字class,它是一个类,它的对象用来描述一个运行状态的类或接口。一个xxx.java文件编译后生成一个xxx.class文件,一个xxx.class文件被JVM加载后生成该类对应的Class对象,该对象包含了该类的所有信息,比如,类中有字段、构造器、方法等信息。一个类有一个对应的Class对象,元素类型相同且长度相同的数组共享一个Class对象,java基本类型包括void也都有各自的Class对象。Class是一个泛型类,如果不加泛型,需要强转。

如何获取一个类的Class对象?

Class没有public构造器,当类被加载时,JVM会通过调用ClassLoader的defineClass方法来自动创建该类的Class对象。

获取一个类的Class对象有三种方式:

1)类名.class

  1. 该类的对象.getClass()

  2. Class.forName(String 类名) (包名加类名)

Class对象有何作用?

下面列出几个Class类的方法:

  1. 获取类加载器:

getClassLoader()

  1. 获取Constructor构造器对象:

getConstructor(Class... parameterType)   获取具有指定参数的公共构造器对象

getConstructors()   获取所有公共构造器对象

getDeclaredConstructor(Class... parameterType)       获取具有指定参数的构造器对象

getDdclaredConstructors()   获取所有构造器对象

  1. 获取Method对象:

getMethod(String name,Class...parameterType)       获取具有指定名称和参数的公共方法对象

getMethods() 获取所有公共方法对象

getDeclaredMethod(String name,Class...parameterType) 获取具有指定名称和参数的方法对象

getDeclaredMethods()                  获取所有的方法对象

4)获取Field字段对象:

getField(String name)                   获取具有指定名称的公共字段对象

getFields()                        获取具有所有公共字段对象

getDeclaredField(String name)               获取具有指定名称的字段对象

getDeclaredFields()                   获取所有字段对象

5)获取Class对象所代表的类的一个对象(非常重要的一个方法)

Object newInstance() 用默认的无参数构造器创建一个对象

(带Declared的get方法可以获取任意访问权限的成员,不带Declared的只能获取public成员)

测试Class,更多的测试在其他类的测试中体现。

|

|

package cn.edu;

public class User {

private String username;

private int age;

public User() {

}

public User(String username , ``int age) {

this``.username = username;

this``.age = age;

}

private User(String username) {

this``.username = username;

}<br>

public void say(String str) {<br>       System.out.println(str);<br>     }<br><br>

@Override

public String toString() {

return "User [username=" + username + ``", age=" + age + ``"]"``;

}

}

|

|

|

@Test

public void fun2() ``throws Exception {

Class userClass = User.``class``;

System.out.println(userClass.getName()); ``//获取该class对象的类的类名

System.out.println(userClass.getClassLoader().toString()); ``//获取类加载器

User user = (User)userClass.newInstance(); ``//调用默认的无参数构造器创建对象

System.out.println(user.toString());

}

|

运行结果:

image

三、Constructor类

构造器类,封装构造器的有关信息。

主要方法 Object newInstance(Object...arg) 用指定参数创建对象

测试Constructor

|

|

@Test

public void fun2() ``throws Exception {

Class userClass = User.``class``;

Constructor userConstructor1 = userClass.getConstructor(String.``class , ``int``.``class``); ``//有参构造器

User user1 = (User)userConstructor1.newInstance(``"小红"``,``18``);

System.out.println(user1.toString());

Constructor userConstructor2 = userClass.getConstructor(); ``//无参构造器

User user2 = (User)userConstructor2.newInstance();

System.out.println(user2);

Constructor userConstructor3 = userClass.getDeclaredConstructor(String.``class``); ``//私有构造器

userConstructor3.setAccessible(``true``); ``//开启访问权限

User user3 = (User)userConstructor3.newInstance(``"小明"``);

System.out.println(user3);

}

|

运行结果:

image

默认是不可以访问private成员的,userConstructor3.setAccessible(true)是用于开启访问权限的,这样就可以访问了,感觉是开挂一样!

四、Method类

方法类,封装方法的有关信息

主要方法

Object** invoke**(Object obj , Object... args) 调用obj对象的Method对象代表的方法,args为参数

测试Method:

|

|

@Test

public void fun2() ``throws Exception {

Class userClass = User.``class``;

User user = (User)userClass.newInstance(); ``//用默认无参数构造方法创建对象

Method method = userClass.getMethod(``"say"``,String.``class``); ``//获取名为"say",参数为string的method对象

method.invoke(user,``"hello"``); ``//调用user的say方法

}

|

运行结果:

image

五、Field类

字段类,封装字段的有关信息

主要方法

Object get(Object obj) 获取obj对象的此Field对象代表的字段的值

void set(Object obj , Object value)              设置obj对象的此Field对象代表的字段的值

测试Fidle

|

|

@Test

public void fun2() ``throws Exception {

Class userClass = User.``class``;

Constructor userConstructor = userClass.getConstructor(String.``class``,``int``.``class``);

User user = (User)userConstructor.newInstance(``"小明"``,``18``);

System.out.println(user.toString());

Field userField = userClass.getDeclaredField(``"username"``); ``//获取username字段

userField.setAccessible(``true``); ``//开启访问权限

userField.set(user, ``"小红"``); ``//给user对象的该字段设置值

System.out.println(user.toString());

}

|

运行结果:

image

到此关于反射的几个类就简单的认识了一下,我们可以不用new关键字来创建对象,调用对象的方法也与传统的调用方式有很大区别,我们甚至可以操作private成员(虽然这样做破坏了封装性),相对于传统的操作方式,反射更像是一种逆向思维,以前操作成员,主体在于对象,而反射的主体在于Class和成员本身。到此我们对反射有了初步的认识。接下在叙述一个重要的概念,有助于我们更好的理解反射。

六、动态加载与静态加载

注意此处所说的加载是针对编译的,将xxx.java转化成xxx.class,而不是运行的加载字节码。Java创建对象的常用方式是使用new 关键字,如 User user = new User(); 这种是静态加载,即在编译期就已经获取User类的有关信息,如果User类不存在或有错误,编译会报错。动态加载就是用上面的Class.forName("包名.User");来加载User类,如果User类不存在或是有错误,在编译时是不会报错的,因为根本没去加载User类。只有当程序运行到该处,JVM才会去加载User,而动态加载则是依赖反射实现的。

好了,可以给出最终概念了,通过上面的重重示例与解析,应该不难理解反射了。

七、反射

Java反射机制是指java程序在运行过程中,可以获取任意一个类的相关信息,并且能够调用其方法和属性,这种动态获取信息和动态调用方法的功能叫做Java的反射机制。

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