基础加强_注解_类加载器_动态代理

Junit单元测试的基本使用:
1.在要执行的方法上添加一个注解@Test
2.注解会报错 解决方式ctrl+1 add junit
3.选中要执行的方法 右键 run as --> junit Test

一次执行多个方法:选中类 右键run as --> Junit Test

Junit单元测试的注意事项:
1.没有添加@Test注解的方法不能使用Junit运行
2.Junit只能运行修饰符为public 返回值类型为void 的空参数方法


和单元测试有关的注解

@Test:单元测试,可以单独的执行某个方法
@Before:在单元测试@Test之前执行 可以用来获取一些资源
@After:在单元测试@Test之后执行 可以用来使用一些资源
注意:@Before和@After不能单独执行 运行@Test他们会自动执行

JDK1.5之后提供的注解
@Deprecated:表示已经过时的
@Deprecated:可以用来修饰类 表示已经过时的类,也可以用来修饰方法 表示已经过时的方法
已经过时的类和方法 可以使用 但是不建议 因为可能存在缺陷 或者被更好的方法取代了

JDK1.5之后提供的注解
@Override:用来测试方法是否为重写的方法
JDK1.5时 @Override只能检测类继承类重写的方法
JDK1.6及以上,@Override即能检测类继承类重写的方法 又能检测类实现接口重写的方法

JDK1.5之后提供的注解
@SuppressWarnings:表示抑制警告(不让警告显示出来)
@SuppressWarnings:使用时必须明确要抑制的是哪个警告
@SuppressWarnings(参数):参数是一个字符串数组
如果只写一个参数 可以忽略{} 如果有多个参数必须使用{}多个参数之间使用逗号隔开
String[] a = {"ac","ds"}
可以抑制的警告有:
rawtypes, 忽略类型安全
unchecked 忽略安全检查
unused 忽略不使用
deprecation 忽略过时
null 忽略空指针
serial 忽略序列号
all 忽略所有
注解 的作用域:可以定义在类上 方法上 代码上
同一个位置只能使用一次同一个注解


自定义注解:使用关键字@interface
定义类:class
定义接口:interface
定义枚举:enum(淘汰)
定义注解:@interface
定义注解的格式:
修饰符 @interface 注解名{
注解的属性;(可以有 可以没有)
定义含有属性的注解:
属性相当于类中的成员变量 成员方法
属性的定义格式:
修饰符 返回值类型(数据类型) 属性名()[default 属性值]
修饰符:固定的格式(类似接口) public abstract 写不写都是 建议写出 增强阅读行
返回值类型:基本数据类型(4类8种)String 类型 Class类型 枚举 注解 以上类型的一维数组
[default 属性值]:[]可选的 属性可以给出默认值 也可以不给默认值
int a; int a = 10;

 1 public @interface MyAnnotation02 {
 2     //基本数据类型(4类8种)
 3     public abstract int a() default 10;
 4     //String类型
 5     public abstract String s();
 6     //Class类型
 7     public abstract Class clazz();
 8     //枚举
 9     public abstract Color c();
10     //注解
11     public abstract MyAnnotation01 myanno01();
12     //以上类型的一维数组
13     public abstract String[] arr();
14 }
15 
16 enum Color{
17     GREEN,
18     RED
19     /*
20      * public static final Color GREEN = new Color();
21      * public static final Color RED = new Color();
22      */
23 }

定义一个含有属性的注解
这个注解只有一个属性 属性的名字叫value

元注解:用来修饰自定义注解的JDK提供的注解
@Retention 用于确定被修饰的自定义注解声明周期
Retention 注解的属性是一个枚举RetentionPolicy(枚举有3个属性SOURCE,CLASS,RUNTIME)
作用:指示注释类型的注释要保留多久
如果注释类型声明中不存在Retention注释 则保留策略默认为RetentionPolicy.CLASS
RetentionPolicy.SOURCE 被修饰的注解只能存在源码中,字节码class没有。用途:提供给编译器使用。
RetentionPolicy.CLASS 被修饰的注解只能存在源码和字节码中,运行时内存中没有。用途:JVM java虚拟机使用
RetentionPolicy.RUNTIME 被修饰的注解存在源码、字节码、内存(运行时)。用途:取代xml配置
@Target 用于确定被修饰的自定义注解使用位置
Target注解的属性是一个枚举ElementType(常用的属性TYPE,CONSTRUCTOR....)
作用:指示注释类型所适用的程序元素的种类。
如果注释类型声明中不存在 Target 元注释,则声明的类型可以用在任一程序元素上。
ElementType.TYPE 修饰类、接口
ElementType.CONSTRUCTOR 修饰构造
ElementType.METHOD 修饰方法
ElementType.FIELD 修饰字段

1 @Retention(RetentionPolicy.RUNTIME)
2 @Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
3 public @interface MyAnnotation03 {
4     public abstract int value();
5 }

使用自定义注解:
格式:@自定义注解的名字(属性名= 属性值 ,属性名=属性值)
注意:
1.自定义注解没有属性,可以直接使用-->@自定义注解的名字
2.自定义注解有属性 使用的时候 必须使用键值对的方式 给所有属性赋值 才能使用 有默认值的属性可以不用赋值
3.如果注释的属性是一个数组 赋值的时候只有一个值可以省略{} 赋值多个必须写出{}
4.注解的使用范围 可以用来修饰类 方法 构造方法 变量
5.使用自定义注解 如果只有一个属性 名字叫value 赋值的时候value可以省略不写
6.一个对象上(修饰类, 方法,构造方法,变量)注解只能使用一次 不能重复使用

自定义注解的解析:使用自定义注解 获取自定义注解的属性值
和解析有关的接口:
java.lang.reflect.AnnotatedElement接口
所有已知实现类:AccessibleObject Class Constructor Field Method Package
接口中的方法:
boolean isAnnotationPresent(Class annotationClass)
如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
判断(Constructor, Field, Method...)有没有指定的注解
参数:注解的class文件对象,可以传递MyAnnotation03.class(String.class,int.class)
T getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
获取(Constructor, Field, Method...)上的注解,参数传递的是哪个注解的class文件对象,就获取哪个注解
参数:注解的class文件对象,可以传递MyAnnotation03.class


使用步骤:
1.定义一个方法,使用自定义注解
2.使用反射技术获取本类的class文件对象
3.使用反射技术获取类中所有的方法
4.遍历包含所有方法的数组,获取每一个方法
5.使用isAnnotationPresent判断该方法上是否包含传递参数的注解
6.如果方法上包含注解,使用getAnnotation获取方法上的注解
7.使用属性的名字,获取属性值

 1 public class UseMyAnnotation02 {
 2     //1.定义一个方法,使用自定义注解
 3     @MyAnnotation03(value=10)
 4     public void method(){
 5         
 6     }
 7     
 8     @Test
 9     public void test(){
10         //2.使用反射技术获取本类的class文件对象
11         Class clazz = UseMyAnnotation02.class;
12         //3.使用反射技术获取类中所有的方法
13         Method[] methods = clazz.getMethods();
14         //4.遍历包含所有方法的数组,获取每一个方法
15         for (Method method : methods) {
16             String methodName = method.getName();
17             //5.使用isAnnotationPresent判断该方法上是否包含传递参数的注解
18             boolean b = method.isAnnotationPresent(MyAnnotation03.class);
19             if(b){
20                 System.out.println(methodName+":"+b);
21                 //6.如果方法上包含注解,使用getAnnotation获取方法上的注解
22                 MyAnnotation03 myAnno = method.getAnnotation(MyAnnotation03.class);
23                 //7.使用属性的名字,获取属性值
24                 int v = myAnno.value();
25                 System.out.println(v);
26             }
27         }
28     }
29 }

类加载器:把class文件加载到内存中 并生成一个class文件对象

加载器的组成:
Bootstrap ClassLoader 引导(根)类加载器
也被称为引导类加载器 负责java核心类的加载
Extension ClassLoader 扩展类加载器
负责人JRE的扩展目录中的jar包的加载
在JDK中JRE的lib目录下井ext目录
AppClassLoader 应用类加载器
负责在JVM启动时加载来自java命令的class文件 以及classpath环境变量
所指定的jar包和类路径
自定义的类型Person; commons-io-2.4.jar
类加载器的继承关系:
AppClassLoader extends ExtClassLoader extends Bootstrap ClassLoader extends ClassLoader
和类加载器有关的方法:
Class类中的方法:
ClassLoader getClassLoader() 返回该类的类加载器。
ClassLoader类中的方法:
ClassLoader getParent() 返回委托的父类加载器。

 1 public class DemoClassLoader {
 2     @Test
 3     public void show01(){
 4         //获取应用类加载器
 5         ClassLoader loader = DemoClassLoader.class.getClassLoader();
 6         System.out.println(loader);//sun.misc.Launcher$AppClassLoader@5fcf29
 7         
 8         loader = loader.getParent();
 9         System.out.println(loader);//sun.misc.Launcher$ExtClassLoader@5fcf29
10         
11         loader = loader.getParent();
12         System.out.println(loader);//根类加载器由c/c++编写,没有相关的类描述,返回null
13     }
14     
15     @Test
16     public void app(){
17         //获取应用类加载器
18         ClassLoader loader = DemoClassLoader.class.getClassLoader();
19         System.out.println(loader);//sun.misc.Launcher$AppClassLoader@5fcf29
20     }
21     
22     @Test
23     public void ext(){
24         //获取扩展类加载器
25         /*
26          * 扩展包中的类,不支持使用
27          * 想使用必须设置访问权限
28          * sun/**
29          */
30         ClassLoader loader = SunEC.class.getClassLoader();
31         System.out.println(loader);//sun.misc.Launcher$ExtClassLoader@19b1de
32     }
33     
34     @Test
35     public void boot(){
36         ClassLoader loader = String.class.getClassLoader();
37         System.out.println(loader);//null
38     }
39 }

JDK动态代理:只能代理接口
java.util.collections集合的工具类
Collections集合的工具类的静态方法
static <T> List<T> unmodifiableList(List<? extends T> list)
返回指定列表的不可修改视图
传递一个List集合返回一个被代理的List集合
unmodifiableList方法就是一个代理方法,代理List集合
如果调用size get方法 没有对集合进行修改 则允许执行
如果调用add remove set 对集合进行了修改,则抛出异常不让方法执行
会抛出UnsupportedOperationException:不支持操作异常

 1 public class Demo01Proxy {
 2     @Test
 3     public void show(){
 4         List<String> list = new ArrayList<String>();
 5         list.add("a");
 6         list.add("b");
 7         
 8         //调用Collections中的方法unmodifiableList
 9         list = Collections.unmodifiableList(list);
10         String s = list.get(0);
11         System.out.println(s);
12         
13         System.out.println(list.size());
14         
15         //list.add("c");
16         //list.remove(0);
17     }
18 }

创建接口InvocationHandler的实现类
重写接口中的方法invoke 对集合的方法进行判断
如果调用size get方法 没有对集合进行修改 则允许执行
如果调用add remove set 对集合进行了修改 则抛出异常不让方法执行
Object invoke(Object proxy,Method method,Object[] args)在代理实例上处理方法调用并返回结果
参数:
Object proxy:内部会使用反射创建一个代理人对象,和我们无关
Method method:内部会使用反射获取到执行List集合的方法(size,get,....)
Object[] args:内部会使用反射获取到调用集合方法的参数
返回值:
Object:调用List集合的方法的返回值

注意事项:
代理的是List集合,必须把被代理的集合传递到实现类中,为了保证代理的始终是同一个List集合
在成员位置创建一个List集合
使用带参数构造给集合赋值

 1 public class InvocationHandlerImpl implements InvocationHandler{
 2     private List<String> list;
 3     
 4     public InvocationHandlerImpl(List<String> list) {
 5         this.list = list;
 6     }
 7 
 8     @Override
 9     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
10         //获取方法的名字
11         String mehtodName = method.getName();
12         //对方法的名字进行判断,如果是add,remove,set就抛出异常
13         if("add".equals(mehtodName)){
14             throw new UnsupportedOperationException("add no run");
15         }
16         
17         if("remove".equals(mehtodName)){
18             throw new UnsupportedOperationException("remove no run");
19         }
20         
21         if("set".equals(mehtodName)){
22             throw new UnsupportedOperationException("set no run");
23         }
24         //如果是size,get执行方法
25         Object obj = method.invoke(list, args);
26         return obj;
27     }
28 
29 }
 1 /*
 2  * 动态代理综合案例:
 3  * 需求:
 4  *     模拟Collections.unmodifiableList(list);
 5  *         传递List,返回List
 6  *         调用List方法的时候,通过我的代理类中的方法 invoke,
 7  *         如果调用size,get方法,没有对集合进行修改,则允许执行
 8  *         如果调用add,remove,set,对集合进行了修改,则抛出异常不让方法执行
 9  *             会抛出UnsupportedOperationException:不支持操作异常
10  * 实现步骤:
11  *     1.模拟unmodifiableList方法,定义一个代理的方法proxyList,参数传递List集合,返回被代理后的List集合
12  *     2.在proxyList方法内部实现动态代理
13  *         java.lang.reflect.Proxy:提供了和动态代理有关的方法
14  *         static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 
15  *             返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。 
16  *         参数:
17  *             ClassLoader loader:传递类加载器,加载类到内存中,创建class文件对象;可以传递本类的类加载器
18  *             Class<?>[] interfaces:传递ArrayList实现的接口List/Collection的Class文件对象
19  *             InvocationHandler h:创建一个InvocationHandler的实现类,重写接口中的方法invoke,对集合的方法进行判断
20  *                 如果调用size,get方法,没有对集合进行修改,则允许执行
21  *                 如果调用add,remove,set,对集合进行了修改,则抛出异常不让方法执行
22  *         返回值类型:
23  *             Object:返回被代理后的List集合
24  */
25 @SuppressWarnings("all")
26 public class Demo02Proxy {
27     /*
28      * 1.模拟unmodifiableList方法,定义一个代理的方法proxyList,参数传递List集合,返回被代理后的List集合
29      */
30     public static List<String> proxyList(List<String> list){
31         //2.在proxyList方法内部实现动态代理,调用Proxy类中的方法newProxyInstance
32         List<String> proxyList = (List<String>) Proxy.newProxyInstance(Demo02Proxy.class.getClassLoader(),
33                 list.getClass().getInterfaces(), new InvocationHandlerImpl(list));
34         return proxyList;
35     }
36     
37     /*
38      * 1.模拟unmodifiableList方法,定义一个代理的方法proxyList,参数传递List集合,返回被代理后的List集合
39      */
40     public static List<String> proxyList02(final List<String> list){
41         //2.在proxyList方法内部实现动态代理,调用Proxy类中的方法newProxyInstance
42         List<String> proxyList = (List<String>) Proxy.newProxyInstance(Demo02Proxy.class.getClassLoader(),
43                 list.getClass().getInterfaces(), new InvocationHandler() {
44                     @Override
45                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
46                         //获取方法的名字
47                         String mehtodName = method.getName();
48                         //对方法的名字进行判断,如果是add,remove,set就抛出异常
49                         if("add".equals(mehtodName)){
50                             throw new UnsupportedOperationException("add no run");
51                         }
52                         
53                         if("remove".equals(mehtodName)){
54                             throw new UnsupportedOperationException("remove no run");
55                         }
56                         
57                         if("set".equals(mehtodName)){
58                             throw new UnsupportedOperationException("set no run");
59                         }
60                         //如果是size,get执行方法
61                         Object obj = method.invoke(list, args);
62                         return obj;
63                     }
64                 });
65         return proxyList;
66     }
67     
68     @Test
69     public void test(){
70         List<String> list = new ArrayList<String>();
71         list.add("a");
72         list.add("b");
73         //调用代理方法proxyList传递list集合
74         //list = Collections.unmodifiableList(list);
75         list = Demo02Proxy.proxyList(list);
76         System.out.println(list.size());
77         System.out.println(list.get(0));
78         //list.add("c");//UnsupportedOperationException:add no run
79         //list.remove(0);//UnsupportedOperationException:remove no run
80         list.set(0, "c");//UnsupportedOperationException:set no run
81     }
82 }
原文地址:https://www.cnblogs.com/caigq/p/7049156.html