java入門---對象和類&概念詳解&實例


    Java作為一種面向對象語言。支持以下基本概念:

 

  • 多態
  • 繼承
  • 封裝
  • 抽象
  • 對象
  • 實例
  • 方法
  • 重載

    這篇文章,我們主要來看下:

 

  • 對象:對象是類的一個實例(對象不是找個女朋友),有狀態和行為。例如,一條狗是一個對象,它的狀態有:顏色、名字、品種;行為有:搖尾巴、叫、吃等。
  • :類是一個模板,它描述一類對象的行為和狀態。

    下圖中男孩女孩為類,而具體的每個人為該類的對象:


    現在讓我們深入了解什么是對象。看看周圍真實的世界,會發現身邊有很多對象,車,狗,人等等。所有這些對象都有自己的狀態和行為。拿一條狗來舉例,它的狀態有:名字、品種、顏色,行為有:叫、搖尾巴和跑。對比現實對象和軟件對象,它們之間十分相似。軟件對象也有狀態和行為。軟件對象的狀態就是屬性,行為通過方法體現。在軟件開發中,方法操作對象內部狀態的改變,對象的相互調用也是通過方法來完成。

    接下來,我們來看下類。類可以看成是創建Java對象的模板,通過下面一個簡單的類來理解下Java中類的定義:

 

public class Dog{     String breed;     int age;     String color;     void barking(){     }      void hungry(){     }       void sleeping(){     } } 

    一個類可以包含以下類型變量:

 

  • 局部變量:在方法、構造方法或者語句塊中定義的變量被稱為局部變量。變量聲明和初始化都是在方法中,方法結束后,變量就會自動銷毀。
  • 成員變量:成員變量是定義在類中,方法體之外的變量。這種變量在創建對象的時候實例化。成員變量可以被類中方法、構造方法和特定類的語句塊訪問。
  • 類變量:類變量也聲明在類中,方法體之外,但必須聲明為static類型。

    一個類可以擁有多個方法,在上面的例子中:barking()、hungry()和sleeping()都是Dog類的方法。然后我們來看下構造方法。每個類都有構造方法。如果沒有顯式地為類定義構造方法,Java編譯器將會為該類提供一個默認構造方法。在創建一個對象的時候,至少要調用一個構造方法。構造方法的名稱必須與類同名,一個類可以有多個構造方法。下面是一個構造方法示例:

public class Puppy{
    public Puppy(){
    }
 
    public Puppy(String name){
        // 這個構造器僅有一個參數:name
    }

}

    然后我們來看下對象創建。對象是根據類創建的。在Java中,使用關鍵字new來創建一個新的對象。創建對象需要以下三步:

 

  • 聲明:聲明一個對象,包括對象名稱和對象類型。
  • 實例化:使用關鍵字new來創建一個對象。
  • 初始化:使用new創建對象時,會調用構造方法初始化對象。

    下面是一個創建對象的例子:

public class Puppy{
   public Puppy(String name){
      //這個構造器僅有一個參數:name
      System.out.println("小狗的名字是 : " + name );
   }
   public static void main(String []args){
      // 下面的語句將創建一個Puppy對象
      Puppy myPuppy = new Puppy( "tommy" );
   }

}

    編譯並運行上面的程序,會打印出下面的結果:

 

小狗的名字是 : tommy

    然后我們來通過已創建的對象來訪問成員變量和成員方法,如下所示:

 

/* 實例化對象 */
ObjectReference = new Constructor(); /* 訪問類中的變量 */ ObjectReference.variableName; /* 訪問類中的方法 */ ObjectReference.MethodName(); 

    下面的例子展示如何訪問實例變量和調用成員方法:

public class Puppy{
   int puppyAge;
   public Puppy(String name){
      // 這個構造器僅有一個參數:name
      System.out.println("小狗的名字是 : " + name );
   }
 
   public void setAge( int age ){
       puppyAge = age;
   }
 
   public int getAge( ){
       System.out.println("小狗的年齡為 : " + puppyAge );
       return puppyAge;
   }
 
   public static void main(String []args){
      /* 創建對象 */
      Puppy myPuppy = new Puppy( "tommy" );
      /* 通過方法來設定age */
      myPuppy.setAge( 2 );
      /* 調用另一個方法獲取age */
      myPuppy.getAge( );
      /*你也可以像下面這樣訪問成員變量 */
      System.out.println("變量值 : " + myPuppy.puppyAge );
   }

}

    編譯並運行上面的程序,產生如下結果:

 

小狗的名字是 : tommy 小狗的年齡為 : 2 變量值 : 2

    然后我們來看下源文件的聲明規則。當在一個源文件中定義多個類,並且還有import語句和package語句時,要特別注意這些規則:

 

  • 一個源文件中只能有一個public類
  • 一個源文件可以有多個非public類
  • 源文件的名稱應該和public類的類名保持一致。例如:源文件中public類的類名是Employee,那么源文件應該命名為Employee.java。
  • 如果一個類定義在某個包中,那么package語句應該在源文件的首行。
  • 如果源文件包含import語句,那么應該放在package語句和類定義之間。如果沒有package語句,那么import語句應該在源文件中最前面。
  • import語句和package語句對源文件中定義的所有類都有效。在同一源文件中,不能給不同的類不同的包聲明。

    類有若干種訪問級別,並且類也分不同的類型:抽象類和final類等。除了上面提到的幾種類型,Java還有一些特殊的類,如:內部類、匿名類。

    然后來看下java包。包主要用來對類和接口進行分類。當開發Java程序時,可能編寫成百上千的類,因此很有必要對類和接口進行分類。

    再來看下import語句。在Java中,如果給出一個完整的限定名,包括包名、類名,那么Java編譯器就可以很容易地定位到源代碼或者類。Import語句就是用來提供一個合理的路徑,使得編譯器可以找到某個類。例如,下面的命令行將會命令編譯器載入java_installation/java/io路徑下的所有類:

 

import java.io.*;

    在下面例子中,我們創建兩個類:EmployeeEmployeeTest。首先打開文本編輯器,把下面的代碼粘貼進去。注意將文件保存為 Employee.java。Employee類有四個成員變量:name、age、designation和salary。該類顯式聲明了一個構造方法,該方法只有一個參數。


import java.io.*;
 
public class Employee{
   String name;
   int age;
   String designation;
   double salary;
   // Employee 類的構造器
   public Employee(String name){
      this.name = name;
   }
   // 設置age的值
   public void empAge(int empAge){
      age =  empAge;
   }
   /* 設置designation的值*/
   public void empDesignation(String empDesig){
      designation = empDesig;
   }
   /* 設置salary的值*/
   public void empSalary(double empSalary){
      salary = empSalary;
   }
   /* 打印信息 */
   public void printEmployee(){
      System.out.println("名字:"+ name );
      System.out.println("年齡:" + age );
      System.out.println("職位:" + designation );
      System.out.println("薪水:" + salary);
   }
}

    程序都是從main方法開始執行。為了能運行這個程序,必須包含main方法並且創建一個實例對象。下面給出EmployeeTest類,該類實例化2個 Employee 類的實例,並調用方法設置變量的值。將下面的代碼保存在 EmployeeTest.java文件中:

import java.io.*;
public class EmployeeTest{
 
   public static void main(String args[]){
      /* 使用構造器創建兩個對象 */
      Employee empOne = new Employee("RUNOOB1");
      Employee empTwo = new Employee("RUNOOB2");
 
      // 調用這兩個對象的成員方法
      empOne.empAge(26);
      empOne.empDesignation("高級程序員");
      empOne.empSalary(1000);
      empOne.printEmployee();
 
      empTwo.empAge(21);
      empTwo.empDesignation("菜鳥程序員");
      empTwo.empSalary(500);
      empTwo.printEmployee();
   }
}


    編譯這兩個文件並且運行 EmployeeTest 類,可以看到如下結果:

 

$ javac EmployeeTest.java $ java EmployeeTest 名字:RUNOOB1 年齡:26 職位:高級程序員 薪水:1000.0 名字:RUNOOB2 年齡:21 職位:菜鳥程序員 薪水:500.0

    我們要知道java因強制要求類名(唯一的public類)和文件名統一,因此在引用其它類時無需顯式聲明。在編譯時,編譯器會根據類名去尋找同名文件。

    package 的作用就是 c++ 的 namespace 的作用,防止名字相同的類產生沖突。Java 編譯器在編譯時,直接根據 package 指定的信息直接將生成的 class 文件生成到對應目錄下。如 package aaa.bbb.ccc 編譯器就將該 .java 文件下的各個類生成到 ./aaa/bbb/ccc/ 這個目錄。

    import 是為了簡化使用 package 之后的實例化的代碼。假設 ./aaa/bbb/ccc/ 下的 A 類,假如沒有 import,實例化A類為:new aaa.bbb.ccc.A(),使用 import aaa.bbb.ccc.A 后,就可以直接使用 new A() 了,也就是編譯器匹配並擴展了 aaa.bbb.ccc. 這串字符串。

    了解了上面的東西,我們就來看下,為什么java文件中只能含有一個public類?java 程序是從一個 public 類的 main 函數開始執行的,(其實是main線程),就像 C 程序 是從 main() 函數開始執行一樣。 只能有一個 public 類是為了給類裝載器提供方便。 一個 public 類只能定義在以它的類名為文件名的文件中。每個編譯單元(文件)都只有一個 public 類。因為每個編譯單元都只能有一個公共接口,用 public 類來表現。該接口可以按照要求包含眾多的支持包訪問權限的類。如果有一個以上的 public 類,編譯器就會報錯。 並且 public類的名稱必須與文件名相同(嚴格區分大小寫)。 當然一個編譯單元內也可以沒有 public 類。

    然后我們再來看下,java中成員變量與類變量的區別。首先,由static修飾的變量稱為靜態變量,其實質上就是一個全局變量。如果某個內容是被所有對象所共享,那么該內容就應該用靜態修飾;沒有被靜態修飾的內容,其實是屬於對象的特殊描述。不同的對象的實例變量將被分配不同的內存空間, 如果類中的成員變量有類變量,那么所有對象的這個類變量都分配給相同的一處內存,改變其中一個對象的這個類變量會影響其他對象的這個類變量,也就是說對象共享類變量。

 

   1、兩個變量的生命周期不同

      成員變量隨着對象的創建而存在,隨着對象的回收而釋放。

      靜態變量隨着類的加載而存在,隨着類的消失而消失。

   2、調用方式不同

      成員變量只能被對象調用。

      靜態變量可以被對象調用,還可以被類名調用。

   3、別名不同

      成員變量也稱為實例變量。

      靜態變量也稱為類變量。

   4、數據存儲位置不同

      成員變量存儲在堆內存的對象中,所以也叫對象的特有數據。

      靜態變量數據存儲在方法區(共享數據區)的靜態區,所以也叫對象的共享數據。

    static 關鍵字,是一個修飾符,用於修飾成員(成員變量和成員函數)。來看下特點:

 

   1、想要實現對象中的共性數據的對象共享。可以將這個數據進行靜態修飾。

   2、被靜態修飾的成員,可以直接被類名所調用。也就是說,靜態的成員多了一種調用方式。類名.靜態方式。

   3、靜態隨着類的加載而加載。而且優先於對象存在。

    再來看下弊端:

 

   1、有些數據是對象特有的數據,是不可以被靜態修飾的。因為那樣的話,特有數據會變成對象的共享數據。這樣對事物的描述就出了問題。所以,在定義靜態時,必須要明確,這個數據是否是被對象所共享的。

   2、靜態方法只能訪問靜態成員,不可以訪問非靜態成員。

      因為靜態方法加載時,優先於對象存在,所以沒有辦法訪問對象中的成員。

   3、靜態方法中不能使用this,super關鍵字。

      因為this代表對象,而靜態在時,有可能沒有對象,所以this無法使用。

    什么時候定義靜態成員呢?或者說:定義成員時,到底需不需要被靜態修飾呢?

    成員分兩種:

 

   1、成員變量。(數據共享時靜態化)

      該成員變量的數據是否是所有對象都一樣:

      如果是,那么該變量需要被靜態修飾,因為是共享的數據。 

      如果不是,那么就說這是對象的特有數據,要存儲到對象中。 

   2、成員函數。(方法中沒有調用特有數據時就定義成靜態)

      如果判斷成員函數是否需要被靜態修飾呢?

      只要參考,該函數內是否訪問了對象中的特有數據:

      如果有訪問特有數據,那方法不能被靜態修飾。

      如果沒有訪問過特有數據,那么這個方法需要被靜態修飾。

    然后就來看下成員變量和靜態變量的區別:

 

   1、成員變量所屬於對象。所以也稱為實例變量。

      靜態變量所屬於類。所以也稱為類變量。

   2、成員變量存在於堆內存中。

      靜態變量存在於方法區中。

   3、成員變量隨着對象創建而存在。隨着對象被回收而消失。

      靜態變量隨着類的加載而存在。隨着類的消失而消失。

   4、成員變量只能被對象所調用 。

      靜態變量可以被對象調用,也可以被類名調用。

    所以,成員變量可以稱為對象的特有數據,靜態變量稱為對象的共享數據。

    然后看類變量類型。1.局部變量:在方法、構造方法、語句塊中定義的變量。其聲明和初始化在方法中實現,在方法結束后自動銷毀:

 

public class ClassName{     public void printNumber(){         int a;     }     // 其他代碼 }

    2.成員變量:定義在類中,方法體之外。變量在創建對象時實例化。成員變量可被類中的方法、構造方法以及特定類的語句塊訪問:

 

public class ClassName{     int a;     public void printNumber(){         // 其他代碼     } }

    3.類變量:定義在類中,方法體之外,但必須要有 static 來聲明變量類型。靜態成員屬於整個類,可通過對象名或類名來調用:

 

public class ClassName{     static int a;     public void printNumber(){         // 其他代碼     } }

    再來看下類的構造方法:

 

1、構造方法的名字和類名相同,並且沒有返回值。

2、構造方法主要用於為類的對象定義初始化狀態。

3、我們不能直接調用構造方法,必須通過new關鍵字來自動調用,從而創建類的實例。

4、Java的類都要求有構造方法,如果沒有定義構造方法,Java編譯器會為我們提供一個缺省的構造方法,也就是不帶參數的構造方法。

    完事看下new關鍵字的作用:

 

1、為對象分配內存空間。

2、引起對象構造方法的調用。

3、為對象返回一個引用。

    有時候,你想擁有所有對象通用的變量。 這是通過靜態修改器完成的。 在其聲明中具有靜態修飾符的字段稱為靜態字段或類變量。 他們與類相關,而不是與任何對象相關聯。這就是是 Oracle 對於靜態的定義。

    然后我們來使用java類實例化一個對象的時候,如果在類中不顯式的聲明其構造函數,則會使用一個默認的構造函數來初始化對象:

 

//一個沒有顯式聲明構造函數的類 Public class People{     int age = 23;     Public void getAge(){         System.out.print("the age is "+age);     } } //用這個類來實例化一個對象 People xiaoMing = new People(); // People() 是People類的默認構造函數,它什么也不干 xiaoMing.getAge();//打印年齡

    我們也可以在聲明類的時候顯式的聲明一個構造函數:

 

//一個帶顯式構造函數的類 Public class People{     int age = 23;         Public void getAge(){         System.out.print("the age is "+ age);     }     // 顯式聲明一個帶參數的構造函數,用於初始化年齡     Public People(int a){         this.age = a;     } } //用這個類來實例化一個對象 People xiaoMing = new People(20); // 使用帶參數的構造函數來實例化對象 xiaoMing.getAge(); // 打印出來的年齡變為20

    再來看下成員變量與局部變量的區別:

 

1.聲明位置不同

成員變量也就是屬性,在類中聲明的。

局部變量,在方法中聲明或代碼塊中聲明。

2.初始值不同

成員變量如果沒有賦值則是有默認值的,數據類型不同則默認值不同。

局部變量是沒有默認值,也就是說必須先聲明,再賦值,最后才使用。

3.在一個類中,局部變量可以與成員變量同名,但是局部變量優先,如果非要訪問成員變量的屬性,則必須使用 this.color

this 代表當前這個對象,也就是當前誰調用這個方法則這個對象就是誰。

    還有對象與引用的區別。對象是具體的一個實例,如:new Student(); new 表示創建一個對象,並在堆內存中開辟一塊空間。引用名稱是存放的對象的地址。

    內部類:將一個類的定義放在另一個類的定義內部,這就是內部類。如同一個人是由大腦、肢體、器官等身體結果組成,而內部類相當於其中的某個器官之一,例如心臟:它也有自己的屬性和行為(血液、跳動)。顯然,此處不能單方面用屬性或者方法表示一個心臟,而需要一個類,而心臟又在人體當中,正如同是內部類在外部內當中。然后看個不用內部類的例子:

 

public class Person { private int blood; private Heart heart; } public class Heart { private int blood; public void test() { System.out.println(blood); } }

    看個使用內部類的例子:

 

public class Person { private int blood; public class Heart { public void test() { System.out.println(blood); } } public class Brain { public void test() { System.out.println(blood); } } }

    看下內部類的優缺點:

 

  • 優點:可訪問外部類私有屬性(心臟可訪問身體的血液,而不是外部抽血)。
  • 缺點:破壞原有類的程序結構(屬性、構造方法、普通方法、內部類)。

    然后看下應用中的實例:

 

//外部類 class Out { private int age = 12; //內部類 class In { public void print() { System.out.println(age); } } } public class Demo { public static void main(String[] args) { Out.In in = new Out().new In(); in.print(); //或者采用下種方式訪問 /* Out out = new Out(); Out.In in = out.new In(); in.print(); */ } }

    運行結果是12。從上面的例子不難看出,內部類其實嚴重破壞了良好的代碼結構,但為什么還要使用內部類呢?因為內部類可以隨意使用外部類的成員變量(包括私有)而不用生成外部類的對象,這也是內部類的唯一優點。如同心臟可以直接訪問身體的血液,而不是通過醫生來抽血。程序編譯過后會產生兩個 .class 文件,分別是 Out.class 和 Out$In.class。其中 $ 代表了上面程序中 Out.In 中的那個。Out.In in = new Out().new In() 可以用來生成內部類的對象,這種方法存在兩個小知識點需要注意:

 

  • 1.開頭的 Out 是為了標明需要生成的內部類對象在哪個外部類當中。
  • 2.必須先有外部類的對象才能生成內部類的對象,因為內部類的作用就是為了訪問外部類中的成員變量。

    如果對這部分內部類感興趣的小伙伴們可以看下 Java 內部類詳解 java 中的內部類總結

    這次的分享就到這里了。有點繁瑣,但是很重要哦。如果感覺不錯的話,請多多點贊支持哦。。。

  原文地址:https://blog.csdn.net/luyaran/article/details/80092771


免責聲明!

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



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