java注解多此一举_功能: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 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 list){

}

public Map 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文档,祝你前程似锦

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值