java基礎-反射(1):基本類周邊資訊獲取
前言:堅持夢想,過程或是艱辛的,回憶是幸福的。與其最後豪言如果當時我怎樣怎樣,倒不如堅持腳下。
相關文章:
今天開始給大家講講有關反射的知識,在應用程式開發時,如果純做上層,搭搭框架啥的,那用到反射的機會不多,但如果你想做出來一個公共類或者公共模組給其它人用的時候,那用到反射的可能性就大大增加了。況且反射聽起來也是蠻屌的名字,今天就我們徹底認識他下吧。
一、引入
在開始反射之前,我們先看看JVM是如何將我們寫的類對應的java檔案載入到記憶體中的。1、類的生命週期
這部分我們先講講JVM的載入機制(可能會有點難度,我盡力講的直白點)我們寫一個最簡單的Main函式,來看看這個函式的是如何被執行的,程式碼如下:(Main.java)
- public
- publicstaticvoid main(String[] args) {
- Animal animal = new Animal();
- animal.setName("cat");
- }
- publicstaticclass Animal{
- private String name;
- public String getName() {
- return name;
- }
- publicvoid setName(String name) {
- this.name = name;
- }
- }
- }
大家都知道,在拿到一個java原始檔後,如果要經過原始碼編譯,要經過兩個階段:
編譯:
- javac Main.java
執行
然後使用java Main命令執行程式:
- java Main
裝載:類的裝載是通過類載入器完成的,載入器將.class檔案的二進位制檔案裝入JVM的方法區,並且在堆區建立描述這個類的java.lang.Class物件。用來封裝資料。 但是同一個類只會被類裝載器裝載一次,記住:只裝載一次!
連結:連結就是把二進位制資料組裝為可以執行的狀態。連結分為校驗,準備,解析這3個階段。校驗一般用來確認此二進位制檔案是否適合當前的JVM(版本),準備就是為靜態成員分配記憶體空間,並設定預設值。解析指的是轉換常量池中的程式碼作為直接引用的過程,直到所有的符號引用都可以被執行程式使用(建立完整的對應關係)。
初始化:初始化就是對類中的變數進行初始化值;完成之後,型別也就完成了初始化,初始化之後類的物件就可以正常使用了,直到一個物件不再使用之後,將被垃圾回收。釋放空間。
當沒有任何引用指向Class物件時就會被解除安裝,結束類的生命週期。如果再次用到就再重新開始裝載、連結和初始化的過程。
上面這一大段有關類生命週期有講解,可能會有些難度,畢竟有關JVM的東東不是三言兩語能講透徹的,通過上面的這一段只想告訴大家一點:類只會被裝載一次!!!!利用裝載的類可以例項化出各種不同的物件!
2、獲取類型別
1、泛型隱藏填充型別預設填充為無界萬用字元?
在上面,我們講了,類只會被裝載一次,利用裝載的類可以例項化出各種不同的物件。而反射就是通過獲取裝載的類來做出各種操作的。裝載的類,我們稱為類型別,利用裝載的類產生的例項,我們稱為類例項。下面我們就看看,如何利用程式碼獲取類型別的:- //使用方法一
- Class class1 = Animal.class;
- System.out.println(class1.getName());
- //使用方法二
- Class<?> class2= Animal.class;
- System.out.println(class2.getName());
從結果中可以看出class1和class2是完全一樣的,那構造他們時的方法一和方法二有什麼區別呢?
- //使用方法一
- Class class1 = Animal.class;
- //使用方法二
- Class<?> class2= Animal.class;
方法一中,是直接生成了一個Class的例項。
而在方法二中,則生成的是一個Class的泛型,並且使用的是無界萬用字元來填充的。有關無界萬用字元的事,下面再說,這裡先講講方法一中直接生成Class物件與方法二中生成的Class泛型的區別。
我們都知道,Class類是一個泛型。而泛型的正規寫法就應該是
- Class<Animal> class2= Animal.class;
- Class<?> class1 = Animal.class;
如果我們不用萬用字元,也就只能這樣寫:
- Class<Animal> class2= Animal.class;
在本文中,為了不誤導大家,我們採用完整的Class填充方式即Class<?>
2、獲取類型別的方法
上面我們通過Class<?> class1 = Animal.class,即直接使用類名的Class物件可以獲取類型別,這只是其中一個方法,下面這四種方法都可以獲得對應的類型別:- //方法一:
- Person person = new Person();
- Class a = person.getClass()
- //方法二:
- Class b = Persion.class;
- //方法三:
- Class c = Class.forName(String ClassName);
- //方法四:(不建議使用)
- Class d = context.getClassLoader().loadClass(String ClassName);
方法二中,直接通過類的class物件得到
方法三和方法四中是通過類名得到,這兩點要非常注意,這裡的ClassName一定要從包名具體到類名,唯一定位到一個類才行,不然就會報ClassNotFound錯誤
在上面我們提到過,類只會被載入一次,所以a,b,c,d都是相等的,因為他們都是指向同一個物件,如果用等號操作符來判斷的話:
- boolean result = (clazz1 == clazz2 && clazz3 == clazz4 && clazz1 == clazz3);
下面我們針對方法三和方法四舉個粟子來看下:
先看一下完整的程式碼結構:
可以看到我們有一個Activity:MyActivity,和一個類Animal;
我們在Activity上放一個btn,把所有程式碼放在btn的點選響應中,Activity的佈局難度不大就不再貼出程式碼,下面僅針對類型別的程式碼講解。
Animal類的定義與上方一樣,唯一不同的是,Animal類已經不再是內部類了而是單獨出來的一個類。
- publicclass Animal {
- private String name;
- public String getName() {
- return name;
- }
- publicvoid setName(String name) {
- this.name = name;
- }
- }
- //btn點選時呼叫demoFunc()函式
- Button button = (Button)findViewById(R.id.btn);
- button.setOnClickListener(new View.OnClickListener() {
- @Override
- publicvoid onClick(View v) {
- try{
- demoFunc();
- }catch (Exception e){
- System.out.print(e.getMessage());
- }
- }
- });
- publicvoid demoFunc()throws Exception{
- Class<?> class1 = Class.forName("com.example.myReflect.Animal");
- Log.d(TAG,"通過Class.forName獲得的類名:"+class1.getName());
- class1 = getClassLoader().loadClass("com.example.myReflect.Animal");
- Log.d(TAG,"通過ClassLoader獲得的類名:"+class1.getName());
- }
- privatestatic String TAG = "qijian";
從上面的用法中,可以看出,我們要使用Class.forName()或者getClassLoader().loadClass(),其中的類名必須是從包名到類名的完整路徑!
從這裡看來Class.forName()和getClassLoader().loadClass()是相同的,其實他們是有區別的,平時,我們不建議使用getClassLoader().loadClass()的方法來載入類型別。有關Class.forName()和getClassLoader().loadClass()的具體區別,會在本篇末尾講述。
二、基本類型別周邊資訊獲取
我們知道類分為基本類和泛型類,這篇我們只講基本類型別的周邊資訊獲取,有關泛型類的周邊資訊獲取,我們會放到下一篇中。
這部分主要講述類型別周邊資訊獲取方法,包括類名,包名,超類和繼承介面。
1、類名,包名獲取
相關的有三個函式:- //獲取完整的類名(包含包名)
- public String getName();
- //僅獲取類名
- public String getSimpleName();
- //獲取類型別所對應的package物件
- public Package getPackage()
- Class<?> class1 = Animal.class;
- Package package1 = class1.getPackage();
- Log.d(TAG,"完整的類名:"+class1.getName());
- Log.d(TAG,"僅獲取類名:"+class1.getSimpleName());
- Log.d(TAG,"包名:"+package1.getName());
從結果中很清晰的看到,class.getName()獲取的是類名包含完整路徑。呼叫Class.forName()就是用的這個值。class.getSimpleName()得到的是僅僅是一個類名。而class.getPackage()得到的是該類對應的Package物件。通過package.getName()能獲得該類所對應的包名。
有關Package類的相關函式就不講了,基本用不到。
(2)、獲取超類Class物件
獲取superClass的類物件,涉及到兩個函式:- //獲取普通函式的父類Class物件
- public Class<?> getSuperclass();
- //針對泛型父類而設計
- public Type getGenericSuperclass();
我們仍然利用前面講到的Animal類,然後在其上派生一個AnimalImpl子類:
- publicclass Animal {
- private String name;
- public String getName() {
- return name;
- }
- publicvoid setName(String name) {
- this.name = name;
- }
- }
- publicclass AnimalImpl extends Animal {
- }
- Class<?> class2 = Class.forName("com.example.myReflect.AnimalImpl");
- Class<?> parentClass = class2.getSuperclass();
- Log.d(TAG, "父類:" + parentClass.getName());
在這裡,我們使用了Class.forName(“com.example.myReflect.AnimalImpl”);找到AnimalImpl的類型別物件
然後呼叫 class2.getSuperclass()找到它的父類Class物件。很明顯,它的父類是Animal類
由於我們這裡得到了父類的Class物件parentClass,所以可以對它使用Class的一切函式。
所以呼叫parentClass.getName()就可以獲得父類的名稱了。
(3)、獲取類所直接繼承的介面的Class物件
這裡要先宣告一個觀點:Class類,不同於定義類的class標識,Class類是一個泛型。類物件是由Class物件來表示,而介面物件同樣也是用Class物件來表示!所以同樣是Class物件,它可能表示的類物件,也可能表示的是介面物件!
獲取介面物件的函式如下:
- //獲取普通介面的方法
- public Class<?>[] getInterfaces();
- //獲取泛型介面的方法
- public Type[] getGenericInterfaces();
getInterfaces()將獲取指定類直接繼承的介面列表!注意一點:直接繼承!!!如果不是直接繼承,那將是獲取不到的。
我們舉個例子:
同樣,以上面的Animal為例:
我們先宣告一個介面,讓Animal類來繼承:
- publicinterface IAnimal {
- void setName(String name);
- String getName();
- }
- publicclass Animal implements IAnimal{
- private String name;
- @Override
- public String getName() {
- return name;
- }
- @Override
- publicvoid setName(String name) {
- this.name = name;
- }
- }
- publicclass AnimalImpl extends Animal {
- }
然後我們分別看看Animal類和AnimalImpl類的的獲取介面的結果,完整的程式碼如下:
- //獲取Animal類的介面列表
- Class<?> class3 = Animal.class;
- Class<?>[] interfaces = class3.getInterfaces();
- for (Class interItem:interfaces){
- Log.d(TAG, "Animal繼承的介面:" + interItem.getName());
- }
- //獲取AnimalImpl的介面列表
- class3 = AnimalImpl.class;
- interfaces = class3.getInterfaces();
- if (interfaces.length >0) {
- for (Class interItem : interfaces) {
- Log.d(TAG, "AnimalImpl繼承的介面:" + interItem.getName());
- }
- }else {
- Log.d(TAG, "AnimalImpl無繼承的介面");
- }
我們先看看Animal類的介面列表:
- Class<?> class3 = Animal.class;
- Class<?>[] interfaces = class3.getInterfaces();
- for (Class interItem:interfaces){
- Log.d(TAG, "Animal繼承的介面:" + interItem.getName());
- }
從結果可以看出,這裡找到了Animal類所繼承的介面值。
那我們再來看看AnimalImpl的介面獲取情況又是怎樣呢:
- class3 = AnimalImpl.class;
- interfaces = class3.getInterfaces();
- if (interfaces.length >0) {
- for (Class interItem : interfaces) {
- Log.d(TAG, "AnimalImpl繼承的介面:" + interItem.getName());
- }
- }else {
- Log.d(TAG, "AnimalImpl無繼承的介面");
- }
從結果也可以看出,這裡獲取到的介面列表為空!所以這也證明了getInterfaces()只能獲取類直接繼承的介面列表。
(4)、綜合提升:獲取某個類型別的所有介面
現在我們提升一下,如果我想傳進去一下類型別,然後要得到它所有繼承的介面列表要怎麼辦?(不管它是不是直接繼承來的都要列出來)那只有靠遞規了,我們需要遞規它的父類直接繼承的介面、父類的父類直接繼承的介面以此類推,最終到Object類的時候就找到所有繼承的介面了
在開始遞規獲取所有介面之前,我們先構造下程式碼。
由於我們要獲取所有介面,為了效果更好些,我們在Animal和AnimalImpl基礎上,多加幾個繼承的介面:
- //給Animal新增 IAnimal,Serializable兩個介面
- publicclass Animal implements IAnimal,Serializable{
- private String name;
- @Override
- public String getName() {
- return name;
- }
- @Override
- publicvoid setName(String name) {
- this.name = name;
- }
- }
- //給AnimalImpl新增Serializable介面
- publicclass AnimalImpl extends Animal implements Serializable {
- }
好了,言規正轉,看獲取類型別所有介面列表的方法:
- /**
- * 獲取所傳類型別的所有繼承的介面列表
- * @param clazz
- * @return
- */
- public Class<?>[] getAllInterface(Class<?> clazz){
- //獲取自身的所有介面
- Class<?>[] interSelf = clazz.getInterfaces();
- //遞規呼叫getAllInterface獲取超類的所有介面
- Class<?> superClazz = clazz.getSuperclass();
- Class<?>[] interParent = null;
- if (null != superClazz) {
- interParent = getAllInterface(superClazz);
- }
- //返回值
- if (interParent == null && interSelf != null){
- return interSelf;
- }elseif (interParent == null && interSelf == null){
- returnnull;
- }elseif (interParent != null && interSelf == null){
- return interParent;
- }else {
- finalint length = interParent.length + interSelf.length;
- Class<?>[] result = new Class[length];
- System.arraycopy(interSelf,0,result,0,interSelf.length);
- System.arraycopy(interParent,0,result,interSelf.length,interParent.length);
- return result;
- }
- }
- //呼叫
- Class<?>[] clazzes = getAllInterface(AnimalImpl.class);
- SpannableStringBuilder builder = new SpannableStringBuilder();
- for (Class clazz:clazzes){
- builder.append(clazz.getName());
- builder.append(" ");
- }
- Log.d(TAG, "AnimalImpl繼承的所有介面:"+ builder.toString());
這段程式碼最關鍵的地方在於getAllInterface(Class<?> clazz);我們來看看這個函式是如何遞規得到所有介面的陣列的。
- public Class<?>[] getAllInterface(Class<?> clazz){
- //獲取自身的所有介面
- Class<?>[] interSelf = clazz.getInterfaces();
- //遞規呼叫getAllInterface獲取超類的所有介面
- Class<?> superClazz = clazz.getSuperclass();
- Class<?>[] interParent = null;
- if (null != superClazz) {
- interParent = getAllInterface(superClazz);
- }
- //返回值
- if (interParent == null && interSelf != null){
- return interSelf;
- }elseif (interParent == null && interSelf == null){
- returnnull;
- }elseif (interParent != null && interSelf == null){
- return interParent;
- }else {
- finalint length = interParent.length + interSelf.length;
- Class<?>[] result = new Class[length];
- System.arraycopy(interSelf,0,result,0,interSelf.length);
- System.arraycopy(interParent,0,result,interSelf.length,interParent.length);
- return result;
- }
- }
- //獲取自身的所有介面
- Class<?>[] interSelf = clazz.getInterfaces();
- //遞規呼叫getAllInterface獲取超類的所有介面
- Class<?> superClazz = clazz.getSuperclass();
- Class<?>[] interParent = null;
- if (null != superClazz) {
- interParent = getAllInterface(superClazz);
- }
- Class<?> superClazz = clazz.getSuperclass();
- Class<?>[] interParent = null;
- if (null != superClazz) {
- interParent = getAllInterface(superClazz);
- }
有些同學不解了,getAllInterface(superClazz)這不是當前函式自己嗎?是的,我們寫getAllInterface(superClazz)是來幹什麼的,就是用來獲取傳進去的類的所有介面,所以我們把父類傳進去,當然也能獲得它父類的所有介面列表了。(有關遞規的知識,可能是有些難度的,遞規不是本文重點,不做詳細介紹,有疑問的同學可以搜搜這方面文章補充下)
我們再重複一遍,我們的getAllInterface(Class<?> clazz)函式,會返回clazz物件的所有介面列表。現在我們得到了它自己直接繼承的介面,也有它父類的所有介面列表。那麼,把它們兩個合併,就是所有的介面列表了。
所以下面是介面列表返回的程式碼:
- if (interParent == null && interSelf != null){
- return interSelf;
- }elseif (interParent == null && interSelf == null){
- returnnull;
- }elseif (interParent != null && interSelf == null){
- return interParent;
- }else {
- finalint length = interParent.length + interSelf.length;
- Class<?>[] result = new Class[length];
- System.arraycopy(interSelf,0,result,0,interSelf.length);
- System.arraycopy(interParent,0,result,interSelf.length,interParent.length);
- return result;
- }
有點難度的地方,可能是當兩個都不為空的時候,合併時的程式碼:
- finalint length = interParent.length + interSelf.length;
- Class<?>[] result = new Class[length];
- System.arraycopy(interSelf,0,result,0,interSelf.length);
- System.arraycopy(interParent,0,result,interSelf.length,interParent.length);
- return result;
然後通過System.arraycopy()函式,將它們兩個複製到result陣列中。
System.arraycopy()的定義及釋義如下:
- /**
- * 將指定個數的元素從源陣列src複製到目標陣列dst中
- *
- * @param src :源陣列
- * @param srcPos:源陣列開始複製的item的索引,從0開始
- * @param dst:目標陣列
- * @param dstPos:目標陣列開始接收復制item的位置索引,從0開始
- * @param length:要複製的元素個數
- */
- publicstaticnativevoid arraycopy(Object src, int srcPos, Object dst, int dstPos, int length);
- Class<?>[] clazzes = getAllInterface(AnimalImpl.class);
- SpannableStringBuilder builder = new SpannableStringBuilder();
- for (Class clazz:clazzes){
- builder.append(clazz.getName());
- builder.append(" ");
- }
- Log.d(TAG, "AnimalImpl繼承的所有介面:"+ builder.toString());
到這裡,基本類的周邊資訊獲取就結束了,下面我們來看看泛型類的周邊資訊獲取要怎麼來做。
(5)、獲取類的訪問修飾符
由於我們在定義類時,比如下面的內部類:- publicstaticfinalclass InnerClass{
- }
我們先看一個例子(我們以上面的內部類InnerClass為例):
- Class<?> clazz = getClassLoader().loadClass(InnerClass.class.getName());
- int modifiers = clazz.getModifiers();
- String retval = Modifier.toString(modifiers);
- boolean isFinal = Modifier.isFinal(modifiers);
- Log.d(TAG, "InnerClass的定義修飾符:" + retval);
- Log.d(TAG, "is Final:" + isFinal);
首先,在這部分程式碼中,我們又換了一種類載入方式,使用的是ClassLoader;
然後我們單獨來看看這句:
- int modifiers = clazz.getModifiers();
另外Java開發人員單獨提供了一個類來提取這個整型變數中各標識位的函式,這個類就是Modifier
Modifier中主要有以下幾個方法:
- //根據整型變數來生成對應的修飾符字串
- String Modifier.toString(int modifiers)
- //以下這些方法來檢查特定的修飾符是否存在
- boolean Modifier.isAbstract(int modifiers)
- boolean Modifier.isFinal(int modifiers)
- boolean Modifier.isInterface(int modifiers)
- boolean Modifier.isNative(int modifiers)
- boolean Modifier.isPrivate(int modifiers)
- boolean Modifier.isProtected(int modifiers)
- boolean Modifier.isPublic(int modifiers)
- boolean Modifier.isStatic(int modifiers)
- boolean Modifier.isStrict(int modifiers)
- boolean Modifier.isSynchronized(int modifiers)
- boolean Modifier.isTransient(int modifiers)
- boolean Modifier.isVolatile(int modifiers)
- String Modifier.toString(int modifiers)
其它的就是一些isXXXX(int moifiers)的判斷指定標識位的函數了,沒什麼難度
在例子中,我們使用了Modifier.isFinal(int modifiers)來判斷是不是具有final修飾符,返回結果為true;
從Modifier類的isXXX()系列函式中,可以看到它的修飾符確實很多,但這些修飾符,有些類是根本用不到的,比如isNative()等,這是因為不光類會使用Modifier類來判斷訪問修飾符,介面,成員變數和成員函式所對應的型別也同樣都是使用Modifier來判斷訪問修飾符的,這些我們後面在講到的時候,都會說到!
(6)、獲取介面的訪問修飾符
從上面獲取類的訪問修飾符時,我們講過,介面,類,函式都是通過Modifier類判斷訪問修飾符的,又因為類和介面型別全部都是用Class物件來標識,所以介面和類的獲取訪問修飾符的方式完全相同,下面就舉一個簡單的例子:- //定義一個類部介面
- publicstaticinterface InnerInteface{
- }
- //使用
- Class<?> clazz2 = InnerInteface.class;
- int modifiers = clazz2.getModifiers();
- String retval = Modifier.toString(modifiers);
- boolean isInteface = Modifier.isInterface(modifiers);
- Log.d(TAG, "InnerClass的定義修飾符:" + retval);
- Log.d(TAG, "isInteface:" + isInteface);
- Class<?> clazz2 = InnerInteface.class;
因為我們現在知道Class物件,不光代表類也可以代表介面。
下面有關Modifier的使用與第五部分獲取類的修飾符是一樣的,就不再細講。
(7)Class.forName(String className)與ClassLoader.loadClass(String ClassName)的區別
我們通過原始碼來看看他們的區別:先看Class.forName:
- publicstatic Class<?> forName(String className) throws ClassNotFoundException {
- return forName(className, true, VMStack.getCallingClassLoader());
- }
- publicstatic Class<?> forName(String className, boolean initializeBoolean,
- ClassLoader classLoader) throws ClassNotFoundException {
- Class<?> result;
- try {
- result = classForName(className, initializeBoolean,
- classLoader);
- } catch (ClassNotFoundException e) {
- Throwable cause = e.getCause();
- if (cause instanceof ExceptionInInitializerError) {
- throw (ExceptionInInitializerError) cause;
- }
- throw e;
- }
- return result;
- }
其中:
- className:類名
- initializeBoolean:表示是否需要初始化;如果設為true,表示在載入以後,還會進入連結階段
- classLoader:ClassLoader載入器
下面再來看看ClassLoader.loadClass()
- public Class<?> loadClass(String className) throws ClassNotFoundException {
- return loadClass(className, false);
- }
- protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
- Class<?> clazz = findLoadedClass(className);
- if (clazz == null) {
- try {
- clazz = parent.loadClass(className, false);
- } catch (ClassNotFoundException e) {
- // Don't want to see this.
- }
- if (clazz == null) {
- clazz = findClass(className);
- }
- }
- return clazz;
- }
通過程式碼也可以看出來ClassLoader的loadClass(String className)只是將類加載出來,並沒有連結與初始化的步驟。所以這就是它們的區別
最後,我們總結一下,Class.forName(String className)不僅會將類載入進來,而且會對其進行初始化,而ClassLoader.loadClass(String ClassName)則只是將類載入進來,而沒有對類進行初始化。一般來講,他們兩個是通用的,但如果你載入類依賴初始化值的話,那ClassLoader.loadClass(String ClassName)將不再適用。
舉例來說:
在JDBC程式設計中,常看到這樣的用法,Class.forName(“com.mysql.jdbc.Driver”),如果換成了getClass().getClassLoader().loadClass(“com.mysql.jdbc.Driver”),就不行。
為什麼呢?開啟com.mysql.jdbc.Driver的原始碼看看,
- // Register ourselves with the DriverManager
- static {
- try {
- java.sql.DriverManager.registerDriver(new Driver());
- } catch (SQLException E) {
- thrownew RuntimeException("Can't register driver!");
- }
- }
好了,這篇就到這了,內容不太多,但比較複雜。最後我們再總結一下這篇文章所涉及到的幾個函式:
- //獲取類型別物件的幾種方式:
- Person person = new Person();
- Class a = person.getClass() //方法一:
- Class b = Persion.class;//方法二:
- Class c = Class.forName(String ClassName); //方法三:
- Class d = context.getClassLoader().loadClass(String ClassName);//方法四:(不建議使用)
- //獲取包名類名
- public String getName();//獲取完整的類名(包含包名)
- public String getSimpleName();//僅獲取類名
- public Package getPackage()//獲取類型別所對應的package物件
- //獲取超類Class物件
- public Class<?> getSuperclass();//獲取普通函式的父類Class物件
-
相關推薦
java基礎-反射(1):基本類周邊資訊獲取
前言:堅持夢想,過程或是艱辛的,回憶是幸福的。與其最後豪言如果當時我怎樣怎樣,倒不如堅持腳下。 相關文章: 今天開始給大家講講有關反射的知識,在應用程式開發時,如果純做上層,搭搭框架啥的,那用到反射的機會不多,但如果你想做出來一個公共類或者公共模組給其它人用的時候,那用到反射的可能性就大大增加了。況且
java基礎(一) 深入解析基本類型
後者 active 位數 自動完成 符號 情況 換算 ade 相等 一、基本類型的簡介 基本類型的兩條準則: Java中,如果對整數不指定類型,默認時int類型,對小數不指定類型,默認是double類型。 基本類型由小到大,可以自動轉換,但是由大到小,則需要強制類型轉換。
java基礎(一) 深入解析基本類型
java一、基本類型的簡介 基本類型的兩條準則: Java中,如果對整數不指定類型,默認時int類型,對小數不指定類型,默認是double類型。 基本類型由小到大,可以自動轉換,但是由大到小,則需要強制類型轉換。 所占的字節數: byte: 1個字節;char: 2個字節;short: 2個字節;int:
java基礎之十三:Abstract類和方法
.get 引用 ava ESS 實現 print student 通過 bst 這篇介紹Java中抽象類和抽象方法,用關鍵字abstract表示抽象,是一個可以修飾類和方法的關鍵字。如果類名前面用abstract修飾,這個類就是抽象類。如果方法名稱前面有abstract修
spring基礎(1:基本概念)
poj 操作 共享問題 元素 組成 The 開發 let 可選值 本系列筆記來自對《Spring實戰》第三版的整理,Spring版本為3.0 ??spring是為了解決企業級應用開發的復雜性而創建的,spring最根本的使命是:簡化Java開發。為降低開發復雜性有以下四種關
java基礎梳理二:基本資料型別、變數
1、基本資料型別 分為四大類: 佔用位元組數①整數型別byte:位元組型別 1short:短整型 2int:整型 4long:長整型 8②浮點數型別float:單精度
java基礎梳理三:基本資料型別轉換、運算子
1、基本資料型別轉換 byte i = 2;int j = 3;byte result = i + j;×①賦值號右側兩個int型別的變數相加,得到的還是一個int型別的結果,把int型別的結果賦值給byte型別的變數,產生精度丟失,提示出錯 ②賦值號右側int型別的變數和byte型別的變數相加
Java自學之路-Java基礎教程-1:第一行Java程式碼Hello World!
Java是一門很熱門的計算機語言,它能為網際網路應用、企業內部應用提供很好的程式,還可以在硬體如手機,家電,機床,伺服器,電腦,機器人等上面進行嵌入式程式設計讓硬體活動,也可以用來建設網站,比如影音藝這個網站就是使用純Java語言寫的。這是由於Java具有的幾大特性:
Java基礎系列1:Java面向物件
該系列博文會告訴你如何從入門到進階,一步步地學習Java基礎知識,並上手進行實戰,接著瞭解每個Java知識點背後的實現原理,更完整地瞭解整個Java技術體系,形成自己的知識框架。 概述: Java是面向物件的程式設計語言,Java語言提供了定義類、成員變數、方法等最基本的功能。類可被認為是一種自
Java基礎系列4:抽象類與介面的前世今生
該系列博文會告訴你如何從入門到進階,一步步地學習Java基礎知識,並上手進行實戰,接著瞭解每個Java知識點背後的實現原理,更完整地瞭解整個Java技術體系,形成自己的知識框架。 1、抽象類: 當編寫一個類時,常常會為該類定義一些方法,這些方法用以描述該類的行為方式,那麼這些方法都
Java基礎_3.5:簡單Java類
inf 簡單 字符串 stat 被調用 name屬性 職位 void 類的定義 簡單Java類 簡單Java類是一種在實際開發之中使用最多的類的定義形式,在簡單Java類中包含有類、對象、構造方法、private封裝等核心概念的使用,而對於簡單Java類首先給出如下的基本開
Java基礎 實驗二:類和物件
1.實驗目的 掌握類的宣告、物件的建立、方法的定義和呼叫、建構函式的使用。 2.實驗內容 1)定義一個表示學生資訊的類Student,要求如下: ① 類Student的成員變數: sNO 表示學號;
Java學習筆記1:計算機基礎知識、java語言基礎。
一、計算機基礎知識 1、 計算機是一種能夠按照程式執行,自動、高速處理海量資料的現代化智慧電子裝置。由硬體和軟體所組成,沒有安裝任何軟體的計算機稱為裸機。常見的形式有臺式計算機、筆記本計算機、大型計算機等。 硬體通常由CPU、主機板、記憶體、電源、主機箱、硬碟、顯示卡、鍵盤、滑鼠,顯示器等多
Java基礎知識回顧之一 ----- 基本數據類型
博客 string 它的 基本數據 int short 溢出 etc tostring 前言 在開始工作至今,學習各種各樣的技術之中發現自己的很多Java的基礎知識都忘了⊙﹏⊙b汗。。。 而且越是學習越是發現Java基礎的重要性,所以準備單獨抽一下時間進行Java基礎的重新
java基礎知識1:關鍵字;介面和抽象類;java併發相關
true、false、null都不是關鍵字 goto、const、是保留的關鍵字 abstract continue for new switch defa
學習Spring必學的Java基礎知識(1)----反射
是什麼? 1.Java語言允許通過程式化的方式間接對Class進行操作,Class檔案由類裝載器裝載後,在JVM中將形成一份描述Class結構的元資訊物件,通過該元資訊物件可以獲知Class的結構資訊:如建構函式、屬性和方法等。Java允許使用者藉由這個Class相關的
Java併發指南1:併發基礎與Java多執行緒
什麼是併發 在過去單CPU時代,單任務在一個時間點只能執行單一程式。之後發展到多工階段,計算機能在同一時間點並行執行多工或多程序。雖然並不是真正意義上的“同一時間點”,而是多個任務或程序共享一個CPU,並交由作業系統來完成多工間對CPU的執行切換,以使得每個任務都有機會
java基礎-反射詳解與反射是否會破壞類的封裝性見解
問題:反射是否會破壞類的封裝性見解 首先,封裝,是將具體的實現細節隱藏,而把功能作為整體提供給類的外部使用,也就是說,公有方法能夠完成類所具有的功能。當別人使用這個類時,如果通過反射直接呼叫私有方法,可能根本實現不了類的功能,甚至可能會出錯,因此通過反射呼叫私有方
Java基礎--反射機制簡單使用(Class類)
//插槽類 public interface InterfaceDemo { public void open(); public void run(); public void close(); } //手機主機板類 public class CardSlotDem
番外 01:Spring IoC 實現原理簡析,Java的反射機制,通過類名建立物件
轉載請註明來源 賴賴的部落格 前景概要 在 01 走進Spring,Context、Bean和IoC 中,我們看到了強大的Spring通過ApplicationContext實現了bean工廠(也就是物件工廠),那究竟是怎麼實現的呢,本次給大家寫一個小D