Java 中的 反射机制
概念明确
什么是类的对象?
类的对象就是:基于某个类 new 出来的对象,也称为实例对象。这个很容易理解,就不过多阐述了。
什么是类对象?
类对象就是:类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)。

包含类信息的.class文件被JVM加载到内存后,一个个的类就变成了一个个的 java.long.Class 对象,每个类有且只有一个java.long.Class对象,这些对象包含了类的全部信息,这些对象存储在方法区中。
每一个对象实例和创建它的类对象之间都有一条类型引用,代表着此实例是这个类型的。
反射机制
什么是反射机制?
在 Java 中要使用一个类首先要将该类加载到内存中,系统会为该类生成一个java.lang.Class的实例。这个 Class 对象的作用很大,通过它系统可以访问到JVM中该类的信息,同时 Class 对象也是实现 Java 反射机制的核心要素。
反射(Reflection)是指:
程序可以访问、检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
上面的解释并不太通俗易懂,我们看看下面的阐述:
在高级语言中,允许改变程序结构或变量类型的语言称为动态语言,例如Perl、Python、Ruby等就是动态语言,而像C、C++、Java这类语言在程序编译时就确定了程序的结构和变量的类型,因此不是动态语言。尽管如此,Java还是为开发者提供了一个非常有用的与动态相关的机制-反射(Reflection)。
运用反射机制可以在运行时加载和使用编译期间未知的类型。也就是说,Java程序可以加载在运行时才得知类名的class,并生成其对象实体,或访问其属性,或唤起其成员方法。通俗点讲,所谓Java的反射机制,就是在Java程序运行时动态地加载并使用在编译期并不知道的类。
反射机制的作用
① 获取一个类的信息。
② 通过类型的名称动态生成并操作对象。
获取一个类的Class对象
通过一个类的Class对象可以获取该类的信息,包括类的构造函数、属性、方法等,那么如何来获取一个类的Class对象呢?
在Java中获取一个类的Class对象的方法有3种:
➷ Class.forName(className)。『推荐使用』
➷ 调用某个类的class属性获取该类对应的Class对象。
➷ 调用对象的getClass()方法获取该对象所属类对应的Class对象。
代码演示:
// Person 类
public class Person implements Serializable, Cloneable{
private String name;
private int age; public Person(String name, int age) {
super();
this.name = name;
this.age = age;
} public Person() {
super();
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} @Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
} public void eat() {
System.out.println(name + "正在吃东西。。。");
} public void eat(String food) {
System.out.println(name + "正在吃" + food + "。。。");
} private void privateMethod() {
System.out.println("这是一个私有方法");
} public static void staticMethod() {
System.out.println("这是一个静态方法");
} }
public class Test {
public static void main(String[] args) throws Exception {
// 1.创建类的对象
Person zhangsan = new Person("张三", 18);
System.out.println(zhangsan.toString());
// 2.获取类对象
// 方式一:通过类的对象,获取类对象
Person s = new Person();
Class<?> c = s.getClass();
System.out.println(c.toString());
// 方式二:通过类名获取类对象
Class<?> c1 = Person.class;
System.out.println(c1.toString());
// 方式三:通过静态方法获取类对象 [推荐使用]
Class<?> c2 = Class.forName("com.ruoli.reflect.Person");
System.out.println(c2.toString());
}
}
运行结果:

一般情况下生成一个类的对象是不需要使用反射的。但是有些特殊的情况必须用到反射才能实现类的实例化。比如要对一个类进行操作,但是这个类的类名需要从配置文件中读取,事先并不知道该类的类名等信息。这样在编译时就无法确定该类的类名,也就无法按照传统的方法构建类的对象了。所以可以先读取配置文件并拿到这个类的全类名,然后利用反射生成该类的对象,并进行相应的操作。一个很好的例子就是设计模式中的简单工厂模式。
综上所述,所以大多数情况下都是使用Class.forName(className)这种方法来获取类对象的,也推荐大家在日常编程中多实用这种方法。
获取类的名字,包名,父类,接口
代码演示:
public class Test {
public static void main(String[] args) throws Exception {
// 1.获取类对象
Class<?> c2 = Class.forName("com.ruoli.reflect.Person");
// 2.获取类的名字
System.out.println("类名:" + c2.getName());
// 3.获取类的包名
System.out.println("包名:" + c2.getPackage().getName());
// 4.获取类的父类
System.out.println("父类:" + c2.getSuperclass().getName());
// 5.获取类的接口
Class<?>[] classes = c2.getInterfaces();
System.out.println("接口:" + Arrays.toString(classes));
// 6.获取类的简称
System.out.println("简称:" + c2.getSimpleName());
}
}
运行结果:

获取类的构造方法,并创建对象
代码演示:
public class Test {
public static void main(String[] args) throws Exception {
// 1.获取类对象
Class<?> c2 = Class.forName("com.ruoli.reflect.Person");
// 2.获取类的构造方法
// 2.1获取全部的构造方法
// Constructor<?>[] cons = c2.getConstructors();
// for (Constructor<?> constructor : cons) {
// System.out.println(constructor.toString());
// }
// 2.2获取无参的构造方法,创建对象
// Constructor<?> con = c2.getConstructor();
// System.out.println(con.toString());
//
// Person zhangsan = (Person)con.newInstance();
// System.out.println(zhangsan.toString());
// 简单方法:实际上就是调用上面的无参构造
// Person xiaoming = (Person)c2.newInstance();
// System.out.println(xiaoming.toString());
// 2.3获取带参的构造方法,创建对象
Constructor<?> con = c2.getConstructor(String.class, int.class);
System.out.println(con.toString());
Person xiaoming = (Person)con.newInstance("小明", 19);
System.out.println(xiaoming.toString());
}
}
运行结果:

获取类中的方法,并调用方法
代码演示:
public class Test {
public static void main(String[] args) throws Exception {
// 1.获取类对象
Class<?> c2 = Class.forName("com.ruoli.reflect.Person");
// 2.获取类的方法
// 2.1 getMethods() 只能获取公开的方法,包括从父类继承的方法
// Method[] methods = c2.getMethods();
// for (Method method : methods) {
// System.out.println(method.toString());
// }
// 2.2 getDeclaredMethods() 获取类中的所有方法,包括私有、默认、保护的方法,不包含继承的
// Method[] methods = c2.getDeclaredMethods();
// for (Method method : methods) {
// System.out.println(method.toString());
// }
// 2.3获取单个方法
// 获取无参、无返回值的方法eat():
Method eatMethod = c2.getMethod("eat");
System.out.println(eatMethod.toString());
Person zhangsan = (Person)c2.newInstance();
eatMethod.invoke(zhangsan);
// 获取无参、有返回值的方法toString():
Method toStringMethod = c2.getMethod("toString");
System.out.println(toStringMethod.toString());
Object result = toStringMethod.invoke(zhangsan);
System.out.println(result);
// 获取带参、无返回值的方法eat(String food):
Method eatMethod2 = c2.getMethod("eat", String.class);
System.out.println(eatMethod2.toString());
eatMethod2.invoke(zhangsan, "鸡腿");
// 获取私有方法privateMethod()
Method privateMethod = c2.getDeclaredMethod("privateMethod");
System.out.println(privateMethod.toString());
// 此时调用方法(私有方法),没有访问权限
// 设置访问权限无效
privateMethod.setAccessible(true);
privateMethod.invoke(zhangsan);
// 获取静态方法staticMethod()
Method staticMethod = c2.getMethod("staticMethod");
System.out.println(staticMethod.toString());
staticMethod.invoke(null);
}
}
运行结果:

这里需要注意的是,当我们通过反射获取一个类的私有方法时,我们是没有权限来使用的,因此需要设置访问权限,然后才能使用这个私有方法。
获取类中的属性
代码演示:
public class Test {
public static void main(String[] args) throws Exception {
// 1.获取类对象
Class<?> c2 = Class.forName("com.ruoli.reflect.Person");
// 2.获取属性 公开的字段,父类继承的字段
// Field[] fields = c2.getFields();
// System.out.println(fields.length);
// 2.获取属性 获取所有的属性,但不包含继承的
// Field[] fields = c2.getDeclaredFields();
// System.out.println(fields.length);
// for (Field field : fields) {
// System.out.println(field);
// }
// 2.获取单个属性
Field nameField = c2.getDeclaredField("name");
nameField.setAccessible(true);
// 赋值
Person zhangsan = (Person)c2.newInstance();
nameField.set(zhangsan, "张三");
// 获取值
System.out.println(nameField.get(zhangsan));
}
}
运行结果:

反射机制总结
反射机制
所谓Java的反射机制,就是在Java程序运行时动态地加载并使用在编译期并不知道的类。
反射机制的作用
➷ 反射机制可以动态获取一个类的信息,包括该类的属性和方法,这个功能可应用于对class文件进行反编译。
➷ 反射机制也可以通过类型的名称动态生成对象,并调用对象中的方法。
反射机制的优缺点
优点:可以在运行时获取一个类的实例,大大提高了系统的灵活性和可扩展性。
✘ 缺点:性能较差,安全性不高,破坏了类的封装性。
Java 中的 反射机制的更多相关文章
- java中的反射机制在Android开发中的用处
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反 ...
- 浅说Java中的反射机制(二)
写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下: 引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧.(()为我手记) 什么是反射? 正常编 ...
- 浅说Java中的反射机制(一)
在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...
- 【Java基础】java中的反射机制与动态代理
一.java中的反射机制 java反射的官方定义:在运行状态下,可以获取任意一个类的所有属性和方法,并且可通过某类任意一对象实例调用该类的所有方法.这种动态获取类的信息及动态调用类中方法的功能称为ja ...
- java 中利用反射机制获取和设置实体类的属性值
摘要: 在java编程中,我们经常不知道传入自己方法中的实体类中到底有哪些方法,或者,我们需要根据用户传入的不同的属性来给对象设置不同的属性值,那么,java自带的反射机制可以很方便的达到这种目的,同 ...
- Java 中的反射机制
JAVA反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能称为ja ...
- 深入理解Java中的反射机制
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. ...
- Java中的反射机制和动态代理
一.反射概述 反射机制指的是Java在运行时候有一种自观的能力,能够了解自身的情况为下一步做准备,其想表达的意思就是:在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法:对于任意一个对象 ...
- Java中的反射机制Reflection
目录 什么是反射? 获取.class字节码文件对象 获取该.class字节码文件对象的详细信息 通过反射机制执行函数 反射链 反射机制是java的一个非常重要的机制,一些著名的应用框架都使用了此机制, ...
- Java中的反射机制
Java反射机制 反射机制定义 反射机制是Java语言中一个非常重要的特性,它允许程序在运行时进行自我检查,同时也允许其对内部成员进行操作.由于反射机制能够实现在运行时对类进行装载,因此能够增加程序的 ...
随机推荐
- 编程体系结构(05):Java多线程并发
本文源码:GitHub·点这里 || GitEE·点这里 一.多线程导图 二.多线程基础 1.基础概念 线程是操作系统能够进行运算调度的最小单位,包含在进程之中,是进程中的实际运作单位.一条线程指的是 ...
- [VBA原创源代码] excelhome 汇总多工作表花名册
生病了,一点一滴的积累,慢慢康复,今年十月,我就 2 周岁了. 以下代码完成了excelhome中留的作业 http://club.excelhome.net/forum.php?mod=viewth ...
- 【题解】CF1207E XOR Guessing
Link 这是一道交互题. \(\text{Solution:}\) 观察到猜的数范围只有\(2^{14}.\) 我第一次想到的方法是,我们可以确定系统选择的两个数的异或和,用这个异或和去穷举所有目标 ...
- C#实现——十大排序算法之选择排序
选择排序法 1.工作原理(算法思路) 给定一个待排序数组,找到数组中最小的那个元素 如果最小元素不是待排序数组的第一个元素,则将其和第一个元素互换 在剩下的元素中,重复1.2过程,直到排序完成. 2. ...
- 记录编译JDK11源码时遇到的两个问题
执行make all报错信息: 错误一 /src/hotspot/share/runtime/arguments.cpp:1461:35: error: result of comparison ag ...
- MQTT消息队列压力测试
环境准备: jmeter插件下载:mqttxmeter1.0.1jarwithdependencies.jar 把MQTT插件放在 %JMeter_Home%/lib/ext下.重启jmeter. M ...
- Docker笔记7:Docker 命令自动补齐
经常大家会碰到这种现象,Docker 已经安装好了,但是使用 docker 命令时 不能自动补齐,即输入 docker 命令后,按 Tab 键无法列出子命令(或参数)的候选项. [机制] Linux ...
- XML流操作
/// <summary> /// 保存XML为指定格式 /// </summary> /// <param name=& ...
- Axure实现vcg官网首页原型图
W240第二天第三天 Axure的简单使用: 作业实现:vcg官网首页原型图 帮助文档基础篇:原型图基础之axure线框图设计 导航栏设计: 添加通用母版header 导航栏设计注意: 鼠标移动到下面 ...
- MeteoInfoLab脚本示例:获取一维数据并绘图
气象数据基本为多维数据(通常是4维,空间3维加时间维),只让数据中一维可变,其它维均固定即可提取一维数据.比如此例中固定了时间维.高度维.纬度维,只保留经度维可变:hgt = f['hgt'][0,[ ...