java 反射 内存_Java内存到反射入门
Java內存到反射入門(一)
初識Java內存
平常我們最常提到的的JAVA分區是這三個分區
其中方法區是一個特殊的堆,功能如圖上所示。
初識反射:框架設計的靈魂
反射的功能:將類的各個組成部分封裝為對象,并在程序運行的過程中可以調用它們。
Java代碼的三個階段
我們平時書寫的java代碼,從書寫完成到內存中執行主要經歷了三個階段:Source 源代碼階段,class類對象階段,Runtime運行時階段。下圖以一個簡單的Person類來舉例說明。
第一階段:Source源代碼階段
首先,我們編寫好了一個Person類的代碼,它由成員變量,構造方法,成員方法三部分組成。
public class Person{
private String name;
private int age;
public Person(){}
public void eat(){}
}
此時它是一個Person.java文件。還不能運行,接著我們要用javac命令編譯它,使生成一個Person.Class字節碼文件。
這個文件我們并不能看懂,其實里面主要包含三部分內容:成員變量,成員方法和構造方法,還有一些諸如包名的信息。
至此,源代碼和字節碼都是以文件的形式儲存在硬盤上的,還未進入內存,此階段我們稱之為Source源代碼階段。
第二階段:Class類對象階段
要想由第一個階段進入第二個階段,要經過一個加載的過程。由類加載器ClassLoder將class文件加載到內存中,并生成該類的class類對象。class類對象是來描述字節碼文件的,字節碼文件被封裝為三大部分:
1.成員變量被封裝為Field對象,并用Filed[]存儲。
2.構造方法被封裝為Constructor對象,并用Constructor[]存儲。
3.成員方法被封裝為Method對象,并用Method[]存儲。
這樣的封裝就是反射機制,經過了這樣的封裝后,我們就可以在程序運行的過程中來操作這些對象了。即獲取,修改變量和執行方法等。
舉個栗子:在IDEA等IDE中,寫如下一段代碼:
//定義了一個字符串變量,并嘗試調用它自帶的方法
String str = "abc";
str.
在按下str后面這個.后,IDEA會提示許多的方法。
那么為什么IDEA會提示這些方法呢?其實內部就是反射機制。 定義了一個String變量后,則字符串的字節碼文件就會被加載進內存。在內存中就有了String的class類對象,里面封裝了Method[]存儲了所有String的方法。所以只要挨個顯示一下就可以了。
第三階段:Runtime運行時階段
第二階段通過創建對象等操作就會進入第三階段,創建對象時就會根據這個class類對象創建一個真正的Person對象。
獲得class類的三種方法
Class.forName("全類名"):將字節碼文件加載進內存,返回Class對象 * 多用于配置文件,將類名定義在配置文件中。讀取文件,加載類
//如獲取Person類的.Class文件
Class a = Class.forName("Domain.Person");//Domian是Person類所在包
類名.class:通過類名的屬性class獲取,該方法多用于參數的傳遞。
Class a = Person.calss;
對象.getClass():getClass()方法在Object類中定義著,該方法多用于對象的獲取字節碼的方式
Person person = new Person();
Class a = person.getClass();
Tip:同一個字節碼文件(*.class)在一次程序運行過程中,只會被加載一次,不論通過哪一種方式獲取的Class對象都是同一個。
//采用多種方式得到.Class文件
Class a = Class.forName("Domain.Person");
Person person1 = new Person();
Person person2 = new Person();
Class b = person1.getClass();
Class c = Person.class;
Class d = person2.getClass();
//不管以哪種方式得到的.Class類,只要是Person類的,那就是一樣的。
System.out.println(a==b); //true
System.out.println(c==b); //true
System.out.println(a==c); //true
System.out.println(a==d); //true
Class類的用法
在熟悉了Class類的獲取方法后,自然要熟悉其用法。
//以下是測試用的Person類
public class Person {
private String name;
private int age;
private int id;
public Person() {
}
public Person(String name, int age, int id) {
this.name = name;
this.age = age;
this.id = id;
}
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;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Person{" +
"name='" \+ name \+ '\\'' +
", age=" \+ age +
", id=" \+ id +
'}';
}
}
用法一:獲取類的名字
方法有兩個:
String getName(); //返回類的包名+類名
String getSimpleName();//獲取簡單類名
Class c1 = Person.class;
System.out.println(c1.getName()); //該方法獲取類的全名,輸出Domain.Person
System.out.println(c1.getSimpleName());//該方法獲取類的簡單名,即Person
用法二:獲得類的屬性
方法有四個:
Field[] getFields() :獲取所有public修飾的成員變量
Field getField(String name) 獲取指定名稱的 public修飾的成員變量
Field[] getDeclaredFields() 獲取所有的成員變量,不考慮修飾符
Field getDeclaredField(String name)
用法三:獲得類的方法
方法有四個:
Method[] getMethods() ;
Method getMethod(String name, 類>... parameterTypes) ;
Method[] getDeclaredMethods() ;
Method getDeclaredMethod(String name, 類>... parameterTypes) ;
注意第一個方法會獲取包括本類和父類的所有public方法。 第二個方法只會獲取本類的所有方法,包括private的,不包括父類的方法。
獲取指定方法的第一個參數是方法的名稱,第二個參數是要獲取的方法的參數類型,如setName(String name);函數,參數是String,則此處寫String.Class;
用法四:獲得構造器(構造方法)
有四種方法:
獲取構造方法們
Constructor>[] getConstructors()
Constructor getConstructor(類>... parameterTypes)
Constructor getDeclaredConstructor(類>... parameterTypes)
Constructor>[] getDeclaredConstructors() ;
總結
以上是生活随笔為你收集整理的java 反射 内存_Java内存到反射入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux多线程——使用互斥量同步线程
- 下一篇: java美元兑换,(Java实现) 美元