1:单元测试
1)JUnit是一个Java语言的单元测试框架,这里的单元指的就是方法
2)单元测试用来替换以前的main方法

1.1 Junit测试的步骤
1:在方法的上面加上 @Test
2:将junit库添加到工程的构建路径
3:选中方法--->右键--->JunitTest
1.2 常用的Junit测试注解
常用注解
@Test,用于修饰需要执行的方法
@Before,测试方法前执行的方法
@After,测试方法后执行的方法
1.3 测试有返回值的方法
public int sum(int a, int b){

int sum = a + b;
return sum;
}

@Test
public void testSum(){
int result = sum(10, 10);
//断言,如果条件成立,则程序正常,如果条件不成立,则程序直接结束
//参1:期望的值 参2:实际得到的值
assertEquals(20, result);

xxxxxxxxxxxxxxxxxx
}

2:注解(Annotation)
注解可以理解成一个符号(@注解的名字)
JDK1.5及以后版本引入

注解的作用:
1. 编译检查:通过代码里标识注解,让编译器能够实现基本的编译检查
2. 编写文档:通过代码里标识注解,辅助生成帮助文档对应的内容 (@Document)

2.1 注解的分类
JDK提供的注解
1.@Deprecated 表示被修饰的方法已经过时。过时的方法不建议使用,但仍可以使用。
一般过时的方法都有一个新的方法来替换
2.@Override 类的重写
3:@SuppressWarnings("all"),表示抑制警告,被修饰的类或方法如果存在编译警告,将被编译器忽略
deprecation ,或略过时
rawtypes ,忽略类型安全(没有加泛型)
unused ,忽略不使用
unchecked ,忽略安全检查(没有泛型,还添加数据)
null,忽略空指针(空指针去调用方法 )

package pack02_annotation;

import java.io.Serializable;
import java.util.ArrayList;

@SuppressWarnings("all") //对整个类起作用
public class Demo02JDKAnnotation implements Serializable{

// @SuppressWarnings("unchecked") //对整个方法起作用
// @SuppressWarnings({"unused", "rawtypes","unchecked", "null"})
public static void main(String[] args) {
//参数表示出现警告的原因
int a = 123;

ArrayList list = new ArrayList();

list.add("hello");

String str = null;

System.out.println(str.length());
}
public static void method(){
int a = 123;
}

}

package pack01_junit;

import static org.junit.Assert.assertEquals;
import static java.lang.Math.*;
import org.junit.Test;
public class Demo02Junit {

public int add(int a , int b){
return a + b;
}

@Test
public void testAdd(){
int result = add(10, 20);
//断言
//参1:表示期望得到的值
//参2:表示实际得到的值
//如果两个值一致,程序正常结束,如果不一致程序直接终止
assertEquals(31, result);
}
}

自定义注解

3:自定义注解
 定义注解使用关键字: @interface 

public @interface MyAnnotation {

}

//使用注解
@MyAnnotation
@MyAnnotation1
class Demo{
public void func(){

}
}
//------------------------------
@MyAnnotation1
@MyAnnotation2
public void func(){

}
3.2 给注解添加属性
2. 返回值类型:基本类型、字符串String、Class、注解、枚举,以及以上类型的一维数组
public @interface MyAnnotation {
//属性格式:修饰符 返回值类型 属性名() [default 默认值]
//1修饰符:默认值 public abstract ,且只能是public abstract。
public abstract String myString();
public abstract int myInt() default 123;
}

//-----------------例子-------------------------------
enum MyEnum{
Red,Blue
//public static final MyEnum Red = new MyEnum();
//public static final MyEnum Blue = new MyEnum();
}
public @interface MyAnnotation { //反编译之后,其实是接口
//给注解添加属性
public abstract int myInt() default 123; //类似于该方法的返回值
public abstract String myString();
public abstract Class myClass();
public abstract MyAnnotation3 myAnno();
public abstract MyEnum myEnum();

public abstract int[] myIntArray();

}

2.4 自定义注解:使用
@注解类名( 属性名= 值 , 属性名 = 值 , .....)

//-------------例子------------------------------
public @interface MyAnnotation4 {
public abstract String value();
}

//如果一个注解只有一个属性,并且名字为value, 则可以不用加属性名
@MyAnnotation4("hello")
class Demo2{

}

 注解使用的注意事项:
 注解可以没有属性,如果有属性需要使用小括号括住。例如:@MyAnno1或@MyAnno1()
 属性格式:属性名=属性值,多个属性使用逗号分隔。例如:@MyAnno2(username="rose")
 如果属性名为value,且当前只有一个属性,value可以省略。
 如果使用多个属性时,k的名称为value不能省略
 如果属性类型为数组,设置内容格式为:{ 1,2,3 }。例如:arrs = {"baidu","baidu"}
 如果属性类型为数组,值只有一个{} 可以省略的。例如:arrs = "baidu"

//当使用一个有属性的注解时,必须指定属性的值
//一个类可以使用多个注解
//同一个注解一个类只能被使用一次

2.5 注解的解析
1:获取注解的属性值
JDK提供java.lang.reflect.AnnotatedElement接口允许在运行时通过反射获得注解。

@interface MyAnnotation{
}
Class对象 //MyAnnotation.class
Method : 判断方法上是否有这个注解,参数为注解的Class对象
Class : 判断类上是否有这个注解,参数为注解的Class对象
boolean isAnnotationPresent(Class annotationClass) 当前对象(方法,类)是否有注解

Class :获取类上的注解, 参数表示要获取的注解的Class对象
Method:获取方法上的注解, 参数表示要获取的注解的Class对象 //MyAnnotation.class
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) //获取注解对象

3:元注解
是对注解的注解
JDK提供4种元注解:
 @Retention 用于确定被修饰的自定义注解生命周期(注解从生效到消失)
 RetentionPolicy.SOURCE 被修饰的注解只能存在源码中,字节码class没有。用途:提供给编译器使用。
 RetentionPolicy.CLASS 被修饰的注解只能存在源码和字节码中,运行时内存中没有。用途:JVM java虚拟机使用
 RetentionPolicy.RUNTIME 被修饰的注解存在源码、字节码、内存(运行时)。用途:通过反射获取属性值
默认的声明周期是: RetentionPolicy.CLASS
当我们自定义一个注解,需要为注解加声明周期:RetentionPolicy.RUNTIME

3.2 注解的修改目标
 ElementType.TYPE 修饰类、接口
 ElementType.CONSTRUCTOR 修饰构造
 ElementType.METHOD 修饰方法
 ElementType.FIELD 修饰字段
 @Documented 使用javaDoc生成 api文档时,是否包含此注解
@Inherited 如果父类使用该注解,子类会继承该注解

//---------------------------------------------
@Retention(RetentionPolicy.RUNTIME) //指定注解的声明周期
@Target({ElementType.TYPE, ElementType.METHOD}) //指定注解的作用目标
public @interface MyAnnotation2 {

}

package pack05_parse_annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//元注解:是对注解的注解

//自定义一个注解时要给该注解设置生命周期
@Retention(RetentionPolicy.RUNTIME) //注解可以到内存中,就可以反射

//给自定义的注解设置修饰的目标: 该注解既可以修饰类,也可以修饰方法
//默认情况下,注解可以修饰一切
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyAnnotation {
public abstract String myString();
}

package pack05_parse_annotation;

import java.lang.reflect.Method;

import org.junit.Test;

@MyAnnotation(myString="类上的注解属性值")
public class UseAnnotation {

@MyAnnotation(myString="方法上的注解属性值")
public void func1(){
System.out.println("func1方法");
}

public void func2(){
System.out.println("func2方法");
}

@Test
public void parseAnnoClass(){
//1:获取类的CLass对象
Class<?> clazz = UseAnnotation.class;

//2:判断类上是否有@MyAnnotation注解
boolean bl = clazz.isAnnotationPresent(MyAnnotation.class);
if(bl){
//3:获取注解
MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);
//4:调用方法
String value = annotation.myString();
System.out.println(value);
}
}

//在该方法中获取注解的属性值
@Test
public void parseAnno(){
//1:获取类的Class对象
Class<?> clazz = UseAnnotation.class;

//2:因为不知道哪个方法有注解,所以需要获取所有的方法
Method[] methods = clazz.getMethods();
//3:遍历数组,判断哪个方法有注解
for (Method method : methods) {
//这里的参数要指定获取的是哪一个注解
boolean bl = method.isAnnotationPresent(MyAnnotation.class);
// System.out.println(method.getName()+":"+bl);
if(bl){
//表示该方法加了MyAnnotation注解
//获取注解:参数要指定获取的是哪一个注解
//本质上获取注解就是获取注解注解 接口的实现类对象
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
//获取属性值:调用注解中的方法,拿到返回值,就得到属性值

String value = annotation.myString();
System.out.println(value);
}
}
}
}

package pack07_test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestDemo {

public static void main(String[] args) throws Exception {
//1:获取使用注解方法所在类Class对象
Class<?> clazz = UseAnnotation.class;

Object obj = clazz.newInstance();
//2:获取所有的方法
Method[] methods = clazz.getMethods();

for (Method method : methods) {
//判断哪个方法有注解
boolean bl = method.isAnnotationPresent(MyTest.class);
if(bl){
//如果 哪个方法加了这个注解,就执行哪个方法
//加了注解之后,还要获取属性值
MyTest annotation = method.getAnnotation(MyTest.class);
String value = annotation.value();
//只有属性值是run 才能运行
if(value.equals("run")){
method.invoke(obj);
}
}
}
}

}

4:类加载器
引导类加载器:BootstrapClassLoader // 加载的是核心类,加载 jdk/jre/lib/rt.jar
扩展类加载器:ExtClassLoader //加载扩展类, jdk/jre/lib/ext/
应用类加载器:AppClassLoader //加载应用类(HelloWorld TestDemo)

//获取一个类的加载器
TestDemo.class.getClassLoader()

加载原则:
全盘负责制: A类要使用B类,A类必须负责加载B类中所有的类
TestDemo --->String 类
父亲委托制:子类要使用某个类,先要委托父类先加载,如果父类没有加载成功,则子类才会加载
盘负责委托机制保证一个class文件只会被加载一次,形成一个Class对象。

class F
{
Demo demo;
}

class Zi extends Fu
{
Demo demo2();
}

new ZI();

///--------------------
class A
{
String str;
}

class B
{
A a;
}
5:动态代理

作用
//1:在不改变一个类源码的情况下,去对类中的方法进行功能增强
class Demo
{
public void method(){
System.out.println("功能1");
}
}

//---------------------------------
public void method(){
System.out.println("功能1");
System.out.println("功能2");
System.out.println("功能3");
}

//2:在不改变一个类源码的情况下,屏蔽类中的某些功能
class Demo
{
public void method(){
//System.out.println("功能1");
//System.out.println("功能2");
System.out.println("功能3");
}
}

动态代理的特点:
1:动态代理基于接口机制
2: Proxy 代理类
/*
参1:表示类加载器
参2:表示实现的接口
参3: 接口
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)

//-------------------------------------
@Retention(RetentionPolicy.RUNTIME) //指定注解的声明周期
@Target({ElementType.TYPE, ElementType.METHOD}) //指定注解的作用目标
public @interface MyAnnotation2 {

}

//------------------------------------------------
//1:反射判断哪个方法有注解
Class<?> clazz = UseAnnotation.class;
TreeMap<Integer, Method> tm = new TreeMap<Integer, Method>();
//创建对象
Object obj = clazz.newInstance();
//2:获取所有的方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
boolean bl = method.isAnnotationPresent(MyAnnotation.class);
if(bl){
//还要判断属性值是否是:run
//获取属性值
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
String value = annotation.value();
//如果注解的属性值是run,则运行该方法
if(value.equals("run")){
// method.invoke(obj);

}

}
}
}

//动态代理的步骤
1:写一个接口 //List
public interface Sing
{
public abstract void sing();
}

2:一个类实现接口 //ArrayList
class Singer implements Sing
{
public void sing(){
//唱歌
}
}

package com.baidu_05;

public interface RunnCode {
public abstract void run();
}

package com.baidu_05;

public class Demo01 implements RunnCode {

@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i < 10000; i++) {
System.out.println("i=" + i);
}
}

}

package com.baidu_05;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

class MyInn3 implements InvocationHandler {

RunnCode obj;

public MyInn3(RunnCode obj) {
super();
this.obj = obj;
}

public MyInn3() {
super();
// TODO Auto-generated constructor stub
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
long t1 = System.currentTimeMillis();
Object result = method.invoke(obj, args);
long t2 = System.currentTimeMillis();
System.out.println("消耗了:" + (t2-t2) + "毫秒");
return result;
}

}

public class Test2 {
public static void main(String[] args) {
RunnCode rc = new Demo01();

rc.run();

rc = (RunnCode)Proxy.newProxyInstance(rc.getClass().getClassLoader(), rc.getClass().getInterfaces(), new MyInn3(rc));
rc.run();
}

}

3:动态代理
3.1 必须创建一个被代理对象
Sing singer = new Singer();
3.2 开始动态代理
//代理类也实现了Sing接口,并创建接口的实现类对象
Sing singer = (Sing)Proxy.newProxyInstance()

//创建一个InvocationHandler接口的实现类,并在invoke方法中,指定你要增强的方法

t1
func();
t2

package pack12_proxy;

import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

public class Demo02Pproxy {
public static void main(String[] args) {
//创建被代理类对象
List<String> list = new ArrayList<String>();

list.add("hello");
list.add("world");

list = myProxy(list);

// list.add("xxx");
// list.set(0,"xxx");
System.out.println(list.get(0));
}

private static List<String> myProxy(List<String> list) {
@SuppressWarnings("unchecked")
List<String> proxyList=(List<String>)Proxy.newProxyInstance(list.getClass().getClassLoader(),
list.getClass().getInterfaces(), new MyInvocationHandler(list));
return proxyList;
}
}

package pack12_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;

public class MyInvocationHandler implements InvocationHandler {
List<String> obj;

public MyInvocationHandler() {
super();
// TODO Auto-generated constructor stub
}

public MyInvocationHandler(List<String> obj) {
super();
this.obj = obj;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//屏蔽add,set,remove方法
if(method.getName().equals("add")){
throw new RuntimeException("你不能调用add方法");
}
if(method.getName().equals("set")){
throw new RuntimeException("你不能调用set方法");
}
if(method.getName().equals("remove")){
throw new RuntimeException("你不能调用remove方法");
}
//其他方法正常调用
Object result = method.invoke(obj, args);
return result;
}

}

作业:

public class UseAnnotation {

@MyTest("run","first")
public void func1(){
System.out.println("func1方法");
}

@MyTest("run","third")
public void func2(){
System.out.println("func2方法");
}

@MyTest("aaa")
public void func3(){
System.out.println("func3方法");
}
@MyTest("run","second")
public void func4(){
System.out.println("func4方法");
}

@MyTest("run","four")
public void fun5(){
System.out.println("func2方法");
}

}

java基础第十八篇之单元测试、注解和动态代理的更多相关文章

  1. java基础(十八)IO流(一)

    这里有我之前上课总结的一些知识点以及代码大部分是老师讲的笔记 个人认为是非常好的,,也是比较经典的内容,真诚的希望这些对于那些想学习的人有所帮助! 由于代码是分模块的上传非常的不便.也比较多,讲的也是 ...

  2. java基础第十二篇之集合、增强for循环、迭代器和泛型

    Collection接口中的常用方法: * 所有的子类子接口都是具有的 * 集合的方法:增删改查 * * public boolean add(E e);//添加元素 返回值表示是否添加成功 * pu ...

  3. Java基础(十八)集合(5)Queue集合

    队列是只能在尾部添加元素,同时只能在头部删除元素的数据结构.队列的原则就是“先进先出”. Queue接口是Collection接口的最后一个子接口. Queue接口是队列接口,而Deque接口是Que ...

  4. java基础第十九篇之Xml

    1:xml的概述 1.1 xml是什么 标记语言:语言中出现了<a></a>的标签 a:HTML 超文本标记语言 (语法非常严格,不能随意的定义标签) b:XML 可扩展的标记 ...

  5. java基础第十六篇之多线程

    1:线程的概念 进程(任务):一个正在运行的程序 进程的调度:CPU来决定什么时候该运行哪个进程 (时间片轮流法) 线程在一个应用程序中,同时,有多个不同的执行路径,是进程中的实际运作单位. 好处是提 ...

  6. java基础第十五篇之IO流和递归算法

    FileInputStream : 输入流 int available() : 一次读取所有的字节数 read() : 将文件上的字节读取到内存的数组中 FileOutputStream : 输出流 ...

  7. java基础第十四篇之Map

    一,Map集合的特点: *  * 1.Map集合和Collection集合,没有关系 *  * 2.Map集合的元素是成对存在(夫妻关系) *         Collection集合的元素是独立存在 ...

  8. 夯实Java基础(十八)——泛型

    1.什么是泛型 泛型是Java1.5中出现的新特性,也是最重要的一个特性.泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类. ...

  9. Python之路【第十八篇】:Web框架们

    Python之路[第十八篇]:Web框架们   Python的WEB框架 Bottle Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Pytho ...

随机推荐

  1. PostSharp-4.3.33安装包_KeyGen发布

    PostSharp-4.3.33安装包_KeyGen发布 请低调使用. PostSharp安装及注册步骤截图.rar 请把浏览器主页设置为以下地址支持本人.https://www.duba.com/? ...

  2. SQL Server分页存储过程笔记

    USE [database] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[ProcedureN ...

  3. GlusterFS集群文件系统研究(负载均衡的最常用办法) good

    http://blog.csdn.net/liuaigui/article/details/6284551 http://blog.csdn.net/liuaigui/article/details/ ...

  4. Qt中事件处理的顺序

    本站所有文章由本站和原作者保留一切权力,仅在保留本版权信息.原文链接.原文作者的情况下允许转载,转载请勿删改原文内容, 并不得用于商业用途. 谢谢合作.原文链接:Qt中事件处理的顺序 文章内容主要来自 ...

  5. 零元学Expression Blend 4 - Chapter 3 熟悉操作第一步(制作一个猴子脸)

    原文:零元学Expression Blend 4 - Chapter 3 熟悉操作第一步(制作一个猴子脸) 本篇内容会教你如何使用笔刷.钢笔.渐层以及透明度的调整,还有如何转化图层和路径,最重要的是要 ...

  6. MIPS虚拟机代码

    http://download.eeworld.com.cn/download/mamselc/472333http://download.eeworld.com.cn/detail/lamas/36 ...

  7. EnterpriseLibrary 6.0 AOP 使用问题

    因为EnterPrise Library 6.0改动了模块的功能类不再自动从Unity创建了,也就是引导也不依赖Unity容器组件,需要先使用静态方法注册一下 private static void ...

  8. 了解BroadcastRecever

    广播分类: 标准广播(Normal broadcasts):完全异步执行的广播,接收没有先后顺序,效率高,无法被接收器被拦截. 有序广播(Ordered broadcasts) :同步执行的广播,有先 ...

  9. Qt的QWaitCondition(允许线程在一定条件下唤醒其他线程,这样对不间断上传可能比较适用)

    对生产者和消费者问题的另一个解决办法是使用QWaitCondition,它允许线程在一定条件下唤醒其他线程.其中wakeOne()函数在条件满足时随机唤醒一个等待线程,而wakeAll()函数则在条件 ...

  10. Qt之Model-View架构(雨田哥的博客)

    Qt之Model-View架构 Qt之Model-View架构 简述 效果图 代码 结尾 简述 为什么会用这个模式,这里我就不解释了,可以看下 豆子哥的见解 .这里我只是如何去使用的.供大家共同探讨学 ...