一.類的加載機制
jvm把class文件加載到內存,並對數據進行校驗、解析和初始化,最終形成jvm可以直接使用的java類型的過程。
(1)加載
將class文件字節碼內容加載到內存中,並將這些靜態數據轉換成方法區中的運行時數據結構,在堆中生成一個代表這個類的java.lang.Class對象,作為方法區類數據的訪問入口。
(2)鏈接 將java類的二進制代碼合並到jvm的運行狀態之中的過程。
-
- 驗證:確保加載的類信息符合jvm規范,沒有安全方面的問題。
- 准備:正式為類變量(static變量)分配內存並設置類變量初始值的階段,這些內存都將在方法區中進行分配。
- 解析:虛擬機常量池內的符號引用替換為直接引用的過程。(比如String s ="aaa",轉化為 s的地址指向“aaa”的地址)
(3)初始化
初始化階段是執行類構造器方法的過程。類構造器方法是由編譯器自動收集類中的所有類變量的賦值動作和靜態語句塊(static塊)中的語句合並產生的。
當初始化一個類的時候,如果發現其父類還沒有進行過初始化,則需要先初始化其父類的初始化
虛擬機會保證一個類的構造器方法在多線程環境中被正確加鎖和同步
當訪問一個java類的靜態域時,只有真正聲明這個靜態變量的類才會被初始化。
二.java反射機制
通俗地說:反射就是將Student類中的方法、成員變量、構造方法,抽象出來可以讓Class的對象單獨進行訪問。
JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;
這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。
1、獲取Class對象的三種方式
(1)通過調用forName(String className),注意className的格式為:包名.類名獲得Class對象。
(2)通過類獲取Class對象,String.class、int.class這些字節碼是Class類的對象。
(3)通過類的對象獲取Class對象。
1 public static void getClass1() throws ClassNotFoundException { 2 //獲取Class的方法 3 //正射 4 Student stu=new Student(); 5 //第一種(優先選擇):傳的是包名.類名,通過包名和類名獲得反射Class 6 Class cl1=Class.forName("day20.Student"); 7 //第二種:通過類來獲取Class對象 8 Class cl2=Student.class; 9 //第三種:通過對象獲取Class對象 10 Student s=new Student(); 11 Class cl3=s.getClass(); 12 //判斷三種方法是否是同一個Class對象 13 System.out.println(cl1==cl2); 14 System.out.println(cl2==cl3); 15 16 }
2、獲取構造方法
(1)獲取公開的構造方法
(2)獲取所有的構造方法
主要為調取Student類中的私有方法。注意:不能獲得Student類的父類Human中的構造方法。
(3)調用特定的構造方法
無參構造和有參構造方法Constructors1.newInstance();//實例化獲取的類
私有構造方法的調用,要注意要設置其訪問權限Constructors1.setAccessible(true)。
1 public static void getConstruction() throws Exception { 2 //獲取構造方法 3 Class cl=Class.forName("day20.Student"); 4 System.out.println("==========公開的構造方法=========="); 5 //獲得公開的構造方法 6 Constructor[] cons=cl.getConstructors(); 7 for(Constructor con:cons) { 8 System.out.println(con); 9 } 10 System.out.println("==========所有的構造方法=========="); 11 //獲得所有的構造方法 12 Constructor[] constructors=cl.getDeclaredConstructors(); 13 for (Constructor con:constructors 14 ) { 15 System.out.println(con); 16 } 17 System.out.println("==========調用構造方法=========="); 18 //調用無參構造方法 19 Constructor constructors1=cl.getConstructor(); 20 Student student=(Student)constructors1.newInstance(); 21 //調用有參構造方法 22 Constructor constructors2=cl.getConstructor(String.class); 23 Student student1=(Student) constructors2.newInstance("英語"); 24 //調用私有構造方法 25 Constructor constructors3=cl.getDeclaredConstructor(int.class); 26 constructors3.setAccessible(true);//因為是私有化的方法,所以要設置訪問權限 27 Student student2=(Student) constructors3.newInstance(2); 28 }
執行結果:
==========公開的構造方法========== |
3、獲取方法
私有屬性的調用,要注意要設置其訪問權限Constructors1.setAccessible(true)。
1 private static void getMethod1() throws Exception { 2 Class cl=Class.forName("day20.Student"); 3 //獲取所有公開的方法,包括Object中的類 4 Method[] method=cl.getMethods(); 5 for (Method m:method 6 ) { 7 System.out.println(m.getName()); 8 } 9 //獲取本類中所有的方法,不包括父類和eObject 10 System.out.println("==========私有方法=========="); 11 Method[] methods=cl.getDeclaredMethods(); 12 for (Method ms:methods 13 ) { 14 System.out.println(ms.getName()); 15 } 16 //調取方法 17 System.out.println("==========調取特有方法=========="); 18 //獲取非靜態的無參方法 19 Method method1=cl.getMethod("eat"); 20 //獲取Student類的成員 21 Constructor constructor=cl.getConstructor(); 22 Student student=(Student)constructor.newInstance(); 23 method1.invoke(student); 24 //獲取非靜態含參方法 25 Method method2=cl.getMethod("study", String.class); 26 method2.invoke(student,"物理"); 27 //獲取靜態無參方法 28 Method method3=cl.getMethod("sleep"); 29 method3.invoke(null); 30 //獲取靜態含參方法 31 try { 32 Method method4=cl.getMethod("saveMoney", double.class); 33 method4.setAccessible(true); 34 method4.invoke(null,100.0); 35 }catch (NoSuchMethodException e){ 36 e.getMessage(); 37 }catch(Exception e){ 38 e.getMessage(); 39 } 40 41 }
執行結果:
getName |
4、獲取屬性
1 private static void getAttribute1() throws Exception{ 2 Class cl=Class.forName("day20.Student"); 3 //獲取所有屬性 4 Field[] fields=cl.getFields(); 5 for (Field field:fields 6 ) { 7 System.out.println("屬性值有:"+field.getName()); 8 } 9 //獲取私有化屬性 10 Field field=cl.getDeclaredField("money"); 11 field.setAccessible(true); 12 //獲取Student類的成員 13 Constructor constructor=cl.getConstructor(); 14 Student student=(Student)constructor.newInstance(); 15 student.setMoney(100); 16 System.out.println("通過對象.方法進行屬性賦值:"+student.getMoney()); 17 field.set(student,200); 18 System.out.println("通過Field對象.方法進行賦值:"+student.getMoney()); 19 }
執行結果:
屬性值有:name |
Student類和父類
1 package day20; 2 3 public class Student extends Human{ 4 public String name; 5 int age; 6 private double money; 7 8 public Student() { 9 System.out.println("無參構造方法"); 10 } 11 public Student(String subject) { 12 System.out.println("有參構造方法"+subject); 13 } 14 15 private Student(int i) { 16 System.out.println("私有構造方法"+i); 17 } 18 public String getName() { 19 return name; 20 } 21 public void setName(String name) { 22 this.name = name; 23 } 24 public int getAge() { 25 return age; 26 } 27 public void setAge(int age) { 28 this.age = age; 29 } 30 public double getMoney() { 31 return money; 32 } 33 public void setMoney(double money) { 34 this.money = money; 35 } 36 37 public void eat(){ 38 System.out.println("吃飯"); 39 } 40 41 public void study(String subject){ 42 System.out.println("學習"+subject); 43 } 44 45 public static void sleep(){ 46 System.out.println("睡覺"); 47 } 48 49 private static void saveMoney(double money){ 50 System.out.println("存款"+money); 51 } 52 } 53 54 55 package day20; 56 57 public class Human { 58 private String sex; 59 public Human(){ 60 61 } 62 63 private Human(int i){ 64 65 } 66 67 public String getSex() { 68 return sex; 69 } 70 71 public void setSex(String sex) { 72 this.sex = sex; 73 } 74 }