關於Java類和對象,你想知道的在這裏!

java類的基本組成

java做爲一門面向對象的語言, 類和對象是最重要的概念之一,下面,就讓咱們來看看java中類的基本結構是怎樣的:java

一個簡單的java類主要可由如下幾個部分(要素)組成:數組

1.實例變量函數

2.構造函數 測試

3.更改器方法this

4.訪問器方法spa

例如:命令行

class Myclass {
   field1...  // 聲明實例變量(實例域)
   field2...  // 聲明實例變量(實例域)
   constructor..   // 構造函數
   getMethod1..  // 訪問器方法1
   getMethod2..   // 訪問器方法2
   setMethod1...  // 更改器方法1
   setMethod2...  // 更改器方法2
}

也許你對java類的運用早已了熟於心了,但對結構的細化和分析有助於你進一步的瞭解對象

讓咱們看一下下面這個實例three

Myclass.java:字符串

public class Myclass {
     private String name;  // 聲明實例變量(實例域)
     public Myclass () {   // 構造函數
       name = "尚無名字";
     }
     public String getName () {   // 訪問器方法
       return name;
     }
     public void setName (String str) {  // 更改器方法
       name = str;
     }
}

Test.java:

public class Test {
   public static void main(String args []) {
     Myclass instance = new Myclass();
     System.out.println(instance.getName());  // 輸 出當前的實例變量name的值
     instance.setName("彭湖灣");    // 修改name的值
     System.out.println(instance.getName()); // 再次輸 出實例變量name的值
   }
}

結果:

尚無名字
彭湖灣

關於構造函數有幾點要注意:

1. 構造函數和類同名

2. 它沒有返回值

3. 能夠有多個構造函數,容許實現構造函數重載(下面會講)

【注意】沒有返回值意味着你不能在構造函數裏寫return XXX,或者是爲方法加上類型如public String Myclass() (具體點說,若是你在構造器裏面return一個值會直接致使報錯error,而若是你經過public String Myclass的方式加上類型,那麼這就再也不是個構造函數,而是個普通方法)

函數重載

函數重載: 對類中的一組同名函數, 根據函數實參的參數類型參數個數不一樣決定調用哪個對應的函數,這個過程,叫作函數的重載:

根據參數類型不一樣進行重載

people.java:

public class People {
   public  void print (String str) {
     System.out.println("我調用了參數類型爲String的方法!");
     System.out.println(str);
   }
   public  void print (int number) {
     System.out.println("我調用了參數類型爲int的方法!");
     System.out.println(number);
   }
}

Test.java:

public class Test {
   public static void main(String args []) {
     People people1 = new People();
     people1.print("字符串");
   }
}

輸出:

我調用了參數類型爲String的方法!
字符串

若是將Test.java中的語句換成:

People people1 = new People();
people1.print(1);

結果

我調用了參數類型爲int的方法!
1

根據參數個數不一樣進行重載

People.java:

public class People {
   public  void print (String str) {
     System.out.println("我調用了一個參數的方法!");
   }
   public  void print (String str1, String str2) {
     System.out.println("我調用了兩個參數的方法!");
   }
}

Test.java:

public class Test {
   public static void main(String args []) {
     People people1 = new People();
     people1.print("參數1", "參數2");
   }
}

輸出:

我調用了兩個參數的方法!

若是將Test.java中的語句換成:

public static void main(String args []) {
   People people1 = new People();
   people1.print("參數");
}

輸出:

我調用了一個參數的方法!

【注意】函數重載只和參數類型和參數個數有關,和返回值類型無關!! 例如public void XXX()和public String XXX()不構成重載! (這也固然會報錯,由於兩個函數重複了)同時重載也和參數的命名無關, public void XXX(String str1)和 public void XXX(String str2)是同一個函數,這和函數重載就更沒有毛線關係了

構造函數重載

和函數重載的特性一致,但有一個有趣的一點要注意: 當你沒有寫入構造函數的時候,系統會默認提供一個無參的構造函數給你, 因此就算沒有顯式地寫type 實例 = new type()也是成立的

可是! 當你寫了一個有參數的構造函數,但又沒有寫無參數的構造函數時,type 實例 = new type()就會報錯了!(由於默認的無參構造函數已經被你寫的有參數的構造函數給取代了嘛~~~~)

實例變量的默認值,和初始化實例變量

若是你聲明瞭一個實例變量,但沒有初始化它,那麼這個變量會取得一個默認值,默認值依類型決定:

這是每一個基本類型對應的默認值

boolean        false
char              '/uoooo'(null)
byte              (byte)0
short             (short)0
int                  0
long               0 (L)
float               0.0 (f)
double           0.0 (d)

對於引用類型,一概初始化爲null

例子:

Default.java:

public class Default {
   private  int number;
   private float f;
   private boolean bool;
   private char c;
   private byte b;
   public void printDefaultValues () {
     System.out.println("int的默認值:" + number);
     System.out.println("float的默認值:" + f);
     System.out.println("boolean的默認值:" + bool);
     System.out.println("char的默認值:" + c);
     System.out.println("byte的默認值:" + b);
   }
}

Test.java:

public class Test {
   public static void main(String args []) {
     Default default1 = new Default();
     default1.printDefaultValues();
   }
}

輸出

int的默認值:0
float的默認值:0.0
boolean的默認值:false
char的默認值:

通常狀況下,最好對一個實例變量進行初始化,去覆蓋掉默認值

public class Default {
   private  int number = 1;
}

訪問私有實例變量

私有變量的訪問方式我分紅兩種: 類內訪問實例訪問

(實際上二者概念上有交叉,但爲了方便說明我將二者分開了)

類內訪問:在定義一個類的時候,在類內部訪問私有變量

實例訪問: 建立對應類的一個對象,經過對象訪問

實例訪問

建立的對象不能直接訪問私有實例變量,但能經過公有的訪問器方法訪問:

例如:

People.java:

public class People {
   private String name;
   public People (String aName) {
     name = aName;
   }
   public String getName () {
     return name;
   }
}

在Test.java中,若是咱們試圖直接經過People的實例對象訪問name私有變量:

public class Test {
   public static void main(String args []) {
     People people1 = new People("彭湖灣");
     System.out.println(people1.name);  // 直接經過People的實例對象訪問name私有變量
   }
}

編譯器會友好地提示:The field People.name is not visible,並在運行時候報error,這告訴咱們不能不能經過people1.name直接訪問私有實例變量name

但咱們的訪問器方法getName是定義爲public的呀,因此咱們能經過getName方法訪問

public class Test {
   public static void main(String args []) {
     People people1 = new People("彭湖灣");
     System.out.println(people1.getName());   
   }
}

運行後輸出:

彭湖灣

私有的變量對於類實例來講本是「不可見」的,但公有的訪問器方法卻有權讓它暴露出來。

類內訪問

在類定義的代碼裏,咱們能夠自由地訪問私有實例變量,不過有一點要注意: 私有實例變量的最高訪問權限是類,而不只僅是單個對象(也就是說同一個類定義的不一樣的對象可以對各自的私有實例變量「互訪」)

例如,在下咱們經過 equalName方法判斷People類的兩個實例對象的name變量值是否相等

public class People {
   private String name;
   public People (String aName) {
     name = aName;
   }
   public boolean equalName (People other) {
     String otherName = other.name; // 訪問另外一個對象的私有的name變量
     return name.equals(otherName);
   }
}

在Test.java中:

public class Test {
   public static void main(String args []) {
     People people1 = new People("彭湖灣");
     People people2 = new People("XXX");
     People people3 = new People("彭湖灣");
     System.out.println(people1.equalName(people2));
     System.out.println(people1.equalName(people3));
   }
}

輸出結果:

false   // 說明people1和people2的name值不相等
true    // 說明people1和people3的name值相等

在equalName方法中,咱們在方法參數中聲明瞭同一個people類的另一個實例對象other,並經過other.name直接取得它的私有實例變量並在方法中使用。運行是成功的,這意爲着私有實例變量並非爲單個對象「所私有」,而是爲整個類所「私有」。 這個類下的全部對象,都擁有對同一類下某個對象的私有實例變量的直接的訪問權限

固然,不一樣類的對象, 就沒有這種直接的訪問權限了

實例變量和局部變量「交鋒」

在方法中, 能夠直接經過名稱訪問實例變量(隱式訪問),也能夠經過this去顯式訪問

事實上,如下兩種方式效果是相同的

public class People {
   private String name;
   public People (String aName) {
     name = aName; // 隱式訪問實例變量
   }
}
public class People {
   private String name;
   public People (String aName) {
     this.name = aName;   // 顯式訪問實例變量
   }
}

當局部變量和實例變量同名的時候,局部變量會覆蓋同名的實例變量,讓咱們看一個例子:

public class People {
   private String name ="實例name變量";
   public People (String name) {
     System.out.println("輸出:" + name);  //在構造函數中這樣作有些怪異,但爲了展現請不要介意
   }
}

在People類中,有一個實例變量name, 同時在構造函數中將經過參數的形式引入一個同名的局部變量

name,這個時候,咱們經過name訪問到的是局部變量name,而不是隱式訪問的實例變量name:

請看Test.java中的測試:

public class Test {
   public static void main(String args []) {
     People people1 = new People("局部name變量");
   }
}

運行後打印 

輸出:局部name變量

打印的是「局部name變量」而不是"實例name變量", 這表明, 同名的局部變量覆蓋了對應的實例變量

嗯嗯,正因如此就會產生一些問題了:咱們可能經常但願可以在構造函數中經過參數引入的局部變量的值初始化實例變量,但由於同名覆蓋的問題卻會帶來一些煩惱:

// 無效的寫法!
public class People {
   private String name
   public People (String name) {
     name = name; // 兩個都取局部變量this,固然無效了
   }
}

解決辦法有兩種:

1. 爲局部變量取另一個名稱(爲了語意的理解能夠在同名變量前加上一個字母)

public class People {
   private String name
   public People (String aName) {
     name = aName;
   }
}

2. 使用this顯式訪問實例變量,這樣就能夠「繞過」局部變量的覆蓋

public class People {
   private String name;
   public People (String name) {
     this.name = name;
   }
   public String getName () {
     return this.name;
   }
}

小小地總結一下這一小節:

1. 在方法中, 能夠直接經過名稱訪問實例變量(隱式訪問),也能夠經過this去顯式訪問實例變量

2. 當局部變量和實例變量同名的時候,局部變量會覆蓋同名的實例變量

3.  對2中形成的衝突問題,可從兩個方向解決:

  3.1 爲局部變量取另一個名稱

  3.2  使用this顯式訪問實例變量

靜態變量和靜態方法

當對一個實例變量加以static修飾符的時候,它就變成了一個靜態變量。(「靜態」這個詞可能並不太能讓你推測出它的意義和用法)

例如:

public static int  peopleTotal = 0; // 這裏設爲public只是爲了演示

靜態變量是隸屬於類的,而不是隸屬於對象,也就是說,靜態變量和實例變量是剛好對立的兩種變量,前者屬於類,後者屬於類建立的實例對象。

對於實例變量:每建立一個對象,就會建立一份類內全部實例變量的拷貝

對於靜態變量: 不管建立多少個對象, 靜態變量從始至終都只有一份,爲全部對象「共享」

示例(訪問靜態變量):

People.java:

public class People {
   private String name;
   public static int  peopleTotal = 0; // 這裏設爲public只是爲了演示
   public People (String name) {
     this.name = name;
     peopleTotal++; // 每次調用構造函數時候,使得類的peopleTotal靜態變量加1
   }
}

Test.java:

public class Test {
   public static void main(String args []) {
         // 建立三個People對象
     People people1 = new People("one");
     People people2 = new People("tow");
     People people3 = new People("three");
     System.out.print(People.peopleTotal); // 輸出此時的peopleTotal
   }
}

結果: 輸出3

咱們須要注意兩點

第一點,咱們最終是經過People.peopleTotal去訪問的peopleTotal, 這進一步證實了它是屬於類的,而不屬於對象

第二點,最後結果輸出了3, 這說明:peopleTotal靜態變量「從始至終都只有一個」, 連續的三次實例化而調用的構造函數, 使它經歷了從0到1,1到2和2到3的過程(反之,若是peopeTotal是實例變量,那麼由於每一個對象都對這個有個拷貝,則最終輸出的應該是1(0+1=1))

經過靜態方法訪問靜態變量

若是一個方法僅僅用到靜態變量的話,那麼這個方法應該做爲一個靜態方法使用而不是實例方法,也就是說, 它要加上static修飾符,例如:

public static int getPeopleTotal

讓咱們對上述的例子稍加改造:

People.java

public class People {
   private String name;
   private static int  peopleTotal = 0; // 和上面的例子不一樣,這裏的靜態變量是私有的
   public People (String name) {
     this.name = name;
     peopleTotal++; // 每次調用構造函數時候,使得類的peopleTotal靜態變量加1
   }
   public static int getPeopleTotal () {
     return peopleTotal; // 經過靜態方法訪問私有靜態變量
   }
}

Test.java:

public class Test {
   public static void main(String args []) {
     People people1 = new People("one");
     People people2 = new People("tow");
     People people3 = new People("three");
     System.out.print(People.getPeopleTotal()); // 輸出peopleTotal
   }
}

結果 輸出3

靜態方法的各類性質和靜態變量相似,它也是隸屬於類而不是對象

上面咱們都在強調一點,靜態變量, 靜態方法隸屬於類而不是對象,那麼你可能會所以問幾個問題:

1.對象可以訪問靜態變量和靜態方法嗎? (靜態變量/方法是否必定要由類調用?)

2.類內定義的實例方法能訪問靜態變量嗎? (類內的靜態變量是否必定要由靜態方法調用?)

下面我將對這兩個問題一一解答:

對象可以訪問靜態變量和靜態方法嗎?

能夠!

實際上,你能夠用對象訪問靜態變量或方法,但你最好不要這樣作,由於這容易形成混淆,具體一點說是混淆咱們對「靜態」的認知,實際上和對象毫無關係的靜態變量用對象來調用,會形成咱們在理解上的一種矛盾,這下降了程序的可讀性。 用類名調用靜態方法纔是建議的操做

// 雖然能達到相同效果但不要這麼作!!
Test.java
public class Test {
   public static void main(String args []) {
     People people1 = new People("one");
     People people2 = new People("tow");
       People people3 = new People("three");
     System.out.print(people1.getPeopleTotal()); // 用people1對象調用了靜態方法
   }
}

類內定義的實例方法能訪問靜態變量嗎?

(類內的靜態變量是否必定要由靜態方法調用?)

能夠!

答案固然是能夠的,但請注意,若是一個方法僅僅只使用到靜態變量(例如咱們這個例子),那它應該做爲一個靜態方法,而不是實例方法,緣由和上面相同,這容易混淆咱們對於靜態變量的認知

// 雖然能達到相同效果但不要這麼作!!
People.java:
public class People {
   private String name;
   private static int  peopleTotal = 0;
   public People (String name) {
   this.name = name;
   peopleTotal++; // 每次調用構造函數時候,使得類的peopleTotal靜態變量加1
   }
   public  int getPeopleTotal () {
   return peopleTotal; // 經過實例方法訪問私有靜態變量
   }
}

Test.java:

public class Test {
   public static void main(String args []) {
     People people1 = new People("one");
     People people2 = new People("tow");
           People people3 = new People("three");
     System.out.print(people1.getPeopleTotal()); // 用people1對象調用了實例方法!!
   }
}

【注意】上面說法的前提「一個方法僅僅只使用到靜態變量」,若是一個方法不只僅用到靜態變量,狀況就不同了

main方法

我想每個寫java的筒子們應該都很熟悉的一段代碼是public static void main(String args []){ ....}

1.在Java中,main()方法是Java應用程序的入口方法

2. java規範要求必須寫成public static void main(String 字符串 []){ ....}的形式

除了字符串數組名稱能夠任意取,static,void和參數一概不可缺乏

例如我若是省略static就會致使這一段報錯:

String args [] 的做用

這個字符串數組是用來接收命令行輸入參數的,命令行的參數之間用空格隔開

例子:

public class TestMain {
    public static void main(String args[]){
        System.out.println("打印main方法中的輸入參數!");
        for(int i=0;i<args.length;i++){
            System.out.println(args[i]);
        }
    }
}

假設要執行的這個java文件的路徑是D:\Study\basetest\src, 則:

D:\Study\basetest\src>javac TestMain.java
 
D:\Study\basetest\src>java TestMain 1 2 3
打印main方法中的輸入參數!
1
2
3

[完]

相關文章
相關標籤/搜索