java反射原来是这么玩的(反射一开,谁都不爱)
反射的发展历史
1996年01月23日,jdk 1.0版本发布,代号为Oak(橡树)。
这个代号为Oak(橡树)的版本,在发布后的第二年,1997年02月19日,发布jdk 1.1版本,这次版本发布中引入了反射机制。
关于反射机制,由于年代久远,能搜索到对于反射机制的记载少之又少,能找到最为久远的是一篇题为《Using Java Reflection》的文章,发表于 1998年1月,文中提到:反射是一个可以获取java类、属性的一个工具,因为它是动态加载的
。
而在另外一篇文章《A Button is a Bean》里解释道,反射是为了能把一个类的属性可视化的展示给用户,如下图所示:
通俗的解释就是:无论是公有还是私有的方法、属性、构造方法,全都可以用反射进行获取、进行赋值、调用。听到这个解释,是不是感觉反射很强。
正因为反射的强大,在java世界里运用的地方有很多,比如:Java类加载和初始化、Java中RTTI、Spring的IOC,。
如此广泛的运用,只能说反射除了强,用起来肯定很爽。我想起我的同事,IT界的刁民,总是热衷于反射。
他在讲解他是如何运用反射时,嘴角总是压抑不住的微笑,这种迷恋反射的样子,像极了爱情。
正所谓:反射一开,谁都不爱。(傲娇)
下面就看看反射究竟是如何在程序中使用的。
反射的概述和使用
反射的概述
JAVA反射机制是在运行状态中,
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
我们知道class文件是在编译的时候生成的,Class对象是将class文件读入内存,并为之创建一个Class对象。
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。
Class类里面,包含了一个类应有的所有描述,包括:
字段:Field.java
方法:Method.java
构造方法:Constructor.java
等等...
知道了Class类里面包含了哪些内容之后,再看一下new一个对象的究竟会发生那些过程:
反射的使用
这里使用一个Animal类来作为示范,可以看到这个类里的成员变量、方法、构造方法的访问修饰符既有public、也有private的。下面就将使用反射获取不同修饰符修饰的成员变量、方法、构造方法。
package com.shuai.ioc.ref;
public class Animal {
/**
* 动物名字
*/
public String name;
/**
* 动物年龄
*/
protected int age;
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
/**
* 默认的构造方法
*
* @param name
*/
Animal(String name) {
System.out.println("执行了" + "默认的构造方法 " + name);
}
/**
* 无参构造方法
*/
public Animal() {
System.out.println("执行了" + "无参构造方法 ");
}
/**
* 有一个参数的构造方法
*
* @param name
*/
public Animal(char name) {
System.out.println("执行了" + "有一个参数的构造方法 name:" + name);
}
/**
* 有多个参数的构造方法
*
* @param name
* @param age
*/
public Animal(String name, int age) {
System.out.println("执行了" + "有多个参数的构造方法 name:" + name + "age:" + age);
}
/**
* protected的构造方法
*
* @param n
*/
protected Animal(boolean n) {
System.out.println("执行了" + "受保护的构造方法 n:" + n);
}
/**
* 私有构造方法
*
* @param age
*/
private Animal(int age) {
System.out.println("执行了" + "私有构造方法 age:" + age);
this.name = "私有构造方法调用成功";
this.age = age;
}
/**
* 公有方法
*
* @param s
*/
public void public1(String s) {
System.out.println("调用了" + "公有的方法" + ": public1 , s:" + s);
}
/**
* protected的方法
*/
protected void protected2() {
System.out.println("调用了" + "protected的方法" + ": protected2 ");
}
/**
* 友好的方法
*/
void friendly1() {
System.out.println("调用了" + "友好的方法" + ": friendly1 ");
}
/**
* 私有方法
*
* @param age
* @return
*/
private String private1(int age) {
System.out.println("调用了" + "私有方法" + ": private1 ,age:" + age);
return age + "";
}
}
用反射获取类的构造方法
在Class类中,提供一系列获取被反射类构造方法的方法。
- 批量获取构造方法的方法
public Constructor[] getConstructors()
:所有"公有的"构造方法public Constructor[] getDeclaredConstructors()
:获取所有的构造方法(包括私有、受保护、默认、公有)
- 获取单个的方法,并调用
public Constructor getConstructor(Class... parameterTypes)
:获取单个的"公有的"构造方法public Constructor getDeclaredConstructor(Class... parameterTypes)
:获取"某个构造方法"可以是私有的,或受保护、默认、公有;
- 调用构造方法
- newInstance(Object... initargs)
package com.shuai.ioc.ref;
import com.shuai.ioc.Book;
import java.lang.reflect.Constructor;
public class ConstructorsTest {
public static void main(String[] args) throws Exception {
//1.加载Class对象
Class clazz = Class.forName("com.shuai.ioc.ref.Animal");
//2.获取所有公有构造方法
System.out.println("所有公有构造方法");
Constructor[] conArray = clazz.getConstructors();
for (Constructor c : conArray) {
System.out.println(c);
}
// 所有的构造方法,公有、私有都行
System.out.println("");
System.out.println("所有的构造方法,包括:私有、受保护、默认、公有");
conArray = clazz.getDeclaredConstructors();
for (Constructor c : conArray) {
System.out.println(c);
}
// 获取公有、无参的构造方法
System.out.println("");
System.out.println("获取公有、无参的构造方法");
Constructor con = clazz.getConstructor(null);
System.out.println("con = " + con);
//调用构造方法
Object obj = con.newInstance();
// 获取私有构造方法
System.out.println("");
System.out.println("获取私有构造方法,并调用");
con = clazz.getDeclaredConstructor(int.class);
System.out.println(con);
//暴力访问,忽略掉访问修饰符
con.setAccessible(true);
//调用构造方法
Animal animal = (Animal) con.newInstance(1);
System.out.println(animal.toString());
}
}
用反射获取类的方法
在Class类中,提供一系列获取被反射类构造方法的方法。
- 批量的
public Method[] getMethods()
:获取所有"公有方法";(包含了父类的方法也包含Object类)public Method[] getDeclaredMethods()
:获取所有的成员方法,包括私有的(不包括继承的)
- 获取单个的
public Method getMethod(String name,Class<?>... parameterTypes)
,name
: 方法名;Class ...
:形参的Class类型对象public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
,obj
:要调用方法的对象;args
:调用方式时所传递的实参;
- 调用方法
public Object invoke(Object obj,Object... args)
,obj
:要调用方法的对象;args
:调用方式时所传递的实参;
package com.shuai.ioc.ref;
import java.lang.reflect.Method;
public class MethodClassTest {
public static void main(String[] args) throws Exception {
//1.获取Class对象
Class stuClass = Class.forName("com.shuai.ioc.ref.Animal");
//2.获取所有公有方法
System.out.println("获取所有 公有 方法");
stuClass.getMethods();
Method[] methodArray = stuClass.getMethods();
for (Method m : methodArray) {
System.out.println(m);
}
System.out.println();
System.out.println("获取所有的方法,包括私有的");
methodArray = stuClass.getDeclaredMethods();
for (Method m : methodArray) {
System.out.println(m);
}
System.out.println();
System.out.println("获取公有的public1()方法");
Method m = stuClass.getMethod("public1", String.class);
System.out.println(m);
//实例化一个Student对象
Object obj = stuClass.getConstructor().newInstance();
m.invoke(obj, "this is name value");
System.out.println();
System.out.println("获取私有的private1()方法");
m = stuClass.getDeclaredMethod("private1", int.class);
System.out.println(m);
m.setAccessible(true);//解除私有限定
Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
System.out.println("返回值:" + result);
}
}
用反射获取类的字段
在Class类中,提供一系列获取被反射类构造方法的方法。
- 批量的
Field[] getFields()
:获取所有的"公有字段"Field[] getDeclaredFields()
:获取所有字段,包括:私有、受保护、默认、公有;
- 获取单个的
public Field getField(String fieldName)
:获取某个"公有的"字段;public Field getDeclaredField(String fieldName)
:获取某个字段(可以是私有的)
- 设置字段的值
public void set(Object obj,Object value)
:obj
:要设置的字段所在的对象;value
:要为字段设置的值;
package com.shuai.ioc.ref;
import java.lang.reflect.Field;
public class FieldsTest {
public static void main(String[] args) throws Exception {
//1.获取Class对象
Class animalClass = Class.forName("com.shuai.ioc.ref.Animal");
//2.获取字段
System.out.println("获取所有公有的字段");
Field[] fieldArray = animalClass.getFields();
for (Field f : fieldArray) {
System.out.println(f);
}
System.out.println();
System.out.println("获取所有的字段(包括私有、受保护、默认的)");
fieldArray = animalClass.getDeclaredFields();
for (Field f : fieldArray) {
System.out.println(f);
}
System.out.println();
System.out.println("获取公有字段并调用");
Field f = animalClass.getField("name");
System.out.println(f);
//获取一个对象
Object obj = animalClass.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();
//为字段设置值
f.set(obj, "dog");//为Student对象中的name属性赋值--》stu.name = "刘德华"
//验证
Animal stu = (Animal) obj;
System.out.println("验证name:" + stu.name);
System.out.println();
System.out.println("获取私有字段并调用");
f = animalClass.getDeclaredField("name");
System.out.println(f);
f.setAccessible(true);//暴力反射,解除私有限定
f.set(obj, "this is name value");
System.out.println("验证name:" + stu);
}
}
反射越过泛型检查
编写代码时,如果我们设置容器list为String类型,在调用add方法插入数据时入参传了其他类型,编译时会无法成功,但是通过反射却可以执行,实例代码:
package com.shuai.ioc.ref;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/*
* 通过反射越过泛型检查
*
*/
public class IgnoreType {
public static void main(String[] args) throws Exception {
List<String> list = new ArrayList<>();
list.add("one");
//反射获取list对象
Class listClass = list.getClass();
// 调用list对象的add方法
Method m = listClass.getMethod("add", Object.class);
m.invoke(list, 100);
//输出验证
for (Object obj : list) {
System.out.println(obj);
}
}
}
java反射原来是这么玩的(反射一开,谁都不爱)的更多相关文章
- Java反射机制demo(七)—反射机制与工厂模式
Java反射机制demo(七)—反射机制与工厂模式 工厂模式 简介 工厂模式是最常用的实例化对象模式. 工厂模式的主要作用就是使用工厂方法代替new操作. 为什么要使用工厂模式?直接new不好吗? 直 ...
- Android(java)学习笔记108:通过反射获取私有构造方法并且使用
反射获取私有构造方法并且使用: 1.获取字节码文件.class对象: Class c = Class.forName("cn.itcast_01.Person") ...
- JAVA进阶之旅(二)——认识Class类,反射的概念,Constructor,Field,Method,反射Main方法,数组的反射和实践
JAVA进阶之旅(二)--认识Class类,反射的概念,Constructor,Field,Method,反射Main方法,数组的反射和实践 我们继续聊JAVA,这次比较有意思,那就是反射了 一.认识 ...
- Android(java)学习笔记49:通过反射获取私有构造方法并且使用
1. 反射获取私有构造方法并且使用: (1)获取字节码文件.class对象: Class c = Class.forName("cn.itcast_01.Person&qu ...
- java反射并不是什么高深技术,面向对象语言都有这个功能,而且功能也很简单,就是利用jvm动态加载时生成的class对象
java反射并不是什么高深技术,面向对象语言都有这个功能. 面向对象语言都有这个功能,而且功能也很简单,就是利用jvm动态加载时生成的class对象,去获取类相关的信息 2.利用java反射可以调用类 ...
- java反射构建对象和方法的反射调用
Java反射技术应用广泛,其能够配置:类的全限定名,方法和参数,完成对象的初始化,设置是反射某些方法.可以增强java的可配置性. 1.1 通过反射构建对象(无参数): 例如我们使用 ReflectS ...
- Java SE练习 - 对dom4j解析、反射的综合练习
原 Java SE练习 - 对dom4j解析.反射的综合练习 2017年12月13日 14:41:07 都说名字长不会被发现 阅读数 138 版权声明:本文为博主原创文章,遵循CC 4.0 by-sa ...
- Java反射理解(五)-- 方法反射的基本操作
Java反射理解(五)-- 方法反射的基本操作 方法的反射 1. 如何获取某个方法 方法的名称和方法的参数列表才能唯一决定某个方法 2. 方法反射的操作 method.invoke(对象,参数列表) ...
- java 面向对象(三十七):反射(一) 反射的概述
1.本章的主要内容 2.关于反射的理解 Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属 ...
随机推荐
- [程序员代码面试指南]递归和动态规划-最小编辑代价(DP)
问题描述 输入 原字符串StrOrg,目标字符串StrTarget,插入.删除.替换的编辑代价ic,dc,rc.输出将原字符串编辑成目标字符串的最小代价. 解题思路 状态表示 dp[i][j]表示把s ...
- 使用阿里云OSS的服务端签名后直传功能
网站一般都会有上传功能,而对象存储服务oss是一个很好的选择.可以快速的搭建起自己的上传文件功能. 该文章以使用阿里云的OSS功能为例,记录如何在客户端使用阿里云的对象存储服务. 服务端签名后直传 背 ...
- C#开发PACS医学影像处理系统(十一):Dicom影像挂片协议
通俗点说,挂片协议可以看作整个系统的一个相对复杂一点的配置文件,可以用JSON或XML格式来读取与保存, 另外,可以制作一个独立的exe配置程序来管理这些挂片协议. 假设配置了CT的挂片协议的右键菜单 ...
- 1. spring5源码 -- Spring整体脉络 IOC加载过程 Bean的生命周期
可以学习到什么? 0. spring整体脉络 1. 描述BeanFactory 2. BeanFactory和ApplicationContext的区别 3. 简述SpringIoC的加载过程 4. ...
- matlab中的多项式计算
在做多项式加法的时候需要做多项式扩展.这里将g1扩展到与f等长 多项式的乘积,是两个多项式之和减1, 多项式求导函数:ployder() 先建立两个多项式,再求a的导函数 在计算两个多项式乘积的导函数 ...
- Nginx 配置 HTTPS 完整过程(阿里云申请免费版一年ssl证书)
1. nginx 的 ssl 模块安装 查看 nginx 是否安装 http_ssl_module 模块. $ /usr/local/nginx/sbin/nginx -V 如果出现 configur ...
- 关于SpringBoot的一点笔记
@SpringBootApplication /** * @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用 */ @SpringBootAppl ...
- MATLAB 安装
参考: 链接1 链接2 重要: 1.秘钥:09806-07443-53955-64350-21751-41297 2.在安装目录下替换 bin
- 初探JVM
JVM探究 请你谈谈你对JVM的理解?java8虚拟机和之前的变化更新? 什么是OOM,什么是栈溢出StackOverFlowError?怎么分析? JVM的常用调优参数? 内存快照如何抓取,怎么分析 ...
- Mongodb PHP封装类
分享一个Mongodb PHP封装类 <?php /** * Mongodb 基本操作API,支持基本类似关系统型数据库的操作接口 * * @version 1.0 * [说明] * * 1:该 ...