Day3—面向?qū)ο螅▽?duì)象創(chuàng)建于使用、屬性、方法、構(gòu)造器、封裝)

概述

面向?qū)ο蟮娜筇卣?/h5>
  • 封裝 (Encapsulation)
  • 繼承 (Inheritance)
  • 多態(tài) (Polymorphism)
面向?qū)ο蟮乃枷敫攀?/h5>

類(Class)和對(duì)象(Object)是面向?qū)ο蟮暮诵母拍睢?/p>

  • 類是對(duì)一類事物的描述,是抽象的、概念上的定義
  • 對(duì)象是實(shí)際存在的該類事物的每個(gè)個(gè)體,因而也稱為實(shí)例(instance)

可以理解為:類 = 抽象概念的人;對(duì)象 = 實(shí)實(shí)在在的某個(gè)人
面向?qū)ο蟪绦蛟O(shè)計(jì)的重點(diǎn)是類的設(shè)計(jì);而類的設(shè)計(jì),其實(shí)就是類的成員的設(shè)計(jì)。

java類

類的語(yǔ)法格式
修飾符  class  類名 {

    屬性聲明;
    方法聲明;

}
類的成員構(gòu)成
  • 屬性
  • 構(gòu)造器
  • 方法
  • 代碼塊
  • 內(nèi)部類
類的成員構(gòu)成

對(duì)象創(chuàng)建和使用

要想創(chuàng)建一個(gè)對(duì)象并且使用,首先要進(jìn)行類的創(chuàng)建:

// 類的創(chuàng)建
class Person{
    // 屬性
    String name;
    int age;

    // 方法
    public void grown(){
        age++;
    }

    public void greeting(){
        System.out.println("Domo, my name is "+ name +", nice to meet you!");
    }

}

有了類之后,便可以通過(guò)類名創(chuàng)建對(duì)象,并且通過(guò)" . "的方式來(lái)訪問(wèn)對(duì)象中的屬性和方法:

    public static void main(String[] args) {
        
        // 創(chuàng)建對(duì)象
        Person p1 = new Person();

        // 調(diào)用屬性
        p1.name = "Kana";
        p1.age = 14;
        System.out.println(p1.name);
        System.out.println(p1.age);
        
        // 調(diào)用方法
        p1.greeting();    // Domo, my name is Kana, nice to meet you!
        p1.grown();
        System.out.println(p1.age);   // 15
    }

完成一個(gè)對(duì)象創(chuàng)建后,系統(tǒng)會(huì)給對(duì)象的屬性賦予默認(rèn)的初始值;同時(shí),對(duì)象之間的直接復(fù)制,本質(zhì)上是將兩個(gè)對(duì)象指向了同一個(gè)地址值。這點(diǎn)跟數(shù)組的情況非常類似:

        // 對(duì)象內(nèi)屬性的默認(rèn)初始化值
        Person p2 = new Person();
        System.out.println(p2.name);   // null
        System.out.println(p2.age);   // 0

        // 對(duì)象復(fù)制(類似數(shù)組)
        Person p3 = new Person();
        p3 = p1;
        p3.name = "Yuki";
        System.out.println(p1.name);   // Yuki

以上代碼的內(nèi)存解析圖如下:


內(nèi)存解析圖
匿名對(duì)象

可以不定義對(duì)象的句柄,而直接調(diào)用這個(gè)對(duì)象的方法。這樣的對(duì)象叫做匿名對(duì)象。

new Person().shout(); 

使用情況:

  • 如果對(duì)一個(gè)對(duì)象只需要進(jìn)行一次方法調(diào)用,那么就可以使用匿名對(duì)象。
  • 匿名對(duì)象可作為實(shí)參傳遞給一個(gè)方法進(jìn)行調(diào)用。

比如,先聲明一個(gè)Phone的類:

class Phone{
    // 屬性
    double price;
    
    // 方法
    public void sendEmail(){
        System.out.println("Send E-mail...");
    }
    
    public void playGame(){
        System.out.println("Game Start!");
    }
    
    public void showPrice(){
        System.out.println(price);
    }
}

通過(guò)匿名對(duì)象的形式,調(diào)用其方法:

// 匿名對(duì)象
// 每一個(gè)匿名對(duì)象,都會(huì)是一個(gè)單獨(dú)的實(shí)例
new Phone().playGame();
new Phone().price = 1999;
new Phone().showPrice();   // 0.0

這里需要注意,每一個(gè)匿名對(duì)象,都是一個(gè)單獨(dú)的實(shí)例;即便上述代碼通過(guò)調(diào)用匿名對(duì)象方法對(duì)其price屬性進(jìn)行賦值,但是通過(guò)調(diào)用匿名對(duì)象方法打印出來(lái)的price值依舊是0.0,這說(shuō)明兩次調(diào)用方法的不是同一個(gè)實(shí)例。

接著,再聲明PhoneMall的類,它沒(méi)有屬性值,僅有一個(gè)通過(guò)Phone創(chuàng)建的實(shí)例作為參數(shù)、調(diào)用其方法的方法:

class PhoneMall{
    public void showPhone(Phone phone,double price){
        phone.price = price;
        System.out.println(phone.price);
        phone.sendEmail();
        phone.playGame();
    }
}

Phone的匿名對(duì)象作為實(shí)參,傳遞給方法進(jìn)行調(diào)用。以下例子是通過(guò)這樣的操作完成對(duì)匿名對(duì)象的price屬性進(jìn)行修改:

// 匿名對(duì)象的使用
PhoneMall mall = new PhoneMall();
mall.showPhone(new Phone(),2999);   // 作為形參進(jìn)行值傳遞,調(diào)用方法或者更改屬性

類的屬性

屬性是類的成員之一,同時(shí)作為類的變量存在

當(dāng)一個(gè)對(duì)象被創(chuàng)建時(shí),會(huì)對(duì)其中各種類型的成員變量自動(dòng)進(jìn)行初始化賦值,這點(diǎn)與數(shù)組十分類似:


對(duì)象屬性的初始化值
變量(補(bǔ)充)

變量分為局部變量和全局變量(成員變量),類的屬性就屬于全局變量的一種;它們之間詳細(xì)的分類和區(qū)別如下:


變量

結(jié)合之前類的屬性、以及方法的形參進(jìn)行比較,局部變量和全局變量的區(qū)別如下:


局部變量與全局變量

類的方法

  • 方法是類或?qū)ο笮袨樘卣鞯某橄?,用?lái)完成某個(gè)功能操作。在某些語(yǔ)言中也稱為函數(shù)或過(guò)程。
  • 將功能封裝為方法的目的是:可以實(shí)現(xiàn)代碼重用,簡(jiǎn)化代碼。
  • Java里的方法不能獨(dú)立存在,所有的方法必須定義在類里。
class Customer{

    // 屬性
    String name;
    int age;


    // 方法
    public void intro(){   // 無(wú)形參、無(wú)返回值
        System.out.println("Hello, nice to meet you");
    }

    public void years(int year){   // 有形參、無(wú)返回值
        age += year;
        return;    // 可省略,表示結(jié)束此方法
    }

    public String getName(){     // 無(wú)形參、有返回值
        return name;
    } 

    public String getNation(String nation, String district){    // 有形參(形參列表)、有返回值
        return nation + "," +district;
    }
}

方法的定義形式跟其返回值類型和參數(shù)有直接關(guān)系,在通過(guò)對(duì)象調(diào)用方法時(shí),也需要根據(jù)返回值類型和參數(shù)注意其格式:

        // 創(chuàng)建實(shí)例
        Customer cus1 = new Customer();

        cus1.name = "Tom";
        cus1.age = 24;

        cus1.intro();
        cus1.years(10);
        System.out.println(cus1.age);    //  34
        System.out.println(cus1.getName());
        System.out.println("I am coming from " + cus1.getNation("China","Chongqing"));

注意:

  • 方法被調(diào)用一次,就會(huì)執(zhí)行一次。
  • 沒(méi)有具體返回值的情況,返回值類型用關(guān)鍵字void表示,那么方法體中可以不必使用return語(yǔ)句。如果使用,僅用來(lái)結(jié)束方法。
  • 定義方法時(shí),方法的結(jié)果應(yīng)該返回給調(diào)用者,交由調(diào)用者處理。
  • 方法中只能調(diào)用方法或?qū)傩?,不可以在方法?nèi)部定義方法。
  • 方法結(jié)束后,方法中定義的局部變量會(huì)被釋放掉。
方法重載
  1. 在同一個(gè)類中,允許存在一個(gè)以上的同名方法,只要它們的參數(shù)個(gè)數(shù)或者參數(shù)類型不同即可。
  2. 與返回值類型無(wú)關(guān),只看參數(shù)列表,且參數(shù)列表必須不同。(參數(shù)個(gè)數(shù)或參數(shù)類型)。調(diào)用時(shí),根據(jù)方法參數(shù)列表的不同來(lái)區(qū)別。

以下三個(gè)方法彼此之間構(gòu)成重載:

    public int getSum(int i,int j){
        return (i + j);
    }
    
    public double getSum(double i,double j){
        return (i + j);
    }
    
    public String getSum(String i,String j){
        return (i + j);
    }
    
//  public int getSum(int i,int j){     // 報(bào)錯(cuò)
//      return 0;   
//  }
可變個(gè)數(shù)的形參

JavaSE 5.0 中提供了Varargs(variable number of arguments)機(jī)制,允許直接定義能和多個(gè)實(shí)參相匹配的形參。從而,可以用一種更簡(jiǎn)單的方式,來(lái)傳遞個(gè)數(shù)可變的實(shí)參。

    public void show(int i){
        System.out.println(i);
    }
    
    public void show(String i){
        System.out.println(i);
    }
    
    public void show(String ...strings){   // 未指定參數(shù)數(shù)量
        String str = "";
        for(int i = 0; i < strings.length; i++){
            str += strings[i];
        }
        System.out.println(str);
    }
    
//  public void show(String[] strings){    // 本質(zhì)上是數(shù)組形式
//  }

可變形參方法與其他同名方法之間構(gòu)成重載。

值傳遞機(jī)制
  • 若參數(shù)是基本數(shù)據(jù)類型,實(shí)參賦給形參的是實(shí)參真實(shí)存儲(chǔ)的數(shù)據(jù)值
  • 若參數(shù)是引用數(shù)據(jù)類型,實(shí)參賦給形參的是實(shí)參存儲(chǔ)數(shù)據(jù)的地址值

比如以下類中,第一個(gè)方法的形參為基本數(shù)據(jù)類型,第二個(gè)方法的形參為引用數(shù)據(jù)類型,它們同樣是執(zhí)行交換數(shù)據(jù)的功能:

class Object{
    // 屬性
    int m;
    int n;
    
    // 方法
    public void swap(int m ,int n){
        int temp = m;
        m = n; 
        n = temp;
    }
    
    public void swap(Object obj){
        int temp = obj.m;
        obj.m = obj.n; 
        obj.n = temp;
    }   
}
        // 若參數(shù)是基本數(shù)據(jù)類型,實(shí)參賦給形參的是實(shí)參真實(shí)存儲(chǔ)的數(shù)據(jù)值
        int m = 10;
        int n = 20;
        Object obj = new Object();
        obj.swap(m,n);
        System.out.println("m = "+ m +";n = " + n);   //  m = 10;n = 20
         
        
        // 若參數(shù)是引用數(shù)據(jù)類型,實(shí)參賦給形參的是實(shí)參存儲(chǔ)數(shù)據(jù)的地址值
        obj.m = 10;
        obj.n = 20;
        obj.swap(obj);
        System.out.println("obj.m = "+ obj.m +";obj.n = " + obj.n);   //  obj.m = 20; obj.n = 10

然而兩個(gè)方法的執(zhí)行結(jié)果卻大相徑庭,采用基本數(shù)據(jù)類型作為形參的方法,其實(shí)參傳遞給形參后進(jìn)行交換,完全不會(huì)影響到對(duì)象內(nèi)的屬性值;而采用引用數(shù)據(jù)類型作為形參的方法,因?yàn)橹苯咏粨Q的地址值,所以其指向的對(duì)象也會(huì)發(fā)生實(shí)質(zhì)性的交換。

遞歸方法

遞歸方法:一個(gè)方法體內(nèi)調(diào)用它自身

  • 1、方法遞歸包含了一種隱式的循環(huán),它會(huì)重復(fù)執(zhí)行某段代碼,但這種重復(fù)執(zhí)行無(wú)須循環(huán)控制。
  • 2、遞歸一定要向已知方向遞歸,否則這種遞歸就變成了無(wú)窮遞歸,類似于死循環(huán)。

比如:

    // 利用遞歸累積求和
    public int getSum(int n){
        if(n == 1){
            return 1;
        }else{
            return n + getSum(n-1);
        }
    }

當(dāng)調(diào)用getSum(100)時(shí),因?yàn)閮?nèi)部存在遞歸方法,就會(huì)調(diào)用 getSum(99) ;同理,當(dāng)調(diào)用 getSum(99) 時(shí),就會(huì)調(diào)用 getSum(98) ... ... 以此類推,最終總會(huì)調(diào)用 getSum(1) = 1 這個(gè)已知的條件,從而按原來(lái)相反的順序返回 getSum(100) 的值。

封裝與隱藏

隱藏對(duì)象內(nèi)部的復(fù)雜性,只對(duì)外公開(kāi)簡(jiǎn)單的接口,便于外界調(diào)用,從而提高系統(tǒng)的可擴(kuò)展性、可維護(hù)性。通俗的說(shuō),把該隱藏的隱藏起來(lái),該暴露的暴露出來(lái)。這就是封裝性的設(shè)計(jì)思想

比如,聲明一個(gè)Animal類,并使其legs屬性為私有的,如需通過(guò)對(duì)象對(duì)該屬性使用,則需要在類中聲明訪問(wèn)私有屬性的方法 getXxx() 和 setXxx() 。

class Animal{
    // 屬性
    String name;
    int age;
    private int legs;   // 腿的個(gè)數(shù)
    
    // 方法
    // 屬性的設(shè)置與獲取
    public void setLegs(int l){
        if(l >= 0 && l % 2 ==0){
            legs = l;
        }else{
            legs = 0;
        }
    }
    
    public int getLegs(){
        return legs;
    }
    
    // 其它函數(shù)
    public void eat(){
        System.out.println("eating...");
    }
    
    public void show(){
        System.out.println("name:"+ name +"  age:"+ age +"  legs:"+ legs);
    }
}

創(chuàng)建Animal類的實(shí)例后,無(wú)法再用 “.” 的方式訪問(wèn)其私有屬性。而應(yīng)該使用事先聲明好的 getXxx() 和 setXxx() 方法:

        Animal a = new Animal();
        a.name = "dog";
        a.age = 2;
//      a.legs = 4;    // 屬性不可見(jiàn)/隱藏,不可直接調(diào)用
        a.setLegs(4);
        System.out.println(a.getLegs());
        a.show();
權(quán)限修飾符

Java權(quán)限修飾符public、protected、(缺省)、private置于類的成員定義前,用來(lái)限定對(duì)象對(duì)該類成員的訪問(wèn)權(quán)限。


權(quán)限修飾符

類的構(gòu)造器

類的構(gòu)造器用來(lái)創(chuàng)建對(duì)象;并給對(duì)象進(jìn)行初始化。

比如聲明一個(gè)Student類:

class Student{
    // 屬性
    private String name;
    private int age;
    
    // 構(gòu)造器
    public Student(){    // 系統(tǒng)提供的默認(rèn)構(gòu)造器
        
    }
    
    public Student(String n){
        name = n;
    }
    
    public Student(String n, int a){
        name = n;
        age = a;
    }
    
    // 方法
    public void show(){
        System.out.println("Name:"+ name +"  Age:" + age);
    }
}
  1. 如沒(méi)有事先顯示定義構(gòu)造器,則系統(tǒng)默認(rèn)提供一個(gè)空參數(shù)的夠造器
  2. 一旦顯示定義了構(gòu)造器,系統(tǒng)就不會(huì)提供默認(rèn)構(gòu)造器
  3. 一個(gè)類中可以定義多個(gè)構(gòu)造器,彼此構(gòu)成重載
        Student stu = new Student();
        stu.show();
        
        Student stu1 = new Student("Kana", 16);
        stu1.show();
構(gòu)造器特征
  • 它具有與類相同的名稱
  • 它不聲明返回值類型。(與聲明為void不同)
  • 不能被static、final、synchronized、abstract、native修飾,不能有return語(yǔ)句返回值

關(guān)鍵字(this、package、import)

this

當(dāng)this在方法內(nèi)部使用,即這個(gè)方法所屬對(duì)象的引用;
當(dāng)this在構(gòu)造器內(nèi)部使用,表示該構(gòu)造器正在初始化的對(duì)象。

當(dāng)在方法內(nèi)需要用到調(diào)用該方法的對(duì)象時(shí),就用this。
具體的:我們可以用this來(lái)區(qū)分屬性和局部變量。
比如:this.name = name;

class Person{
    // 屬性
    private String name;
    private int age;

    // 方法
    public void setName(String name){
        this.name = name;
    }
    
    public void setAge(int age){
        this.age = age;
    }
    
    public String getName(){
        return this.name;
    }
    
    public int getAge(){
        return this.age;
    }
    
    public void show(){
        System.out.println("Name:"+this.getName()+"  Age:"+this.getAge());
    }
}

this修飾構(gòu)造器:

// 構(gòu)造器
    // this修飾/調(diào)用構(gòu)造器
    public Person(){
        // 假設(shè)對(duì)象初始化,必須輸出以下字段
        System.out.println("this is an important sentence!");
    }
    
    public Person(String name){
        this();
        this.name = name;
    }
    
    public Person(int age){
        this();
        this.age = age;
    }
    
    public Person(String name,int age){
        this(age);      // 通過(guò)this(field)來(lái)調(diào)用其他指定的構(gòu)造器
        this.name = name;
    }
package

package語(yǔ)句作為Java源文件的第一條語(yǔ)句,指明該文件中定義的類所在的包。(若缺省該語(yǔ)句,則指定為無(wú)名包)。

package project.java;

系統(tǒng)文件夾會(huì)創(chuàng)建對(duì)應(yīng)的路徑:


系統(tǒng)文件夾
import

為使用定義在不同包中的Java類,需用import語(yǔ)句來(lái)引入指定包層次下所需要的類或全部類(.*)。import語(yǔ)句告訴編譯器到哪里去尋找類。

package practice.java;

import project.java.*;

public class Test {
    public static void main(String[] args) {
        CustomerView cs = new CustomerView();
        cs.enterMainMenu();
    }
}

通過(guò)import,在當(dāng)前包(practice)中導(dǎo)入另一個(gè)包(project)的項(xiàng)目工程。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容