反射:
反射:在運行時動態分析或使用一個類進行工作。
java.lang.Class類:描述類信息的類。
類對象:描述一個類信息的對象,當虛擬機加載類的時候,就會創建這個類的類對象並加載該對象,Class是類對象的類型。
獲得類對象的方式:
用" 類名.class "獲得這個類的類對象。
用類的對象掉用getClass(),如object.getClass()得到這個對象的類型的類對象。
可以使用Class.forName(類名),也可以得到這個類的類對象,(注意,這裏寫的類名必須是全限定名(全名),是包名加類名,XXX.XXX.XXXX)。
基本類型也有類對象,用" 封裝類.TYPE "可以獲得對應的基本類型的類對象。
java.lang.reflect包下的三個重要類:
Field屬性類:用來描述屬性的信息。
Method方法類:方法的信息的描述。
Constructor構造方法類:用來描述構造方法的信息。
Class類中的常用方法:
newInstance()
創建此 Class 對象所表示的類的一個新實例(調用無參構造創建的對象)。
getDeclaredMethods()
獲得的是一個Method方法類對象的數組,獲得本類(不包括父類)聲明的所有(包括private的)方法對象。
getMethods() //推薦使用
獲得的是一個Method方法類對象的數組,獲得所有(父類的也包括)publice的方法對象。
getDeclaredConstructors()
獲得的是一個Constructor構造方法類對象的數組,獲得這個類聲明的所有構造方法對象。
getConstructors() //推薦使用
獲得的是一個Constructor構造方法類對象的數組,獲得所有publice的構造方法對象。
getDeclaredFields() //推薦使用
獲得的是一個Field屬性類對象的數組,獲得本類聲明的所有屬性的屬性對象。
getFields()
獲得的是一個Field屬性類對象的數組,獲得所有publice的屬性對象。
使用反射構造一個類的對象的步驟:
a. 獲得類對象
b. 獲得構造方法對象
c. 獲得對象,用構造方法對象調用構造方法,如果使用無參構造方法,可以跳過第二步,直接使用" 類對象.newInstance() "方法來獲得這個類的對象
d. 獲得方法對象
e. 用方法對象調用方法(用這個類的對象作爲第一參數)
如下面的例子:
反射機制的實現類:
package day07.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class TestReflect {
public static Object get(String className , Map<String,Object> map) throws Exception{
Class c = Class.forName(className); //獲得類對象
Object o = c.newInstance(); //獲得對象
Set<String> set = map.keySet();
for(String str : set){
String s = "set" + str.substring(0,1).toUpperCase()+str.substring(1);
Field f = c.getDeclaredField(str);
Method m = c.getMethod(s, f.getType()); //獲得方法對象
m.invoke(o, map.get(str)); //用方法對象調用方法
}
return o;
}
public static void main(String[] args) throws Exception {
Map m = new HashMap();
m.put("name", "zhang");
m.put("age", 22);
Object o = get("day07.reflect.Student",m);
Student s = (Student) o;
System.out.println(s.getName() + " " + s.getAge());
Map m1 = new HashMap();
m1.put("name", "li");
m1.put("gender", "男");
Object o1 = get("day07.reflect.Teacher",m1);
Teacher t = (Teacher) o1;
System.out.println(t.getName() + " " + t.getGender());
}
}
學生類:
package day07.reflect;
public class Student {
private String name;
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
教師類:
package day07.reflect;
public class Teacher {
private String name;
private String gender;
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
內部類:
定義:
定義在另外一個類中的類,就是內部類。
編譯後生成的兩個獨立的類:Outer.class 和Outer$Inner.class。
內部類的分類:
靜態內部類:靜態內部類定義在類中,任何方法外,用static修飾
靜態內部類只能訪問外部類的靜態成員。
在外部類的外部,要創建一個靜態內部類對象不需要外部類對象:
Outer.Inner in = new Outer.Inner();
在本類內部生成內部類對象的方式:
Inner in = new Inner();
成員內部類:作爲外部類的一個成員存在,與外部類的屬性、方法並列
在內部類中可以直接訪問外部類的私有屬性。
內部類和外部類的實例變量允許命名衝突。
在內部類中訪問實例變量:this.屬性
在內部類訪問外部類的實例變量:外部類名.this.屬性
在外部類的外部,要創建一個成員內部類對象,要首先建立一個外部類對象,然後再創建一個成員內部類對象。
Outer out = new Outer();
Outer.Inner in = out.new Inner();
在本類內部生成內部類對象的方式:
在靜態方法中:Inner in = new Outer().new Inner();
在非靜態方法中:Inner in = this.new Inner();
成員內部類不可以有靜態成員,這是因爲靜態屬性是在加載類的時候創建,這個時候內部類還沒有被創建。
局部內部類:在外部類的方法中定義的內部類
與局部變量類似,在局部內部類前不可以加修飾符public和private,其作用域爲定義它的代碼塊。
局部內部類不僅可以訪問外部類的實例變量,還可以訪問外部類的局部變量,但要求外部類的局部變量必須爲final的。
配合接口使用,來做到強制弱耦合。
在外部類的外部不可創建局部內部類對象,只能在局部內部類所在的方法中創建:
Inner in = new Inner();
匿名內部類:一種特殊的局部內部類
沒有名字,也沒有class、extends、implements關鍵字
用一種隱含的方式實現一個接口或繼承一個類,並且只能創建一次實例。
實現方式:在某個語句中,new 父類/父接口名字(){ 類體中實現方法 }
例如:
TreesSet ts = new TreeSet(new Comparator(){
public int compare(Object o1, Object o2){
return 0;
}
});
匿名內部類屬於局部內部類,那麼局部內部類的所有限制都對其生效。
匿名內部類是唯一一種無構造方法的類,因爲構造器的名字必須合類名相同,而匿名內部類沒有類名。