功能:Java注解的介绍和反射使用
功能:Java注解的介绍和反射使用
一、注解
1、注解介绍
java注解(Annotation),又称为java标注,是jdk5.0引入的一种机制。
Java 语言中的类、方法、变量、参数和包等都可以被标注,对这些代码段进行解释,编译时生成class时,标注也可以被编译。在运行时,java可以通过反射获取到注解内容,进行一些骚操作,进而简化开发。
2、注解分类
Java 定义了一些注解,有些比较常见
@Override:检查方法是否重写父类方法@Deprecated:标记方法过时@SuppressWarnings:忽略警告元注解,标注注解的注解,一切注解的开始
@Retention:使用范围,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问@Documented:标记这些注解是否包含在用户文档中@Target:作用范围,可以标记哪些代码块,方法,类或者是字段等其他@Inherited:标记这个注解是继承于哪个注解类java7后加入的注解
@SafeVarargs:Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告@FunctionalInterface:Java 8 开始支持,标识一个匿名函数或函数式接口@Repeatable:Java 8 开始支持,标识某注解可以在同一个声明上使用多次
3、自定义注解
1)定义语法
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "";
String[] params() default {};
}
如上:
@Documented:此注解将包含在用户文档中@Target: ElementType.Type是说,该注解可以在类、接口(包含注解)、枚举上使用@Retention:此注解将编译至class文件中,在运行时,会被虚拟机读取使用- 和定义接口不同的是,注解的定义前添加
@号- 如果是字段名是value,则使用注解时可以省略字段名
2)RetentionPolicy,作用范围枚举
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, // Annotation信息仅存在于编译器处理期间,编译后该注解不存在
CLASS, // 编译器将Annotation存储于类对应的class文件中
RUNTIME // 编译器将Annotation存储于class文件中,并且可由JVM读入
}
3)ElementType,使用范围枚举
package java.lang.annotation;
public enum ElementType {
// 类,接口(包括注解),枚举
TYPE,
// 字段,包括枚举字段
FIELD,
// 方法
METHOD,
// 方法参数,括号内的形参
PARAMETER,
// 构造方法
CONSTRUCTOR,
// 局部变量
LOCAL_VARIABLE,
// 注解
ANNOTATION_TYPE,
// 包
PACKAGE,
// Type parameter declaration,@since 1.8
TYPE_PARAMETER,
// Use of a type,@since 1.8
TYPE_USE
}
二、java反射
1、反射介绍
1)反射是什么
简单的来说,反射就是运行时才知道操作的类是什么,并且在运行阶段有虚拟机进行实例化,可知道内部所有的(包括private私有的)属性和方法,这种机制叫做反射
java之所以有了这种机制,才会成为一门准动态语言
动态语言和静态语言的区别
- 动态语言:是指一类在运行时,也可以改变程序结构的语言,加入新的函数,对象,甚至是代码都可以被引入,可以根据某些条件改变自身结构
- 主要语言有:C#、JavaScript、PHP、Python
- 静态语言:相对于动态语言,在运行时结构不可改变的语言就是静态语言
- 主要语言有:Java、C、C++
在java有了反射之后,java就可以称为准动态语言,反射使得java有了一定的动态性,我们可以通过这种机制,让编程更加灵活,玩出骚操作。
2)简单明白反射作用
在程序开发之初,程序员往往都知道自己需要使用到某些类,这样实例化对象是没问题的,程序也是可以正常访问的,如下
程序员知道要把东西给学生,所以new Student()进行实例化
public class SomeThingTest {
public static void main(String[] args) {
Student student = new Student();
student.give("一个红包");
}
}
abstract class Person {
public abstract void give(String some);
}
class Student extends Person{
@Override
public void give(String some) {
System.out.println("给了学生:" + some);
}
}
class Teacher extends Person{
@Override
public void give(String some) {
System.out.println("给了老师:" + some);
}
}
那程序员不知道要把东西交给谁呢?程序进行不下去了,所以为了解决此类问题,反射机制诞生了,如下
运行结果相差不大,但内部实现机制完全不一致
public class SomeThingTest {
public static void main(String[] args) throws Exception {
Class cls = Class.forName("com.banmoon.something.Teacher");
Method giveMethod = cls.getMethod("give", String.class);
Object teacher = cls.newInstance();
giveMethod.invoke(teacher, "一个苹果");
}
}
问题:
com.banmoon.something.Teacher,这段字符串还不是程序员写死的,就算内部是反射实现的,那这样岂不是多此一举?非也非也,我给大家看一段常用的配置文件,大家就明白了
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test
username: root
password: 1234
熟悉吗,那个数据库连接驱动和数据库连接池,那些开发框架的程序员,他们可不知道我们使用的是什么数据库和什么连接池,所以在我们指定对应的驱动路径后,java虚拟机才反射去获取对应的驱动实例。
这样一来,可以说反射机制是框架设计的灵魂,若没有反射,也没有如此丰富全面的java框架,庞大的java生态系统
2、反射使用
1)反射获取Class对象
在java中,万物皆对象。所以类在反射出来后产生的对象便是Class
获取反射的3种方式,其中2、3种方法的使用是在编码阶段都清楚类的前提下使用的
- 使用Class对象的静态方法,forName(),根据类的全路径进行加载
- 通过类名.class获取该类的Class对象
- 使用实例对象.getClass()获取该类的Class对象
public class SomeThingTest {
public static void main(String[] args) throws ClassNotFoundException {
Class cla1 = Class.forName("java.lang.String");
Class cla2 = String.class;
Class cla3 = "abc".getClass();
}
}
问题:以下
cla3和cla4是否为同个对象?public class SomeThingTest {
public static void main(String[] args) throws ClassNotFoundException {
Class cla3 = "abc".getClass();
Class cla4 = new String("123").getClass();
System.out.println(cla3.hashCode());
System.out.println(cla4.hashCode());
}
}
哪些类型可以有Class对象
- class:普通类,内部类,静态内部类,局部内部类,匿名内部类
- interface:接口
- []:数组
- enum:枚举
- annotation:注解
- 基本数据类型:int等
- void
2)反射获取类的属性和方法
2.1)写几个类
abstract class Person implements Serializable {
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public abstract void give(String some);
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Student extends Person{
@Override
public void give(String some) {
System.out.println("给了学生:" + some);
}
public static void staticMothed(){
System.out.println("静态方法");
}
}
class Teacher extends Person{
public String subject;
public String getPost() {
return post;
}
public void setPost(String post) {
this.post = post;
}
private String post;
public Teacher() {
}
private Teacher(String name, String subject, String post) {
super(name);
this.subject = subject;
this.post = post;
}
@Override
public void give(String some) {
System.out.println("给了老师:" + some);
}
public void teach(String content){
System.out.println("教学方法一");
}
private void teach(String content, Person person){
System.out.println("教学方法二");
}
}
2.2)反射使用
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class SomeThingTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
// 获取Teacher类的class对象
Class teacherClass = Teacher.class;
// 获取Teacher类的名字
System.out.println(teacherClass.getName());
System.out.println(teacherClass.getSimpleName());
System.out.println("============= 分割线 ==============");
// 获取Teacher类的属性,只能获取到public权限的
Field[] fieldArr = teacherClass.getFields();
for (Field field : fieldArr) {
System.out.println(field);
}
System.out.println("============= 分割线 ==============");
// 获取Teacher类的属性,可以获取所有权限的属性
fieldArr = teacherClass.getDeclaredFields();
for (Field field : fieldArr) {
System.out.println(field);
}
System.out.println("============= 分割线 ==============");
// 获取Teacher类的方法,只能获取到public权限的,且可以获取到继承父类的方法
Method[] methodArr = teacherClass.getMethods();
for (Method method : methodArr) {
System.out.println(method);
}
System.out.println("============= 分割线 ==============");
// 获取Teacher类的方法,可以获取所有权限的方法,获取不到继承父类的方法
methodArr = teacherClass.getDeclaredMethods();
for (Method method : methodArr) {
System.out.println(method);
}
System.out.println("============= 分割线 ==============");
// 指定获取Teacher类的方法
System.out.println(teacherClass.getMethod("teach", String.class));
System.out.println(teacherClass.getDeclaredMethod("teach", String.class, Person.class));
System.out.println("============= 分割线 ==============");
// 获取Teacher类的构造器,只能获取到public权限的
Constructor[] constructorArr = teacherClass.getConstructors();
for (Constructor constructor : constructorArr) {
System.out.println(constructor);
}
System.out.println("============= 分割线 ==============");
// 获取Teacher类的构造器,可以获取所有权限的构造器
constructorArr = teacherClass.getDeclaredConstructors();
for (Constructor constructor : constructorArr) {
System.out.println(constructor);
}
System.out.println("============= 分割线 ==============");
// 拥有无参构造器时,直接进行实例化,不推荐
Teacher teacher = (Teacher) teacherClass.newInstance();
// 指定获取Teacher类的构造器,并实例化对象
Constructor constructor = teacherClass.getConstructor();
teacher = (Teacher) constructor.newInstance();
System.out.println(String.format("姓名:%s,职务:%s,科目:%s", teacher.getName(), teacher.getPost(), teacher.subject));
constructor = teacherClass.getDeclaredConstructor(String.class, String.class, String.class);
constructor.setAccessible(true);// 设置访问权限,为true时可访问私有private
teacher = (Teacher) constructor.newInstance("半月无霜", "教导主任", "计算机");
System.out.println(String.format("姓名:%s,职务:%s,科目:%s", teacher.getName(), teacher.getPost(), teacher.subject));
System.out.println("============= 分割线 ==============");
// 调用方法
Method teachMethod = teacherClass.getDeclaredMethod("teach", String.class, Person.class);
teachMethod.setAccessible(true);// 设置访问权限,为true时可访问私有private
teachMethod.invoke(teacherClass.newInstance(), "教学", new Student());
}
}
3)反射获取注解
3.1)写两个注解和类
import lombok.Data;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface MyClassInfo{
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyFieldInfo{
String value();
String mappingType();
}
@Data
@MyClassInfo("用户类")
class User{
@MyFieldInfo(value = "主键ID", mappingType = "int")
private Integer id;
@MyFieldInfo(value = "用户名", mappingType = "varchar")
private String username;
@MyFieldInfo(value = "密码", mappingType = "varchar")
private String password;
}
3.2)反射使用注解
public class SomeThingTest {
public static void main(String[] args) {
Class<User> userClass = User.class;
Annotation[] annotationArr = userClass.getDeclaredAnnotations();
for (Annotation annotation : annotationArr) {
System.out.println(annotation);
}
MyClassInfo myClassInfo = userClass.getAnnotation(MyClassInfo.class);
System.out.println(myClassInfo.value());
Field[] fieldArr = userClass.getDeclaredFields();
for (Field field : fieldArr) {
MyFieldInfo myFieldInfo = field.getDeclaredAnnotation(MyFieldInfo.class);
System.out.println(String.format("%s[value:%s,mappingType:%s]", field.getName(), myFieldInfo.value(), myFieldInfo.mappingType()));
}
}
}
4)反射获取泛型
4.1)写两个泛型的方法
public class Person{
public void setList(List<String> list){
}
public Map<String, Object> returnMap() {
return null;
}
}
4.2)反射使用泛型
public class SomeThingTest {
public static void main(String[] args) throws NoSuchMethodException {
Method setList = Person.class.getDeclaredMethod("setList", List.class);
Type[] genericParameterTypes = setList.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println(genericParameterType);
if (genericParameterType instanceof ParameterizedType){
// 获取List中的泛型
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument.getTypeName());
}
}
}
System.out.println("============= 分割线 ==============");
Method returnMap = Person.class.getDeclaredMethod("returnMap");
Type type = returnMap.getGenericReturnType();
System.out.println(type);
if (type instanceof ParameterizedType){
// 获取Map中的泛型
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument.getTypeName());
}
}
}
}
5)在线JDK8API文档
现在,已经知道了反射使用,去剖析框架源码时的你真帅
附上jdk8的在线API文档,祝你前程似锦
功能:Java注解的介绍和反射使用的更多相关文章
- Java注解基本介绍
注解(Annotation),又称元数据(MetaData),提供了一种在代码中添加信息的形式化的方法,将元数据和源代码结合在一起. 1. 外部配置文件如XML存在的问题: 代码复杂度较高,需要编写很 ...
- JAVA 注解,泛型,反射获取泛型,并实例化
JAVA 的泛型加大了 编程的灵活性,在配合上反射,可以让我们省去大量的重复代码,当你用 SpringBoot 整合 JPA 的时候 你会发现,你的 DAO 层只需要继承 BaseDao,在显示标明泛 ...
- java注解(Annotation)解析
注解(Annotation)在java中应用非常广泛.它既能帮助我们在编码中减少错误,(比如最常见的Override注解),还可以帮助我们减少各种xml文件的配置,比如定义AOP切面用@AspectJ ...
- java基础---->java注解的使用(一)
注解是众多引入到Java SE5中的重要的语言变化之一.它为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据.今天我们就开始学习一下java中注解的知识. j ...
- Java基础笔记 – Annotation注解的介绍和使用 自定义注解
Java基础笔记 – Annotation注解的介绍和使用 自定义注解 本文由arthinking发表于5年前 | Java基础 | 评论数 7 | 被围观 25,969 views+ 1.Anno ...
- Java注解教程:自定义注解示例,利用反射进行解析
Java注解能够提供代码的相关信息,同时对于所注解的代码结构又没有直接影响.在这篇教程中,我们将学习Java注解,如何编写自定义注解,注解的使用,以及如何使用反射解析注解. 注解是Java 1.5引入 ...
- Java注解(一):介绍,作用,思想及优点
“注解优先于命令模式”-出自<Effective Java> Java 注解,从名字上看是注释,解释.但功能却不仅仅是注释那么简单.注解(Annotation) 为我们在代码中添加信息提供 ...
- 【转】Spring学习---Bean配置的三种方式(XML、注解、Java类)介绍与对比
[原文]https://www.toutiao.com/i6594205115605844493/ Spring学习Bean配置的三种方式(XML.注解.Java类)介绍与对比 本文将详细介绍Spri ...
- Java自定义注解和运行时靠反射获取注解
转载:http://blog.csdn.net/bao19901210/article/details/17201173/ java自定义注解 Java注解是附加在代码中的一些元信息,用于一些工具在编 ...
随机推荐
- 虚拟机测试cobbler,网络安装加载最后出现 dracut:/#
1.cobbler的几个重要概念: distro:发行版系统容,我理解为镜像来源,提供了kernel 和 initrd 文件以及repo源 profile:kickstart文件,用于定制系统,定制安 ...
- java内存区域的划分
前言 之前我们探讨过一个.class文件是如何被加载到jvm中的.但是jvm内又是如何划分内存的呢?这个内被加载到了那一块内存中?jvm内存划分也是面试当中必被问到的一个面试题. 什么是JVM内存区域 ...
- Linux速通08 网络原理及基础设置、软件包管理
使用 ifconfig命令来维护网络 # ifconfig 命令:显示所有正在启动的网卡的详细信息或设定系统中网卡的 IP地址 # 应用 ifconfig命令设定网卡的 IP地址: * 例:修改 et ...
- 漫漫Java路1—基础知识3—数据类型和变量作用域以及常量
强类型语言 所有变量定义后才能使用,区别于js等弱类型语言 数据类型分类 基本类型(primitive type) 引用类型(reference type) 整数类 byte:占1字节 short:占 ...
- springmvc redis @Cacheable扩展(一)
springmvc 中有自带的cache处理模块,可以是方法级别的缓存处理,那么在实际使用中,很可能自己造轮子,因为实际中永远会有更奇怪的需求点.比如: 1 清除缓存时候,能模糊的进行删除 2 针对不 ...
- SpringCloud里面切换数据源无效的问题
问题描述: 调用链:controller1的接口A->service1的方法A->service2的方法B 方法A开启了事务,且指定了数据库A的数据源 方法B也开启了事务,使用了默认的事务 ...
- 树莓派 3/4 安装 FreeBSD
已盼春来归 已盼春来归 今日去 愿为春来归 盼归春天来了 FreeBSD 的春天在哪里? 树莓派是什么,相信凡是关注了我们的人都不会不知道,但是介于非专业人员需要在此做简要介绍.我们的安卓手机,大部分 ...
- P3388 【模板】割点(割顶) 题解 (Tarjan)
题目链接 P3388 [模板]割点(割顶) 解题思路 最近学的东西太杂了,多写点博客免得自己糊里糊涂的过去了. 这个题求割点,感觉这篇文章写得挺好. 割点是啥?如果去掉这个点之后连通图变成多个不连通图 ...
- 2019第十届蓝桥杯省赛及国赛个人总结(java-B组)
省赛: 今年省赛的题目比18年简单的多,基本都是暴力枚举.BFS之类.还记得去年在山师考蓝桥杯,我这种辣鸡连题目都没看懂.本以为蓝桥会变得越来越难,没想到今年就被打脸了.今年省赛后面三个编程大题一个没 ...
- 攻防世界 reverse Newbie_calculations
Newbie_calculations Hack-you-2014 题目名百度翻译成新手计算,那我猜应该是个实现计算器的题目.... IDA打开程序,发现一长串的函数反复调用,而且程序没有输入,只有输 ...