常用類庫
泛型
概述
泛型,即“參數化類型”(方法中參數的類型可以在使用時建立)。
就是将類型由原來的具體的類型參數化,類似于方法中的變量參數,
此時類型也定義成參數形式(可以稱之為類型形參),
然後在使用/調用時傳入具體的類型(類型實參)。
如何了解?
相當于一個容器,可以裝載不同的東西.
分析:
如方法的參數傳遞時以前用的是方法的重載當參數不确定時
這時候重載就有缺點: 代碼重複率高,效率降低
使用Object參數: 算數運算會有問題, 存在強制類型轉換可能會出錯
解決:
采用泛型
類型不确定,後續使用時再去指定泛型的具體類型
好處:
- 提高代碼複用率
- 泛型中的類型在使用時指定,不需要強制類型轉換。(編譯器會自動檢測)
使用
泛型類
定義一個泛型類:
public class ClassName<T>{
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
常用的泛型
: 通常指的是Element,元素
泛型接口
public interface IntercaceName<T>{
T getData();
}
實作接口時,可以選擇指定泛型類型,也可以選擇不指定, 如下:
指定類型:
public class Interface1 implements IntercaceName<String> {
private String text;
@Override public String getData() {
return text;
}
}
不指定類型:
public class Interface1<T> implements IntercaceName<T> {
private T data;
@Override public T getData() {
return data;
}
}
泛型方法
泛型限制類型
- 在使用泛型時, 可以指定泛型的限定區域 ,
- 例如: 必須是某某類的子類或 某某接口的實作類,
格式:
代碼示例:
public class Demo2 {
public static void main(String[] args) {
Cup<Cola> c = new Cup<>();
}
}
//定義一個飲料接口
interface Drinks{}
//定義一個可樂類,繼承飲料類
class Cola implements Drinks{
}
//定義一個杯子類,限定了這個杯子繼承飲料類的子類,也就是可樂類
class Cup<T extends Drinks>{
T data;
}
泛型中的通用符 ?
類型通配符是使用?
代替方法具體的類型實參。
1 <? extends Parent> 指定了泛型類型的上屆
// ? 代表了Cola是繼承Drinks
Cup<? extends Drinks> c1 = new Cup<Cola>();
2 <? super Child> 指定了泛型類型的下屆
// ? 表示Cola 的父類是Drinks
Cup<? super Cola> c2 = new Cup<Drinks>();
3 <?> 指定了沒有限制的泛型類型
Cup<?> c2 = new Cup<>();
作用
1、 提高代碼複用率
2、 泛型中的類型在使用時指定,不需要強制類型轉換(類型安全,編譯器會檢查類型)
注意
在編譯之後程式會采取去泛型化的措施。
也就是說Java中的泛型,隻在編譯階段有效。
在編譯過程中,正确檢驗泛型結果後,
會将泛型的相關資訊擦出,
并且在對象進入和離開方法的邊界處添加類型檢查和類型轉換的方法。
也就是說,泛型資訊不會進入到運作時階段。
常用類庫
java.util.Objects
equals()
兩個對象是否相等
代碼示例
import java.util.Objects;
public class Demo01 {
public static void main(String[] args) {
String a = null;
String b = "123";
//會産生空指針異常
System.out.println(a.equals(b));
//能夠避免空指針異常
System.out.println(Objects.equals(a,b));
}
}
isNull()
判斷是否為空
import java.util.Objects;
public class Demo01 {
public static void main(String[] args) {
String a = null;
System.out.println(Objects.isNull(a));
}
}
requireNonNull()
檢查指定的對象引用是否為
null
,如果是,則抛出自定義的
NullPointerException
。 此方法主要用于在具有多個參數的方法和構造函數中進行參數驗證.
java.lang.Math
import java.util.Objects;
public class Demo01 {
public static void main(String[] args) {
//絕對值
System.out.println(Math.abs(-100));//100
//最大最小值
System.out.println(Math.max(100,200));//200
System.out.println(Math.min(100,200));//100
//四舍五入
System.out.println(Math.round(3.5));//4
System.out.println(Math.round(-3.5));//-3
//傳回小于等于參數的最大整數
System.out.println(Math.floor(3.5));//3.0
System.out.println(Math.floor(-3.5));//-4.0
//傳回大于等于參數的最小整數
System.out.println(Math.ceil(3.5));//4.0
System.out.println(Math.ceil(-3.5));//-3.0
}
}
java.math.BigDecimal
概述
通過在控制台運作0.1+0.2 ,會發現float和double 的運算誤差
由于這兩種類型在運算時可能會産生誤差,為了實作精确運算時則需要
借助BigDecimal類加以描述
import java.math.BigDecimal;
public class Demo01 {
public static void main(String[] args) {
//()内不能直接輸入double,要輸入String類型才能精确轉換
BigDecimal b1 = new BigDecimal("0.1");
BigDecimal b2 = new BigDecimal("0.2");
BigDecimal b3 = b1.add(b2);
System.out.println(b3);
}
}
常用構造方法
public BigDecimal(String val){
}
常用方法
下述所有的運算方法,不會影響參與運算的資料本身,運算的結果會被封裝為一個新的BigDecima1對象,這個對象會
通過return傳回出去。
1.public BigDecimal add(BigDecimal augend){} //加法運算
2.public BigDecimal subtract(BigDecimal augend){} //減法運算
3.public BigDecimal mutiply(BigDecimal augend){} //乘法運算
4.public BigDecimal divide(BigDecimal augend){} //除法運算
java.util.Date
java.util.DateFormat
java.util.Calendar
java.lang.System
-
類包含幾個有用的類字段和方法。 它無法執行個體化。System
類提供的設施包括标準輸入,标準輸出和錯誤輸出流; 通路外部定義的屬性和環境變量; 加載檔案和庫的方法; 以及用于快速複制陣列的一部分的實用方法。System
String
String 被聲明為 final,是以它不可被繼承。(Integer 等包裝類也不能被繼承)
在 Java 8 中,String 内部使⽤ char 數組存儲資料。
在 Java 9 之後,String 類的實作改⽤ byte 數組存儲字元串,同時使⽤ coder 來辨別使⽤了哪種編碼。
-
類表示字元串。 Java程式中的所有字元串文字(例如String
)都實作為此類的執行個體。"abc"
- 字元串是不變的; 它們的值在建立後無法更改。 字元串緩沖區支援可變字元串。 因為String對象是不可變的,是以可以共享它們。
- String的兩種指派方式
- 字面量直接指派,
string text = "hello";
- 通過關鍵字new調用String的構造方法指派 :
String str = new String ("hello");
String 為什麼是不可變的、jdk 源碼中的 String 如何定義的、為什麼這麼設計?
首先了解一下什麼是 , 不可變對象就是一經建立後, 其對象的内部狀态不能被修改, 啥意 思呢? 也就是說不可變對象需要遵守下面幾條原則 不可變對象的内部屬性都是 final 的不 可變對象的内部屬性都是 private 的 不可變對象不能提供任何可以修改内部狀态的方法、setter 方法也不行 不可變對象不能被繼承和擴充 與其說問 String 為什麼是不可變的, 不如說如何把 String 設計成不可變的。 String 類是一種對象, 它是獨立于 Java 基本資料類型而存在的, String 你可以把它了解為字元串的集 合, String 被設計為 final 的, 表示 String 對象一經建立後, 它的值就不能再被修改, 任何對 String 值 進行修改的方法就是重新建立一個字元串。String 對象建立後會存在于運作時常量池中, 運作時常量池 是屬于方法區的一部分, JDK1 .7 後把它移到了堆中。
String s1 = new String(“abc”) 在記憶體中建立了幾個對象
一個或者兩個, String s1 是聲明了一個 String 類型的 s1 變量, 它不是對象。使用new關鍵字會在堆中建立一個對象, 另外一個對象是 ABC, 它會在常量池中建立, 是以一共建立了兩個對象; 如果 abc 在常量池中已經存在的話, 那麼就會建立一個對象。
字元串常量池
1.方法區(Method Area),又稱永久代(Permanent Generation),常稱PermGen 位于非堆空間,又稱非堆區(Non-Heap-Space)。 方法區是被所有線程共享。 所有字段和方法位元組碼,以及一些特殊方法如構造函數,接口代碼也在此定義。 簡單說,所有定義的方法的資訊都儲存在該區域,此區屬于共享區間。 這些區域存儲的是:靜态變量+常量+類資訊(構造方法/接口定義) +運作時常量池。 但是,執行個體變量 存在堆記憶體中,和方法區無關。 以上,隻是邏輯上的定義。 在HotSpot中,方法區僅僅隻是邏輯上的獨立,實際上還是包含在Java堆中,也是就說,方式區 在實體上屬于Java堆區中的一部分,而永久區(Permanent Generation) 就是方法區的實作。 2.堆(Heap) 一個JVM執行個體隻存在一個堆記憶體,堆記憶體的大小是可以調節的。類加載器讀取了類檔案後,需要把類、方法、常變量放到堆記憶體中,儲存所有引用類型的真實資訊,以友善執行器執行。 堆在邏輯上分為三部分(Perm) : 新生代(Young Generation, 常稱為YoungGen) 老年代(old Generation, 常稱為0ldGen、TenuringGen) 永久代(Permanent Generation,常稱為PermGen) 2.1、新生區(New/Young Generation) 新生代(Young Generation) ,常稱為YoungGen,位于堆空間; 新生區又分為Eden區 和Survior (幸存區)。 Eden :新建立的對象 Survior 0、1:經過垃圾回收,但是垃圾回收次數小于15次的對象 2.2、養老代(0ld Generation) 老年代(old Generation) ,常稱為oldGen,位于堆空間; 0ld :垃圾回收次數超過15次,依然存活的對象 2.3、永久區(Permanent Generation) 永久代(Permanent Generation) ,常稱為PermGen,位于非堆空間。 永久區是一個常駐記憶體區域,用于存放JDK自身所攜帶的Class ,Interface的中繼資料,也就是說它存儲的是運作環境必須的類資訊,被裝載進此區域的資料是不會被垃圾回收器回收掉的,關閉JVM 才會釋放此區域所占用的記憶體。 2.3.1、方法區的實作的演變: Jdk1.7之前: hotspot虛拟機對方法區的實作為永久代; Jdk1.8及之後: hotspot移除了永久代用元空間(Metaspace), 2.3.2、運作時常量池存和字元串常量池的變化 JDK1.7之前: 運作時常量池(包含 字元串常量池)存放在方法區,此時hotspot虛拟機對方法區的實作為永久代。 JDK1.7 : 字元串常量池被從方法區拿到了堆中; 運作時常量池剩下的東西還在方法區,也就是hotspot 中的永久代。 JDK1.8 : hotspot移除了永久代, 用元空間(Metaspace)取而代之。 這時候,字元串常量池還在堆, 運作時常量池還在方法區,隻不過方法區的實作從永久代變成元空間(Metaspace) 。
注意
避免通過"+"拼接字元串 使用StringBuffer StringBuilder
- 字面量直接指派,