1. 類的加載
當程式要使用某個類時,如果該類還未被加載到記憶體中,則系統會通過加載,連接配接,初始化三步來實作對這個類進行初始化。
-
加載
就是指将class檔案讀入記憶體,并為之建立一個Class對象。
。任何類被使用時系統都會建立一個Class對象
-
連接配接
驗證:是否有正确的内部結構,并和其他類協調一緻
準備:負責為類的靜态成員配置設定記憶體,并設定預設初始化值
解析:将類的二進制資料中的符号引用替換為直接引用
- 初始化 就是我們以前講過的初始化步驟
2.反射機制
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHLxEkaNhXSU90MJpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2YjM2MTOxcTM5EzMwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
2.1 定義
JAVA反射機制是在運作狀态中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法和屬性;這種動态擷取的資訊以及動态調用對象的方法的功能稱為
java語言的反射機制
。
簡而言之:
反射就是通過class檔案對象,去使用該檔案中的成員變量,構造方法,成員方法。
2.2 擷取class檔案對象的方式:
- Object類的getClass()方法:不常用
- 資料類型的靜态屬性class:友善
- Class類中的靜态方法:最常用,參數是字元串,友善配置
(參數是包括包名的全路徑)public static Class forName(String className)
public static void main(String[] args) throws Exception {
// 方式1
Person p = new Person();
Class c = p.getClass();
Person p2 = new Person();
Class c2 = p2.getClass();
System.out.println(p == p2);// false
System.out.println(c == c2);// true
// 方式2
Class c3 = Person.class;
System.out.println(c == c3);// true
// 方式3
Class c4 = Class.forName("d1.Person");
System.out.println(c == c4);// true
}
2.3 擷取構造方法
// 1.擷取位元組碼檔案對象
Class c = Class.forName("cn.itcast_01.Person");
// 2.1擷取公有帶參構造方法
// public Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor con = c.getConstructor(String.class, int.class,String.class);
// 2.2擷取私有構造方法
Constructor con = c.getDeclaredConstructor(String.class);
con.setAccessible(true); // 值為true則訓示反射的對象在使用時應該取消Java語言通路檢查。
// 3.通過構造方法對象建立對象
// public T newInstance(Object... initargs)
Object obj = con.newInstance("林青霞", 27, "北京");
2.3 擷取成員變量
// 擷取公有成員變量address并對其指派
Field addressField = c.getField("address");
// public void set(Object obj,Object value) 設定新值
addressField.set(obj, "北京"); // 給obj對象的addressField字段設定值為"北京"
System.out.println(obj);
// 擷取私有成員變量name并對其指派
Field nameField = c.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj, "林青霞");
System.out.println(obj);
2.3 擷取成員方法
// 擷取公有方法 public void show()
// public Method getMethod(String name,Class<?>... parameterTypes)
// 第一個參數表示的方法名,第二個參數表示的是方法的參數的class類型
Method m1 = c.getMethod("show");
m1.invoke(obj); // 調用obj對象的m1方法
// 擷取私有方法 private String getString(String s, int i)
Method m3 = c.getMethod("getString", String.class, int.class);
m3.setAccessible(true);
Object objString = m3.invoke(obj, "hello", 100);
System.out.println(objString);
3. commons-beanutils工具
内省依賴反射
,但比反射簡化一點點,用來操作JavaBean把Map中的資料封裝到指定類型的JavaBean中。
1. 通過Class對象擷取BeanInfo
BeanInfo info = Introspector.getBeanInfo(User.class);
2. 通過BeanInfo擷取所有屬性描述符對象
PropertyDescriptor[] pds = info.getPropertyDescriptors();
3. PropertyDescriptor:
* String name getName():擷取目前屬性名稱
* Method getReadMethod():擷取get方法反射對象
* Method getWriteMethod():擷取set方法反射對象
commons-beanutils這個工具。它
底層使用了内省
,對内省進行了大量的簡化!
BeanUtils.getProperty(Object bean, String propertyName)
BeanUtils.setProperty(Object bean, String propertyName, String propertyValue)
BeanUtils.populate(Map map, Object bean)
1. jar包
commons-beanutils.jar、commons-logging.jar
2. 通過反射設定Javabean
Class<User> clazz = User.class;
Object user = clazz.newInstance();
BeanUtils.setProperty(user, "username", "admin");
BeanUtils.setProperty(user, "password", "admin123");
3. 擷取屬性值
String username = BeanUtils.getProperty(user, "username");
4. 把Map資料封裝到JavaBean對象中
Map<String,String> map = new HashMap<String,String>();
map.put("username", "admin");
map.put("password", "admin123");
User user = new User();
BeanUtils.populate(user, map);
要求:map的key名稱必須與User類的屬性名稱相同。不要無法指派!