java镜子之反射篇
注解和反射是Java中非常重要的知识,一些优秀开源的框架都是大量运用了反射+注解这,比如Spring,MyBatis,反射可以帮助大家去阅读这些框架的源码实现。
注解
Annotation主要是位于java.lang.annotation包下,
Annotation
不是程序本身,对程序做出解释
可以被其他程序读取
格式
可以再package,class,method, field
还可以在代码中存在,可以添加一些参数值
内置注解
常见的内置注解有许多,比如下面的三个
@Override 重写的注解,当子类重写父类的方法时,我们会加上这个注解
@Deprecated 这个注解主要是用来提示程序员当前方法可能存在危险,尽量不要使用
@SuppressWarnings 用于镇压警告信息
元注解
负责注解其他注解,这样大家可能觉得元注解并不是很好懂,但是如果给大家一些源码来看的话,大家应该都见过
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target 用于描述注解的使用范围(ElementType)
@Retention 表示需要在什么级别保存该注释信息,用于描述生命周期(Type, Method)
@Ducumented 该注解将被包含在javadoc中
@Inherited 说明子类可以继承父类中的该注解
自定义注解
使用@interface自定义注解,我们可以定义一个供自己使用的注解,在注解的的定义中,如果注解只有一个参数的哈,并且这个参数为value的话,我们可以不用写value=…吧啦吧啦,直接参数就可以,default为默认值
- 如果有填参数,就一定要填或者设置默认值。
/**
* 定义一个注解
* @author 大勇
* @Target 表示我们的注解可以应用在哪些地方
* @Retention 表示我们的注解在什么地方还有效
* runtime> class> sources
* @Documented 表示是否将我们的注解生成Javadoc中
* @Inherited 子类可以继承父类的注解
*/
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIpublicME)
public @interface MyAnnotation02 {
/**
* 注解的参数
*/
String name() default "";
int age() default 0;
int id() default -1;
String[] schools() default {"北京大学", "清华大学"};
}
反射
反射,我们先来看一下反射的定义:
反射(Reflection)就是在运行状态中,对于任何一个类都可以知道这个类的所有属性和方法和调用任意一对象的任意方法和属性,并且能改变它的属性。
- 这也是Java可以成为准静态语言的关键所在。
java.lang.reflect
正常方式:通过new实例化 --> 获取实例化对象
反射方式:实例化对象 --> method: getClass --> 得到类的信息
反射的机制作用
判断任意一个对象所属的类
构造一个类的对象
判断一个类所具有的成员变量和方法
调用一个对象的成员变量和方法
处理注解
生成动态代理
Class类中有getClass(),通过反射后可以获取到这个类的属性、方法和构造器、某个类实现了什么接口。
Class的一些方法
forName(String name); 返回指定类名name的Class对象
newInstance() 调用缺省构造函数,返回Class对象的一个实例
getName() 返回该Class对象所表示的实体的名称
getSuperClass() 返回当前Class对象的父类的Class对象
getInterfaces() 返回当前Class对象的接口
getClassLoader() 返回当前Class对象的类加载器
getConstructors() 返回一个包含某些Constructor对象的数组
getMethod(String name, Class... T) 返回一个Method对象,对象的形参为ParamType
getDeclaredFields() 返回Field对象的
获取Class对象(一个Class只有一个Class对象)
public class Test03 {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("这个人是:" + person.name);
// 一、获取对象实例
Class<? extends Person> c1 = person.getClass();
// 二、forName
Class<?> c2 = Class.forName("reflection.Student");
// 三、类名
Class c3 = Student.class;
// 四、基本内置类型的包装类都有一个Type属性
Class<Integer> c4 = Integer.TYPE;
// 五、获取父类类型
Class<?> c5 = c1.getSuperclass();
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
System.out.println(c4);
System.out.println(c5);
}
}
类的初始化
一定发生类初始化
初始化main方法所在的类
new一个类的对象
调用类的静态成员(除了final)和静态方法
使用java.lang.reflect包的方法对类进行反射调用
初始化一个类,如果其没有被初始化,则先会初始化它的父类
不会发生类的初始化
当访问一个静态域时,只有真在声明这个域的类才会被初始化。(子类引用父类的静态变量,不会导致子类初始化)
通过数组定义类,不会触发此类的初始化
引用常量不会触发此类的初始化
public class test05 {
public static void main(String[] args) {
A a = new A();
System.out.println(A.m);
}
}
class A {
static {
System.out.println("A类静态代码块");
m = 300;
}
static int m = 100;
public A() {
System.out.println("A类的无参构造初始化");
}
}
**但是这里并不能说明静态代码块大于静态成员变量的初始化顺序,因为其实应该是平级的,如果静态成员变量放在静态代码块上面就会发现这个值是300。
**
类加载器
获取类的信息
setAccessible方法可以关闭安全检查,关闭后可以提升反射的速度
Exception in thread "main" java.lang.IllegalAccessException: Class reflection.test09 can not access a member of class reflection.User with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
查看类加载器
public class test07 {
public static void main(String[] args) throws ClassNotFoundException {
// 获取系统类的加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
// 获取系统类的父类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
// 获取扩展类加载器的父类加载器--》根加载器
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);
// 查看当前类是哪个加载器加载的
ClassLoader classLoader = Class.forName("reflection.test07").getClassLoader();
System.out.println(classLoader);
// 获取系统加载器可以加载的路径
System.out.println(System.getProperty("java.class.path"));
// 双亲委派机制
// Java.lang.String
/**
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\charsets.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\ext\access-bridge-64.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\ext\cldrdata.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\ext\dnsns.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\ext\jaccess.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\ext\jfxrt.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\ext\localedata.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\ext\nashorn.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\ext\sunec.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\ext\sunjce_provider.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\ext\sunmscapi.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\ext\sunpkcs11.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\ext\zipfs.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\jce.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\jfr.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\jfxswt.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\jsse.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\management-agent.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\resources.jar;
* C:\Users\dy\.jdks\corretto-1.8.0_322\jre\lib\rt.jar;
* D:\code\exam\out\production\exam;
* D:\IntelliJ IDEA 2021.2.2\lib\idea_rt.jar
*/
}
}
Bootstrap classLoader:主要负责加载核心的类库(java.lang.*等),构造ExtClassLoader和APPClassLoader。
ExtClassLoader:主要负责加载jre/lib/ext目录下的一些扩展的jar。
AppClassLoader:主要负责加载应用程序的主函数类
双亲委派机制
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 查看当前这个类有没有被加载过
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
// 查找父加载器,交给父加载器
if (parent != null) {
c = parent.loadClass(name, false);
} else {
// 找到Bootstrap类加载器
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
当需要加载一个class时,先从AppClassLoader中查看是否加载过,如果没有加不需加载了,如果没有,就会拿到父加载器。父类中也会同样检查自己是否加载过,直到Bootstrap classLoader之前,如果加载过,都不会自己去加载。
反射方法的使用
获取类的成员变量、方法、构造器等方法
public class test08 {
public static void main(String[] args) throws Exception {
Class<?> c1 = Class.forName("reflection.User");
// 获取类的名称
// 包名 + 类名
System.out.println(c1.getName());
// 获取类名
System.out.println(c1.getSimpleName());
// 获取类的属性
// 获取public
Field[] publicField = c1.getFields();
// 获取所有的属性
Field[] fields = c1.getDeclaredFields();
for (Field field: fields) {
System.out.println(field);
}
// 获取指定属性的值
Field name = c1.getDeclaredField("name");
System.out.println(name);
// 获取类的方法
System.out.println("============");
// 获取本类的所有方法和父类的public
Method[] methods = c1.getMethods();
for (Method method: methods) {
System.out.println(method);
}
System.out.println("============");
Method[] declaredMethods = c1.getDeclaredMethods();
for (Method method: declaredMethods) {
System.out.println(method);
}
System.out.println("============");
// 获取指定方法
Method getName = c1.getMethod("getName", null);
System.out.println(getName);
System.out.println("============");
// 获取指定的构造器
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor: constructors) {
System.out.println(constructor);
}
System.out.println("============");
constructors = c1.getDeclaredConstructors();
for (Constructor constructor: constructors) {
System.out.println(constructor);
}
}
}
调用类的方法、成员变量、构造器等
public class test09 {
public static void main(String[] args) throws Exception {
Class<?> c1 = Class.forName("reflection.User");
// 构造一个对象 调用一个无参构造器 必须有一个无参数的构造器
User user = (User) c1.newInstance();
System.out.println(user);
// 通过构造器创建对象
Constructor<?> constructor = c1.getDeclaredConstructor(String.class, Long.class, Integer.class);
User user1 = (User)constructor.newInstance("大勇", 1L, 18);
System.out.println(user1);
//
User user3 = (User) c1.newInstance();
Method setName = c1.getDeclaredMethod("setName", String.class);
// invoke: 激活的意思
// 对象,方法的值
setName.invoke(user3, "大勇");
System.out.println(user3);
System.out.println("9999999999999999999999");
// 通过反射操作属性
User user4 = (User) c1.newInstance();
Field name = c1.getDeclaredField("name");
// 取消安全检查, 不能直接操作私有属性, 关闭属性或者方法
name.setAccessible(true);
name.set(user4, "大勇");
System.out.println(user4);
}
}
四种泛型
ParameterizedType: 表示一种参数化类型,比如Collection
GenericArrayType: 表示一种元素类型是参数化类型或者类型变量的数组类型
TypeVariable: 是各种类型变量的公共父接口
WildcardType: 代表一种通配符类型表达式
public class Test11 extends Object{
public void test01(Map<String, User> map, List<User>list) {
System.out.println("test01");
}
public Map<String, User> test02() {
System.out.println("test02");
return null;
}
public static void main(String[] args) throws Exception{
Method method = Test11.class.getMethod("test01", Map.class, List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println("#" + genericParameterType);
if (genericParameterType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
System.out.println("====================");
method = Test11.class.getMethod("test02", null);
Type genericReturnType = method.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}
实现的ORM小demo
public class Test12 {
public static void main(String[] args) throws Exception{
Class<?> c1 = Class.forName("reflection.Student2");
Annotation[] annotations = c1.getAnnotations();
// 反射获取注解
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
// 获取注解的值
Table annotation = c1.getAnnotation(Table.class);
System.out.println(annotation.value());
// 获取类指定的注解
Field name = c1.getDeclaredField("name");
FieldToColumn fieldToColumn = name.getAnnotation(FieldToColumn.class);
System.out.println(fieldToColumn.columnName());
System.out.println(fieldToColumn.type());
}
}
@Table("student")
class Student2 {
@FieldToColumn(columnName = "id", type = "int")
private int id;
@FieldToColumn(columnName = "age", type = "int")
private int age;
@FieldToColumn(columnName = "name", type = "varchar")
private String name;
public Student2() {
}
public Student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* @author 大勇
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table {
String value();
}
/**
* @author 大勇
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldToColumn {
String columnName();
String type();
}();
}
总结
本文介绍了一些关于反射的知识,可能讲的不是很深,更加偏于使用方面,希望可以帮助大家对反射有更加深入的了解…
t age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
- @author 大勇
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table {
String value();
}
/**
@author 大勇
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldToColumn {
String columnName();String type();
}();
}
## 总结
> 本文介绍了一些关于反射的知识,可能讲的不是很深,更加偏于使用方面,希望可以帮助大家对反射有更加深入的了解......
java镜子之反射篇的更多相关文章
- Java学习之反射篇
Java学习之反射篇 0x00 前言 今天简单来记录一下,反射与注解的一些东西,反射这个机制对于后面的java反序列化漏洞研究和代码审计也是比较重要. 0x01 反射机制概述 Java反射是Java非 ...
- Java反射篇学习笔记
今天重新学习了java中的反射,写一篇学习笔记总结一下.代码基本都是照着两篇博客敲的: 参考一: https://blog.csdn.net/sinat_38259539/article/deta ...
- Java高级特性——反射机制(第二篇)
在Java高级特性——反射机制(第一篇)中,写了很多反射的实例,可能对于Class的了解还是有点迷糊,那么我们试着从内存角度去分析一下. Java内存 从上图可以看出,Java将内存分为堆.栈.方法区 ...
- Java高级特性——反射机制(第三篇)
获取类运行时的结构 通过反射获取运行时类的完整结构 Field.Method.Constructor.Superclass.Interface.Annotation >实现的全部接口 >所 ...
- java中的反射(三)
目录 一.反射 1.class类 2.访问字段 3.调用方法 4.调用构造方法 5.获取继承对象 6.动态代理 二.sping中的反射 本篇转自:https://depp.wang/2020/05/0 ...
- 浅说Java中的反射机制(二)
写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下: 引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧.(()为我手记) 什么是反射? 正常编 ...
- 浅说Java中的反射机制(一)
在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...
- java基础(十一 )-----反射——Java高级开发必须懂的
本文我们通过一个实际的例子来演示反射在编程中的应用,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水.相信通过这篇教程,会让你对反射有一个更深层次的认知. 概念 ...
- 第89节:Java中的反射技术
第89节:Java中的反射技术 反射技术是动态的获取指定的类,和动态的调用类中的内容(没有类前就可以创建对象,将对象的动作完成,这就是动态的获取指定的类). 配置文件把具体实现的类名称定义到配置文件中 ...
- Java 学习笔记提高篇
Java笔记(提高篇)整理 主要内容: 面向对象 异常 数组 常用类 集合 IO流 线程 反射 Socket编程 1. 面向对象 1.1包 用来管理Java中的类, 类似文件夹管理文件一样. 因 ...
随机推荐
- 用反证法说明List<Object>和List<String>不存在子父类关系可行吗?
看宋红康老师的Java基础视频讲解,视频中用反证法证明List
- hhtp协议和html标签分类css
HTTP协议四大特性: 1基于请求响应 2 基于tcp/ip协议之上的应用层协议 3 无状态 不能保存用户信息 4 无链接,短链接 二 get和post的区别? 1 get 不安全,get请求没有请求 ...
- C语言中字符数组的赋值和复制
/*C中,字符串,即字符数组的赋值与字符变量.常量.变量的赋值是不同的.初学者总会犯错误. 常见错误如下: 1.定义的时候直接用字符串赋值 char a[10]; char a[10]="h ...
- 博弈论练习6 Deleting Divisors(sg找规律,思维)
题目链接在这里:G-Deleting Divisors_牛客竞赛博弈专题班组合游戏基本概念.对抗搜索.Bash游戏.Nim游戏习题 (nowcoder.com) 这道题一道比较明显的思路是使用sg函数 ...
- python-实现栈结构
# encoding=utf-8 class Stack(object): """栈""" def __init__(self): &quo ...
- 实验4_开源控制器实践——OpenDaylight
基础要求 需要提交两张图, 一是Mininet拓扑生成并连接控制器的结果 二是Mininet中ping测试截图,并体现个人信息 进阶要求 1.获取拓扑的交换机 2.获取流表状态数量 3.获取指定交换机 ...
- Grafana Dashboard
Grafana Dashboard jvm micrometer (4701) jmx_export (8563) https://grafana.com/grafana/dashboards/856 ...
- Condition 接口
系统性学习,移步IT-BLOG Java 对象拥有一组监视方法:wait().wait(long timeout).notify() 以及 notifyAll() 方法,这些方法与 synchroni ...
- [C++STL教程]2.queue队列容器,小白都能看懂的讲解!
在学习数据结构的时候我们会听到这样一个词:队列. 本文将介绍STL中的队列:queue 本文仅从入门和实用角度介绍queue的用法,主要针对初学者或竞赛向.如有不严谨的地方欢迎指正!本文长度约2000 ...
- OpenTranslator:一款基于ChatGPT API的翻译神器
这是一款使用 ChatGPT API 进行划词翻译和文本润色的浏览器插件.借助了 ChatGPT 强大的翻译能力,它将帮助您更流畅地阅读外语和编辑外语. 它能干啥 一. 可翻译 二. 可润色 三. 可 ...