注解和反射是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. Manage your references to .Net assemblies Dynamics 365 for Operations VS projects

    (Dynamics 365 for Operations was previously known as the New Dynamics AX) Dynamics 365 for Operation ...

  2. java 多线程 数据通信

    1.司机等乘客全部上车后再启动车子 import java.util.concurrent.CountDownLatch;public class A { public static void mai ...

  3. vue+iview 表格行选中修改背景色

    <Table :columns="columns" :no-data-text="L('NoDatas')" border :data="lis ...

  4. jquery 选择器 或 且

    jquery选择器具有很强大的功能,基本的使用方法随处可见,jquery还提供了更为方便的使用. 且:$("div[id^='AAA_']div[id$='_DIV']"),此选择 ...

  5. 【Python】pcap抓MySQL网络包

    pcap # -*- coding:utf-8 -*- # yum install libpcap-devel python-devel # pip install pypcap hexdump -i ...

  6. GDB使用详解

    来源:GDB使用详解 - 知乎 (zhihu.com) 1. 概述 ​ GDB 全称"GNU symbolic debugger",从名称上不难看出,它诞生于 GNU 计划(同时诞 ...

  7. 容器之beanfactory抽丝剥茧系列一

    1.总所周知,spring ioc功能实现的顶层接口就是BeanFactory.如下面类结构图 这张更加全面: 还有更加变态的 2.BeanFactory为最顶层接口,定义了最核心的需要实现的接口 p ...

  8. windows2003 的安装以及安装时遇到的问题

    windows2003 的安装以及安装时遇到的问题 简介:Windows Server 2003是微软于2003年3月28日发布的基于Windows XP/NT5.1开发的服务器操作系统,并在同年4月 ...

  9. Android studio的基本使用--基础篇

    一.新建项目 其实跟IDEA新建项目的流程基本一致,File->New->New project,这样就能够新建出来一个项目啦! 一般情况下,我们都会选择Empty Activity,之后 ...

  10. 11.4 显示窗口(harib08d)11.5 小实验(hearib08e) 11.6 高速计数器(harib08f)

    11.4 显示窗口(harib08d) 书P206 11.5 小实验(hearib08e) 书P208 11.6 高速计数器(harib08f) 书P209