1. 類的加載
當程序要使用某個類時,如果該類還未被加載到內存中,則系統會通過加載,連接,初始化三步來實現對這個類進行初始化。
- 加載
就是指將class文件讀入內存,併爲之創建一個Class對象。
任何類被使用時系統都會建立一個Class對象
。 - 連接
驗證:是否有正確的內部結構,並和其他類協調一致
準備:負責爲類的靜態成員分配內存,並設置默認初始化值
解析:將類的二進制數據中的符號引用替換爲直接引用 - 初始化 就是我們以前講過的初始化步驟
2.反射機制
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類的屬性名稱相同。不要無法賦值!