注解和反射是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镜子之反射篇的更多相关文章

  1. Java学习之反射篇

    Java学习之反射篇 0x00 前言 今天简单来记录一下,反射与注解的一些东西,反射这个机制对于后面的java反序列化漏洞研究和代码审计也是比较重要. 0x01 反射机制概述 Java反射是Java非 ...

  2. Java反射篇学习笔记

    今天重新学习了java中的反射,写一篇学习笔记总结一下.代码基本都是照着两篇博客敲的: 参考一:   https://blog.csdn.net/sinat_38259539/article/deta ...

  3. Java高级特性——反射机制(第二篇)

    在Java高级特性——反射机制(第一篇)中,写了很多反射的实例,可能对于Class的了解还是有点迷糊,那么我们试着从内存角度去分析一下. Java内存 从上图可以看出,Java将内存分为堆.栈.方法区 ...

  4. Java高级特性——反射机制(第三篇)

    获取类运行时的结构 通过反射获取运行时类的完整结构 Field.Method.Constructor.Superclass.Interface.Annotation >实现的全部接口 >所 ...

  5. java中的反射(三)

    目录 一.反射 1.class类 2.访问字段 3.调用方法 4.调用构造方法 5.获取继承对象 6.动态代理 二.sping中的反射 本篇转自:https://depp.wang/2020/05/0 ...

  6. 浅说Java中的反射机制(二)

    写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下: 引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧.(()为我手记) 什么是反射? 正常编 ...

  7. 浅说Java中的反射机制(一)

    在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...

  8. java基础(十一 )-----反射——Java高级开发必须懂的

    本文我们通过一个实际的例子来演示反射在编程中的应用,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水.相信通过这篇教程,会让你对反射有一个更深层次的认知. 概念 ...

  9. 第89节:Java中的反射技术

    第89节:Java中的反射技术 反射技术是动态的获取指定的类,和动态的调用类中的内容(没有类前就可以创建对象,将对象的动作完成,这就是动态的获取指定的类). 配置文件把具体实现的类名称定义到配置文件中 ...

  10. Java 学习笔记提高篇

    Java笔记(提高篇)整理   主要内容: 面向对象 异常 数组 常用类 集合 IO流 线程 反射 Socket编程 1.  面向对象 1.1包 用来管理Java中的类, 类似文件夹管理文件一样. 因 ...

随机推荐

  1. .net 生成Excel并保存

    void SaveQuestionToExcel(List<Question> datas, string path) { using (Workbook workbook = new H ...

  2. FIR滤波器的设计

    FIR数字滤波器的设计 线性相位FIR滤波器的特点 单位冲激响应:\(h(n),0\leq n\leq N-1\) 系统函数:\(H(z)=\sum_{n=0}^{N-1}h(n)z^{-n}\) 零 ...

  3. 纯js实现字符串formate方法

    function format(pattern){ if(! (pattern instanceof String)){ throw new TypeError("错误的参数类型" ...

  4. NX二次开发读属性/表达式封装函数

    int Read_ATTR_Type(int ObjTag, char* Attr_Title); //读取属性返回属性类型 string Read_ATTR_StringValue(int ObjT ...

  5. ACM 的正确入门方式是什么?

    作者:数学lover 链接:https://www.zhihu.com/question/51727516/answer/127265733 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权, ...

  6. scala apply方法和update方法

    示例代码1 class TestApplyClass { def apply(param: String): String = { println("apply method called, ...

  7. Rethinking Table Recognition using Graph Neural Networks

    摘要:CNN用来视觉特征提取:图网络用来处理结构问题:由于缺少大量的数据,作者建立了一个合成数据集的数据库. 关键词:表格识别,结果分析:图神经网络,文档模型:图模型:数据库 源码地址;https:/ ...

  8. Linux 里面安装多个jdk,进行切换

    alternatives --config java

  9. 钉钉获取第三方token时提示签名时间戳参数超时的处理方法

    今天在更新平台功能时,碰到一个问题,从钉钉跳转到平台,始终不能成功.查看日志发现,出现了 签名时间戳参数超时 的错误. 想着没有动过相对应的代码,应该不是代码的问题. 查询官方文档,没有给出明确的答复 ...

  10. idea 调试小心得

    1.为什么需要Debug 目的:开发过程中 查找或定位错误或者阅读源码 程序运行的结果(4种情况) 情况1:没有任何bug,程序执行正确! 情况2: 运行以后,出现了错误或异常信息.但是通过 日志文件 ...