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
2) 该类的对象.getClass()
3) Class.forName(String 类名) (包名加类名)
Class对象有何作用?
下面列出几个Class类的方法:
1) 获取类加载器:
getClassLoader()
2) 获取Constructor构造器对象:
getConstructor(Class... parameterType) 获取具有指定参数的公共构造器对象
getConstructors() 获取所有公共构造器对象
getDeclaredConstructor(Class... parameterType) 获取具有指定参数的构造器对象
getDdclaredConstructors() 获取所有构造器对象
3) 获取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;
}
public void say(String str) {
System.out.println(str);
}
@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());
}
运行结果:

三、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);
}
运行结果:

默认是不可以访问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方法
}
运行结果:

五、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());
}
运行结果:

到此关于反射的几个类就简单的认识了一下,我们可以不用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的反射机制。
上面写了这么多,总结起来也就这一句话。
本文个人编写,水平有限,如有错误,恳请指出,欢迎讨论分享。
Java 反射 (Class、ClassLoader、Constructor、Method、Field)的更多相关文章
- 提高java反射速度的方法method.setAccessible(true)
转载:http://huoyanyanyi10.iteye.com/blog/1317614 提高java反射速度的方法method.setAccessible(true) package com.c ...
- java反射之ClassLoader
类加载器ClassLoader ClassLoader能在运行时, 知道任意一个类的的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性. 一.类加载器的工作机制 1:加载Jvm把clas ...
- Java static block static constructor , static field
http://stackoverflow.com/questions/7121213/singleton-instantiation http://docs.oracle.com/javase/spe ...
- Class类与Java反射
1反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为jav ...
- Java 反射详解 转载
java 反射 定义 功能 示例 概要: Java反射机制详解 | |目录 1反射机制是什么 2反射机制能做什么 3反射机制的相关API ·通过一个对象获得完整的包名和类名 ·实例化Class类对象 ...
- Java进阶(六)Java反射机制可恶问题NoSuchFieldException
作为一种重要特性,Java反射机制在很多地方会用到.在此做一小结,供朋友们参考. 首先从一个问题开始着手. 可恶的问题又来了,NoSuchFieldException,如下图所示: 完全不知道这个qu ...
- [转]Java反射机制详解
目录 1反射机制是什么 2反射机制能做什么 3反射机制的相关API ·通过一个对象获得完整的包名和类名 ·实例化Class类对象 ·获取一个对象的父类与实现的接口 ·获取某个类中的全部构造函数 - 详 ...
- 【转载】Java反射机制详解
转自:http://baike.xsoftlab.net/view/209.html#3_8 1反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对 ...
- java反射相关
反射的机制:反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言 ...
- 详解Java反射机制
反射是程序在运行状态下,动态的获取某个类的内部信息的一种操作.例如:类名,包名,所有属性的集合,所有方法的集合,构造方法的集合等.该操作发生在程序的运行时状态,所以编译器管不着有关反射的一些代码,通常 ...
随机推荐
- jquery之---$.each详细
jQuery.each()函数用于遍历指定的对象和数组,并以对象的每个属性(或数组的每个成员)作为上下文来遍历执行指定的函数. 语法 静态函数$.each()的语法如下:$.each( object, ...
- Intellij idea 一次性包导入
Intellij idea中优化包导入用的快捷键是 ctrl + alt + o,但是如果需要一次性优化自动导入包,可以按照如下配置
- February 6 2017 Week 6 Monday
There are no shortcuts to any place worth going. 任何值得去的地方,都没有捷径. Several years ago, I climbed the Hu ...
- Ace admin 如何实现类似于freamset加载页面
如上标题所述,ace admin做后台页面的时候,可以实现类似于用freamset的功能,但是ace admin做的比freamset更好,他可以用异步加载的形式展示,而加载的页面的内容可以尽可能的少 ...
- C#图解教程读书笔记(第7章 类和继承)
1.所有的类都继承自object 2.如何隐藏基类的成员 要隐藏一个继承的数据成员,需要声明一个新的相同类型的成员,并使用相同的名称. 通过在派生类中声明新的带有相同签名的函数成员,可以隐藏或掩盖继承 ...
- 大素数测试的Miller-Rabin算法
Miller-Rabin算法本质上是一种概率算法,存在误判的可能性,但是出错的概率非常小.出错的概率到底是多少,存在严格的理论推导. 一.费马小定理 假如p是质数,且gcd(a,p)=1,那么 a(p ...
- BZOJ4419:[SHOI2013]发微博(乱搞)
Description 刚开通的SH微博共有n个用户(1..n标号),在短短一个月的时间内,用户们活动频繁,共有m条按时间顺序的记录: ! x 表示用户x发了一条微博: + x y 表示用户x和用 ...
- [USACO19JAN]Exercise Route
题目 这题的数据有点水,暴力合并\(set\)好像过了 分析一下这个题的性质,发现我们一条非树边就会形成一个环,而我们要求选择两个非树边,就会形成两个环,要求不走重复的点,就是说我们需要走一个大环,且 ...
- Windows彻底卸载系统自带的office
由于自带office导致按照新的office会提示要先卸载原来32位的office,又在控制面板或软件管理工具中找不到office,用如下方法删除 1.在C盘删除office文件夹 2.删除注册表 1 ...
- event对象,ie8及其以下
event 对象是 JavaScript 中一个非常重要的对象,用来表示当前事件.event 对象的属性和方法包含了当前事件的状态.当前事件,是指正在发生的事件:状态,是与事件有关的性质,如引发事件的 ...