Day27-基础加强(注解Annotation、动态代理)
来源:互联网 发布:中国兵器工业 知乎 编辑:程序博客网 时间:2024/05/18 02:18
注解Annotation
注解概述:
annotation:是一种代码级别的说明。和类、接口平级;
(注释是给人看的,注解是给计算机(虚拟机)看的)
注解作用:
* 执行编译时期的检查,例如Override* 分析代码(主要用途:替代配置文件)
JDK中的三类注解
1)@Override 标识重写父类方法,描述方法的重写
2)@SuppressWarnings(“all”)压制警告
3)@Deprecated 标识方法过时,例如Date.toLocalString();
自定义注解:
eclipse里面可以直接new 一个,和类、接口是平级关系
@interface 注解名 { }
可以看出注解的本质就是一个接口
插一句:
找到annotation编译出来class文件,shift +右键,打开命令行,javap指令,把class扔进去,就可以看到下图信息:可以看出annotation的本质上就是一个接口
注解本质上就是一个接口,接口中可以定义变量(常量)和方法(抽象),注解中的方法叫注解属性
注解属性:
1)基本数据类型;
2)String类型
3)枚举类型
4)注解类型
5)Class类型
6)以上类型的一位数组类型
注意:一旦注解有了属性,在使用的时候就一定要带上注解的属性。
注解属性:
格式:
定义注解属性的时候:(不写修饰符的时候默认是public abstract修饰,且只能是这个)
@Target(value = {ElementType.METHOD })public @interface AnnotationTest01 { int i() default 1; String s();}
定义注解属性的时候可以指定默认值:
属性类型 属性名() default 默认值;
@Target(value = {ElementType.METHOD })public @interface AnnotationTest01 { int i() default 1;}
使用注解属性的时候
@注解名(属性名=值,属性名2=值2)
eg:@MyAnnotation3(i = 0,s="23")
特殊情况:
1)若属性类型的一维数组的时候,当数组的值只有一个的时候可以有以下下两种写法
两种写法:
@MyAnnotation4(ss = { “a” })
@MyAnnotation4(ss = “a”)
2)如果属性名字为value的时候,且只有一个属性的时候
赋值的时候value可以省略
3)一个类上,注解不能够重复使用,但是可以用不同的注解
元注解:
定义在注解上的注解
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD })
public @interface AnnotationTest01 {
int i() default 1;
}
四个元注解:后两个重要
1)Target:定义该注解可以使用在什么上面,值为:ElementType的枚举值:
* METHOD:方法* TYPE:类 接口* FIELD:字段* CONSTRUCTOR:构造方法声明
如果自定义的注解上没有加target元注解,都默认为该注解可以定义在任何位置上(方法、类、字段、构造函数)
2)Retention:定义该注解保留到哪个代码阶段,值为RetentionPolocy类型
.java(源码阶段)——>.class(字节码阶段)——>运行阶段
* * SOURCE:只在源码上保留 * CLASS:在源码和字节码上保留 * RUNTIME:在所有的阶段都保留 不会分就直接写RUNTIME即可;默认情况下是SOURCE阶段
例子:(如果忘记了具体的值怎么写,可以把鼠标移动到value上,按下ctrl点击进去查看写法)
@Target(value = {ElementType.METHOD,ElementType.TYPE })@Retention(value = RetentionPolicy.RUNTIME)public @interface MyAnnotation03 { int a(); String b();}
注解Api(如果要找以下函数的Api,需要搜索AnnotatedElement)
( java.lang.reflect.AnnotatedElement)
(调用一下api的可以是字节码对象中的method、field、class等等)
* - T getAnnotation(ClassannotationType):得到指定类型的注解引用。没有返回null。
* - Annotation[] getAnnotations():得到所有的注解,包含从父类继承下来的。
* - Annotation[] getDeclaredAnnotations():得到自己身上的注解。
* - boolean isAnnotationPresent(Class
@MyTestclass Demo { public void fun01(){ }}
new Demo().getClass().isAnnotationPresent(MyTest.class);//判断Demo这个类上是否有MyTest的注解
2)getAnnotation()得到指定类型的注解的引用,没有返回null
method.isAnnotationPresent(MyTest.class);//判断一个方法上是否有MyTest的注解
案例:判断指定类中的每个函数是不是被指定的Annotation修饰了,如果是,就执行
思路分析:
- 定义两个类(TestDemo,MainTest)和一个注解(@MyTest)
- 在MainTest这个类的main方法里面:
获得TestDemo里面的所有方法
遍历这些方法, 判断此方法上是否有@MyTes注解,
如果有,就执行该方法
有个细节,要加上元注解Retention,让注解在所有阶段都存在。
使得当前注解保留到运行(任何)阶段
ManTest:
public class MainTest { public static void main(String[] args) throws Exception { //获得要目标类的字节码文件 Class clazz = Class.forName("com.itheima.mainTest.Test01"); //获得目标类中的所有函数 Method[] methods = clazz.getDeclaredMethods(); //遍历目标类中的所有函数 for (Method method : methods) { //判定遍历出来的函数是不是被指定的Annotation修饰了 if(method.isAnnotationPresent(AnnotationTest01.class)){ //如果该函数有AnnotationTest01注解 method.invoke(clazz.newInstance()); //newInstance()使用的是无参数的构造函数,这也是javaBean中为了一定需要无参数的构造函数的原因,因为框架里面都会用到无参数的构造方法。 AnnotationTest01 annotation = method.getAnnotation(AnnotationTest01.class); System.out.println(annotation); } } }}
Test01
public class Test01 { @AnnotationTest01 public void test01(){ System.out.println("test01函数执行了"); } @AnnotationTest01 public void test02(){ System.out.println("test02函数执行了"); } public void test03(){ System.out.println("test03函数执行了"); }}
Annotation的定义
@Retention(value = RetentionPolicy.RUNTIME)@Target(value = {ElementType.METHOD })public @interface AnnotationTest01 { int i() default 1;}
输出结果为:
代理!!
ProxyPattern(代理模式),23中常见的面向对象软件的设计模式之一;
代理概念:
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
意义:增强一个类中的某个方法.
代理模式和装饰者模式挺像。
动态代理:
动态代理它可以直接给某一个目标对象生成一个代理对象,而不需要代理类存在。
动态代理与代理模式原理是一样的,只是它没有具体的代理类,直接通过反射生成了一个代理(虚拟)对象。
静态代理和动态代理的区别:
静态代理一定需要有一个具体的类存在的。
动态代理不需要一个具体的类,通过虚拟机来创建一个代理(虚拟)对象出来
JDK中的动态代理:
Java.lang.reflect.Proxy类可以直接生成一个代理对象
Proxy.newProxyInstance(ClassLoader loader, Class
public class ProxyCarDemo { @Test public void test01(){ final Car myCar = new QqCar(); Car proxyCar = (Car)Proxy.newProxyInstance(myCar.getClass().getClassLoader(), myCar.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equalsIgnoreCase("run")){ System.out.println("代理改装后,可以跑120迈"); return null; } return method.invoke(myCar, args); } }); proxyCar.run(); proxyCar.stop(); proxyCar.addOil(93); } /** * @Title: ProxyCarDemo.java * @Description: TODO(定义一个接口) * @author jjizh * @date 2017年7月10日 上午10:02:19 * @version V1.0 */ interface Car { public void run(); public void stop(); public void addOil(int num); } /** * @Title: ProxyCarDemo.java * @Description: TODO(定义一个接口的实现类qqCar) * @author jjizh * @date 2017年7月10日 上午10:02:58 * @version V1.0 */ class QqCar implements Car{ @Override public void run() { System.out.println("QqCar可以跑60迈"); } @Override public void stop() { System.out.println("car都具有刹车功能"); } @Override public void addOil(int num) { System.out.println("QqCar需要加【"+num+"】号油"); } }}
案例二:统一GET和POST中文乱码的处理(动态代理)
利用filter和动态代理
需求分析:
在整个网站中,可能会有get请求或post请求向服务器提交参数.参数中往往有中文信息.在后台每个Servlet中都需要去处理乱码.
我们想做的是:无论get请求或者是post请求提交到Servlet中.就可以直接调用getParameter方法将乱码处理好.(使用动态代理)
Filter的主要代码
public class CodeFilter implements Filter { public void destroy() { // TODO Auto-generated method stub } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { //强制类型转换 final HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; HttpServletRequest myRequest = (HttpServletRequest) Proxy.newProxyInstance(request.getClass().getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equalsIgnoreCase("getParameter")){ //判断是get提交方式还是post提交方式 if(request.getMethod().equalsIgnoreCase("get")){ String value = (String) method.invoke(request, args); value = new String(value.getBytes("iso8859-1"),"utf-8"); return value; }else if(request.getMethod().equalsIgnoreCase("post")){ request.setCharacterEncoding("utf-8"); return method.invoke(request, args); } } return method.invoke(request, args); } }); // pass the request along the filter chain chain.doFilter(myRequest, response); } public void init(FilterConfig fConfig) throws ServletException { }}
知识点补充: 类加载器
类加载器就是将.class文件加载到内存生成Class对象 反射的原理图:
1.2JVM中的三类加载器
- BootStrap:引导类加载器 ,负责加载JRE/lib/rt.jar ( 加载JDK中绝大部分的类)runtime
- ExtClassLoader:扩展类加载器,负责加载JRE/lib/ext/*.jar
- AppClassLoader:应用类加载器,负责加载在classpath环境变量中的所有类,我们自己编写的
1.3父类委托机制
保证了字节码只被加载一次
- Day27-基础加强(注解Annotation、动态代理)
- day27(反射,动态代理,枚举,注解)
- 基础加强- 注解(Annotation)
- Java基础加强---Annotation(注解)
- 基础加强_注解Annotation
- 基础加强—注解(Annotation)
- java基础加强-注解(Annotation)
- 基础加强:类加载器 ---注解 ---动态代理(装饰设计模式)
- 【黑马程序员】java基础加强-------注解(annotation)
- Java基础加强总结--注解(Annotation)
- Java基础加强---动态代理
- Java 基础加强 - 代理与动态代理
- 黑马程序员---基础加强:注解、代理
- Java基础加强_Eclipse、枚举、反射、注解、泛型、类加载器、动态代理
- 黑马程序员-->Java基础加强-->内省(Introspector)与注解(Annotation)
- 黑马程序员---<<基础加强---1.5新特性(中)(注解(Annotation))>>
- Java基础加强总结(一)——注解(Annotation)
- Java基础加强总结(一)——注解(Annotation)
- H5研究六:力学动画/碰撞动画
- android 混淆。
- 那么厉害的个人所得税计算器代码你竟然不点开看看,你膨胀了!
- ElasticSearch 2.4.2
- PHP中实行对数组的串行化和反串行化
- Day27-基础加强(注解Annotation、动态代理)
- CSS的部分基础属性及CSS的部分选择器
- NoSQL之Redis学习笔记
- 点点滴滴巩固 java基础
- Day28-Linux入门01
- 我即将开启的java之路
- poj3026
- QModbusClient
- 关于判断输入的 数是不是整数的问题,然后判断奇偶性。