day01-java重點複習

day01
MyEclipse介紹javascript

1 debug斷點調試
 設置斷點;
 測試跳入(F5);
 測試跳過(F6);
 測試跳出(F7);
 添加斷點;
 測試進入下一斷點;
 測試返回當前方法棧的頭部(Drop To Frame);
 清除斷點;
 清除表達式;
注意,中止程序!css

2 經常使用快捷鍵
  必須的:
 Alt + /(內容助理):補全;
 Ctrl + 1(快速定位):出錯時定位錯誤,與點擊「紅X」效果同樣;
 Ctrl + Shift + O:導包;
 Ctrl + Shift + F:格式化代碼塊;java

不是必須的(本身讀,不講):
 Ctrl + Shift + T:查看源代碼;
 Ctrl + 點擊源代碼:查看源代碼;
 F3:查看選中類的源代碼;
 Alt + 左鍵:查看源代碼時的「原路返回」;
 Ctrl + Shift + X:把小寫修改成大寫;
 Ctrl + Shift + Y:把小寫修改成小寫;
 Ctrl + Alt + 下鍵:複製當前行;
 Ctrl + /:添加或撤銷行註釋;
 Ctrl + Shift + /:對選中代碼添加段註釋;
 Ctrl + Shift + :撤銷當前段註釋;
 Alt + 上鍵:向上移動當前行;
 Alt + 下鍵:向上移動當前行;
 Ctrl + D:刪除當前行;數組

JUnit
1 JUnit的概述
當咱們寫完了一個類後,老是要執行一下類中的方法,查看是否符合咱們的意圖,這就是單元測試了。而Junit就是單元測試工具。
 導包:導入Junit4或以上版本;
 編寫一個類:Person,它就是要被測試的類;
 編寫測試類:PersonTest,給出測試方法,在測試方法上使用@Test註解;
 執行測試方法。緩存

Person
package cn.itcast;安全

public class Person {
public void run() {
System.out.println("run");
}
public void eat() {
System.out.println("eat");
}
}markdown

包資源管理器選中Person類右鍵newJUnit TestCase修改包名爲junit.test下一步選中要測試的方法。框架

PersonTest
package junit.test;async

import org.junit.Test;
import cn.itcast.Person;ide

public class PersonTest {
@Test
public void testRun () {
Person person = new Person();
person.run();
}
@Test
public void testEat () {
Person person = new Person();
person.eat();
}
}

選中某個測試方法,鼠標右鍵Run asJunit Test,即執行測試方法。
@Test註解的做用是指定方法爲測試方法,測試方法必須是public、void、無參的!!!

2 @Before和@After(瞭解)
若是你須要某個方法在每一個測試方法以前先執行,那麼你須要寫一個方法,而後使用@Before來標記這個方法。例如在testRun()和testEat()方法以前須要建立一個Person對象。
PersonTest
package junit.test;

import org.junit.Before;
import org.junit.Test;
import cn.itcast.Person;

public class PersonTest {
private Person person;
@Before
public void setUp () {
person = new Person();
}
@Test
public void testRun() {
person.run();
}
@Test
public void testEat() {
person.eat();
}
}

@After註解標記的方法會在每一個執行方法以後執行
@Before和@After標記的方法必須是public、void、無參。

JDK5.0新特性

1 自動拆裝箱
自動拆裝箱是JDK5.0的新特性之一,這一特性可使基本類型,與之對應的包裝器類型之間直接轉換,例如int的包裝器類型是Integer!在JDK5.0以後,你甚至能夠把int看成成Integer來使用,把Integer當成int來使用。固然,這不是100%的!
1.1 自動拆裝箱概述
在JDK5.0以後,Java容許把基本類型與其對應的包裝器類型之間自動相互轉換。
 自動裝箱:Integer i = 100,把int類型直接賦值給Integer類型;
 自動拆裝:int a = new Integer(100),把Integer類型直接賦值給int類型。

1.2 自動拆裝箱原理
其實自動拆裝箱是由編譯器完成的!咱們寫的代碼,再由編譯器「二次加工」,而後再編譯成.class文件!那麼編譯器是怎麼「二次加工」的呢?
 Integer i = 100:編譯器加工爲:Integer i = Integer.valueOf(100);
 int a = i:編譯器加載爲:int a = i.intValue();
這也說明一個道理:JVM並不知道什麼是自動拆裝箱,JVM仍是原來的JVM(JDK1.4以前),只是編譯器在JDK5.0時「強大」了!

1.3 自動拆裝箱演變
你們來看看下面代碼:
Integer i = 100;//這是自動裝箱
Object o = i;//這是身上轉型

上面代碼是沒有問題的,咱們是否能夠修改上面代碼爲:
Object o = 100;

ok,這是能夠的!經過編譯器的處理後上面代碼爲:
Object o = Integer.valueOf(100);

在來看下面代碼:
Object o = Integer.valueOf(100);
int a = o;//編譯失敗!

上面代碼是不行的,由於o不是Integer類型,不能自動拆箱,你須要先把o轉換成Integer類型後,才能賦值給int類型。
Object o = Integer.valueOf(100);
int a = (Integer)o;

1.4 變態小題目
來看下面代碼:
Integer i1 = 100;
Integer i2 = 100;
boolean b1 = i1 == i2;//結果爲true

Integer i3 = 200;
Integer i4 = 200;
boolean b2 = i3 == i4;//結果爲false

你可能對上面代碼的結果感到費解,那麼咱們來打開這個疑團。第一步,咱們先把上面代碼經過編譯器的「二次加工」處理一下:
Integer i1 = Integer.valueOf(100);
Integer i2 = Integer.valueOf(100);
boolean b1 = i1 == i2;//結果爲true

Integer i3 = Integer.valueOf(200);
Integer i4 = Integer.valueOf(200);
boolean b2 = i3 == i4;//結果爲false

這時你應該能夠看到,疑團在Integer.valueOf()方法身上。傳遞給這個方法100時,它返回的Integer對象是同一個對象,而傳遞給這個方法200時,返回的倒是不一樣的對象。這是咱們須要打開Integer的源碼(這裏就不粘貼Integer的源代碼了),查看它的valueOf()方法內容。
Integer類的內部緩存了-128~127之間的256個Integer對象,若是valueOf()方法須要把這個範圍以內的整數轉換成Integer對象時,valueOf()方法不會去new對象,而是從緩存中直接獲取,這就會致使valueOf(100)兩次,都是從緩存中獲取的同一個Integer對象!若是valueOf()方法收到的參數不在緩存範圍以內,那麼valueOf()方法會new一個新對象!這就是爲何Integer.valueOf(200)兩次返回的對象不一樣的緣由了。

2 可變參數
可變參數就是一個方法能夠接收任意多個參數!例如:fun()、fun(1)、fun(1,1)、fun(1,1,1)。你可能認爲這是方法重載,但這不是重載,你想一想重載能重載多少個方法,而fun()方法是能夠傳遞任何個數的參數,你能重載這麼多個方法麼?

2.1 定義可變參數方法
public void fun(int… arr) {}
上面方法fun()的參數類型爲int…,其中「…」不是省略號,而是定義參數類型的方式。參數arr就是可變參數類型。你能夠把上面代碼理解爲:public void fun(int[] arr)。
public int sum1(int[] arr) {
int sum = 0;
for(int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
public int sum2(int... arr) {
int sum = 0;
for(int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}

你可能會想,「int[]」和「int…」沒有什麼不一樣,只是「int…」是一種新的定義數組形參的方式罷了。那麼我應該恭喜你了!沒錯,這麼理解就對了!但要注意,只有在方法的形參中可使用int…來代替int[]。

2.2 調用帶有可變參數的方法
sum1()和sum2()兩個方法的調用:
sum1(new int[]{1,2,3});
sum2(new int[]{1,2,3});

這看起來沒什麼區別!可是對於sum2還有另外一種調用方式:
sum2();
sum2(1);
sum2(1,2);
sum2(1,2,3);

  這看起來好像是使用任意多個參數來調用sum2()方法,這就是調用帶有可變參數方法的好處了。

2.3 編譯器「二次加工」
編譯器對sum2方法定義的「二次加工」結果爲:
public int sum2(int[] arr) {
int sum = 0;
for(int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}

即把「int…」修改成「int[]」類型。
編譯器對sum2方法調用的二次加載結果爲:
sum2(new int[0]);
sum2(new int[] {1});
sum2(new int[] {1, 2});
sum2(new int[] {1, 2, 3});

結論:可變參數其實就是數組類型,只不過在調用方法時方便一些,由編譯器幫咱們把多個實參放到一個數組中傳遞給形參。

2.4 可變參數方法的限制
 一個方法最多隻能有一個可變參數;
 可變參數必須是方法的最後一個參數。

3 加強for循環
加強for循環是for的一種新用法!用來循環遍歷數組和集合。

3.1 加強for的語法
for(元素類型 e : 數組或集合對象) {
}
例如:
int[] arr = {1,2,3};
for(int i : arr) {
System.out.println(i);
}
  加強for的冒號左邊是定義變量,右邊必須是數組或集合類型。例如上例中循環遍歷的主濁arr這個int數組,加強for內部會依次把arr中的元素賦給變量i。

3.2 加強for的優缺點
 只能從頭至尾的遍歷數組或集合,而不能只遍歷部分;
 在遍歷List或數組時,不能獲取當前元素下標;
 加強for使用便簡單,這是它惟一的優勢了;
 加強for比使用迭代器方便一點!

3.3 加強for原理
其實加強for內部是使用迭代器完成的!也就是說,任何實現了Iterable接口的對象均可以被加強for循環遍歷!這也是爲何加強for能夠循環遍歷集合的緣由(Collection是Iterable的子接口)。
但要注意,Map並無實現Iterable接口,因此你不能直接使用加強for來遍歷它!
Map<String, String> map = new HashMap<String,String>();
map.put("1", "one");
map.put("2", "two");
map.put("3", "three");

for(String key : map.keySet() ) {
        String value = map.get(key);
        System.out.println(key + "=" + value);
    }

泛型

1 泛型概述
泛型是JDK5.0新特性,它主要應用在集合類上。有了泛型以後,集合類與數組就愈來愈像了。例如:Object[] objs = new Object[10],能夠用來存儲任何類型的對象。String[] strs = new String[10]只能用來存儲String類型的對象。
ArrayList list = new ArrayList(),能夠用來存儲任何類型的對象。ArrayList list = new ArrayList ()只有用來存儲String類型的對象。
1.1 理解泛型類
泛型類具備一到多個泛型變量,在建立泛型類對象時,須要爲泛型變量指定值。泛型變量只能賦值爲引用類型,而不能是基本類型。例如ArrayList類中有一個泛型變量E,在建立ArrayList類的對象時須要爲E這個泛型變量指定值。
list list = new ArrayList ();,
其中String就是給List的泛型變量E賦值了。查閱ArrayList的API你會知道,泛型變量E出如今不少方法中:
boolean add(E e)
E get(int index)
由於咱們在建立list對象時給泛型類型賦值爲String,因此對於list對象而言,全部API中的E都會被String替換。
boolean add(String e)
String get(int index)
也就是說,在使用list.add()時,只能傳遞String類型的參數,而list.get()方法返回的必定是String類型。
list.add(「hello」);
String s = list.get(0);

1.2 使用泛型對象
建立泛型對象時,引用和new兩端的泛型類型須要一致,例如上面的引用是List ,而new一端是new ArrayList ,兩端都是String類型!若是不一致就會出錯:
List list = new ArrayList ();//編譯失敗!

Collection的addAll()方法中使用了通配符(這個概念在下一個基礎增強中講解),因此使用起來比較方便:
List list = new ArrayList();
List list1 = new ArrayList ();
List list2 = new ArrayList ();
list.addAll(list1);
list.addAll(list2);

2 泛型的好處
 將運行期遇到的問題轉移到了編譯期;
 泛型不可能去除全部類型轉換,但能夠減小了類型轉換操做;
 在循環遍歷集合類時,方便了不少;
 必定程度上提升了安全性。

3 自定義泛型類的語法

3.1 自定義泛型類的語法
public class 類型 <一到多個泛型變量的聲明> {…}
例如:
public class A {...}
A類中有一個泛型變量的聲明(或稱之爲定義)。這就至關於建立了一個變量同樣,而後就能夠在類內使用它了。

3.2 泛型類內使用泛型變量
聲明的泛型變量能夠在類內使用,例如建立實例變量時使用泛型變量指定類型,能夠在實例方法中指定參數類型或返回值類型,但不能在static變量或static方法中使用泛型變量。
public class A {
private T bean;
public T getBean() {
return bean;
}
public void setBean(T bean) {
this.bean = bean;
}
}

4 泛型方法定義
不僅能夠建立泛型類,還能夠建立泛型方法。可能你會有個誤區,下面的方法不是泛型方法:
class A {
public void fun(T t) {…}
}

上面fun()方法是泛型類中的方法,它不是泛型方法。
泛型方法是能夠本身建立泛型變量,泛型方法中建立的泛型變量只能在本方法內使用。泛型方法能夠是實例方法,也能夠是靜態方法。
public T get(T[] ts, int index) {
return ts[index];
}

咱們必需要區別開什麼是建立泛型變量,什麼是使用泛型變量。其中 是建立泛型變量,它必須在返回值前面給出。
泛型方法中的泛型變量只有兩個可使用的點:返回值和參數,並且全部有意義的泛型方法中都會在返回值和參數兩個位置上使用泛型變量,但語法上沒有強制的要求。

調用泛型方法,一般無需爲泛型變量直接賦值,而是經過傳遞的參數類型間接爲泛型變量賦值,例如:
String[] strs = {「hello」, 「world」};
String s = get(strs, 0);
  由於給T[] ts參數賦值爲strs,而strs的變量爲String[],因此等同與給get方法的泛型變量賦值爲String類型。因此返回值類型T爲String類型。

枚舉

1 什麼是枚舉類型
  咱們學習過單例模式,即一個類只有一個實例。而枚舉其實就是多例,一個類有多個實例,但實例的個數不是無窮的,是有限個數的。例如word文檔的對齊方式有幾種:左對齊、居中對齊、右對齊。開車的方向有幾種:前、後、左、右!
  咱們稱呼枚舉類中實例爲枚舉項!通常一個枚舉類的枚舉項的個數不該該太多,若是一個枚舉類有30個枚舉項就太多了!

2 定義枚舉類型
定義枚舉類型須要使用enum關鍵字,例如:
public enum Direction {
FRONT, BEHIND, LEFT, RIGHT;
}
Direction d = Direction.FRONT;

注意,定義枚舉類的關鍵字是enum,而不是Enum,全部關鍵字都是小寫的!
其中FRONT、BEHIND、LEFT、RIGHT都是枚舉項,它們都是本類的實例,本類一共就只有四個實例對象。
在定義枚舉項時,多個枚舉項之間使用逗號分隔,最後一個枚舉項後須要給出分號!但若是枚舉類中只有枚舉項(沒有構造器、方法、實例變量),那麼能夠省略分號!建議不要省略分號!
不能使用new來建立枚舉類的對象,由於枚舉類中的實例就是類中的枚舉項,因此在類外只能使用類名.枚舉項。

3 枚舉與switch
枚舉類型能夠在switch中使用
Direction d = Direction.FRONT;
switch(d) {
case FRONT: System.out.println("前面");break;
case BEHIND:System.out.println("後面");break;
case LEFT: System.out.println("左面");break;
case RIGHT: System.out.println("右面");break;
default:System.out.println("錯誤的方向");
}
Direction d1 = d;
System.out.println(d1);

  注意,在switch中,不能使用枚舉類名稱,例如:「case Direction.FRONT:」這是錯誤的,由於編譯器會根據switch中d的類型來斷定每一個枚舉類型,在case中必須直接給出與d相同類型的枚舉選項,而不能再有類型。

4 全部枚舉類都是Enum的子類
全部枚舉類都默認是Enum類的子類,無需咱們使用extends來繼承。這說明Enum中的方法全部枚舉類都擁有。
 int compareTo(E e):比較兩個枚舉常量誰大誰小,其實比較的就是枚舉常量在枚舉類中聲明的順序,例如FRONT的下標爲0,BEHIND下標爲1,那麼FRONT小於BEHIND;
 boolean equals(Object o):比較兩個枚舉常量是否相等;
 int hashCode():返回枚舉常量的hashCode;
 String name():返回枚舉常量的名字;
 int ordinal():返回枚舉常量在枚舉類中聲明的序號,第一個枚舉常量序號爲0;
 String toString():把枚舉常量轉換成字符串;
 static T valueOf(Class enumType, String name):把字符串轉換成枚舉常量。

5 枚舉類的構造器
  枚舉類也能夠有構造器,構造器默認都是private修飾,並且只能是private。由於枚舉類的實例不能讓外界來建立!
enum Direction {
FRONT, BEHIND, LEFT, RIGHT;

Direction()  {
    System.out.println("hello");
}

}

其實建立枚舉項就等同於調用本類的無參構造器,因此FRONT、BEHIND、LEFT、RIGHT四個枚舉項等同於調用了四次無參構造器,因此你會看到四個hello輸出。

6 枚舉類能夠有成員
其實枚舉類和正常的類同樣,能夠有實例變量,實例方法,靜態方法等等,只不過它的實例個數是有限的,不能再建立實例而已。
enum Direction {
FRONT("front"), BEHIND("behind"), LEFT("left"), RIGHT("right");

private String name;

Direction(String name) {
    this.name = name;
}

public String getName() {
    return name;
}

}
Direction d = Direction.FRONT;
System.out.println(d.getName());

由於Direction類只有惟一的構造器,而且是有參的構造器,因此在建立枚舉項時,必須爲構造器賦值:FRONT(「front」),其中」front」就是傳遞給構造器的參數。你不要鄙視這種語法,你應該作的是接受這種語法!
Direction類中還有一個實例域:String name,咱們在構造器中爲其賦值,並且本類還提供了getName()這個實例方法,它會返回name的值。

7 枚舉類中還能夠有抽象方法(瞭解)
  還能夠在枚舉類中給出抽象方法,而後在建立每一個枚舉項時使用「特殊」的語法來重複抽象方法。所謂「特殊」語法就是匿名內部類!也就是說每一個枚舉項都是一個匿名類的子類對象!

一般fun()方法應該定義爲抽象的方法,由於每一個枚舉常量都會去重寫它。
你沒法把Direction聲明爲抽象類,但須要聲明fun()方法爲抽象方法。
enum Direction {
FRONT() {
public void fun() {
System.out.println("FROND:重寫了fun()方法");
}
},
BEHIND() {
public void fun() {
System.out.println("BEHIND:重寫了fun()方法");
}
},
LEFT() {
public void fun() {
System.out.println("LEFT:重寫了fun()方法");
}
},
RIGHT() {
public void fun() {
System.out.println("RIGHT:重寫了fun()方法");
}
};

public abstract void fun() ;

}

反射概述

1 反射的概述
1.1 什麼是反射
  每一個.class文件被加載到內存後都是一個Class類的對象!例如Demo.class加載到內存後它是Class 類型的一個對象。

反射就是經過Class對象獲取類型相關的信息。一個Class對象就表示一個.class文件,能夠經過Class對象獲取這個類的構造器、方法,以及成員變量等。
反射是Java的高級特性,在框架中大量被使用!咱們必需要了解反射,否則沒法學好JavaWeb相關的知識!

1.2 反射相關類
與反射相關的類:
 Class:表示類;
 Field :表示成員變量;
 Method:表示方法;
 Constructor:表示構造器。

2 Class類

2.1 獲取Class類
獲取Class類的三種基本方式:
 經過類名稱.class ,對基本類型也支持;
 Class c = int.class;
 Class c = int[].class;
 Class c = Demo.class
 經過對象.getClass ()方法
 Class c = obj.getClass();
 Class.forName()經過類名稱加載類 ,這種方法只要有類名稱就能夠獲得Class;
 Class c = Class.forName(「cn.itcast.Demo」);

2.2 Class類的經常使用方法
 String getName():獲取類名稱,包含包名;
 String getSimpleName():獲取類名稱,不包含包名;
 Class getSupperClass():獲取父類 的Class,例如:new Integer(100).getClass().getSupperClass()返回的是Class !但new Object().getSupperClass()返回的是null,由於Object沒有父類;
 T newInstance():使用本類無參構造器 來建立本類對象;
 boolean isArray():是否爲數組類型;
 boolean isAnnotation():是否爲註解類型;
 boolean isAnnotationPresent(Class annotationClass):當前類是否被annotationClass註解了;
 boolean isEnum():是否爲枚舉類型;
 boolean isInterface():是否爲接口類型;
 boolean isPrimitive():是否爲基本類型;
 boolean isSynthetic():是否爲引用類型;

2.3 經過反射建立對象
public class Demo1 {
@Test
public void fun1() throws Exception {
String className = "cn.itcast.User";
Class clazz = Class.forName(className);
User user = (User)clazz.newInstance();
System.out.println(user);
}
}

class User {
private String username;
private String password;

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

@Override
public String toString() {
    return "User [username=" + username + ", password=" + password + "]";
}

}
User [username=null, password=null]

3 Constructor
Constructor表示一個類的構造器。即構造器的反射對象 !

3.1 獲取Constructor對象
  獲取Construcator對象須要使用Class對象,下面API來自Class類:
 Constructor getConstructor(Class… parameterTypes):經過指定的參數類型獲取公有構造器反射對象;
 Constructor[] getConstructors():獲取全部公有構造器對象;
 Constructor getDeclared Constructor(Class… parameterTypes):經過指定參數類型獲取構造器反射對象。能夠是私有構造器對象;
 Constructor[] getDeclaredConstructors():獲取全部構造器對象。包含私有構造器;

3.2 Construcator類經常使用方法
 String getName():獲取構造器名;
 Class getDeclaringClass():獲取構造器所屬的類型;
 Class[] getParameterTypes():獲取構造器的全部參數的類型;
 Class[] getExceptionTypes():獲取構造器上聲明的全部異常類型;
 T newInstance(Object… initargs):經過構造器反射對象調用構造器 。

3.3 練習:經過Construcator建立對象

User.java
public class User {
private String username;
private String password;

public User() {
}

public User(String username, String password) {
    this.username = username;
    this.password = password;
}

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

@Override
public String toString() {
    return "User [username=" + username + ", password=" + password + "]";
}

}

Demo1.java
public class Demo1 {
@Test
public void fun1() throws Exception {
String className = "cn.itcast.User";
Class clazz = Class.forName(className);
Constructor c = clazz.getConstructor(String.class, String.class);
User user = (User)c.newInstance("zhangSan", "123");
System.out.println(user);
}
}

4 Method
  Method表示方法的反射對象

4.1 獲取Method
獲取Method須要經過Class對象,下面是Class類的API:
 Method getMethod(String name, Class… parameterTypes):經過方法名和方法參數類型獲取方法反射對象,包含父類中聲明的公有方法,但不包含全部私有方法;
 Method[] getMethods():獲取全部公有方法,包含父類中的公有方法,但不包含任何私有方法;
 Method getDeclaredMethod(String name, Class… parameterTypes):經過方法名和方法參數類型獲取本類中聲明的方法的反射對象,包含本類中的私有方法,但不包含父類中的任何方法;
 Method[] getDeclaredMethods():獲取本類中全部方法,包含本類中的私有方法,但不包含父類中的任何方法。

4.2 Method經常使用方法
 String getName():獲取方法名;
 Class getDeclaringClass():獲取方法所屬的類型;
 Class[] getParameterTypes():獲取方法的全部參數的類型;
 Class[] getExceptionTypes():獲取方法上聲明的全部異常類型;
 Class getReturnType():獲取方法的返回值類型;
 Object invode (Object obj, Object… args):經過方法反射對象調用方法,若是當前方法是實例方法,那麼當前對象就是obj,若是當前方法是static方法,那麼能夠給obj傳遞null。args表示是方法的參數;

4.3 練習:經過Method調用方法
  
public class Demo1 {
@Test
public void fun1() throws Exception {
String className = "cn.itcast.User";
Class clazz = Class.forName(className);
Constructor c = clazz.getConstructor(String.class, String.class);
User user = (User)c.newInstance("zhangSan", "123");

Method method = clazz.getMethod("toString"); 
    String result = (String)method.invoke(user); 
    System.out.println(result); 
}

}

5 Field
  Field表示類的成員變量,能夠是實例變量,也能夠是靜態變量。

5.1 獲取Field對象
獲取Field對象須要使用Class對象,下面是Class類的API:
 Field getField(String name):經過名字獲取公有成員變量的反射對象,包含父類中聲明的公有成員變量;
 Field[] getFields():獲取全部公有成員變量反射對象,包含父類中聲明的公有成員變量;
 Field getDeclaredField(String name):經過名字獲取本類中某個成員變量,包含本類的private成員變量,但父類中聲明的任何成員變量都不包含;
 Field[] getDeclaredFields():獲取本類中聲明的全部成員變量,包含private成員變量,但不包含父類中聲明的任何成員變量;

5.2 Field類的經常使用方法
 String getName():獲取成員變量名;
 Class getDeclaringClass():獲取成員變量的類型;
 Class getType():獲取當前成員變量的類型;
 Object get(Object obj):獲取obj對象的成員變量的值;
 void set(Object obj, Object value):設置obj對象的成員變量值爲value;

5.3 練習:經過Field讀寫成員
User.java
public class User {
public String username;
public String password;

public User() {
}

public User(String username, String password) {
    this.username = username;
    this.password = password;
}

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

@Override
public String toString() {
    return "User [username=" + username + ", password=" + password + "]";
}

}

Demo1.java
public class Demo1 {
@Test
public void fun1() throws Exception {
String className = "cn.itcast.User";
Class clazz = Class.forName(className);
User user = new User("zhangSan", "123");

Field field1 = clazz.getField("username"); 
    Field field2 = clazz.getField("password") ;
    
    String username = (String)field1.get(user); 
    String password = (String)field2.get(user); 
    
    System.out.println(username + ", " + password);
    
    field1.set(user, "liSi"); 
    field2.set(user, "456"); 
    
    System.out.println(user);
}

}

6  AccessibleObject
AccessibleObject類是Constructor、Method、Field三個類的父類。AccessibleObject 最爲重要的方法以下:
 boolean isAccessible():判斷當前成員是否可訪問;
 void setAccessible(boolean flag):設置當前成員是否可訪問。

當Constructor、Method、Field爲私有時,若是咱們想反射操做,那麼就必須先調用反射對象的setAccessible(true)方法,而後才能操做。
User.java
public class User {
private String username;
private String password;

public User() {
}

public User(String username, String password) {
    this.username = username;
    this.password = password;
}

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

@Override
public String toString() {
    return "User [username=" + username + ", password=" + password + "]";
}

}

注意,User類的username和password成員變量爲private的,這時再經過Field來反射操做這兩個成員變量就必須先經過setAccessible(true)設置後才行。
public class Demo1 {
@Test
public void fun1() throws Exception {
String className = "cn.itcast.User";
Class clazz = Class.forName(className);
User user = new User("zhangSan", "123");

Field field1 = clazz.getDeclaredField("username");
    Field field2 = clazz.getDeclaredField("password");
    
    field1.setAccessible(true);
    field2.setAccessible(true);
    
    String username = (String)field1.get(user);
    String password = (String)field2.get(user);
    
    System.out.println(username + ", " + password);
    
    field1.set(user, "liSi");
    field2.set(user, "456");
    
    System.out.println(user);
}

}

posted @ 2018-06-12 22:38  深沉有點事 閱讀( ...) 評論( ...) 編輯 收藏

相關文章
相關標籤/搜索