Java面向對象編程(淺)


java面向對象編程

面向對象的基本特征

面向對象的基本特征包括:抽象、封裝、繼承、多態,這三大特征后面細寫
抽象(個人理解):將一個具體的事物,根據他的特征和行為,將它抽離成一個不具體的一種概念,一種很大的東西,一種分類,就好比人 根據把它的特征抽離成哺乳動物,一說哺乳動物你並不知道這是一個什么東西,它具體是誰,是哪種動物,你可以通過哺乳動物知道人符合條件,老鼠也符合條件,這里面人和老鼠其實都是哺乳動物的一種具體實例。
沒寫太清除,看看再描述一遍老師寫的筆記:讓事物脫離具體化,只將它的類型、屬性和行為抽離出來形成一個類,例如針對貓、狗、牛、羊,根據它們的共同特征和共同行為,可以把它們抽象出一個動物類,這個從現實中的物體到程序的類設計就是一個抽象的過程,動物類本身就是泛指,它不指具體的某一種動物,這就是脫離具體化的體現。

  1. 構造函數
    用途:在實例化的時候調用,常常用來初始化對象,給對象的屬性賦初始值
    書寫規則:訪問修飾符 類名([形參]){
    //內容
    }
    類里面其實有一個默認的無參構造函數,當你沒寫構造函數的時候會默認使用它!但是當你自己寫了構造函數時,這個構造函數就會消失。所以當你寫了有參構造函數的時候,在實例化時就要傳入參數(因為沒有無參的構造函數)這是你要是不需要傳入參數的話,你可以加上無參的構造函數,這里就涉及到了方法的重載
    重載:在同類中不同的方法使用相同的方法名(同類中一種多態性的表現)(同名,不同參:包括順序不一樣,數量不一樣,類型不一樣,返回值可以不同,訪問修飾符也可以不一樣)

  2. static(靜態的)關鍵字: 當你使用static修飾方法或者屬性時,你可以把該方法或者屬性理解為類的專屬的方法和屬性,它不再是某個具體的對象的方法和屬性,它是所有對象所共有的,因為它是"類的屬性和方法",既然如此,那你也可以不用實例化對象,直接使用類名來使用static修飾的屬性或者方法

    注意事項:

    1. 靜態變量只能寫在方法外面,不能寫在方法體中
    2. 靜態方法中不能使用this調用其他的非靜態方法或者非靜態屬性。因為就像我剛才所說,靜態方法的是屬於類中的,而非對象,不用實例化就可以使用,但是this指向當前對象。。。。。不知道怎么說,反正就是this指向的問題。
  3. static修飾的代碼塊:

    static{
    內容
    }

    寫在方法外邊的代碼塊,在類加載時執行該代碼塊且僅僅執行一次(比構造函數早,構造函數在實例化時才執行)

    用途:常用來做初始化操作

  4. 快捷鍵操作

    1. Eclipse中的生成構造函數的快捷鍵:Shift+Alt+S鍵+O鍵
    2. Idea中的快捷鍵:Alt+insert

封裝

概念:隱藏內部實現細節,對外提供接口

  1. 意義:

    1. 避免非法數據(可以對setter方法進行流程控制)使數據更加安全。
    2. 增加代碼的重用性
  2. 封裝是如何實現的:

    1. 改變修飾符,所以修飾符的種類有哪些呢(將public改為private 或者 protected
      • public(公有的)
      • private(私有的)
      • protected(受保護的)
      • friendly(默認)
        封裝的原理就涉及到了一個訪問權限的問題
        訪問權限:public>protected>friendly>private
    訪問范圍 public protected private friendly
    同一個類
    同一包中的其他類 ×
    不同包中的子類 × ×
    不同包中的非子類 x × ×
    1. 設置get/set方法(根據需求 對它加入條件判讀)(這個get&set方法就是對外提供的接口)

繼承

一、繼承

  1. 概念:繼承是類與類之間的關系,被繼承的那一方,可以使用基類的方法和屬性,Java中只能單繼承(即一個子類只能繼承自一個父類)繼承要滿足 is-a的關系,例如:熊貓是一只哺乳動物;那么熊貓不僅有哺乳動物的特性還有一些特有的屬性和行為;假如有多個類,它們有很多類似的地方,那我們就可以將這些共性抽離成一個父類,然后再讓他們繼承這個父類;

  2. 語法,如下面代碼所示,在需要繼承的類后面加extends關鍵字再在關鍵字后面加入需要繼承的類名

package cn.Sukura.www;
class Animals{
public String name;
public Animals(String name) {
  this.name = name;
}
public void sayHi() {
  System.out.printf("My name is %s\n",this.name);
}
}
class Pandas extends Animals{
public Pandas(String name) {
  //super()必須寫在第一行
  super(name);
}
}
public class Test {
   public static void main(String[] args) {
       Pandas p = new Pandas("榮榮");
       p.sayHi();
   }
}
  1. 哪些不能被繼承
  • final(最終的)修飾的類
  • 不能繼承父類的構造方法
  • 不能繼承被private修飾的方法或屬性
  • 不能繼承在不同包下的父類中使用默認修飾符friendly的修飾的屬性和方法(上面那條和這條其實就是設計一個訪問權限的問題)
  1. super關鍵字

    super()調用父類的構造方法,其實this的使用是一樣的,只不過super是調用關於父類的一切,super.Method()調用父類方法,super.attribute調用父類屬性,在子類構造中調用super()時,super()必須寫在第一行,不然不能通過編譯

  2. 實例化子類對象的執行過程:

    父類的靜態成員,靜態代碼塊 --> 子類的靜態成員,靜態代碼塊 -->父類屬性 -->父類構造 -->子類屬性 -->子類構造 -->實例化完成

二、重寫

  1. 概念:是指子類繼承自父類,寫一個和父類中方法名和參數相同的方法,子類中的該方法會覆蓋父類的方法。(發生在繼承當中)

  2. 好處,可以子類根據不同的需要來實現不同的行為,父類只用來提供一個模板

  3. 注意事項:

    • 繼承是重寫的大前提,沒有繼承就沒有重寫

    • 方法名和參數列表完全一致才叫做重寫

    • 子類方法的訪問修飾符必須大於或者等於父類方法的訪問修飾符

  • 子類方法的返回值必須與父類的返回值相關(返回基本數據類型時子類必須與父類完全一樣,返回引用數據類型時,子類的返回值類型與父類的返回值類型相同,或是父類的返回值類型的子類)
  1. 注解:以@開頭的稱為注解,@Override是重寫的注解,表示該方法是重寫方法,如果該方法不滿足重寫規則,使用該注解時就會報錯。

三、抽象類

  1. 什么是抽象類:使用abstract修飾類是抽象類,語法如下:

    public abstract class 類名{
        public void sayHi(){
            //這是一個正經的方法
        }
        public abstract void sayLove();//這是一個抽象方法
    }
    
  2. 注意事項:

    • 抽象類不能被實例化,它主要的目的就是為了給子類做模板的!
    • abstract關鍵字不能和finalstatic一起出現(他們有沖突)
    • abstract修飾的方法是抽象方法,它沒有方法體,抽象方法必須被子類實現,除非子類也是一個抽象類
    • 抽象方法必須寫在抽象類中,但抽象類不止有抽象方法
  3. abstract關鍵字 和 final關鍵字的異同

    • abstract可以修飾方法和類 ** final可以修飾方法屬性**
      • abstract修飾類時 該類不能被實例化,但是可以被子類繼承(設計出來就是用來繼承的)
      • final修飾類時 該類為最終類,不能被繼承
      • abstract修飾方法時 該方法必須被子類實現除非子類也是一個抽象類,該方法不能有方法體!
      • final修飾方法時為最終方法,不能被重寫
      • final修飾屬性時,表示常量,必須賦初始值,並且一旦賦值就不能在修改

多態

接口

  1. 接口的概念:Java中的接口是一個全部由抽象方法組成的集合,使用interface關鍵字來聲明一個接口,接口里面只能有抽象方法和常量,實際上,它就是提供了一種規范,表示一種能力,增強了對於事物的擴展

  2. 對於面向接口編程的理解: 要盡可能的使代碼更加簡介,復用性更高,我們就可以考慮,我們需要的是什么,我們需要知道它是什么嗎?還是只需要知道它能做什么。可能我沒說明白,還是寫一段代碼看看吧

    //首先根據業務需要 老師要教小朋友說普通話 
    class Teacher{
        public void teachToTalk(){
            //方法
        }
    }
    class Kids{
        String name;
        public void listenForClass{
            //假裝里面有代碼
        }
        public void readBookLoudly{
            //假裝里面有代碼
        }
    }
    //這時業務很簡單,很容易就實現了
    
    //后來業務升級  老師的服務對象不僅僅只是小孩了 還有其他類型的學生 這時就會比較繁瑣了,這時我們可以把他們的共性抽離出來寫一個抽象類 也可以實現
    class abstract Person{
        String name;
        public abstract void listenForClass();
        public abstract void readBookLoudly();
    }
    class Kids extends Person{
        public void listenForClass{
            //假裝里面有代碼
        }
        public void readBookLoudly{
            //假裝里面有代碼
        }
    }
    class Adults extends Person{
        public void listenForClass{
            //假裝里面有代碼
        }
        public void readBookLoudly{
            //假裝里面有代碼
        }
    }
    class Teacher{
        public void teachToTalk(){
            //方法
        }
    }
    
    //現在你會發現只要服務對象是人都可以解決 業務繼續升級  這時老師又需要服務動物 但是動物的技能和前面的不匹配了 而且也不可能實現多種動物,這時你會想到你關注的到底是什么,是他們是誰?還是他們能做什么?
    public interface ListenAndRead{
        public void listen();
        public void recite();
    }
    abstract class Person implements ListenAndRead{
    }
    class Child extends Person{//兒童
        public void listen(){}//聽課
        public void recite(){}//朗讀
    }
    class Student extends Person{
        public void listen(){}//聽課
        public void recite(){}//朗讀
    }
    class Foreigner extends Person{
        public void listen(){}
        public void recite(){}
    }
    class Parrot implements ListenAndRead{//鸚鵡
        public void listen(){}
        public void recite(){}
    }
    class Teacher{
        public void teach(ListenAndReciteAble lar){}
    }
    

    引用: 要讓一個依賴方達到最大的兼容性或擴展性,就要讓依賴的對象類型盡量寬泛,當然(為什么不用Object)Object是最寬泛的,但是這就不明確了,而且不能保證依賴方的需要。這是就要跳出一些定式,我需要什么的是什么?還是我需要的是他們會什么?這就變成了面向接口編程。

  3. 接口的語法

    定義接口:

    訪問修飾符 interface關鍵字 接口的名字{
        
    }
    例如:
    public interface Call{
        void CallByWechat();
    }
    

    實現接口:

    • 父類和子類的關系叫做繼承
    • 接口與實現類的關系叫做實現
    • 使用implements關鍵字來實現接口,可以實現很多接口(實現多繼承)
    class Phone implements Call,Play{
        public void CallByWechat(){
            //實現
        }
    }
    
  4. 接口的特點

    • 不能被實例化

    • 接口中的方法都是抽象方法訪問修飾符默認為public 且必須是public

    • 接口可以有屬性,但他們只能是公有的靜態常量(public static final)寫於不寫都如此

    • 實現類必須重寫父接口的所有方法

    • 接口可以繼承接口

  5. 接口與抽象類的異同點

接口 抽象類
不能被實例化
可以包含抽象方法
可以包含靜態常量
使用interface關鍵字聲明 使用abstract修飾的類
沒有構造方法 有構造方法
不能包含非抽象方法,且所有方法必須是public的,只能包含public的靜態常量。 可以包含非抽象方法並且可以是非public的,可以包含非public的普通變量。
滿足 has-a的關系 表示某有某一種能力 表示什么可以做什么。 滿足 is-a的關系 比如哈士奇是一條狗 這里就是繼承關系

異常

  1. 概念: 程序在運行中出現預料之外的錯誤

  2. 在Java中一般產生異常的情況有以下三種:

    • Java內部發生錯誤產生異常,Java虛擬機產生的異常
    • 編寫代碼錯誤產生的異常,如空指針異常,數組越界等異常,這種異常稱為未檢查異常
    • 通過throw語句手動拋出的異常
  3. 異常的類型

    graph TD A(Throwable)-->B1(Error錯誤) A -->B2(Exception異常) B2 -->C1(運行時異常即非檢查異常) B2 -->C2(非運行時異常即檢查異常)

運行時異常:都是RuntimeException 類及其子類異常,例如空指針異常、數組越界異常等,這些異常是不檢查異常,程序可以選擇捕獲處理,或者不處理,這些異常一般都是程序的邏輯引起的

檢查異常:指運行時異常以外的類型,在類型上都屬於Exception及其子類,該類異常必須處理,如果不處理就無法編譯通過,常見的有IOExceptionClassNotFoundException 等還有用戶自己拋出的異常,如果你不處理的話肯定是會報紅的對不對

  1. 常見的異常

    異常類型 說明
    Exception 異常類,它是所有異常類的頂級父類。
    RuntimeException 運行時異常
    ArithmeticException 除0異常,除數不能為0
    ArrayIndexOutOfBoundsException 數組下標越界
    NullPointerExceptio 空指針異常
    ClassNotFoundException 不能加載所需要的類
    ClassCastException 對象強制類型轉換錯誤
  2. 處理的方式,如下代碼演示

    捕獲處理方式

    try{    //可能出現異常的代碼塊}catch(異常類型 對象名字){    //出現異常時處理方式}catch(異常類型 對象名字){    //出現異常時處理方式}finally{    //最后執行這個 無論如何都會執行 除非System.exit()}
    

    捕獲異常代碼一般根據異常類型從小到大捕獲 因為程序出現異常時只會進入第一個符合條件的代碼塊中

    還可以通過拋出的方式處理異常

    //將異常往外拋出,不再用本類中的try-catch來處理,讓調用該方法的那一方來處理public class Test {    //throws 往外拋出異常  throw 人為制造一個異常	public void playing() throws Exception {//在方法名的小括號后面、大括號前面加上 throws 異常類名1,異常類名2		throw new Exception("作業沒寫完,還想玩?");	}	public static void main(String[] args) {		Test t = new Test();		try {			t.playing();		} catch (Exception e) {			e.printStackTrace();		}	}}
    
    1. finally、finalize、final的區別
    finally finalize final的區別
    修飾類時,此類不能被繼承,修飾方法時,該方法不能被重寫,修飾屬性時,屬性的值不能被更改而且一定要賦值 java中的垃圾回收方法,可以清理內存未使用的對象該方法不需要調用,因為java會自動檢測並清理內存,簡稱為GC 異常處理的一部分 表示一定執行 除非遇到上面講的那個語句

集合框架

  1. 為什么要使用集合框架?
    數組的弊端:類型必須相同、長度是固定的,如果一組數據在程序運行時並不能確定長度,那就不能再使用數組了
    相對於數組,集合框架不限類型,並且長度可變,運用更加靈活。

現學部分的重點是標紅部分

CollectionMapjava.util包下的兩個集合上級接口

  • Collection:存儲單個對象的集合 特點:無序(有序、無序是指在進行插入操作時,插入位置的順序性
    先插的位置在前,后插的位置在后,則為有序,反之無序
    ),不唯一

    如圖所示,它擁有三個子類型集合ListSetQueue(重點是List)

    • List :有序,不唯一

      ​ 常用的實現類:

      	1.  `ArrayList` :以`數組`的方式存儲,**查詢的效率高,插入和刪除的效率低**	2.  `LinkedList`:以`鏈表`的方式,**插入和刪除的效率高,查詢的效率低**,和`ArrayList`相反
      
    List常用方法 功能
    add(obj) /add(int index,obj o) 添加對象/在指定位置插入
    remove(obj (這是Collection提供的方法))/remove(int index)(這是List提供的方法) 按對象刪除/按下標刪除
    get(int index) 獲取對象
    size() 獲取集合的長度
    contains() 查看集合中是否包含某對象

    前三個方法LinkedList有擴展的方法如addFirst(),addLast();(功能就不解釋了,顧名思義,其余兩個以此類推)

    • Set:無序、唯一,典型的實現類有:
      HashSet:以哈希表的形式存儲
      TreeSet:以樹形表的形式存儲
  • Map:存儲鍵(key,value)值對的集合 鍵唯一,值不唯一。

Map常用方法 功能
put(key,value) 往Map中添加鍵值對
remove(key) 移除一對鍵值對
get(key) 根據鍵獲取值
size() 獲取集合的長度
values() 獲取值集,返回Collection對象,因為Collection是不唯一的,所以值不唯一
keySet() 獲取鍵集,返回Set對象,因為Set是唯一的,所以鍵唯一
containsKey(key) 判斷集合中是否有某鍵

Map典型的實現類
- HashMap: 允許插入空值,效率高,線程不安全
- Hashtable :不允許插入空值,效率低,但線程安全
- TreeMap

集合的遍歷

  1. java中的foreach
for(類名 對象名:集合){    }//例如class Student{	String name;	int age;	public Student(String name, int age) {		this.name = name;		this.age = age;	}	}public class Test {	public static void main(String[] args) {				List l = new ArrayList();		l.add(new Student("Yuan",19));		l.add(new Student("He",19));		for(Object s:l) {			Student stu = (Student)s;			System.out.println(stu.name);		}	}}
  1. 使用iterator迭代器

    • 如何獲得iterator迭代器?

      通過Collection提供的方法Iterator<e> Iterator()方法來得到一個迭代器

    • Iterator迭代器有哪些方法

    方法 功能
    boolean hasNext() 判斷是否還有下一個元素,如果有返回true,沒有返回false
    E next() 獲得下一個元素
List list = new ArrayList() {
	{
		this.add(new Student("張三",20));
		this.add(new Student("李四",20));
	}
};
Iterator iter= list.iterator();
while(iter.hasNext()) {
	Student s = (Student)iter.next();
	String name = s.name;
	System.out.println(name);
}
  1. 使用for循環 + Iterator迭代器
List list = new ArrayList() {
	{
		this.add(new Student("張三",20));
		this.add(new Student("李四",20));
	}
};	
for(Iterator iter = list.iterator();iter.hasNext();) {
	Student s = (Student)iter.next();
	String name = s.name;
	System.out.println(name);
}
//另外 單純的用for循環也是可以遍歷的 因為List是有序的

泛型

  1. 為什么要用泛型:先注意集合的特點:集合長度可變,並且可以放任意的引用數據類型,存儲的數據類型也可以不一樣假如我有一個這樣的需求,我需要獲取全班所有人的姓名,但有個別人搗亂,把名字寫成電話號碼,導致我后面的代碼出錯,這種時候,就需要使用到泛型了,如果沒按照我的規定來存放數據就會報錯,等於是將運行時期會發生的異常提前到編譯時期了。所以可見泛型是一種安全機制,一種規范,它和接口一樣在制定規則。

  2. 如何理解泛型?大家上學的時候都寫過作文吧,考試的時候作文上面的要求經常是題材不限,但是一旦你確認題材了,你就不能再寫其他題材的作文了,泛型也是如此,本質上泛型是一個變量,它是需要我們賦值的。

//例如
List<student> names = new ArrayList<student> names();
//這時我如果給他存放其他的數據類型就會出錯  而且我們在取元素的時候不需要強制類型轉換

還有泛型類泛型方法之類的沒太多時間去補充,到時候補充和完善。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM