一、類加載器
1、Java類加載機制
- 加載:將class文件字節碼內容加載到內存中,並將這些靜態數據轉換成方法區中的運行時數據結構,在堆中生成一個代表這個類的java.lang.Class對象,作爲方法區類數據的訪問入口。
- 鏈接:將java類的二進制代碼合併到 jvm的運行狀態之中的過程,鏈接過程又分爲3個過程:
- 驗證:確保加載的類信息符合jvm規範,沒有安全方面的問題。
- 準備:正式爲類變量(static變量)分配內存並設置類變量初始值的階段, 這些內存都將在方法區中進行分配。
- 解析:虛擬機常量池內的符號引用替換爲直接引用的過程。(比如String s =“aaa”,轉化爲 s的地址指向“aaa”的地址)
- 初始化:初始化階段是執行類構造器方法的過程。類構造器方法是由編譯器自動收集類中的所有類變量的賦值動作和靜態語句塊(static塊)中的語句合併產生的。當初始化一個類的時候,如果發現其父類還沒有進行過初始化,則需要先初始化其父類的初始化虛擬機會保證一個類的構造器方法在多線程環境中被正確加鎖和同步 當訪問一個java類的靜態域時,只有真正聲明這個靜態變量的類纔會被初始 化。
Java類的生命週期:
2、ClassLoader類加載器
ClassLoader類加載器的作用就是將 .class
文件加載到JVM虛擬機中去。
package com.lydms.test;
public class ClassLoaderDemo {
public static void main(String[] args) throws ClassNotFoundException {
//獲取類加載器
ClassLoader classLoader = ClassLoaderDemo.class.getClassLoader();
//常用三種方式加載類
// 使用ClassLoader.loadClass()來加載類,不會執行初始化塊
System.out.println("‐‐ClassLoader.loadClass()‐‐");
classLoader.loadClass("com.lydms.test.Test1");
// 使用Class.forName(clssName) 來加載類,默認會執行初始化塊
System.out.println("‐‐Class.forName(clssName)‐‐");
Class.forName("com.lydms.test.Test2");
// 使用Class.forName(className, initialize, ClassLoader) 來加載類,並指定ClassLoader,初始化時不執行靜態塊.
// 參數:類名,是否初始化,類加載器
System.out.println("‐‐Class.forName(className,initialize,ClassLoader)‐‐");
Class.forName("com.lydms.test.Test3", false, classLoader);
}
}
class Test1 {
static {
System.out.println("Test1 靜態初始化塊");
}
}
class Test2 {
static {
System.out.println("Test2 靜態初始化塊");
}
}
class Test3 {
static {
System.out.println("Test3 靜態初始化塊");
}
}
二、獲取Class對象的方式
1、Class.forName(“全類名”)
通過指定的字符串路徑獲取
Class<?> aClass = Class.forName("com.lydms.classes.TestFiled");
2、類名.class
通過類名的屬性class獲取
Class<ArrayList> arrayListClass = ArrayList.class;
3、對象.getClass()
通過對象的getClass()方法獲取
Class<? extends TestFiled> aClass = new TestFiled().getClass();
三、常用方法:
字節碼文件 | Class類 | Class.forName() |
---|---|---|
構造方法 | Constructor類 | getConstructor() |
成員方法 | Method類 | getMethod() |
成員變量 | Field類 | getField() |
首先獲取該類的class對象
Class<?> aClass = Class.forName("com.lydms.classes.TestFiled");
1、獲取構造方法、成員方法、成員變量(公開的public)
// 構造方法
Constructor<?>[] constructors = aClass.getConstructors();
// 成員方法
Method[] methods = aClass.getMethods();
// 成員變量
Field[] fields = aClass.getFields();
2、獲取構造方法、成員方法、成員變量(所有的public+private)
// 構造方法
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
// 成員方法
Method[] declaredMethods = aClass.getDeclaredMethods();
// 成員變量
Field[] declaredFields = aClass.getDeclaredFields();
3、獲取名稱
String name = aClass.getName();
// 返回源代碼中給出的底層類的簡稱。
String simpleName = aClass.getSimpleName();
String typeName = aClass.getTypeName();
4、獲取父接口
Class<?> superclass = aClass.getSuperclass();
5、獲取實現的接口
Class<?>[] interfaces = aClass.getInterfaces();
6、實例化爲新對象
Object newInstance = aClass.newInstance();
7、返回此元素上存在的所有註釋
返回此元素上存在的所有註釋(public)
RestController annotation = aClass.getAnnotation(RestController.class);
// 獲取所有
Annotation[] annotations = aClass.getAnnotations();
for (int i = 0; i < annotations.length; i++) {
System.out.println(annotations[i].toString());
}
返回此元素上存在的所有註釋(public+private)
RestController declaredAnnotation = aClass.getDeclaredAnnotation(RestController.class);
// 獲取所有
Annotation[] aas = aClass.getDeclaredAnnotations();
for (int i = 0; i < aas.length; i++) {
System.out.println(aas[i].toString());
}
8、返回此類的包(package com.lydms.classes)
String packUrl = aClass.getPackage().toString();
9、查找帶有給定名稱的資源(打印絕對路徑)
URL resource = aClass.getResource("TestFiled.class");
System.out.println(resource.getPath().toString());
10、判斷類型
// 是否爲數組類
boolean isArray = aClass.isArray();
// 是否爲接口類
boolean isInterface = aClass.isInterface();
// 是否爲枚舉類
boolean isEnum = aClass.isEnum();
四、案例
1、獲取對應的名稱
getName();
通過一個對象獲得完整的包名+類名(java.util.HashMap)
HashMap<String, String> hashMap = new HashMap<>();
String name = hashMap.getClass().getName();
System.out.println(name);
2、獲得類的簡稱(HashMap)
getSimpleName();
獲得類的簡稱(HashMap)
HashMap<String, String> hashMap = new HashMap<>();
String typeName = hashMap.getClass().getSimpleName();
System.out.println(typeName);
3.實例化Class對象
forName("com.lydms.utils.Test")
package com.lydms.utils;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
// 實例化Class對象(com.lydms.utils.Test)
Class<?> aClass1 = Class.forName("com.lydms.utils.Test");
Class<? extends Test> aClass2 = new Test().getClass();
Class<Test> aClass3 = Test.class;
System.out.println(aClass1.getName());
System.out.println(aClass2.getName());
System.out.println(aClass3.getName());
}
}
4、獲取一個對象的父接口和實現的接口
getSuperclass(); //父接口
getInterfaces(); //接口實現類
package com.lydms.utils;
import java.io.Serializable;
public class Test implements Serializable {
public static void main(String[] args) throws ClassNotFoundException {
// 4、獲取一個對象的父接口和實現的接口
Class<?> aClass = Class.forName("com.lydms.utils.Test");
Class<?> superclass = aClass.getSuperclass();
// 獲取到的父類
String parentName = superclass.getName();
System.out.println("父類名爲:" + parentName);
// 獲得所有的接口實現類
Class<?>[] interfaces = aClass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
System.out.println("實現的接口爲:" + interfaces[i]);
}
}
}
5、反射機制實例化一個類的對象
newInstance();
getConstructors();
getParameterTypes();
方法一:
// 1、強轉爲指定格式對象
Class<?> aClass = Class.forName("com.lydms.utils.User");
User user = (User) aClass.newInstance();
user.setName("張三");
user.setAge(11);
System.out.println(user.toString());
方法二:
// 2、方式二(先獲取方法對象,在取參數)
Constructor<?>[] constructors = aClass.getConstructors();
for (int i = 0; i < constructors.length; i++) {
Class<?>[] parameterTypes = constructors[i].getParameterTypes();
for (int i1 = 0; i1 < parameterTypes.length; i1++) {
String name = parameterTypes[i1].getName();
System.out.println("name"+name);
}
}
實體類
package com.lydms.utils;
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
6、獲取某個類的全部屬性
aClass.getDeclaredFields(); //獲取本類的全部屬性(數組)
aClass1.getFields(); //獲取實現的接口或父類的屬性
fields[i].getModifiers() //數字型權限修飾符
Modifier.toString(modifiers); //將返回的數字型修飾符,轉爲string類型。(private static final)
獲取本類的全部屬性(數組)
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Test{
private static final long seriaVersionUID = 342342342;
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("com.lydms.utils.Test");
// 獲取本類的全部屬性(循環獲取)
Field[] fields = aClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
// 權限修飾符(private static final)
int modifiers = fields[i].getModifiers();
String str = Modifier.toString(modifiers);
System.out.println(str);
// 屬性類型(long)
Class<?> type = fields[i].getType();
// private static final + long + seriaVersionUID;
System.out.println(str + "+" + type.getName() + "+" + fields[i].getName() + ";");
}
}
獲取實現的接口或父類的屬性
public interface interfaceTest {
static final long interfaceTest= 111111;
}
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Test implements interfaceTest {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("com.lydms.utils.Test");
Field[] fields1 = aClass.getFields();
for (int i = 0; i < fields1.length; i++) {
int mo = fields1[i].getModifiers();
String str = Modifier.toString(mo);
// 權限修飾符(private static final)
System.out.println(str);
// 屬性類型(long)
Class<?> type = fields1[i].getType();
System.out.println(type.getName());
// 方法的名稱(interfaceTest)
System.out.println(fields1[i].getName());
}
}
}
7、獲取某個類的全部屬性(修飾符,入參,返回值)
aClass.getMethods(); //獲取類中所有方法
methods[i].getName() //方法名
methods[i].getModifiers(); //修飾符
methods[i].getReturnType().getTypeName(); //返回值類型
methods[i].getParameterTypes(); //獲取入參的對象
methods[i].getExceptionTypes() //拋出的異常
待獲取方法
package com.lydms.classes;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class TestClass {
public String getClass(String in) throws IOException {
System.out.println("獲取所有的方法");
return null;
}
}
獲取TestClass中全部屬性
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("com.lydms.classes.TestClass");
Method[] methods = aClass.getMethods();
for (int i = 0; i < methods.length; i++) {
1.方法名(getClass)
String name = methods[i].getName();
2.修飾符(public)
int modifiers = methods[i].getModifiers();
String modifierName = Modifier.toString(modifiers);
3.返回值類型(java.lang.String)
String name1 = methods[i].getReturnType().getName();
4.入參的對象(class java.lang.String)
Class<?>[] parameterTypes = methods[i].getParameterTypes();
5. 拋出的異常( class java.io.IOException)
Class<?>[] exceptionTypes = methods[i].getExceptionTypes();
}
}
8、通過反射機制調用某個類的方法
aClass.newInstance() //闖將TestRun類的對象
test01.invoke(aClass.newInstance()); //執行test01方法
待獲取方法
public class TestRun {
public void test01(){
System.out.println("執行Test01方法");
}
public void test02(int age,String name){
System.out.println("執行Test02方法,其中年齡:"+age+",姓名:"+name);
}
}
執行裏面方法
public static void main(String[] args) throws Exception{
Class<?> aClass = Class.forName("com.lydms.classes.TestRun");
// 1、調用TestRun類中的test01()方法
Method test01 = aClass.getMethod("test01");
test01.invoke(aClass.newInstance());
// 2、調用TestRun類中的test02()方法
Method test02 = aClass.getMethod("test02", int.class, String.class);
// test02的執行,需要TestRun的對象,和2個入參
test02.invoke(aClass.newInstance(),10,"李四");
}
9、更改類中屬性
aClass.getDeclaredField("pro"); //獲取裏面參數pro的對象
pro.set(testObject, "新的參數"); //設置pro參數的值
pro.get(testObject) //獲取pro參數的值(TestFiled類對象)
待獲取方法
public class TestFiled {
private String pro = null;
}
執行裏面方法
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("com.lydms.classes.TestFiled");
Field pro = aClass.getDeclaredField("pro");
// true 則指示反射的對象在使用時,應該取消Java 語言訪問檢查
pro.setAccessible(true);
Object testObject = aClass.newInstance();
pro.set(testObject, "新的參數");
/ 打印更改後的參數值
System.out.println(pro.get(testObject));
}
10、執行配置文件中指定的類中方法
配置文件application.properties
className=com.lydms.utils.TestClass
methodName=test
測試執行的方式:
package com.lydms.utils;
public class TestClass {
public void test(){
System.out.println("通過反射執行test中方法");
}
}
反射使用代碼:
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
public class GoToClass {
public static void main(String[] args) throws Exception {
// 1.1 創建Properties對象
Properties pro = new Properties();
// 1.2 加載配置文件,轉換爲一個集合
InputStream is = new FileInputStream("E:\Code\test\src\main\java\com\lydms\utils\TestClass.java");
// 加載配置信息
pro.load(is);
// 2. 獲取配置文件中定義的數據
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
// 3. 加載該類進內存
Class cls = Class.forName(className);
// 4. 創建對象
Object obj = cls.newInstance();
// 5. 獲取方法對象
Method method = cls.getMethod(methodName);
// 6. 執行方法
method.invoke(obj);
}
}
執行結果:
11、通過反射機制往List中添加任意類型的元素
注意:這只是演示反射機制,在正常的開發中不能這樣使用(忽略了創建對象時,指定的類型)
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
List<Integer> list = new ArrayList<Integer>();
list.add(11);
//獲取類
Class<?> class1 = list.getClass();
//獲取方法
Method addMethod = class1.getMethod("add", Object.class);
//執行,添加任意類型對象
addMethod.invoke(list, "asfdgh");
addMethod.invoke(list, true);
addMethod.invoke(list, new Date());
System.out.println(list);
}
}
五、Xmind整理
CSDN地址:
百度網盤地址:
鏈接:https://pan.baidu.com/s/1_RKxpkZehV0wSFASdv-LXQ
提取碼:czz3