天天看點

基礎一:一切都是對象概述用引用操作對象必須由你建立所有對象永遠不需要銷毀對象方法、參數和傳回值static關鍵字

概述

OOP-面向對象程式設計(Object Oriented Programming),在Java中(幾乎)一切都是對象。

用引用操作對象

在Java中一切都是被看作為對象,是以可以采用單一固定的文法。

盡管一切都看做對象,但操作的标示符實際上僅僅是對象的一個“引用”(reference)。

如果想操作一個字元串,則可以建立一個String 引用:

String s ;           

複制

但是這裡建立的僅僅是引用,而不是對象。是以如果要操作s,這會傳回錯誤。這是因為s實際上并沒有與任何對象關聯.

錯誤如下所示:

基礎一:一切都是對象概述用引用操作對象必須由你建立所有對象永遠不需要銷毀對象方法、參數和傳回值static關鍵字

是以一種安全的做法就是:建立一個引用的同時便進行初始化

String s = "abc";           

複制

必須由你建立所有對象

一旦建立了一個引用,就希望它能與一個新的對象相關聯。

通常使用new操作符來實作這一目的。比如

String s = new String("abc");           

複制

存儲到什麼位置

程式運作時,對象是怎樣放置安排的呢? 特别是記憶體是怎樣配置設定的呢?

其實有五個不同的地方可以存儲資料:

名稱 說明
寄存器 最快的存儲區,位于存儲器内部,但是寄存器的數量極其有限,按需配置設定。你不能直接控制,也不能在程式中感覺到寄存器存在的任何迹象。
堆棧 位于通用RAM(随機通路存儲器)中,但通過堆棧指針可以從處理器那裡獲得直接支援。堆棧指針向下移動—>配置設定新的記憶體,向上移動—>釋放記憶體。這種配置設定存儲的方法效率僅次于寄存器。 一般來講,引用存放在堆棧中,Java對象并不存儲在其中。
一種通用的記憶體池(也位于RAM中),用于存放所有的Java對象。堆不同于堆棧的好處是:編譯器不需要知道存儲的資料在堆裡存活多長時間。 是以在堆裡配置設定存儲有很大的靈活性。這種靈活性必須付出相應的代價:比用堆棧進行配置設定存儲需要更多的時間
常量存儲 常量值通常存放在程式代碼内部,永遠不會被改變。
非RAM存儲 資料完全存活于程式之外,比如 流對象 和 持久化對象。

特例:基本類型

在程式設計中常用到一系列類型,他們需要特殊對待,可以把他們想象成基本類型。

之是以特殊對待,是因為new将對象存儲在“堆”中,故用new建立一個對象–特别是小的、簡單的變量,往往不是很有效。

是以,Java采用了和C,C++相同的方法,也就是不用new建立,而是建立一個并非是引用的“自動“變量。 這個變量直接存儲”值“,并置于堆棧中,是以更高效。

Java要确定每種基本類型所占存儲控件的大小,它們的大小并不像其他語言那樣随着機器硬體架構的變化而變化。

基本類型 大小 最小值 最大值 包裝類型
boolean Boolean
char 16-bit Unicode 0 Unicode 2^16-1 Character
byte 8-bits -128 +127 Byte
short 16-bits -2^15 +2^15-1 Short
int 32-bits -2^31 +2^31-1 Integer
long 64-bits -2^63 +2^63-1 Long
float 32-bits IEEE754 IEEE754 Float
double 64-bits IEEE754 IEEE754 Double
void Void

基本類型具有的包裝器類,使得可以在堆中建立一個非基本的對象,用來表示對應的基本類型。比如:

char c = 'x';
Character ch = new Character(c);
或者:
Character ch  = new Character('x');           

複制

Java SE5的自動包裝功能自動的将基本類型轉換為包裝器類型

Character ch = 'x';           

複制

并可以反向轉換:

char c = ch;           

複制

高精度數字:

Java提供了2個高精度計算的類

BigInteger BigDecimal.

雖然他們大體上屬于包裝器類的範疇,但是卻沒有對應的基本類型。

  • 這兩個類都有自己的一系列方法,類似于我們針對主類型執行的操作,也就是說能用 int 或float 做的事情,用BigInteger和BigDecimal 一樣可以做,隻是必須換用方法調用,而不是使用運算符。此外由于牽涉更多,是以運算速度會慢一點總之我們犧牲了速度,但換來了精度。
  • BigInteger支援任意精度的整數,也就是說我們可精确表示任意大小的整數值;同時在運算過程中不會丢失任何資訊;
  • 在BigInteger類中有所有的基本算術運算方法,如加、減、乘、除,以及可能會用到的位運算如或、異或、非、左移、右移等。
  • 從數值上比較兩個 BigDecimal 值時,應該使用 compareTo() 而不是 equals()。
  • 要小心使用 BigDecimal(double) 構造函數, 因為如果不了解它,會在計算過程中産生舍入誤差。請使用基于整數或 String 的構造函數。
  • 由于 BigDecimal 對象是不可變的,這些方法中的每一個都會産生新的 BigDecimal 對象。是以,因為建立對象的開銷,BigDecimal 不适合于大量的數學計算,但設計它的目的是用來精确地表示小數。如果您正在尋找一種能精确表示如貨币量這樣的數值,則 BigDecimal 可以很好地勝任該任務。

永遠不需要銷毀對象

作用域

作用域由花括号的位置決定。

{
            // x available
            int x = 12 ;
            System.out.println("x:" + x );
            {
                // Both x & y available
                int y = 9 ;
                System.out.println("x:" + x + ",y:" + y);
            }
            // only x available
            System.out.println("x:" + x );
        }           

複制

在作用域中定義的變量隻可用于作用域結束之前。

對象的作用域

Java對象不具備和基本類型一樣的生命周期。

當使用new建立一個java對象時,它可以存活于作用域之外。

比如

{
    String s = new String("sss");
}// end of scope           

複制

引用s在作用域終點就消失了,但是s指向的對象任然占據這記憶體空間。

我們無法在這個作用域之後通路這個對象,因為對它唯一的引用已經超出了作用域的範圍。

事實證明,由new建立的對象,隻要你需要就會一直保留下去。

那java如何防止這些對象填滿記憶體空間,進而阻塞你的程式呢?

Java中有一個垃圾回收器,用來監視用new建立的所有對象,并辨識那些不會被再引用的對象。随後,釋放這些對象占用的記憶體空間,以便提供給其他新的對象使用。

建立新的資料類型:類

如果一切都是對象,那什麼決定了某一類對象的外觀和行為呢? 換句話說 什麼确定了對象的類型?

在Java中使用class這個關鍵字

class ATypeName {
    // class body gose here 
}           

複制

執行個體化

ATypeName  a = new ATypeName();           

複制

字段和方法

一旦定義了一個類,就可以在類中設定兩種類型的元素:字段+方法。

字段可以是任何類型的對象,可以通過起引用與其進行通信;也可以是基本類型中的一種。

如果字段是某個對象的引用,那麼必須初始化該引用,以便使其與一個實際的對象相關聯。

每個對象都有用來存儲其字段的空間; 普通字段不能在對象間共享。

class  DataOnly{
            int i ;
            double d ;
            boolean b ;
        }           

複制

盡管這個類除了存儲資料之外什麼也不能做,但是依然可以建立它的一個對象:

DataOnly data = new DataOnly();           

複制

可以給字段指派,但首先必須知道如何引用一個對象的成員:

objectReference.member

例如:

data.i = 10;
data.d = 1.1;
data.b = false;           

複制

基本成員預設值

若類的某個成員是基本類型資料,即使沒有初始化,Java會確定它有一個預設值。

當變量作為類的成員變量使用時,Java才確定給定其預設值,以確定那些是基本類型的成員變量得到初始化,防止産生程式錯誤。

不過最好明确的對變量進行初始化。

上述確定初始化的方法并不适用于“局部變量”(即并非某個類的字段)。

如下:

在某個方法中定義

int x ;           

複制

這是不會被自動化初始為0 ,如果未明确的指派,在編譯時會抛出異常

基礎一:一切都是對象概述用引用操作對象必須由你建立所有對象永遠不需要銷毀對象方法、參數和傳回值static關鍵字

方法、參數和傳回值

Java的方法決定了一個對象能接收什麼樣的的消息。 參數清單給出了要傳給方法的資訊的類型和名稱。 方法名和參數清單唯一的辨別出某個方法。

Java中的方法隻能作為類的一部分建立。 方法隻能通過對象才能被調用(static方法是針對類調用的,并不依賴于對象的存在),且這個對象必須能執行這個方法的調用。

如下:

objectName.methodName(arg1,arg2,arg3);           

複制

參數清單

像java中任何傳遞對象的場合一樣,這裡傳遞的實際上也是引用(對于基本類型是一個類外。通常盡管傳遞的是對象,而實際上傳遞的對象的引用。)

并且引用的類型必須正确。

比如 參數類型為String ,則必須傳遞一個String對象,否則編譯器抛出異常。

假設某個方法接收String為其參數,具體定義如下,該方法必須置于某個類的定義内才能被正确的編譯。

int storage(String s){
    return s.length();
}           

複制

通過上面的例子,我們還可以了解到return關鍵字的用法。

  • 代表已經執行完畢,離開此方法
  • 如果該方法有傳回值,需要放到return後
boolean flag(){ return true;}
double naturalLogBase(){ return 2.879;}

void nothing(){return ;}
void nothing2(){}           

複制

若傳回類型是void ,return關鍵字的作用隻是用來退出方法。是以沒有必要到方法結束時才離開,可以在任何地方離開。

但如果傳回類型不是void ,無論在何處傳回,編譯器都會強制傳回一個正确類型的傳回值。

static關鍵字

通常來說,當建立一個類時,就是在描述那個類的對象的外觀與行為。

除非用new建立那個類的對象,否則,實際上并沒有擷取到任何對象, 執行new 來建立對象時,資料存儲空間才能被配置設定,其方法才能被外界調用。

有兩種情況是以上方法無法解決的:

1. 隻想為某特定域配置設定單一存儲空間,而不考慮究竟要建立多少對象,甚至根本就不建立對象。

2. 第二種情況是:希望某個方法不與包含它的類的任何對象關聯在一起,也就是說,即使沒有建立對象,也能夠調用該方法。

通過static關鍵字可以滿足這兩方面的需求。

當聲明一個事物是static時,也就意味着這個域或者方法不會與包含它的那個類的任何對象執行個體關聯子啊一起, 是以即使從未建立某個類的任何對象,也可以通過調用其static方法或者通路其static域。

通常你必須建立一個對象,并且用它來通路資料或者方法,因為非static域和方法必須知道他們一起運作的特定對象。

隻需要将static關鍵字放在定義之前,就可以将字段或者方法設定為static

例如

class StaticTest{
    static int i = 5;
}           

複制

即使我們創立了兩個StaticTest對象,StaticTest.i也隻有一份存儲空間,這兩個對象共享同一個i.

基礎一:一切都是對象概述用引用操作對象必須由你建立所有對象永遠不需要銷毀對象方法、參數和傳回值static關鍵字

在這裡 a.i和b.i都指向同一個存儲空間。

引用static變量的兩種方法:

  1. 可以通過一個對象去引用它,比如 上面中的 a.i
  2. 也可以通過類名直接引用,而這對于非靜态成員則不行,比如

    Demo21.i == Demo21.i

    這種方式是首選方式,推薦使用這種方式。

類似邏輯同樣也适用于 靜态方法。