【Java语言特性学习之二】反射
一、概念
java加载class文件分两种情况:
(1)类型是编译器已知的,这种文件的.class文件在编译的时候,编译器会把.class文件打开(不加载)检查,称为Run- Time Type Identification 运行时类型识别
(2)从其它地方获取引用,然后动态的把这个未知类型的引用的对象的.class文件加载进jvm虚拟机里,称为反射;
在运行状态中,动态获取类信息(属性、方法)及动态调用类对象方法的功能称为java的反射机制。
二、反射API
Java反射包:java.lang.reflect.*
1、获取类
首先获取类,获取到类之后,Class类提供了很多获取类属性,方法,构造方法的api
(1)obj.getClass(),这个是Object类里面的方法;
(2)User.Class属性,任何的数据类型,基本数据类型或者抽象数据类型,都可以通过这种方式获取类;
(3)Class.forName(""),Class类提供了这样一个方法,让我们通过类名来获取到对象类,使用最多;
package reflect;
import reflect.test.model.User;
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
//1.通过Object类里面的方法getClass()
User u = new User();
Class c = u.getClass();
System.out.println(c);//class reflect.test.model.User
//2通过.Class属性
Class c2 = User.class;
System.out.println(c2);//class reflect.test.model.User
//3.Class.forName("全路径名")
Class c3 = Class.forName("reflect.test.model.User");
System.out.println(c3);//class reflect.test.model.User
}
}
2、获取属性和方法
package reflect.test.model;
public class User {
private String name;
private int age;
public User() {}
public User(String name,int age) {
this.name = name;
this.age = age;
}
public int a = 100;
private String str = "123456789";
public boolean dosomething(Integer a,Float b) {
System.out.println("dosomething");
return true;
}
}
package reflect; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier; public class Main2 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException { /************************获取所有的属性************************/
Class<?> c = Class.forName("reflect.test.model.User");
//getDeclaredFields 获取所有的属性
Field[] fs = c.getDeclaredFields(); // 定义可变长的字符串,用来存储属性
StringBuffer sb = new StringBuffer();
// 通过追加的方法,将每个属性拼接到此字符串中
// 最外边的public定义
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() + "{\n");
// 里边的每一个属性
for (Field field : fs) {
sb.append("\t");// 空格
sb.append(Modifier.toString(field.getModifiers()) + " ");// 获得属性的修饰符,例如public,static等等
sb.append(field.getType().getSimpleName() + " ");// 属性的类型的名字
sb.append(field.getName() + ";\n");// 属性的名字+回车
} sb.append("}"); System.out.println(sb); /***************************获取指定属性***********************/ //获取id属性
Field idF = null;
try {
idF = c.getDeclaredField("age");
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
//实例化这个类赋给o
Object o = null;
try {
o = c.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
//打破封装
idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。
//给o对象的id属性赋值"110"
try {
//set
idF.set(o,110);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
//get
try {
System.out.println(idF.get(o));
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
} /***************************获取方法****************************/ //getDeclaredMethods() 获取所有的方法(不包含构造方法)
Method[] declaredMethods = c.getDeclaredMethods();
for (Method m:declaredMethods) {
System.out.println(m);
//getReturnType() 获得方法的放回类型
System.out.println(m.getReturnType());
//getParameterTypes() 获得方法的传入参数类型
Class<?>[] parameterTypes = m.getParameterTypes();
for(Class cc : parameterTypes) {
System.out.println(cc);
}
} //getDeclaredMethod("方法名",参数类型.class,……) 获得特定的方法
Method declaredMethod = c.getDeclaredMethod("dosomething", Integer.class,Float.class);
System.out.println(declaredMethod);
Method method = c.getMethod("dosomething", Integer.class,Float.class);
System.out.println(method);
//getDeclaredConstructors() 获取所有的构造方法
Constructor<?>[] declaredConstructors = c.getDeclaredConstructors();
for(Constructor ccc : declaredConstructors) {
System.out.println(ccc);
}
//getDeclaredConstructor(参数类型.class,……) 获取特定的构造方法
Constructor<?> declaredConstructor = c.getDeclaredConstructor(String.class,int.class);
System.out.println(declaredConstructor);
//getSuperclass() 获取某类的父类
Class<?> superclass = c.getSuperclass();
System.out.println(superclass);
//getInterfaces() 获取某类实现的接口
Class<?>[] interfaces = c.getInterfaces();
for(Class cccc: interfaces) {
System.out.println(cccc);
} } }
结果:
public class User{
private String name;
private int age;
public int a;
private String str;
}
110
public boolean reflect.test.model.User.dosomething(java.lang.Integer,java.lang.Float)
boolean
class java.lang.Integer
class java.lang.Float
public boolean reflect.test.model.User.dosomething(java.lang.Integer,java.lang.Float)
public boolean reflect.test.model.User.dosomething(java.lang.Integer,java.lang.Float)
public reflect.test.model.User()
public reflect.test.model.User(java.lang.String,int)
public reflect.test.model.User(java.lang.String,int)
class java.lang.Object
三、反射应用--动态代理
package reflect.test.intf;
public interface Interface {
public void dosomething() ;
}
package reflect.test.intf.impl;
import reflect.test.intf.Interface;
public class InterfaceImpl implements Interface {
@Override
public void dosomething() {
System.out.println("dosomething");
}
}
1、静态代理
package reflect; import reflect.test.intf.Interface;
import reflect.test.intf.impl.InterfaceImpl; /**
* 静态代理
*/
public class HandProxy implements Interface{ Interface inter = new InterfaceImpl(); @Override
public void dosomething() {
System.out.println("静态代理类");
inter.dosomething();
} }
package reflect;
public class TestHandProxy {
public static void main(String[] args) {
HandProxy p = new HandProxy();
p.dosomething();
}
}
结果:
静态代理类
dosomething
2、动态代理
package reflect; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; /**
* 动态代理
*/
public class AutoProxy implements InvocationHandler{
private Object target; public Object bind(Object target) {
this.target = target;
/**
* 第一个是被代理类的类构造器,
* 第二个指的是被代理类的接口,也就是Interface接口,
* 第三个是实现这个代理的类,这里就是本类。
* 这个方法执行了下面三步:
1.生成一个实现了参数interfaces里所有接口且继承了Proxy的代理类的字节码,然后用参数里的classLoader加载这个代理类。
2.使用代理类父类的构造函数 Proxy(InvocationHandler h)来创造一个代理类的实例,将我们自定义的InvocationHandler的子类传入。
3.返回这个代理类实例,因为我们构造的代理类实现了interfaces(也就是我们程序中传入的target.getClass().getInterfaces())里的所有接口,因此返回的代理类可以强转成Interface类型来调用接口中定义的方法。
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("动态代理");
result = method.invoke(target, args);
System.out.println("动态代理执行结束");
return result;
} }
package reflect; import reflect.test.intf.Interface;
import reflect.test.intf.impl.InterfaceImpl; public class TestAutoProxy { public static void main(String[] args) {
Interface inter = new InterfaceImpl();
AutoProxy ap = new AutoProxy();
Interface obj = (Interface)ap.bind(inter);
obj.dosomething();
} }
结果:
动态代理
dosomething
动态代理执行结束
【Java语言特性学习之二】反射的更多相关文章
- 【Java语言特性学习之一】设计模式
设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...
- 【Java语言特性学习之六】扩展知识点
一.SPI机制 二.注解处理机制 三.java native关键字 https://www.cnblogs.com/KingIceMou/p/7239668.html
- 【Java语言特性学习之三】Java4种对象引用
为了更灵活的控制对象的生命周期,在JDK1.2之后,引用被划分为(引用的级别和强度由高到低)强引用.软引用.弱引用.虚引用四种类型,每种类型有不同的生命周期,它们不同的地方就在于垃圾回收器对待它们会使 ...
- 【Java语言特性学习之四】常用集合
java中常见的数据结构
- 【Java语言特性学习之五】版本差异新特性
- java之jvm学习笔记二(类装载器的体系结构)
java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...
- java语言特性概述
一.前言 我们都知道java是面向对象的编程,其中四个基本特性:抽象.封装.继承.多态.这四个特性,概括起来可以这么理解,抽象.封装.继承是多态的基础,多态是抽象.封装.继承的表现. 二. JAVA ...
- [原]Java修炼 之 基础篇(一)Java语言特性
学习软件开发,首先要选择的就是选择需要采用的编程语言,考虑语言本身的优缺点和实际需求,综合评价之后选择相关的语言进行系统开发.本篇博客开始就从近年来比较流行的Java开始为大家讲起. 背景 1995年 ...
- Java 语言特性
介绍以下几种语言特性: Java5的特性 1.静态引用 2.可变参数 3.自动装箱和拆箱 包装类的缓存设计 4.枚举 一.静态引用(语法糖,不推荐使用,了解一下即可) 先看看普通的引用,就是impo ...
随机推荐
- video调用直播接口:防止缓存方案
有时候我们需要调用解析过直播接口,使用video播放,但是在暂停又开始后,直播视频不会自动刷新,而是继续从暂停之前的时间点开始播放. 下面是我的解决方案代码,弟弟们请看我的下面: <!DOCTY ...
- 《细说PHP》第四版 样章 第18章 数据库抽象层PDO 1
现在,如果你已经能熟练地使用MySQL客户端软件来操作数据库中的数据,就可以开始学习如何使用PHP来显示和修改数据库中的数据了.PHP提供了标准的函数来操作数据库.在PHP 5以上的版本中可以使用My ...
- js移动端自适应动态设置html的fontsize
JS设计移动端页面时会遇到自适应问题,大多数都知道用rem来设置页面的比例大小,下面就来说几种常见的html中的fontsize设置方法: 1.使用flexible.js插件库. 淘宝就是利用这个来 ...
- HTTP 响应的分块传输
Transfer-Encoding 响应头用于告诉客户端服务器发送内容的编码格式. 其可选值有: chunked:数据分块发送.此时应缺省 Content-Length 响应头. compress:使 ...
- 基础查询-SQL和Linq相互化
目录 SELECT SQL SELECT DISTINCT 语句 WHERE 和 操作符 BETWEEN 和操作符 LIKE 和通配符 ORDER BY 排序 TOP In Alias(as) EXI ...
- python基础(15):内置函数(一)
1. 内置函数 什么是内置函数? 就是python给你提供的,拿来直接⽤的函数,比如print,input等等,截⽌到python版本3.6.2 python⼀共提供了68个内置函数.他们就是pyth ...
- VMWare虚拟机应用介绍
目录 一:VMWare简介 二:VMWare启动第一个虚拟机 一:VMWare简介 VMWare虚拟机软件是一个"虚拟PC"软件,它使你可以在一台机器上同时运行二个或更多Win ...
- react-native聊天室|RN版聊天App仿微信实例|RN仿微信界面
一.前言 9月,又到开学的季节.为每个一直默默努力的自己点赞!最近都沉浸在react native原生app开发中,之前也有使用vue/react/angular等技术开发过聊天室项目,另外还使用RN ...
- 2019年上半年收集到的人工智能GAN干货文章
2019年上半年收集到的人工智能GAN干货文章 GAN简介及其常见应用 训练GAN,你应该知道的二三事 了解生成对抗网络(GAN) CosmoGAN:训练GAN,让AI寻找宇宙中的暗物质 关于GAN的 ...
- 【Gradle】Gradle构建脚本基础
Gradle构建脚本基础 Settings文件 在Gradle中,定义了一个设置文件,用于初始化以及工程树的配置.设置文件的默认名为settings.gradle,放在根工程目录下. 设置文件大多数的 ...