Java匹馬行天下之JavaSE核心技術——物件導向

泰斗賢若如發表於2019-04-01

                                       物件導向

注:

看此篇時強烈建議有一定的物件導向思想基礎,有一定的基礎後先翻到下面看第九條:
      9.物件導向: 從未封裝→封裝→繼承→多型→抽象類→介面的程式碼演變

按這個邏輯去看,,哪有不理解的再回頭看知識點,這是掌握理解最好最快的方法,切記切記

 

萬物皆物件

            描述一個物質都可以通過兩方面說明:資料模型(屬性)、行為模型(行為)。

            在Java程式設計中,我們使用成員變數表示資料模型,用成員方法表示行為模型。

            使用表示某些具有相同屬性和行為的事物。

 

1. 方法:

        構造方法     

                     語法:

             [訪問修飾符]  類名(){ }

                  注意:

                           當類中沒有顯式的構造方法,例項化該類的物件時,程式會自動建立一個公開的無參構造方法;

                           如果類中有顯示的構造方法,程式就不會建立無參構造;

                 構造方法,一般是用於為成員屬性賦初始化值;                 

        靜態方法

                       static 關鍵字用來宣告獨立於物件的靜態方法。靜態方法不能使用類的非靜態變數。靜態方法從引數列表得到資料,然後計算這些資料。

                  對類變數和方法的訪問可以直接使用 classname.variablename 和 classname.methodname 的方式訪問。

 

                  如下例所示,static修飾符用來建立類方法和類變數:

public class InstanceCounter {
   private static int numInstances = 0;
   protected static int getCount() {
      return numInstances;
   }
 
   private static void addInstance() {
      numInstances++;
   }
 
   InstanceCounter() {
      InstanceCounter.addInstance();
   }
 
   public static void main(String[] arguments) {
      System.out.println("Starting with " +
      InstanceCounter.getCount() + " instances");
      for (int i = 0; i < 500; ++i){
         new InstanceCounter();
          }
      System.out.println("Created " +
      InstanceCounter.getCount() + " instances");
   }
}

 

執行結果:

Starting with 0 instances
Created 500 instances

  

        成員方法(例項方法)

2. 變數:

        成員變數(例項變數)

      • 宣告在所有方法體和程式碼塊之外,並且沒有使用static修飾的變數,叫做例項變數;
      • 可以使用訪問修飾符和final修飾;
      • 使用final修飾時,一定要賦值;
      • 例項變數是在物件被建立時建立,物件被銷燬時銷燬;
      • 作用域範圍在整個類中;

        區域性變數                      

      • 宣告在構造方法、靜態方法、例項方法、程式碼塊中的變數,都是區域性變數;
      • 不能使用static和訪問修飾符修飾;
      • 可以使用final修飾,即為常量,不必在宣告語句中賦值;
      • 當執行區域性變數所在的方法或程式碼塊時,才有機會被建立,在方法或程式碼塊執行結束後被自動銷燬;
      • 區域性變數在記憶體的棧區分配;
      • 區域性變數在使用之前必須要先賦值;

        靜態變數(類的變數)

      • 宣告在所有方法體和程式碼塊之外,並且使用static修飾的變數;
      • 可以使用訪問修飾符修飾;
      • 一般配合final使用,即public  static  fianl,識別符號使用大寫;
      • 類變數被分配在靜態儲存區,是被所有該類的物件共享資料;
      • 類變數是在程式開始時被建立,程式結束時銷燬;

 

3. 修飾符

        訪問修飾符      

                  Java中,可以使用訪問控制符來保護對類、變數、方法和構造方法的訪問。Java 支援 4 種不同的訪問許可權。

      • default (即預設,什麼也不寫): 在同一包內可見,不使用任何修飾符。使用物件:類、介面、變數、方法。

      • private : 在同一類內可見。使用物件:變數、方法。 注意:不能修飾類(外部類)

      • public : 對所有類可見。使用物件:類、介面、變數、方法

      • protected : 對同一包內的類和所有子類可見。使用物件:變數、方法。 注意:不能修飾類(外部類)

                            我們可以通過以下表來說明訪問許可權:

 修飾符 當前類 同包的類 同包的子孫類 異包類 異包的子孫類
public 
protected × ×
default × ×
private × × × ×

 

          非訪問修飾符

                     為了實現一些其他的功能,Java 也提供了許多非訪問修飾符。

                      static 修飾符,用來修飾類方法和類變數。

                      final 修飾符,用來修飾類、方法和變數,final 修飾的類不能夠被繼承,修飾的方法不能被繼承類重新定義,修飾的變數為常量,是不可修改的。             

                                    final 變數:

                                final 表示"最後的、最終的"含義,變數一旦賦值後,不能被重新賦值。被 final 修飾的例項變數必須顯式指定初始值。

                                final 修飾符通常和 static 修飾符一起使用來建立類常量。

                                                                 

//例項
public class Test{
  final int value = 10;
  // 下面是宣告常量的例項
  public static final int BOXWIDTH = 6;
  static final String TITLE = "Manager";
 
  public void changeValue(){
     value = 12; //將輸出一個錯誤
  }
}

                                                        

                                        final 方法:

                                      類中的 final 方法可以被子類繼承,但是不能被子類修改。

                                      宣告 final 方法的主要目的是防止該方法的內容被修改。

     如下所示,使用 final 修飾符宣告方法:

public class Test{
    public final void changeName(){
       // 方法體
    }
}

  

                                        final 類:

                                     final 類不能被繼承,沒有類能夠繼承 final 類的任何特性。

//例項
public final class Test {
   // 類體
}

  

                        注意:

        • 當final修飾類時,當前類不能被繼承;
        • 當final修飾方法時,該方法不能被重寫;
        • 當final修飾變數時,變數的值不能被修改,即為常量;

 

                   abstract 修飾符,用來建立抽象類和抽象方法。

        

                              抽象類:

                                     抽象類不能用來例項化物件,宣告抽象類的唯一目的是為了將來對該類進行擴充。

                                     一個類不能同時被 abstract 和 final 修飾。如果一個類包含抽象方法,那麼該類一定要宣告為抽象類,否則將出現編譯錯誤。

                                     抽象類可以包含抽象方法和非抽象方法。

 

                          規則:

                           含有抽象方法的類,一定是抽象類;

        • 抽象類中可以宣告成員變數、常量、成員方法、抽象方法,抽象類中不一定要有抽象方法;
        • 抽象類不能被例項化;
        • 抽象類可以被繼承;
        • 可以通過兩種方式獲得抽象類物件:父類引用指向子類物件、匿名內部類;
        • 子類必須重寫抽象父類的所有抽象方法,或者是把子類也定義為抽象類;
        • 如果一個類繼承的抽象父類還有上級抽象父類,那麼子類中需要要重寫所有抽象父類的所有抽象方法;
        • 抽象類也可以繼承非抽象類,同時繼承了父類的所有非私有的屬性和方法;
例項
abstract class Caravan{
   private double price;
   private String model;
   private String year;
   public abstract void goFast(); //抽象方法
   public abstract void changeColor();
}

                      抽象方法

                              抽象方法是一種沒有任何實現的方法,該方法的的具體實現由子類提供。

                              抽象方法不能被宣告成 final 和 static。

                              任何繼承抽象類的子類必須實現父類的所有抽象方法,除非該子類也是抽象類。

                              如果一個類包含若干個抽象方法,那麼該類必須宣告為抽象類。抽象類可以不包含抽象方法。

                              抽象方法的宣告以分號結尾,例如:public abstract sample();

例項
public abstract class SuperClass{
    abstract void m(); //抽象方法
}
 
class SubClass extends SuperClass{
     //實現抽象方法
      void m(){
          .........
      }
}

 

                          synchronized volatile 修飾符,主要用於執行緒的程式設計。

                                    synchronized 修飾符

                                      synchronized 關鍵字宣告的方法同一時間只能被一個執行緒訪問。synchronized 修飾符可以應用於四個訪問修飾符。

例項
public synchronized void showDetails(){
.......
}

  

                                 transient 修飾符

                                  序列化的物件包含被 transient 修飾的例項變數時,java 虛擬機器(JVM)跳過該特定的變數。

                                  該修飾符包含在定義變數的語句中,用來預處理類和變數的資料型別。

例項
public transient int limit = 55;   // 不會持久化
public int b; // 持久化

  

                             volatile 修飾符

                                   volatile 修飾的成員變數在每次被執行緒訪問時,都強制從共享記憶體中重新讀取該成員變數的值。而且,當成員變數發生變化時,                                     會強制執行緒將變化值回寫到共享記憶體。這樣在任何時刻,兩個不同的執行緒總是看到某個成員變數的同一個值。

                                    一個 volatile 物件引用可能是 null。

 

例項
public class MyRunnable implements Runnable
{
    private volatile boolean active;
    public void run()
    {
        active = true;
        while (active) // 第一行
        {
            // 程式碼
        }
    }
    public void stop()
    {
        active = false; // 第二行
    }
}

 

              通常情況下,在一個執行緒呼叫 run() 方法(在 Runnable 開啟的執行緒),在另一個執行緒呼叫 stop() 方法。 如果 第一行 中緩衝區的 active 值被                         使用,那麼在 第二行 的 active 值為 false 時迴圈不會停止。

             但是以上程式碼中我們使用了 volatile 修飾 active,所以該迴圈會停止。

 

4. this關鍵字

                           this指當前物件,用法:

          • 當區域性變數名和例項變數名同名時,使用this.變數名來表示例項變數;
          • this()表示當前類的構造方法,只能在構造方法中使用該寫法,並且是寫在構造方法內的第一行。

 

                                              物件導向三大特徵:封裝、繼承、多型

5. 封裝

                             私有的屬性,公開的方法。

                             封裝的步驟:

                                    宣告私有(private)的屬性;

                                    宣告公開(public)的geter和seter方法;

6. 繼承

                                Java中的繼承是單繼承,可以實現多層繼承,繼承的關鍵字extends

                語法:

public class Son extends Father{

 

}

  

               規則:

      • 子類繼承父類非私有的所有屬性和方法,不能繼承父類的構造方法;
      • 例項化子類物件的步驟:先執行父類的構造方法,再執行子類的構造方法

                重寫定義:

      • 子類重新宣告從父類繼承來的方法,稱為方法重寫;
      • 方法重寫時,方法的宣告部分要和父類保持一致(返回值型別,方法名,引數);
      • 重寫方法的訪問許可權要大於等於父類中方法的訪問許可權;
      • 子類重寫父類方法,子類物件呼叫的是子類中重寫後的方法;
      • 使用static修飾的方法不能被重寫,但是可以被子類重寫宣告;
      • 不同包的子類可以重寫父類中protected修飾的方法,但是不能以繼承的形式,用子類物件直接呼叫父類的該方法;

7. 多型

                實現的必要條件:

      • 繼承
      • 重寫
      • 父類引用指向子類物件

 

                              instanceof關鍵字:

 

語法:
if (物件名 instanceof 類名) {		
			型別轉換程式碼;
}

 

  

例項:
Animal cat = new Cat();
		if (cat instanceof Cat) {//返回結果為boolean型別
			Cat c = (Cat) cat;
			c.eat();
		}else{
			System.out.println("型別不匹配");
		}

8. 介面

語法:
public interface ITest {

}

  

                規則:

      • 介面使用interface關鍵字修飾;
      • 介面是一個完全抽象的抽象類;
      • 介面中沒有構造方法
      • 介面不能被例項化物件
      • 介面中可以宣告靜態常量、抽象方法、靜態方法;
      • 介面中不能宣告例項方法,宣告抽象方法時,不能使用static關鍵字修飾;
      • 宣告介面語句中,預設含有abstract關鍵字,抽象方法中也預設含有abstract關鍵字;
      • 介面可以被實現,使用implements關鍵字,一個類實現一個介面,必須重寫該介面中所有的抽象方法;
      • 一個類可以實現多個介面,每個介面名用英文的逗號隔開,該類中必須重寫所有已實現介面中的抽象方法;

                          介面可以繼承介面,介面與介面間是多繼承關係,介面不能繼承類;

 

9.物件導向: 從未封裝→封裝→繼承→多型→抽象類→介面的程式碼演變:

            未封裝:

 

public class Person {
    int age;//年齡
    String name;//姓名
    public void print()
    {
        System.out.println("age:"+this.age+" "+"name:"+this.name);
    }
}
class Text{
    public static void main(String[] args) {
        Person person = new Person();//例項化物件
        person.age = -100;//賦值
        person.name = "張三";
        person.print();//執行類中的方法
    }
}

執行結果:
age:-100 name:張三

  

               封裝:

public class Person {
    private int age;//年齡
    private String name;//姓名

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + this.age +
                ", name='" + this.name + '\'' +
                '}';
    }
}

 

class Text{
    public static void main(String[] args) {
        Person person = new Person();
        person.setAge(20);
        person.setName("張三"); ;
        String s = person.toString();
        System.out.println(s);
    }
}

 

執行結果:
Person{age=20, name='張三'}

  

                  繼承:

public class Office {
    public void print(){
        System.out.println("列印");
    }
}

  

class Word extends Office {
    @Override
    public void print() {
        System.out.println("Word列印");
    }
}

  

class Test{
    public static void main(String[] args) {
        Word word = new Word();
        word.print();
    }
}

  

執行結果:

Word列印

  一個Java原始檔中可以宣告多個class類,但只能有一個public修飾的類。

       

                  多型:

public class Office {
    public void print(){
        System.out.println("列印");
    }
}

  

class Word extends Office {
    @Override
    public void print() {
        System.out.println("Word列印");
    }
}

  

class Excle extends Office{
    @Override
    public void print() {
        System.out.println("Excel列印");
    }
}

  

class  Ppt extends Office{
    public void daYin() {//子類可以重寫父類方法,也可以自己定義方法
        System.out.println("PPT列印");
    }
}

  

class Test{
    public static void main(String[] args) {
        Office o = new Word();//多種形態,即多型
        o.print();
    }
}

  

執行結果:

Word列印

  

class Test{
    public static void main(String[] args) {
        Office o = new Excle();
        o.print();
    }
}

  

執行結果:

Excel列印

  

class Test{
    public static void main(String[] args) {
        Office o = new Ppt();
        o.print();
    }
}

  

執行結果:

列印

  為避免這種方法名稱多樣的情況,用一種約束抽象類

public abstract class Office {
    public abstract void print();
}

class Word extends Office {
    @Override
    public void print() {
        System.out.println("Word列印");
    }
}

class Excle extends Office{
    @Override
    public void print() {
        System.out.println("Excel列印");
    }
}

class  Ppt extends Office{
    @Override
    public void print() {
        System.out.println("PPT列印");
    }
}

class Test{
    public static void main(String[] args) {
        Office o = new Ppt();//父類引用指向子類物件,子類重寫父類方法,父類引用呼叫子類重寫後的方法,執行的結果是子類重寫後的方法
        o.print();
    }
}
執行結果:

PPT列印

  介面是完全抽象的抽象類,並且可以多實現

 

介面預設為:
public  class abstract interface Office {
public abstract void print();
}

  

public interface Office {
    void print();
}

class Word implements Office {
    @Override
    public void print() {
        System.out.println("Word列印");
    }
}

class Excle implements Office{
    @Override
    public void print() {
        System.out.println("Excel列印");
    }
}

class  Ppt implements Office{
    @Override
    public void print() {
        System.out.println("PPT列印");
    }
}

class Test{
    public static void main(String[] args) {
        Office o = new Ppt();
        o.print();
    }
}
執行結果為:

PPT列印

10. 內部類

               成員內部類

                          成員內部類宣告在類中,方法體、程式碼塊之外。和成員變數、成員方法在同一級別。

 

語法:
public class Out {
	  //成員內部類
	  public class Inner{
	  }
}

  

例項化成員內部類:
		//先例項化外部類
		Out o = new Out();
		//使用外部類物件,再例項化內部
		Out.Inner inner = o.new Inner();

  

例項:
public class Out {
	//成員變數
	public int a = 1;
	
	//成員內部類
	public class Inner{
		public int a = 2;
		//內部類的成員方法
		public void print(){
//執行內部類中的例項變數a
			System.out.println(a);
//執行外部類的例項變數a
			System.out.println(Out.this.a);		
}
	}
}

  

            靜態內部類

                      宣告的位置參考成員內部類。

語法:
public class Out {
	//靜態內部類
	public static class Inner{
		
	}
}

  

例項化靜態內部的物件:
Out.Inner inner = new Out.Inner();

  

例項:
public class Out {
	public static int a = 1;
	public int b = 3;
	//靜態內部類
	public static class Inner{
		public static int a = 2;
		public static void print(){
			//執行靜態內部的靜態變數
			System.out.println(a);
			//執行外部類的靜態變數
			System.out.println(Out.a);
			//執行外部類的例項變數
			Out o = new Out();
			System.out.println(o.b);
		}
	}
}

  

                 區域性內部類

                            宣告在方法體或程式碼塊內,作用域範圍在方法體或程式碼塊內。

 

語法:
public class Out {
	public void method(){
		//區域性內部類
		class Inner{
			//區域性內部類的成員方法
			public void print(){
				System.out.println("區域性內部類");
			}
		}
		//例項化區域性內部類
		Inner inner = new Inner();
		inner.print();
	}
}

  

執行區域性內部類的方法:
Test類:
public static void main(String[] args) {
		Out o  = new Out();
		o.method();
}

  

                 匿名內部類

      • 宣告位置同區域性內部類一樣,前提條件:必須繼承一個類或實現一個介面,匿名內部類的宣告和例項化物件是同時進行的;
      • 一般使用於獲得抽象類或介面物件;
語法:
父類名/介面名  物件名 =  new  父類名/介面名(){
		//匿名內部類成員
};

  

例項:
父類
public class Father {
}

  

匿名內部類:
public class Out {
	public void method(){
		//匿名內部類物件
		Father f = new Father(){
		};
	}
}

  

 

相關文章