Java創(chuàng)建對象之顯示創(chuàng)建與隱式創(chuàng)建
一. 對象簡介
1. 概念
在之前的文章中,其實已經(jīng)給大家解釋過對象的概念了。在面向?qū)ο蟮木幊桃?guī)范中,“一切皆對象”,對象就是面向?qū)ο缶幊痰暮诵摹,F(xiàn)實世界中的每一個物體都是對象!當然,這個“對象”不是你懷里撒嬌的男/女朋友,而是指某個“類”的一個實例。
比如,“人”是一個“整體”的概念,它不是“個體”的概念,所以“人”是“類別(模板)”,而不是對象。但是在人這個“類別”中,有法外狂徒張三這個個體,張三就是一個具體的“對象”。每個對象都有自己的狀態(tài)和行為,比如張三的狀態(tài)有:身高、體重、愛好;行為有:吃、喝、piao、du、抽,坑、蒙、拐、騙、偷等。
2. 行為和特征
一個對象主要包括行為和特征(狀態(tài)、屬性)兩個核心要素。
行為:一般是動詞,指的是方法,代表一個對象能干什么,具有哪些功能或能力,例如人可以吃飯、睡覺、說話、工作等;在Java中,一般是用方法來表明對象所具有的行為。
特征:也可以叫做狀態(tài),一般是名詞,指的是屬性,代表一個對象有什么特點或參數(shù),例如每個人的姓名、年齡、性別、體重等。在Java中,一般是用變量來表明對象的狀態(tài)。
3. 對象的創(chuàng)建方式(重點)
對象就是類的實例化,也就是根據(jù)類來創(chuàng)建一個具體的對象,就好比我們使用一個手機殼模具制造出一個具體的手機殼。接下來就給大家講一下,在Java中創(chuàng)建對象的兩種主要方式:顯式創(chuàng)建與隱式創(chuàng)建。
3.1 顯式創(chuàng)建
其中顯式創(chuàng)建對象時,又有以下4種具體的創(chuàng)建方式:
- 使用new關(guān)鍵字創(chuàng)建對象;
- 使用newlnstance()實例方法創(chuàng)建對象;
- 使用clone()方法創(chuàng)建對象;
- 使用ObjectlnputStream對象的readObject()方法創(chuàng)建對象。
3.2 隱式創(chuàng)建
隱式創(chuàng)建對象主要是包括以下幾種方式:
- 給String字符串變量賦值;
- “+”號拼接多個字符串;
- JVM虛擬機加載類時隱式創(chuàng)建類對象。
接下來分別給大家講解一下這幾種創(chuàng)建對象的方式。受限于篇幅,今天主要是給大家講解通過new關(guān)鍵字創(chuàng)建對象的方式,其他的方式我們以后再細講。
二. 顯式創(chuàng)建
1. 使用new關(guān)鍵字創(chuàng)建對象
1.1 new簡介
我們知道,new是"新的"的意思。在Java中,new是一個關(guān)鍵字,它用于創(chuàng)建一個新的類實例,即新的類對象。所以在Java中,創(chuàng)建新對象也可以叫做實例化對象。 對于引用類型來說,如果該類型沒有進行實例化,也就是沒有進行對象的創(chuàng)建,那么該對象的屬性、方法等在內(nèi)存中都是不存在的。只有使用new關(guān)鍵字創(chuàng)建了對象之后,這個對象在內(nèi)存中才會存在,才能使用。
1.2 new作用
當一個引用類型的變量被聲明以后,如果沒有進行初始化,那么它就不指向任何對象,我們也就沒辦法使用該變量。所以我們就可以通過new關(guān)鍵字對該變量進行初始化,具體地來說,new關(guān)鍵字的作用如下:
- 為新對象及對象中的各實例變量分配內(nèi)存空間;
- 將新對象中的各實例變量自動初始化成對應類型的默認值;
- 初始化對象,并給各實例變量賦予正確的初始值;
- 調(diào)用引用類型對應的構(gòu)造方法;
- 返回對象的引用。
1.3 基本語法
new關(guān)鍵字創(chuàng)建對象的語法格式如下:
類名 對象名 = new 類名();
1.4 代碼案例
為了讓大家更好地理解new的用法,給大家設(shè)計了如下代碼案例。
/** * @author */ public class Demo01 { public static void main(String[] args) { // new關(guān)鍵字 Person p1 = new Person(); } }
在這段簡單的代碼中,Person p1=new Person();
,前半部分Person p1
,表示是在內(nèi)存中分配一個Person類型的變量p1。后半部分new Person();
,表示利用new關(guān)鍵字和構(gòu)造方法來創(chuàng)建一個Person類型的對象,Person()
是構(gòu)造方法的名字。當構(gòu)造方法執(zhí)行完,這個Person類型的對象就建造出來了,也就為其分配了對應的內(nèi)存。
雖然p1是引用類型的變量,但p1自身會存儲在棧內(nèi)存中。而使用new關(guān)鍵字創(chuàng)造出來的對象,則被存儲在堆內(nèi)存(heap)中。且在new關(guān)鍵字真正創(chuàng)建出引用類型的對象之后,會把這個對象在內(nèi)存中的地址返回給p1變量進行引用,這樣我們就可以通過調(diào)用p1找到對內(nèi)存中的Person對象。
所以Person p1=new Person();
這行代碼的作用就是,把Person對象在內(nèi)存中的地址 賦值 給變量p1。在Java中,我們可以把p1變量叫做引用變量,或者簡稱為引用。又因為p1變量中存放的是引用類型的內(nèi)存地址值,我們也可以把p1的值叫做引用地址。
2. newlnstance()方法
除了使用new關(guān)鍵字創(chuàng)建對象之外,我們還可以使用newInstance()方法創(chuàng)建對象。該方法是java.lang.Class 或 java.lang.reflect.Constuctor類中的實例方法,其語法格式如下:
java.lang.Class 類對象名稱 = java.lang.Class.forName(要實例化的類全稱);
類名 對象名 = (類名)Class類對象名稱.newInstance();
我們在調(diào)用java.lang.Class類中的forName()方法時,需要將待實例化類的全限定名(如 com.yyg.Person)作為參數(shù)傳遞進來,然后再調(diào)用 java.lang.Class類對象的newInstance()方法創(chuàng)建對象。
/** * @author */ public class Demo01 { public static void main(String[] args) { //newInstance()方法創(chuàng)建對象 try { Class<?> clazz = Class.forName("com.yyg.Person"); Person p2 = (Person) clazz.newInstance(); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } } }
因為這一塊的內(nèi)容涉及到了反射的知識點,后面會專門講解反射,這一塊的內(nèi)容大家先有所了解即可。
3. clone()方法
第三種顯式創(chuàng)建對象的方法,就是利用實例對象的clone()方法進行對象的復制,也可以創(chuàng)建一個新對象出來。clone()方法創(chuàng)建對象時,不會調(diào)用類的構(gòu)造方法,它會創(chuàng)建一個復制的對象,這個對象和原來的對象具有不同的內(nèi)存地址,但它們的屬性值卻相同。
另外clone()方法是Java Object對象中被protected修飾的方法,可供子類調(diào)用以實現(xiàn)子類的克隆邏輯,但不能直接調(diào)用。并且我們使用該方法創(chuàng)建對象時,還要求待實例化的類必須實現(xiàn) java.lang.Cloneable接口,否則會拋出 java.lang.CloneNotSupportedException異常,比較麻煩,所以該方法并不常用。 clone()方法創(chuàng)建對象的語法格式如下:
類名 對象名 = (類名)已創(chuàng)建好的類對象名.clone();
4. readObject()方法
我們還可以使用java.io.ObjectlnputStream
對象的readObject()
方法來創(chuàng)建一個新對象。ObjectlnputStream
是IO流中的內(nèi)容,以后會詳細講解Java中的IO流,大家對此先有一個大致的印象即可。
5. 小結(jié)
在上面給大家提到了4種顯式創(chuàng)建對象的方式,在此我們進行一個小小的總結(jié):
- new關(guān)鍵字是最常用的創(chuàng)建對象方式;
- 使用 new關(guān)鍵字 或 Class對象的newInstance()方法 創(chuàng)建對象時,都會調(diào)用類的構(gòu)造方法;
- 使用 Class類的newInstance()方法 創(chuàng)建對象時,會調(diào)用類的默認構(gòu)造方法,即無參構(gòu)造方法;
- 使用 Object類的clone()方法 創(chuàng)建對象時,不會調(diào)用此類的構(gòu)造方法,只會創(chuàng)建一個復制出的對象,該對象和原來的對象具有不同的內(nèi)存地址,但它們的屬性值相同;
- 如果類沒有實現(xiàn)Cloneable接口卻調(diào)用它的clone()方法,會拋出 java.lang.CloneNotSupportedException異常。
三. 隱式創(chuàng)建
在Java中,除了可以顯式地創(chuàng)建對象之外,還可以隱式地創(chuàng)建對象。隱式創(chuàng)建對象主要是通過以下幾種方式:
- 給String字符串變量賦值;
- “+”號拼接多個字符串;
- JVM虛擬機加載類時隱式創(chuàng)建類對象。
1. 給String字符串變量賦值
我們經(jīng)常給一個字符串變量賦值,如下所示:
String str = "Hello,壹哥";
上面的str變量,其實就是一個String對象,該對象會由JVM虛擬機隱式地創(chuàng)建出來。
2. “+”號拼接多個字符串
我們知道,“+”運算符有兩個基本作用:加法運算和字符串拼接。當進行字符串拼接時,其運算的結(jié)果是一個新的 String對象,示例如下:
String str1 = "Hello"; String str2 = "一一哥"; String str3 = str1+str2; // str3引用一個新的String對象
通過上面的語句,JVM會隱式地創(chuàng)建出第3個String對象。
3. JVM虛擬機加載類時隱式創(chuàng)建類對象
當Java的JVM虛擬機加載一個類時,會隱式地創(chuàng)建出一個可以描述這個類的Class實例對象。類的加載是指把類的.class字節(jié)碼文件讀到內(nèi)存中,把它存放到運行時數(shù)據(jù)區(qū)的方法區(qū)中,然后會在堆區(qū)創(chuàng)建一個 java.lang.Class對象,用來封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。
4. 小結(jié)
無論我們是釆用顯式或是隱式方式創(chuàng)建對象,Java虛擬機都會在創(chuàng)建對象時包含以下步驟:
- 給對象分配內(nèi)存;
- 將對象的實例變量自動初始化成該變量類型的默認值;
- 初始化對象,給實例變量賦予正確的初始值。
四. 對象的使用
1. 簡介
我們在通過一系列方式創(chuàng)建好對象之后,那么這個對象該怎么用呢?我們知道對象中有狀態(tài)和行為兩個核心要素,那怎么來調(diào)用一個對象的行為和狀態(tài)呢?Java中,一個普通的實例對象調(diào)用它的行為和狀態(tài),基本的語法格式如下:
//調(diào)用狀態(tài)
對象.屬性名;
//調(diào)用方法
對象.方法名();
接下來我們通過一個小案例給大家展示一下。
2. 使用
/** * @author */ public class Demo02 { public static void main(String[] args) { // 對象的使用 //先創(chuàng)建一個對象 Person p1=new Person(); //調(diào)用對象的屬性(該屬性不能是私有的,否則別的類中無法看到)--狀態(tài). String name = p1.name; //調(diào)用對象的方法 p1.eat(); p1.speak("一一哥", "男", 18); } }
大家要注意,當我們在A類中調(diào)用B類對象時,B類對象的屬性或方法不能是私有的,否則在A類中會無法看到該屬性或方法。
五. 創(chuàng)建對象的內(nèi)存分析(重點)
1. 內(nèi)存簡介
Java程序在運行時,操作系統(tǒng)會給程序分配三塊主要的內(nèi)存空間:棧內(nèi)存、堆內(nèi)存、方法區(qū)。
- 棧內(nèi)存: 棧內(nèi)存也叫做虛擬機棧,可以存放基本類型的數(shù)據(jù)和引用類型的地址,主要是局部變量。 這些 局部變量存放了編譯期可知長度的各種基本數(shù)據(jù)類型和對象引用,方法執(zhí)行完就會自動釋放。棧內(nèi)存具有先進后出、占用空間比較小、存取速度相對較快的特點。
- 堆內(nèi)存: 堆內(nèi)存中可以存放各對象實例(所有new出來的對象都是)和數(shù)組都在堆中存放,即堆中存放的是引用類型的實際數(shù)據(jù)。 堆內(nèi)存占用的空間比較大,存取速度相對較慢。
- 方法區(qū): 方法區(qū)主要用于存儲類信息、常量、靜態(tài)變量,靜態(tài)代碼塊、即時編譯器(JIT Compiler)編譯后的代碼數(shù)據(jù)等 , 簡單言之就是存儲類的結(jié)構(gòu)信息。類的結(jié)構(gòu)信息包括類的名稱、方法信息、字段信息等。在方法區(qū)中,有一塊空間叫做常量池(串池),用來存放字符串常量。還有一塊空間叫做靜態(tài)區(qū),用來存儲靜態(tài)變量等靜態(tài)數(shù)據(jù)。但在JDK 7之后,常量池、靜態(tài)區(qū)作為堆中的一個子部分,方法區(qū)的概念被弱化。
2. 內(nèi)存分析
/** * @author */ public class Demo02 { public static void main(String[] args) { // 對象的使用 //先創(chuàng)建一個Person對象 Person p1=new Person(); p1.name="一一哥"; p1.age=18; p1.sex="男"; //創(chuàng)建p2對象 Person p2=new Person(); } }
在上述代碼中,我們定義的Person類型p1變量實際上是一個引用,它會被存放在棧內(nèi)存中,而存放實際數(shù)據(jù)的Person對象則存放在堆內(nèi)存中。如下圖所示:
根據(jù)上面的內(nèi)存分析圖可知:
- Person類中包含了name、age、sex三個屬性,它們分別是String、int、String類型。我們知道,它們的默認值分別是null、0、null。
- 我們創(chuàng)建一個p1對象之后,p1會被存放在棧區(qū),然后p1會通過堆中Person對象的內(nèi)存地址,去找到該對象被實例化的內(nèi)容(即name、age、sex等)。
- Java代碼中剛創(chuàng)建出來的對象屬性都是采用默認值(null、0、null),等我們通過"對象.屬性"的方式對屬性進行重新賦值后,堆內(nèi)存中存儲的才是賦值后的內(nèi)容。
- 我們創(chuàng)建的另一個對象p2,p2依然在棧區(qū),但并沒有對p2進行初始化,所以p2的屬性在堆內(nèi)存中都是默認值。
- 堆內(nèi)存中的每一個對象,都有一個獨立的內(nèi)存空間。
六. 結(jié)語
至此,就給大家把Java的對象介紹完畢了,現(xiàn)在你知道幾種創(chuàng)建對象的方式呢?最后再跟大家說一下,不管我們用哪種方式創(chuàng)建出來的對象,每個對象都是相互獨立的。這些不同的對象在內(nèi)存中會占有獨立的內(nèi)存地址,且每個對象都具有自己的生命周期。當一個對象的生命周期結(jié)束時,對象就變成了垃圾,這些垃圾對象會被JVM虛擬機自帶的GC垃圾回收機制來處理。
以上就是Java創(chuàng)建對象之顯示創(chuàng)建與隱式創(chuàng)建的詳細內(nèi)容,更多關(guān)于Java創(chuàng)建對象的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
自帶IDEA插件的阿里開源診斷神器Arthas線上項目BUG調(diào)試
這篇文章主要為大家介紹了自帶IDEA插件阿里開源診斷神器Arthas線上項目BUG調(diào)試,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06commons fileupload實現(xiàn)文件上傳的實例代碼
這篇文章主要介紹了commons fileupload實現(xiàn)文件上傳的實例代碼,包括文件上傳的原理分析等相關(guān)知識點,本文給大家介紹的非常詳細,具有參考借鑒價值,感興趣的朋友一起看看吧2016-10-10淺談@FeignClient中name和value屬性的區(qū)別
這篇文章主要介紹了@FeignClient中name和value屬性的區(qū)別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07