反射与注解

文章目录

    • 一、反射
    • 二、注解

一、反射

1.1反射引入

• 编译时知道类或对象的具体信息,此时直接对类和对象进行操作即可,无需反射(reflection)
• 如果编译不知道类或对象的具体信息,此时应该如何做呢?使用反射来实现。比如类的名称放在XML文件中,属性和属性值放在XML文件中,需要在运行时读取XML文件,动态获取类的信息
• 反射的应用场合
o 在编译时根本无法知道该对象或类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息
o 比如log4j,Servlet、SSM框架技术都用到了反射
• 反射的作用
o 动态创建对象
o 动态操作属性
o 动态调用方法
o 动态操作泛型和注解
• 在JDK中,主要由以下类来实现Java反射机制,都位于java.lang.reflect包中
o Class类:代表一个类
o Constructor 类:代表类的构造方法
o Field 类:代表类的成员变量(属性)
o Method类:代表类的成员方法

1.2反射的入口—Class类

• Class类是Java 反射机制的起源和入口
• 用于获取与类相关的各种信息
• 提供了获取类信息的相关方法
• Class类继承自Object类

【示例】认识Class类

public class TestClass1 {public static void main(String[] args) throws Exception {//1.获取一个类的结构信息Class clazz = Class.forName("com.why.Dog");//2.从类对象中获取类的各种结构信息//2.1 获取基本结构信息clazz.getName());clazz.getSimpleName());clazz.getSuperclass());Arrays.toString(clazz.getInterfaces()));//2.2 获取构造方法//只能得到public修 饰的构造方法//Constructor constructor = clazz.getConstructor();//获取无参数构造方法//Constructor constructor = clazz.getConstructor(String.class);//Constructor[] constructors = clazz.getConstructors();//任何权限修饰符都可获取Constructor[] constructors = clazz.getDeclaredConstructors(); //2.3 获取属性PublicField[] fields = clazz.getFields();   // 获取属性PublicField [] fields = clazz.getDeclaredFields(); //本类的任何权限修饰符都可获取,父类不行//2.3 获取方法//Method[] methods = clazz.getMethods();Method [] methods = clazz.getDeclaredMethods();  //本类//Method m = clazz.getMethod("shout",String.class);//Method m = clazz.getMethod("run");//publicMethod m = clazz.getDeclaredMethod("run");}
}

Class类的常用方法

getFields() 获得类的public类型的属性。
getDeclaredFields() 获得类的所有属性
getField(String name) 获得类的指定属性
getMethods() 获得类的public类型的方法
getMethod (String name,Class [] args) 获得类的指定方法
getConstrutors() 获得类的public类型的构造方法
getConstrutor(Class[] args) 获得类的特定构造方法
newInstance() 通过类的无参构造方法创建对象
getName() 获得类的完整名字
getPackage() 获取此类所属的包
getSuperclass() 获得此类的父类对应的Class对象

获取一个类的类对象的多种方式

1、Class.forName(“oracle.jdbc.driver.OracleDriver”);
2、String.class;
Student.class;
int.class
3、String str=“sxt";
Class clazz = str.getClass();
4、Student stu = new Student();
Class c1 = stu.getClass();
Class c2 = stu.getSuperClass();
5、Class c1 = Integer.TYPE; (内部基本数据类型的Class对象)

1.3使用反射创建对象

【示例】通过Class的newInstance()方法创建对象

Object obj = clazz.newInstance();

【示例】通过Constructor的newInstance()方法创建对象

public class TestConstructor3 {public static void main(String[] args) throws Exception {//1.读取配置文件,或者类的完整路径字符串String className = "com.why.Dog";//2.根据类的完整路径字符串获取Class信息Class clazz = Class.forName(className);//3.从Class信息中获取有参数构造方法// Constructor con = clazz.getConstructor(String.class,String.class);Constructor con = clazz.getDeclaredConstructor(String.class,String.class);//指定形参//4.使用反射创建对象//突破封装性的限制,即使是private、默认的也可以访问con.setAccessible(true); Object obj = con.newInstance("旺财1","黑色2");//传递实参System.out.println(obj);}
}

反射优点

功能强大
1)编码时不知道具体的类型,可以使用反射动态操作
2) 突破封装的限制,即使private的成员也可以进行操作

反射缺点:

1).代码繁琐,可读性差
2).突破封装的限制,即使private的成员也可以进行操作(既是优点也是缺点)

2.1 使用反射操作属性

【示例】使用反射操作属性

public class TestField {public static void main(String[] args) throws Exception{//1.获取类的完整路径字符串String className = "com.why.Dog";//2.得到类对象Class clazz = Class.forName(className);//3.使用反射创建对象Object dog = clazz.getConstructor().newInstance();//4.获取属性Field f1 =  clazz.getField("color");Field f2 = clazz.getDeclaredField("age");//5.给属性赋值f1.set(dog,"黑色1"); //  dog.color ="黑色";f2.setAccessible(true);//突破权限的控制f2.set(dog,10);//6.输出给属性System.out.println(f1.get(dog)); //dog.colorSystem.out.println(f2.get(dog)); //dog.ageSystem.out.println(dog);}
}

2.2 使用反射执行方法

• 通过Class对象的getMethods() 方法可以获得该类所包括的全部public方法, 返回值是Method[]
• 通过Class对象的getMethod()方法可以获得该类所包括的指定public方法, 返回值是Method
• 每个Method对象对应一个方法,获得Method对象后,可以调用其invoke() 来调用对应方法
• Object invoke(Object obj,Object [] args):obj代表当前方法所属的对象的名字,args代表当前方法的参数列表,返回值Object是当前方法返回值,即执行当前方法的结果。

【示例8】使用反射执行方法

public class TestMethod {public static void main(String[] args) throws Exception{//1.获取类的完整路径字符串String className = "com.why.Dog";//2.得到类对象Class clazz = Class.forName(className);//3.使用反射创建对象//Object dog = clazz.newInstance();Object dog = clazz.getConstructor().newInstance();//4.获取方法Method m1 = clazz.getMethod("shout");Method m2 = clazz.getMethod("add",int.class,int.class);//5.使用反射执行方法m1.invoke(dog);//dog.shout();Object result = m2.invoke(dog,10,20);   System.out.println(result);}
}

2.3 使用反射操作泛型

【示例】使用反射获取泛型类型

public class TestGeneric {
public void method1(Map<Integer, Student> map, List<Student> list, String str) {}public Map<Integer, Student> method2() {     return null;  }public static void main(String[] args) throws NoSuchMethodException {Class clazz = TestGeneric.class;Method method1 =clazz.getMethod("method1", Map.class, List.class, String.class);//获取参数类型(不带泛型)Class[] paramTypes = method1.getParameterTypes();//获取参数类型(带泛型)Type[] types = method1.getGenericParameterTypes();for (Type type : types) {if (type instanceof ParameterizedType) {Type typeArgs[] =((ParameterizedType) type).getActualTypeArguments();}}

给集合添加泛型后,可以限制元素类型,提高安全性。使用反射还可以突破泛型的限制;

【示例】使用反射突破泛型的限制

public class TestGeneric {public static void main(String[] args) throws Exception {//不是反射List<String> list = new ArrayList<String>();list.add("Java");list.add("MySQL");list.add("MyBatis");//list.add(new Date());//list.add(100);//使用反射调用add//先得到List的结构信息ClassClass clazz = list.getClass();//获取add方法Method method = clazz.getMethod("add",Object.class);//使用反射调用add方法method.invoke(list,100);method.invoke(list,new Date());System.out.println(list);}
}

二、注解

2.1 认识注解

Annotation ,JDK1.5新提供的技术
我们在编程中经常会使用到注解,作用有:
1)编译检查:比如@SuppressWarnings, @Deprecated 和 @Override 都具有编译检查作用
2)替代配置文件:使用反射来读取注解信息
目前大部分框架(如Spring)都使用了注解简化代码并提高编码的效率(使用注解之前使用的xml进行配置)
注解其实就是代码里的特殊标记,它用于替代配置文件:传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。
在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。 注解可以标记在包、类、属性、方法,方法参数以及局部变量上,且同一个地方可以同时标记多个注解。
注解可以在编译(source),类加载(class),运行时(runtime)被读取,并执行相应的处理,以便于其他工具补充信息或者进行部署

2.2 内置注解

主要有三个内置注解

 @Override - 检查该方法是否是重载方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
 @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
 @SuppressWarnings - 指示编译器去忽略注解中声明的警告。

从 Java 7 开始,额外添加了 3 个注解:
 @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
 @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
 @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

2.3 元注解
元注解是指注解的注解,在JDK 1.5中提供了4个标准的用来对注解类型进行注解的注解类。可以使用这4个元注解来对我们自定义的注解类型进行注解

  1. @Retention用来约束注解的生命周期,分别有三个值,源码级别(source),类文件级别(class)或者运行时级别(runtime),若没有 @Retention,则默认是 RetentionPolicy.CLASS。其含有如下:
     SOURCE:注解将被编译器丢弃(该类型的注解信息只会保留在源码里,源码经过编译后,注解信息会被丢弃,不会保留在编译好的class文件里)
     CLASS:注解在class文件中可用,但会被VM丢弃(该类型的注解信息会保留在源码里和class文件里,在执行的时候,不会加载到虚拟机中)。
     RUNTIME:注解信息将在运行期(JVM)也保留,因此可以通过反射机制读取注解的信息(源码、class文件和执行的时候都有注解的信息),如SpringMvc中的@Controller、@Autowired、@RequestMapping等。
  2. @Target -用来约束注解可以应用的地方(如方法、类或字段),其中ElementType是枚举类型。若没有 @Target,则该 Annotation 可以用于任何地方。
public enum ElementType {/**标明该注解可以用于类、接口(包括注解类型)或enum声明*/TYPE,/** 标明该注解可以用于字段(域)声明,包括enum实例 */FIELD,/** 标明该注解可以用于方法声明 */METHOD,/** 标明该注解可以用于参数声明 */PARAMETER,/** 标明注解可以用于构造函数声明 */CONSTRUCTOR,/** 标明注解可以用于局部变量声明 */LOCAL_VARIABLE,/** 标明注解可以用于注解声明(应用于另一个注解上)*/ANNOTATION_TYPE,/** 标明注解可以用于包声明 */PACKAGE,/*** 标明注解可以用于类型参数声明(1.8新加入)* @since 1.8*/TYPE_PARAMETER,/*** 类型使用声明(1.8新加入)* @since 1.8*/TYPE_USE
}
  1. @Documented - 标记这些注解是否包含在用户文档中。Java -d doc xx.java
  1. @Inherited - 指示注解类型被自动继承。当@InheritedAnno注解加在某个类A上时,假如类B继承了A,则B也会带上该注解。

2.4 自定义注解

【示例】自定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(value= {ElementType.METHOD,ElementType.TYPE})
public @interface MyAnnoation {int id() default 0;String name() default "";double [] scoreArr() default {};
}
public @interface MyAnnotation2 {String value();    
}
@MyAnnotation2("aaa")
@MyAnnoation
public class TestAnnotation {@MyAnnoation(id=5,name="张三",scoreArr = {78,89,34})public static void main(String[] args) {}@MyAnnotation2(value="bbb")public void method1(){}
}

总结:

 定义注解的关键字是@interface
 自定义注解中可以定义多个配置参数,不是成员方法,不是成员变量;说明参数的名称,以及参数值的类型
 如果只有一个配置参数,一般命名为value
 如果配置参数是value,并且只有一个配置参数,value可以省略

注意:

 定义注解时,意味着它实现了 java.lang.annotation.Annotation 接口,即该注解就是一个Annotation。
 和我们通常 implements实现接口的方法不同。Annotation 接口的实现细节都由编译器完成。通过 @interface 定义注解后,该注解不能继承其他注解或接口。

2.5 使用反射读取注解

目前大部分框架(如Spring、MyBatis、SpringMVC)都使用了注解简化代码并提高编码的效率(使用注解之前使用的xml进行配置)。
ORM,Object-Relationl Mapping,对象关系映射,它的作用是在关系型数据库和对象之间作一个映射,这样我们在具体的操作数据库的时候,只要像平时操作对象一样操作它就可以了,ORM框架会根据映射完成对数据库的操作,就不需要再去和复杂的SQL语句打交道了。常用的ORM框架有MyBatis和Hibernate。
在ORM中,数据库表对应Java实体类,数据库表的字段对应Java实体类的成员变量,数据库表的记录对应Java实体类的对象。
其实ORM可以借助注解来进行映射,并使用反射读取注解信息完成最终的操作。

【示例】模拟实现MyBatis的注解并使用反射读取

@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.TYPE)
public @interface Table {String value();
}@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.FIELD)
public @interface Column {String columnName(); //列名String columnType(); //列类型int length(); //列长度int precision() default 0;//小数位数
}@Table(value = "t_student")
public class Student {@Column(columnName="id",columnType = "int",length=6)private int id;@Column(columnName = "sname",columnType = "varchar",length = 10)private String name;@Column(columnName = "score",columnType = "double",length = 4,precision = 1)private double score;
}public class TestORM {public static void main(String[] args) throws Exception {String className ="com.annotation3.Student";Class clazz = Class.forName(className);//获取类的所有注解Annotation [] annotations = clazz.getAnnotations();for (Annotation annotation:annotations  ) {System.out.println(annotation);}//获取类的指定注解Table annotation =(Table) clazz.getAnnotation(Table.class);System.out.println(annotation);System.out.println(annotation.value());//获取id属性的注解Field idField = clazz.getDeclaredField("id");Column  idColumn =(Column)idField.getAnnotation(Column.class);System.out.println(idColumn.columnName());System.out.println(idColumn.columnType());System.out.println(idColumn.length());System.out.println(idColumn.precision());//获取name属性的注解//获取score属性的注解//拼接create DDL语句,通过JDBC创建数据库表 excuteUpdate()//根据Student类id、name、score的值,对T_Student表进行添 //加、修改、删除操作;将T_Student表的一条记录的各列的数据取出来,存//入一个Student对象中}
}

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

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

相关文章

.net core 2.0学习笔记(一):开发运行环境搭建

期待已久的.net core 2.0终于发布了&#xff01;大家等的花儿都谢了。 不过比预期提前了一个多月&#xff0c;这在微软历史上还真的不多见。按照历史经验看&#xff0c;2.0版本应该比较靠谱&#xff0c;我猜这也是社区非常火爆的原因吧。下面就简单分享一下.net core2.0开发运行…

不好意思,你这个加分理由不行……

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。周五了&#xff0c;又该周测了&#xff0c;今天和以往一样&#xff0c;上午前两节课都在上课&#xff0c;第三节课进行测试&#xff0c;这周的填空题有点儿多&#xff0c;所以考试的时间较…

SQL索引一步到位

转载自 SQL索引一步到位 SQL索引在数据库优化中占有一个非常大的比例&#xff0c; 一个好的索引的设计&#xff0c;可以让你的效率提高几十甚至几百倍&#xff0c;在这里将带你一步步揭开他的神秘面纱。 1.1 什么是索引&#xff1f; SQL索引有两种&#xff0c;聚集索引和非聚…

jzoj3794,P1383-高级打字机【欧拉序,离线O(n)】

正题 题目链接&#xff1a;https://www.luogu.org/problemnew/show/P1383 大意 三个操作 T c&#xff1a;加入一个字符c U x&#xff1a;撤销前x次操作&#xff08;只包括T和U&#xff09; Q x&#xff1a;询问当前第x个字符 解题思路 对于50%的数据U不会撤销到U 所以我们可…

你也可以做一个简易抽奖程序!

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。今天给大家分享一个使用winform制作的小案例——随机点名&#xff08;抽奖&#xff09;程序&#xff0c;下面我们来看看运行结果&#xff1a;在班内点名为了公平起见&#xff0c;一直使用的…

ASP.NET Core 2.0 特性介绍和使用指南

ASP.NET Core 2.0 发布日期&#xff1a;2017年8月14日 ASP.NET团队宣布ASP.NET Core 2.0正式发布&#xff0c;发布Visual Studio 2017 15.3支持ASP.NET Core 2.0&#xff0c;提供新的Razor Pages项目模板。 详细发布信息查看.NET Core 2.0.0发布说明文档 最新版SDK下载&…

blog项目中遇到的问题及解决

1、dependencesmangement 只做资源定位 2、多模块开发中mapper扫描 3、lambda表达式简写时&#xff08;使用lombox建造者模式&#xff09; 4、新增评论时 使用mp的自动填充时userid未赋值

你在学校我安排了你没有做到最多凶你一顿,在公司不一样,直接得让走人!...

今天放一部分聊天记录吧~毛帅龙同学穆老师我今天跟着公司做项目了雄雄的小课堂可以呀雄雄的小课堂厉害了雄雄的小课堂好好干哈雄雄的小课堂等有空了出一套若依的文档雄雄的小课堂给大家分享分享毛帅龙同学那个ruoyi视频买了雄雄的小课堂199&#xff1f;毛帅龙同学现在每天看两个…

2018/7/10-纪中某C组题【jzoj3792,jzoj3793,jzoj3794】

前言 由于B组题目太残酷&#xff0c;忒容易爆零&#xff0c;于是我就回到了C组温暖的怀抱 今日说法分数 正题 T1&#xff1a;jzoj3792,P2062-分队问题【贪心】 博客链接&#xff1a;https://blog.csdn.net/mr_wuyongcong/article/details/80988719 T2&#xff1a;jzoj3793,…

ASP.NET Core 源码学习之 Logging[2]:Configure

在上一章中&#xff0c;我们对 ASP.NET Logging 系统做了一个整体的介绍&#xff0c;而在本章中则开始从最基本的配置开始&#xff0c;逐步深入到源码当中去。 默认配置 在 ASP.NET Core 2.0 中&#xff0c;对默认配置做了很大的简化&#xff0c;并把一些基本配置移动到了程序…

两个月拿到N个offer,看看我是如何做到的

转载自 两个月拿到N个offer&#xff0c;看看我是如何做到的 前言&#xff1a; 北京-三年经验-Java&#xff0c;在金三银四这两个月期间&#xff08;在五月初还去面试了几家&#xff0c;主要是三四月份期面试剧居多&#xff09;&#xff0c;我跳槽面试&#xff0c;前前后后我…

Redis工具类

文章目录Redis使用FastJson序列化Redis配置类Redis工具类Redis使用FastJson序列化 <!--fastjson依赖--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.33</version></depend…

“小朋友”们节日快乐呀~

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。今天是六月一日——儿童节&#xff0c;看了看朋友圈&#xff0c;不管是大孩子还是小孩子&#xff0c;都在过节&#xff0c;哈哈哈。最近四班一直在做项目&#xff0c;一共6个小组&#xff…

jzoj1293,P2933-气象牛(气象测量)【dp】

前言 考试时题目都没看懂&#xff0c;题目十分玄学 举个栗子 Sum(sj,s(j1))Sum(sj,s(j1))就是Sum(msj,ms(j1))Sum(msj,ms(j1))and 用1∼n1∼n的数概况1∼10000001∼1000000的数 反正就是十分的玄学 正题 大意 在nn个数m" role="presentation" style="…

Entity Framework Core 2.0 全局查询过滤器

本博文翻译自&#xff1a;http://gunnarpeipman.com/2017/08/ef-core-global-query-filters/ Entity Framework Core 2.0 全局查询过滤器 Entity Framework Core 2.0引入了全局查询过滤器&#xff0c;可以在创建模型时应用到实体 。它使得构建多租户应用程序和支持对实体 的软…

SpringCloudGateway

文章目录SpringCloudGateway起步消费端整合SpringCloudGateway静态路由配置内置扩展网关过滤内置网关过滤自定义过滤全局过滤器内置全局过滤器自定义全局过滤器ForwardRoutingFilterNetty全局路由响应式负载均衡代理GatewayMetricsFilter网关度量过滤器&#xff08;服务监控&am…

来自一位家长的肺腑之言,句句在理!!!

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。今天分享一段话&#xff0c;原创来自三班的一位同学家长&#xff0c;可所谓字字在理&#xff01;看完之后我自己也反思了好多&#xff0c;主要是思想观念的转变&#xff0c;就像佟老师给我说的一样…

jzoj1295,P1607-轻轨(庙会班车)【贪心,线段树】

前言 我考试时敲了一个不仅比正解编程复杂度高&#xff0c;而且时间更慢&#xff0c;还AC不了的费用流 垃圾代码 #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define MN 20011 using namespace std; struct node{int…

一篇文章了解RPC框架原理

转载自 一篇文章了解RPC框架原理 1.RPC框架的概念 RPC&#xff08;Remote Procedure Call&#xff09;–远程过程调用&#xff0c;通过网络通信调用不同的服务&#xff0c;共同支撑一个软件系统&#xff0c;微服务实现的基石技术。使用RPC可以解耦系统&#xff0c;方便维护…

winform分页案例简单实现方式~

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。最近&#xff0c;四班在做KTV点歌系统&#xff0c;正好需要用到分页的内容&#xff0c;所以今天我就整理整理&#xff0c;写了一个简易的winfrom分页案例&#xff0c;以下是案例截图&#…