文档章节

java --反射

求是科技
 求是科技
发布于 2016/10/05 11:04
字数 2279
阅读 38
收藏 4
点赞 0
评论 1

反射是动态语言的关键。
反射机制提供的功能
1.在运行时判断一个对象所属的类
2.在运行时构造任意一个类的对象
3.在运行时判断一个类的成员变量与方法
4.在运行时调用一个对象的成员变量与方法
5.生成动态代理
#1.反射简单应用

	public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
		/**常规方法:创建一个类的对象,并调用其中的方法**/
		Person p1 = new Person();
		p1.setName("张三");
		p1.setAge(30);
		System.out.println(p1);
		p1.dothing();
		
		/***反射实现**/
		Class<?> clazz = Person.class;
		//1.创建clazz对应的运行时类Person的对象
		Person p2 = (Person) clazz.newInstance();
		//此时p2对象的属性都是默认值
		System.out.println(p2);
		//2.获取p2对象的属性(共有权限)
		Field f1 = clazz.getField("name");
		//3.给属性赋值
		f1.set(p2, "李四");
		//此时p2对象的name有值了
		System.out.println(p2);
		//4.获取p2对象的属性(私有权限)
		Field f2 = clazz.getDeclaredField("age");
		//设置权限
		f2.setAccessible(true);
		f2.set(p2, 31);
		//此时p2对象的name与age均有值了
		System.out.println(p2);
		//5.获取p2对象的方法(无参方法)
		Method m1 = clazz.getMethod("dothing");
		//调用方法
		m1.invoke(p2);
		//6.获取p2对象的方法(有参方法)
		Method m2 = clazz.getMethod("dothing2", String.class);
		//调用方法
		m2.invoke(p2, "王五");
	}

Person类如下

public class Person {
	public String name;
	private int age;
	//无参方法
	public void dothing(){
		System.out.println("我是中国人");
	}
	//有参方法
	public void dothing2(String name){
		System.out.println("我是:"+name);
	}
}

#2.详讲Class

	/**
	 * java.lang.Class:是反射的源头
	 * 有三种方法获取Class类的实例
	 * @throws ClassNotFoundException 
	 */
	public static void main(String[] args) throws ClassNotFoundException {
		//方法1:调用运行时类本身的.class属性
		Class clazz1 = Person.class;
		System.out.println(clazz1.getName());
		//举例(jdk自带的类也行)
		Class clazz2 = String.class;
		System.out.println(clazz2.getName());
		
		//方法2:通过运行时类的对象获取
		Person p1 = new Person();
		Class clazz3 = p1.getClass();
		System.out.println(clazz3.getName());
		
		//方法3:通过Class的静态方法获取
		String className = "com.test.reflect.Person";
		Class<?> clazz4 = Class.forName(className);
		System.out.println(clazz4.getName());
	}

#3.ClassLoader
类加载器是用来把类(class)装载进内存的。
jvm定义了两种类型的类加载器:启动类加载器(bootstrap)和用户自定义类加载器。jvm在运行时会产生三个类加载器,引导类加载器(bootstrap)、扩展类加载器(extension)、系统类加载器(system)。

	@Test
	public void test() throws ClassNotFoundException, IOException{
		//获取系统类加载器
		ClassLoader loader1 = ClassLoader.getSystemClassLoader();
		//sun.misc.Launcher$AppClassLoader@73d16e93
		System.out.println(loader1);
		
		//获取系统类加载器的父级
		ClassLoader loader2 = loader1.getParent();
		//sun.misc.Launcher$ExtClassLoader@15db9742
		System.out.println(loader2);
		
		//查看Person类是由哪个加载器加载
		Class<?> clazz1 = Person.class;
		ClassLoader loader4 = clazz1.getClassLoader();
		//sun.misc.Launcher$AppClassLoader@73d16e93
		System.out.println(loader4);
		
		//查看系统类是由哪个类加载器加载
		String className = "java.lang.Object";
		Class<?> clazz2 = Class.forName(className);
		ClassLoader loader5 = clazz2.getClassLoader();
		//打印null,因为Object是属于系统类,应该由系统类加载器加载,在初始化加载一次
		System.out.println(loader5);
		
		//获取属性文件的值
		//方法1:属性文件在工程的某个包下
		//ClassLoader loaderWay1 = this.getClass().getClassLoader();
		//InputStream is = loaderWay1.getResourceAsStream("com\\test\\reflect\\db1.properties");
		
		//方法2:属性文件存放在src目录下
		//FileInputStream is = new FileInputStream(new File("src\\db2.properties"));
		
		//方法3:属性文件存放在工程路径下
		FileInputStream is = new FileInputStream(new File("db3.properties"));
		//公共部分
		Properties pros = new Properties();
		pros.load(is);
		String name = pros.getProperty("user_name");
		String password = pros.getProperty("user_password");
		System.out.println(name+":"+password);
	}

属性文件所在位置图
输入图片说明
#4.反射的实际应用
##1.创建运行时类的对象
调用Class类的newInstance()方法,可以创建类的对象。

	public void test() throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException{
		String name = "com.test.reflect.Person";
		Class<?> clazz = Class.forName(name);
		//1.创建运行时类的对象,newInstance调用了Person的无参构造器
		Object obj = clazz.newInstance();
		Person p = (Person) obj;
		System.out.println(p);
	}

##2.获取类的属性、方法

	/**
	 * 获取对应的运行时类的属性
	 */
	@Test
	public void test(){
		Class<?> clazz = Person.class;
		//1.getFields:可以获取本类及父类中申明为public的属性
		Field[] f = clazz.getFields();
		for(Field fTmp:f){
			System.out.println(fTmp.getName());
		}
		//2.getDeclaredFields:可以获取本类中所有的属性
		Field[] f2 = clazz.getDeclaredFields();
		for(Field fTmp2:f2){
			System.out.println(fTmp2.getName());
		}
		
	}

Person类

/**
 * 单继承,多实现
 */
public class Person extends Nature implements MyInterface,Serializable{
	
	private static final long serialVersionUID = 1L;
	public String name;
	private int age;
	int id;
}

Nature类

public class Nature {
	public double weight;
	//方法
	public void breath(){
		System.out.println("呼吸");
	}
}

MyInterface接口

public interface MyInterface {

	public void show();
}

##3.获取权限修饰符/变量类型/变量名

	@Test
	public void test(){
		Class<?> clazz = Person.class;
		Field[] f = clazz.getDeclaredFields();
		for(Field fTmp:f){
			//1.获取属性权限修饰符
			int i = fTmp.getModifiers();
			//将整型转成实际的权限
			String cc = Modifier.toString(i);
			System.out.print(cc+" ");
			//2.获取属性的变量类型
			Class type = fTmp.getType();
			System.out.print(type.getName()+" ");
			//3.获取属性名
			System.out.print(fTmp.getName());
			//换行
			System.out.println();
		}
	}

##4.获取运行时类的方法

	@Test
	public void test(){
		Class<?> clazz = Person.class;
		//1.getMethods:获取运行时类及其父类中所有的public方法
		Method[] methods = clazz.getMethods();
		for(Method m:methods){
			System.out.println(m);
		}
		//2.getDeclaredMethods:获取运行时类本身所申明的方法
		Method[] methods2 = clazz.getDeclaredMethods();
		for(Method m2:methods2){
			System.out.println(m2.getName());
		}
	}

##5.获取运行时类的方法权限修饰符/返回值类型/方法名

	@Test
	public void test(){
		Class<?> clazz = Person.class;
		Method[] methods2 = clazz.getDeclaredMethods();
		for(Method m2:methods2){
			//1.获取权限修饰符
			String str = Modifier.toString(m2.getModifiers());
			System.out.print(str);
			//2.返回值类型
			Class returnType = m2.getReturnType();
			System.out.print(returnType.getName());
			//3.方法名
			System.out.print(m2.getName());
		}
	}

##6.获取运行时类的构造器

	@Test
	public void test() throws ClassNotFoundException{
		String className = "com.test.reflect.Person";
		Class clazz = Class.forName(className);
		//获取Person类的所有的构造器
		Constructor[] cons = clazz.getDeclaredConstructors();
		for(Constructor c:cons){
			System.out.println(c.getName());
		}
	}

##7.获取运行时类的父类/带泛型的父类

	@Test
	public void test() throws ClassNotFoundException{
		String className = "com.test.reflect.Person";
		Class clazz = Class.forName(className);
		Class superClass = clazz.getSuperclass();
		System.out.println(superClass);
	}

##8.获取运行时类的接口

	@Test
	public void test() throws ClassNotFoundException{
		String className = "com.test.reflect.Person";
		Class clazz = Class.forName(className);
		Class[] interfaces = clazz.getInterfaces();
		for(Class i:interfaces){
			System.out.println(i);
		}
	}

##9.获取运行时类的包

	@Test
	public void test() throws ClassNotFoundException{
		String className = "com.test.reflect.Person";
		Class clazz = Class.forName(className);
		Package pack = clazz.getPackage();
		System.out.println(pack);
	}

#5.通过反射调用类中指定方法/指定属性

	/**
	 * 调用运行时类中指定的属性
	 * @throws SecurityException 
	 * @throws NoSuchFieldException 
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 */
	@Test
	public void test() throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException{
		String className = "com.test.reflect.Person";
		Class clazz = Class.forName(className);
		/***获取运行时类对象***/
		//1.创建运行时类的对象
		Person p = (Person) clazz.newInstance();
		System.out.println(p);
		/***获取指定属性***/
		//2.获取指定的属性(公有属性)
		Field name = clazz.getField("name");
		//2.1给指定属性赋值(公有属性)
		name.set(p, "张三");
		//3.获取指定属性(私有属性)
		Field age = clazz.getDeclaredField("age");
		//3.1修改私有属性的可访问权限
		age.setAccessible(true);
		//3.2给指定属性赋值(私有属性)
		age.set(p, 30);
		System.out.println(p);
		/***获取指定方法***/
		Method m1 = clazz.getMethod("show");
		//调用指定方法
		Object obj = m1.invoke(p);
		//如果obj==null,则说明该方法返回void
		System.out.println(obj);
		
		//调用静态方法
		Method m2 = clazz.getMethod("testStatic");
		Object obj2 = m2.invoke(Person.class);
		System.out.println(obj2);
	}

#6.反射应用之动态代理
动态代理是指用户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态地创建目标类的代理对象。 动态代理使用场合:调试、远程方法调用
代理设计模式原理
1.使用一个代理将对象包装起来
2.使用该代理对象取代原始对象
3.任何对原始对象的调用都要经过代理对象
4.代理对象决定是否/何时将方法的调用转到原始对象上
##6.1静态代理

/**
 * 静态代理模式
 */
public class TestDelegate {
	public static void main(String[] args) {
		//被代理类
		NikeClothFactory ncf = new NikeClothFactory();
		//代理类
		ProxyFactory proxy = new ProxyFactory(ncf);
		//调用方法
		proxy.productCloth();
	}
}

接口

//接口
interface ClothProduct{
	void productCloth();
}

被代理类

//被代理类
class NikeClothFactory implements ClothProduct{

	@Override
	public void productCloth() {
		System.out.println("nike工厂生产衣服");
	}
}

代理类

//代理类
class ProxyFactory implements ClothProduct{

	//创建接口
	ClothProduct cp;
	//构造器
	//创建代理类的对象,实际传入的是一个被代理的对象
	//该构造器的功能:完成被代理类的初始化
	public ProxyFactory(ClothProduct cp) {
		this.cp = cp;
	}
	@Override
	public void productCloth() {
		System.out.println("代理类执行");
		cp.productCloth();
	}
}

##6.2动态代理

/**
 * 动态代理模式
 */
public class TestProxyDelegate {
	public static void main(String[] args) {
		//1.被代理类对象
		RealSubject rsj = new RealSubject();
		//2.代理类对象
		MyInvocationHandler mih = new MyInvocationHandler();
		//3.传入被代理类,动态返回一个代理对象
		Object obj = mih.blind(rsj);
		//4.强转,此时的sb就是代理类的对象
		Subject sb = (Subject) obj;
		//5.执行被代理类方法,此时会转成去执行代理类的invoke方法
		sb.action();
		
		//再举一例
		NikeClothFactory nike = new NikeClothFactory();
		Object obj2 = mih.blind(nike);
		ClothProduct cp = (ClothProduct) obj2;
		cp.productCloth();
		
	}
}

接口

//接口
interface Subject{
	void action();
}

被代理类

//被代理类
class RealSubject implements Subject{

	@Override
	public void action() {
		System.out.println("我是被代理类");
	}
}

动态代理类

//动态代理类
class MyInvocationHandler implements InvocationHandler{
	//定义一个类,表示实现了接口的类(即被代理类)
	Object obj;
	
	//实例化被代理的类
	//返回一个代理类的对象
	//方法名随便命名
	public Object blind(Object obj){
		//1.实例化被代理的类
		this.obj = obj;
		//2.返回一个代理类
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
	}
	/**
	 * 代理类的对象调用被代理类的方法时,会转换为对如下invoke方法的调用
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//1.获取被代理类执行的方法名称
		String methodName = method.getName();
		System.out.println("被代理类执行的方法名称:"+methodName);
		//2.获取被代理类执行的方法的参数
		if (args != null) {
			for(Object arg:args){
				System.out.println(arg);
			}
		}
		//3.被代理类执行方法返回值
		Object returnVal = method.invoke(obj, args);
		System.out.println(returnVal);
		return returnVal;
	}
}

© 著作权归作者所有

共有 人打赏支持
求是科技
粉丝 89
博文 453
码字总数 228281
作品 0
成都
后端工程师
加载中

评论(1)

业余编程人士
业余编程人士
请问一下 反射提取Field的时候 可以判断哪些是 int, double, final 或者 static类型吗?
Java基础之反射(非常重要)

反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一、反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道...

Java-老刘 ⋅ 05/15 ⋅ 0

Java反射改变Android属性

Java反射改变Android属性 在某些情况下,Android体系里面的某些对象没有对外提供针对某个属性或者类,方法公开的get或者set方法,但是项目需要对这些需要修改和调整。就需要使用Java的反射机...

zhangphil ⋅ 04/28 ⋅ 0

有一到五年开发经验的JAVA程序员需要掌握的知识与技能!

JAVA是一种平台,也是一种程序设计语言,如何学好程序设计不仅仅适用于JAVA,对C++等其他程序设计语言也一样管用。有编程高手认为,JAVA也好C也好没什么分别,拿来就用。为什么他们能达到如此...

java高级架构牛人 ⋅ 06/02 ⋅ 0

作为一个java程序员这些技能你都知道吗?

一、Java特点 1、 面向对象 尽管受到其前辈的影响,但Java没被设计成兼容其他语言源代码的程序。这允许Java开发组自由地从零开始。这样做的一个结果是,Java语言可以更直接、更易用、更实际的...

java高级架构牛人 ⋅ 05/23 ⋅ 0

Java反序列化漏洞的原理分析

  *本文原创作者:Moonlightos,本文属FreeBuf原创奖励计划,未经许可禁止转载   世界上有三件事最难:      把别人的钱装进自己的口袋里   把自己的想法装进别人的脑袋里   让自...

FreeBuf ⋅ 05/04 ⋅ 0

Java进阶知识点8:高可扩展架构的利器 - 动态模块加载核心技术(ClassLoader、反射、依

Java进阶知识点8:高可扩展架构的利器 - 动态模块加载核心技术(ClassLoader、反射、依 博客园ZHYongu2018-05-312 阅读 反射java架构ClassLoader动态扩展模...

博客园_ZHY_ongu ⋅ 05/31 ⋅ 0

升级到JDK9的一个BUG,你了解吗

概述 前几天在一个群里看到一个朋友发了一个demo,说是JDK的bug,昨天在JVM的一个群里又有朋友发了,觉得挺有意思,分享给大家,希望大家升级JDK的版本的时候注意下是否存在这样的代码,如果...

你假笨 ⋅ 06/06 ⋅ 0

基于ClassLoader的java代码加密的经验分享

原理就是 生成项目时将待加密的java class文件通过加密算法转换生成加密的二进制文件,此文件不会被JD-GUI等反编译工具直接解密。 项目在启动时,用自定义的ClassLoader将加密的二进制文件进...

hxt168 ⋅ 06/06 ⋅ 0

Jenkins 教程(一)实现自动化打包及邮件通知

个人不喜欢装腔作势一堆专业术语放上去,让大多数人看不懂来提升逼格(所谓的专家),所以我简单的介绍jenkins是干啥的。本文使用jenkins,就是让它把git仓库里的东西取出来,然后在jenkins容器...

FantJ ⋅ 05/26 ⋅ 0

Java反射实践:从反射中理解class

写在前面 今天在需求评审的时候,遇到了挺有意思的要求。需求是什么样子就不说了。总之完成这个需求需要一个调用系统api的操作。然而这个api因为并不稳定的原因。被谷歌hide掉了。 这个时候我...

MDove ⋅ 04/11 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

linux 安装docker

通过以下命令下载安装docker wget -qO- https://get.docker.com | sh 执行以上命令后输出以下内容说明安装成功,注意红框中的内容,docker安装成功后默认只有root能使用,红框中给出的提示是...

haoyuehong ⋅ 24分钟前 ⋅ 0

482. License Key Formatting - LeetCode

Question 482. License Key Formatting Solution 思路:字符串转化为char数组,从后遍历,如果是大写字母就转化为小写字母,如果是-就忽略,如果遍历了k个字符(排除-)就追加一个-。 Java实现...

yysue ⋅ 42分钟前 ⋅ 0

聊聊spring cloud gateway的LoadBalancerClientFilter

序 本文主要研究一下spring cloud gateway的LoadBalancerClientFilter GatewayLoadBalancerClientAutoConfiguration spring-cloud-gateway-core-2.0.0.RELEASE-sources.jar!/org/springfram......

go4it ⋅ 今天 ⋅ 0

详解:Nginx反代实现Kibana登录认证功能

Kibana 5.5 版后,已不支持认证功能,也就是说,直接打开页面就能管理,想想都不安全,不过官方提供了 X-Pack 认证,但有时间限制。毕竟X-Pack是商业版。 下面我将操作如何使用Nginx反向代理...

问题终结者 ⋅ 今天 ⋅ 0

002、nginx配置虚拟主机

一、nginx配置虚拟主机可分为三种方式,分别为: 1、基于域名的虚拟主机,通过域名来区分虚拟主机——应用:外部网站 2、基于端口的虚拟主机,通过端口来区分虚拟主机——应用:公司内部网站...

北岩 ⋅ 今天 ⋅ 0

shell脚本之死循环写法

最近在学习写shell脚本,在练习if while等流程控制时,突然它们的死循环写法是怎么样的?经过百度与亲测记录如下: for死循环 #! /bin/bashfor ((;;));do date sleep 1d...

hensemlee ⋅ 今天 ⋅ 0

苹果的ARKit2.0有多可怕,看了就知道

序言 ARKit主要由三部分组成: 跟踪(Tracking) 跟踪是ARKit的核心组件之一,其提供了设备在物理世界中的位置与方向信息,并对物体进行跟踪,如人脸。 2.场景理解(Scene Understanding) 场...

_小迷糊 ⋅ 今天 ⋅ 0

5.1 vim介绍 5.2 vim移动光标 5.3 ,5.4vim一般模式下移动光标,复制粘贴

vim命令 vim是vi的一个升级版;vim可以显示文字的颜色 安装vim这一个包vim-enhanced 如果不知道安装包,可以使用 命令下面命令来查看vim命令是那个包安装的。 [root@linux-128 ~]# yum prov...

Linux_老吴 ⋅ 今天 ⋅ 0

vim一般模式

vim 是什么 vim是什么 ? 在之前接触Linux,编辑网卡配置文件的时候我们用过了vi ,vim简单说就是vi的升级版,它跟vi一样是Linux系统中的一个文本编辑工具。 如果系统中没有vim ,需要安装一...

李超小牛子 ⋅ 今天 ⋅ 0

docker实战

构建企业级Docker虚拟化平台实战 重点剖析虚拟化和云计算概念; 分析Docker虚拟化的概念和原理; 从0开始实战Docker虚拟化平台; 基于Docker构建Nginx WEB服务器和CentOS虚拟机; 基于开源监...

寰宇01 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部