前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java基础第十八篇之单元测试、注解和动态代理

java基础第十八篇之单元测试、注解和动态代理

作者头像
海仔
发布2019-08-05 18:40:30
4250
发布2019-08-05 18:40:30
举报
文章被收录于专栏:海仔技术驿站

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){

代码语言:javascript
复制
		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及以后版本引入

代码语言:javascript
复制
注解的作用:
	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;

代码语言:javascript
复制
	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 {

代码语言:javascript
复制
public int add(int a , int b){
	return a + b;
}

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

}

代码语言:javascript
复制
自定义注解

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

代码语言:javascript
复制
 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”

代码语言:javascript
复制
//当使用一个有属性的注解时,必须指定属性的值

//一个类可以使用多个注解 //同一个注解一个类只能被使用一次

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

代码语言:javascript
复制
	@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 如果父类使用该注解,子类会继承该注解

代码语言:javascript
复制
//---------------------------------------------
	@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 {

代码语言:javascript
复制
@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); //获取属性值:调用注解中的方法,拿到返回值,就得到属性值

代码语言:javascript
复制
			String value = annotation.myString();
			System.out.println(value);
		}
	}
}

}

package pack07_test;

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

public class TestDemo {

代码语言:javascript
复制
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)

代码语言:javascript
复制
//获取一个类的加载器
	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”); }

代码语言:javascript
复制
//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 {

代码语言:javascript
复制
  }

//------------------------------------------------ //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);

代码语言:javascript
复制
			}
			
		}
	}
}	

//动态代理的步骤 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 {

代码语言:javascript
复制
@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 {

代码语言:javascript
复制
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();

代码语言:javascript
复制
	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()

代码语言:javascript
复制
	//创建一个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 list = new ArrayList();

代码语言:javascript
复制
	list.add("hello");
	list.add("world");
	
	list = myProxy(list);

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

代码语言:javascript
复制
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 obj;

代码语言:javascript
复制
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 {

代码语言:javascript
复制
@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方法");
}

}

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年07月13日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档