日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

单元测试、注解、枚举、反射(5)JavaSE

發布時間:2024/3/7 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 单元测试、注解、枚举、反射(5)JavaSE 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1 JUnit單元測試

1.1 Junit的介紹

Junit屬于白盒測試(白盒測試是對軟件的過程性細節做細致的檢查。這種方法是把測試對象看做一個打開的盒子,它允許測試人員利用程序內部的邏輯結構及有關信息,設計或選擇測試用例,對程序的所有邏輯路徑進行測試,通過在不同點檢查程序狀態,確定實際狀態是否與預期的狀態一致。因此白盒測試又稱為結構測試)。
使用JUnit的原因是因為在沒有使用Junit的時候,有以下缺點:
(1)測試一定走main方法,是程序的入口,main方法的格式必須不能寫錯。
(2)要是在同一個main方法中測試的話,那么不需要測試的東西必須注釋掉。
(3)測試邏輯如果分開的話,需要定義多個測試類,麻煩。
(4)業務邏輯和測試代碼,都混淆了。
而使用Junit就可以在同一個類中定義多個方法,并且增加更多強大的功能。

1.2 Junit的使用

(1)一般測試和業務做一個分離,分離為不同的包,以后測試類就單獨放在這個包下。(建議起名:公司域名倒著寫+test)
(2)測試類的名字:****Test (見名知意)
(3)測試方法的定義:這個方法可以獨立運行,不依托于main方法。(建議:名字見名知意:testAdd() ,testSub()。參數:無參。返回值:void)。
(4)測試方法定義完成后,還不能直接獨立運行,必須在方法上加一個注解:@Test,并且導入JUnit包后,才可以獨立運行。
(5)判定結果是綠色:正常結果。紅色:出現異常。
(6)即使出現綠色效果,也不意味著你的測試就通過了,因為代碼中邏輯也可能出現問題,這種情況怎么解決呢?加入斷言。同理綠色通過,紅色不通過。
EG:做一個對兩個方法(加法和減法)的測試類

import org.junit.Test; import com.jayden.Calculator//對計算器Calculator類定義一個測試類 class CalculatorTest{//對計算器Calculator類中的add加法方法進行測試@Testpublic static void testAdd(){System.out.println("測試add方法");Calculator cal = new Calculator();int result = cal.add(10,30);//加入**斷言**:預測一下結果,判斷一下我預測的結果和 實際的結果是否一致://第一個參數:預測結果 第二個參數:實際結果Assert.assertEquals(40,result);}//對計算器Calculator類中的sub減法方法進行測試public static void testSub(){System.out.println("測試減法方法");Calculator cal = new Calculator();int result = cal.sub(30,10);System.out.println("result");} }

(7)如果需要對一個類中的很多方法進行測試的過程中,這些方法都需要寫一些同樣的代碼,我們如果每一個方法中都寫入這些代碼,就會造成很大的冗余。遇到這種情況就可以使用JUnit中兩個注解@Before和@After。
某一個方法中,加入@Before注解以后,那么這個方法中的功能會在測試方法執行前先執行。一般會在@Beforer修飾的那個方法中加入:加入一些申請資源的代碼:申請數據庫資源,申請IO資源,申請網絡資源等等。
加入了@After注解以后,那么這個方法中的功能會在測試方法執行后先執行。一般會在@After修飾的那個方法中加入:加入釋放資源的代碼:釋放數據庫資源,釋放IO資源,釋放網絡資源等等。

2 注解

2.1 注解的介紹

  • 注解(Annotation,也稱元數據)是在JDK5.0新增的。
  • 它是代碼里面的特殊標記。使用注解時要在其前面增加@符號,并把該注解當成一個修飾符使用。用于修飾它支持的程序元素。這些標記可以在編譯,類加載,運行時被讀取,并執行相應的處理。通過使用注解,程序員可以在不改變原有邏輯的情況下,在源文件中嵌入一些補充信息。代碼分析工具、開發工具和部署工具可以通過這些補充信息進行驗證或者進行部署。
  • Annotation 可用于修飾包,類,構造器,方法,成員變量,參數,局部變量,這些信息被保存在Annotation的"name=value"對中。在JavaSE中,注解的使用目的比較簡單,例如標記過時的功能,忽略警告等。在JavaEE/ArIdroid中注解占據了更重要的角色,例如用來配置應用程序的任何切面,代替JavaEE舊版中所遺留的繁冗代碼和XML配置等。未來的開發模式都是基于注解的,JPA(java的持久化API)是基于注解的,Spring2.5以. E都是基于注解的,Hibernate3.x以后也是基于注解的,現在的Struts2有一部分也是基于注解的了,注解是一種趨勢,一定程度上可以說 :框架=注解+反射+設計模式

2.2 注解的使用

2.2.1 Junit的注解

@Test @Before @After 見1.2

2.2.2 文檔相關的注解

文檔注釋(/** … **/)允許你在程序中嵌入關于程序的信息。需要配合javadoc工具軟件來生成信息,并且顯示在HTML文件中。文檔注解(@author)一般就使用在文檔注釋之中。
javadoc工具一般識別的標簽有

注意:
? @param @return和@exception這三個標記都是只用于方法的。
? @param的格式要求: @param 形參名 形參類型 形參說明
? @return的格式要求: @return 返回值類型返回值說明,如果方法的返回值類型是void就不能寫
? @exception的格式要求: @exception 異常類型異常說明
? @param和@exception可以并列多個

EG:生成一個Person的文檔注釋HTML /*** @author : jayden* @version : 1.0*/ public class Person {/*** 下面是eat方法,實現了XXX功能* @param num1 就餐人數* @param num2 點了幾個菜*/public void eat (int num1,int num2){ }/*** 下面是睡覺方法* @param age 年齡* @return int* @exception RuntimeException 當年齡過大時* @exception IndexOutOfBoundsException 當年齡過小時* @see Student*/public int sleep(int age){new Student();if(age>100){throw new RuntimeException();}if(age<0){throw new IndexOutOfBoundsException();}return 10;} }

IDEA中javadoc的使用:


在指定的目錄輸出后會有很多html文件,index.html就是我們要查看的注解文檔。
注意:防止亂碼:

2.2.3 JDK內置的3個注解

  • @Override: 限定重寫父類方法,該注解只能用于方法,只要重寫方法在父類中有問題,就會有錯誤提示。
  • @Deprecated: 用于表示所修飾的元素(類,方法,構造器,屬性等)已過時。通常是因為所修飾的結構危險或存在更好的選擇。
  • @SuppressWarnnings: 抑制編譯器警告

EG:

class Person{public void eat(){System.out.println("父類eat...");} }public class Student extends Person {/*@Override的作用:限定重寫的方法,只要重寫方法有問題,就有錯誤提示。*/@Overridepublic void eat(){System.out.println("子類eat..");}/*在方法前加入@Deprecated,這個方法就會變成一個廢棄方法/過期方法/過時方法*/@Deprecatedpublic void study(){System.out.println("學習。。");} }class Test{public static void main(String[] args){Student stu = new Student();/*過期方法的用畫橫線提示*/stu.study();@SuppressWarnings("unused")int age = 10; //原本是暗色,變成亮色int num = 10;System.out.println(num); //只要被使用過就會變亮//rwatypes:泛型@SuppressWarnings({"unused","rwatypes"})ArrayList al = new ArrayList();} }

2.2.4 代替配置文件的注解

在servlet3.0之前的配置:
需要專門用一個xml配置文件來設置該Servlet所對應的訪問地址

package com.bjsxt.servlet;import javax.servlet.*; import java.io.IOException;public class HelloServlet implements Servlet {@Overridepublic void init(ServletConfig servletConfig) throws ServletException {}@Overridepublic ServletConfig getServletConfig() {return null;} @Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("service方法被調用了...");}@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {} } <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!--配置Servlet--><!--配置Servlet的信息--><servlet><servlet-name>HelloServlet</servlet-name><servlet-class>com.bjsxt.servlet.HelloServlet</servlet-class></servlet><!--配置Servlet的映射路徑--><servlet-mapping><servlet-name>HelloServlet</servlet-name><!--http://localhost:8080/01-hello-servlet/hello--><url-pattern>/hello</url-pattern></servlet-mapping> </web-app>

在servlet3.0之后使用注解:替代配置文件。
只需要一個@WebServlet注解指定地址即可。

package com.bjsxt.servlet;import javax.servlet.*; import java.io.IOException;@WebServlet("/hello") public class HelloServlet implements Servlet {@Overridepublic void init(ServletConfig servletConfig) throws ServletException {}@Overridepublic ServletConfig getServletConfig() {return null;}/*** 用于提供服務, 接收請求, 處理響應** @param servletRequest* @param servletResponse* @throws ServletException* @throws IOException*/@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("service方法被調用了...");}@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {} }

2.2.5 自定義注解

1.自定義注解使用很少,一般情況下都是用現成的注解。

EG:接口的定義 public @interface MyAnnotation {String[] value(); }

2.發現定義的注解的聲明使用的關鍵字:@interface,跟接口沒有一點關系。
3.這value是屬性看上去是無參數方法,實際上理解為一個成員變量,一個屬性
無參數方法名字看成是成員變量的名字,無參數方法的返回值看成是成員變量的類型。這個參數叫 配置參數
4.無參數方法的類型:基本數據類型(八種),String,枚舉,注解類型,還可以是以上類型對應的數組。

EG:接口的使用

1)使用注解的話,如果你定義了配置參數,就必須給配置參數進行賦值操作:

@MyAnnotation(value={"abc","ccc"}) public class Test { }

2)如果只有一個參數,并且這個參數的名字為value的話,那么value=可以省略不寫。

@MyAnnotation({"abc","ccc"}) public class Test { }

3)如果你給配置參數設置默認的值了,那么使用的時候可以無需傳值:

public @interface MyAnnotation {String[] value() default {"abc","hello"}; } @MyAnnotation() public class Test { }

4)注解可以疊加使用

@MyAnnotation() @MyAnnotation2 public class Test { }

5)一個注解的內部是可以不定義配置參數的。內部沒有定義配置參數的注解叫做標記。內部定義配置參數的注解叫做元數據

public @interface MyAnnotation2 { }

2.2.6 元注解

元注解是用于修飾其它注解的注解。
JDK5.0提供了四種元注解:Retention, Target, Documented, Inherited

EG:元注解使用的例子 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings {String[] value(); }

1)@Retention
@Retention:用于修飾注解,用于指定被修飾注解的生命周期,@Rentention包含一個RetentionPolicy枚舉類型的成員變量,使用@Rentention時必須為該value成員變量指定值。

  • RetentionPolicy.SOURCE: 只在源文件中有效(即源文件保留),編譯器直接丟棄這種策略的注釋,在.class文件中不會保留注解信息(具體表現,反編譯查看字節碼文件:發現字節碼文件中沒有MyAnnotation這個注解。)
  • RetentionPolicy.CLASS: 在class文件中有效(即class保留),保留在.class文件中,但是當運行Java程序時,他就不會繼續加載了,不會保留在內存中,JVM不會保留注解。如果注解沒有加Retention元注解,那么相當于默認的注解就是這種狀態。(反編譯看字節碼文件,字節碼文件中帶有MyAnnotation注解。)
  • RetentionPolicy.RUNTIME:在運行時有效(即運行時保留),當運行 Java程序時,JVM會保留注釋,加載在內存中了,那么程序可以通過反射獲取該注釋。

2)@Target
用于修飾注解的注解,用于指定被修飾的注解能用于修飾哪些程序元素。@Target也包含一個名為value的成員變量。

@Target(ElementType.ANNOTATION_TYPE) public @interface Target {ElementType[] value(); }

ElementType變量是一個枚舉數組,里面包含數據類型,方法,類等。如果要使用@Target標記過的注解@test,那么@test首先就要指定@Target指定的范圍如@Target({TYPE,METHOD}),然后再使用@test注解后就只能再指定類型上使用這個注解

public enum ElementType {TYPE,//類FIELD,//屬性METHOD,//方法PARAMETER,//參數CONSTRUCTOR,//構造器LOCAL_VARIABLE,ANNOTATION_TYPE,//注解類型PACKAGE,//包TYPE_PARAMETER,TYPE_USE } EG: @Target({TYPE}) public @interface MyAnnotation { } @MyAnnotation() //因為@Target指定了TYPE,所以可以作用再類Class上 public class Test {@MyAnnotation() //不能使用int a;@MyAnnotation() //不能使用public static void testOne(){} }

3)@Documented
用于指定被該元注解修飾的注解類將被javadoc工具提取成文檔。默認情況下,javadoc是 不包括注解的,但是加上了這個注解生成的文檔中就會帶著注解了。
4)@Inherited
被它修飾的Annotation將具有繼承性。如果某個類使用了被@Inherited修飾的Annotation,則其子類將自動具有該注解。

3 枚舉

在java中,類的對象是有限個,確定的。這個類我們可以定義為枚舉類。
舉例:
星期:一二三四五六日
性別:男女
季節:春夏秋冬
構造枚舉類的特點:
1.屬性是私有的,而且不可改變
2.構造器也是私有的,不可以隨意構造枚舉類
3.在類中定義枚舉,提供給外界的構造方法是有限的。

3.2 枚舉的構造

在JDK1.5之前,得自定義枚舉類。EG: public class Season {//屬性是私有的,而且不可改變private final String seasonName;private final String seasonDesc;//構造器也是私有的,不可以隨意構造Season類private Season(String seasonName,String seasonDesc){this.seasonName = seasonName;this.seasonDesc = seasonDesc;}//枚舉,提供給外界的構造方法是有限的。public static final Season SPRING = new Season("春天","春暖花開");public static final Season SUMMER = new Season("夏天","烈日炎炎");public static final Season AUTUMN = new Season("秋天","碩果累累");public static final Season WINTER = new Season("冬天","冰天雪地");//額外:public String getSeasonName(){return this.seasonName;}public String getSeasonDesc(){return this.seasonDesc;}@Overridepublic String toString() {return "Season{" +"seasonName='" + seasonName + '\'' +", seasonDesc='" + seasonDesc + '\'' +'}';} } class TestSeason {//這是一個main方法,是程序的入口:public static void main(String[] args) {Season summer = Season.SUMMER;System.out.println(summer/*.toString()*/);System.out.println(summer.getSeasonName());} } 在JDK1.5之后,枚舉類enum出現,可以簡化很多,對應自定義的修改。EG: public enum Season {//定義枚舉,必須放在最前面//提供枚舉類的有限的 確定的對象:--->enum枚舉類要求對象(常量)必須放在最開始位置//多個對象之間用逗號,進行連接,最后一個對象后面用分號;結束SPRING ("春天","春暖花開"),SUMMER ("夏天","烈日炎炎"),AUTUMN("秋天","碩果累累"),WINTER("冬天","冰天雪地");//屬性是私有的,而且不可改變private final String seasonName;private final String seasonDesc;//構造器也是私有的,不可以隨意構造Season類private Season(String seasonName,String seasonDesc){this.seasonName = seasonName;this.seasonDesc = seasonDesc;}//額外:public String getSeasonName(){return this.seasonName;}public String getSeasonDesc(){return this.seasonDesc;}@Overridepublic String toString() {return "Season{" +"seasonName='" + seasonName + '\'' +", seasonDesc='" + seasonDesc + '\'' +'}';}

3.2 枚舉的使用以及常用的方法:

public class TestSeason {public static void main(String[] args) {Season winter = Season.WINTER;System.out.println(winter);//enum關鍵字對應的枚舉類的上層父類是 :java.lang.Enum//但是我們自定義的枚舉類的上層父類:ObjectSystem.out.println(Season.class.getSuperclass().getName());//java.lang.Enum} } public class TestSeason {public static void main(String[] args) {//enum關鍵字對應的枚舉類的上層父類是 :java.lang.Enum//但是我們自定義的枚舉類的上層父類:ObjectSeason winter = Season.WINTER;System.out.println(winter);System.out.println(Season.class.getSuperclass().getName());//java.lang.Enum//用enum關鍵字創建的Season枚舉類上面的父類是:java.lang.Enum,常用方法子類Season可以直接拿過來使用://toString();--->獲取對象的名字Season autumn = Season.AUTUMN;System.out.println(autumn/*.toString()*/);//AUTUMNSystem.out.println("--------------------");//values:返回枚舉類對象的數組Season[] values = Season.values();for(Season s:values){System.out.println(s/*.toString()*/);}System.out.println("--------------------");//valueOf:通過對象名字獲取這個枚舉對象//注意:對象的名字必須傳正確,否則拋出異常Season autumn1 = Season.valueOf("AUTUMN");System.out.println(autumn1);} }

注意:
1.為什么在很多源碼中看到別人定義的枚舉類形態特別簡單:因為這個枚舉類底層沒有屬性,構造器,toString,get方法都刪掉不寫了,然后案例應該寫為:SPRING() 現在連括號()也可以省略,就變成SPRING。看到的形態就剩:常量名(對象名)

public enum Season {SPRING,SUMMER,AUTUMN,WINTER; }

3.3 枚舉的應用

定義一個Person類,類中又一個屬性是性別Sex,那么這個sex屬性由于只有男和女兩種選擇而不能隨意,那么就可以用枚舉類來限定Person的set方法。

class Person {//屬性:private int age;private String name;private Gender sex;public Gender getSex() {return sex;}public void setSex(Gender sex) {this.sex = sex;} } enum Gender {,; } public class Test {//這是一個main方法,是程序的入口:public static void main(String[] args) {Person p = new Person();p.setAge(19);p.setName("lili");p.setSex(Gender.);//傳入枚舉類Gender的對象:-->在入口處對參數進行了限制System.out.println(p);//還可以通過枚舉結合switch處理:Gender sex = Gender.;//switch后面的()中可以傳入枚舉類型//switch后面的():int,short,byte,char,String ,枚舉switch (sex){case:System.out.println("是個女孩");break;case:System.out.println("是個男孩");break;}} }

4 反射

4.1 為什么要用反射

案例引入:美團外賣付款實現(要么用微信支付 要么用支付寶支付 )

//接口的制定方:美團外賣 public interface Mtwm {//在線支付功能:void payOnline(); } class WeChat implements Mtwm{@Overridepublic void payOnline() {//具體實現微信支付的功能:System.out.println("我已經點了外賣,正在使用微信支付");} } class AliPay implements Mtwm {@Overridepublic void payOnline() {//具體的支付寶支付:System.out.println("我已經點了外賣,我正在使用支付寶進行支付");} }

最一般的實現

public class Test {public static void main(String[] args) {//定義一個字符串,用來模擬前臺的支付方式:String str = "微信";if("微信".equals(str)){//str.equals("微信")---?避免空指針異常//微信支付://new WeChat().payOnline();pay(new WeChat());}if("支付寶".equals(str)){//支付寶支付://new AliPay().payOnline();pay(new AliPay());}if("招商銀行".equals(str)){pay(new BankCard());}}//微信支付public static void pay(WeChat wc){wc.payOnline();}//支付寶支付public static void pay(AliPay ap){ap.payOnline();}//招商銀行支付public static void pay(BankCard bc){bc.payOnline();} }

發現要寫的方法很多,代碼冗余。這個時候可以用多態來簡化

public class Test {public static void main(String[] args) {//定義一個字符串,用來模擬前臺的支付方式:String str = "微信";if("微信".equals(str)){//str.equals("微信")---?避免空指針異常//微信支付:pay(new WeChat());}if("支付寶".equals(str)){//支付寶支付:pay(new AliPay());}if("招商銀行".equals(str)){pay(new BankCard());}}//方法形參是接口,具體傳入的是接口的實現類的對象--->多態的一種形式public static void pay(Mtwm m){m.payOnline();} }

多態確實可以提高代碼的擴展性,但是:擴展性沒有達到最好。
怎么沒有達到最好:上面的if分支,還是需要手動的刪除或者添加,如果假如同時來了50個付款方式,那就要加50個if。
解決辦法:反射機制
利用反射實現上述功能:

public class Demo {public static void main(String[] args) throws Exception {//定義一個字符串,用來模擬前臺的支付方式:String str = "com.jayden.test01.AliPay"; //字符串:實際上:就是微信類的全限定路徑//下面的代碼就是利用反射:Class cls = Class.forName(str);//cls-->Class類具體的對象--》AliPay字節碼信息Object o = cls.newInstance();Method method = cls.getMethod("payOnline");method.invoke(o);} }

上述代碼不管又多少家銀行來了,這個類中的邏輯代碼都不用變了,要變的只有一個字符串接口。

4.2 反射的概念

  • JAVA反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱為java語言的反射機制
  • 在編譯后產生字節碼文件的時候,類加載器子系統通過二進制字節流,負責從文件系統加載class文件。在執行程序(java.exe)時候,將字節碼class文件讀入JVM中(即類的加載)。這個時候JVM會在內存中對應創建一個java.lang.Class對象,這個對象也會被放入字節碼信息中,這個Class對象,就對應加載那個字節碼信息,這個對象將被作為程序訪問方法區中的這個類的各種數據的外部接口。
    所以:我們可以通過這個對象看到類的結構,這個對象就好像是一面鏡子,透過鏡子看到類的各種信息,我們形象的稱之為反射。
  • 這種“看透”class的能力(the ability of the program to examine itself)被稱為introspection(內省、內觀、反省)。Reflection和introspection是常被并提的兩個術語。

說明:在運行期間,如果我們要產生某個類的對象,Java虛擬機(JVM)會檢查該類型的Class對象是否已被加載。
如果沒有被加載,JVM會根據類的名稱找到.class文件并加載它。一旦某個類型的Class對象已被加載到內存,就可以用它來產生該類型的所有對象。

補充:動態語膏vs靜態語言
1、動態語言
是一類在運行時可以改變其結構的語言:例如新的函數、對象、甚至代碼可以被引進,已有的函數可以被刪除或是其他結構上的變化。通俗點說就是在運行時代碼可以根據某些條件改變自身結構。
主要動態語言: Object-C、 C#、JavaScript、 PHP、 Python、 Erlang 。
2、靜態語言
與動態語言相對應的,運行時結構不可變的語言就是靜態語言。如Java、C、C++。
所以Java不是動態語言,但Java可以稱之為“準動態語言”。即Java有一定的動態性,我們可以利用反射機制、字節碼操作獲得類似動態語言的特性。Java的動態性讓編程的時候更加靈活!

4.3 獲取字節碼信息的4種方式

//舉例要用的類Person class Person {//屬性private int age;public String name;//方法private void eat(){System.out.println("Person---eat");}public void sleep(){System.out.println("Person---sleep");} } public class Test {public static void main(String[] args) throws ClassNotFoundException {//案例:以Person的字節碼信息為案例//方式1:通過getClass()方法獲取Person p = new Person();Class c1 = p.getClass();System.out.println(c1);//方式2:通過內置class屬性:Class c2 = Person.class;System.out.println(c2);System.out.println(c1==c2);//注意:方式1和方式2不常用,因為既然都已經又Person類了,就可以直接用Person類的對象來使用里面的屬性和方法,沒有必要多此一舉。//方式3:用的最多:調用Class類提供的靜態方法forNameClass c3 = Class.forName("com.zhaoss.test02.Person");//方式4:利用類的加載器(了解技能點)ClassLoader loader = Test.class.getClassLoader();Class c4 = loader.loadClass("com.zhaoss.test02.Person");} }

4.4 Class類的具體的實例

  • Calss類的具體實例可以有:外部類,內部類、接口、注解、數組、基本數據類型、void。
public class Demo {public static void main(String[] args) {/*Class類的具體的實例:(1)類:外部類,內部類(2)接口(3)注解(4)數組(5)基本數據類型(6)void*/Class c1 = Person.class;Class c2 = Comparable.class;Class c3 = Override.class;int[] arr1 = {1,2,3};Class c4 = arr1.getClass();int[] arr2 = {5,6,7};Class c5 = arr2.getClass();System.out.println(c4==c5);//結果:true .同一個維度,同一個元素類型,得到的字節碼就是同一個Class c6 = int.class;Class c7 = void.class;} }

4.5 通過Class類來獲取運行時類的完整對象

舉例要用的類:

//作為一個父類 public class Person implements Serializable {//屬性private int age;public String name;//方法private void eat(){System.out.println("Person---eat");}public void sleep(){System.out.println("Person---sleep");} } //Student作為子類 @MyAnnotation(value="hello") public class Student extends Person implements MyInterface{//屬性:private int sno;//學號double height;//身高protected double weight;//體重public double score;//成績//方法:@MyAnnotation(value="himethod")public String showInfo(){return "我是一名三好學生";}public String showInfo(int a,int b){return "重載方法====我是一名三好學生";}private void work(){System.out.println("我以后會找工作--》成為碼農 程序員 程序猿 程序媛");}void happy(){System.out.println("做人最重要的就是開心每一天");}protected int getSno(){return sno;}//構造器public Student(){System.out.println("空參構造器");}private Student(int sno){this.sno = sno;}Student(int sno,double weight){this.sno = sno;this.weight = weight;}protected Student(int sno,double height,double weight){this.sno = sno;}@Override@MyAnnotation(value="hellomyMethod")public void myMethod() {System.out.println("我重寫了myMethod方法。。");}@Overridepublic String toString() {return "Student{" +"sno=" + sno +", height=" + height +", weight=" + weight +", score=" + score +'}';} }/* @Target:定義當前注解能夠修飾程序中的哪些元素 @Retention:定義注解的聲明周期*/ @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation {String value();//屬性 }public interface MyInterface {//自定義的接口//隨便定義一個抽象方法:void myMethod(); }

1)獲取構造器和創建對象

public class Test {public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {//獲取字節碼信息:Class cls = Student.class;//通過字節碼信息可以獲取構造器://getConstructors只能獲取當前運行時類的被public修飾的構造器Constructor[] c1 = cls.getConstructors();for(Constructor c:c1){System.out.println(c);}System.out.println("-------------------");//getDeclaredConstructors:獲取運行時類的全部修飾符的構造器Constructor[] c2 = cls.getDeclaredConstructors();for(Constructor c:c2){System.out.println(c);}System.out.println("-------------------");//獲取指定的構造器://得到空構造器Constructor con1 = cls.getConstructor();System.out.println(con1);//得到兩個參數的有參構造器:Constructor con2 = cls.getConstructor(double.class, double.class);System.out.println(con2);//得到一個參數的有參構造器:并且是private修飾的Constructor con3 = cls.getDeclaredConstructor(int.class);System.out.println(con3);//有了構造器以后我就可以創建對象:Object o1 = con1.newInstance();System.out.println(o1);Object o2 = con2.newInstance(180.5, 170.6);System.out.println(o2);} }

2)獲取屬性和對屬性進行賦值

public class Test {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {//獲取運行時類的字節碼信息:Class cls = Student.class;//獲取屬性://getFields:獲取運行時類和父類中被public修飾的屬性Field[] fields = cls.getFields();for(Field f:fields){System.out.println(f);}System.out.println("---------------------");//getDeclaredFields:獲取運行時類中的所有屬性Field[] declaredFields = cls.getDeclaredFields();for(Field f:declaredFields){System.out.println(f);}System.out.println("---------------------");//獲取指定的屬性:Field score = cls.getField("score");System.out.println(score);Field sno = cls.getDeclaredField("sno");System.out.println(sno);System.out.println("---------------------");//屬性的具體結構://獲取修飾符,返回的是一個int類型的數,打開modifier源碼后可以看到數字對應的字符串,如private就是2,static是8,那么修飾為private static就是10。然后它的ToString方法可以將這個數字轉化為對應修飾符,所以我們可以利用這個方法獲得對應屬性的修飾符/*int modifiers = sno.getModifiers();System.out.println(modifiers);System.out.println(Modifier.toString(modifiers));*/System.out.println(Modifier.toString(sno.getModifiers()));//獲取屬性的數據類型:Class clazz = sno.getType();System.out.println(clazz.getName());//獲取屬性的名字:String name = sno.getName();System.out.println(name);System.out.println("-------------------------------");//給屬性賦值:(給屬性設置值,必須要有對象)Field sco = cls.getField("score");Object obj = cls.newInstance();sco.set(obj,98);//給obj這個對象的score屬性設置具體的值,這個值為98System.out.println(obj);} }

3)獲取方法和調用方法

public class Test {public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {//獲取字節碼信息:Class cls = Student.class;//獲取方法://getMethods:獲取運行時類的方法還有所有父類中的方法(被public修飾)Method[] methods = cls.getMethods();for(Method m:methods){System.out.println(m);}System.out.println("-----------------------");//getDeclaredMethods:獲取運行時類中的所有方法:Method[] declaredMethods = cls.getDeclaredMethods();for(Method m:declaredMethods){System.out.println(m);}System.out.println("-----------------------");//獲取指定的方法:Method showInfo1 = cls.getMethod("showInfo");System.out.println(showInfo1);Method showInfo2 = cls.getMethod("showInfo", int.class, int.class);System.out.println(showInfo2);Method work = cls.getDeclaredMethod("work",int.class);System.out.println(work);System.out.println("-----------------------");//獲取方法的具體結構:/*@注解修飾符 返回值類型 方法名(參數列表) throws XXXXX{}*///名字:System.out.println(work.getName());//修飾符:int modifiers = work.getModifiers();System.out.println(Modifier.toString(modifiers));//返回值:System.out.println(work.getReturnType());//參數列表:Class[] parameterTypes = work.getParameterTypes();for(Class c:parameterTypes){System.out.println(c);}//獲取注解:Method myMethod = cls.getMethod("myMethod");Annotation[] annotations = myMethod.getAnnotations();for(Annotation a:annotations){System.out.println(a);}//獲取異常:Class[] exceptionTypes = myMethod.getExceptionTypes();for(Class c:exceptionTypes){System.out.println(c);}//調用方法:Object o = cls.newInstance();myMethod.invoke(o);//調用o對象的mymethod方法System.out.println(showInfo2.invoke(o,12,45));;} }

4)獲取類的接口,所在包,注解

public class Test {public static void main(String[] args) {//獲取字節碼信息:Class cls = Student.class;//獲取運行時類的接口:Class[] interfaces = cls.getInterfaces();for(Class c:interfaces){System.out.println(c);}//得到父類的接口://先得到父類的字節碼信息:Class superclass = cls.getSuperclass();//得到接口:Class[] interfaces1 = superclass.getInterfaces();for(Class c:interfaces1){System.out.println(c);}//獲取運行時類所在的包:Package aPackage = cls.getPackage();System.out.println(aPackage);System.out.println(aPackage.getName());//獲取運行類的注解:Annotation[] annotations = cls.getAnnotations();for(Annotation a:annotations){System.out.println(a);}} }

4.6 反射面試題

  • 創建Person的對象,以后用new Person()創建,還是用反射創建?
    如果某個對象,只有在程序運行時才可以動態的知道具體時哪一個對象時,這個時候就用反射。
  • 反射是否破壞了面向對象的封裝性?
    封裝性和反射各自解決的是不同的問題,事實上,反射確實是具有可以訪問private修飾的屬性的,但是這僅僅是提供了這種方法。不建議使用。舉個例子:在廁所上有男生女生的標識,但是如果真有變態,那也就是可以進入與自己性別不符的門。但不能因為有變態的存在,直接不在廁所上貼男生女生的標識。

總結

以上是生活随笔為你收集整理的单元测试、注解、枚举、反射(5)JavaSE的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。