Java面向对象编程篇6——注解与反射

Java面向对象编程篇6——注解与反射

1、注解概述

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制

Java 语言中的类、方法、变量、参数和包等都可以被标注。Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标

可简单理解为标签

2、元注解

元注解顾名思义我们可以理解为注解的注解

@Retention(注解保留时期)

  • @Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码文件中不包含

  • @Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得

  • @Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通过反射获取到

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}

@Target(注解作用的范围)

  • @Target(ElementType.TYPE) 作用接口、类、枚举、注解
  • @Target(ElementType.FIELD) 作用属性字段、枚举的常量
  • @Target(ElementType.METHOD) 作用方法
  • @Target(ElementType.PARAMETER) 作用方法参数
  • @Target(ElementType.CONSTRUCTOR) 作用构造函数
  • @Target(ElementType.LOCAL_VARIABLE)作用局部变量
  • @Target(ElementType.ANNOTATION_TYPE)作用于注解(@Retention注解中就使用该属性)
  • @Target(ElementType.PACKAGE) 作用于包
  • @Target(ElementType.TYPE_PARAMETER) 作用于类型泛型,即泛型方法、泛型类、泛型接口 (jdk1.8加入)
  • @Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class (jdk1.8加入)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
}

@Documented(文档)

  • Document的英文意思是文档。它的作用是能够将注解中的元素包含到 Javadoc 中去
@Documented
public @interface MyAnnotation {
}

@Inherited(继承)

  • Inherited的英文意思是继承
  • 并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.TYPE)
@Inherited
public @interface MyAnnotation {
}
@MyAnnotation
public class Test {
}class Test1 extends Test{
}

注解 MyAnnotation被 @Inherited 修饰,之后类 Test 被 MyAnnotation 注解,类 Test1 继承 Test,那么类 Test1 也拥有 MyAnnotation 这个注解。

@Repeatable(可重复)

  • Repeatable的英文意思是可重复的。顾名思义说明被这个元注解修饰的注解可以同时作用一个对象多次,但是每次作用注解又可以代表不同的含义
//相当于一堆注解
@Retention(RetentionPolicy.RUNTIME)
public @interface Values {Value[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Values.class)
public @interface Value {String id() default "value";
}
public class Test {@Value("hello")@Value("world")public static void test(String var1, String var2) {System.out.println(var1 + " " + var2);}public static void main(String[] args) {Method[] methods = Test.class.getMethods();for (Method method : methods){if (method.getName().equals("test")) {Annotation[] annotations = method.getDeclaredAnnotations();System.out.println(annotations.length);System.out.println(method.getName() + " = " + Arrays.toString(annotations));}}}
}
  • 在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组

  • 注解中属性可以有默认值,默认值需要用 default 关键值指定

  • 如果一个注解内仅仅只有一个名字为 value 的属性时,应用这个注解时可以直接接属性值填写到括号内

3、注解的提取(反射)

这里我们暂时先使用以下反射,稍后详细讲述反射

@Retention(RetentionPolicy.RUNTIME)
public @interface Values {Value[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Values.class)
public @interface Value {String id() default "id";String name() default "name";
}
@Value(id = "1",name = "zhangsan")
@Value(id = "2",name = "lisi")
public class Test {public static void main(String[] args) {if (Test.class.isAnnotationPresent(Values.class)){Values annotation = Test.class.getAnnotation(Values.class);Value[] values = annotation.value();for (Value value : values) {System.out.println("id="+value.id());System.out.println("name="+value.name());}}}
}
id=1
name=zhangsan
id=2
name=lisi

属性、方法上的注解照样是可以的,同样还是要假手于反射

@Retention(RetentionPolicy.RUNTIME)
public @interface Values {Value[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Values.class)
public @interface Value {String id() default "id";String name() default "name";
}
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@Value(id = "-1",name = "yoya")
@Value(id = "0",name = "ruoye")
public class Test {@Value(id = "1",name = "zhangsan")public int a;@Value(id = "2",name = "lisi")public void todo(){}public static void main(String[] args) {boolean hasAnnotation = Test.class.isAnnotationPresent(Values.class);if ( hasAnnotation ) {Values values = Test.class.getAnnotation(Values.class);//获取类的注解System.out.println("类注解======================");System.out.println(values);}try {Field a = Test.class.getDeclaredField("a");a.setAccessible(true);//获取一个成员变量上的注解Value value = a.getAnnotation(Value.class);if ( value != null ) {System.out.println("属性注解======================");System.out.println(value.id());System.out.println(value.name());}Method testMethod = Test.class.getDeclaredMethod("todo");if (testMethod!=null) {// 获取方法中的注解System.out.println("方法注解======================");Value declaredAnnotation = testMethod.getDeclaredAnnotation(Value.class);if ( value != null ){System.out.println(declaredAnnotation.id());System.out.println(declaredAnnotation.name());}}} catch (Exception e) {System.out.println(e.getMessage());}}
}

4、反射(框架设计的灵魂)

4.1、反射是什么

  • 将类的各个组成部分封装为其他对象,这就是反射机制

  • 可以在程序运行过程中,操作这些对象

  • 可以解耦,提高程序的可扩展性

  • 过多的反射会影响性能

4.2、获取Class对象的三种方式

同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个

4.2.1、通过该类的对象去获取到对应的Class对象

一般不使用这种方式

public class Student {
}
public class Test {public static void main(String[] args) {Student student = new Student();System.out.println(student.getClass());System.out.println(student.getClass().getName());}
}
class com.ruoye.Student
com.ruoye.Student

4.2.2、通过类名.class静态属性获取

需要导包

public class Student {
}
public class Test {public static void main(String[] args) {System.out.println(Student.class);}
}
class com.ruoye.Student

4.2.3、通过Class类中的静态方法 forName()方法获取

public class Student {
}
public class Test {public static void main(String[] args) throws ClassNotFoundException {Class<Student> studentClass = (Class<Student>) Class.forName("com.ruoye.Student");System.out.println(studentClass.getName());}
}
com.ruoye.Student

4.3、通过Class对象获取到该类的构造器

public class Student {private int num;private String name;public Student() {}private Student(int num) {this.num = num;}public Student(String name) {this.name = name;}private Student(int num, String name) {this.num = num;this.name = name;}
}
public class Test {public static void main(String[] args) throws NoSuchMethodException {Class<Student> studentClass = Student.class;System.out.println("所有构造函数================");Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println(declaredConstructor);}System.out.println("公有构造函数=================");Constructor<?>[] constructors = studentClass.getConstructors();for (Constructor<?> constructor : constructors) {System.out.println(constructor);}System.out.println("指定参数的所有构造器==============");Constructor<Student> constructor = studentClass.getDeclaredConstructor(int.class);System.out.println(constructor);System.out.println("指定参数的公开构造器==============");Constructor<Student> constructor1 = studentClass.getConstructor(String.class);System.out.println(constructor1);}
}
所有构造函数================
private com.ruoye.Student(int,java.lang.String)
public com.ruoye.Student(java.lang.String)
private com.ruoye.Student(int)
public com.ruoye.Student()
公有构造函数=================
public com.ruoye.Student(java.lang.String)
public com.ruoye.Student()
指定参数的所有构造器==============
private com.ruoye.Student(int)
指定参数的公开构造器==============
public com.ruoye.Student(java.lang.String)

4.4、通过获取到的构造器创建对象

public class Student {private int num;private String name;public Student() {}private Student(int num) {this.num = num;}public Student(String name) {this.name = name;}private Student(int num, String name) {this.num = num;this.name = name;}@Overridepublic String toString() {return "Student{" +"num=" + num +", name='" + name + '\'' +'}';}
}
public class Test {public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Class<Student> studentClass = Student.class;Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor(int.class, String.class);//暴力反射declaredConstructor.setAccessible(true);Student zhangsan = declaredConstructor.newInstance(1, "zhangsan");System.out.println(zhangsan);}
}

4.5、通过Class对象获取成员变量

public class Student {public boolean flag;private int num;private String name;public Student() {}private Student(int num) {this.num = num;}public Student(String name) {this.name = name;}private Student(int num, String name) {this.num = num;this.name = name;}public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;}public int getNum() {return num;}public void setNum(int num) {this.num = num;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Student{" +"num=" + num +", name='" + name + '\'' +'}';}
}
public class Test {public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Class<Student> studentClass = Student.class;System.out.println("获取所有字段==============");Field[] fields = studentClass.getDeclaredFields();for (Field field : fields) {System.out.println(field.getName());}System.out.println("获取公有字段==============");Field[] fields1 = studentClass.getFields();for (Field field : fields1) {System.out.println(field.getName());}System.out.println("获取特定字段===========");Field num = studentClass.getDeclaredField("num");System.out.println(num.getName());System.out.println("为字段设置值============");Student student = studentClass.getDeclaredConstructor(null).newInstance();student.setName("ruoye");System.out.println(student.toString());}
}

4.6、通过Class对象获取到该类的方法

public class Student {private void sleep(int a){System.out.println("sleep");}public void study(String name){System.out.println("study");}
}
public class Test {public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Class<Student> studentClass = Student.class;System.out.println("获取所有方法================");Method[] declaredMethods = studentClass.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod);}System.out.println("获取公有方法(包含父类的方法)================");Method[] declaredMethods1 = studentClass.getMethods();for (Method declaredMethod : declaredMethods1) {System.out.println(declaredMethod);}System.out.println("获取指定公共方法================");Method study = studentClass.getMethod("study", String.class);System.out.println(study);System.out.println("获取指定方法================");Method sleep = studentClass.getDeclaredMethod("sleep", int.class);Student student = studentClass.getDeclaredConstructor(null).newInstance();sleep.setAccessible(true);System.out.println(sleep);//唤醒方法sleep.invoke(student,1);}
}

4.7、通过Method对象调用指定方法

public class Student {private void sleep(int a){System.out.println("sleep:"+a);}public void study(String name){System.out.println(name+":study");}public static void run(String name){System.out.println(name+":run");}
}
public class Test {public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Class<Student> studentClass = Student.class;Method sleep = studentClass.getDeclaredMethod("sleep", int.class);Student student = studentClass.getDeclaredConstructor(null).newInstance();sleep.setAccessible(true);System.out.println(sleep);sleep.invoke(student,1);Method run = studentClass.getDeclaredMethod("run", String.class);System.out.println(run);//方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null//方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null//方法是静态的,并且尚未初始化声明此方法的类,则会将其初始化run.invoke(null,"zhangsan");}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/557524.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle数据库支持2颗cpu,2.3 Oracle数据库中常见的性能问题

2.3 Oracle数据库中常见的性能问题这一节列出和描述了Oracle数据库中常见的性能问题。通过下面的Oracle性能调优方法&#xff0c;你应该可以避免这些问题&#xff0c;如果你遇到这些问题了&#xff0c;那么重复前面谈到的Oracle性能调优的步骤&#xff0c;或查阅适当的章节来解…

oracle fnd file.log,OracleEBSWIP模块DebugLog收集方法

How to generate WIP debug log files in ONLINE cases? For 11.5.10 and above, the WIP debug log files will be created ifHow to generate WIP debug log files in ONLINE cases?For 11.5.10 and above, the WIP debug log files will be created if1. FND: Debug Log F…

Java核心类库篇1——简介

Java核心类库篇1——简介 1、核心类库 包名主要功能java.applet提供了创建applet需要的所有类java.awt.*提供了创建用户界面以及绘制和管理图形、图像的类java.beans.*提供了开发Java Beans需要的所有类java.io.*提供了通过数据流、对象序列以及文件系统实现的系统输入、输出…

oracle更新blol字段超长,oracle - 将对象值插入表PL / SQL而无需指定属性 - 堆栈内存溢出...

我有以下架构DROP TABLE ALUMNO_ASIGNATURA;DROP TABLE ASIGNATURA;DROP TABLE TITULACION;DROP TABLE PROFESOR;DROP TABLE ALUMNO;DROP TABLE PERSONA;CREATE TABLE PERSONA( DNI VARCHAR2(9) CONSTRAINT PERSONA_PK PRIMARY KEY,NOMBRE VARCHAR2(20) CONSTRAINT PERSONA_NOM…

Java核心类库篇2——lang

Java核心类库篇2——lang 1、Object 该类是所有类的父类&#xff0c;每个类都使用它作为超类&#xff0c;没有任何属性 方法声明功能介绍Object()使用无参方式构造对象boolean equals(Object obj)用于判断调用对象是否与参数对象相等。 该方法默认比较两个对象的地址是否相等…

Java核心类库篇3——util

Java核心类库篇3——util 1、Date 用于描述特定的瞬间&#xff0c;也就是年月日时分秒&#xff0c;可以精确到毫秒 1.1、构造方法 方法声明功能介绍public Date()获取当前时间表示的date对象public Date(long date)根据给定的毫秒值创建date对象 public class Test {public…

linux怎么重装ssh服务器,Linux平台下安装SSH

什么是SSH&#xff1f;Secure Shell(缩写为SSH)&#xff0c;由IETF的网络工作小组(Network Working Group)所制定&#xff1b;SSH为一项创建在应用层和传输层基础上的安全协议&#xff0c;为计算机上的Shell(壳层)提供安全的传输和使用环境。传统的网络服务程序&#xff0c;如r…

Java核心类库篇4——集合

Java核心类库篇4——集合 1、集合的意义 记录单个数据内容时&#xff0c;则声明一个变量记录多个类型相同的数据内容时&#xff0c;声明一个一维数组记录多个类型不同的数据内容时&#xff0c;则创建一个对象记录多个类型相同的对象数据时&#xff0c;创建一个对象数组记录多…

计划任务文件 linux,Linux之任务计划

一、单次任务计划二、周期性任务计划一、单次任务计划命令&#xff1a;batch&#xff1a;系统空闲时自动执行&#xff0c;不常用at&#xff1a;可以使用相对时间、绝对时间或模糊时间&#xff0c;例如相对时间&#xff1a;at now3min&#xff0c;表示3分钟后执行绝对时间&#…

Java核心类库篇5——异常

Java核心类库篇5——异常 java.lang.Throwable类是Java语言中错误(Error)和异常(Exception)的超类其中Error类主要用于描述Java虚拟机无法解决的严重错误&#xff0c;通常无法编码解决&#xff0c;如&#xff1a;JVM挂掉了 等其中Exception类主要用于描述因编程错误或偶然外在…

linux2019内核版本发布,求问Linux最新内核版本以及发布日期。

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼具有时效性的东西&#xff0c;百度能查处什么鬼来。mainline:4.3-rc32015-09-27[tar.xz][pgp][patch][view diff][browse]stable:4.2.22015-09-29[tar.xz][pgp][patch][inc. patch][view diff][browse][changelog]longterm:4.1.920…

Java核心类库篇6——IO

Java核心类库篇6——IO 1、File 1.1、构造方法 方法声明功能介绍public File(File parent, String child)从父抽象路径名和子路径名字符串创建新的 File实例public File(String pathname)通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例public File(String pa…

linux搭建web服务器原理,【LINUX】linux搭建web服务器

linux httpd假设服务器地址为192.168.80.20/241.将准备安装的httpd软件包共享给everyone&#xff0c;(1)在linux上mount.cifs //真机IP地址/共享文件夹名/media /ls /meidia/查看tar xjvf httpd-2.4.10.tar.bz2 -C /usr/src解压至/usr/src下下面两个插件是httpd2.4以…

Java核心类库篇7——多线程

Java核心类库篇7——多线程 1、程序、进程和线程 程序 - 数据结构 算法&#xff0c;主要指存放在硬盘上的可执行文件进程 - 主要指运行在内存中的可执行文件线程就是进程内部的程序流 操作系统内部支持多 进程的&#xff0c;而每个进程的内部又是支持多线程的 2、线程的创…

Java核心类库篇8——网络编程

Java核心类库篇8——网络编程 1、七层网络模型 OSI&#xff08;Open System Interconnect&#xff09;&#xff0c;即开放式系统互联&#xff0c;是ISO&#xff08;国际标准化组织&#xff09;组织在1985 年研究的网络互连模型。 当发送数据时&#xff0c;需要对发送的内容按…

linux网站如何添加swf支持,linux下安装swftools和openOffice

1.openOffice下载地址&#xff1a;http://download.openoffice.org/all_rc.html#untested-full 下载 Linux 32-bit Intel rpm 包 版本自选 2.安装openOffice 1】 tar -zxvf OOo_3.2.1_Linux_x86_install-rpm-wJRE_zh-CN.tar.gz 2】 cd OOO320_m18_native_packed-1_zh-CN1.openO…

Java番外篇1——正则表达式

Java番外篇1——正则表达式 1、什么是正则表达式 正则表达式定义了字符串的模式正则表达式可以用来搜索、编辑或处理文本正则表达式并不仅限于某一种语言&#xff0c;但是在每种语言中有细微的差别 2、正则表达式规则 2.1、普通字符 普通字符包括没有显式指定为元字符的所…

linux 1号硬盘不能用,linux 挂载硬盘的疑问 : IDE1 上的接口无法使用.

状况说明:我将在linux系统上挂载多块硬盘(目前是redhat9).我通过3块硬盘试验.问题出现:无论如何链接 IDE1 上的硬盘, /dev/hdc 都无法 mount.数据:1. 使用 fdisk -l : 不会显示接到 IDE1 上的硬盘(目前只试验了在 IDE1 上接 1个硬盘,用 master 端口).2. 使用 fdisk /dev/hdc : …

Java番外篇2——jdk8新特性

Java番外篇2——jdk8新特性 1、Lambda 1.1、无参无返回值 public class Test {interface Print{void print();}public static void main(String[] args) { // Print printnew Print() { // Override // public void print() { // …

linux同花顺乱码,打开同花顺软件全是问号

官方答案&#xff1a;字体库字体乱码【原因分析】&#xff1a;系统字体缺失&#xff0c;损坏。【解决方案】方案一&#xff1a;使用360电脑门诊进行修复1.打开【360安全卫士】—【电脑专家】搜索乱码&#xff0c;然后会弹出如下六个解决方案&#xff0c;根据当前计算机的故障现…