Java 數據類型在實際開發中應用
在前邊的文章中,我已經介紹了Java核心的容器IO等,現在我來說一下java中的數據類型。在java中,一切東西皆為對象(這句話意思是java中絕大數情況都用對象),極少數不是對象的,也存在與之對應的對象(比如基本數據類型存在與之對應的包裝類,數組有List對象可以代替)
Java中數據類型 主要有「基本數據類型」、「String」、「引用類型」 (基本的引用類型不多做介紹,在下一篇博文中著重介紹「枚舉」,也算是引用類型的一種)
一:基本數據類型
1.1基本數據類型的定義
byte、char、int、 float 、double、long...這些屬於java的基本數據類型。具體用法可以參照 (Java基本數據類型總結 ) .在java看來,使用基本類型並不是面向對象的設計,於是提供一些專門的包裝類。實際開發中,不需要我們考慮到底是用基本類型還是包裝類(Java提供了自動裝箱機制)。當然基本類型還是有必要學習一下的。
1.1.1按種類了解基本類型
基本類型可以分為三類,字元類型char,布爾類型boolean以及數值類型byte、short、int、long、float、double。JAVA中的數值類型不存在無符號的,它們的取值範圍是固定的,不會隨著機器硬體環境或者操作系統的改變而改變
Java決定了每種簡單類型的大小,並不隨著機器結構的變化而變化。這正是Java程序具有很強移植能力的原因之一。下表列出了Java中定義的簡單類型、佔用二進位位數及對應的封裝器類。
簡單類型 | boolean | byte | char | short | Int | long | float | double | void |
二進位位數 | 1 | 8 | 16 | 16 | 32 | 64 | 32 | 64 | -- |
封裝器類 | Boolean | Byte | Character | Short | Integer | Long | Float | Double | Void |
這張表可以簡單的看一下,但不推薦花費太多時間(實際開發不需要,如果是應付考試還是需要記一下的)。因為 Java語言之所以流行就是希望程序員可以消耗更少的心力在語法上,從而省出更多的時間去整理具體的業務邏輯。在基本數據類型這一塊,Java提供自動裝箱機制,下面簡單介紹一下自動裝箱。
1.1.2Java中自動裝箱
自動裝箱就可以簡單的理解為將基本數據類型封裝為對象類型,來符合java的面向對象。比如你可以直接把一個int值複製給一個Integer對象
自動裝箱的時候,存在一個細節點就是「對於值從–128到127之間的值,它們被裝箱為Integer對象後,會存在內存中被重用,始終只存在一個對象」,測試如下
有時候,只能用包裝類,不能用基本數據類型,比如集合內
具體的細節可以參考這幾位仁兄的博客 (Java 自動裝箱與拆箱(Autoboxing and unboxing),java 自動裝箱與拆箱)
1.2 基本數據類型的保存位置
基本類型存儲在棧中,處於效率考慮,基本類型保存在棧中。延伸一下,包裝類保存在堆中(注意我之前說過的-127到128之間的包裝類Integer)
1.3 堆棧的簡單介紹(這個和基本數據類型沒有太大關係相當於是擴展內容)
Java的堆是一個運行時數據區,不需要程序代碼來顯式的釋放,由垃圾回收來負責即可。堆的優勢是可以動態地分配內存 大小,生存期也不必事先告訴編譯器(因為是在運行時動態分配內存的,Java的垃圾收集器會自動收走這些不再使用的數據)。但缺點是,由於要在運行時動態分配內存,存取速度較慢。
棧的優勢是,存取速度比堆要快,僅次於寄存器,棧數據可以共享。但缺點是,存在棧中的數據大小與生存期必須是確定的,缺乏靈活性。棧中主要存放一些基本類型的變數數據(int, short, long, byte, float, double, boolean, char)和引用數據類型(這個和基本數據類型無關,不多做介紹)
1.3.1 數據共享簡單介紹
1.3.2 局部變數與成員變數保存位置簡單介紹
對於成員變數和局部變數:成員變數就是方法外部,類的內部定義的變數;局部變數就是方法或語句塊內部定義的變數。局部變數必須初始化。
形式參數是局部變數,局部變數的數據存在於棧內存中。棧內存中的局部變數隨著方法的消失而消失。
成員變數存儲在堆中的對象裡面,由垃圾回收器負責回收
1.3.3 java中常量簡單介紹
十六進位整型常量:以十六進位表示時,需以0x或0X開頭,如0xaa,0X9f。
八進位整型常量:八進位必須以0開頭,如0123,034。
長整型: 長整型必須以L作結尾,如9L,342L。
浮點數常量: 由於小數常量的默認類型是double型,所以float類型的後面一定要加f(F)。同樣帶小數的變數默認為double類型。 如:float f;f=1.3f;//必須聲明f。
字元常量: 字元型常量需用兩個單引號括起來(注意字元串常量是用兩個雙引號括起來)。Java中的字元佔兩個位元組。
1.4 Java基本類型的「類型轉換」
簡單類型數據間的轉換,有兩種方式:自動轉換和強制轉換,通常發生在表達式中或方法的參數傳遞時。
1.4.1 自動轉換:是JVM根據條件自動幫助我們轉換,可以簡單了解一下轉換規則。
當一個較"小"數據與一個較"大"的數據一起運算時,系統將自動將"小"數據轉換成"大"數據,再進行運算 。
這些類型由"小"到"大"分別為 (byte,short,char)--int--long--float—double,這裡我們所說的"大"與"小",並不是指佔用位元組的多少,而是指表示值的範圍的大小 。所以byte --char--short之間不可以自動轉換
1.4.2 強制轉換:
將"大"數據轉換為"小"數據時,你必須使用強制類型轉換。即你必須採用下面這種語句格式: int n=(int)3.14159/2;可以想像,這種轉換肯定可能會導致溢出或精度的下降
表達式的數據類型自動提升 eg 所有的byte,short,char型的值將被提升為int型;
包裝類和基本類型轉換 :實際上Java存在一個自動裝箱的機制,他可以自動轉換。但是,我們可以用構造器轉為包裝類;用包裝類對象的xxxValue()把包裝類轉為基本類型
其它類型間轉為字元串:①調用類的串轉換方法:X.toString(); ②自動轉換:X+""; ③使用String的方法:String.volueOf(X);
字元串轉為其它類型 ①先轉換成相應的封裝器實例,再調用對應的方法轉換成其它類型 new Double("3.1").doubleValue().或者Double.valueOf("32.1").doubleValue()②靜態parseXXX方法String s = "1";byte b = Byte.parseByte( s );
Date類與其它數據類型的相互轉換 :整型和Date類之間並不存在直接的對應關係,只是你可以使用int型為分別表示年、月、日、時、分、秒,這樣就在兩者之間建立了一個對應關係 。具體轉換,可能用到format類
1.4.3 備註
只有boolean不參與數據類型的轉換
二:String類型
在實際開發中 String使用非常廣泛。於是Java設計者針對String做了非常多的優化來提高效率,這雖然提高了程序的效率,但是在一定程度上也會給我們開發提高了難度,於是在Thinking in Java中單獨把String當作一個章節。下面我會從整體上總結一下String,一些具體的方法可以去查詢API(Java API)
2.1 String創建方式
new是按照面向對象的標準語法,在內存使用上存在比較大的浪費。所以String對象的創建是不需要new的(這樣可以提高效率,但是如果用new創建字元串也不會報錯)
2.1.1在這裡,延伸一下,java中創建對象的方式一共存在五種:
分別是 new 關鍵字、Class類的 newInstance 方法、Constructor類的 newInstance 方法、String對象的 clone方法、反序列化機制。但是String對象還有一種特殊的創建方式,就是通過使用 「 或 』 包裹字元序列
2.1.2 簡單的概括一下:
用「」創建對象的時候,String對象是放到常量池中,只會創建一個,每次都是先去找一下常量池有沒有該字元串
用 new創建對象,會在隊中創建一個對象,然後在棧內創建該對象應用,每次都是新創建
2.2 String類初始化後是不可變的(immutable)
String類初始化之後不可變,因為java設計者不希望我們方法傳參是字元串的時候,方法內修改會影響外邊的串,所以採取了一種傳遞拷貝的方式(也就是傳值)
2.2.1 Java中String不可變是怎麼一回事
java中,一旦產生String對象,該對象就不會在發生變化。但是String另一方面的確提供了修改String的方法。這看起來很矛盾,實際上是我們沒有仔細的了解那些修改的方法
比如replace(),如果可以看到源碼,可以清楚的看到該方法實際上新產生一個字元串,替換操作是針對新的字元串。(下圖參考自參考Java進階01 String類,簡單的表示replace()方法調用時
s的變化)
下邊的代碼 :我在原字元串的基礎上添加了一句話,然後判斷他們是否相同(如果是同一個對象修改,==輸出結果應該是true)
思考一下 "s1指向的對象中的字元串是什麼"(我們潛意識的認為s1也會被修改,但是當s2 = "s2"時,實際上s2的引用已經被修改,它和s1沒關係了)
再重複一遍,無論是修改字元串的方法還是對字元串賦值,都和普通的對象不同。賦值是讓字元串指向一個新的字元串,方法傳參是copy一份值,傳入進去。
再比如說:String str=」kv」+」ill」+」 「+」ans」; 就是有4個字元串常量,首先」kv」和」ill」生成了」kvill」存在內存中,然後」kvill」又和」 」 生成 「kvill 「存在內存中,最後又和生成了」kvill ans」;並把這個字元串的地址賦給了str
所以 + 會產生很多臨時變數。下文中會說到StringBuilder 來避免這種情況。不過有一種特殊情況。 "ab"+"cd" 在JVM編譯後和"abcd"一樣
2.2.2 Java是怎樣做到String的不可變的
在String源碼中 ,使用private final char value[]來實現字元串的存儲,就是因為final,才說String類型是不可變
2.3 String的保存位置
深入一點,我們了解一下String保存的位置(可以參考java+內存分配及變數存儲位置的區別[轉],java中的String類常量池詳解)
String常量是保存在常量池中。JVM中的常量池在內存當中是以表的形式存在的, 對於String類型,有一張固定長度的CONSTANT_String_info表用來存儲文字字元串值,注意:該表只存儲文字字元串值,不存儲符號引用。說到這裡,對常量池中的字元串值的存儲位置應該有一個比較明了的理解了。在程序執行的時候,常量池會儲存在Method Area,而不是堆中。常量池中保存著很多String對象; 並且可以被共享使用,因此它提高了效率
什麼是常量池
常量池指的是在編譯期被確定,並被保存在已編譯的.class文件中的一些數據。
除了包含代碼中所定義的各種基本類型(如int、long等等)和對象型(如String及數組)的常量值(final)還包含一些以文本形式出現的符號引用。
2.4主要的方法
s.length() 返回s字元串長度
s.charAt(2) 返回s字元串中下標為2的字元
s.substring(0, 4) 返回s字元串中下標0到4的子字元串
s.indexOf("Hello") 返回子字元串"Hello"的下標
s.startsWith(" ") 判斷s是否以空格開始
s.endsWith("oo") 判斷s是否以"oo"結束
s.equals("Good World!") 判斷s是否等於"Good World!" ==只能判斷字元串是否保存在同一位置。需要使用equals()判斷字元串的內容是否相同。
s.compareTo("Hello Nerd!") 比較s字元串與"Hello Nerd!"在詞典中的順序, 返回一個整數,如果<0,說明s在"Hello Nerd!"之前 如果>0,說明s在"Hello Nerd!"之後 如果==0,說明s與"Hello Nerd!"相等。
s.trim() 去掉s前後的空格字元串,並返回新的字元串
s.toUpperCase() 將s轉換為大寫字母,並返回新的字元串
s.toLowerCase() 將s轉換為小寫,並返回新的字元串
s.replace("World", "Universe") 將"World"替換為"Universe",並返回新的字元串
2.5:簡單概括總結String中的細節點
總體來說,如果你還是對String感到困惑,不如把握住一點就是「 創建時間」 如果編譯期就知道是啥,會丟到常量池.
單獨使用""引號創建的字元串都是常量,編譯期就已經確定存儲到String Pool中;
使用new String("")創建的對象會存儲到heap中,是運行期新創建的;
使用只包含常量的字元串連接符如"aa" + "aa"創建的也是常量,編譯期就能確定,已經確定存儲到String Pool中;
使用包含變數的字元串連接符如"aa" + s1創建的對象是運行期才創建的,存儲在heap中;
intern(): String實例調用該方法可以讓JVM檢查常量池,如果沒有實例的value屬性對應的字元串序列,就將本實例放入常量池,如果有則返回常量池中相對應的實例的引用而不是當前實例的引用
2.6 StringBuilder 和StringBuffer 和 +
首先StringBuilder 和StringBuffer區別是 StringBuffer線程安全(存在一堆synchronized)
其次,我們推薦用StringBuilder 而不是+ ,雖然+號在jvm中本質也是建StringBuilder,但是每s = s+"1";都會引入一個StringBuilder對象
另外:StringBuilder允許我們在聲明的時候指定大小,避免我們多次分配緩存
三:Java引用類型
Java有 5種引用類型(對象類型):類 介面 數組 枚舉 標註。
new 的對象會放到java堆中,然後把引用放到棧內,這裡不多加敘述
學習Java過程中遇到什麼問題或者想獲取學習資源的話,歡迎加入Java學習交流群495273252,我們一起學Java!


※編程語言間的鬥爭
※Java後端程序員1年工作經驗總結
※Java基礎——異常詳解
※Java常用類String的面試題匯總
TAG:Java團長 |
※微軟首次確認《戰爭機器5》在開發中 首發將加入Xbox Game Pass
※開發者從代碼中發現一款配有Face ID的iPad Pro
※Mock API是如何在開發中發光發熱的?
※Facebook對應用開發商加強限制:保護用戶數據
※Android簡單應用開發實戰
※MagicLeap與NBA合作開發AR應用 並展示機器實物
※《Superhot VR》開發商:正在開發一款硬核VR體驗
※微軟允許開發者在Microsoft Store中向私人發布應用或遊戲
※研發實戰:現在開始,用Unity為Magic Leap One開發MR內容
※PS Classic的模擬器非自家開發 採用了開源模擬器PCSX
※《Raw Data》開發商Survios:大部分VR用戶並非硬核玩家
※微軟員工證實新版的HoloLens正在開發中
※中本聰最信任的人Martti Malmi 回歸數字貨幣開發領域
※Ghostlight成為NS官方開發商 並稱首款JRPG已在開發中
※vivo全球首發Android P開發者預覽版
※bigide之數據開發
※Surface Phone正在開發中,有證據!
※Mapbox發布新SDK幫助開發人員開發AR導航應用程序
※使用 aws lambda 開發無伺服器程序
※Limitless加入Lytro 開發遊戲引擎中結合光場和實時渲染工具