1. 程式人生 > 實用技巧 >Java基礎知識回顧(陣列,函式,遞迴,物件,匿名內部類,介面,泛型)

Java基礎知識回顧(陣列,函式,遞迴,物件,匿名內部類,介面,泛型)

”雖然我走得很慢,但我從不後退!“你好我是夢陽辰,快和我一起打卡學吧!

文章目錄

01.陣列

1.為什麼要陣列?
如果沒有陣列,當儲存很多資料時需要設定很多變數來儲存,造成變數名過多,使得變成變得複雜。

如果有了陣列,可以讓相同型別的資料有序的儲存起來,使程式設計變得簡單起來。

2.當要求輸出集合2中,跟集合1不同的資料時,我們該如何去解決呢?
我們知道,找到相同資料是很簡單的,我們可以從這一點出發,設定標記,當遇到跟集合1相同的資料時,修改標記的值,並且跳出迴圈。再根據標記輸出值。

for(int i:arrays1){
	boolean flag = false;//不相同
	for(int j:arrays2){
		if(i==j){
		flag = true;
		break;
	}
	if(!flag){
		System.out.print(j);
	}
}
	

如果採用以下方法則顯得笨拙。

for(int i=0;i<N;i++){
            System.out.print(arrays1[i]+" ");
            for(int j=0;j<N;j++){
                if(arrays2[i]==arrays1[j]){//如果找到相同的值,直接跳過該值
                    break;
                }
                else if(arrays2[i]!=arrays1[j]&&j==N-1){
                    System.out.print(arrays2[i]+" ");
                }
            }

02.函式

1.函式的本質:
狹義:解決特定功能的一段程式碼。

廣義的理解:函式是一個資訊(或物品)加工的封閉的盒子。

2.命名規則
見名知意
變數的命名規則。

3.傳遞引數原則
最少原則
輸入性/輸出型引數。

4.返回結果
需要返回多個結果怎麼辦。

1.一個值代表多個含義(哥德堡猜想)。
2.封裝成結構體或物件。
3.通過輸出型引數返回。(引用)。

03.遞迴

(1)將n階問題降階為n-1階問題。
(2)遞迴出口,初始條件。
(3)找到n階和n-1階的關係。

04.面向物件

1.物件:萬物皆物件,物件是由靜態的屬性和動態的方法組成。
2.類:一組具有相同屬性和行為物件的抽象事物。

例如:
3.訊息:向某個物件傳送請求。(手機來電)
4.方法:物件對收到請求的響應。(如:收到來電震動)

1.面向物件的基本特徵

**抽象:**從一個具體的物件中提取一組資料,去除非本質和特性的東西,保留本質的,共性的。

**封裝:**給物件一個邊界,將內部資訊隱藏,只保留對外的介面。比如遙控器,滑鼠。

**繼承:**允許後代直接使用前輩直接擁有的。繼承是一種程式碼重用的方式,使程式碼更省略,更可靠。

2.類和物件的定義和方法

2.1類的定義:
Class 類名{
資料成員:-靜態屬性
成員函式: -動態行為
}

2.2物件的定義:
類名 物件名

this表示當前物件的引用!

2.3對於物體的抽象需要合理:

如定義三角形的類。
其屬性應該是三個點,而非三條邊來確定三角形。

2.4拷貝建構函式:
用已有的物件去建立一個相同的物件。

 Circle c1 = new Circle();
 Circle c2 = new Circle(c1);//用c1複製另一個物件。

//拷貝建構函式
public Circle( Circle c1){
	this.p=c1.p;//p為引用型別,p為Point類的物件的引用,儲存的是地址。
	this.r=c1.r;
}

淺度拷貝:
上面那個例子,p為引用,將c1的引用地址賦值給新的物件c2,這會導致c1的p對應的物件發生改變,導致c2的p發生改變。

深度拷貝:
c1變化後c2不會發生改變。

2.5靜態
靜態成員修飾的成員與一般的成員有何區別呢?
一般的成員是每個物件有一份資料,而靜態成員是屬於類的,即所有物件所共享的。

一般成員的訪問方式:物件名.成員名,而靜態成員的訪問方式:類名.成員名。

靜態常量,靜態成員變數,靜態成員方法,靜態程式碼塊

靜態變數一直存在,值不會動態的改變。

一般的成員都是通過建構函式去完成初始化(例項化物件時),而靜態成員則是在載入類的時候(也就是例項化之前)初始化。

靜態方法沒有this

靜態方法只能訪問靜態成員。

靜態程式碼塊在類載入的時候執行。

05.內部類和匿名內部類

1.內部類的作用?
內部類可以訪問定義這個類的作用域中的私有屬性。

內部類可以對其同包中的其它類隱藏。

內部類可以簡潔的實現回撥,不過現在lambda表示式在這方面做得很好。

內部類是指在一個類的內部定義的類

內部類可以自由訪問外部類的所有成員

內部類可以作為成員類(在外部類中定義,和成員方法平行)和方法內部類(定義在外部類的成員方法裡面)。

2.內部類的例項化:
Computer.Cpu cpu=new Computer().new Cpu();
System.out.println(cpu.getY());
當一個類離開另一個類而無法單獨存在或者說沒有意義的情況下,使用內部類是最合適的(如:CPU離開計算機類,單獨存在就沒有意義了)

3.匿名內部類
解決只用一次某個類的物件,使程式碼簡潔的問題。只想建立某個類的一個物件,不需要為類指定名字。

public class InnerClass {
    /**
     * 動物介面
     */
    public interface Animal{
        public void eat();
        public void shot();
    }

    /**
     * 車類
     */
     public class Vehicle{
       
    }

    public static void main(String[] args) {
        /**
         * 匿名內部類
         */
        Animal dog = new Animal() {
            @Override
            public void eat() {
                System.out.println("吃狗糧!");
            }

            @Override
            public void shot() {
                System.out.println("汪汪汪");
            }
        };
        dog.eat();
        dog.shot();

        //內部類
       InnerClass.Vehicle car = new InnerClass().new Vehicle();
        
    }
}

06多型

多型:多型是同一個行為具有多個不同表現形式或形態的能力。

多型的意義:
(1)解決多種型別資料存放在同一容器問題。

(2)解決不同子類傳遞到同一個方法時,形參型別不同導致需要建立多個方法的問題。
而用形參設為父類,即可解決這個問題。

多型基於繼承。

07.設定標記

設定標記,有時程式設計可以達到很好的效果。
下面為設計了exit標記來退出while迴圈。

 exit: while(true){//exit為標記
            System.out.println("請輸入操作:");
            String s1 = scan.next();
            switch (s1){
                case "q":break exit;
                case "w":p1.move(0,1);break;//上移
                case "a":p1.move(-1,0);break;//左移
                case "s":p1.move(0,-1);break;//下移
                case "d":p1.move(1,0);break;//右移
            }
            p1.print();
        }

08.double資料型別比較大小

doulbe型別的資料比較大小不能用雙等號。因為計算機的位數問題,double型資料又是不會那麼精確,只是會無限接近於一個數。
而應該使用:Double的compare方法比較兩個資料。

Double.compare(num1,num2)==0
Double.compare(num1,num2)>0
Double.compare(num1,num2)<0

09.抽象類和介面

1.抽象類規定了方法的名字和引數,雖無法建立物件,但是其具有上層規劃的作用,其子類必須按要求實現其方法。

2.介面:屬性為常量,方法為抽象方法。使用介面同樣起到了統一規劃的目的,便於使用和維護。

10.泛型

**泛型:**把型別明確的工作推遲到建立物件或呼叫方法的時候才去明確的特殊的型別。

1.泛型的作用:

定義類或方法的時候不確定其型別,在使用的時候需要確定型別。解決了傳型別問題。

泛型在集合中的作用:因為集合可以儲存任何資料型別,在取出的時候,需要將其強制轉換。而使用泛型規定了集合儲存的型別,獲取時不需要強制型別轉換,可讀性和穩定性增強。

2.型別引數:

1.將型別當作引數一樣傳遞。

2.用法:<資料型別> 只能為引用資料型別。

ArrayList中的E稱為型別引數變數。

ArrayList中的Integer稱為實際型別引數

整個稱為泛型型別。

3.泛型類

將泛型定義到類上,使用者使用該類的時候,才把型別明確下來。這樣就解決類強制型別轉換的問題,避免了強制型別轉換出錯。
例子:

//佇列類:
public class Queue<T>{//泛型類,使用者在使用該類的時候才把型別確定下來
    private T[] data;//存放資料的區域
    private int capacity;//容量
    private int head;//頭指標
    private int rear;//尾指標
    private int size;//實際資料個數
    private T result;//出隊的值

    public Queue(int capacity) {
        this.capacity = capacity;
        data =(T[]) new Object[capacity];
        head = 0;
        rear = 0;
        size = 0;
    }

    /**
     * 資料入隊
     * @param d 入隊的資料
     * @return 入隊是否成功
     */
    public boolean push(T d){
        if(size == capacity){
            return false;
        }
        data[rear]=d;
        rear = (rear+1)%capacity;//尾指標後移,並且可以迴圈回來
        size++;
        return true;
    }

    /**
     * 資料出隊
     * @return 出隊是否成功
     */
    public boolean pop(){
        if(size==0){
            return false;
        }
        this.result = this.data[head];
        head = (head+1)%capacity;
        size--;
        return true;
    }

    public T[] getData() {
        return data;
    }

    public void setData(T[] data) {
        this.data = data;
    }

    public int getCapacity() {
        return capacity;
    }

    public void setCapacity(int capacity) {
        this.capacity = capacity;
    }

    public int getHead() {
        return head;
    }

    public void setHead(int head) {
        this.head = head;
    }

    public int getRear() {
        return rear;
    }

    public void setRear(int rear) {
        this.rear = rear;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public T getResult() {
        return result;
    }

    public void setResult(T result) {
        this.result = result;
    }
}

//測試類:
public class Test03{
    public static void main(String[] args) {
        Queue queue = new Queue(5);//objectl型別
        queue.push(2.2);
        queue.push(2);

        Queue<Integer> queue1 = new Queue<>(5);//泛型中的型別需為引用型別
        queue1.push(3);
        queue1.push(4);

        if(queue.pop()){
            System.out.println(queue.getResult());
        }
        if(queue1.pop()){
            System.out.println(queue1.getResult());
        }
    }
}

4.泛型方法

如果只想在某個方法上使用泛型,即使用者只關心該方法,如果在類上定義就顯得大材小用了。

public <T> void print(T t){
System.out.println(t);
}

//呼叫方法,傳入的引數是什麼型別,返回值就是什麼型別。
物件.print("adf");
物件.print(123);
物件.print(2.22);

5.泛型類的子類

1.當子類明確了泛型類的型別引數變數

public interface Animal<T>{
	void shot(T,t);
}

pulic class dog implements Animal<String>{
	@Override
	public void shot(String s){
	System.out.println(s);
	}
}

2.當子類未明確泛型類的型別引數變數

public interface Animal<T>{
	void shot(T,t);
}

pulic class cat<T> implements Animal<T>{
	@Override
	public void shot(T s){
	System.out.println(s);
	}
}

測試:

public static void main(String[] args){
	//第一種情況
	Animal<String> i = new dog();
	i.shot("旺旺");
	//第二種情況
	Animal<String> i1 = new cat()<>;
	i1.shot("喵喵");
}

6.型別萬用字元


public void print(List list){


    for(int i=0;i<list.size();i++){
        
        System.out.println(list.get(i));
    
    }
}

當我們在遍歷集合的時候,不知道集合中元素的型別,因為集合中的型別可以任意。直接遍歷雖然可以實現,但是會出現警告。如何解決這個問題。如果我們知道每個元素的型別,我們可以一個個的強制轉換,但是我們不清楚,這時我們可以使用萬用字元”?“解決這個問題。

public void print(List<?> list){


    for(int i=0;i<list.size();i++){
        
        System.out.println(list.get(i));
    
    }
}

**注意:**因為我們不知道元素的型別,所以我們不可以用物件含有型別的方法。
如:上面的例子我們不能使用list.add()方法。

7.萬用字元和泛型方法


    //使用萬用字元
    public static void print(List<?> list) {

    }

    //使用泛型方法
    public <T> void  print(List<T> t) {
        
    }

在使用上面這兩個方法都是可以的解決上訴問題。
使用原則:

返回值是與引數之間有依賴關係的使用泛型方法。

如果沒有依賴關係的,就使用萬用字元。

8.萬用字元上下限

1.萬用字元上限

List<? extends Number>

List集合只能是Number的子類或自身。

2.萬用字元下限

 <? super Type>

只能是Type的父類或自身。

泛型PECS原則總結

如果要從集合中讀取型別T的資料,並且不能寫入,可以使用 ? extends 萬用字元;(Producer Extends)

如果要從集合中寫入型別T的資料,並且不需要讀取,可以使用 ? super 萬用字元;(Consumer Super)

如果既要存又要取,那麼就不要使用任何萬用字元。

埋怨只是一種懦弱的表現;努力,才是人生的態度。不安於現狀,不甘於平庸,就可能在勇於進取的奮鬥中奏響人生壯美的樂間。