日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

java的一些基本知識

系統 2051 0

對象與基本類型

幾乎所有Java 初學者都被告知,在Java里一切都被視為對象(Object),操縱對象的表示符實際上時對象的一個引用(Reference)。例如

String str; // 注意!此處創建了一個引用,而非對象

str=new String(“Hello”);// 這里創建了一個String 對象并與str相關聯

通常用new 操作符來創建一個新對象,并存儲在堆里面。 【注】具體內容可以參看 Java 堆與棧

程序設計中有一系列小的、簡單的變量(筆者是這樣認為的),將它們存儲在堆里往往并不是很高效,因此對于這些基本類型,Java 創建一個并非引用的“自動”的變量,并將其值存儲在棧中。 【注】具體內容可以參看 Java 堆與棧

Java 確定了每種基本類型所占存儲空間的大小,并且不隨計算機硬件架構的變化而變化,因此他們更具可移植性。Java 基本類型及其包裝器的具體信息參見下表:

基本類型

大小

最小值

最大值

包裝器類型

boolean

Boolean

char

16-bit

Unicode o

Unicode 264-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

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

Character ch=new Character( ‘c ’);

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

Character ch= ‘c ’;//Autoboxing

可以看到Java SE5 的自動包裝功能為我們提供了很大的方便(泛型中你會看到它的優勢),然而如果你不了解它的工作原理則會讓你陷入意想不到的困惑和麻煩之中。請看下面的例子:

      
public static void main(String args[]) { Integer i1 = 127 ; Integer i2 = 127 ; System.out.println(i1 == i2); i1 = 128 ; i2 = 128 ; System.out.println(i1 == i2); } /* Output: * true * false */

有些令人驚訝,兩個范例語法完全一樣,只不過改個數值而已,結果卻相反。這是因為在自動包裝時對于從–128 到127之間的值,它們被包裝為Integer對象后,會存在內存中被重用,而其它的值,被包裝后的Integer對象并不會被重用,即相當于每次包裝時都新建一個Integer對象。

然而下面的輸出卻是ture ,這是因為你用了n1=n2,n1只是n2的別名而已。

在看一個例子:

      
public static void main(String args[]) { Integer i1 = 12 ; Integer i2 = 12 ; System.out.println(i1 == i2); i1 = new Integer( 13 ); i2 = new Integer( 13 ); System.out.println(i1 == i2); i1 = i2 = new Integer( 14 ); System.out.println(i1 == i2); } /* Output: * true * false * true */

天吶!數字13 仿佛被詛咒了一般,==對它的判斷似乎失去了效用!事實上可憐的Java一無所知,如果你對輸出的結果感到疑惑,說明你對==和Java的存儲還不是很了解。


回頁首

== 與equals()

如果知道下面的規則,你對上面例子的輸出結果或許就不會那么疑惑了:

1. 對于基本類型,== 將比較兩邊的值是否相等;

2. 對于對象,== 則比較對象的是否指向同一個對象。

如果你仍然對輸出結果不甚明白,那么別急,關于Java 堆與棧的介紹將會讓你明了,但是在這里我還要添加關于equals()的介紹。

或許你已經被告知,要想比較對象的實際內容是否相同必須使用所有對象都適用的特殊方法equals() ,例如:

Integer n1=new Integer(13);

Integer n2=new Integer(13);

System.out.println(n1.equals(n2)); //true

這看上去的確很簡單,但是下面的例子中equals() 又要讓你失望和疑惑了:

public class Value { public int i;}

Value v1=new Value();

Value v2=new Value();

v1.i=v2.i=13;

System.out.println(v1.equals(v2)); //false

哦,它輸出了false !好吧,讓我們看看equals()方法的原型:

      
public boolean equals(Object obj) { return ( this == obj); }

再讓我們看看Integer 中的equals()方法:

      
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false ; }

OK! 一切都清楚了,繼承自Object 中的equals()方法與==沒什么兩樣,只是Integer類對equals()方法進行了重寫而已,這樣我們很容易能寫出令上面例子中System.out.println(v1.equals(v2));語句輸出true的方法


回頁首

Java 堆與棧

Java 的堆是一個位于隨機訪問存儲器(RAM )的運行時數據區。通常使用new操作符在堆中創建對象,它們不需要程序代碼來顯式的釋放。堆是由垃圾回收來負責的,堆的優勢是可以動態地分配內存大小,生存期也不必事先告訴編譯器,因為它是在運行時動態分配內存的,Java的垃圾收集器會自動收走這些不再使用的數據。但缺點是,由于要在運行時動態分配內存,存取速度較慢。

Java 的棧也位于RAM ,它的存取速度比堆要快,僅次于寄存器且據可以共享,主要存放一些基本類型的變量和對象的引用;但存在于棧中的數據大小與生存期必須是確定的,缺乏靈活性。

棧有一個很重要的特殊性,就是存在棧中的數據可以共享。假設我們同時定義:

int a = 3;

int b = 3

編譯器先處理int a = 3 ;首先它會在棧中創建一個變量為a的引用,然后查找棧中是否有3這個值,如果沒找到,就將3存放進來,然后將a指向3。接著處理int b = 3;在創建完b的引用變量后,由于在棧中查找到3這個值,便將b直接指向3。這樣,就出現了a與b同時均指向3的情況。

這時,如果再令a=4 ;那么編譯器會重新搜索棧中是否有4值,如果沒有,則將4存放進來,并令a指向4;如果已經有了,則直接將a指向這個地址。因此a值的改變不會影響到b的值。

好了,我們再來看上面的例子:

Integer i1 = 12;

Integer i2 = 12;

System.out.println(i1==i2); //true

由于是自動包裝,對于從–128 到127之間的值,它們被包裝為Integer對象后,會存在內存中被重用,因此輸出的是true;

i1=new Integer(13);

i2=new Integer(13);

System.out.println(i1==i2); //flase

由于使用的是new 操作符,而不是自動包裝功能,Java在堆里面創建了兩個Integer對象,分別與i1和i2關聯,由于==對于對象比較的是引用,所以輸出是false;

然而下面的語句中實際上只創建了一個對象,這里又出現的別名的現象

i1=i2=new Integer(14);

System.out.println(i1==i2);

因此用第一種方式創建多個int, 在內存中其實只存在一個對象而已.這種寫法有利與節省內存空間.同時它可以在一定程度上提高程序的運行速度,因為JVM會自動根據棧中數據的實際情況來決定是否有必要創建新對象。而對于Integer i = new Integer (int);的代碼,則一概在堆中創建新對象,而不管其字符串值是否相等,是否有必要創建新對象,從而加重了程序的負擔。

好了,這樣以來相信下面的程序也不會為我們帶來太多的疑惑了:

      
public static void main(String args[]) { Integer i1 = new Integer( 13 ); Integer i2 = new Integer( 13 ); int i3 = 13 ; System.out.println(i1 == i2); System.out.println(i2 == i3); System.out.println(i3 == i1); } /* Output * false * true * true */


回頁首

賦值

賦值操作符“= ”對我們來說是再熟悉不過的了。它取右邊的值(右值)復制給左邊的值(左值),左值必須是一個明確的已命名的變量。例如:

Integer n1=new Integer(13);

Integer n2=new Integer(14);

n2=n1; // 別名現象

n2=11;

System.out.println(n1); //11

了解了Java 的存儲分配就不難知道,對于基本類型復制的是值,對于對象復制的則是對象的引用。

進行賦值的時候Java 編譯器會自動檢查左值和右值的類型是否匹配,必要的時候會洗的進行類型轉換。

一方面Java 中允許我們顯式的進行類型轉換,例如:

int i=(int)1.7; //i 的值1 ,如例子所示將浮點類型轉化為整型是Java總是對數字執行截尾而非舍入

另一方面,編譯器會自動進行類型的提升,例如:

int i=13;

long l=i;

Java 的自動提升確實提供了一定的便利,然而更多的是讓我們陷入一種迷茫之中,例如:

short s=1;

s=s+1;

運行的時候編譯器會提示“可能損失精度”。首先在s=s+1; 語句中由于Java將整型常量1默認為int類型,編譯器會自動將s提升為int與1相加之后返回int類型,而s為short類型,則需要進行窄化轉換,并造成“可能損失精度“。

然而下面的語句卻能順利的通過:

short s=1;

s+=1;

許多程序員都會認為E1 op = E2 只是E1 = E1 op E2)的簡寫方式,而事實上中講到,復合賦值E1 op= E2等價于簡單賦值E1 = (T)((E1)op(E2)),其中T是E1的類型,除非E1只被計算一次(參見《Java語言規范)。可以看到復合賦值幫我們進行了顯式的類型轉換。

再來看下面的例子,

      
public static void main(String args[]) { int a = 3 ; int b = 7 ; a ^= b ^= a ^= b; System.out.println( " a= " + a + " b= " + b); } /* Output: * a=0 b=3 */

如果你了解C 語言,那么上述表達式是交換兩個int類型數據的方法之一,然而這在Java中卻不管用,得到的結果卻是a=0 b=3;

《Java 語言規范》描述到:操作符的操作數是從左向右求值的。為了求表達式x ^= expr的值,x的值是在計算expr之前被提取的,并且這兩個值的異或結果被賦給變量x。因此Java中a^=b^=a^=b;的實際行為:

      
int tmp1 = a ; // a在表達式中第一次出現 int tmp2 = b ; // b的第一次出現 int tmp3 = a ^ b ; // 計算a ^ b a = tmp3 ; // 最后一個賦值:存儲a ^ b 到 a b = tmp2 ^ tmp3 ; // 第二個賦值:存儲最初的a值到b中 a = tmp1 ^ b ; // 第一個賦值:存儲0到a中

回頁首

參考資料

1. 《Thinking in Java, Second Edition 》,Bruce Eckel,Prentice Hall

2. 《Java Puzzlers : Traps, Pitfalls, and Corner Cases 》,Joshua Bloch,Neal Gafter,Addison Wesley/Pearson

3. 《The Java Language Specification 》,James Gosling,bill Joy,Guy Steele,Addison-Wesley Professional

java的一些基本知識


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 连江县| 十堰市| 浪卡子县| 开封县| 锡林浩特市| 阿克苏市| 陆丰市| 清苑县| 广灵县| 达州市| 巩留县| 仲巴县| 马鞍山市| 渭南市| 徐闻县| 瓦房店市| 玉田县| 成武县| 广安市| 大竹县| 越西县| 大理市| 阿巴嘎旗| 炎陵县| 府谷县| 曲阜市| 尚义县| 荔浦县| 会宁县| 安顺市| 自贡市| 娱乐| 栾城县| 逊克县| 桂平市| 湟源县| 德化县| 庄浪县| 玛曲县| 蒙阴县| 石首市|