Java

Yolololololo發表於2024-10-21

Java

Hello world!

image-20240926164131545

psvm解釋語句,main方法,main(引數),以上無引數,sout輸出

注:

  • 注意大小寫
  • 檔名和類名需要保持一致
  • 命名規則,首字母小寫 駝峰式命名

識別符號

  • 能字母,$,_,開頭
  • 不能以關鍵字作為變數名或方法名
  • 注意大小寫(大寫的跟小寫的不是同一個變數)
  • 不能以特殊符號,數字來命名
  • 下劃線之後可以存在數字

image-20240926173231335

佔位符

%表示佔位符,因此,連續兩個%%表示一個%字元本身

佔位符 說明
%d 格式化輸出整數
%x 格式化輸出十六進位制整數
%f 格式化輸出浮點數
%e 格式化輸出科學計數法表示的浮點數
%s 格式化字串

資料型別

基本型別

image-20240926174647432

image-20240926174356424

擴充

整數

image-20240926175445238

浮點數

image-20240926180159672

float接近但不等於,大約 (少用浮點數進行比較 有誤差)

字元

強制轉換成數字(字元的本質是數字)

image-20240926180743772

編碼

image-20240926181117678

跳脫字元

\t	製表符
\n	換行

ps:

if (flag==true){}
和
if (flag){}
是一樣的,只是寫法不同

型別轉換

image-20240926191150268

強制轉換 :(型別)變數名 高到底

自動轉換: ... 低到高

  • 不能對布林值進行轉換
  • 存在記憶體溢位或精度問題

image-20240926191959631

image-20240926192143551

image-20240926192536368

變數

變數作用域

賦值

變數的一個重要特徵是可以重新賦值

第一次賦值時定義過了變數型別,第二次賦值時則不需要重新賦值

image-20241009200336737

將一個變數的值重新賦值另一個變數

image-20241009201721838

類變數

從屬於類,隨著類一起存在一起消失

image-20240926210750001

例項變數

從屬於物件,如果未設定初始化,輸出型別的預設值

image-20240926210451017

區域性變數

必須聲名和初始化值

定義在某個方法內,當程式執行完該方法的時候 無法呼叫該變數

常量

final 常量名 常量值

變數命名

image-20240926212241648

運算子

image-20240926212513092

自增 自減

image-20240926215532055

邏輯運算子

image-20240926220241599

b是假 上來就結束執行 稱為短路運算

image-20240926220445301

如果後面的執行 結果為6

位運算

image-20240926221559373

當出現字串時,後面的數字將會被轉化成字串型別顯示出來 所以輸出是1020

image-20240927082629966

三元運算子

b ? x : y

image-20240927083108429

包機制

包 其實就是資料夾

利用公司域名倒置作包名 eg:com.baidu.www

image-20240927085811946

image-20240927101503378

匯入包

image-20240927102245781

Doc

引數資訊

@author 作者名
@version 版本號
@since 指明需要最早使用的的jdk版本
@return 返回值情況
@throws 異常丟擲情況

生成Doc文件

命令列:javadoc 引數 java檔案

javadoc -encoding UTF-8 -charset UTF-8 Doc.java

image-20240927091714852

image-20240927091749665

IDEA生成doc文件

image-20240927094021232

生成doc

image-20240927095514764

生成了

image-20240927095658960

image-20240927095630030

控制流程

輸入

``System.in代表標準輸入流

Scanner物件

透過Scanner類來獲取使用者的輸入,透過Scanner類的next()nextLine()方法獲取輸入的字串,用hasNext()hasNextLine()判斷是否還有輸入的資料

image-20240927112231974

next

image-20240927112442836

nextLine

image-20240927112520634

簡潔版

image-20240927112913289

判斷

image-20240927164455871

image-20240927164620441

求和 平均數

image-20240927170226256

image-20240927170545641

輸出

``System.out代表標準輸出流

順序結構

選擇結構

image-20240927172707194

image-20240927172720680

多選擇結構

if,else,else if

image-20240927215215413

switch case語句

case穿透

當沒有break語句時,會將下面的語句全部輸出,而不是可選模式

image-20240927220453747

反編譯

image-20240927221202862

資料夾 複製檔案

image-20240927221411854

反編譯檔案

image-20240927221444174

中文時透過雜湊值來比較

image-20240927221602271

判斷引用型別相等

  • 判斷引用型別的變數是否相等用 ==

  • 判斷引用型別的變數內容是否相等用 equals()方法

迴圈結構

while迴圈

如果不滿足條件,則不能進入迴圈

先判斷後執行

image-20240928091137451

image-20240928091531427

do...while

即使不滿足while迴圈條件,至少也會執行一次迴圈

先執行後判斷

image-20240928092515326

while和do..while迴圈的區別

image-20240928093022859

for迴圈

for(初始化;布林表示式;更新){
	//程式碼
}

image-20240928093710131

計算1-100之間的奇數和,偶數和

image-20240928095128953

計算1-1000之間的能被5整除的數,並且3個數一換行

image-20240928100525715

注:

println輸出完 會換行

print輸出完 不會換行

九九乘法表

image-20240928102219525

增強for迴圈

image-20240928105301569

語句更簡便

breakcontinue

break是強制退出迴圈,不執行剩下的語句

continue 用於終止某次迴圈過程,跳過迴圈體中尚未執行的語句,接著進行下一次是否執行迴圈的判定(再次回到尋魂開始的地方,從新開始迴圈)

image-20240928140648801

標籤

image-20240928141308637

列印三角形

image-20240928142449929

方法

Java方法是語句的集合,他們在一起執行一個功能

  • 方法是解決一類問題的步驟的有序組合
  • 方法包含於類或物件中
  • 方法在程式中被建立,在其他地方被引用
  • 方法的本意是功能塊
  • 一個方法只完成一個功能

image-20240928191935748

void表示

main方法要時刻保持簡介乾淨,儘量將公共模組都提取到外面,通方法呼叫來實現功能

image-20240928195152724

方法的定義

Java的方法類似於其他語言的函式,是一段用來完成特定功能的程式碼片段

定義方法的語句

方法包含一個方法頭和一個方法體

image-20240928200006774

形參和實參

image-20240928202526653

方法呼叫

呼叫方法:物件名.方法名(實參列表)

  • 當方法返回一個值得時候,方法呼叫通常被當作一個值

    int larger = max(30,40);
    
  • 當方法返回值是void,方法呼叫一定是一條語句

    System.out.println("Hello,Yolo!")
    

image-20240928211748887

方法過載

過載就是在一個類中,有相同的函式名稱,但形參不同的函式

方法的過載的規則:

  • 方法名稱必須相同
  • 引數列表必須不同(個數不同,或型別不同,引數排列順序不同等)
  • 方法的返回型別可以相同也可以不同
  • 僅僅返回型別不同不足以成為方法的過載

image-20240929171454189

可變引數(不定項引數)

image-20240929193520659

遞迴

自己呼叫自己

遞迴的兩部分

  • 遞迴頭:定義什麼時候不呼叫自身方法。如果沒有頭,將陷入死迴圈
  • 遞迴體:什麼時候需要呼叫自身方法

image-20240929195810357

image-20240929200743571

image-20240929201051691

基數大的不要用遞迴

計算器

陣列

陣列是相同型別資料的有序集合,是相同型別的若干個資料,按照一定的先後次序排雷組合而成

其中的每一個資料稱作一個陣列元素,每個陣列元素可以透過一個下標來訪問他們

格式

dataType[] arrayRefVar;

用 new 來建立陣列

定義了什麼型別的陣列,就new什麼型別的陣列

dataType[] arrayRefVar = new dataType[arraySize];

eg:

nums = new int [10];			#可以存放10個int型別的數字

image-20240929220817489

記憶體分析

陣列邊界

注意下標的合法區間 [0,length-1]超出區間會報錯

image-20241007173640671

image-20241007173755943

陣列的使用

for迴圈

image-20241007200142765

反轉陣列

image-20241008153318298

多維陣列

二維陣列

int a[][] = new int[2][5];

image-20241008155425775

image-20241008155712066

image-20241008161417004

image-20241008161654473

氣泡排序

  • 比較陣列中,兩個相鄰的元素,如果第一個數比第二個數大,我們就交換他們的位置

  • 每一次比較,都會產生出一個最大,或者最小的數字;

  • 下一輪則可以少一次排序!

  • 依次迴圈,直到結束!

image-20241008171733829

自動排序

Arrays.sort(n);

稀疏陣列

  • ​ 當一個陣列中大部分元素為0,或者為同一值的陣列時,可以用稀疏陣列來儲存陣列
  • 稀疏陣列的處理方式
    1. 記錄陣列一共有幾行幾列,有多少個不同值
    2. 把具有不同值的元素而後行列及值記錄愛意額小規模陣列中,從而縮小程式的規模

image-20241008201704591

轉換為稀疏陣列

獲取有效值個數

image-20241008203320501

稀疏陣列還原

物件導向程式設計 和 程序導向程式設計 的區別

程序導向程式設計是 將任務一步步拆分,第一步幹啥,第二步幹啥,最後幹啥

物件導向程式設計是 先有物件 然後與其進行互動

GirlFriend gf = new GirlFriend();
gf.name = "Alice";
gf.send("flowers");

建立物件,賦值,呼叫物件,並傳遞了個引數 Alice傳送了一些 花

物件導向

本質

以類的方式組織程式碼,以物件的組織(封裝)資料

基本概念

  • 例項
  • 方法

三大特性

(物件導向的實現方式)

  • 封裝

  • 繼承

  • 多型

物件導向基礎

Person zhang = new Person();

建立了Person型別的例項,透過變數zhang來指向它

Person zhang是定義Person是定義Person型別的變數zhangnew Person()是建立Person例項

image-20241010201108240

方法

public變成private

外部程式碼呼叫方法setName()setAge()來間接修改private欄位

setAge()就會檢查傳入的引數

image-20241010204106305

注:類透過定義方法,可以給外部程式碼暴露一些操作的介面

定義方法

修飾符 方法返回型別 方法名(方法引數列表) {
    若干方法語句;
    return 方法返回值;
}
private方法

只有內部方法可以呼叫private方法

image-20241010211847814

以上程式碼沒有定義age欄位,獲取age時,透過方法getAge()返回的是一個實時計算的值,並非儲存在某個欄位的值。這說明方法可以封裝一個類的對外介面,呼叫方不需要知道也不關心Person例項在內部到底有沒有age欄位

this變數

在方法內部呼叫,始終指向當前例項

沒有命名衝突時可以省略

class Person {
    private String name;

    public String getName() {
        return name; // 相當於this.name
    }
}
class Person {
    private String name;

    public void setName(String name) {
        this.name = name; // 前面的this不可少,少了就變成區域性變數name了
    }
}
方法引數
class Person {
    ...
    public void setNameAndAge(String name, int age) {
        ...
    }
}

當呼叫以上方法時,必須呼叫兩個引數, stringint

Person zhang = new Person();
zhang.steNameAndAge("zhangsan",18)
可變引數

可變引數跟陣列型別類似

image-20241011215334894

引數繫結

呼叫方把引數傳遞給例項方法時,呼叫時傳遞的值會按引數位置一一繫結

基本型別的引數傳遞

image-20241011222206952

以上,setAge方法是將傳入的值賦給Person例項的 age屬性,變數 n本身與 age屬性並沒有繫結,所以 當 n值改變時,page屬性保持不變

故 基本型別的引數傳遞 時區域性變數和n互不影響

傳遞引用引數

image-20241012192648660

以上 引數是以一個陣列,修改其內容,例項 p 的欄位 name的內容 也會被修改

引用型別引數的傳遞,呼叫方的變數,和接收方的引數變數,指向的是同一個物件。雙方任意一方對這個物件的修改,都會影響對方(因為指向同一個物件)

image-20241012200121161

呼叫方法

例項變數.方法名("引數")

zhang.setName("李華")

構造方法

建立例項時,透過構造方法實現將例項的值初始化完成

image-20241012202411799

構造方法名是類名,對引數沒有限制,在方法內部(跟普通方法象不沒有返回值【包括void】)

注:

當我們定義了一個類而沒有自定義構造方法時,編譯器會自動生成一個預設的構造方法,預設構造方法裡 沒有引數和執行語句

class Person {
    public Person() {
    }
}

我們還可以定義兩個構造方法 比如帶引數的和不帶引數的

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("Xiao Ming", 15); // 既可以呼叫帶引數的構造方法
        Person p2 = new Person(); // 也可以呼叫無引數構造方法
    }
}

class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }
}

image-20241012205337665

由於先執行初始化程式碼 在執行建構函式的程式碼 ,所以 new Person的值由構造方法確定

多個構造方法
class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(String name) {
        this.name = name;
        this.age = 12;
    }

    public Person() {
    }
}

如果呼叫new Person("Xiao Ming", 20);,會自動匹配到構造方法public Person(String, int)

如果呼叫new Person("Xiao Ming");,會自動匹配到構造方法public Person(String)

如果呼叫new Person();,會自動匹配到構造方法public Person()

構造方法呼叫另一個構造方法
class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(String name) {
        this(name, 18); // 呼叫另一個構造方法Person(String, int)
    }

    public Person() {
        this("Unnamed"); // 呼叫另一個構造方法Person(String)
    }
}

方法過載

方法名相同,但引數不同,叫方法過載(Overload)

功能類似的方法,使用同一方法名,呼叫起來方便

class Hello {
    public void hello() {
        System.out.println("Hello, world!");
    }

    public void hello(String name) {
        System.out.println("Hello, " + name + "!");
    }

    public void hello(String name, int age) {
        if (age < 18) {
            System.out.println("Hi, " + name + "!");
        } else {
            System.out.println("Hello, " + name + "!");
        }
    }
}

可以有多個過載方法

繼承

繼承機制,可以複用程式碼

當我們在person類的基礎上新增studentstudent類包含了person類已有的欄位和方法並且多了sorce欄位

class Person {
    private String name;
    private int age;

    public String getName() {...}
    public void setName(String name) {...}
    public int getAge() {...}
    public void setAge(int age) {...}
}

class Student {
    private String name;
    private int age;
    private int score;

    public String getName() {...}
    public void setName(String name) {...}
    public int getAge() {...}
    public void setAge(int age) {...}
    public int getScore() { … }
    public void setScore(int score) { … }
}

根據繼承機制 以上程式碼可以用 extends關鍵字來實現繼承

不需要重新定義agename欄位 只需要重新定義score欄位

class Person {
    private String name;
    private int age;

    public String getName() {...}
    public void setName(String name) {...}
    public int getAge() {...}
    public void setAge(int age) {...}
}

class Student extends Person {
    private int score;

    public int getScore() { … }
    public void setScore(int score) { … }

注:子類自動獲得了父類的所有欄位,嚴禁定義與父類重名的欄位!

在OOP的術語中,我們把Person稱為超類(super class),父類(parent class),基類(base class),把Student稱為子類(subclass),擴充套件類(extended class

感覺跟ssti的繼承類似 每個類都會繼承自某個類

image-20241013113757929

也可以 某兩個類繼承於同一個類

protected關鍵字

  • 子類無法訪問父類的private欄位 或者private方法
  • 但是 只要將 private修改為 protected就能被子類訪問到
  • 子類的子類 也可以訪問其父類的protected
  • protected關鍵字所修飾的欄位和防範 能夠保證訪問許可權在繼承樹的內部

super(父類)

super表示父類,當子類引用父類的欄位時,可以用 super.fileName

class Student extends Person {
    public String hello() {
        return "Hello, " + super.name;
    }
}

除必要情況 也可以直接使用 this.anme或者name 效果是一樣的

當父類沒有預設的構造方法時 子類就必須呼叫super();

public class Main {
    public static void main(String[] args) {
        Student s = new Student("Xiao Ming", 12, 89);
    }
}

class Person {
    protected String name;
    protected int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
        super(name, age); // 呼叫父類的構造方法Person(String, int)
        this.score = score;
    }
}

子類不會繼承任何父類的構造方法。子類預設的構造方法是編譯器自動生成的,不是繼承的

使用sealed修飾class,並透過permits明確寫出能夠從該class繼承的子類名稱

public sealed class Shape permits Rect, Circle, Triangle {
    ...
}

向上轉型

student繼承了 person之後 student就有了 perosn的所有功能 可以實現一個引用型別為 person的變數指向 student型別的例項

Person p = new Student();

透過以上例項 可以發現 子類型別可以轉換為更高層次的父類甚至是 object

向下轉型

將父類型別強制轉換成子型別

Person p1 = new Student();
Student s1 (Student) p1;

但是如果 p2一開始是指向Person的將無法轉換

Person p2 = new Person();
Student s2 (Student) p2;
instanceof運算子
Person p = new Person();
System.out.println(p instanceof Person); // true
System.out.println(p instanceof Student); // false

Student s = new Student();
System.out.println(s instanceof Person); // true
System.out.println(s instanceof Student); // true

Student n = null;
System.out.println(n instanceof Student); // false

判斷instanceof

 public static void main(String[] args) {
        Object obj = "hello";
        if (obj instanceof String s) {
            // 可以直接使用變數s:
            System.out.println(s.toUpperCase());
        }
    }
}

組合

studentpersonis關係, studentbookhas關係

is關係是繼承 has關係是組合

class Student extends Person {
    protected Book book;
    protected int score;
}

多型

在繼承關係中,子類如果定義了一個與父類方法簽名完全相同的方法,被稱為覆寫(Override)

class Person {
    public void run() {
        System.out.println("Person.run");
    }
}

在子類Student中,覆寫這個run()方法:

class Student extends Person {
    @Override	//編譯器會幫助檢查是否覆寫成功
    public void run() {
        System.out.println("Student.run");
    }
}

計算稅收的例項

// Polymorphic
public class Main {
    public static void main(String[] args) {
        // 給一個有普通收入、工資收入和享受國務院特殊津貼的小夥伴算稅:
        Income[] incomes = new Income[] {
            new Income(3000),
            new Salary(7500),
            new StateCouncilSpecialAllowance(15000)
        };
        System.out.println(totalTax(incomes));
    }

    public static double totalTax(Income... incomes) {
        double total = 0;
        for (Income income: incomes) {
            total = total + income.getTax();
        }
        return total;
    }
}

class Income {
    protected double income;

    public Income(double income) {
        this.income = income;
    }

    public double getTax() {
        return income * 0.1; // 稅率10%
    }
}

class Salary extends Income {
    public Salary(double income) {
        super(income);
    }

    @Override
    public double getTax() {
        if (income <= 5000) {
            return 0;
        }
        return (income - 5000) * 0.2;
    }
}

class StateCouncilSpecialAllowance extends Income {
    public StateCouncilSpecialAllowance(double income) {
        super(income);
    }

    @Override
    public double getTax() {
        return 0;
    }
}

在必要的情況下,我們可以覆寫Object的這幾個方法。例如:

class Person {
    ...
    // 顯示更有意義的字串:
    @Override
    public String toString() {
        return "Person:name=" + name;
    }

    // 比較是否相等:
    @Override
    public boolean equals(Object o) {
        // 當且僅當o為Person型別:
        if (o instanceof Person) {
            Person p = (Person) o;
            // 並且name欄位相同時,返回true:
            return this.name.equals(p.name);
        }
        return false;
    }

    // 計算hash:
    @Override
    public int hashCode() {
        return this.name.hashCode();
    }
}

在子類的覆寫方法中,如果要呼叫父類的被覆寫的方法,可以透過super來呼叫

繼承可以允許子類覆寫父類的方法。如果一個父類不允許子類對它的某個方法進行覆寫,可以把該方法標記為final。用final修飾的方法不能被Override

class Person {
    protected String name;
    public final String hello() {
        return "Hello, " + name;
    }
}

class Student extends Person {
    // compile error: 不允許覆寫
    @Override
    public String hello() {
    }
}

如果一個類不希望任何其他類繼承自它,那麼可以把這個類本身標記為final。用final修飾的類不能被繼承:

final class Person {
    protected String name;
}

// compile error: 不允許繼承自Person
class Student extends Person {
}

欄位同理

class Person {
    public final String name = "Unamed";
}

給final欄位重新賦值會報錯

如果父類的方法本身不需要實現任何功能,僅僅是為了定義方法簽名,目的是讓子類去覆寫它,那麼,可以把父類的方法宣告為抽象方法

抽象方法

如果一個class定義了方法,但沒有具體執行程式碼,這個方法就是抽象方法,抽象方法用abstract修飾。

因為無法執行抽象方法,因此這個類也必須申明為抽象類(abstract class)。

介面

interface用 它來宣告一個介面

所謂interface,就是比抽象類還要抽象的純抽象介面,因為它連欄位都不能有。因為介面定義的所有方法預設都是public abstract

當一個具體的class去實現一個interface時,需要使用implements關鍵字。舉個例子:

class Student implements Person {
    private String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(this.name + " run");
    }

    @Override
    public String getName() {
        return this.name;
    }
}

介面繼承

一個interface可以繼承自另一個interfaceinterface繼承自interface使用extends,它相當於擴充套件了介面的方法。例如:

interface Hello {
    void hello();
}

interface Person extends Hello {
    void run();
    String getName();
}

此時,Person介面繼承自Hello介面,因此,Person介面現在實際上有3個抽象方法簽名,其中一個來自繼承的Hello介面

image-20241013170726459

靜態欄位和靜態方法

靜態欄位

public class Main {
    public static void main(String[] args) {
        Person ming = new Person("Xiao Ming", 12);
        Person hong = new Person("Xiao Hong", 15);
        ming.number = 88;
        System.out.println(hong.number);
        hong.number = 99;
        System.out.println(ming.number);
    }
}

class Person {
    public String name;
    public int age;

    public static int number;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

推薦用類名來訪問靜態欄位

Person.number = 99;
System.out.println(Person.number);

靜態方法

靜態方法需透過類名呼叫

靜態方法屬於class不屬於例項

包沒有父子關係 沒有繼承關係

解決包衝突的問題包名.類名,如

小明的Person類存放在包ming下面,因此,完整類名是ming.Person

JDK的Arrays類存放在包java.util下面,因此,完整類名是java.util.Arrays

在定義class的時候,我們需要在第一行宣告這個class屬於哪個包

小明的Person.java檔案:

package ming; // 申明包名ming

public class Person {
}

包作用域

包作用域是指,一個類允許訪問同一個 package的沒有 publicprivate修飾的 class,以及沒有public protected private修飾的欄位和方法

位於同一個包的類,可以訪問包作用域的欄位和方法。不用publicprotectedprivate修飾的欄位和方法就是包作用域。例如,Person類定義在hello包下面:

package hello;

public class Person {
    // 包作用域:
    void hello() {
        System.out.println("Hello!");
    }
}

當小明要引用小軍的類時

package ming;

// 匯入完整類名:
import mr.jun.Arrays;

public class Person {
    public void run() {
        // 寫簡單類名: Arrays
        Arrays arrays = new Arrays();
    }
}

定義為public的類或者方法可以被其它類呼叫,前提是要有訪問的權力

定義為private的方法無法被其他類訪問:

image-20241014203521520

巢狀

定義在 class內部的 class 就是巢狀類

final可以阻止區域性變數、方法被重新賦值,方法被子類覆寫,class被覆寫

內部類

有一種類被定義在另一個類的內部,稱為內部類(Inner Class)

class Outer {
    class Inner {
        // 定義了一個Inner Class
    }
}

上述定義的Outer是一個普通類,而Inner是一個Inner Class,它與普通類有個最大的不同,就是Inner Class的例項不能單獨存在,必須依附於一個Outer Class的例項。示例程式碼如下:

// inner class
public class Main {
    public static void main(String[] args) {
        Outer outer = new Outer("Nested"); // 例項化一個Outer
        Outer.Inner inner = outer.new Inner(); // 例項化一個Inner
        inner.hello();
    }
}

class Outer {
    private String name;

    Outer(String name) {
        this.name = name;
    }

    class Inner {
        void hello() {
            System.out.println("Hello, " + Outer.this.name);
        }
    }
}
Outer.Inner inner = outer.new Inner();

想要例項化Inner,我們必須首先建立一個Outer的例項,然後,呼叫Outer例項的new來建立Inner例項

觀察Java編譯器編譯後的.class檔案可以發現,Outer類被編譯為Outer.class,而Inner類被編譯為Outer$Inner.class

Static Nested Class

最後一種內部類和Inner Class類似,但是使用static修飾,稱為靜態內部類(Static Nested Class):

// Static Nested Class
public class Main {
    public static void main(String[] args) {
        Outer.StaticNested sn = new Outer.StaticNested();
        sn.hello();
    }
}

class Outer {
    private static String NAME = "OUTER";

    private String name;

    Outer(String name) {
        this.name = name;
    }

    static class StaticNested {
        void hello() {
            System.out.println("Hello, " + Outer.NAME);
        }
    }
}

static修飾的內部類和Inner Class有很大的不同,它不再依附於Outer的例項,而是一個完全獨立的類,因此無法引用Outer.this,但它可以訪問Outerprivate靜態欄位和靜態方法。如果把StaticNested移到Outer之外,就失去了訪問private的許可權。

classpath

classpath是JVM用到的一個環境變數,它用來指示JVM如何搜尋class

Jar包

將目錄打包

字串和編碼

String是一個引用型別

String s1 = "Hello";

實際上字串在String內部是透過一個char[]陣列表示的,因此,按下面的寫法也是可以的:

String s2 = new String(new char[] {'H', 'e', 'l', 'l', 'o', '!'});

字串比較

比較兩個字串的內容是否相等 要用equals()方法

public class Main {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
    }
}

索引從零開始

搜尋子串的更多的例子:

"Hello".indexOf("l"); // 2
"Hello".lastIndexOf("l"); // 3
"Hello".startsWith("He"); // true
"Hello".endsWith("lo"); // true

提取子串的例子:

"Hello".substring(2); // "llo"
"Hello".substring(2, 4); "ll"

去除首尾空白字元

使用trim()方法可以移除字串首尾空白字元。空白字元包括空格,\t\r\n

"  \tHello\r\n ".trim(); 

使用 isEmpty()isBlank()來判斷字串是否為空和空白字串

替換字串

要在字串中替換子串,有兩種方法。一種是根據字元或字串替換:

String s = "hello";
s.replace('l', 'w'); // "hewwo",所有字元'l'被替換為'w'
s.replace("ll", "~~"); // "he~~o",所有子串"ll"被替換為"~~"

另一種是透過正規表示式替換:

String s = "A,,B;C ,D";
s.replaceAll("[\\,\\;\\s]+", ","); // "A,B,C,D"

image-20241014220739424

格式化字串

字串提供了formatted()方法和format()靜態方法,可以傳入其他引數,替換佔位符,然後生成新的字串:

// String
public class Main {
    public static void main(String[] args) {
        String s = "Hi %s, your score is %d!";
        System.out.println(s.formatted("Alice", 80));
        System.out.println(String.format("Hi %s, your score is %.2f!", "Bob", 59.5));
    }
}

有幾個佔位符,後面就傳入幾個引數。引數型別要和佔位符一致。我們經常用這個方法來格式化資訊。常用的佔位符有:

  • %s:顯示字串;
  • %d:顯示整數;
  • %x:顯示十六進位制整數;
  • %f:顯示浮點數。

型別轉換

使用 valueof

String.valueOf(123); // "123"
String.valueOf(45.67); // "45.67"
String.valueOf(true); // "true"
String.valueOf(new Object()); // 類似java.lang.Object@636be97c

image-20241014221514879

參考連結

相關文章