Java基礎類庫


面向對象的核心—類和對象

  1. 類的語法定義
    • 類的修飾符
      • static可以修飾變量和方法,稱為類變量、類方法,它們屬於類本身。不被static修飾的變量和方法稱為實例變量、實例方法,屬於類的實例。
      • 在類准備階段,系統就為類變量分配內存空間,類初始化階段完成類變量的初始化。類變量可以通過類來訪問,也可以通過類的對象來訪問(其實系統在底層轉換成通過該類訪問類變量,並不會為類變量分配內存),類方法也是。
      • 類成員的作用域比實例成員的作用域更大,可能類成員初始化完成而實例成員未初始化完成,為避免錯誤,類成員不能訪問實例成員。
[public/final/abstract] class Name{
        //構造器
        [public/private/protected] Name(struct val){
        }    
        //成員變量
        [public/protected/private/static/final] type tname [= defualt];
        //方法
        [public/protected/private/static/final/abstract] type set/get(struct val){
        }
}
- 類名
- 成員變量
    類的成員變量分為類變量和實例變量,類變量與類共存亡,實例變量與對象共存亡。
- 局部變量
    局部變量分為形參、方法局部變量和代碼塊局部變量,除了形參之外的局部變量聲明后必須顯式初始化才能使用(系統不會默認初始化局部變量)。局部變量保存基本類型的值或者對象的引用,存放在棧內存中,隨着方法或代碼塊的結束而消亡。
- 構造器
    - 構造器名與類名相同,不能顯式指定返回值(隱式返回當前類)。沒有顯式提供構造器時調用系統默認構造器,即Java至少有一個構造器。
    - 創建對象的根本途徑就是使用new關鍵字調用類的構造器。
        `Person p = new Person();`
        p是一個引用變量,只存儲一個地址值,Java程序不允許直接訪問堆內存中的對象,只能通過對象的引用來訪問。`創建對象`的過程如下:
        - 調用構造器
        - 類准備階段--系統為對象分配內存空間
        - 類初始化階段--執行初始化塊,執行默認初始化
        - 通過this引用執行構造器內的程序體,進行顯式初始化
        - 返回該對象
    - 構造器重載
        如果一個構造器包含另一個構造器,則可以使用this來調用另一個構造器,方便以后的修改,降低維護成本。
- 初始化塊
    如果多個構造器中有相同的初始化代碼,則可以把它們放到普通初始化塊里完成。初始化塊總在構造器執行之前執行。static{}靜態初始化塊初始化類。
- 方法
    - Java的方法只能屬於類本身或者類的對象,不能獨立存在。
     - Java方法只能使用值傳遞。如果參數是基本類型的值,則會開辟新的棧內存存放臨時變量;如果參數是引用類型的值,也會開辟新的棧內存存放引用變量,但是變量都是指向堆內存的同一對象。
    - 參數為數組時可以采用形參個數可變的方法,進而使用foreach循環。
        `public void exmple(int a, String... strings){}`
    - 方法重載
    同一個類相同方法名,參數列表不同即為重載,和其他項無關。
  1. 類的作用
    • 定義變量
    • 創建類的對象
    • 調用類的方法或訪問類的變量
  2. this引用
    this關鍵字總是指向調用該方法的對象。
    • 構造器中引用正在初始化的對象
public Person(int age){
    this.age = age;
}
- 普通方法中引用調用該方法的對象(可省略this關鍵字)
    誰調用set()方法,this代表誰。
public void get(){
}
    pubilc void set(){
        this.get();
    }
- static修飾的方法不能使用this引用,因為如果使用this,則this無法指向合適的對象

抽象類

抽象類作為一種模板,提供通用的方法,是一種更高層次的抽象。

  1. 抽象方法只有方法簽名,沒有方法實現。有抽象方法的類只能被定義為抽象類,而抽象類里可以沒有抽象方法。抽象類和抽象方法都用abstract修飾。抽象方法和空方法不同。
    public abstract void test();
  2. 抽象類的構造器不能創建實例,僅用於子類調用,子類必須重寫抽象方法。所以final、private和abstract不能同時使用,static和abstract不能同時修飾方法,可同時修飾內部類。

接口

接口作為特殊的抽象類,是一種規范,其不提供任何方法實現。所有方法都是抽象方法,Java8允許定義默認方法(default修飾,可以提供實現)。

  1. 接口使用interface關鍵字定義。
  2. 接口只能繼承接口,可以有多個父接口。
  3. 接口只能包含靜態常量(pubilc static final修飾+指定默認值),只能有抽象方法(默認public abstract,普通方法不能有方法實現,類方法和默認方法必須實現),只能定義內部類/接口/枚舉(默認public static)。
  4. 訪問控制符只能使用public或者省略。
  5. 一個類可以實現多個接口,關鍵字用implements,放在extends后面。
  6. 實現類必須重寫接口所有的抽象方法,必須用public修飾。

比較抽象類和接口

Java8增強的包裝類

  1. 為了將八種基本數據類型變成引用類型,繼承Object類,Java提供了包裝類,對應關系如下:
    • byte - Byte
    • short - Short
    • int - Integer
    • long - Long
    • char - Character
    • float - Float
    • double - Double
    • boolean - Boolean
  2. 自動裝箱和自動拆箱
    可以直接將一個基本類型的變量賦值給對應的包裝類變量,或者賦值給Object變量,自動拆箱則相反。
  3. 字符串轉換成基本類型的值
    • 利用除Character類的包裝類提供的靜態方法
      int it1 = Integer.parseInt("12345");
    • 利用包裝類提供的構造器
      float ft1 = new Float("12345");
  4. 基本類型的值轉換成字符串
    • 利用連接符+
      String str1 = 10 + "";
    • 利用String類重載的valueOf()方法
      String str2 = String.valueOf(true);
  5. 包裝類的實例可以與基本數據類型的值進行比較
  6. 自動裝箱緩存問題(見java.lang.Integer類的源代碼)
    將-128~127之間的整數自動裝箱成Integer實例時,永遠都是引用cache數組中的同一個數組元素,而在范圍之外的值自動裝箱時,總是會創建新的Integer實例,不相同。

Object類

Java所有的類默認繼承Object父類,因此所有的類都可調用父類的方法。

  1. 重寫toSpring()方法輸出類的對象的狀態信息
    public String toString(){
            return "success";
    }
    
  2. ==和equals方法
    • 運算符
      如果兩個數值類型(不一定數據類型嚴格對應)相等則返回true;如果兩個引用變量指向同一對象則返回true,
      不能比較非父子關系的兩個對象。
    • 關於常量池
      在編譯時被確定並保存在.class文件中的字符串常量和類、接口、方法中的常量保存在常量池中。常量池中的常量是唯一的。new Integer(12)實際上定義了兩個對象。
class EqualTest{
	        public void compare() {
		        String str1 = "123";
		        String str2 = "123";
		        String str3 = new String("123");
		        String str4 = new String("123");
		
		        System.out.println(str1 == str2);
		        System.out.println(str1 == str3);
		        System.out.println(str3 == str4);
		
		        System.out.println(str1.equals(str2));
		        System.out.println(str1.equals(str3));
		        System.out.println(str3.equals(str4));
	        }
}

輸出true、false、false;true、true、true。
- equals方法
- 如果兩個對象的值相等則返回true。
- String已經重寫了equals方法,對於其他的Object類equals方法等同於==(都是比較對象的地址),如果想自定義可以重寫equals方法。
- equals方法的前一個變量不能為null,如"123".equals(str)

public class Test {
	String id = "213";
	public String getId() {
		return id;
	}
	
	public boolean equals(Object object) {
		if(this == object)
			return true;
		if(object != null && object.getClass() == Test.class) {
			Test test = (Test)object;
			if(this.getId().equals(test.getId())) {
				return true;
			}
		}
		return false;
	}
}

equals要求兩個對象是同一個類的實例,所以用object.getClass()==Test.class代替instanceof,這里用到了反射基礎。
3. getClass()方法
返回該對象的運行時類。
4. 控制線程的暫停和運行的方法
wait()、notify()、notifyAll()
5. protected修飾的clone()方法
自定義類實現克隆如下:

//自定義類實現Cloneable接口
public class User implements Cloneable{
	//自定義實現clone()方法
	public User cloneUser() throws CloneNotSupportedException {
		//返回對象的副本
		return (User)super.clone();
	}
}

使用克隆數組比copy方法快。

Objects工具類

提供空指針安全的方法來操作對象。

String、StringBuffer和StringBuilder類

  1. String類是不可變類,所以會額外產生很多臨時變量
    • int length()方法返回字符串長度
    • charAt(int index)方法返回指定位置的字符
    • int compareTo(String str)方法比較兩個字符串的大小,返回長度差或第一個不相同字符的差
    • boolean contentEquals()方法比較兩個字符串是否相同
    • byte[] getBytes()方法將字符串轉換成數組
    • 。。。
  2. StringBuffer類和StringBuilder類相似,其對象字符串序列可變,前者線程安全,后者性能略高
    • append(String string)方法追加字符串
    • insert(int index, String string)方法插入字符串
    • reverse()方法反轉字符串
    • setCharAt()方法
    • setlength()方法設置長度
    • replace(left, right, string)替換字符串
    • toString()方法將StringBuffer對象轉換為String對象
  3. 幾個面試題
    • 請問String s = new String("hello");創建了幾個對象。
      兩個。一個"hello"字符串對象,在方法區的常量池;一個s對象,在棧內存。
    • 請寫出下面的結果
    		String s1 = new String("abc");
    		String s2 = new String("abc");
    		String s3 = "abc";
    		String s4 = "abc";
    
    		syso(s1==s2);  //false
    		syso(s1==s3);  //false
    		syso(s3==s4);  //true
    
    • 字符串對象一旦被創建就不能被改變。
      指的是字符串常量值不改變。
  4. 正則表達式



Math類

其構造器為private修飾,提供大量類變量(如PI、E)和類方法。
- pow()方法計算乘方
- random()方法返回一個偽隨機數(0.0-1.0)

Random類和ThreadLocalRandom類

  1. Random類生成的是一種偽隨機數,相同的種子相同的方法會產生相同的隨機數,因此使用當前時間作種子
    Random rand = new Random(System.currentTimemillis());
  2. 使用ThreadLocalRandom在並發環境下具有更好的線程安全性,它通過current()方法生成對象
    ThreadLocalRandom rand = ThreadLocalRandom.current();
    - 生成指定范圍的隨機數
    int tmp = rand.nextInt(5, 10);

BigDecimal類

Java的float和double類型會引起精度丟失,BigDecimal類提供大量構造器創建對象。
- 優先推薦使用參數為String的構造器。
- 如果必須使用浮點數為參數的構造器,需要使用valueOf(double val)靜態方法轉換為BigDecimal對象
BigDecimal f = BigDecimal.valueOf(12.45);
- 基本運算有add()方法、subtract()方法、multiply()方法、divide()方法、pow()方法等

Calendar類

  1. 抽象類,調用getInstance()靜態方法獲取對象。
    Calendar cal = Calendar.getInstance();
    • 獲取日期cal.getTime()
    • 修改日歷指定字段的值cal.set(2013, 12, 20, 06, 30, 42)
    • add()
    • roll()
  2. java8新增了java.time包,含如下類:
    • Clock類可取代System類的currentTimemillis()
    • LocalDate類不帶時區的日期,提供靜態now()方法獲取當前時刻
    • LocalTime類不帶時區的時間
    • DayOfWeek枚舉類定義了周六到周日
    • Month枚舉類定義了十二個月

單例類

不允許自由創建該類的實例,只允許該類創建一個實例。

public class Singleton {
	
	//需要被static方法訪問的緩存變量
	private static Singleton singleton = null;
	
	//隱藏構造器
	private Singleton() {
	}
	
	//暴露的方法,因為調用該方法之前還沒有對象,所以要用static修飾
	public static Singleton getSingleton() {
		if(singleton == null)
			singleton = new Singleton();
		return singleton;
	}
}

final

  1. final修飾的變量不可被改變,但是final修飾的引用變量所引用的對象的內容可以被改變。final修飾的成員變量必須顯式的指定初始值(否則沒意義,默認初始化)。
  2. final定義並指定初始值的變量在編譯階段就確定下來,保存在常量池中,程序執行時直接進行宏替換。
  3. final修飾的方法不能被重寫,比如Object類中的getClass()方法,
  4. final修飾的類不能被繼承。

不可變類

  1. Java提供的八個包裝類和java.lang.String類是不可變類,它們的實例變量不可改變。
  2. 自定義不可變類需要滿足的規則:
    • 使用private和final修飾成員變量
    • 使用帶參數的構造器來初始化成員變量
    • 提供getter方法,不能提供setter方法
    • 有必要的話重寫Object類的hashCode()和equals方法
    • 保證成員變量引用的對象不可變
  3. 如果某個不可變實例經常被使用,需考慮對不可變實例進行緩存,減少系統開銷。

System類和Runtime類

系統提供System類和Runtime類與程序的運行平台進行交互。

  • System類代表當前Java程序的運行平台,它提供了一些代表標准輸入、標准輸出、錯誤輸出的類變量和用於訪問環境變量、系統屬性的類方法。
    比如用long Tnow = System.currentTimeMillis()返回系統當前時間。
  • Runtime類代表Java程序的運行時環境,可以訪問JVM的相關信息。

內部類

Java8新增的lambda表達式

參見Lambda入門

枚舉類

枚舉類是一種特殊的類,使用enum關鍵字, 定義如下:

public enum SeasonEnum {
	SPRING, SUMMER, FALL, WINTER;
}

使用如下:


public class EnumTest {
	public void getEnum() {
		
		//枚舉類默認的values()方法返回所有實例
		for(SeasonEnum s : SeasonEnum.values()) {
			System.out.println(s);
		}
	}
	public void select(SeasonEnum s) {
		//swich的控制表達式可以是枚舉類型
		switch (s) {
			//無需添加枚舉類限定
			case SPRING:
				System.out.println("spring");
				break;
			case SUMMER:
				System.out.println("summer");
				break;
			case FALL:
				System.out.println("fall");
				break;
			case WINTER:
				System.out.println("winter");
				break;
		
		}
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM