內部類,Object,字串
內部類
內部類的存在允許了一個類定義在另一個類之中
內部類的基本語法
class 類名 {
// 內部類
class 類名 {
}
內部類的分類
成員內部類
顧名思義,成員內部類即將類當成外部類的一個成員變數
- 成員內部類可以直接呼叫外部類的成員變數(包括private)→例項化物件之後就無法訪問了
- 由於外部類例項化的過程中已經攜帶了內部類的資訊,即給類資訊分配好了記憶體,則我們例項化內部類時只需要呼叫已經例項化完成了的外部類物件.
OuterClass.InnerClass innerClass = new OuterClass().new InnerClass();
透過類例項化OuterClass.InnerClass innerClass = outerClass.new InnerClass();
透過外部類物件例項化
public class OuterClass {
private int outVar=100;
public class InnerClass{
public void display(){
System.out.println("外部類變數為:"+outVar);//內部類可以直接訪問外部類變數
}
}
}
public class Test {//測試類
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = new OuterClass().new InnerClass();
//類例項化
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
//外部類物件例項化
}
}
靜態內部類
靜態內部類就是被static關鍵字修飾的內部方法,簡單來說就是把他放入static池中,
- 不用例項化外部類物件就可以呼叫其中的靜態成員方法和靜態成員變數
- 靜態內部類可以直接呼叫外部靜態方法和靜態變數
public class OuterClass {
private static int outVar=100;
public static class StaticInnerClass{ //靜態內部類
public static void display(){
System.out.println("外部類變數為:"+outVar);//內部類可以直接訪問外部類變數
}
public void notStaticDisplay(){ //非靜態內部類
System.out.println("外部類變數為:"+outVar);
}
}
}
public class Test {
public static void main(String[] args) {
OuterClass.StaticInnerClass.display();//當呼叫靜態方法時不需建立例項物件
OuterClass.StaticInnerClass staticInnerClass = new OuterClass.StaticInnerClass();
//當呼叫非靜態方法時需建立例項物件
staticInnerClass.notStaticDisplay();
}
}
區域性內部類
區域性內部類是定義再方法內部或任意程式碼塊中的類
-
區域性內部類的作用域:只能在其被定義的方法或程式碼塊中使用,包括其建構函式
public class OuterClass { private int outVar=100; public void doSomething(){ class LocalInnerClass { void display() { System.out.println("外部類的成員變數值為:"+outVar);//可以訪問外部類的成員 } } //可以在方法中例項化區域性內部類 LocalInnerClass localInnerClass = new LocalInnerClass(); localInnerClass.display(); } //會報錯 LocalInnerClass localInnerClass = new LocalInnerClass(); localInnerClass.display(); }
訪問外部類的成員:區域性內部類可以訪問外部類的所有成員(包括private),但不能訪問定義它們的方法(即它們所在的方法)和或程式碼塊的引數(除非其是final
匿名內部類
匿名內部類是沒有類名內部類,通常用於實現介面或者繼承類,繼承或者實現介面的時候,如果子類只用到了一次,則可以直接使用匿名內部類來是實現
介面 變數名=new 介面() //基本語法
{
};
public class OuterClass
{
int OutVar=100;
//已知外部已經存在一個介面OneInterface
OneInterface oneInterface=new OneInterface() {
@Override
public void display() {
System.out.println(OutVar);
}
};
} //內部類的基本用法
Object
在java中,Object類是所有類的根類.這意味著一個類沒有明確繼承的類時,則它預設繼承Object類.
Object中幾個重要的方法
equals()
- 用途:用於比較兩個物件的相等性(而不是它們的引用→記憶體地址)
- 通常情況下,
equals()
是使用==
來比較物件的記憶體地址,即比較兩個物件是否是一個物件.但實際情況中,我們通常要比較兩個物件的內容是否一致,這是就得重寫equals()
方法 equals()
與==
的區別- 對於基本資料型別:如
int,double,float,Boolean
,==
運算子的作用是比較兩個值是否相等,即直接比較兩個值在記憶體中的表示是否相同. - 對於引用型別:如 陣列,介面,類等,
==
運算子是用於比較兩個引用是否指向記憶體中同一個物件,簡單來說就是比較它們的記憶體地址是否相同,而不是比較它們的內容是否相同 - 我會在講解了
String
類之後給大家舉個例子
- 對於基本資料型別:如
toString()
- 用途:返回該物件的字串表示形式
- 預設情況下,
toString()
方法返回的字串是類名+”@”+物件的雜湊碼和無符號十六進位制表示形式.但實際開發我們通常需要更具體,更有意義的字串表達形式,這是我們可以對toString()
方法進行重寫
預設toString()方法的example:
public class Person
{ private int age;
String sex;
//getter setter 方法
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.toString());
}
}
輸出為:
重寫toString()
方法
public class Person {
private int age;
String sex;
String name;
//構造一個構造器便於我們理解toString()的重寫
public Person(int age, String sex, String name) {
this.age = age;
this.sex = sex;
this.name = name;
}
//重寫toString()
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex="
+sex+
'}';
}
public static void main(String[] args) {
Person person = new Person(18,"man","Jack");
System.out.println(person.toString());
}
}
輸出為:
hashCode()
- 用途:返回該物件的雜湊碼值.(雜湊碼都是唯一的整數).雜湊碼值主要用於雜湊資料結構如,
HashMap
,HashSet
- 預設情況下,
hashCode()
返回的雜湊碼是物件的記憶體地址,但如果重寫了equals()
方法通常都要重寫hashCode()
方法
hashCode()
返回的效果
finalize()
- 用途:在垃圾收集器決定回收某物件之前呼叫此方法
- 預設情況下,我們不用手動去呼叫,由JVM來呼叫,當垃圾回收器確定不存在該物件的引用時,由物件的垃圾回收器呼叫此方法,某些情況下,我們可能執行一些具體的功能如 關閉檔案,斷開資料庫等等,這時需要我們重寫
finalize()
方法
getClass()
- 用途:返回此
Object
執行時類的Class物件 - 該方法在反射和泛型型別檢查等場景中特別有用,由於這節課不涉及該知識點,我們之後學習到再詳細講解
String(字串類
String
是java中一個核心類,用於表示字元序列(即文字).
不可變性
- 核心特性:
String
物件的內容是不可變的,一旦一個String
物件被建立,它的內容就不能被改變 - 快取特性:字串池(String Pool) 可以儲存已經建立過的字串物件,避免重複建立相同的字串物件
字串建立的方法
1. 字面量建立
- 直接使用
=
與””
字元序列來建立字串
String str1="Hello";
- 透過這種方法來建立的字串,本質上是透過字串池來引用已有的字串常量;
2. 構造方法建立
- 透過
String
類的構造方法來建立字串物件
String str1=new String("Hello");
- 透過這種方法來建立字串,是再堆記憶體中申請了一個新的
String
物件,即建立了一個新的物件
字串池(StringPool
- 概念: 字串池是java堆記憶體中一個特殊區域,用於存放字串的字面量(即程式碼中的字串
””
中的) - 特點:當建立一個字串字面量時,JVM首先會檢查字串池中是否已經存在相同的字串.如果有則返回其引用(即指向已存在的字串常量);否則,再字串池中建立一個新的字串物件,並返回其引用
該特性也可以用來區分equals()
與==
的區別
public class Test {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello");
String str4 = new String("Hello");
System.out.println(str1 == str2); //true
System.out.println(str1 == str3);//false
System.out.println(str3 == str4);//false
//equals()
System.out.println(str1.equals(str2)); //true
System.out.println(str1.equals(str3));//true
System.out.println(str3.equals(str4));//true
}
}
分析:
首先程式開始,JVM先掃描靜態區和字串常量,先找到
”Hello”
,先放入字串池中,接著String str1 = "Hello";String str2 = "Hello";
這兩步的作用是將str1,str2的引用指向了字串池中的”Hello”
常量;因此str1與str2兩個指向的是同一個地址.
接著透過
String
建構函式建立了兩個新物件,str3,str4
str3
與str4
實際儲存的是新new出來的例項物件的值,而這兩個例項物件中有一個value值,指向的是字串池中的”Hello”
常量
如下圖具體:
字串常用的方法
方法 | 描述 |
---|---|
public boolean equals(Object anObject) | 比較字串的內容,嚴格區分大小寫。 |
public boolean equalsIignoreCase(String anotherString) | 比較字串的內容,忽略大小寫。 |
public int length() | 返回此字串的長度。 |
public char charAt(int index) | 返回指定索引處的 char 值。 |
public char[] toCharArray() | 將字串拆分為字元陣列後返回。 |
public String substring(int beginIndex, int endIndex) | 根據開始和結束索引進行擷取,得到新的字串(包含頭,不包含尾)。 |
public String substring(int beginIndex) | 從傳入的索引處擷取,擷取到末尾,得到新的字串。 |
public String replace(CharSequence target, CharSequence replacement) | 使用新值,將字串中的舊值替換,得到新的字串。 |
public String[] split(String regex) | 根據傳入的規則切割字串,得到字串陣列。 |
public byte[] getBytes() | 獲得當前字串底層的位元組陣列。 |
StringBuilder 和 StringBuffer(線上程中會更詳細講解)
- 由於
String
的不可變性,頻繁的字串連線操作會導致大量的中間字串物件被建立和銷燬,從而影響效能。為了解決這個問題,Java 提供了StringBuilder
和StringBuffer
類,它們允許在記憶體中直接修改字元序列,從而提高效能。 StringBuilder
不是執行緒安全的,而StringBuffer
是執行緒安全的(但效能略低於StringBuilder
)。在單執行緒環境中,通常使用StringBuilder
;在多執行緒環境中,如果需要執行緒安全,則使用StringBuffer
。