Java面向對象講解與實例

面向對象

文章目錄

面向過程和麪向對象


面向過程和麪向對象都是軟件分析、設計和開發的一種思想,它指導着人們以不同的方式去分析、設計和開發軟件。

面向過程思想思考問題時,我們首先思考“怎麼按步驟實現?”並將步驟對應成方法,一步一步,最終完成。

這個適合簡單任務,不需要過多協作的情況下。比如,如何開車?

對象的進化史(數據管理和企業管理共同之處)


事物的發展總是遵循“量變引起質變”的哲學原則;企業管理和數據管理、甚至社會管理也有很多共通的地方。

  • 數據無管理時代
    • 例如:初級公司一人身兼多職,但當業務量大時無法管理
  • 數組管理和企業部門制
    • 相同數據放到同一數據中,相當於部門,數組也是對象
  • 對象和企業項目制
    • 對象包含不同類型的變量,還可以有各種方法,相當於獨立公司

對象和類的概念


類可以看做是一個模板,或者圖紙,系統根據類的定義來造出對象。

類:

我們叫做class。

對象:

我們叫做Object,instance(實例)。

以後我們說某個類的對象,某個類的實例。是一樣的意思。

public class Stu{
    /*
    屬性filed,成員變量
    方法
    */
    int id;
    String name;
    int age;
    Computer comp;//電腦
    
    void speak(){
        System.out.println("說話");
    }
    
    void study(){
        System.out.println("使用"+comp.brand);
    }
    /*無參的構造方法 用於創建這個類的對象,無參的構造方法可以由系統自動創建*/
    Stu(){
        
    }
    
    public static void main(String[] args){
        /*實例化對象*/
        Stu stu = new Stu();//創建一個對象 通過構造方法來創建類
        stu.id=1;
        stu.name="junwei";
        Computer c1 = new Computer();
        c1.brand = "ThinkPad";
        stu.comp = c1;
        stu.study();
    }
}

class Computer{
    String brand;//品牌
}

面向對象的內存分析


Java虛擬機的內存可以分爲三個區域:棧stack、堆heap、方法區method area

棧stack的特點:

  1. 棧描述的是方法執行的內存模型。每個方法都被調用都會創建一個棧幀(存儲局部變量、操作數、方法出口等)
  2. JVM爲每一個線程創建一個棧,用於存放該線程執行方法的信息(實際參數、局部變變量等)
  3. 棧屬於線程私有。不能實現線程間的共享
  4. 棧的存儲特性是“先進後出,後進先出”
  5. 棧是由系統自動分配,速度快!棧是一個連續的內存空間

堆heap的特點:

  1. 堆用於存儲創建好的對象和數組(數組也是對象)
  2. JVM只有一個堆,被所有線程共享
  3. 堆是一個連續的內存空間,分配靈活,速度慢

方法區(又叫靜態區)特點:

  1. JVM只有做一個方法區,被所有線程共享

  2. 方法區實際也是堆,只是用於存儲類、常量相關的信息

  3. *用來存放程序中永遠是不變或唯一的內容。(類信息,class對象,靜態變量,字符串常量等)

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-X2WdvRh6-1589329523683)(E:\java ee\筆記\Java SE\images\內存.png)]

構造方法


構造器也叫構造方法(constructor),用於對象的初始化、

要點:

  1. 通過new關鍵字調用
  2. 構造器雖然有返回值,但是不能定義返回值類型(返回值得類型肯定是本類),不能再構造器裏使用return返回某個值
  3. 如果我們沒有定義構造器,則編譯器會自動定義一個無參的構造函數。如果已定義則編譯器不會自動添加。
  4. 構造區的方法名必須和類名一致。

構造方法的重載

構造方法重載和方法的總在要素一樣

  • 構造方法的第一句總是super()
  • this表示創建好的對象

垃圾回收機制(Garbage Collection)


內存管理

  • Java的內存管理很大程度值得就是對象的管理,其中包括對象空間的分配和釋放。
  • 對象空間的分配:使用new關鍵字創建對象即可
  • 對象空間的釋放:將對象賦值null即可。垃圾回收器將負責回收所有“不可達”對象的內存空間

垃圾回收過程

任何一種垃圾回收算法一般都要做兩件基本事情:

  1. 發現無用的對象
  2. 回收無用對象佔用的內存空間

垃圾回收機制保證可以將“無用的對象”進行回收。無用的對象指的就是沒有任何變量引用對象。Java的垃圾回收器通過其相關算法發現無用對象,並進行清除和整理

垃圾回收相關算法

  1. 引用計數法

    堆中每個對象有一個引用計數。被引用一次,計數加1,被引用變量值爲null,則計數減1,值到計數爲0,則表示變成無用對象。優點是算法簡單,缺點是“循環引用的無用對象”無法識別

    public class Student{
        String name;
        Student friend;
        public static void main(String[] args){
            Student s1 = new Student();
            Student s2 = new Student();
            
            s1.friend = s2;
            s2.friend = s1;
            s1 = null;
            s2 = null;
        }
    }
    

    s1和s2互相引用對方,導致他們引用計數不爲0,但是實際已經無用,但無法被識別。

    2.引用可達法(根搜索算法)

    程序把所有的引用關係看做一張圖,從一個節點GC ROOT開始,尋找對應的引用節點,找到這個節點以後,繼續尋找這個節點的引用節點,當然所有的引用節點尋找完畢之後,剩餘的節點則被認爲是沒有被引用的節點,即無用節點。

    通用的分代垃圾回收機制

    我們將對象分爲三種狀態:年輕代、年老代、持久代(存在方法區裏)

    JVM將堆內存劃分爲Eden、Survivor和Tenured/Old空間。

    1. Eden區:存儲了從未通過垃圾回收的新對象
    2. Survivor區:存放垃圾回收後,仍然有用的對象,循環存放,小魚15次垃圾回收次數
    3. Tenured區:年老代區域存放超過15次垃圾回收的對象
  • 新建對象存在在Eden中,當Eden滿了,不能創建新對象,則觸發垃圾回收(GC),將無用的清理掉,然後剩餘對象賦值到Survivor中,以此類推。當old區滿了,則會觸發一個一次完整的垃圾回收
    • Minor GC:用於清理年青代區域。Eden區滿了就會觸發一次Minor GC。清理無用對象,將有用對象賦值到“Suvivor1”、“Suvivor2”區中(這兩個區,大小空間相同,同一時刻Suvivor1和Suvivor2只有一個在用,一個爲空)
    • Major GC:用於清理老年代區
    • Full GC:用於清理年青代、年老代區域。成本較高,會對系統性能產生影響(通長堆垃圾回收機制的優化,是對此進行優化

JVM調優和Full GC

在對JVM調優的過程中,很大一部分工作就是對Full GC的調節。有如下原因可能導致Full GC:

  1. 年老代(Tenured)被寫滿
  2. 持久代(Perm)被寫滿
  3. System.gc()被顯式調用(程序建議GC啓動,不是調用GC 只是建議,並不是調用)
  4. 上一次GC後Heap(堆)的各域分配策略動態變化

開發中容易造成內存泄漏的操作


如下四種情況時最容易造成內存泄漏的場景,開發時一定注意:

  • 創建大量無用對象

    比如,我們在需要大量拼接字符串時,使用了String而不是StringBuilder。

    String str = "";
    for(int i = 0; i < 1000; i++){
        str += i;//相當於產生了1000個String對象
    }
    
  • 靜態集合類的使用

    象HashMap、Vector、List等的使用最容易出現內存泄漏,這些靜態變量的生命週期和應用程序一致,所有的對象Objec也不能被釋放。

  • 各種連接對象(IO流對象、數據庫連接對象,網絡連接對象)未關閉

    IO流對象、數據庫連接對象、網絡連接對象等連接對象屬於物理連接,和硬盤或者網絡連接,不使用的時候一定要關閉。

  • 監聽器的使用

    釋放對象時,沒有刪除相應的監聽器。

要點:
  1. 程序員無權調用垃圾回收器
  2. 程序員可以調用System.gc(),該方法只是通知JVM,並不是運行垃圾回收器。儘量少用,會申請啓動Full GC,成本高,影響系統性能。
  3. finalize方法,是Java提供給程序員用來釋放對象或資源的方法,但是儘量少用。

對象創建的過程和this的本質


  • ##### 創建一個對象分爲如下四步:,1. 分配對象空間,並將對象成員變量初始化爲0或空,2. 執行屬性值的顯示初始化,3. 執行構造方法,4. 返回對象的地址給相關變量

this關鍵字

this的本質就是“創建好的對象的地址”由於在構造方法調用前,對象已經創建。因此,在構造方法中也可以使用this代表“當前對象”。

區分成員變量和局部變量

**this調用構造器 this(a,b,c) 且構造器的調用只能在第一句 **

this不能用於static方法中

static關鍵字

在類中,用static聲明的成員變量爲靜態成員變量,也稱爲類變量。類變量的生命週期和類相同,在整個引用程序執行期間都有效。

static修飾的成員變量和方法,從屬於類。

普通變量和方法從屬於對象。

  • 在類中,用static聲明的成員變量爲靜態成員變量,或者叫做:類屬性,類變量。

  • 它爲該類的公有變量,屬於類,被該類的所有實例共享,在類被載入時被顯式初始化

  • 對於該類的所有對象來說,static成員變量只有一份。被該類的所有對象共享。

  • 可以使用“對象.類屬性”來調用。不過,一般都是用“類名.類屬性”

  • static變量置於方法區中

  • 用static聲明的方法爲靜態方法

    • 不需要對象,就可以調用(類名.方法名)
    • 在調用該方法時,不會將對象的引用傳遞給它,所以在static方法中不可訪問非stati的成員。
    • 靜態方法不能以任何方式引用this和super關鍵字

靜態初始化塊


  • 如果希望加載後,對整個類進行某些初始化操作,可以使用stati初始化塊
  • 類第一次被載入時先執行static代碼塊;類多次被加載時,static代碼塊只執行一次;static經常用來進行static變量的初始化
  • 是在類初始化時執行,不能再創建對象時執行。
  • 靜態初始化塊中不能訪問非static成員。

參數傳值機制

方法中所有參數都是“值傳遞”,也就是“傳遞的是值得副本”,不會影響原件

引用類型參數的傳值

傳遞的是值得副本,但是引用類型指的是“對象的地址”。因此,副本和參數都指向了同一個“地址”,改變“副本指向地址的對象的值,也意味着原參數指向對象的值也發生了改變”

Java包(package)概念


包機制是Java中管理類的重要手段。開發中,我們會遇到大量同名的類,通過包我們很容易對解決類重名的問題,也可以實現對類的有效管理。包對於類,相當於文件夾對於文件的作用。

域名倒置

繼承的實現(extends)


  1. 父類也稱做超類,基類派生類等。
  2. Java中只有單繼承,沒有c++那樣多繼承。多繼承會引起混亂,是得繼承鏈過於複雜,系統按已維護
  3. Java中類沒有多繼承,接口有多實現
  4. 子類繼承父類,可以得到父類的全部屬性和方法(除了父類的構造方法),但不見得可以直接訪問(比如,父類私有的屬性和方法)。
  5. 如果定義一個類時沒有調用extends,則它的父類時:java.lang.Object.

instanceof運算符

instanceof是二元運算符,左邊是對象,右邊是類;當對象是右面類或子類所創建對象時,返回true;否則返回false

方法的重寫override


  1. 方法名、形參列表相同
  2. 返回值類型和聲明異常類型,子類小於等於父類
  3. 訪問權限,子類大於等於父類

Object類


Object類是所有Java類的根基類,也就意味着所有的Java對象都擁有Object類的屬性和方法

toString()方法

將HashCode轉換爲16進制輸出

==和equals方法

  • “==”代表比較雙方是否相同。如果是基本類型則表示值相等,如果是引用類型則表示地址相等即是同一個對象。比較對象是否相同
  • equals 比較內容是否相同
    • Object類中定義有:public boolean equals(Object obj)方法,提供定義“對象內容相等”的邏輯。
    • 比較兩個對象的hashcode值

super


super是直接父類對象的引用。可以通過super來訪問父類中被子類覆蓋的方法或屬性。

繼承樹追溯

構造方法調用順序;

**構造方法第一句總是super(…)**來調用父類對應的構造方法。所以,流程就是:先向上追溯到Object,然後再依次向下執行類的初始化塊和構造方法,直到當前子類爲止。

注:靜態初始化塊調用順序,與構造方法調用順序一樣,不再重複

封裝的作用和含義


“高內聚,低耦合”

高內聚就是類的內部數據操作細節自己完成,不允許外不干涉

低耦合是僅暴露少量的方法給外部使用,儘量方便外部調用

封裝的優點:

  1. 提高代碼安全性
  2. 提高代碼複用性
  3. “高內聚”:封裝細節,便於修改內部代碼,提高可維護性。
  4. “低耦合”:簡化外部調用,便於調用者使用,便於擴展和協作。

封裝的實現——使用訪問控制符

修飾符 同一個類 同一個包中 不同包子類 所有類
private *
default * *
protected * * *
public * * * *
  1. private 表示私有的的,只有自己類能訪問
  2. default 表示沒有修飾符,只有同一個包的類能訪問
  3. protected 表示可以被同一個包的類以及其他包中的子類訪問
  4. public 表示可以被該項目的所有包中的所有類訪問

封裝的使用細節

類的屬性的處理:
  1. 一般使用private訪問權限
  2. 提供相應的get/set方法來訪問相關屬性,這些方法通常是public修飾的,以提供對屬性的賦值與讀取操作(注意:boolean變量的get方法是is開頭)
  3. 一些只用於本類的輔助性方法可以用private修飾符,希望其他類調用的方法用public修飾。

多態(polymorphism)


多態指的是同一個方法調用,由於對象不同可能會有完全不同的行爲。現實生活中,同一個方法,具體實現會完全不同。

多態的要點:

  1. 多態是方法的多態,不是屬性的多態(多態與屬性無關)
  2. 多態的存在要有3個必要條件:繼承、方法重寫、父類引用指向子類對象
  3. 父類引用指向子類對象後,用該類引用調用子類重寫的方法,此時多態就出現了。

對象的轉型(casting)


父類引用指向子類對象對象,我們稱這個過程爲向上轉型,屬於自動類型轉換。

向上轉型後的父類引用變量只能調用它編譯類型的方法,不能調用它運行時類型的方法。這時,我們就需要進行類型的強制轉換,我們稱之爲向下轉型。

final關鍵字


  1. 修飾變量:被修飾的變量不可改變,一旦賦了初值,就不能被重新賦值
  2. 修飾方法:該方法不可被子類重寫。但是可以被重載
  3. 修飾類:修飾的類不能被繼承

數組概述和特點


數組是相同類型數據的有序集合。數組描述的是相同類型的若干個數據,按照一定的先後次序排列組合而成。其中,每一個數據稱作一個元素,每個元素可以通過一個索引(下標)來訪問它們。

數組的三個基本特點:

  1. 長度是確定的。數組一旦被創建,它的大小就是不可以改變的
  2. 其元素必須是相同類型,不允許出現混合類型
  3. 數組類型可以是任何數據類型,包括基本類型和引用類型

數組變量屬引用類型,數組也可以看成是對象,數組中的每個元素相當與該對象的成員變量。

注意事項:
  1. 聲明的時候並沒有實例化任何對象,只有在實例化數組對象時,JVM才分配空間,這時才與長度有關。
  2. 聲明一個數組的時候並沒有數組真正被創建
  3. 構造一個數組,必須制定長度。

抽象方法和抽象類(abstract)


抽象類的使用要點:

  1. 有抽象方法的類只能定義成抽象類
  2. 抽象類不能實例化,即不能用new來實例化抽象類
  3. 抽象類可以包含屬性、方法、構造方法。但是構造方法不能用來new實例,只能用來被子類調用
  4. 抽象類只能用來被繼承
  5. 抽象方法必須被子類實現

接口的作用


定義接口的詳細說明:

  1. 訪問修飾符:只能是public或默認
  2. 接口名:和類名採用相同的命名機制
  3. extends:接口可以多繼承
  4. 常量:接口中的屬性只能是常量,總是:public static final 修飾。不寫也是
  5. 方法:接口中的方法只能是public abstract。省略的話 也是。

要點:

  1. 子類通過implements來實現接口中的規範
  2. 接口不能創建實例,但是可用於聲明引用變量類型
  3. 一個類實現了接口,必須實現接口中所有的方法,並且這些方法之只能是public的。
  4. JDK1.7之前,接口中只能包含靜態常量、抽象方法、不能有普通屬性、構造方法、普通方法
  5. JDK1.8後,接口中包含普通靜態方法

內部類的分類


在Java中內部類主要分爲成員內部類(非靜態內部類、靜態內部類)、匿名內部類、局部內部類

非靜態內部類(外部類裏使用非靜態內部類和平時使用其他類沒什麼不同)

  • 非靜態內部類必須寄存在一個外部類對象裏。因此,如果有一個非靜態內部類對象那麼一定存在對應的外部類對象。非靜態內部類對象單獨屬於外部類的某個對象。
  • 非靜態內部類可以直接訪問外部類的成員,但是外部類不能直接訪問非靜態內部類成員
  • 非靜態內部類不能有靜態方法、靜態屬性和靜態初始化塊
  • 外部類的靜態方法、靜態代碼塊不能訪問非靜態內部類,包括不能使用非靜態內部類定義變量、創建實例
成員變量訪問要點:
  1. 內部類裏方法的局部變量:變量名
  2. 內部類屬性:this.變量名
  3. 外部類屬性:外部類名.this.變量名
package com.junwei.oop;

public class TestInnerClass {
    public static void main(String[] args) {
        Outer outer = new Outer();
        //創建內部類對象
        Outer.Inner inner = new Outer().new Inner();
        inner.show();
    }
}
class Outer{
    private int age = 10;
    public void testOuter(){

    }
    /**內部類*/
    class Inner{
        int age = 30;
        public void show(){
            int age = 20;
            System.out.println("外部類的成員變量age:" + Outer.this.age);
            System.out.println("方法內變量age:" + age);
            System.out.println("內部類的成員變量age:" + this.age);
        }
    }
}

靜態內部類

package com.junwei.oop;

public class TestInnerClass {
    public static void main(String[] args) {
        Outer outer = new Outer();
        //創建內部類對象
        Outer.Inner inner = new Outer().new Inner();
        inner.show();
    }
}
class Outer{
    private int age = 10;
    public void testOuter(){

    }
    /**內部類*/
    class Inner{
        int age = 30;
        public void show(){
            int age = 20;
            System.out.println("外部類的成員變量age:" + Outer.this.age);
            System.out.println("方法內變量age:" + age);
            System.out.println("內部類的成員變量age:" + this.age);
        }
    }
}

匿名內部類

package com.junwei.oop;

/**
 * 匿名內部類
 */
public class TestAnonymousInnerClass {
    public static void main(String[] args) {
        TestAnonymousInnerClass.test(new AA() {
            @Override
            public void aa() {
                System.out.println("你好匿名內部類!");
            }
        });
        TestAnonymousInnerClass.test(()-> System.out.println("Lambda表達式實現匿名內部類!"));
    }
    public static void test(AA a){
        a.aa();
    }
}
interface AA{
    void aa();
}

String基礎


String類和常量池

在java的內存分析中,我們會經常聽到關於“常量池”的描述,實際上常量池也分了以下三種:

全局字符串常量池(String Pool)

全局字符串常量池中存放的內容實在類加載完成後存到String pool中的,在每個JVM中只有一份,存放的是字符串常量的引用值(在堆中生成字符串對象實例)

class文件常量池(Class Constant Pool)

class常量池是在編譯的時候每個class都有的,在編譯階段,存放的是常量(文本字符串、final常量等)和符號引用

運行時常量池(Runtime Constant Pool)

運行時常量池在類加載完成之後,將每個class常量池中的符號引用值轉存到運行時常量池中,也就是說,每個class都有一個運行時常量池,類在解析之後,將符號引用替換成直接引用,與全局常量池中的引用保持一致。

通長比較字符串使用equals

String類常用方法

package com.junwei.oop;

public class TestString {
    public static void main(String[] args) {
        String s1 = " core Java ";
        String s2 = "Core Java";
        //提取下標爲3的字符 從0開始
        System.out.println(s1.charAt(3));
        //字符串的長度 算上空格
        System.out.println(s2.length());
        //比較兩個字符串是否相等
        System.out.println(s1.equals(s2));
        //比較兩個字符串(忽略大小寫)
        System.out.println(s1.equalsIgnoreCase(s2));
        //字符串s1中是否包含Java 返回首字符位置
        System.out.println(s1.indexOf("Java"));

        //將s1中的空格替換成&
        String s = s1.replace(' ','&');
        System.out.println(s);
        //是否以core開頭
        System.out.println(s1.startsWith("core"));
        //是否以Java結尾
        System.out.println(s1.endsWith("Java"));
        //提取字符串:從下標爲4的開始到字符串結尾爲止
        System.out.println(s1.substring(4));
        //提取字符串:下標[4,7)不包括7 前包後不包
        System.out.println(s1.substring(4,7));
        //轉小寫
        System.out.println(s1.toLowerCase());
        //轉大寫
        System.out.println(s1.toUpperCase());
        //去除首位空格
        System.out.println(s1.trim());
    }
}

數組的拷貝


arrayCopy

package com.junwei.array;

import org.jetbrains.annotations.Contract;
import org.junit.Test;

import java.util.Scanner;

public class TestArrayCopy {
    static String[] s1 = {"aa","bb","cc","dd","ee"};
    public static void main(String[] args) {
        String[] s2 = new String[10];
        //arrayCopy數組拷貝方法
        // 要拷貝的數組,從哪開始拷貝,拷貝到哪個數組中,從新數組中的哪個位置開始,要拷貝的長度是多少
        System.arraycopy(s1,2,s2,3,3);
        for (String str : s2
             ) {
            System.out.print(str+"\t");
        }
        System.out.println();
        testDel();
        System.out.println("----------------------");
        while (true) {
            testInsert();
            System.out.println();
            System.out.println("++++++++++++++++++++++++");
        }
    }

    /**刪除字符串指定元素的方法*/
    public static String[] deleteElement(String[] str,int index){
        System.arraycopy(str,index+1,str,index,str.length-index-1);
        str[str.length-1] = null;
        return str;
    }
    /**在數組指定位置插入元素*/
    public static String[] insertElement(String[] strs, int index, String str){
        //如果原數組已滿 進行擴容
        if (isFull(strs)){
            String[] strings = new String[strs.length+strs.length];
            System.arraycopy(strs,0,strings,0,strs.length);
            System.arraycopy(strings,index,strings,index+1,strings.length-index-1);
            strings[index] = str;
            return strings;
        }else {
            System.arraycopy(strs,index,strs,index+1,strs.length-index-1);
            strs[index] = str;
            return strs;
        }
    }

    /**判斷數組是否以滿*/
    @Contract(pure = true)
    public static boolean isFull(String[] strs){
       for (int i = 0; i < strs.length; i++){
           if (strs[i] == null){
               return false;
           }
       }
        return true;
    }
    @Test
    public void test3(){
        String str = null;
        System.out.println(str == null);
    }

    public static void testInsert(){
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入要插入的元素:");
        String str = sc.next();
        System.out.println("請輸入要插入元素的位置:");
        int index = sc.nextInt();
        String[] strings = insertElement(s1, index, str);
        if (strings.length!=s1.length){
            s1 = strings;
        }
        for(String s : strings){
            System.out.print(s+"\t");
        }
    }
    public static void testDel(){
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入要刪除的元素下標");
        int index = sc.nextInt();
        String[] strings = deleteElement(s1, index);
        for(String str : strings){
            System.out.print(str+"\t");
        }
    }

    @Test
    public void test(){
        //需求:將s1字符串cc刪除
        System.arraycopy(s1,3,s1,2,2);
        s1[s1.length-1] = null;
        for(String str : s1){
            System.out.print(str+"\t");
        }
    }
    /**數組的擴容
     * 本質上是:先定義一個更大的數組,然後將原數組內容原封不動的拷貝到新數組中
     * */
    public static void extendRange(){
        String[] s1 = {"aa","bb"};

        String[] s2 = new String[s1.length+10];
        System.arraycopy(s1,0,s2,0,s1.length);
    }
}

Arrays工具類的使用

包含了排序、查找、填充、打印內容等常見操作

package com.junwei.array;

import java.util.Arrays;

public class TestArrays {
    public static void main(String[] args) {
        int[] nums = {2,4,1,3,8,4,5,23,12,31};
        ///輸出
        System.out.println(Arrays.toString(nums));
        //排序
        Arrays.sort(nums);
        System.out.println(Arrays.toString(nums));
        //查找 返回索引位置 如果查不到 返回 -1
        System.out.println(Arrays.binarySearch(nums,3));
    }
}

冒泡排序的基礎算法

package com.junwei.array;

import java.util.Arrays;
/***冒泡排序及優化*/
public class TestBubbleSort {
    public static void main(String[] args) {
        int[] nums = {2,4,1,3,8,4,5,23,12,31};
        int temp = 0;
        for (int j = 0; j < nums.length-1; j++) {
            //定義標誌位
            boolean flag = true;
            for (int i = 0; i < nums.length-1-j; i++) {
                //比較大小,換順序
                if (nums[i]>nums[i+1]){
                    temp = nums[i];
                    nums[i] = nums[i+1];
                    nums[i+1] = temp;
                    flag = false;
                }
                System.out.println(Arrays.toString(nums));
            }
            if (flag){
                System.out.println("結束");
                break;
            }
            System.out.println("---------------");
        }
    }
}

二分法查找(折半查找)

package com.junwei.array;

import java.util.Arrays;

/**
 * 二分法查找
 */
public class TestBinarySearch {
    public static void main(String[] args) {
        int[] nums = {2,4,1,3,8,4,5,23,12,31};
        Arrays.sort(nums);
        System.out.println(Arrays.toString(nums));
        int i = myBinarySearch(nums, 12);
        System.out.println("位置:" + i);
    }
    public static int myBinarySearch(int[] nums, int value){
        int low = 0;
        int high = nums.length;

        while (low <= high){
            int mid = (low + high)/2;

            if (value == nums[mid]){
                return mid;
            }
            if (value > nums[mid]){
                low = mid + 1;
            }
            if (value < nums[mid]){
                high = mid - 1;
            }
        }
        return -1;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章