JAVA基础-反射
一、反射的介绍
JAVA反射机制是在运行状态中,能够获取任意一个类的所有属性和方法,对于任意一个对象,都能够调用它的任意
一个方法。这种动态获取的以及动态调用对象的方法的功能称为java语言的反射机制。JAVA编译时是先获取到类,然
后才是类里边的属性和方法,而反射则和编译相反,他是先获取类里边的对象和方法然后在告诉他是哪个类里的。简单
来说, 就可以把.class文件比做动物的尸体, 而反射技术就是对尸体的一种解剖.通过反射技术, 我们可以拿到该字节码
文件中所有的东西, 例如成员变量, 成员方法, 构造方法, 而且还包括私有。想要反射首先要获取到程序的“尸体”也就
是.class文件。
二、字节码文件的获取
获取字节码对象有3种方式:
1、类名.class - 这是一个静态的属性, 只要知道类名, 就可以获取
2、对象名.getClass() - Object类里的getClass()方法,对象已经存在的情况下, 可以使用这种方式
3、Claire.forName("类的全类名(包名+类名)") - 通过Class类里的静态方法forName来获取节码对象
举例:
public static void main(String[] args) throws ClassNotFoundException {
// 通过Object的getClass()方法获取,必须要有对象
Student s = new Student();
Class clazz = s.getClass();
// 通过类名获取字节码对象
Class clazz2 = Student.class;
// 通过Class类里的静态方法forName来获取节码对象
Class clazz3 = Class.forName("com.fanshe.Student");
System.out.println(clazz == clazz2);
System.out.println(clazz == clazz3);
System.out.println(clazz); }
字节码文件其实就是描述.class文件的对象。
三、对构造方法的操作
*通过反射获取公有构造方法的两种方式:
1、返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法,可以获取无参构造也可以
根据传入的类型来匹配对应的构造方法:getConstructor(Class<?>... parameterTypes)
2、返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法:
getConstructors()
3、创建此 Class 对象所表示的类的一个新实例:
newInstance()
*暴力获取(可以获取全部权限的):
1、返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法:
getDeclaredConstructor(Class<?>... parameterTypes)
2、返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法:
getDeclaredConstructors()
举例:
public static void main(String[] args) throws ReflectiveOperationException {
// Class.forName()获取字节码对象
Class<?> forName = Class.forName("com.fanshe.Student");
// 获取所有公共构造方法
Constructor<?>[] constructors = forName.getConstructors();
// 遍历
for (Constructor<?> constructor : constructors) {
// 打印结果
System.out.println(constructor);
}
System.out.println("--------------------------------------");
// 暴力获取,可以获取所有的构造方法(包括私有的)
Constructor<?> c1 = forName.getDeclaredConstructor();
c1.setAccessible(true);
System.out.println(c1);
//获取有参构造
Constructor<?> c2 = forName.getConstructor(String.class, int.class);
System.out.println(c2);
}
四、对成员变量和方法的操作
*公有成员变量获取方法:
1、返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段:
getField(String name) - 参数为要返回的变量名
2、返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段:
getFields() - 参数为要返回的变量名
*任意成员变量获取方法:
1、返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段:
getDeclaredField(String name) - 参数为要返回的变量名
2、返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段:
getDeclaredFields() - 参数为要返回的变量名
*获取公有的方法:
1、返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法:
getMethod(String name, Class<?>... parameterTypes) - name 方法名、parameterTypes 参数列表
2、返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口
声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法:
getMethods()
*暴力获取方法:
1、 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法:
getDeclaredMethod(String name, Class<?>... parameterTypes) - name 方法名、parameterTypes
参数列表
2、返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、
默认(包)访问和私有方法,但不包括继承的方法:
getDeclaredMethods()
需要注意的是想要获取私有的变量或者方法时应使用AccessibleObject类里的setAccessible(boolean flag)方法 - 参数
值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问
检查。
Constructor, Field, Method都是AccessibleObject的子类所以可以直接使用父类的setAccessible(boolean flag)方法。
**通过反射获得变量的流程:
1. 通过反射获取该类的字节码对象
2. 创建该类对象
3. 获取该类中需要操作的字段(成员变量)
4. 通过字段对象中的方法修改属性值
**通过反射执行方法的流程
1. 通过反射获取该类的字节码对象
2. 创建该类对象
3. 调用getMethod方法获取Method对象, 方法形参接受方法的名字
4. 调用Method方法中的invoke()将方法运行
举例:
*被反射的学生01类
public class Student01 {
public String name;
private int age; public Student01() {
super();
// TODO Auto-generated constructor stub
} public Student01(String name, int age) {
super();
this.name = name;
this.age = age;
} public void name() {
System.out.println("测试"); } 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;
} private void mane1() {
System.out.println("这是个萌萌哒私有的"); } @Override
public String toString() {
return "Student01 [name=" + name + ", age=" + age + "]";
} }
*对学生01类进行反射
public static void main(String[] args) throws ReflectiveOperationException {
// 获取字节码对象
Class<?> clazz = Class.forName("com.fanshe.Student01");
// 创建该类的对象
Object stu = clazz.newInstance();
// System.out.println(stu);
// 获取学生类的name变量
Field f1 = clazz.getField("name");
/*
* set将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
* 为stu对象里的name变量赋值
*/
f1.set(stu, "李四");
// get()返回指定对象上此 Field 表示的字段的值。
Object name = f1.get(stu);
// 暴力获取age字段
Field f2 = clazz.getDeclaredField("age");
System.out.println(f2);
// 让jvm不检查权限
f2.setAccessible(true);
// 为其赋值
f2.set(stu, 24);
// 获取stu对象的f2字段的值
Object age = f2.get(stu);
System.out.println(name);
System.out.println(age);
// 公有无参无返回值,name()
Method method = clazz.getMethod("name");
// 使用Method类的invoke方法执行name方法
method.invoke(stu);
// 公有代参无返回值,参数为String类型
Method m2 = clazz.getMethod("setName", String.class);
// 执行stu对象的setName方法,传入参数
m2.invoke(stu, "李晨宇");
// 公有无参有返回值
Method m3 = clazz.getMethod("getName");
// 返回值为invoke
Object invoke = m3.invoke(stu);
System.out.println(invoke);
// 私有
Method m4 = clazz.getDeclaredMethod("mane1");
// 让jvm不检查权限
m4.setAccessible(true);
// 执行stu对象的mane1方法
m4.invoke(stu);
}
需要注意的是,反射无参构造时被反射的类一定要有无参构造方法,默认生成的也算。
五、反射的应用
我们在开发的时候,由于要考虑到代码的重用性,就会用反射来处理一些问题。而JAVA的一些常用jar包和主流框架的配置
都用到了反射的原理,学习反射有助于我们对源码的阅读和理解。BeanUtils工具类(Apache开发的便于操作JavaBeen的工具类)
就用到了反射的方法。
*BeanUtils的部分实现:
public class MyBeanUtils {
//因为是工具类,不需要实例化。所以私有构造方法
private MyBeanUtils() {
super();
// TODO Auto-generated constructor stub
} /*
* 给对象中的属性赋值 传入类的对象类型,和要修改的属性的值不确定所以用Object类型,属性名用String类型
*/
public static void setProrerty(Object object, String name, Object values)
throws ReflectiveOperationException, SecurityException {
// 获取传入对象的字节码文件
Class clazz = object.getClass();
// 根据传入的属性获取Field对象,因为不确定属性的权限,用的暴力反射
Field field = clazz.getDeclaredField(name);
// 让jvm不检查权限
field.setAccessible(true);
// 为object对象里的name属性赋值
field.set(object, values); } // 获取对象中的属性
public static String getProrerty(Object object, String name)
throws ReflectiveOperationException, SecurityException {
// 获取传入对象的字节码文件
Class clazz = object.getClass();
// 根据传入的属性获取Field对象,因为不确定属性的权限,用的暴力反射
Field field = clazz.getDeclaredField(name);
// 让jvm不检查权限
field.setAccessible(true);
// 获取name属性的值
Object object2 = field.get(object);
// System.out.println(object);
// 将值返回
return object2.toString();
} // 给对象中的属性赋值(通过Map的方式),Map里key存的是属性名,value存的是要赋的值
public static void populat(Object object, Map map) throws ReflectiveOperationException, SecurityException {
// 获取传入对象的字节码文件
Class clazz = object.getClass();
// 返回此集合中的key集合
Set keySet = map.keySet();
// 遍历key
for (Object object2 : keySet) {
// 获得value值
Object value = map.get(object2);
try {
// 根据传入的key(属性)获取Field对象,因为不确定属性的权限,用的暴力反射
Field field = clazz.getDeclaredField(object2.toString());
// 让jvm不检查权限
field.setAccessible(true);
// 赋值
field.set(object, value);
} catch (NoSuchFieldException e) {
// 出现异常,给出友好型提示
System.out.println("Mdzz,属性都记不住");
}
}
}
}
*测试工具类:
public static void main(String[] args) throws RuntimeException, ReflectiveOperationException {
// 创建学生01对象
Student01 s1 = new Student01();
// 使用MyBeanUtils工具类为学生01对象赋值
MyBeanUtils.setProrerty(s1, "name", "啦啦");
MyBeanUtils.setProrerty(s1, "age", 15);
// 使用MyBeanUtils工具类为学生01对象取值
String name = MyBeanUtils.getProrerty(s1, "name");
String age = MyBeanUtils.getProrerty(s1, "age");
// 打印出来
System.out.println(name);
System.out.println(age);
System.out.println("------------------------------------ ");
// 创建HashMap作为数据源
HashMap<String, Object> hashMap = new HashMap<>();
// 为HashMap赋值
hashMap.put("qqqqq", "大大的"); // 属性不存在会给出友好型提示
hashMap.put("name", "大大的");
hashMap.put("age", 110);
// 使用MyBeanUtils工具类为学生01对象赋值
MyBeanUtils.populat(s1, hashMap);
System.out.println(s1);
}
JAVA基础-反射的更多相关文章
- Java基础-反射(reflect)技术详解
Java基础-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类加载器 1>.JVM 类加载机制 如下图所示,JVM类加载机制分为五个部分 ...
- Java基础——反射
今天学到Java基础中的反反射.依照我学习后的个人理解呢,反射就是一套获取类.属性.方法等的工具吧.(其实,感觉学完反射后,有点像喝凉水,解渴但确实我也没体会出它有什么味道,我可能没有学到精髓吧.自己 ...
- Java基础反射(二)
原文地址http://blog.csdn.net/sinat_38259539/article/details/71799078 反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Cla ...
- java基础(反射,注解,多线程,juc)
JAVA基础 java反射 class对象 三种方式获取class加载时对象 1.class.forName("全类名"):将字节码文件加载进内存,返回class对象 2.类名.c ...
- [java 基础]反射入门
原文 概况 使用java的反射,可以让我们检查(或者修改)类,接口,字段,方法的特性.当你在编译期不知道他们的名字的时候非常有用. 除此之外,可以使用反射来创建实例,调用方法或者get/set 字段值 ...
- JAVA基础-反射机制
什么是JAVA的反射机制 Java反射是Java被视为动态(或准动态)语言的一个关键性质.这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其 ...
- java基础-反射(细节)
java面试题--java反射机制? Java反射机制的作用:1)在运行时判断任意一个对象所属的类.2)在运行时判断任意一个类所具有的成员变量和方法.3)在运行时任意调用一个对象的方法4)在运行时构造 ...
- Java基础—反射(转载)
转载自: JAVA反射与注解 JAVA反射 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射机制是什么 反射 ...
- java基础——反射机制
反射机制是什么 反射机制就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为jav ...
- Java基础—反射与代理(新手向)
第1章 反射与代理 1.1 反射定义 一般情况下,需要一个功能的前提是遇到了某个问题,这里先列举一些问题,然后再通过反射是如何解决了这些问题,来引出反射的定义. 普通开发人员工作中最常见的问题:需要生 ...
随机推荐
- Java学习5——标识符和关键字
标识符: 1.Java对各种变量.方法和类等要素命名时使用的字符串序列称为标识符.凡是自己可以起名字的地方都叫标识符,都要遵守标识符的规则. 2.Java标识符命名规则: 标识符由字母.下划线&quo ...
- 团队作业4——第一次项目冲刺(Alpha版本)4.22
团队作业4--第一次项目冲刺(Alpha版本) Day one: 会议照片 由于团队中的组员今天不在学校,所以我们的站立会议提前一天展开. 项目进展 由于今天是Alpha版本项目冲刺的第一天,所以没有 ...
- 201521123072《java程序设计》第十一周学习总结
201521123072<java程序设计>第十一周学习总结 1. 本周学习总结 2. 书面作业 本次PTA作业题集多线程 互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问 ...
- 201521123048 《Java程序设计》第13周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu ...
- JAVA课程设计+五子棋(个人博客)
1.团队博客地址: http://www.cnblogs.com/yzb123/p/7063424.html 2.个人负责模块或任务说明 游戏初始化,清除棋盘上的棋子 鼠标监听器 棋子落棋 判断胜负 ...
- Sublime自定义语法
以thinkphp框架的assign函数为例 在sublime\Data\Packages\PHP下 新建文件:assign.sublime-snippet 内容为 <snippet> & ...
- Apache Spark 2.2.0 中文文档 - 概述 | ApacheCN
Spark 概述 Apache Spark 是一个快速的, 多用途的集群计算系统. 它提供了 Java, Scala, Python 和 R 的高级 API,以及一个支持通用的执行图计算的优化过的引擎 ...
- java围棋游戏源代码
//李雨泽源代码,不可随意修改.//时间:2017年9月22号.//地点:北京周末约科技有限公司.//package com.bao; /*围棋*/ /*import java.awt.*; impo ...
- 凸包GiftWrapping GrahamScan 算法实现
开始 游戏内有需求做多边形碰撞功能,但是接入box2d相对游戏的需求来说太重度了.所以准备自己实现碰撞. 确定多边形,必然要用到凸包的算法.在github上也找到了一些lua实现,但是这里的算法没有考 ...
- 在vue中let var 和const 区别
let和const 使用方法: (1).有没有感觉到在 javascript 使用var会发生变量提升,即脚本开始运行时, 变量已经存在了,但是没有值,所以会输出undefined. 而 ...