java 反射详解
反射的概念和原理
|
类字节码文件是在硬盘上存储的,是一个个的.class文件。我们在new一个对象时,JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用在加载了,而是直接使用之前缓存的这个字节码信息。 字节码的信息包括:类名、声明的方法、声明的字段等信息。在Java中“万物皆对象”,这些信息当然也需要封装一个对象,这就是Class类、Method类、Field类。 通过Class类、Method类、Field类等等类 可以得到 这个类字节码的全部信息,甚至可以不用new关键字就创建一个实例,可以执行一个对象中的方法,设置或获取字段的值,这就是反射技术。 注意:在反射技术中一个类的任何成员都有对应 的类进行描述。 比如: 成员变量(Field) 方法----> Method类 |
Class类
Class类解释说明:
|
Java中有一个Class类用于代表某一个类的字节码。通过获取这个class类的对象,就可以得到字节码的一些信息 |
得到class对象的三种方法
|
Java提供了三种方式获取类的字节码 forName():forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装(推荐使用这个,一般配合配置文件读取类的全名 创建对象) 类名.class 对象.getClass() |
例子:
Person类,用于被测试的类
|
package cn.itcast.reflect; public class Person { private int id; String name; public Person(int id,String name){ this.id = id; this.name = name; } public Person(){} private Person(int id){ this.id = id; } public void eat(int num){ System.out.println(name+"吃很"+num+"斤饭"); } private static void sleep(int num){ System.out.println("明天睡上"+num+"小时"); } public static void sum(int[] arr){ System.out.println("长度是:"+ arr.length); } @Override public String toString() { return " 编号:"+ this.id +" 姓名:"+ this.name; } } |
获取class对象的代码:
|
public static void main(String[] args) throws ClassNotFoundException { //推荐使用: 获取Class对象的方式一 Class clazz1 = Class.forName("cn.itcast.reflect.Person"); System.out.println("clazz1:"+ clazz1); //获取Class对象的方式二: 通过类名获取 Class clazz2 = Person.class; System.out.println("clazz1==clazz2?"+ (clazz1==clazz2)); //获取Class对象的方式三 :通过对象获取 Class clazz3 = new Person(110,"狗娃").getClass(); System.out.println("clazz2==clazz3?"+ (clazz2==clazz3)); } |
打印结果:
|
clazz1:class cn.itcast.reflect.Person clazz1==clazz2?true clazz2==clazz3?true |
通过class对象获取一些信息
获取类的全名(包名+类名),类的简单名称(不带包名,只有类名),类的修饰符
API解释说明:
|
1. getName()类的名称(全名,全限定名) 2 getSimpleName()类的的简单名称(不带包名) 3. getModifiers(); 类的的修饰符 |
例子:
|
import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; //获取到对应的Class对象 Class clazz = Class.forName("cn.itcast.reflect.Person"); System.out.println("-----------获取类的全名------------"); //通过Class对象获取类的全名(包含 包名) String fullName = clazz.getName(); System.out.println(fullName); //通过class对象获取类名(不包含包名) String simpleName = clazz.getSimpleName(); System.out.println(simpleName); //通过class对象获取类的修饰符 int modifyName = clazz.getModifiers(); String retval = Modifier.toString(modifyName); System.out.println("Class Modifier = " + retval); |
打印结果:
|
-----------获取类的全名------------ cn.itcast.reflect.Person Person Class Modifier = public |
获取类的全部构造函数,私有的,公有的
API:
|
getConstructors()获取一个类的所有公共的构造方法 getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。 |
代码:
|
//通过Class对象获取对应的构造方法 Constructor[] constructors = clazz.getConstructors(); // getConstructors()获取一个类的所有公共的构造方法 for(Constructor constructor : constructors){ System.out.println(constructor); } System.out.println("\n-------------获取所有的构造方法,包括私有的-------------"); Constructor[] constructors2 = clazz.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。 for(Constructor constructor2 : constructors2){ System.out.println(constructor2); } |
打印的结果:
|
----------获取所有的公共构造方法-------------- public cn.itcast.reflect.Person() public cn.itcast.reflect.Person(int,java.lang.String) -------------获取所有的构造方法,包括私有的------------- private cn.itcast.reflect.Person(int) public cn.itcast.reflect.Person() public cn.itcast.reflect.Person(int,java.lang.String) |
获取指定的构造对象,然后new出一个对象(这个是不能new出private修饰的构造函数)
API:
|
newInstance方法构造对象,默认使用的是无参数的构造方法 举例:Object ins = clazz.newInstance(); getConstructor(参数类型的.class)获取单个指定的构造方法。 举例:clazz.getConstructor(int.class,String.class); 局限地方:不能获取private的构造函数 |
例子:
|
System.out.println("\n获取指定的构造方法,然后new出一个对象"); //newInstance方法构造对象,默认使用的是无参数的构造方法 Object ins = clazz.newInstance(); Person p = (Person) ins; System.out.println(p); //getConstructor 获取单个指定的构造方法。 clazz.getConstructor(int.class,String.class); Constructor constructor = clazz.getConstructor(int.class,String.class); // Person p2 = (Person) constructor.newInstance(999,"小城"); // newInstance()创建一个对象 System.out.println(p2); |
打印结果:
|
获取指定的构造方法,然后new出一个对象 编号:0 姓名:null 编号:999 姓名:小城 |
获取指定的私有构造函数
API:
|
getDeclaredConstructor 方法:获取指定的私有构造函数 |
例子:
|
System.out.println("\n获取指定的私有构造函数"); Constructor constructor1 = clazz.getDeclaredConstructor(int.class); System.out.println(constructor1); |
打印结果:
|
获取指定的私有构造函数 private cn.itcast.reflect.Person(int) |
暴力反射:
|
System.out.println("暴力反射"); Constructor constructor2 = clazz.getDeclaredConstructor(int.class); System.out.println(constructor2); constructor2.setAccessible(true);//设置为true表示可以进行暴力反射,强行用private 构造函数new对象 Person p3 =(Person) constructor2.newInstance(100); System.out.println(p3); |
打印结果:
|
暴力反射 private cn.itcast.reflect.Person(int) 编号:100 姓名:null |
获取构造函数的完整代码:
|
package cn.itcast.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; /* 如何通过Class对象获取构造方法。 */ public class Demo2 { public static void main(String[] args) throws Exception { //获取到对应的Class对象 Class clazz = Class.forName("cn.itcast.reflect.Person"); // System.out.println("-----------获取类的全名------------"); // //通过Class对象获取类的全名(包含 包名) // String fullName = clazz.getName(); // System.out.println(fullName); // // // //通过class对象获取类名(不包含包名) // String simpleName = clazz.getSimpleName(); // System.out.println(simpleName); // // //通过class对象获取类的修饰符 // int modifyName = clazz.getModifiers(); // String retval = Modifier.toString(modifyName); // System.out.println("Class Modifier = " + retval); // System.out.println("----------获取所有的公共构造方法--------------"); // // //通过Class对象获取对应的构造方法 // Constructor[] constructors = clazz.getConstructors(); // getConstructors()获取一个类的所有公共的构造方法 // for(Constructor constructor : constructors){ // System.out.println(constructor); // } // // System.out.println("\n-------------获取所有的构造方法,包括私有的-------------"); // Constructor[] constructors2 = clazz.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。 // for(Constructor constructor2 : constructors2){ // System.out.println(constructor2); // } // System.out.println("\n获取指定的构造方法,然后new出一个对象"); // // //newInstance方法构造对象,默认使用的是无参数的构造方法 // Object ins = clazz.newInstance(); // Person p = (Person) ins; // System.out.println(p); // // //getConstructor 获取单个指定的构造方法。 // clazz.getConstructor(int.class,String.class); // Constructor constructor = clazz.getConstructor(int.class,String.class); // // Person p2 = (Person) constructor.newInstance(999,"小城"); // newInstance()创建一个对象 // System.out.println(p2); // System.out.println("\n获取指定的私有构造函数"); // Constructor constructor1 = clazz.getDeclaredConstructor(int.class); // System.out.println(constructor1); // // System.out.println("暴力反射"); Constructor constructor2 = clazz.getDeclaredConstructor(int.class); System.out.println(constructor2); constructor2.setAccessible(true);//设置为true表示可以进行暴力反射,强行用private 构造函数new对象 Person p3 =(Person) constructor2.newInstance(100); System.out.println(p3); } } |
通过class类获取 字节码中的方法信息
获取全部的方法部分
Api详解:
|
getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。 getDeclaredMethods()//获取到所有的方法(私有的也有),但是不包含父类的方法。 |
例子:
|
//获取到对应的Class对象 Class clazz = Class.forName("cn.itcast.reflect.Person"); //获取到所有公共的方法 Method[] methods = clazz.getMethods(); // getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。 //Method[] methods = clazz.getDeclaredMethods(); //获取到所有的方法(私有的也有),但是不包含父类的方法。 for(Method method : methods){ System.out.println(method); } |
获取指定的方法,并执行它
API:
|
getMethod("eat", int.class);//获取指定的方法,但是不能获取私有的方法 getDeclaredMethod("sleep",int.class);////执行私有的方法 setAccessible(true);//设置访问权限允许访问 invoke(p, 6);//invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。 |
用法:
|
Person p = new Person(110,"狗娃"); //获取指定的方法,但是不能获取私有的方法 Method m = clazz.getMethod("eat", int.class); //invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。 m.invoke(p, 3); //执行私有的方法 Method m2 =clazz.getDeclaredMethod("sleep",int.class); //设置访问权限允许访问 m2.setAccessible(true); //静态的方法第一个参数写null,表示没有对象调用,类本身会调用 m2.invoke(p, 6); |
暴力反射:
|
//暴力反射,获取私有的方法,并执行它 Method m = clazz.getDeclaredMethod("sleep", int.class); System.out.println(m); m.setAccessible(true); m.invoke(p, 8); |
获取方法部分完整代码:
|
package cn.itcast.reflect; import java.lang.reflect.Method; /* 通过Class对象获取到对应的方法。 在反射技术中使用了Method类描述了方法的。 */ public class Demo3 { public static void main(String[] args) throws Exception { //获取到对应的Class对象 Class<?> clazz = Class.forName("cn.itcast.reflect.Person"); // //获取到所有公共的方法 // Method[] methods = clazz.getMethods(); // getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。 //// Method[] methods = clazz.getDeclaredMethods(); //获取到所有的方法(私有的也有),但是不包含父类的方法。 // for(Method method : methods){ // System.out.println(method); // } Person p = new Person(110,"狗娃"); // // //获取指定的方法,但是不能获取私有的方法 // Method m = clazz.getMethod("eat", int.class); // //invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。 // m.invoke(p, 3); // // // //执行私有的方法 // Method m2 =clazz.getDeclaredMethod("sleep",int.class); // //设置访问权限允许访问 // m2.setAccessible(true); // //静态的方法第一个参数写null,表示没有对象调用,类本身会调用 // m2.invoke(p, 6); // Method m = clazz.getMethod("sum", int[].class); // m.invoke(p,new int[]{12,5,9}); //暴力反射,获取私有的方法,并执行它 Method m = clazz.getDeclaredMethod("sleep", int.class); System.out.println(m); m.setAccessible(true); m.invoke(p, 8); } } |
通过class对象获取到字段信息
代码;
|
public static void main(String[] args) throws Exception { //获取到对应的Class对象 Class clazz = Class.forName("cn.itcast.reflect.Person"); //获取 到所有的成员变量(包含私有的) // Field[] fields = clazz.getDeclaredFields(); // for(Field field : fields){ // System.out.println(field); // } Person p = new Person(); Field field = clazz.getDeclaredField("id"); //设置访问权限可以访问 field.setAccessible(true); field.set(p, 110); //第一个参数: 设置该数据 的成员变量, 第二个参数:属性值。 System.out.println(p); } |
反射API总结:
Class类
|
1. getName()类的名称(全名,全限定名) 2 getSimpleName()类的的简单名称(不带包名)
|
|
4.getConstructors()获取一个类的所有公共的构造方法 5.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。 |
|
6.newInstance方法构造对象,默认使用的是无参数的构造方法 举例:Object ins = clazz.newInstance(); 7.getConstructor(参数类型的.class)获取单个指定的构造方法。 举例:clazz.getConstructor(int.class,String.class); 局限地方:不能获取private的构造函数 |
|
8.getDeclaredConstructor 方法:获取指定的私有构造函数 |
|
方法部分 |
|
getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。 getDeclaredMethods()//获取到所有的方法(私有的也有),但是不包含父类的方法。 |
|
getMethod("eat", int.class);//获取指定的方法,但是不能获取私有的方法 |
|
clazz.getDeclaredMethod("sleep",int.class);//执行私有的方法 m2.invoke(p, 6); //表示m2这个方法被p这个对象执行了,后面的参数是m2这个方法需要的参数 |
|
字段部分 1.获取公共字段 Field[] getFields() 2.获取指定参数的公共字段 Field getField(String name) 3.获取所有的字段 Field[] getDeclaredFields() 4.获取指定参数的字段,包括私用 Field getDeclaredField(String name) |
一般用getDeclaredConstructor方法进行获取构造函数,一般不获取private修饰的构造函数
java 反射详解的更多相关文章
- Java基础13:反射详解
本节主要介绍Java反射的原理,使用方法以及相关的技术细节,并且介绍了关于Class类,注解等内容. 具体代码在我的GitHub中可以找到 https://github.com/h2pl/MyTech ...
- Java基础-面向接口编程-JDBC详解
Java基础-面向接口编程-JDBC详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.JDBC概念和数据库驱动程序 JDBC(Java Data Base Connectiv ...
- java基础(3)--详解String
java基础(3)--详解String 其实与八大基本数据类型一样,String也是我们日常中使用非常频繁的对象,但知其然更要知其所以然,现在就去阅读源码深入了解一下String类对象,并解决一些我由 ...
- Linux基础知识之挂载详解(mount,umount及开机自动挂载)
Linux基础知识之挂载详解(mount,umount及开机自动挂载) 转载自:http://www.linuxidc.com/Linux/2016-08/134666.htm 挂载概念简述: 根文件 ...
- 学习Spring必学的Java基础知识(1)----反射(转)
引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩".以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系 ...
- 学习Spring必学的Java基础知识(1)----反射
引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩".以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系 ...
- JAVA基础知识|java虚拟机(JVM)
一.JVM简介 java语言是跨平台的,兼容各种操作系统.实现跨平台的基石就是虚拟机(JVM),虚拟机不是跨平台的,所以不同的操作系统需要安装不同的jdk版本(jre=jvm+类库:jdk=jre+开 ...
- [java基础知识]java安装步骤
jre: java运行环境. jre = java虚拟机 + 核心类库(辅助java虚拟机运行的文件).如果只是运行java程序,只需要安装jre. jdk: java开发工具集 jd ...
- java基础知识——Java的定义,特点和技术平台
(作者声明:对于Java编程语言,很多人只知道怎么用,却对其了解甚少.我也是其中一员.所以菜鸟的我,去查询了教科书以及大神的总结,主要参考了<Java核心技术>这本神作.现在分享给大家!) ...
- 计算机基础知识和tcp详解
计算机基础知识 作为应用软件开发程序员是写应用软件的,而应用软件必须应用在操作系统之上,调用操作系统接口,由操作系统控制硬件 比如客户端软件想要基于网络发送一条消息给服务端软件,流程是: 1.客户端软 ...
随机推荐
- react - 解刨组件的多种写法
一,原始的createClass写法 对于写react组件,很多人第一印象往往是createClass,这是因为createClass是react组件最原始的写法,基本每个学react的人都是接触这种 ...
- NYOJ 128 前缀表达式的计算
前缀式计算 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 先说明一下什么是中缀式: 如2+(3+4)*5这种我们最常见的式子就是中缀式. 而把中缀式按运算顺序加上括 ...
- css小随笔
一.什么是CSS W3C标准中,倡导有3:其一为内容与表现分离,其二为内容与行为分离,其三为内容结构的语义化.其倡导中第一条的"表现"指的便可以说是CSS.CSS全称Cascadi ...
- 14. Longest Common Prefix【leetcode】
14. Longest Common Prefix Write a function to find the longest common prefix string amongst an array ...
- 分享一个markdownpad2的授权key
邮箱地址:Soar360@live.com授权秘钥:GBPduHjWfJU1mZqcPM3BikjYKF6xKhlKIys3i1MU2eJHqWGImDHzWdD6xhMNLGVpbP2M5SN6bn ...
- C#之隐式与显示类型转换
今天在看一篇有关数据类型的文章的时候,无意间看到了两个关键词,"隐式转换"与"显示转换",然后突然想起了当初开始学编程的时候,也总是在代码编译的时候遇到这样的问 ...
- 2017年最重要的HTML5开发手册,传播正能量
今天给大家推荐这个HTML5开发手册,希望能帮助正在学习web前端的人,鄙人也是刚学习前端没多久,借助于一点资讯平台能够结识更多前端大牛,这是我的HTML5进阶学习一点资讯群:250777811,里面 ...
- Android -- AsyncTask源码解析
1,前段时间换工作的时候,关于AsyncTask源码这个点基本上大一点的公司都会问,所以今天就和大家一起来总结总结.本来早就想写这篇文章的,当时写<Android -- 从源码解析Handle+ ...
- 多人开发的git项目如何保持提交日志为一条直线?
多人开发的git项目如何保持提交日志为一条直线? 一.Git的项目的git常用操作 a)Git clone 项目地址 从远程仓库克隆项目到本地 b)Git pull 从当前分支拉取更新代码 c)Git ...
- Mac OS X下安装和配置Maven
1.下载Maven 打开Maven官网下载页面:http://maven.apache.org/download.cgi 下载:apache-maven-3.5.0-bin.tar.gz 解压下载的安 ...