JavaEE學習日誌持續更新----> 必看!JavaEE學習路線(文章總彙)
Java學習日誌(二十五)
Junit單元測試
Junit單元測試:單獨執行某一個方法
使用步驟:
- 導入Junit的jar包
- 在方法上添加一個@Test註解,並導入test註解所在的包
- 點擊方法左邊的綠色三角/右鍵選擇方法,選擇run執行方法
點擊類左邊的綠色三角/右鍵選擇方法,選擇run執行全部被@Test修飾的方法
Junit的注意事項:
1.沒有被@Test註解修飾的方法,不能使用Junit單獨執行
2.Junit只能執行public void 修飾的空參數方法
Junit相關的註解:
@Test
,用於修飾需要執行的測試方法@Before
,修飾的方法會在測試方法之前被自動執行,用於獲取資源@After
,修飾的方法會在測試方法執行之後自動被執行,用於釋放資源
注意:
@Before和@After修飾的方法,不能單獨執行
代碼示例:
public class Demo03 {
@Test
public void test01() {
System.out.println("test01");
}
@Test
public void test02() {
System.out.println("test02");
}
@Test
public void test03() {
System.out.println("test03");
}
@Before
public void myBefore() {
System.out.println("myBefore");
}
@After
public void myAfter() {
System.out.println("myAfter");
}
}
反射
類加載器
反射的概念與原理
看圖就完事了
獲取class文件對象的方式
獲取class文件對象的方式(重點):
- 可以使用Object類中的方法,獲取class文件對象
Class<?> getClass()
返回此 Object的運行時類。 - 可以使用數據類型.class屬性,獲取class文件對象
java爲每種數據類型,都賦予了一個class屬性
基本數據類型(4類8種):int.class,double.class
引用數據類型(類,接口,數組):Person.class,String.class,ArrayList<String>.class
- 可以使用class類中的靜態方法,獲取class文件對象
static Class<?> forName(String className)
返回與具有給定字符串名稱的類或接口關聯的類對象。
參數:String className:全類名(包名+類名:cn.itcast.demo02.Reflect.Person)
選中類名,右鍵copyReference即可拷貝包名+類名
注意:class文件對象是由類加載器創建的,無論用哪種方法獲取,都是同一個class文件對象,class文件對象只有一個。
代碼示例:Person類
public class Person {
private String name;
private int age;
private Person(String name) {
this.name = name;
System.out.println("Person類的私有構造方法");
}
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person類的滿參數構造方法");
}
public Person() {
System.out.println("Person類的空參數構造方法");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
private void method(){
System.out.println("私有方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
測試類
public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException {
//1.可以使用Object類中的方法,獲取class文件對象
Person p = new Person();
Class c1 = p.getClass();
System.out.println(c1);//class cn.itcast.demo02.Reflect.Person
//2.可以使用數據類型.class屬性,獲取class文件對象
/*int.class;
double.class;
String.class;*/
Class c2 = Person.class;
System.out.println(c2);//class cn.itcast.demo02.Reflect.Person
//3.可以使用class類中的靜態方法,獲取class文件對象
Class c3 = Class.forName("cn.itcast.demo02.Reflect.Person");
System.out.println(c3);//class cn.itcast.demo02.Reflect.Person
//class文件對象只有一個
System.out.println(c1==c2);//true
System.out.println(c1==c3);//true
System.out.println(c2==c3);//true
}
}
Class類中的常用方法
Class類中的常用方法
String getSimpleName()
:獲得簡單類名,只是類名,沒有包String getName()
:獲取全類名,包含包名+類名
在Person類中加入一個靜態代碼塊
static {
System.out.println("靜態代碼塊");
}
代碼示例:獲取class文件對象,會執行類中的靜態代碼塊
public class Demo02 {
public static void main(String[] args) throws ClassNotFoundException {
//獲取class文件對象,會執行類中的靜態代碼塊-->mysql-->JDBC
Class clazz = Class.forName("cn.itcast.demo02.Reflect.Person");
String simpleName = clazz.getSimpleName();
System.out.println(simpleName);//Person
String name = clazz.getName();
System.out.println(name);//cn.itcast.demo02.Reflect.Person
}
}
獲取類中的構造方法並創建對象
使用反射技術獲取類中的構造方法,並使用獲取到的構造方法創建對象
獲取構造方法
實現步驟:
- 獲取類的class文件對象
- 使用class文件對象中的方法
getConstructor/Constructors
獲取類中的構造方法 - 使用Constructor類中的方法newInstance創建對象(實例化對象)
Person類中的三個構造方法:
public Person()
:空參構造
private Person(String name)
:私有構造
public Person(String name, int age)
:滿參構造
成員方法:
構造器<?>[] getConstructors()
返回一個包含構造器對象的數組,構造器對象反映了此類對象所表示的類的所有公共構造函數。構造器<?>[] getDeclaredConstructors()
返回構造器對象的數組,構造器對象反映由此類對象表示的類聲明的所有構造函數(包括私有)。構造器<T> getConstructor(類<?>... parameterTypes)
返回一個 構造器對象,該對象反映此 類對象所表示的類的指定公共構造函數。
參數:類<?>… parameterTypes:可變參數,構造方法參數的class文件對象構造器<T> getDeclaredConstructor(類<?>... parameterTypes)
返回一個構造器對象,該對象反映此類對象所表示的類或接口的指定構造函數(包括私有)。
注意:如果類中沒有指定的構造方法,會拋出NoSuchMethodException異常
代碼示例:獲取類中的構造方法
public class Demo03GetConstructor {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
//1.獲取類的class文件對象
Class<?> clazz = Class.forName("cn.itcast.demo02.Reflect.Person");
//2.使用class文件對象中的方法getConstructor/Constructors獲取類中的構造方法
//構造器<?>[] getConstructors()
Constructor<?>[] cons = clazz.getConstructors();
for (Constructor<?> con : cons) {
System.out.println(con);
}
System.out.println("--------------------");
//構造器<?>[] getDeclaredConstructors()
Constructor<?>[] declaredCons = clazz.getDeclaredConstructors();
for (Constructor<?> con : declaredCons) {
System.out.println(con);
}
System.out.println("--------------------");
//構造器<T> getConstructor(類<?>... parameterTypes)
//public Person()
Constructor<?> con1 = clazz.getConstructor();
System.out.println(con1);//public cn.itcast.demo02.Reflect.Person()
//public Person(String name, int age)
Constructor<?> con2 = clazz.getConstructor(String.class, int.class);
System.out.println(con2);
//構造器<T> getDeclaredConstructor(類<?>... parameterTypes)
//private Person(String name)
Constructor<?> con3 = clazz.getDeclaredConstructor(String.class);
System.out.println(con3);
}
}
newInstance方法創建對象
java.lang.reflect.Constructor :描述構造方法的類
使用Constructor類中的方法newInstance創建對象(實例化對象)
成員方法:
T newInstance(Object... initargs)
:實例化對象,創建對象
參數:Object... initargs:可變參數,構造方法創建對象實際使用的參數
返回值:T:創建好的對象,類型使用Object類型
私有的構造方法,沒有權限訪問,執行的時候有權限檢查,會拋出
IllegalAccessException非法訪問異常
。
可以使用Constructor的父類中的方法解決這個問題
Constructor extends AccessibleObject
void setAccessible(boolean flag)
將此反射對象的 accessible標誌設置爲指示的布爾值。
- true:表示反射對象在使用時應禁止檢查Java語言訪問控制
- false:表示反射對象在使用時應強制檢查Java語言訪問控制
代碼示例:
public class Demo03GetConstructor {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.獲取類的class文件對象
Class<?> clazz = Class.forName("cn.itcast.demo02.Reflect.Person");
//2.使用class文件對象中的方法getConstructor/Constructors獲取類中的構造方法
//構造器<?>[] getConstructors()
Constructor<?>[] cons = clazz.getConstructors();
for (Constructor<?> con : cons) {
System.out.println(con);
}
System.out.println("--------------------");
//構造器<?>[] getDeclaredConstructors()
Constructor<?>[] declaredCons = clazz.getDeclaredConstructors();
for (Constructor<?> con : declaredCons) {
System.out.println(con);
}
System.out.println("--------------------");
//構造器<T> getConstructor(類<?>... parameterTypes)
//public Person()
Constructor<?> con1 = clazz.getConstructor();
System.out.println(con1);//public cn.itcast.demo02.Reflect.Person()
//public Person(String name, int age)
Constructor<?> con2 = clazz.getConstructor(String.class, int.class);
System.out.println(con2);
//構造器<T> getDeclaredConstructor(類<?>... parameterTypes)
//private Person(String name)
Constructor<?> con3 = clazz.getDeclaredConstructor(String.class);
System.out.println(con3);
//3.使用Constructor類中的方法newInstance創建對象(實例化對象)
/*
java.lang.reflect.Constructor<T> :描述構造方法的類
T newInstance(Object... initargs) :實例化對象,創建對象
參數:Object... initargs:可變參數,構造方法創建對象實際使用的參數
返回值:T:創建好的對象,類型使用Object類型
*/
//public Person()
Object obj1 = con1.newInstance();//此方法相當於new Person();
System.out.println(obj1);//Person{name='null', age=0}
/*Person p = (Person)obj1;
System.out.println(p);////Person{name='null', age=0}*/
//public Person(String name, int age)
Object obj2 = con2.newInstance("老王",18);//此方法相當於new Person("老王",18);
System.out.println(obj2);
/*
私有的構造方法,沒有權限訪問,執行的時候有權限檢查,會拋出
IllegalAccessException非法訪問異常。
可以使用Constructor的父類中的方法解決這個問題
Constructor extends AccessibleObject
void setAccessible(boolean flag) 將此反射對象的 accessible標誌設置爲指示的布爾值。
值true表示反射對象在使用時應禁止檢查Java語言訪問控制。
值false表示反射對象在使用時應強制檢查Java語言訪問控制
注意:暴力反射不建議使用,破壞了類的封裝性
*/
//private Person(String name)
con3.setAccessible(true);//取消con3構造方法的權限檢查-->暴力反射
Object obj3 = con3.newInstance("老張");
System.out.println(obj3);
}
}
簡便寫法–>直接創建空參構造
使用反射技術獲取構造方法並創建對象的簡便方式:
Class類中的成員方法:
T newInstance()
直接獲取空參構造並創建對象返回,省略了獲取Constructor的過程
使用前提:
- 類中必須有空參構造
- 空參數構造方法的修飾符不能是private,建議使用public
代碼示例:
public class Demo04 {
public static void main(String[] args) throws Exception {
//獲取class文件對象
Class<?> clazz = Class.forName("cn.itcast.demo02.Reflect.Person");
//直接使用newInstance方法獲取對象
Object obj = clazz.newInstance();
System.out.println(obj);
//取代了
Object obj2 = clazz.getDeclaredConstructor().newInstance();
System.out.println(obj2);
}
}
獲取類中的成員方法並執行
獲取成員方法
使用反射技術獲取類中的成員方法,並執行
執行步驟
- 獲取類的class文件對象
- 使用class文件對象中的方法getMethod/getMethods獲得成員方法
- 使用Method類中的方法invoke執行獲取到的成員方法
Person類中的成員方法:
public String getName()
public void setName(String name)
private void method()
Class類中的方法:
-
方法[] getMethods()
獲取類中所有公共的成員方法,包括父類和接口中的 -
方法[] getDeclaredMethods()
返回一個包含 方法對象的數組, 方法對象反映此 類對象表示的類或接口的所有已聲明方法,包括public,protected,default(package)訪問和私有方法,但不包括繼承的方法。 -
方法 getMethod(String name, 類<?>... parameterTypes)
獲取指定的公共成員方法 -
方法 getDeclaredMethod(String name, 類<?>... parameterTypes)
返回 方法對象,該對象反映此 類對象表示的類或接口的指定聲明方法。參數: String name:方法名稱 類<?>... parameterTypes:成員方法參數列表的class文件對象
注意:類中沒有指定的成員方法,會拋出NoSuchMethodException
代碼示例:
public class Demo05 {
public static void main(String[] args) throws NoSuchMethodException {
//1.獲取類的class文件對象
Class clazz = Person.class;
//2.使用class文件對象中的方法getMethod/getMethods獲得成員方法
/*
方法[] getMethods() 獲取類中所有公共的成員方法,包括父類和接口中的
方法[] getDeclaredMethods() 返回一個包含 方法對象的數組, 方法對象反映此 類對象表示的類或接口的所有已聲明方法,包括public,protected,default(package)訪問和私有方法,但不包括繼承的方法。
*/
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("------------------------------------");
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
System.out.println("------------------------------------");
/*
方法 getMethod(String name, 類<?>... parameterTypes)獲取指定的公共成員方法
方法 getDeclaredMethod(String name, 類<?>... parameterTypes) 返回 方法對象,該對象反映此 類對象表示的類或接口的指定聲明方法。
參數:String name:方法名稱
類<?>... parameterTypes:成員方法參數列表的class文件對象
注意:類中沒有指定的成員方法,會拋出NoSuchMethodException
*/
//public String getName()
Method getNameMethod = clazz.getMethod("getName");
System.out.println(getNameMethod);
//public void setName(String name)
Method setNameMethod = clazz.getMethod("setName", String.class);
System.out.println(setNameMethod);
//private void method()
Method privateMethod = clazz.getDeclaredMethod("method");
System.out.println(privateMethod);
}
}
invoke方法執行獲取到的成員方法
java.lang.reflect.Method :描述成員方法的類
Method類中的invoke方法:
Object invoke(Object obj, Object... args)
執行成員方法
參數:
Object obj:invoke方法需要對象支持,執行的是哪個類的方法,就傳遞哪個對象,執行的是Person類的方法,傳遞Person對象(clazz.newInstance())。
Object... args:成員方法執行的時候,需要的實際參數。
返回值:
Object:方法的返回值,如果方法有返回值則返回對應的值,如果沒有返回值,返回null。
注意:私有方法沒有權限執行,有權限檢查,會拋出IllegalAccessException
使用暴力反射,取消權限檢查。
代碼示例:
public class Demo05 {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//1.獲取類的class文件對象
Class clazz = Person.class;
//2.使用class文件對象中的方法getMethod/getMethods獲得成員方法
/*
方法[] getMethods() 獲取類中所有公共的成員方法,包括父類和接口中的
方法[] getDeclaredMethods() 返回一個包含 方法對象的數組, 方法對象反映此 類對象表示的類或接口的所有已聲明方法,包括public,protected,default(package)訪問和私有方法,但不包括繼承的方法。
*/
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("------------------------------------");
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
System.out.println("------------------------------------");
/*
方法 getMethod(String name, 類<?>... parameterTypes)獲取指定的公共成員方法
方法 getDeclaredMethod(String name, 類<?>... parameterTypes) 返回 方法對象,該對象反映此 類對象表示的類或接口的指定聲明方法。
參數:String name:方法名稱
類<?>... parameterTypes:成員方法參數列表的class文件對象
注意:類中沒有指定的成員方法,會拋出NoSuchMethodException
*/
//public String getName()
Method getNameMethod = clazz.getMethod("getName");
System.out.println(getNameMethod);
//public void setName(String name)
Method setNameMethod = clazz.getMethod("setName", String.class);
System.out.println(setNameMethod);
//private void method()
Method privateMethod = clazz.getDeclaredMethod("method");
System.out.println(privateMethod);
System.out.println("----------------------------------");
//3.使用Method類中的方法invoke執行獲取到的成員方法
/*
java.lang.reflect.Method :描述成員方法的類
Object invoke(Object obj, Object... args) 執行成員方法
參數:Object obj:invoke方法需要對象支持,執行的是哪個類的方法,就傳遞哪個對象
執行的是Person類的方法,傳遞Person對象(clazz.newInstance())
Object... args:成員方法執行的時候,需要的實際參數
返回值:Object:方法的返回值
如果方法有返回值則返回對應的值,如果沒有返回值,返回null
*/
Object obj = clazz.newInstance();
//public String getName()
Object v1 = getNameMethod.invoke(obj);//此方法相當於執行了getName方法
System.out.println("v1:"+v1);//v1:null
////public void setName(String name)
Object v2 = setNameMethod.invoke(obj,"老王");//此方法相當於執行了setName方法,給成員遍歷賦值
System.out.println("v2:"+v2);//v2:null 方法沒有返回值
System.out.println(obj);
/*
私有方法沒有權限執行,有權限檢查,會拋出IllegalAccessException
使用暴力反射,取消權限檢查
*/
privateMethod.setAccessible(true);
//private void method()
privateMethod.invoke(obj);
}
}