java基礎(chǔ)第十八篇之單元測(cè)試、注解和動(dòng)態(tài)代理

1:單元測(cè)試

1)JUnit是一個(gè)Java語言的單元測(cè)試框架,這里的單元指的就是方法

2)單元測(cè)試用來替換以前的main方法

? 1.1 Junit測(cè)試的步驟

? ? 1:在方法的上面加上 @Test

2:將junit庫添加到工程的構(gòu)建路徑

3:選中方法--->右鍵--->JunitTest

? 1.2 常用的Junit測(cè)試注解

常用注解

@Test,用于修飾需要執(zhí)行的方法

@Before,測(cè)試方法前執(zhí)行的方法

@After,測(cè)試方法后執(zhí)行的方法

? 1.3 測(cè)試有返回值的方法

? public int sum(int a, int b){

int sum = a + b;

return sum;

}

@Test

public void testSum(){

int result = sum(10, 10);

//斷言,如果條件成立,則程序正常,如果條件不成立,則程序直接結(jié)束

//參1:期望的值 參2:實(shí)際得到的值

assertEquals(20, result);

xxxxxxxxxxxxxxxxxx

}

2:注解(Annotation)

注解可以理解成一個(gè)符號(hào)(@注解的名字)

JDK1.5及以后版本引入

注解的作用:

1. 編譯檢查:通過代碼里標(biāo)識(shí)注解,讓編譯器能夠?qū)崿F(xiàn)基本的編譯檢查

2. 編寫文檔:通過代碼里標(biāo)識(shí)注解,輔助生成幫助文檔對(duì)應(yīng)的內(nèi)容 (@Document)

2.1 注解的分類

JDK提供的注解

1.@Deprecated 表示被修飾的方法已經(jīng)過時(shí)。過時(shí)的方法不建議使用,但仍可以使用。

? ? ? ? ? ? ? 一般過時(shí)的方法都有一個(gè)新的方法來替換

2.@Override? 類的重寫

3:@SuppressWarnings("all"),表示抑制警告,被修飾的類或方法如果存在編譯警告,將被編譯器忽略

deprecation ,或略過時(shí)

rawtypes ,忽略類型安全(沒有加泛型)

unused ,忽略不使用

unchecked ,忽略安全檢查(沒有泛型,還添加數(shù)據(jù))

null,忽略空指針(空指針去調(diào)用方法 )

package pack02_annotation;

import java.io.Serializable;

import java.util.ArrayList;

@SuppressWarnings("all") //對(duì)整個(gè)類起作用

public class Demo02JDKAnnotation implements Serializable{

// @SuppressWarnings("unchecked") //對(duì)整個(gè)方法起作用

// @SuppressWarnings({"unused", "rawtypes","unchecked", "null"})

public static void main(String[] args) {

//參數(shù)表示出現(xiàn)警告的原因

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:表示實(shí)際得到的值

//如果兩個(gè)值一致,程序正常結(jié)束,如果不一致程序直接終止

assertEquals(31, result);

}

}

自定義注解

3:自定義注解

? 定義注解使用關(guān)鍵字: @interface ?

? ? public @interface MyAnnotation {

}

//使用注解

@MyAnnotation

@MyAnnotation1

class Demo{

public void func(){

}

}

//------------------------------

@MyAnnotation1

@MyAnnotation2

public void func(){

}

3.2 給注解添加屬性

2. 返回值類型:基本類型、字符串String、Class、注解、枚舉,以及以上類型的一維數(shù)組

public @interface MyAnnotation {

//屬性格式:修飾符 返回值類型 屬性名()? [default 默認(rèn)值]

//1修飾符:默認(rèn)值 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 { //反編譯之后,其實(shí)是接口

//給注解添加屬性

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

}

//如果一個(gè)注解只有一個(gè)屬性,并且名字為value,? 則可以不用加屬性名

@MyAnnotation4("hello")

class Demo2{

}

? 注解使用的注意事項(xiàng):

? 注解可以沒有屬性,如果有屬性需要使用小括號(hào)括住。例如:@MyAnno1或@MyAnno1()

? 屬性格式:屬性名=屬性值,多個(gè)屬性使用逗號(hào)分隔。例如:@MyAnno2(username="rose")

? 如果屬性名為value,且當(dāng)前只有一個(gè)屬性,value可以省略。

? 如果使用多個(gè)屬性時(shí),k的名稱為value不能省略

? 如果屬性類型為數(shù)組,設(shè)置內(nèi)容格式為:{ 1,2,3 }。例如:arrs = {"baidu","baidu"}

? 如果屬性類型為數(shù)組,值只有一個(gè){} 可以省略的。例如:arrs = "baidu"

//當(dāng)使用一個(gè)有屬性的注解時(shí),必須指定屬性的值

//一個(gè)類可以使用多個(gè)注解

//同一個(gè)注解一個(gè)類只能被使用一次

? 2.5 注解的解析

? ? ? 1:獲取注解的屬性值

JDK提供java.lang.reflect.AnnotatedElement接口允許在運(yùn)行時(shí)通過反射獲得注解。

@interface MyAnnotation{

}

Class對(duì)象? ? ? ? ? ? ? ? ? ? ? //MyAnnotation.class

? ? Method :? 判斷方法上是否有這個(gè)注解,參數(shù)為注解的Class對(duì)象

Class? :? 判斷類上是否有這個(gè)注解,參數(shù)為注解的Class對(duì)象

boolean isAnnotationPresent(Class annotationClass) 當(dāng)前對(duì)象(方法,類)是否有注解


Class :獲取類上的注解,? 參數(shù)表示要獲取的注解的Class對(duì)象

? ? Method:獲取方法上的注解, 參數(shù)表示要獲取的注解的Class對(duì)象 //MyAnnotation.class

? ? ? public <T extends Annotation> T getAnnotation(Class<T> annotationClass) //獲取注解對(duì)象

3:元注解

? 是對(duì)注解的注解

JDK提供4種元注解:

? @Retention 用于確定被修飾的自定義注解生命周期(注解從生效到消失)

? RetentionPolicy.SOURCE 被修飾的注解只能存在源碼中,字節(jié)碼class沒有。用途:提供給編譯器使用。

? RetentionPolicy.CLASS 被修飾的注解只能存在源碼和字節(jié)碼中,運(yùn)行時(shí)內(nèi)存中沒有。用途:JVM java虛擬機(jī)使用

? RetentionPolicy.RUNTIME 被修飾的注解存在源碼、字節(jié)碼、內(nèi)存(運(yùn)行時(shí))。用途:通過反射獲取屬性值

默認(rèn)的聲明周期是: RetentionPolicy.CLASS

? ? 當(dāng)我們自定義一個(gè)注解,需要為注解加聲明周期:RetentionPolicy.RUNTIME

? 3.2 注解的修改目標(biāo)

? ElementType.TYPE 修飾類、接口

? ElementType.CONSTRUCTOR? 修飾構(gòu)造

? ElementType.METHOD 修飾方法

? ElementType.FIELD 修飾字段

? @Documented 使用javaDoc生成 api文檔時(shí),是否包含此注解

@Inherited 如果父類使用該注解,子類會(huì)繼承該注解

//---------------------------------------------

@Retention(RetentionPolicy.RUNTIME) //指定注解的聲明周期

@Target({ElementType.TYPE, ElementType.METHOD}) //指定注解的作用目標(biāo)

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;

//元注解:是對(duì)注解的注解

//自定義一個(gè)注解時(shí)要給該注解設(shè)置生命周期

@Retention(RetentionPolicy.RUNTIME) //注解可以到內(nèi)存中,就可以反射

//給自定義的注解設(shè)置修飾的目標(biāo): 該注解既可以修飾類,也可以修飾方法

//默認(rèn)情況下,注解可以修飾一切

@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對(duì)象

Class<?> clazz = UseAnnotation.class;

//2:判斷類上是否有@MyAnnotation注解

boolean bl = clazz.isAnnotationPresent(MyAnnotation.class);

if(bl){

//3:獲取注解

MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);

//4:調(diào)用方法

String value = annotation.myString();

System.out.println(value);

}

}

//在該方法中獲取注解的屬性值

@Test

public void parseAnno(){

//1:獲取類的Class對(duì)象

Class<?> clazz = UseAnnotation.class;

//2:因?yàn)椴恢滥膫€(gè)方法有注解,所以需要獲取所有的方法

Method[] methods = clazz.getMethods();

//3:遍歷數(shù)組,判斷哪個(gè)方法有注解

for (Method method : methods) {

//這里的參數(shù)要指定獲取的是哪一個(gè)注解

boolean bl = method.isAnnotationPresent(MyAnnotation.class);

// System.out.println(method.getName()+":"+bl);

if(bl){

//表示該方法加了MyAnnotation注解

//獲取注解:參數(shù)要指定獲取的是哪一個(gè)注解

//本質(zhì)上獲取注解就是獲取注解注解 接口的實(shí)現(xiàn)類對(duì)象

MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);

//獲取屬性值:調(diào)用注解中的方法,拿到返回值,就得到屬性值

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對(duì)象

Class<?> clazz = UseAnnotation.class;

Object obj = clazz.newInstance();

//2:獲取所有的方法

Method[] methods = clazz.getMethods();

for (Method method : methods) {

//判斷哪個(gè)方法有注解

boolean bl = method.isAnnotationPresent(MyTest.class);

if(bl){

//如果 哪個(gè)方法加了這個(gè)注解,就執(zhí)行哪個(gè)方法

//加了注解之后,還要獲取屬性值

MyTest annotation = method.getAnnotation(MyTest.class);

String value = annotation.value();

//只有屬性值是run 才能運(yùn)行

if(value.equals("run")){

method.invoke(obj);

}

}

}

}

}

4:類加載器

引導(dǎo)類加載器:BootstrapClassLoader // 加載的是核心類,加載 jdk/jre/lib/rt.jar

擴(kuò)展類加載器:ExtClassLoader? ? ? //加載擴(kuò)展類, jdk/jre/lib/ext/

應(yīng)用類加載器:AppClassLoader? ? ? //加載應(yīng)用類(HelloWorld? TestDemo)

//獲取一個(gè)類的加載器

TestDemo.class.getClassLoader()

加載原則:

全盤負(fù)責(zé)制: A類要使用B類,A類必須負(fù)責(zé)加載B類中所有的類

? TestDemo --->String 類

父親委托制:子類要使用某個(gè)類,先要委托父類先加載,如果父類沒有加載成功,則子類才會(huì)加載

? 盤負(fù)責(zé)委托機(jī)制保證一個(gè)class文件只會(huì)被加載一次,形成一個(gè)Class對(duì)象。

class F

{

Demo demo;

}

class Zi extends Fu

{

Demo demo2();

}

new ZI();

///--------------------

? class A

? {

? String str;

? }

? class B

? {

? A a;

? }

5:動(dòng)態(tài)代理


? 作用

? ? //1:在不改變一個(gè)類源碼的情況下,去對(duì)類中的方法進(jìn)行功能增強(qiáng)

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:在不改變一個(gè)類源碼的情況下,屏蔽類中的某些功能

class Demo

{

public void method(){

//System.out.println("功能1");

//System.out.println("功能2");

System.out.println("功能3");

}

}

動(dòng)態(tài)代理的特點(diǎn):

1:動(dòng)態(tài)代理基于接口機(jī)制

2: Proxy 代理類

? /*

? 參1:表示類加載器

? 參2:表示實(shí)現(xiàn)的接口

? 參3: 接口

? */

? public static Object newProxyInstance(ClassLoader loader,

Class<?>[] interfaces,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? InvocationHandler h)



//-------------------------------------

@Retention(RetentionPolicy.RUNTIME) //指定注解的聲明周期

@Target({ElementType.TYPE, ElementType.METHOD}) //指定注解的作用目標(biāo)

public @interface MyAnnotation2 {

? }

//------------------------------------------------

//1:反射判斷哪個(gè)方法有注解

Class<?> clazz = UseAnnotation.class;

TreeMap<Integer, Method> tm = new TreeMap<Integer, Method>();

//創(chuàng)建對(duì)象

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,則運(yùn)行該方法

if(value.equals("run")){

// method.invoke(obj);

}

}

}

}

//動(dòng)態(tài)代理的步驟

1:寫一個(gè)接口? ? ? //List

public interface Sing

{

public abstract void sing();

}

2:一個(gè)類實(shí)現(xiàn)接口? //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:動(dòng)態(tài)代理

3.1 必須創(chuàng)建一個(gè)被代理對(duì)象

Sing singer = new Singer();

? ? 3.2 開始動(dòng)態(tài)代理

//代理類也實(shí)現(xiàn)了Sing接口,并創(chuàng)建接口的實(shí)現(xiàn)類對(duì)象

Sing singer = (Sing)Proxy.newProxyInstance()


//創(chuàng)建一個(gè)InvocationHandler接口的實(shí)現(xiàn)類,并在invoke方法中,指定你要增強(qiáng)的方法

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

//創(chuàng)建被代理類對(duì)象

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("你不能調(diào)用add方法");

}

if(method.getName().equals("set")){

throw new RuntimeException("你不能調(diào)用set方法");

}

if(method.getName().equals("remove")){

throw new RuntimeException("你不能調(diào)用remove方法");

}

//其他方法正常調(diào)用

Object result = method.invoke(obj, args);

return result;

}

}

作業(yè):

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方法");

}

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 課程地址:Java基礎(chǔ)之 — 反射(非常重要) (使用的前提條件:必須先得到代表的字節(jié)碼的Class,Cla...
    叨唧唧的閱讀 765評(píng)論 0 2
  • 什么是注解(Annotation):Annotation(注解)就是Java提供了一種元程序中的元素關(guān)聯(lián)任何信息和...
    九尾喵的薛定諤閱讀 3,415評(píng)論 0 2
  • Java是一種可以撰寫跨平臺(tái)應(yīng)用軟件的面向?qū)ο蟮某绦蛟O(shè)計(jì)語言。Java 技術(shù)具有卓越的通用性、高效性、平臺(tái)移植性和...
    Java小辰閱讀 745評(píng)論 1 2
  • 本文包括:1、Listener簡(jiǎn)介2、Servlet監(jiān)聽器3、監(jiān)聽三個(gè)域?qū)ο髣?chuàng)建和銷毀的事件監(jiān)聽器4、監(jiān)聽三個(gè)域?qū)?..
    廖少少閱讀 6,654評(píng)論 6 28
  • 我回來了,但也沒人知道我走了 為了四級(jí),第四次四級(jí)。做了套模擬題只考了360分,意味著我這次還可能不過,一氣之下我...
    我是陳希閱讀 381評(píng)論 6 5

友情鏈接更多精彩內(nèi)容