前言

近期在学习SSM框架的过程中发现在SSM框架中大量用到了反射与注解的知识,要想学好SSM框架,必须将注解与反射熟记于心,尤其是对Java反射机制的理解。

对于我这种记性不好的人来说“基础不牢,地动山摇”的情况经常发生,所以就用这篇博客记录下关于注解与反射的知识,有出现错误的地方还请大家多多包涵,欢迎大家指出错误!

下面进入正题!!!

1.什么是注解

注解可以被其他程序(比如编译器)读取

2.内置注解

@Override:重写

@Deprecated:废弃

@SuppressWarnings(""):抑制编译时的警告信息(需要添加参数)

3.元注解

负责注解其他注解

@Target:被描述的注解可以用在什么地方

@Retention:表示需要在什么级别保存改注释信息,用于描述注解的生命周期(SOURCE<CLASS<RUNTIME)什么时候有效

@Documented:说明该注解将被包含在javadoc中

@Inherited:说明子类可以继承父类中的该注解

4.自定义注解

使用@interface自定义注解

//自定义注解
public class Test03 {
//注解可以显示的赋值,如果没有默认值,我们就必须该注解赋值
@MyAnnotation2(age = 18)
public void test(){}
@MyAnnotation3("ikun")
public void Test2(){} } @Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
//这不是方法,是注解的参数
String name() default "";
int age() default 0;//默认值是-1代表不存在
String[] schools() default {"清华","北大"};
} @Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
//这不是方法,是注解的参数
String value(); }

5.反射概述

  • 动态语言:就是在运行时代码可以根据某些条件改变自身结构(c#,JavaScript,php,python)

  • 静态语言:运行时结构不可变(Java,C,C++)

在java中我们可以利用反射机制获得类似动态语言的特性

  • Java Reflection



6.获得反射对象

  • 反射相关的主要API

    java.lang.Class:代表-个类

    java.lang.reftect.Method:代表类的方法

    java.lang.reflect.Field:代表类的成员变量

    java.lang.reflect.Constructor:代表类的构造器

    ...

7.得到class类的几种方式(重点)

Class类

对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。

对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特

定某个结构(class/.interface/.enum/annotation/primitive type/.void/们)的有关信息。

  • Class本身也是一个类
  • Class对象只能由系统建立对象
  • 一个加载的类在JVM中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个.class文件
  • 每个类的实例都会记得自己是由哪个Class实例所生成
  • 通过Classi可以完整地得到一个类中的所有被加载的结构
  • Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象
 //方式一:通过对象获得
Class c1 = person.getClass();
System.out.println(c1.hashCode()); //方式二:forName获得(常用)
Class c2 = Class.forName("com.qjd.reflection.Student");
System.out.println(c2.hashCode()); //方式三:通过类名.class
Class c3 = Student.class;
System.out.println(c3.hashCode()); //方式四:基本内置类型的包装类都有一个Type属性
Class c4 = Integer.TYPE;
System.out.println(c4);

8.所有类型的class对象

哪些类型可以有Class对象

  • class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。
  • interface:接口
  • []:数组
  • enum:枚举
  • annotation:注解@interface
  • primitive type:基本数据类型
  • void

9.类加载内存分析

当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化

public class Test05 {
public static void main(String[] args) {
A a = new A();
System.out.println(A.m);
/**
* 1.加载到内存,会产生一个类对应Class对象
* 2.链接,链接结束后,m=0
* 3.初始化
* <clinit>{ System.out.println("A类静态代码块初始化");
* m=300;
* m=100;
* }
*
* m=100
*
*
*/ } }
class A{ static{
System.out.println("A类静态代码块初始化");
m=300;
}
/*
* m=300
* m=100
* */
static int m = 100;
public A(){
System.out.println("A类的无参构造初始化"); } }

内存图分析

10.分析类初始化

注:常量不会引发初始化

11.类加载器

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); //获取扩展类加载器的父类加载器---》根加载器(c/c++)
ClassLoader parent1 = parent.getParent();
System.out.println(parent1); //测试当前类是哪个加载器加载的(系统)
ClassLoader classLoader = Class.forName("com.qjd.reflection.Test07").getClassLoader();
System.out.println(classLoader); //测试jdk内置的类是哪个加载器加载的(根)
classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader); //如何获得系统类加载器可以加载的路径
System.out.println(System.getProperty("java.class.path"));
//D:\Program Files (x86)\java\jdk1.8\jre\lib\charsets.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\deploy.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\access-bridge-64.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\cldrdata.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\dnsns.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\jaccess.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\jfxrt.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\localedata.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\nashorn.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\sunec.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\sunjce_provider.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\sunmscapi.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\sunpkcs11.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\zipfs.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\javaws.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\jce.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\jfr.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\jfxswt.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\jsse.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\management-agent.jar;D
// :\Program Files (x86)\java\jdk1.8\jre\lib\plugin.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\resources.jar;
// D:\Program Files (x86)\java\jdk1.8\jre\lib\rt.jar;
// E:\SSM\反射和注解\reflect\target\classes;
// E:\Java\IntelliJ IDEA 2020.3.4\lib\idea_rt.jar //双亲委派机制
//(如果存在重名)检测跟加载器的包而不是自己写的
}
}

12.创建运行时类的对象(重点)

//获得类的信息
public class Test08 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("com.qjd.reflection.User"); //获得类的名字
System.out.println(c1.getName());//包名加类名
System.out.println(c1.getSimpleName());//类名 //获得类的属性
System.out.println("===========================================================");
Field[] fields = c1.getFields();//只能找到public属性 fields = c1.getDeclaredFields();//找到全部的属性
for (Field field : fields) {
System.out.println(field);
} //获得指定属性的值
Field name = c1.getDeclaredField("name");
System.out.println(name); //获得类的方法
System.out.println("===========================================================");
Method[] methods = c1.getMethods();//获得本类及其父类全部的public方法
for (Method method : methods) {
System.out.println("正常的"+method);
} Method[] declaredMethods = c1.getDeclaredMethods();//获得本类的所有方法包括private方法
for (Method declaredMethod : declaredMethods) {
System.out.println("declaredMethods"+declaredMethod); } //获得指定方法
//重载
System.out.println("===========================================================");
Method getName = c1.getMethod("getName", null);
Method setName = c1.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName); //获得构造器
System.out.println("===========================================================");
Constructor[] constructors = c1.getConstructors();//获得public方法
for (Constructor constructor : constructors) {
System.out.println(constructor);
} Constructor[] declaredConstructors = c1.getDeclaredConstructors();//获得全部方法
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
} //获得指定的构造器
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
System.out.println("指定的"+declaredConstructor); }
}

13.动态创建对象执行方法(重点)

代码实现

//动态创建对象,通过反射
public class Test09 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获得Class对象
Class c1 = Class.forName("com.qjd.reflection.User");
//构造一个对象
//User user = (User) c1.newInstance();//本质上是调用类的无参构造器
//System.out.println(user); //通过构造器创建对象
// Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
// User user2 = (User) constructor.newInstance("ikun",001,18);
// System.out.println(user2); //通过反射调用普通方法
User user3 = (User) c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getMethod("setName", String.class);
//invoke激活
//(对象,“方法的值”)
setName.invoke(user3,"kunkun");
System.out.println(user3.getName()); //通过反射操作属性
System.out.println("===========================================");
User user4 = (User) c1.newInstance();
Field name = c1.getDeclaredField("name"); //不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的setAccessible(true);
name.setAccessible(true);
name.set(user4,"坤坤");
System.out.println(user4.getName()); } }

14.性能对比分析

//分析性能问题
public class Test10 {
//普通方式调用
public static void test01(){
User user = new User(); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis(); System.out.println("普通方式执行1000000000次:"+(endTime-startTime)+"ms");
} //反射方式调用
public static void test02() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
User user = new User();
Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName", null); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis(); System.out.println("反射方式执行1000000000次:"+(endTime-startTime)+"ms");
} //反射方式调用 关闭检测 public static void test03() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
User user = new User();
Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName", null); getName.setAccessible(true); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis(); System.out.println("关闭检测执行1000000000次:"+(endTime-startTime)+"ms");
} public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
test01();
test02();
test03();
} }

结果

15.获取泛型信息

反射操作泛型

  • Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除

  • 为了通过反射操作这些类型,Java新增ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型

  • ParameterizedType:表示一种参数化类型,比如Collection

  • GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型

  • ypeVariable:是各种类型变量的公共父接口

  • WildcardType:代表一种通配符类型表达式

16.反射操作注解

ORM

//练习反射操作注解
public class Test12 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.qjd.reflection.Student2"); //通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获得注解的value的值
TableQjd tableQjd = (TableQjd)c1.getAnnotation(TableQjd.class);
String value = tableQjd.value();
System.out.println(value); //获得类指定的注解
System.out.println("===================");
Field field = c1.getDeclaredField("name");
FieldQjd annotation = field.getAnnotation(FieldQjd.class);
System.out.println(annotation.columnName());
System.out.println(annotation.type());
System.out.println(annotation.length()); } } @TableQjd("db_student")
class Student2{
@FieldQjd(columnName = "db_id",type = "int",length = 10)
private int id;
@FieldQjd(columnName = "db_age",type = "int",length = 10)
private int age;
@FieldQjd(columnName = "db_name",type = "varchar",length = 3)
private String name; public Student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
} public Student2() {
} @Override
public String toString() {
return "Student2{" +
"id=" + id +
", age=" + age +
", 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;
}
} //类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableQjd{
String value();
} //属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldQjd{
String columnName();
String type();
int length();
}

注:本文参考与B站up主遇见狂神说的讲解视频进行编写,如有遗漏和错误,欢迎大家提出

大家觉得文章还可以的话可以点个推荐支持博主,我会不定期更新博客的,你们的肯定就是我创作的最大动力!!!

Java---注解与反射的更多相关文章

  1. Java注解与反射

    概要 本文主要是总结Java注解与反射的相关知识,加深自己对Java类动态语言的理解,同时为日后学习Spring打下基础. 注解: 什么是注解 Annotation的作用 不是程序本身,但是可以对程序 ...

  2. 小白都能学会的Java注解与反射机制

    前言 Java注解和反射是很基础的Java知识了,为何还要讲它呢?因为我在面试应聘者的过程中,发现不少面试者很少使用过注解和反射,甚至有人只能说出@Override这一个注解.我建议大家还是尽量能在开 ...

  3. Java注解和反射笔记

    Java注解和反射笔记 1 注解 1.1 定义 Annotation是从JDK1.5开始引入的技术 作用 不是程序本身,可以对程序作出解释 可以被其他程序(编译器等)读取 格式 @注释名,可以添加一些 ...

  4. Java注解和反射

    1.注解(Annotation) 1.1.什么是注解(Annotation) 注解不是程序本身,可以在程序编译.类加载和运行时被读取,并执行相应的处理.注解的格式为"@注释名(参数值)&qu ...

  5. java注解实例-反射生成sql

    定义描述用户表的注解: package dao; import java.lang.annotation.ElementType; import java.lang.annotation.Retent ...

  6. JAVA 注解和反射

    通过反射来获取类 Class MyTest{ private String name; public String showName{ System.out.println(this.name); } ...

  7. java注解和反射学习

    spring框架很多地方都应用了注解,如@controller,所以要学会自定义注解及注解处理器. Class<?> cl=Class.froName(className) //通过类名加 ...

  8. java自定义注解与反射

    java注解与反射一.Java中提供了四种元注解,专门负责注解其他的注解,分别如下 1.@Retention元注解,表示需要在什么级别保存该注释信息(生命周期).可选的RetentionPoicy参数 ...

  9. Java基于注解和反射导入导出Excel

    代码地址如下:http://www.demodashi.com/demo/11995.html 1. 构建项目 使用Spring Boot快速构建一个Web工程,并导入与操作Excel相关的POI包以 ...

  10. Java注解Annotation与自定义注解详解

    Java注解简介 开发中经常使用到注解,在项目中也偶尔会见到过自定义注解,今天就来探讨一下这个注解是什么鬼,以及注解的应用场景和如何自定义注解. 下面列举开发中常见的注解 @Override:用于标识 ...

随机推荐

  1. 2022年5月11日,NBMiner发布了41.3版本,在内核中加入了100%LHR解锁器,从此NVIDIA的显卡再无锁卡一说

           2022年5月11日,NBMiner发布NBMiner_41.3版本,主要提升了稳定性.         2022年5月8日,NBMiner发布NBMiner_41.0版本,在最新的内核 ...

  2. vs code 终端字体间距过大(全角的样子)

    文件-首选项-设置 将 terminal.integrated.fontFamily 配置为 Consolas, 'Courier New', monospace 或其他想要的字体,或者点击齿轮按钮重 ...

  3. k8s系列--node(k8s节点介绍,新增节点,移除节点)

    一.简介 Node是Pod真正运行的主机,可以是物理机也可以是虚拟机. Node本质上不是Kubernetes来创建的, Kubernetes只是管理Node上的资源. 为了管理Pod,每个Node节 ...

  4. ElasticSearch7.3学习(二十六)----搜索(Search)参数总结、结果跳跃(bouncing results)问题解析

    1.preference 首先引入一个bouncing results问题,两个document排序,field值相同:不同的shard上,可能排序不同:每次请求轮询打到不同的replica shar ...

  5. 使用虚拟机在3台centos7系统安装docker和k8s集群

    一.安装docker 环境:准备3台centos7系统,都安装上docker环境,具体安装步骤和流程如下 参考: https://docs.docker.com/install/linux/docke ...

  6. ABP框架之——数据访问基础架构

    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享阅读心得,希望我的文章能成为你成长路上的一块垫脚石,我们一起精进. 几乎所有的业务应用程序都要适用一种数据库基础架构,用来实现数据访问逻辑,以便从数 ...

  7. 【可视化分析案例】用python分析B站Top100排行榜数据

    一.数据源 之前,我分享过一期爬虫,用python爬取Top100排行榜: 最终数据结果,是这样的: 在此数据基础上,做python可视化分析. 二.数据读取 首先,读取数据源: # 读取csv数据 ...

  8. SmartIDE v0.1.18 已经发布 - 助力阿里国产IDE OpenSumi 插件安装提速10倍、Dapr和Jupyter支持、CLI k8s支持

    SmartIDE v0.1.18 (cli build 3538) 已经发布,在过去的Sprint 18中,我们集中精力推进对 k8s 远程工作区 的支持,同时继续扩展SmartIDE对不同技术栈的支 ...

  9. 内网 Ubuntu 20.04 搭建 docusaurus 项目(或前端项目)的环境(mobaxterm、tigervnc、nfs、node)

    内网 Ubuntu 20.04 搭建 docusaurus 项目(或前端项目)的环境 背景 内网开发机是 win7,只能安装 node 14 以下,而 spug 的文档项目采用的是 Facebook ...

  10. 某CMS后台通杀getshell

    此CMS是基于thinkphp框架二次开发的,目前有thinkphp5,以及thinkphp6两种版本.这些漏洞挖掘出来的时候已经在cnvd被提交过了.但是网上并没有漏洞文章.避免风险这里只分享思路. ...