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