面向對象
文章目錄
- 面向對象
- 面向過程和麪向對象
- 對象的進化史(數據管理和企業管理共同之處)
- 對象和類的概念
- 面向對象的內存分析
- 構造方法
- 垃圾回收機制(Garbage Collection)
- 開發中容易造成內存泄漏的操作
- 對象創建的過程和this的本質
- static關鍵字
- 靜態初始化塊
- 參數傳值機制
- Java包(package)概念
- 繼承的實現(extends)
- instanceof運算符
- 方法的重寫override
- Object類
- toString()方法
- super
- 封裝的作用和含義
- 多態(polymorphism)
- 對象的轉型(casting)
- final關鍵字
- 數組概述和特點
- 抽象方法和抽象類(abstract)
- 接口的作用
- 內部類的分類
- String基礎
- 數組的拷貝
- 冒泡排序的基礎算法
- 二分法查找(折半查找)
面向過程和麪向對象
面向過程和麪向對象都是軟件分析、設計和開發的一種思想,它指導着人們以不同的方式去分析、設計和開發軟件。
面向過程思想思考問題時,我們首先思考“怎麼按步驟實現?”並將步驟對應成方法,一步一步,最終完成。
這個適合簡單任務,不需要過多協作的情況下。比如,如何開車?
對象的進化史(數據管理和企業管理共同之處)
事物的發展總是遵循“量變引起質變”的哲學原則;企業管理和數據管理、甚至社會管理也有很多共通的地方。
- 數據無管理時代
- 例如:初級公司一人身兼多職,但當業務量大時無法管理
- 數組管理和企業部門制
- 相同數據放到同一數據中,相當於部門,數組也是對象
- 對象和企業項目制
- 對象包含不同類型的變量,還可以有各種方法,相當於獨立公司
對象和類的概念
類可以看做是一個模板,或者圖紙,系統根據類的定義來造出對象。
類:
我們叫做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的特點:
- 棧描述的是方法執行的內存模型。每個方法都被調用都會創建一個棧幀(存儲局部變量、操作數、方法出口等)
- JVM爲每一個線程創建一個棧,用於存放該線程執行方法的信息(實際參數、局部變變量等)
- 棧屬於線程私有。不能實現線程間的共享
- 棧的存儲特性是“先進後出,後進先出”
- 棧是由系統自動分配,速度快!棧是一個連續的內存空間
堆heap的特點:
- 堆用於存儲創建好的對象和數組(數組也是對象)
- JVM只有一個堆,被所有線程共享
- 堆是一個連續的內存空間,分配靈活,速度慢
方法區(又叫靜態區)特點:
-
JVM只有做一個方法區,被所有線程共享
-
方法區實際也是堆,只是用於存儲類、常量相關的信息
-
*用來存放程序中永遠是不變或唯一的內容。(類信息,class對象,靜態變量,字符串常量等)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-X2WdvRh6-1589329523683)(E:\java ee\筆記\Java SE\images\內存.png)]
構造方法
構造器也叫構造方法(constructor),用於對象的初始化、
要點:
- 通過new關鍵字調用
- 構造器雖然有返回值,但是不能定義返回值類型(返回值得類型肯定是本類),不能再構造器裏使用return返回某個值
- 如果我們沒有定義構造器,則編譯器會自動定義一個無參的構造函數。如果已定義則編譯器不會自動添加。
- 構造區的方法名必須和類名一致。
構造方法的重載
構造方法重載和方法的總在要素一樣
- 構造方法的第一句總是super()
- this表示創建好的對象
垃圾回收機制(Garbage Collection)
內存管理
- Java的內存管理很大程度值得就是對象的管理,其中包括對象空間的分配和釋放。
- 對象空間的分配:使用new關鍵字創建對象即可
- 對象空間的釋放:將對象賦值null即可。垃圾回收器將負責回收所有“不可達”對象的內存空間
垃圾回收過程
任何一種垃圾回收算法一般都要做兩件基本事情:
- 發現無用的對象
- 回收無用對象佔用的內存空間
垃圾回收機制保證可以將“無用的對象”進行回收。無用的對象指的就是沒有任何變量引用對象。Java的垃圾回收器通過其相關算法發現無用對象,並進行清除和整理
垃圾回收相關算法
-
引用計數法
堆中每個對象有一個引用計數。被引用一次,計數加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空間。
- Eden區:存儲了從未通過垃圾回收的新對象
- Survivor區:存放垃圾回收後,仍然有用的對象,循環存放,小魚15次垃圾回收次數
- 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:
- 年老代(Tenured)被寫滿
- 持久代(Perm)被寫滿
- System.gc()被顯式調用(程序建議GC啓動,不是調用GC 只是建議,並不是調用)
- 上一次GC後Heap(堆)的各域分配策略動態變化
開發中容易造成內存泄漏的操作
如下四種情況時最容易造成內存泄漏的場景,開發時一定注意:
-
創建大量無用對象
比如,我們在需要大量拼接字符串時,使用了String而不是StringBuilder。
String str = ""; for(int i = 0; i < 1000; i++){ str += i;//相當於產生了1000個String對象 }
-
靜態集合類的使用
象HashMap、Vector、List等的使用最容易出現內存泄漏,這些靜態變量的生命週期和應用程序一致,所有的對象Objec也不能被釋放。
-
各種連接對象(IO流對象、數據庫連接對象,網絡連接對象)未關閉
IO流對象、數據庫連接對象、網絡連接對象等連接對象屬於物理連接,和硬盤或者網絡連接,不使用的時候一定要關閉。
-
監聽器的使用
釋放對象時,沒有刪除相應的監聽器。
要點:
- 程序員無權調用垃圾回收器
- 程序員可以調用System.gc(),該方法只是通知JVM,並不是運行垃圾回收器。儘量少用,會申請啓動Full GC,成本高,影響系統性能。
- finalize方法,是Java提供給程序員用來釋放對象或資源的方法,但是儘量少用。
對象創建的過程和this的本質
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)
- 父類也稱做超類,基類派生類等。
- Java中只有單繼承,沒有c++那樣多繼承。多繼承會引起混亂,是得繼承鏈過於複雜,系統按已維護
- Java中類沒有多繼承,接口有多實現
- 子類繼承父類,可以得到父類的全部屬性和方法(除了父類的構造方法),但不見得可以直接訪問(比如,父類私有的屬性和方法)。
- 如果定義一個類時沒有調用extends,則它的父類時:java.lang.Object.
instanceof運算符
instanceof是二元運算符,左邊是對象,右邊是類;當對象是右面類或子類所創建對象時,返回true;否則返回false
方法的重寫override
- 方法名、形參列表相同
- 返回值類型和聲明異常類型,子類小於等於父類
- 訪問權限,子類大於等於父類
Object類
Object類是所有Java類的根基類,也就意味着所有的Java對象都擁有Object類的屬性和方法
toString()方法
將HashCode轉換爲16進制輸出
==和equals方法
- “==”代表比較雙方是否相同。如果是基本類型則表示值相等,如果是引用類型則表示地址相等即是同一個對象。比較對象是否相同
- equals 比較內容是否相同
- Object類中定義有:public boolean equals(Object obj)方法,提供定義“對象內容相等”的邏輯。
- 比較兩個對象的hashcode值
super
super是直接父類對象的引用。可以通過super來訪問父類中被子類覆蓋的方法或屬性。
繼承樹追溯
構造方法調用順序;
**構造方法第一句總是super(…)**來調用父類對應的構造方法。所以,流程就是:先向上追溯到Object,然後再依次向下執行類的初始化塊和構造方法,直到當前子類爲止。
注:靜態初始化塊調用順序,與構造方法調用順序一樣,不再重複
封裝的作用和含義
“高內聚,低耦合”
高內聚就是類的內部數據操作細節自己完成,不允許外不干涉
低耦合是僅暴露少量的方法給外部使用,儘量方便外部調用
封裝的優點:
- 提高代碼安全性
- 提高代碼複用性
- “高內聚”:封裝細節,便於修改內部代碼,提高可維護性。
- “低耦合”:簡化外部調用,便於調用者使用,便於擴展和協作。
封裝的實現——使用訪問控制符
修飾符 | 同一個類 | 同一個包中 | 不同包子類 | 所有類 |
---|---|---|---|---|
private | * | |||
default | * | * | ||
protected | * | * | * | |
public | * | * | * | * |
- private 表示私有的的,只有自己類能訪問
- default 表示沒有修飾符,只有同一個包的類能訪問
- protected 表示可以被同一個包的類以及其他包中的子類訪問
- public 表示可以被該項目的所有包中的所有類訪問
封裝的使用細節
類的屬性的處理:
- 一般使用private訪問權限
- 提供相應的get/set方法來訪問相關屬性,這些方法通常是public修飾的,以提供對屬性的賦值與讀取操作(注意:boolean變量的get方法是is開頭)
- 一些只用於本類的輔助性方法可以用private修飾符,希望其他類調用的方法用public修飾。
多態(polymorphism)
多態指的是同一個方法調用,由於對象不同可能會有完全不同的行爲。現實生活中,同一個方法,具體實現會完全不同。
多態的要點:
- 多態是方法的多態,不是屬性的多態(多態與屬性無關)
- 多態的存在要有3個必要條件:繼承、方法重寫、父類引用指向子類對象
- 父類引用指向子類對象後,用該類引用調用子類重寫的方法,此時多態就出現了。
對象的轉型(casting)
父類引用指向子類對象對象,我們稱這個過程爲向上轉型,屬於自動類型轉換。
向上轉型後的父類引用變量只能調用它編譯類型的方法,不能調用它運行時類型的方法。這時,我們就需要進行類型的強制轉換,我們稱之爲向下轉型。
final關鍵字
- 修飾變量:被修飾的變量不可改變,一旦賦了初值,就不能被重新賦值
- 修飾方法:該方法不可被子類重寫。但是可以被重載
- 修飾類:修飾的類不能被繼承
數組概述和特點
數組是相同類型數據的有序集合。數組描述的是相同類型的若干個數據,按照一定的先後次序排列組合而成。其中,每一個數據稱作一個元素,每個元素可以通過一個索引(下標)來訪問它們。
數組的三個基本特點:
- 長度是確定的。數組一旦被創建,它的大小就是不可以改變的
- 其元素必須是相同類型,不允許出現混合類型
- 數組類型可以是任何數據類型,包括基本類型和引用類型
數組變量屬引用類型,數組也可以看成是對象,數組中的每個元素相當與該對象的成員變量。
注意事項:
- 聲明的時候並沒有實例化任何對象,只有在實例化數組對象時,JVM才分配空間,這時才與長度有關。
- 聲明一個數組的時候並沒有數組真正被創建
- 構造一個數組,必須制定長度。
抽象方法和抽象類(abstract)
抽象類的使用要點:
- 有抽象方法的類只能定義成抽象類
- 抽象類不能實例化,即不能用new來實例化抽象類
- 抽象類可以包含屬性、方法、構造方法。但是構造方法不能用來new實例,只能用來被子類調用
- 抽象類只能用來被繼承
- 抽象方法必須被子類實現
接口的作用
定義接口的詳細說明:
- 訪問修飾符:只能是public或默認
- 接口名:和類名採用相同的命名機制
- extends:接口可以多繼承
- 常量:接口中的屬性只能是常量,總是:public static final 修飾。不寫也是
- 方法:接口中的方法只能是public abstract。省略的話 也是。
要點:
- 子類通過implements來實現接口中的規範
- 接口不能創建實例,但是可用於聲明引用變量類型
- 一個類實現了接口,必須實現接口中所有的方法,並且這些方法之只能是public的。
- JDK1.7之前,接口中只能包含靜態常量、抽象方法、不能有普通屬性、構造方法、普通方法
- JDK1.8後,接口中包含普通靜態方法
內部類的分類
在Java中內部類主要分爲成員內部類(非靜態內部類、靜態內部類)、匿名內部類、局部內部類
非靜態內部類(外部類裏使用非靜態內部類和平時使用其他類沒什麼不同)
- 非靜態內部類必須寄存在一個外部類對象裏。因此,如果有一個非靜態內部類對象那麼一定存在對應的外部類對象。非靜態內部類對象單獨屬於外部類的某個對象。
- 非靜態內部類可以直接訪問外部類的成員,但是外部類不能直接訪問非靜態內部類成員
- 非靜態內部類不能有靜態方法、靜態屬性和靜態初始化塊
- 外部類的靜態方法、靜態代碼塊不能訪問非靜態內部類,包括不能使用非靜態內部類定義變量、創建實例
成員變量訪問要點:
- 內部類裏方法的局部變量:變量名
- 內部類屬性:this.變量名
- 外部類屬性:外部類名.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;
}
}