1. 程式人生 > >Java架構-JavaSE(一)之類與物件

Java架構-JavaSE(一)之類與物件

閱讀目錄(Content)
一、OOP概述
二、類與物件和物件與引用的關係
  2.1、類與物件的關係
三、方法的定義和呼叫
  3.1、方法的定義
  3.2、方法呼叫
四、呼叫方法時的傳參
五、this關鍵字
六、建立與初始化物件
七、構造器

終於到了要學習面向物件程式設計了,其中可能很多東西以前都知道怎麼去用,但是卻不知道怎麼來的,或者怎麼樣寫會出錯,所以今天總結起來。

一、OOP概述

Java的程式語言是面向物件的,採用這種語言進行程式設計稱為面向物件程式設計(Object-Oriented Programming, OOP)。

1)抽象(abstract)
    忽略一個主題中與當前目標無關的那些方面,以便更充分地注意與當前目標有關的方面。抽象並不打算了解全部問題,而只是選擇其中的一部分,暫時不用關注細節。
        例如:要設計一個學生成績管理系統,那麼對於學生,只關心他的班級、學號、成績等,而不用去關心他的身高、體重這些資訊

2)封裝(Encapsulation)
    封裝是面向物件的特徵之一,是物件和類概念的主要特性。封裝是把過程和資料包圍起來,對資料的訪問只能通過指定的方式。

    在定義一個物件的特性的時候,有必要決定這些特性的可見性,即哪些特性對外部是可見的,哪些特性用於表示內部狀態。

    通常,應禁止直接訪問一個物件中資料的實際表示,而應通過操作介面來訪問,這稱為資訊隱藏。

    資訊隱藏是使用者對封裝性的認識,封裝則為資訊隱藏提供支援。

    封裝保證了模組具有較好的獨立性,使得程式維護修改較為容易。對應用程式的修改僅限於類的內部,因而可以將應用程式修改帶來的影響減少到最低限度。

    
3)繼承(inheritance)
    繼承是一種聯結類的層次模型,並且允許和支援類的重用,它提供了一種明確表述共性的方法。
    
    新類繼承了原始類後,新類就繼承了原始類的特性,新類稱為原始類的派生類(子類),而原始類稱為新類的基類(父類)。
    
    派生類(子類)可以從它的基類(父類)那裡繼承方法和例項變數,並且派生類(子類)中可以修改或增加新的方法使之更適合特殊的需要

    繼承性很好的解決了軟體的可重用性問題。比如說,所有的Windows應用程式都有一個視窗,它們可以看作都是從一個視窗類派生出來的。但是有的應用程式用於文書處理,有的應用程式用於繪圖,這是由於派生出了不同的子類,各個子類添加了不同的特性。

4)多型(polymorphism)
    多型性是指允許不同類的物件對同一訊息作出響應。
    多型性語言具有靈活、抽象、行為共享、程式碼共享的優勢,很好的解決了應用程式函式同名問題。

    相同類域的不同物件,呼叫相同方法,表現出不同的結果
    例如:
        public class Person{
            public void say(){}
        }
        public class Student extends Person{
            public void say(){
                System.out.println("I am a student");
            }
        }
        public class Teacher extends Person{
            public void say(){
                System.out.println("I am a teacher");
            }
        }
        main:
            Person s = new Student();
            Person t = new Teacher();
            s.say();
            t.say();

二、類與物件和物件與引用的關係

2.1、類與物件的關係
     類是一種抽象的資料型別,它是對某一類事物整體描述/定義,但是並不能代表某一個具體的事物.
   例如:我們生活中所說的詞語:動物、植物、手機、電腦等等
   這些也都是抽象的概念,而不是指的某一個具體的東西。

      例如: Person類、Room類、Car類等
      這些類都是用來描述/定義某一類具體的事物應該具備的特點和行為

物件是抽象概念的具體例項
   例如:
   張三就是人的一個具體例項,張三家裡的旺財就是狗的一個具體例項。能夠體現出特點,展現出功能的是具體的例項,而不是一個抽象的概念.

例如:
   Student s = new Student(1L,“tom”,20);
   s.study();

          Car c = new Car(1,"BWM",500000);
          c.run();

        物件s就是Student類的一個例項,物件c就是Car類的一個具體例項,能夠使用的是具體例項,而不是類。類只是給物件的建立提供了一個參考的模板而已.
        但是在java中,沒有類就沒有物件,然而類又是根據具體的功能需求,進行實際的分析,最終抽象出來的.

2.2、物件和引用的關係

引用"指向"物件
   使用類型別、陣列型別、介面型別宣告出的變數,都可以指向物件,這種變數就是引用型別變數,簡稱引用。
   在程式中,創建出物件後,直接使用並不方便,所以一般會用一個引用型別的變數去接收這個物件,這個就是所說的引用指向物件.

  總結:物件和引用的關係,就如電視機和遙控器,風箏和線的關係一樣。

三、方法的定義和呼叫

方法一定是定義在類中的,屬於類的成員。

3.1、方法的定義
    格式: 修飾符 返回型別 方法名(引數列表)異常丟擲型別{…}

      1)修飾符:
          public static abstract final等等都是修飾符,一個方法可以有多個修飾符.例如程式入口main方法,就使用了public static這個倆個修飾符
          注:如果一個方法或者屬性有多個修飾符,這多個修飾符是沒有先後順序的

      2)返回型別:
          方法執行完如果有要返回的資料,那麼就要宣告返回資料的型別,如果沒有返回的資料,那麼返回型別就必須寫void.
          只有構造方法(構造器)不寫任何返回型別也不寫void
          例如:
          public String sayHello(){
              return "hello";
          }
          public int max(int a,int b){
              return a>b?a:b;
            }
          public void print(String msg){
              System.out.println(msg);
          }

思考:宣告返回型別的方法中一定要出現return語句,那麼沒有返回型別(void)的方法中,能不能出現return語句?
   注:break和return的區別

      3)方法名:
          遵守java中標示符的命名規則即可.

4)引數列表
   根據需求定義,方法可以是無參的,也可以有一個引數,也可以有多個引數

      5)異常丟擲型別
          如果方法中的程式碼在執行過程中,可能會出現一些異常情況,那麼就可以在方法上把這些異常宣告並丟擲,也可以同時宣告丟擲多個異常,使用逗號隔開即可。
          例如:
          public void readFile(String file)throws IOException{
        
          }
          public void readFile(String file)throws IOException,ClassNotFoundException{
        
          }

3.2、方法呼叫
    在類中定義了方法,這個方法中的程式碼並不會執行,當這個方法被呼叫的時候,方法中的程式碼才會被一行一行順序執行。

      1)非靜態方法
          沒有使用static修飾符修飾的方法,就是非靜態方法.
          呼叫這種方法的時候,是"一定"要使用物件的。因為非靜態方法是屬於物件的。(非靜態屬性也是一樣的)
          例如:
              public class Student{
                  public void say(){}
              }

              main:
                  Student s = new Student();
                  s.say();
    
      2)靜態方法
          使用static修飾符修飾的方法,就是靜態方法.
          呼叫這種方法的時候,"可以"使用物件呼叫,也"可以"使用類來呼叫,但是推薦使用類進行呼叫,因為靜態方法是屬於類的。(靜態屬性也是一樣的)
          例如:
              public class Student{
                  public static void say(){}
              }

              main:
                  Student.say();

3)類中方法之間的呼叫
   假設同一個類中有倆個方法,a方法和b方法

          a和b都是非靜態方法,相互之間可以直接呼叫.
          public void a(){
              b();
          }
          public void b(){
        
          }

          a和b都是靜態方法,相互之間可以直接呼叫.
          public static void a(){
              b();
          }
          public static void b(){
        
         }

          a靜態方法,b是非靜態方法
              a方法中不能直接呼叫b方法,但是b方法中可以直接呼叫a方法.
          public static void a(){
              //b();報錯
          }
          public void b(){
              a();
          }
          另外:在同一個類中,靜態方法內不能直接訪問到類中的非靜態屬性.

總結:類中方法中的呼叫,兩個方法都是靜態或者非靜態都可以互相呼叫,當一個方法是靜態,一個方法是非
靜態的時候,非靜態方法可以呼叫靜態方法,反之不能。

四、呼叫方法時的傳參

1)形參和實參
例如:
// a = x;
public void test(int a){
//…
}
main:
int x = 1;
t.test(x);
引數列表中的a是方法test的形參(形式上的引數)
呼叫方法時的x是方法test的實參(實際上的引數)

    注意:形參的名字和實參的名字都只是一個變數的名字,是可以隨便寫的,我們並不關心這個名字,而是關心變數的型別以及變數接收的值。

2)值傳遞和引用傳遞
    呼叫方法進行傳參時,分為值傳遞和引用傳遞兩種。
    如果引數的型別是基本資料型別,那麼就是值傳遞。
    如果引數的型別是引用資料型別,那麼就是引用傳遞。
    
    值傳遞是實參把自己變數本身存的簡單數值賦值給形參.
    引用傳遞是實參把自己變數本身存的物件記憶體地址值賦值給形參.
    
    所以值傳遞和引用傳遞本質上是一回事,只不過傳遞的東西的意義不同而已.
3)值傳遞的示例
    public class Test{
        public static void changeNum(int a){
            a = 10;
        }

        public static void main(String[] args){
            int a = 1;
            System.out.println("before: a = "+a);
            changeNum(a);
            System.out.println("after: a = "+a);
        }

    }

4)引用傳遞的示例
    public class Test{
        public static void changeName(Student s){
            s.name = "tom";
        }

        public static void main(String[] args){
            Student s = new Student();
            System.out.println("before: name = "+s.name);
            changeName(s);
            System.out.println("after: name = "+s.name);
        }
    }

五、this關鍵字

在類中,可以使用this關鍵字表示一些特殊的作用。

5.1、this在類中的作用

1)區別成員變數和區域性變數
   public class Student{
   private String name;
   public void setName(String name){
   //this.name表示類中的屬性name
   this.name = name;
   }

      }

2)呼叫類中的其他方法
   public class Student{
   private String name;
   public void setName(String name){
   this.name = name;
   }
   public void print(){
   //表示呼叫當前類中的setName方法
   this.setName(“tom”);
   }
   }
注:預設情況下,setName(“tom”)和this.setName(“tom”)的效果是一樣的.

3)呼叫類中的其他構造器
   public class Student{
   private String name;
   public Student(){
   //呼叫一個引數的構造器,並且引數的型別是String
   this(“tom”);
   }
   public Student(String name){
   this.name = name;
   }
   }

    注:this的這種用法,只能在構造器中使用.普通的方法是不能用的.並且這局呼叫的程式碼只能出現在構造器中的第一句.
    例如:
    public class Student{
        private String name;
        //編譯報錯,因為this("tom")不是構造器中的第一句程式碼.
        public Student(){
            System.out.println("hello");
            this("tom");
        }
        public Student(String name){
            this.name = name;
        }
    }

5.2、this關鍵字在類中的意義

this在類中表示當前類將來創建出的物件.
   例如:
   public class Student{
   private String name;
   public Student(){
   System.out.println("this = "+this);
   }
   public static void main(String[] args){
   Student s = new Student();
   System.out.println("s = "+s);
   }
   }
   執行後看結果可知,this和s列印的結果是一樣的,那麼其實也就是變數s是從物件的外部執行物件,而this是在物件的內部執行物件本身.
   這樣也就能理解為什麼this.name代表的是成員變數,this.setName(“tom”)代表的是呼叫成員方法,因為這倆句程式碼從本質上講,和在物件外部使用變數s來呼叫是一樣的,s.name和s.setName(“tom”)。

      this和s打印出來的記憶體地址是一樣的,使用==比較的結果為true。
      例如:
      public class Student{
          public Student getStudent(){

return this;
   }

          public static void main(String[] args) {
              Student s1 = new Student();
              Student s2 = s1.getStudent();
              System.out.println(s1 == s2);//true           
          }

}

例如: 類中的this是和s1相等還是和s2相等呢?
    public class Student{
   private String name;
   public void test(){
   System.out.println(this);
   }
   public static void main(String[] args) {
   Student s1 = new Student();
   Student s2 = new Student();
   s1.test();
   s2.test();
    }
    }
注:這句話是要這麼來描述的,s1物件中的this和s1相等,s2物件中的this和s2相等,因為類是模板,模板中寫的this並不是只有一個,每個物件中都有一個屬於自己的this,就是每個物件中都一個屬於自己的name屬性一樣.

六、建立與初始化物件

使用new關鍵字建立的時候,除了分配記憶體空間之外,還會給建立好的物件進行預設的初始化以及對類中構造器的呼叫

那麼對main方法中的以下程式碼:
   Student s = new Student();
   1)為物件分配記憶體空間,將物件的例項變數自動初始化預設值為0/false/null。(例項變數的隱式賦值)

      2)如果程式碼中例項變數有顯式賦值,那麼就將之前的預設值覆蓋掉。(之後可以通過例子看到這個現象)
          例如:顯式賦值
          private String name = "tom";

      3)呼叫構造器

      4)把物件記憶體地址值賦值給變數。(=號賦值操作)

七、構造器

類中的構造器也稱為構造方法,是在進行建立物件的時候必須要呼叫的。並且構造器有以下倆個特點:
1)必須和類的名字相同
2)必須沒有返回型別,也不能寫void

構造器的作用:
    1)使用new建立物件的時候必須使用類的構造器
    2)構造器中的程式碼執行後,可以給物件中的屬性初始化賦值
        例如:
        public class Student{
            private String name;
            public Student(){
                name = "tom";
            }
        }

構造器過載:
    除了無參構造器之外,很多時候我們還會使用有參構造器,在建立物件時候可以給屬性賦值.
    例如:
        public class Student{
            private String name;
            public Student(String name){
                this.name = name;
            }
        }

構造器之間的呼叫:
    使用this關鍵字,在一個構造器中可以呼叫另一個構造器的程式碼。
    注意:this的這種用法不會產生新的物件,只是呼叫了構造器中的程式碼而已.一般情況下只有使用new關鍵字才會建立新物件。

    例如:
        public class Student{
            private String name;
            public Student(){
                this();
            }
            public Student(String name){
                this.name = name;
            }
        }

預設構造器:
    在java中,即使我們在編寫類的時候沒有寫構造器,那麼在編譯之後也會自動的新增一個無參構造器,這個無參構造器也被稱為預設的構造器。

    例如:
    public class Student{
    
    }
    main:
        //編譯通過,因為有無參構造器
        Student s = new Student();
               
    但是,如果我們手動的編寫了一個構造器,那麼編譯後就不會新增任何構造器了
    例如:
    public class Student{
        private String name;
        public Student(String name){
            this.name = name;
        }
    }
    main:
        //編譯報錯,因為沒有無參構造器
        Student s = new Student();
  • 為什麼某些人會一直比你優秀,是因為他本身就很優秀還一直在持續努力變得更優秀,而你是不是還在滿足於現狀內心在竊喜!
  • 合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!

還是那句話,希望此文能幫到大家的同時,也聽聽大家的觀點。歡迎留言討論,加關注,分享你的高見!持續更新!

To-陌霖Java架構

分享網際網路最新文章 關注網際網路最新發展