對象和類-02


  面向對象就是使用對象進行程序設計(是一種通過對象的方式,把現實世界映射到計算機模型的一種編程方法)。對象代表現實世界中可以明確標識的一個實體。例如:一個學生,一張桌子,一個圓,一個按鈕甚至一筆貸款都可以看着一個對象。每個對象都有自己獨特的標識、狀態和行為。

  • 一個對象的狀態(state,也稱未特征(property)或屬性(attribute))是由具有當前值的數據域來表示的。例如:圓對象具有一個數據域radius,它是標識圓的屬性。一個矩形對象具有數據域width和height,它們都是矩形的屬性。java使用變量定義數據域。
  • 一個對象的行為(behavior,也稱為動作(action))是由方法定義的。調用對象的一個方法就是要求對象完成一個動作。例如:可以為圓設置半徑,可以計算圓的面積,還可以獲取它的周長等。java使用方法定義動作。

  現實世界中,我們定義了“學生”這種抽象概念,而具體的學生則是“peppa”、“suzy”、“emily”等一個個具體的學生。所以,“學生”可以定義為一個類(class),而具體的學生則是類的一個實例(instance)

  所以,只要理解了class和instance的概念,基本上就明白了什么是面向對象編程。

  使用一個通用類來定義同一類型的對象。類是一個模板,藍本或者說是合約,用來定義對象的數據域是什么以及方法是做什么的。一個對象是類的一個實例。可以從一個類中創建多個實例。創建實例的過程稱為實例化。對象(object)和實例(instance)經常是可以互換的。類和對象之間的關系類似於⬇

  可以用一種配方做出任意多的冰淇淋處來。下圖展示名為Circle的類和它的三個對象。

  class是一種對象模版,它定義了如何創建實例,因此,class本身就是一種數據類型:

package edu.uestc.avatar;

/**
 * 每個對象都具有自己獨特的標識、狀態和行為
 *    狀態也稱為屬性或者特征。用數據域(成員變量)描述
 *       行為也稱為動作。通過成員方法描述
 * 使用類描述同一類型的對象
 * 類是對象模板、藍本或者說是合約。用來定義對象的數據域是什么以及方法是做什么的
 */
public class Circle {
    //通過數據域描述對象的屬性(狀態)
    public double radius;
    
    /**
     * 構造方法在使用new關鍵字創建對象時被調用
     *         構造方法作用:一般用作對象的初始化
     * 構造方法是一種特殊的方法:
     * 1、構造必須具有和所在類形同的名字(必須和類名相同)
     * 2、構造方法沒有返回值類型,連void都沒有
     * 3、使用new創建對象時會調用構造方法,作用為初始化對象
     * 
     * 構造方法也可以進行重載
     * 
     * 如果類中沒有定義構造方法,編譯器會自動添加一個公共的無參的構造方法(默認),如果已經定義了構造方法,編譯器不再添加
     * 一般構造定義在數據域下
     */
    public Circle() {
        System.out.println("調用無參構造方法");
                radius = 1;
    }
    public Circle(double newRadius) {
        System.out.println("初始化圓的半徑為:" + newRadius);
        radius = newRadius;
    }
    /**
     * 成員方法描述對象的行為:動作(計算圓的面積)
     * @return 圓的面積
     */
    public double getArea() {
        return 3.14 * radius * radius;
    }
    
    /**
     * 對象的行為/動作
     * 調用一個對象的方法就是要求對象完成一個動作
     * @return 該圓的周長
     */
    public double getPerimeter() {
        return 3.14 * 2 * radius;
    }

}

  而instance是對象實例,instance是根據class創建的實例,可以創建多個instance,每個instance類型相同,但各自屬性可能不相同:

package edu.uestc.avatar;

public class CircleTest {
    public static void main(String[] args) {
        Circle circle1 = new Circle();//調用的對應的構造方法
        double perimeter1 = circle1.getPerimeter();
        System.out.println(circle1 + "==>radius:" + circle1.radius + "==>area:" + circle1.getArea() + "==>perimeter:" + perimeter1);
        
        Circle circle2 = new Circle(25);
        System.out.println(circle2 + "==>radius:" + circle2.radius + "==>area:" + circle2.getArea() + "==>perimeter:" + circle2.getPerimeter());
        
        Circle circle3 = new Circle(125);//調用的對應的構造方法
        System.out.println(circle3 + "==>radius:" + circle3.radius + "==>area:" + circle3.getArea() + "==>perimeter:" + circle3.getPerimeter());
    }
}

  要想使用對象,必須先構造對象並指定其初始狀態。和創建數組一樣,通過new操作符從構造方法創建一個對象。new Circle()創建一個半徑為1的對象,new Circle(25)創建一個半徑為25的對象,new Circle(125)創建一個半徑為125的對象.

  這三個對象(通過circle1,circle2,circle3來引用)有不同的數據,但是有相同的方法。因此可以使用getArea()方法計算它們各自的面積。這三個對象是相互獨立的。可以使用點操作符(.)通過對象引用訪問數據域及調用方法。

  數據域radius稱為實例變量,因為它依賴於某個具體的實例。基於同樣的原因,getArea()及getPerimeter()方法稱為實例方法,因為只能在具體的實例上調用它。調用對象上的實例方法的過程稱為調用對象。

使用構造方法構造對象

  構造方法在使用new操作符創建對象的時候被調用。構造方法時一種特殊的方法:

  • 構造方法必須具備和所在類相同的名字
  • 構造方法沒有返回值類型
  • 構造方法是在創建一個對象使用new操作符時調用的。構造方法的作用是初始化對象。

  構造方法與它所在的類具有完全相同的名字。和其它方法一樣,構造方法也可以重載(也就是說,可以有多個同名構造方法,但它們有不同的參數列表),這樣更易於用不同的初始數據值來構造對象。一個類可以不定義構造方法。在這種情況下,編譯器回自動添加一個方法體為空的公共的無參構造方法。這個構造方法稱為默認構造方法。當且僅當類中沒有明確定義任何構造方法時才會自動提供它。

通過引用變量訪問對象

  新創建的對象在內存中被分配空間。它們可以通過引用變量來訪問。對象的數據和方法可以通過點操作符(.)通過對象的引用變量進行訪問。

//聲明對象引用變量、創建對象以及將對象的引用賦值給這個變量
Circle circle1 = new Circle();

  變量circle1存放的是對Circle對象的一個引用。在創建一個對象后,它的數據域和方法可以使用點操作符(.)來調用和訪問。該操作符也稱為對象成員訪問操作符。

  例如:circle1.radius引用circle1的半徑,而circle1.getArea()調用circle1的getArea方法。方法作為對象上的操作被調用。

  數據域radius稱作實例變量,因為它依賴於某個具體的實例。基於同樣的原因,getArea()方法稱為實例方法,因為只能在具體的實例上調用它。調用對象上的實例方法的過程稱為調用對象。

引用數據域和null值

  數據域也可能是引用類型的。例如:

class Student{
    String name; //引用類型,默認值為null
    int age; //數值型默認值為0
    boolean isScienceMajor; //boolean類型默認值為false
    char gender; //字符型默認值為'\u0000'
}

  如果一個引用類型沒有引用任何對象,那么這個數據域就有一個特殊的java值null。null同true和false一樣都是一個直接量。true和false是boolean類型的直接量,null是引用類型直接量。

  引用類型數據域的默認值為null,數值型數據域默認值為0,boolean類型數據域默認值為false,字符型數據域默認值為'\u0000'。java沒有給方法中的局部變量賦默認值,必須對其進行初始化才能使用。

public static void main(String[] args) {
    Student student = new Student();
    System.out.println("name:" + name);
    System.out.println("age:" + age);
    System.out.println("isScienceMajor:" + isScienceMajor);
    System.out.println("gender:" + gender);
        
    //局部變量未初始化使用
    int x;
    String y;
    System.out.println("x:" + x);//編譯不通過
    System.out.println("y:" + y);
}

  注意:NullPointerException是一種常見的運行時異常,當調用值為null的引用變量上的方法時會發生此類異常。在通過引用變量調用一個方法前。確保先將對象引用賦值給這個變量。

基本類型變量和引用類型變量的區別

  每個變量都代表一個存儲值的內存位置。聲明一個變量時,就是告訴編譯器這個變量可以存放什么類型的值。對基本類型變量來說,對應內存所存儲的值是基本類型。對引用類型變量來說,對應內存所存儲的值是一個引用,是對象的存儲地址。例如:Date對象birthday的值存的是一個引用。它指明這個Date對象存儲在內存中的什么位置。

  將一個變量賦值給另一個變量時,另一個變量就被賦予同樣的值。對基本類型變量而言,就是將一個變量的實際值賦給另一個變量。對引用變量而言,就是將一個變量的引用賦給另一個變量。如下圖所示,賦值語句i = j將基本類型變量j的值復制給基本類型變量i;對引用變量來講,賦值語句deadline = birthday是將birthday的引用賦給deadline。賦值之后,變量birthday和deadline指向同一個對象。

  注:所有的Java對象都存儲在堆中。當一個對象包含另一個對象變量時,它只是包含着另一個堆對象的指針。在C++中,指針十分令人頭疼,因為它們很容易出錯。稍不小心就會創建一個錯誤的指針,或者內存管理出問題。在Java語言中,這些問題都不復存在。如果使用一個沒有初始化的指針,運行時系統將會產生一個運行時錯誤,而不是生成一個隨機的結果。同時,不必擔心內存管理問題,垃圾回收器會處理相關的事宜。

 使用Java中預定義的類

  在使用java開發應用程序,我們將頻繁的使用到Java類庫里的類來開發程序。下面介紹一個典型的類——Date和LocalDate

  可以使用Date類中的無參構造方法為當前的日期和時間創建一個實例。它的getTime()方法返回從GMT時間1970年1月1日至今流逝的時間。它的toString()方法返回日期和時間的字符串。Date類還有另外一個構造方法Date(long elapseTime),可以用它創建一個Date對象。

public class DateDemo {
    public static void main(String[] args) throws ParseException {
        System.out.println(System.currentTimeMillis());
        //為當前時間創建Date對象
        Date date = new Date();
        System.out.println(date);//調用的date.toString();
        
        //date.setTime(0);//為date設置一個新的流逝時間
        /*
         * 對Date進行格式化(字符串)
         * pattern:
         *         y:year
         *         M:month
         *         d:date
         *      h:12小時的小時
         *      H:24小時的小時
         *      m:minutes
         *      s:seconds
         */
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //將date對象轉為指定格式的字符串
        System.out.println(sdf.format(date));
        
        //將指定格式的字符串轉為Date對象
        String pattern = "2012-03-30 14:21:38";
        Date date1 = sdf.parse(pattern);
        System.out.println(date1);
    }
}

  Date類的實例有一個狀態,即特定的時間點。盡管在使用Date類時不必知道這一點,但時間是用距離一個固定時間點的毫秒數(可正可負)表示的,這個時間點就是所謂的紀元( epoch),它是UTC時間1970年1月1日00:00:00。UTC就是Coordinated Universal Time(國際協調時間),與大家熟悉的GMT(即Greenwich Mean Time,格林尼治時間)一樣,是一種實用的科學標准時間。

  但是,Date類對於處理人類記錄日期的日歷信息並不是很有用,如“December 31,1999”。這種特定的日期描述遵循了世界上大多數地區使用的Gregorian 陽歷。但是,同樣的這個時間點采用中國或希伯來的陰歷來描述就很不一樣了,倘若我們有來自火星的顧客,基於他們使用的火星歷來描述這個時間點就更不一樣了。

  類庫設計者決定將保存時間與給時間點命名分開。所以標准Java類庫分別包含了兩個類:一個是用來表示時間點的Date類;另一個是用大家熟悉的日歷表示法表示日期的LocalDate類。Java 8引入了另外一些類來處理日期和時間的不同方面——有關內容參見后續博客。

  將時間度量與日歷分開是一種很好的面向對象設計。通常,最好使用不同的類表示不同的概念。

//不要使用構造器來構造LocalDate類的對象。實際上,應當使用靜態工廠方法( factorymethod),它會代表你調用構造器。
LocalDate localDate = LocalDate.now();
//可以提供年、月和日來構造對應一個特定日期的對象:
LocalDate newDate = LocalDate.of(2008,10,20);
//一旦有了一個LocalDate對象,可以用方法 getYear、getMontValue和 getDayOfMonth得到年、月和日:
int year = newDate.getYear(); // 2008
int month = newDate.getMonthvalue(); // 10
int day = newDate.getDayOfMonth(); // 20

  看起來這似乎沒有多大的意義,因為這正是構造對象時使用的那些值。不過,有時可能有一個計算得到的日期,然后你希望調用這些方法來了解它的更多信息。例如,plusDays方法會得到一個新的LocalDate,如果把應用這個方法的對象稱為當前對象,這個新日期對象則是距當前對象指定天數的一個新日期:

LocalDate aThousandDaysLater = newDate.plusDays ( 1000) ;
year = aThousandDaysLater.getYear(); 
month = aThousandDaysLater.getMonthvalue(); aThousandDaysLater.getDayOfMonth(); 

  LocalDate類封裝了實例字段來維護所設置的日期。如果不查看源代碼,就不可能知道類內部的日期表示。當然,封裝的意義就在於內部表示並不重要,重要的是類對外提供的方法。

Random類

  前面我們經常使用Math.random()來獲取一個0.0到1.0(不包括1.0)之間的隨機double型值。另一種產生隨機數的方法是使用java.uitl.Random類,它可以產生一個int、long、double、float和boolean型值。創建一個Random對象時,必須指定一個種子或者使用默認的種子。種子是一個用於初始化一個隨機生成器的數字。無參構造方法使用當前已經流逝的時間作為種子,創建一個Random對象。如果兩個Random對象有相同的種子,那么它們將產生相同的數列(軟件測試中非常有用)。

public class RandomDemo {
    /**
     * 可以使用Math.random()獲取一個0.0到1.0(不含)之間的隨機double型值
     * 使用Random產生隨機的int、long、float、double、boolean值
     * 
     * Random():以當前時間作為種子創建Random對象
     * Random(seed:long):以特定值seed作為種子創建隨機對象
     * 
     * nextInt():int 返回隨機的int值
     * nextInt(n:int):int 返回一個0到n(不含)之間的隨機整數
     * nextLong():long
     * nextFloat():float
     * nextDouble():double
     * nextBoolean():boolean
     */
    public static void main(String[] args) {
        Random random = new Random();
        System.out.println("隨機的int值:" + random.nextInt());
        System.out.println("隨機的int值[0--100):" + random.nextInt(100));
        System.out.println("隨機的long值:" + random.nextLong());
        System.out.println("隨機的float值:" + random.nextFloat());
        System.out.println("隨機的double值:" + random.nextDouble());
        System.out.println("隨機的boolean值:" + random.nextBoolean());
        
        /*
         * 如果種子數相同,產生的隨機序列也是相同
         */
        Random random1 = new Random(10);
        for(int i = 0; i < 10; i++)
            System.out.print(random1.nextInt(100) + " ");
        System.out.println();
        Random random2 = new Random(10);
        for(int i = 0; i < 10; i++)
            System.out.print(random2.nextInt(100) + " ");
    }
}

static

  靜態變量
public class Student{
    int id;
    static int nextId;
    String name;
}

  靜態變量被類中的所有對象所共享。Student的實例域id和name稱為實例變量。實例變量是綁定到某個特定實例的。它是不能被同一個類的不同對象所共享的。例如,假設創建了如下兩個對象:

Student peppa = new Student();
Student suzy = new Student();

  peppa中的name和suzy中的name是不相關的,它們存儲在不同的內存位置。peppa中name的變化不會影響suzy中的name,反之亦然。

  靜態變量也稱為類變量,它被該類的所有實例所共享。靜態變量將變量值存儲在一個公共的內存地址。因為它是公共地址,所以如果某一個對象修改了靜態變量的值,那么同一個類的所有對象都會受到影響。java支持靜態方法和靜態變量,無須創建類的實例就就可以調用靜態方法。

   靜態常量

  類中的常量是被該類的所有對象所共享的。因此,常量應該聲明為final static,例如,Math類中的常量PI是如下定義的:

    pulbic final static double PI = 3.1415926538979323846;

  靜態方法

  靜態方法是不在對象上執行的方法,比如,Math類的pow方法就是一個靜態方法。表達式:Math.pow(a,b);會計算冪ab。在完成運算時,它並不使用任何Math對象。

  Student類的靜態方法不能訪問id及name實例字段,因為它不能在對象上執行操作。但是,靜態方法可以訪問靜態字段。下面是這樣一個靜態方法的示例:

public static int getNextId() {
     return nextId;
}

  可以通過類名來調用這個方法:Student.getNextId();

  這個方法可以省略關鍵字static嗎?答案是肯定的。但是,這樣一來,你就需要通過Student類對象的引用來調用這個方法。

  注:可以使用對象調用靜態方法,這是合法的。例如,如果peppa是一個 Student對象,可以用peppa.getNextId()代替Student.getNextId()。不過,這種寫法很容易造成混絹,其原因是getNextId方法計算的結果與 peppa毫無關系。我們建議使用類名而不是對象來調用靜態方法。

  在下面兩種情況下可以使用靜態方法:

  • 方法不需要訪問對象狀態,因為它需要的所有參數都通過顯式參數提供(例如:Math.pow)。
  • 方法只需要訪問類的靜態字段(例如:Student.getNextId)。
  初始化塊  

  前面已經講過兩種初始化數據字段的方法:

  • 在構造器中設置值
  • 在聲明中賦值。

  實際上,Java還有第三種機制,稱為初始化塊( initialization block)。在一個類的聲明中,可以包含任意多個代碼塊。只要構造這個類的對象,這些塊就會被執行。例如,

public class Student {
    /**
     * 學生id,用於唯一標識該學生
     */
    int id;
    /**
     * 下一個id號
     */
    static int nextId;
    /**
     * 學生姓名
     */
    String name;
    
    {
        id = nextId++;
    }
    public Student() {
        
    }
    public Student(String name) {
        this.name = name;
    }
}

  在這個示例中,無論使用哪個構造器構造對象,id字段都會在對象初始化塊中初始化。首先運行初始化塊,然后才運行構造器的主體部分。

  這種機制不是必需的,也不常見。通常會直接將初始化代碼放在構造器中。

  靜態代碼塊

  如果類的靜態字段需要很復雜的初始化代碼,那么可以使用靜態的初始化塊。

  將代碼放在一個塊中,並標記關鍵字static。下面是一個示例。其功能是將學生ID的起始值賦子一個小於10000的隨機整數。

import java.util.Random;

public class Student {
    /**
     * 學生id,用於唯一標識該學生
     */
    int id;
    /**
     * 下一個id號
     */
    static int nextId;
    /**
     * 學生姓名
     */
    String name;

    static{
         var generator = new Random();
         nextId = generator.nextInt(10000); }
    
    {
        id = nextId++;
    }
    public Student() {
        
    }
    public Student(String name) {
        this.name = name;
    }
    /**
     * 實例域id的訪問器
     * @return id實例域值
     */
    public int getId() {
        return id;
    }
    /**
     * 實例域id修改器
     * @param id id值
     */
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public static int getNextId() {
        return nextId;
    }
}

  在類第一次加載的時候,將會進行靜態字段的初始化。與實例字段一樣,除非將靜態字段顯式地設置成其他值,否則默認的初始值是0、false或null。所有的靜態字段初始化方法以及靜態初始化塊都將依照類聲明中出現的順序執行:靜態代碼塊>main>構造代碼塊>構造器>普通代碼塊。

可見性修飾符

  可見性修飾符可以用於確定一個類以及他的成員的可見性。可以在類、方法、數據域前使用public修飾符,表示他們可以被任何其他類訪問。如果沒有使用可見性修飾符,那么默認類、方法和數據域可以被同一個包中的任何一個類訪問。這稱為包私有(package-private)或包內訪問(package-access)。

  protected允許子類訪問父類中的數據域或方法,但不允許非子類訪問這些數據域和方法。

  private修飾符限定方法和數據域只能在自己的類中訪問。注意修飾符private只能應用在類成員上,修飾符public可以應用在類或類成員上。在局部變量上使用public和private都會導致編譯錯誤。在大多數情況下構造方法都是公共的,但如果想防止用戶創建類的實例,就使用私有構造方法,實例化時會提示構造方法不可視錯誤。例如Math類所有方法都是靜態方法,所以為防止用戶創建Math對象,其構造方法定義如下

private Math(){
}
數據域封裝

  在前面的程序中,Student類的數據域可以直接修改。這不是一個好的做法,因為:

  首先,數據可能被篡改。例如:nextId是用來計算下一個id值的,但是它可能會被錯誤地設置為一個任意值(例如:Student.nextId = -10).

  其次,它使類變得難以維護,同時容易出現錯誤。假如在其它程序已經使用Student類之后想修改id以確保id是一個非負數。因為使用該類的客戶可以直接修改id(例如:peppa.id= -5),所以,不僅要修改Student,而且還要修改使用Student類的這些程序。

  為了避免對數據域的直接修改,應該使用private修飾符將數據域聲明為私有的,這稱為數據域封裝。在定義私有數據域的類外的對象是不能訪問這個數據域的。但是經常會有客戶端需要獲取、修改數據域的情況。為了能夠訪問私有數據域,可以提供一個訪問器返回數據域的值(get方法)。為了更新一個數據域,可以提供一個修改器給數據域設置新值(set方法)。

public class Student {
    /**
     * 學生id,用於唯一標識該學生
     */
    private int id;
    /**
     * 下一個id號
     */
    private static int nextId;
    /**
     * 學生姓名
     */
    private String name;
    
    {
        id = nextId++;
    }
    public Student() {
        
    }
    public Student(String name) {
        this.name = name;
    }
    /**
     * 實例域id的訪問器
     * @return id實例域值
     */
    public int getId() {
        return id;
    }
    /**
     * 實例域id修改器
     * @param id id值
     */
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public static int getNextId() {
        return nextId;
    }
}

向方法傳遞對象參數

  給方法傳遞一個對象,是將對象的引用傳遞給方法。java只有一種參數傳遞方式:值傳遞(pass-by-value)

package edu.uestc.avatar;

public class CircleTest {
    public static void printArea(Circle circle, int times) {
        System.out.println("Radis\tArea");
        for(int i = 1; i <= times; i++) {
            circle.setRadius(i);
            System.out.println(circle.getRadius() + "\t" + String.format("%.5f", circle.getArea()));
        }
    }
    
    public static void main(String[] args) {
       Circle circle = new Circle();
       int times = 5;
         printArea(circle, times); 
    } 
}    

  針對基本數據類型,傳遞的是基本數據類型值

  針對引用數據類型,傳遞的是引用

對象數組

  數組既可以存儲基本數據類型,也可以存儲對象。對象的數組實際上是引用變量的數組。

不可變對象和類

  通常,創建一個對象后,它的內容是允許之后改變的。有時需要創建一個一旦創建其內容就不能再改變的對象。稱這種對象為一個不可變對象,而它的類稱為不可變類。例如:String類就是不可變的。要使一個類稱為不可變的,它必須滿足:

  • 所有的數據域都是私有的
  • 沒有修改器方法
  • 沒有一個返回指向可變數據域的引用的訪問器方法
import java.util.Date;

public class Employee {
    private static int nextId;
    private int id;
    private String name;
    private Date hireDate;
    public Employee(String name) {
        this.id = nextId;
        nextId++;
        this.name = name;
        this.hireDate = new Date();
    }
    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public Date getHireDate() {
        //返回的是Date對象的一個引用。通過這個引用可以改變hireDate的值
        //return hireDate;
        //可以修改為:
        return (Date)hireDate.clone();
    }
        
}

成員變量VS局部變量

  對象的屬性就是成員變量。局部變量的聲明和使用都在一個方法的內部。

       共同點:

      1.都是變量,他們的定義形式相同:類型 變量名 = 初始化值;

                 2.都有作用域:作用域是在一對大括號內

       不同點:1.內存中存放的位置不同:

                     成員變量存放在堆空間內

                     局部變量存放在棧空間內

              2.聲明的位置不同(作用域不同):

                     成員變量聲明在類的內部,方法的外部,作用整個類;

                     局部變量聲明在方法的內部,從它聲明的地方開始到包含它最近的塊結束。

              3.初始化值不同

                     成員變量可以不賦初值,其默認值按照其數據類型來定

                     局部變量必須顯式地賦初值

              4.權限修飾符不同

                     成員變量的權限修飾符有四個:public (default) protected private

                     局部變量沒有權限修飾符,其訪問權限依據其所在的方法而定(與方法的訪問權限相同)

  如果一個局部變量和一個成員變量具有相同的名字,那么局部變量優先,而同名的類變量將被隱藏。例如:

public class Demo{
     private int x = 0;
     private int y = 0;

     public void test(){
          int x = 100;
          System.out.println("x = " + x);
          System.out.println("y = " + y);
     }
}
用var聲明局部變量

  在Java 10中,如果可以從變量的初始值推導出它們的類型,那么可以用var關鍵字聲明局部變量,而無須指定類型。例如,可以不這樣聲明:

  Circle circle = new Circle(10);

  只需要寫以下代碼:

  var circle = new Circle(10);

  這一點很好,因為這樣可以避免重復寫類型名Circle。

  從現在開始,倘若無須了解任何Java API就能從等號右邊明顯看出類型,在這種情況下我們都將使用var表示法。對Java APl有了更多使用經驗后,你可能會希望更多地使用var關鍵字。

  注意var關鍵字只能用於方法中的局部變量。參數和數據域的類型必須聲明。

this引用

   關鍵字this引用對象自身(自身對象的引用)。this指向調用對象本身的引用名。可以使用this關鍵字引用對象的實例成員。

public class Circle { 
    private double radius;/**
     * 行為:計算該圓的面積
     * @return 圓面積
     */
    public double getArea() {
        //省略了this,return 3.14 * this.radius * this.radius;
        return 3.14 * radius * radius;
    }
}

  this關鍵字可以用於引用類的隱藏數據域。例如,再數據域的set方法中,經常將數據域名用作參數名。在這種情況下,這個數據域在set方法中被隱藏。為了給它設置新值,需要在方法中引用隱藏的數據名。隱藏的靜態變量可以簡單通過"類名.靜態變量"的方式引用。隱藏的實例變量就需要使用this來引用。

public class Circle { 
    private double radius;
    private static int numberOfObjects;
    /**
     * 關鍵字this是指調用實例方法setRadius的對象
     * @param radius 半徑
     */
    public void setRadius(double radius) {
        this.radius = radius;
    }

    public static void setNumberOfObjects(int numberOfObjects){
          Circle.numberOfObjects = numberOfObjects;
    }
}

  關鍵字this可以用於調用同一個類的另一個構造方法。例如

public class Circle {
    private double radius;

    /**
     * java規定:在構造方法中使用this(參數列表)調用構造方法應在任何其它可執行語句之前出現(出現在第一句)
     * @param newRadius 半徑
     */
    public Circle() {
        this(1.0);
    }
    
    public Circle(double radius) {
        this.radius = radius;
    }
}

  如果一個類有多個構造方法,最好盡可能使用this(參數列表)實現它們。這樣做通常可以簡化代碼,使類易於閱讀和維護。

 


免責聲明!

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



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