注解和反射

一、注解
1、什么是注解?(what)
类比注释,注释是给人看的,注解是给人和机器看的。(注解英文是annotation,注释英文是comment)
2、注解有什么用?(why)
首先注解不是程序本身,这点和注释没什么区别,但注解可以对程序作出解释;
其次注解可以被其他程序(比如编译器器等)读取
3、怎么用注解?(how)
使用@注释名,比如常用的内置注解@Override;还可以添加一些参数值,比如内置注解@SuppressWarnings(value=“unchecked”)镇压注解,该注解有参数是因为本身定义的时候有属性value。
4、哪里可以用注解?(where)
类、方法、属性上面,还可以在包上面!相当于给他们添加了额外的辅助信息,然后我们可以通过反射机制编程实现对这些元数据的访问。
5、内置注解
A、@Override
定义在java.lang.Override中,只用于方法上面,表示重写父类或者接口中的方法;
B、@Deprecated
定义在java.lang.Deprecated中,可以用于类、方法和属性上面,表示该类、方法或者属性已过期,不建议使用;
C、@SuppressWarnings
定义在java.lang.SuppressWarnings中,可以用于类或者方法中,用于抑制编译时的警告信息,但因为该注解定义的类里有属性,所以这个注解后面必须加上参数,比如“all”或者“unchecked”(只有一个属性且属性值为value的时候,value可以去掉),实际工作中使用场景之一是强转的时候会有警告信息,用@SuppressWarnings(“unchecked)镇压。
6、元注解和自定义注解
首先public @interface MyAnnotation(如果是内部类则public去掉,因为一个类只能有一个public修饰类)(使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口)
然后可以在上面定义四部分信息,使用元注解来定义
1)@Target
写这个注解是为了用在哪里?
比如type是类上、method是方法上等(可以多个,放到{}里面。
2)@Retention
这个注解在什么时候有效?
分为源码时、编译时和运行也还有效三种,分别对应sources、class和runtime,我们自定义的都是runtime这个最高级别有效(只能一个)
3)@Documented
顾名思义,和Java文档有关,表示是否把我们的注解生成在Javadoc中
4)@Inherited
表示子类可以继承父类的注解
当然还可以在自定义注解里写上属性,但和一般类里属性不同的是这里属性后面要加上(),所以看起来又像方法,但注意不是方法!还有就是这个属性是可以设置默认属性值,比如int age()default 18;如果设置了默认值,那使用该注解的时候就不需要写该参数值。
二、反射
1、反射概述
首先对比下动态语言和静态语言,二者区分的依据是代码在运行时是否可以根据某些条件改变自身结构,比如js和python就是动态语言。
以js为例:
function f(){
var x = “var a=3;b=5;alert(a+b)”;
eval(x)

eval(x)即执行x之后x从字符串类型编程了a+b即int类型。
那常用的java、c和c++就是静态语言,即代码运行时结构不可变。
但java有了反射机制那就可以实现动态性,所以java的性能不如c和c++,因为静态语言的性能显然高于动态语言。
那为什么要实现动态性?比如游戏在运行的时候出现外挂这就是其使用的场景之一。
再回来看下java反射,为什么叫反射?首先明确如何创建对象?new是最常用一种,然后是clone,还有就是框架中常用的反射,反射的反顾名思义肯定是和最常用new对象这种正常方式相反,new对象的正常方式是
A、引入需要的“包类”名称
B、通过new实例化
C、获取实例化对象
(即类到对象)
反射方式是
A、实例化对象
B、getClass()方法
C、获取完整的“包类”名称
(即对象到类,把对象当作镜子,透过这个镜子看的类的结构)
2、获取反射对象
反射对象用到了java.lang.Class类,获取Class类是关键,那怎么获取这个Class对象,一般是三种方法:
A、调用Class类的forName静态方法,方法参数是包名加类名(这种方法比较好,因为不需要new对象,直接调用静态方法,而且方法参数可以外面传入,应用于spring的ioc)(会有类找不到异常)
B、new一个对象,然后调用老祖宗Object类的getClass方法即可获取其Class对象(这个性能最高)
C、直接该类名.class即可。
注:一个类型,对应的Class对象唯一,比如String对象可能很多但对应Class对象是唯一的。
3、类加
一共有三种:
系统类加载器(用户写的类加载器)
扩展类加载器(系统类加载器的父类加载器)
根加载器:用c或者c++写的,Java获取是null
(扩展类加载器的父类)
4、双亲委派机制
这个是为了类安全
比如java.lang.String是根加载器加载的,如果你自己写了一个一样的那是不会加载的!
5、获取类的运行时结构
1)属性
A、getFields方法,获取public修饰的属性
B、getDeclaredFields方法,顾名思义,获取所有声明的属性,包括私有属性。
C、getDeclaredField方法,这个少了s并且方法要指定方法参数,比如name,从而获取特定属性(但这里不能获取私有属性,如果要获取必须关掉程序的安全检测,比如获取Field name = c1.getDeclaredField(“name”)后,name.setAccessible(true)即可。)
2)方法
A、getMethods方法,获取public修饰的方法(包括父类)
B、getDeclaredMethods,获取所有声明方法,包括私有方法(不包括父类)
C、getMethod方法,少了s但对比的不一样,方法必须指定方法名称和方法参数值,如果方法没有请求参数则写努力,为什么要指定方法名?因为方法有重载。(要想获取私有方法,也需要关闭程序的安全检测)
3)构造器
A、getConstructors方法,获取public修饰的构造器
B、getDeclaredConstructors方法,获取所有声明的构造器,包括私有构造器
C、getDeclaredConstructor方法,少个s,获取指定的构造器,不需要构造器方法名,因为就是类名,但需要指定构造器方法参数的类型,比如String.class、int.class等。(这个获取私有构造器前也要关闭安全检测)
6、动态创建对象执行方法
前面知道了Class类,也知道了如何获取该类对象里的属性、方法和构造器,但怎么和实际对象联系起来?比如User.class,如果修改User类对象的属性、方法和构造器?
那肯定要先通过Class类对象c获取user对象,如果有无参构造则直接c.newInstance()即可,如果无无参构造,则需要先通过c对象获取指定的有参构造器,如果该构造器私有则需要先关闭安全检测(改为true),然后再调用该构造器的newInstance方法,该放到需要写入有参构造器指定的参数,具体如下所示
Class c1 = Class.forName(“com.zhang.User”);
Constructor constructor =
c1.getDeclaredConstuctor(String.class,int.class);
User user = constructor.newInstance
(“zb”,28);
获取user之后就可以结合class对象获取的属性或者方法对user赋值,比如属性就直接调用获取的Field对象的set方法,里面两个参数,一个是user对象名称,另一个是值;而方法就是class对象c1获取指定的方法,即Method对象,调用该对象的invoke方法,方法参数第一个还是user对象名,另一个是指定方法的方法参数值(私有方法也要关闭安全检测)
7、正常new实例和反射获取实例性能对比
反射性能慢很多,如果频繁调用反射可以关闭安全检测来提高性能。
8、通过反射获取泛型信息
可以获取方法参数中泛型也可以获取方法返回值泛型
9、通过反射获取注解信息
例子:ORM
Object relationship Mapping 对象关系映射
Java domain和mysql表对应:
类和表结构对应
属性和表中字段对应
对象和表中记录对应
所以可以利用反射和注解完成ORM。
具体怎么弄?
1)类名对应表名
A、写一个domain
B、写一个自定义注解,只作用于类上,而且运行时有效,里面参数只有一个表示表名
C、在A的domain上面写上这个自定义注解并指定参数名即表名
2)类中属性对应表中字段
A、写一个自定义注解,作用于属性,而且运行时有效,里面有多个参数代表mysql中表字段描述,比如字段类型、长度等
B、自定义注解写在类的各个字段上面来修饰字段
3)main方法中
A、三种方式之一获取Class对象
B、获取该对象指定的属性(如果是获取表名,则不需要获取属性,直接getAnnotation方法就可以)
C、调用该属性的getAnnotation方法获取自定义注解对象,方法参数传递自定义注解名.class
D、调用自定义注解对象里的属性方法获取多个属性(这些属性可以用于sql拼接)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值