您好,登錄后才能下訂單哦!
本篇內容介紹了“Java中Class.forName()怎么使用”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
類是程序的一部分,每個類都有一個class對象。
換言之,每當編寫并且編譯了一個新類,就會產生一個class對象(更恰當的說,是被保存在一個同名的class文件中)。
為了生成這個類的對象,運行這個程序的Java虛擬機(jvm)將使用被稱為“類加載器”的子系統。
所有的類都是在對其第一次使用的時候被加載到JVM中。如當程序創建對第一個靜態成員的引用時,就會加載這個類。或者使用new關鍵字創建新的對象的時候。
因此java程序在它運行之前并非完全加載,其各個部分是在必須的時候才加載的。類加載器首先檢查這個類的class對象是否已經加載。如果尚未加載,默認的類加載器就會根據類名查找.class文件。
實際上在Java中每個類都有且只有一個Class對象。
Class 沒有公共構造方法,因此不能顯式地聲明一個Class對象,Class 對象是在載入類時由Java 虛擬機以及通過調用類載入器中的 defineClass 方法自己主動構造的。
Class類被創建后的對象就是Class對象,注意,Class對象表示的是自己手動編寫類的類型信息,比如創建一個Shapes類,那么,JVM就會創建一個Shapes對應Class類的Class對象,該Class對象保存了Shapes類相關的類型信息。
實際上在Java中每個類都有一個Class對象,每當我們編寫并且編譯一個新創建的類就會產生一個對應Class對象并且這個Class對象會被保存在同名.class文件里(編譯后的字節碼文件保存的就是Class對象),那為什么需要這樣一個Class對象呢?
是這樣的,當我們new一個新對象或者引用靜態成員變量時,Java虛擬機(JVM)中的類加載器子系統會將對應Class對象加載到JVM中,然后JVM再根據這個類型信息相關的Class對象創建我們需要實例對象或者提供靜態變量的引用值。
需要特別注意的是,手動編寫的每個class類,無論創建多少個實例對象,在JVM中都只有一個Class對象,即在內存中每個類有且只有一個相對應的Class對象,挺拗口,通過下圖理解(內存中的簡易現象圖):
到這我們也就可以得出以下幾點信息:
Class類也是類的一種,與class關鍵字是不一樣的。
手動編寫的類被編譯后會產生一個Class對象,其表示的是創建的類的類型信息,而且這個Class對象保存在同名.class的文件中(字節碼文件),比如創建一個Shapes類,編譯Shapes類后就會創建其包含Shapes類相關類型信息的Class對象,并保存在Shapes.class字節碼文件中。
每個通過關鍵字class標識的類,在內存中有且只有一個與之對應的Class對象來描述其類型信息,無論創建多少個實例對象,其依據的都是用一個Class對象。
Class類只存私有構造函數,因此對應Class對象只能有JVM創建和加載
Class類的對象作用是運行時提供或獲得某個對象的類型信息,這點對于反射技術很重要(關于反射稍后分析)。
1、調用Object類的getClass()方法來得到Class對象,這也是最常見的產生Class對象的方法。
比如:
MyObject x; Class c1 = x.getClass();
.Object.getClass();
Object中自帶的方法,getclass(),返回一個class對象。
2、使用Class類的中靜態forName()方法獲得與字符串相應的Class對象。
比如:
Class c2=Class.forName("MyObject")
MyObject必須是接口或者類的名字。
class.forname()
Class c=Class.forName("類的全限定名")
傳入string類型參數,要求jvm查找并加載指定的類,返回的是一個class對象的引用。
3、獲取Class類型對象的第三個方法很easy。假設T是一個Java類型。那么T.class就代表了匹配的類對象。
比如
Class cl1 = Manager.class; Class cl2 = int.class; Class cl3 = Double[].class;
注意:Class對象實際上描寫敘述的僅僅是類型。而這類型未必是類或者接口。
比如上面的int.class是一個Class類型的對象。
因為歷史原因。數組類型的getName方法會返回奇怪的名字。
getname()
:以string類型返回class對象表示的實體(類,接口,數組,基本類型,void等)名稱
newInstance()
:創建一個實例,只能調用默認構造器。
getsuperclass()
:返回class表示的實體超類的名稱
getSimpleName()
:不辦含包名的類名。
isInterfence
:告訴你這個class對象是否表示某個接口。
1、getName()
一個Class對象描寫敘述了一個特定類的屬性,Class類中最經常使用的方法getName以 String 的形式返回此 Class 對象所表示的實體(類、接口、數組類、基本類型或 void)名稱。
2、newInstance()
Class另一個實用的方法能夠為類創建一個實例,這種方法叫做newInstance()。
比如:
x.getClass.newInstance()
創建了一個同x一樣類型的新實例。newInstance()方法調用默認構造器(無參數構造器)初始化新建對象。
3、getClassLoader()
返回該類的類載入器。
4、getComponentType()
返回表示數組組件類型的 Class。
5、getSuperclass()
返回表示此 Class 所表示的實體(類、接口、基本類型或 void)的超類的 Class。
6、isArray()
判定此 Class 對象是否表示一個數組類。
1、forName和newInstance結合起來使用,能夠依據存儲在字符串中的類名創建對象。比如
Object obj = Class.forName(s).newInstance();
2、虛擬機為每種類型管理一個獨一無二的Class對象。因此能夠使用==操作符來比較類對象。比如:
if(e.getClass() == Employee.class)...
主要功能
Class.forName(xxx.xx.xx)
返回的是一個類。
Class.forName(xxx.xx.xx)
的作用是要求JVM查找并加載指定的類,也就是說JVM會執行該類的靜態代碼段。
Class.forName是一個靜態方法,相同能夠用來載入類。
該方法有兩種形式:Class.forName(String name, boolean initialize, ClassLoader loader)和 Class.forName(String className)。
第一種形式的參數 name表示的是類的全名;initialize表示是否初始化類。loader表示載入時使用的類載入器。
另外一種形式則相當于設置了參數 initialize的值為 true。loader的值為當前類的類載入器
先來個熱身,給你一個字符串變量,它代表一個類的包名和類名,你怎么實例化它?你第一想到的肯定是new,但是注意一點:
A a = (A)Class.forName(“pacage.A”).newInstance();
這和你 A a = new A(); 是一樣的效果。
現在言歸正傳。
動態加載和創建Class 對象,比如想根據用戶輸入的字符串來創建對象時需要用到:
String str = “用戶輸入的字符串” ; Class t = Class.forName(str); t.newInstance();
在初始化一個類,生成一個實例的時候,newInstance()方法和new關鍵字除了一個是方法,一個是關鍵字外,最主要有什么區別?
它們的區別在于創建對象的方式不一樣,前者是使用類加載機制,后者是創建一個新類。
Java中工廠模式經常使用newInstance()方法來創建對象,因此從為什么要使用工廠模式上可以找到具體答案。 例如:
class c = Class.forName(“Example”); factory = (ExampleInterface)c.newInstance();
其中ExampleInterface是Example的接口,可以寫成如下形式:
String className = “Example”; class c = Class.forName(className); factory = (ExampleInterface)c.newInstance();
進一步可以寫成如下形式:
String className = readfromXMlConfig;//從xml 配置文件中獲得字符串 class c = Class.forName(className); factory = (ExampleInterface)c.newInstance();
上面代碼已經不存在Example的類名稱,它的優點是,無論Example類怎么變化,上述代碼不變,甚至可以更換Example的兄弟類Example2 , Example3 , Example4……,只要他們繼承ExampleInterface就可以。
從JVM的角度看,我們使用關鍵字new創建一個類的時候,這個類可以沒有被加載。但是使用newInstance()方法的時候,就必須保證:
1、這個類已經加載;
2、這個類已經連接了。
而完成上面兩個步驟的正是Class的靜態方法forName()所完成的,這個靜態方法調用了啟動類加載器,即加載 java API的那個加載器。
現在可以看出,newInstance()實際上是把new這個方式分解為兩步,即首先調用Class加載方法加載某個類,然后實例化。
這樣分步的好處是顯而易見的。我們可以在調用class的靜態加載方法forName時獲得更好的靈活性,提供給了一種降耦的手段。
最后用最簡單的描述來區分new關鍵字和newInstance()方法的區別:
newInstance
: 弱類型。低效率。只能調用無參構造。
new
: 強類型。相對高效。能調用任何public構造。
Class.forName(“”)
返回的是類。
Class.forName(“”).newInstance()
返回的是object
Class.forName的一個非經常見的使用方法是在載入數據庫驅動的時候
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); Connection con=DriverManager.getConnection("jdbc:sqlserver://localhost:1433;DatabaseName==JSP","jph","jph");
為什么在我們載入數據庫驅動包的時候有的卻沒有調用newInstance( )方法呢?
即有的jdbc連接數據庫的寫法里是Class.forName(xxx.xx.xx);而有一些:Class.forName(xxx.xx.xx).newInstance()。為什么會有這兩種寫法呢?
通過查詢Java Documentation我們會發現使用Class.forName( )靜態方法的目的是為了動態加載類。通常編碼過程中,在加載完成后,一般還要調用Class下的newInstance( )靜態方法來實例化對象以便操作。因此,單使用Class.forName( )是動態加載類是沒有用的,其最終目的是為了實例化對象。
剛才提到,Class.forName("");的作用是要求JVM查找并加載指定的類,如果在類中有靜態初始化器的話,JVM必然會執行該類的靜態代碼 段。而在JDBC規范中明確要求這個Driver類必須向DriverManager注冊自己,即任何一個JDBC Driver的 Driver類的代碼都必須類似如下:
public class MyJDBCDriver implements Driver { static { DriverManager.registerDriver(new MyJDBCDriver()); } }
既然在靜態初始化器的中已經進行了注冊,所以我們在使用JDBC時只需要Class.forName(XXX.XXX);就可以了。
既然在靜態初始化器的中已經進行了注冊,所以我們在使用JDBC時只需要Class.forName(XXX.XXX);就可以了。
public class ProxoolDriver implements Driver { private static final Log LOG = LogFactory.getLog(ProxoolDriver.class); static { try { DriverManager.registerDriver(new ProxoolDriver()); } catch (SQLException e) { System.out.println(e.toString()); } } }
Method method =Class.forName("android.os.ServiceManager") .getMethod("getService",String.class); // 獲取遠程TELEPHONY_SERVICE的IBinder對象的代理 IBinder binder =(IBinder) method.invoke(null, new Object[] { TELEPHONY_SERVICE}); // 將IBinder對象的代理轉換為ITelephony對象 ITelephonytelephony = ITelephony.Stub.asInterface(binder); // 掛斷電話 telephony.endCall();
“Java中Class.forName()怎么使用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。