《Java8學(xué)習(xí)筆記》讀書筆記(五)

第4章 認(rèn)識(shí)對(duì)象

學(xué)習(xí)目標(biāo)
? 區(qū)分基本類型與對(duì)象類型
? 了解對(duì)象與引用的關(guān)系
? 從打包器認(rèn)識(shí)對(duì)象
? 以對(duì)象觀點(diǎn)看待數(shù)組
? 認(rèn)識(shí)字符串的特性

4.1 類與對(duì)象

第3章講的都是基本類型,這一章開始講對(duì)象類型。在Java中一切皆對(duì)象(Object),要產(chǎn)生對(duì)象必須先寫類(Class),類是對(duì)象的模版,對(duì)象是類的實(shí)例(Instance)

4.1.1 定義類

一個(gè)類就是一個(gè)模版,它包括了所有的屬性和方法,就象設(shè)計(jì)師手上的設(shè)計(jì)圖紙一樣,如果我們需要設(shè)計(jì)一個(gè)大黃鴨,那么我們首先會(huì)繪制一個(gè)大黃鴨的設(shè)計(jì)圖,上面定義了大黃鴨的大小、顏色等,我們會(huì)根據(jù)設(shè)計(jì)圖制作出實(shí)際的大黃鴨,每個(gè)大黃鴨都是同一個(gè)款式,但會(huì)擁有自己的大小,顏色。


圖4.1 大黃鴨設(shè)計(jì)、制作
如果我們要設(shè)計(jì)的就是一個(gè)關(guān)于大黃鴨的設(shè)計(jì)的軟件,那如何使用Java來編寫呢?首先就要在程序中定義類,這相當(dāng)于圖4.1中大黃鴨的設(shè)計(jì)圖:

class BigDuke{
    String color;
    int size;
}

類定義時(shí)使用class關(guān)鍵字,名稱使用BigDuck,相當(dāng)于為大黃鴨的設(shè)計(jì)圖取名叫BigDuck,大黃鴨的顏色用字符串表示,也就是color變量,可存儲(chǔ)”深黃”,”淺黃”,”大黃”等。
大黃鴨的尺寸會(huì)是’大’,’中’,’小’,所以使用了char類型。如果要在程序中,利用BigDuck在程序內(nèi)建立實(shí)例,就要使用new關(guān)鍵字。例如:

new BigDuck();

在對(duì)象術(shù)語中,這叫做實(shí)例化一個(gè)對(duì)象。如果要有個(gè)標(biāo)簽,和這個(gè)對(duì)象綁定,可以這樣聲明:

BigDuck bd;

是不是很象前面我們聲明基本變量的形式?不過Java專門為這種指向?qū)ο蟮摹白兞俊比×藗€(gè)術(shù)語,叫“引用”(Reference Name)。如果要將bd綁到新建的對(duì)象上,可以使用“=”賦值,在Java術(shù)語中,叫“將bd引用至實(shí)例化對(duì)象”。如:

BigDuck bd=new BigDuck();

圖4.2 class、new、=等語法對(duì)應(yīng)
提示:對(duì)象(Object)與實(shí)例(Instance)在Java中幾乎是等義的名詞,本書中就視為相同意義。
在BigDuck類中,定義了color與size兩個(gè)變量,以Java的術(shù)語來說,叫作定義兩個(gè)屬性(Field)成員,或叫定義兩個(gè)成員變量,這表示每個(gè)新建的BigDuck實(shí)例中都能擁有各自不同的color值與size值。(默然說話:其實(shí)簡(jiǎn)單說,就是類是一個(gè)模版,它定義的類別應(yīng)該具有的屬性,但沒有值,而實(shí)例對(duì)象則會(huì)具備相同的屬性,且每個(gè)屬性可以有不同的值。比如人類可以定義膚色與身高,然后每個(gè)人類的實(shí)例可以擁有不同的膚色值與身高值。

class BigDuck{
    String color;
    char size;
}
/**
 * 說明類和對(duì)象關(guān)系的代碼示例
 * 文件:ObjectTest.java
 * @author mouyo
 */
public class ObjectTest {
    public static void main(String[] args) {
        //實(shí)例化大黃鴨對(duì)象
        BigDuck foodDuck=new BigDuck();
        BigDuck lakeDuck=new BigDuck();
        
        //為每個(gè)大黃鴨對(duì)象的屬性賦值
        foodDuck.color="淺黃";
        foodDuck.size='小';
        lakeDuck.color="深黃";
        lakeDuck.size='大';
        
        //顯示每個(gè)大黃鴨對(duì)象的各自屬性值
        System.out.println("黃鴨飯:"+foodDuck.color+","+foodDuck.size);
        System.out.println("湖中大黃鴨:"+lakeDuck.color+","+lakeDuck.size);
    }
}

在這個(gè)ObjectTest.java中,定義了兩個(gè)類,一個(gè)是公開(public)的ObjectTest類,Java規(guī)定,公開(public)的類名必須與文件一致。另一個(gè)是非公開的BigDuck。
提示:只要有類定義,編譯程序就會(huì)產(chǎn)生一個(gè).class文件。上例中會(huì)產(chǎn)生ObjectTest.class和BigDuck.class兩個(gè)文件
程序中實(shí)例化了兩個(gè)BigDuck對(duì)象,并分別聲明了foodDuck與lakeDuck兩個(gè)引用變量,接著指定了foodDuck綁定的對(duì)象所擁有的color和size分別賦值為”淺黃”和’小’,而lakeDuck綁定的對(duì)象所擁有的color和size分別賦值為”深黃”和’大’。最后分別顯示foodDuck與lakeDuck各自擁有的屬性值:

run:
黃鴨飯:淺黃,小
湖中大黃鴨:深黃,大
成功構(gòu)建 (總時(shí)間: 0 秒)

執(zhí)行結(jié)果如上,可以看出來,每個(gè)對(duì)象都擁有自己的數(shù)據(jù),它們是相互獨(dú)立,互不影響的。(默然說話:這也就在提醒我們,當(dāng)我們進(jìn)行屬性賦值的時(shí)候,除了要關(guān)心屬性的值之外,還要關(guān)心被賦值的屬性是哪個(gè)對(duì)象,如果搞錯(cuò)了對(duì)象,那值也就是不對(duì)的了。
觀察為每個(gè)大黃鴨對(duì)象的屬性賦值的那段代碼,你會(huì)發(fā)現(xiàn)它們雖然是給不同的對(duì)象賦值,但代碼的書寫基本是一樣的。只要是一樣的代碼,我們就可以進(jìn)行模版化,讓這些代碼只寫一遍。這里我們可以使用構(gòu)造方法。構(gòu)造方法是與類名同名的方法,它沒有返回值。

public class BigDuck2 {
   String color;
   char size;
   BigDuck2(String color,char size){//構(gòu)造方法
       this.color=color;//將參數(shù)color指定給color屬性
       this.size=size;
   }
   
    public static void main(String[] args) {
        BigDuck2 foodDuck=new BigDuck2("淺黃",'小');//使用指定構(gòu)造方法建立對(duì)象
        BigDuck2 lakeDuck=new BigDuck2("深黃",'大');
        
        //顯示每個(gè)大黃鴨對(duì)象的各自屬性值
        System.out.println("黃鴨飯:"+foodDuck.color+","+foodDuck.size);
        System.out.println("湖中大黃鴨:"+lakeDuck.color+","+lakeDuck.size);
    }
}

在這個(gè)例子中,定義新建對(duì)象時(shí),必須傳入兩個(gè)參數(shù)給String類型的color與char類型size參數(shù),而構(gòu)造方法中,由于color參數(shù)與color屬性名相同,你不可以直接寫color=color,而要寫成this.color=color。
在實(shí)際使用new創(chuàng)建對(duì)象時(shí),就可以直接傳入字符串與字符,分別代表BigDuck實(shí)例的color與size值,執(zhí)行結(jié)果與上個(gè)例子相同。

4.1.2 使用標(biāo)準(zhǔn)類

第一章已經(jīng)講過,Java Se提供了標(biāo)準(zhǔn)API,這些API就是由許多類組成,你可以直接取用這些標(biāo)準(zhǔn)類,省去自己打造基礎(chǔ)的需求。下面舉兩個(gè)基本的標(biāo)準(zhǔn)類:java.util.Scannerjava.math.BigDecimal。
1.使用java.util.Scanner
目前為止的程序例子都很無聊,變量值都是寫死的,沒有辦法接受用戶的輸入。如果要在命令行模式下取得用戶輸入,我們就可以使用java.util.Scanner。

package cn.com.speakermore.ch04;

import java.util.Random;
import java.util.Scanner;//導(dǎo)入標(biāo)準(zhǔn)API中的Scanner類

/**
 * 猜數(shù)
 * @author mouyo
 */
public class Guess {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);//創(chuàng)建Scanner對(duì)象
        int number=new Random().nextInt(10);
        int guess;
        
        do{
            System.out.print("猜數(shù)(0~9)");
            guess=input.nextInt();//獲得用戶輸入的整型數(shù)
        }while(guess!=number);
        System.out.println("恭喜!猜對(duì)了!");
    }
}

由于我們不想每次都輸入java.util.Scanner,所以一開始就使用import告訴編譯器:“我需要使用java.util.Scanner,請(qǐng)幫我導(dǎo)入。”在實(shí)例化(new)Scanner對(duì)象時(shí),必須傳入System.in對(duì)象,它是一個(gè)java.io.InputStream流對(duì)象(默然說話:關(guān)于這些內(nèi)容,第10章會(huì)詳細(xì)介紹,你現(xiàn)在就當(dāng)做烏龜?shù)钠ü伞?guī)定——來照著寫就可以了)。
接下來就可以很簡(jiǎn)單的通過Scanner的對(duì)象(名字叫input)來獲得鍵盤的輸入了。大家完全不用管它是怎么獲得鍵盤輸入的,反正就是能獲得。(默然說話:這就是面向?qū)ο罄锩娴囊粋€(gè)概念:封裝。舉個(gè)生活中的例子:你只要懂得打開水龍頭,就可以得到水,而完全不用去關(guān)心水怎么是從水龍頭里流出來的。忽略細(xì)節(jié),可以讓我們更專心的做自己想要去完成的事情,而不用啥都操心,這就是封裝。后面的相關(guān)章節(jié)還會(huì)詳細(xì)闡述。
ScannernextInt()方法會(huì)查看鍵盤輸入的是不是數(shù)字,如果是數(shù)字就會(huì)接收。Scanner對(duì)每個(gè)基本類型,都會(huì)有個(gè)對(duì)應(yīng)的nextXxx()方法,如nextByte()、nextShort()、nextLong()、nextFloat()、nextDouble()、nextBoolean()等,如果要取字符串,則使用next(),如果是取一行字符串,則使用nextLine()(以換行分隔)。

提示:包是java管理類的一種方式,后面相關(guān)內(nèi)容會(huì)介紹。包名以java開頭的類,都是標(biāo)準(zhǔn)API提供的類。

2.使用java.math.BigDecimal
第2章介紹基本類型的時(shí)候有個(gè)問題:1.0-0.8的結(jié)果是多少?答案肯定不是0.2,而是0.19999999999999996。為什么?java的bug?肯定不是,因?yàn)槟阌闷渌恼Z言來算這個(gè)算式也會(huì)得到同樣的結(jié)果。
簡(jiǎn)單來說,java遵守IEEE754浮點(diǎn)數(shù)運(yùn)算規(guī)范,使用分?jǐn)?shù)與指數(shù)來表示浮點(diǎn)數(shù)。例如0.5是使用1/2來表示,0.75是使用1/2+1/4來表示,而0.1會(huì)使用1/16+1/32+1/256+…無限循環(huán)下去,無法精確表示。因而造成運(yùn)算上的誤差。
再來舉個(gè)例子,你覺得下面的程序片段會(huì)顯示什么結(jié)果?

        double a=0.1;
        double b=0.1;
        double c=0.1;
        
        if((a+b+c)==0.3){
            System.out.println("等于0.3");
        }else{
            System.out.println("不等于0.3");
        }

由于浮點(diǎn)數(shù)誤差的關(guān)系,結(jié)果是顯示“不等于0.3”。類似的例子還有很多,結(jié)論就是,如果要求精確度,那就要小心地使用浮點(diǎn)數(shù),而且別用==直接比較浮點(diǎn)數(shù)運(yùn)算結(jié)果。
那么要怎么辦能得到更好的精確度?可以使用java.math.BigDecimal類。

import java.math.BigDecimal;
/**
 *DecimalDemo.java
 * @author mouyo
 */

public class DecimalDemo {
    public static void main(String[] args) {
        BigDecimal a=new BigDecimal("1.0");
        BigDecimal b=new BigDecimal("0.8");
        BigDecimal result=a.subtract(b);
        System.out.println(result);
        System.out.println(1.0-0.8);
    }
}

創(chuàng)建BigDecimal的方法之一是使用字符串,BigDecimal在創(chuàng)建時(shí)會(huì)分析字符串,以默認(rèn)精度進(jìn)行接下來的運(yùn)算。BigDecimal提供有plus()、substract()、multiply()、divide()等方法,可以進(jìn)行加、減、乘、除等運(yùn)算,這些方法都會(huì)返回代表運(yùn)算結(jié)果的BigDecimal
上面的例子可以看到0.2的結(jié)果,再來看利用BigDecimal比較相等的例子。

import java.math.BigDecimal;

/**
 *DecimalDemo2.java
 * @author mouyo
 */
public class DecimalDemo2 {
    public static void main(String[] args) {
        BigDecimal a=new BigDecimal("0.1");
        BigDecimal b=new BigDecimal("0.1");
        BigDecimal c=new BigDecimal("0.1");
        BigDecimal result=new BigDecimal("0.3");
        
        if(a.add(b).add(c).equals(result)){
            System.out.println("等于0.3");
        }else{
            System.out.println("不等于0.3");
        }
    }
}

由于BigDecimaladd()方法都會(huì)返回代表運(yùn)算結(jié)果的BigDecimal,所以就直接利用返回再次add()。最后再調(diào)用equals()方法比較相等。最后的結(jié)果是等于0.3。

4.1.3 對(duì)象指定與相等性

在上一例中,比較兩個(gè)BigDecimal是否相等,是使用equals()方法而非使用==運(yùn)算符,為什么?前面說過,在Java中有兩大類型系統(tǒng),基本類型和引用類型,基本類型把值直接放到變量中,而引用類型是把對(duì)象的內(nèi)存地址放入變量中。
當(dāng)使用=(默然說話:記??!這個(gè)不是等號(hào),是賦值號(hào),用來把一個(gè)值放到某個(gè)變量中!)給基本變量賦值時(shí),就是把值直接放入了變量中,而引用類型變量賦值時(shí),放入的是一個(gè)對(duì)象的所在位置的地址。正因?yàn)槿绱耍?dāng)使用==進(jìn)行比較時(shí),基本變量就是比較了值是否相等(默然說話:因?yàn)榛咀兞烤捅4媪艘粋€(gè)值呀!)而引用類型變量比較的卻是內(nèi)存位置是否相等(因?yàn)橐妙愋妥兞勘4娴氖堑刂费剑?/em>)。
這是基本類型變量的代碼與示例圖,記住,基本類型保存的是值!

        int a=10;
        int b=10;
        int c=a;
        System.out.println(a==b);
        System.out.println(a==c);

圖4.3 基本變量的賦值與比較相等的結(jié)果


圖4.4 基本變量的賦值與比較相等的原理
這是引用類型變量的代碼與示例圖,記住,引用類型保存的是地址!
BigDecimal a=new BigDecimal("0.1");
BigDecimal b=new BigDecimal("0.1");
BigDecimal c=a;
System.out.println(a==b);
System.out.println(a==c);

圖4.5 引用類型變量的賦值與比較相等

圖4.6 引用類型變量的比較相等結(jié)果
使用==比較的就是變量里所保存的值是否相等,由于引用類型保存的值是對(duì)象的內(nèi)存地址,所以比較兩個(gè)引用型變量相等,就是比較兩個(gè)引用變量所引用的對(duì)象是不是同一個(gè)(默然說話:內(nèi)存地址相同,就是同一個(gè)變量,因?yàn)椴豢赡茉谕粋€(gè)內(nèi)存地址中放兩個(gè)不同的對(duì)象。),如果我們想要的結(jié)果是兩個(gè)對(duì)象的內(nèi)容是不是一樣,我們需要使用equals()方法。(默然說話:上面的程序中可以看到兩個(gè)對(duì)象都裝著“0.1”這個(gè)數(shù),所以如果我們是要兩個(gè)對(duì)象裝的內(nèi)容是不是一樣,是不能使用==來比較的,因?yàn)樗容^的是地址
提示:其實(shí)從內(nèi)存的實(shí)際運(yùn)作來看,=與==對(duì)于基本類型變量與引用類型變量的作用并沒有不同,只是因?yàn)樗鼈兯4娴闹档囊饬x不一樣,才造成了這一區(qū)別。

4.2 基本類型包裝類

基本類型long、int、double、float、boolean等,在J2SE5.0之前必須手動(dòng)使用Long、Integer、Double、Float、Boolean等打包為對(duì)象,才能當(dāng)作對(duì)象來操作。5.0之后開始自動(dòng)打包了。

4.2.1 包裝基本類型

Java的基本類型在于效率,但更多的時(shí)候,會(huì)使用類建立實(shí)例,因?yàn)閷?duì)象本身可以提供更多信息,更多方便的操作。可以使用Long、Integer、Double、Float、Boolean、Byte等類來包裝(Wrap)基本類型。
Long、Integer、Double等類就是所謂的包裝類(Wrapper),正如此名稱所示,這些類主要目的就是提供對(duì)象實(shí)例作為“殼”,將基本類型包裝在對(duì)象中,就像是將基本類型當(dāng)作對(duì)象操作。

/**
 *  IntegerDemo.java
 * @author mouyo
 */
public class IntegerDemo {
    public static void main(String[] args) {
        //基本類型
        int data1=10;
        int data2=10;
        //包裝類型
        Integer wrapper1=new Integer(data1);
        Integer wrapper2=new Integer(data2);
        //基本類型除法,只能得到整數(shù)部分,小數(shù)被舍棄
        System.out.println(data1/3);
        //使用包裝類的方法把整數(shù)轉(zhuǎn)為小數(shù),得到了有小數(shù)的結(jié)果
        System.out.println(wrapper1.doubleValue()/3);
        //使用包裝類提供的方法進(jìn)行比較,得到更多的信息
        System.out.println(wrapper2.compareTo(wrapper2));
    }
}

包裝類都放在java.lang包中,這個(gè)包是java編譯器默認(rèn)會(huì)導(dǎo)入的包,所以不需要import語句來顯示導(dǎo)入。包裝一個(gè)基本類型就是new出包裝類,然后將基本類型傳給包裝類就可以了。
基本數(shù)據(jù)類型如果都是整型,那最后的計(jì)算結(jié)果也會(huì)是整形。
如果我們期望得到小數(shù)的結(jié)果,那么可以使用包裝類的轉(zhuǎn)換方法來得到一個(gè)小數(shù),然后計(jì)算機(jī)在運(yùn)算時(shí)會(huì)自動(dòng)類型轉(zhuǎn)換為小數(shù)后再做計(jì)算,最后的結(jié)果就也是小數(shù)(默然說話:其實(shí)我們平時(shí)寫程序時(shí),是直接把整型數(shù)寫成小數(shù)。比如10/3.0,這樣的結(jié)果就會(huì)是小數(shù)了。)。
Integer提供compareTo()方法,可與另一個(gè)Integer對(duì)象比較,如果相同就返回0,如果小于傳入的對(duì)象就返回-1。否則就是1。而==和!=只能得到很少的信息。

4.2.2 自動(dòng)裝箱、拆箱

除了使用new來包裝之外,從J2SE5.0之后提供了自動(dòng)裝箱功能??梢赃@樣包裝基本類型:

Integer wrapper=10;

編譯程序會(huì)自動(dòng)判斷是否能進(jìn)行自動(dòng)裝箱,在上例如你的wrapper會(huì)被賦值為一個(gè)Integer對(duì)象。其他基本類型也是一樣的。改寫下上面的代碼:

Integer data1=10;
Integer data2=20;
System.out.println(data1.doubleValue() / 3);
System.out.println(data1.compareTo(data2));

程序看上去簡(jiǎn)潔很多,data1和data2在運(yùn)行時(shí)會(huì)自動(dòng)裝箱Integer對(duì)象。自動(dòng)裝箱還可以這樣用:

int i=0;
Integer wrapper=i;

也可以使用更一般化的Number來自動(dòng)裝箱:

Number num=3.11f;

3.11f會(huì)先被自動(dòng)裝箱為Float,然后引用給num。
Java SE 5.0開始,還可以進(jìn)行自動(dòng)拆箱,也就是把包裝類自動(dòng)取值賦給基本類型變量。如:

Integer wrapper=10;//自動(dòng)裝箱
int a=wrapper;//自動(dòng)拆箱

在運(yùn)算時(shí),也可以進(jìn)行自動(dòng)裝箱與拆箱,如:

Integer a=10;
System.out.println(i+10);
System.out.println(i++);

4.2.3 自動(dòng)裝箱、拆箱的內(nèi)幕

所謂自動(dòng)裝箱與拆箱其實(shí)只是編譯器幫我們做了本來是我們需要自己做的事情。編譯器在編譯時(shí)會(huì)根據(jù)我們所寫的代碼來決定是否進(jìn)行裝箱或拆箱。例如下面的代碼:

Integer number=100;

在Oracle的JDK中 ,編譯程序會(huì)自動(dòng)將代碼展開為:

Integer localInteger=Integer.valueOf(100);

但自動(dòng)裝拆箱其實(shí)是有問題的,例如:

Integer a=null;
int j=i;

這段代碼在編譯的時(shí)候是不會(huì)報(bào)錯(cuò)的,因?yàn)閚ull是一個(gè)特殊對(duì)象,它可以指定給任何聲明的對(duì)象,表示沒有引用到任何的內(nèi)存地址,但是一旦執(zhí)行編譯出的代碼,就會(huì)報(bào)錯(cuò),因?yàn)榫幾g后的代碼是這樣的:

Object localObject=null;
int i=localObject.intValue();

這里由于localObject對(duì)象被賦值為空,而代表沒有任何的內(nèi)存位置,所以也就不可能執(zhí)行第二句調(diào)用intValue()方法,此時(shí)計(jì)算機(jī)就會(huì)報(bào)錯(cuò)NullPointerException(空指針異常,有的教科書或老師又把它叫做空點(diǎn)異常)。表示你想調(diào)用一段根本不在內(nèi)存里存在的代碼。
除了有這方面的bug之外,還有一些稀奇古怪的現(xiàn)象。比如下面的代碼:

/**
 *  Boxing.java
 * @author mouyo
 */
public class Boxing {
    public static void main(String[] args) {
        Integer i1=100;
        Integer i2=100;
        if(i1==i2){
            System.out.println("相等");
        }else{
            System.out.println("不相等");
        }
    }
}

這個(gè)代碼沒問題,結(jié)果是相等。


圖4.7 結(jié)果相等
可是,我們只要改一下,象下面這樣:

package cn.com.speakermore.ch04;

/**
 *  Boxing.java
 * @author mouyo
 */
public class Boxing {
    public static void main(String[] args) {
        Integer i1=200;
        Integer i2=200;
        if(i1==i2){
            System.out.println("相等");
        }else{
            System.out.println("不相等");
        }
    }
}

能看出來改了哪里么?對(duì),只是把100換成了200,運(yùn)行之后的結(jié)果卻變成了不相等。


圖4.8 200之后的結(jié)果是不相等。
為何是這樣的結(jié)果,這是因?yàn)樵贗nteger的自動(dòng)裝箱過程中,它使用了valueOf()方法,而valueOf()方法會(huì)建立一個(gè)緩存,緩存那些小于128的整數(shù)。這樣,當(dāng)我們的值小于128時(shí),值相同,對(duì)象就是相同的,但是一旦大于等于128,由于沒有緩存,雖然值是相同的,但對(duì)象就會(huì)不一樣。用==比較時(shí),自然就得到了不相等的結(jié)果。
所以,結(jié)論還是前面已經(jīng)討論過的,別使用==或!=來比較兩個(gè)對(duì)象的值是否相同(因?yàn)橐眯蛿?shù)據(jù)類型都是比較的地址),而要使用equals()方法。

4.3 數(shù)組對(duì)象

數(shù)組在Java中就是對(duì)象,所以前面介紹過的對(duì)象基本性質(zhì),在操作數(shù)組時(shí)也都要注意,如引用名的聲明、=指定的作用、==與!=的比較等。

4.3.1 數(shù)組基礎(chǔ)

數(shù)組基本上是用來收集數(shù)據(jù),具有下標(biāo)(index)的數(shù)據(jù)結(jié)構(gòu),在Java中要聲明數(shù)組并初始值,可以如下:

int[] score={88,87,99,67,77,81,86,55,46,78};

這段代碼創(chuàng)建一個(gè)數(shù)組,因?yàn)槭褂胕nt[]聲明,所以會(huì)在內(nèi)存中分配長度為10的int連續(xù)空間,每個(gè)空間依次存儲(chǔ)了大括號(hào)中的整數(shù),每個(gè)整數(shù)都用一個(gè)下標(biāo)來標(biāo)識(shí),下標(biāo)從0開始,所以10個(gè)長度的數(shù)組,下標(biāo)最大就只到9。如果你使用了10或以上的數(shù)字作下標(biāo),就會(huì)拋出ArrayIndexOutOfBoundException(數(shù)組下標(biāo)越界異常)。
數(shù)組使用下標(biāo)來獲得每一個(gè)數(shù)據(jù),重點(diǎn)就是可以很方便的和循環(huán)結(jié)合,用很少的代碼對(duì)大量數(shù)據(jù)進(jìn)行批量處理:

/**
 * Score.java
 * @author mouyo
 */
public class Score {
    public static void main(String[] args) {
        int[] score={88,87,99,67,77,81,86,55,46,78};
        for (int i = 0; i < score.length; i++) {
            System.out.println("學(xué)生分?jǐn)?shù):"+score[i]);
        }
    }
}

在聲明的數(shù)組名稱旁加上[]并指定下標(biāo),就可以取得對(duì)應(yīng)值,上例從i為0-9,逐一取出值并顯示出來。


圖4.9 10個(gè)學(xué)生分?jǐn)?shù)的顯示
在Java中數(shù)組是對(duì)象,而不是單純的數(shù)據(jù)集合,數(shù)組的length屬性可以取得數(shù)組長度。也就是數(shù)組的元素個(gè)數(shù)。
其實(shí)上面這個(gè)程序可以使用更簡(jiǎn)單的方式來編寫,因?yàn)槭琼樞蛉〉綌?shù)組中每一個(gè)值,所以我們可以使用增強(qiáng)式for循環(huán),這是從JDK5開始出現(xiàn)的更方便的for循環(huán),我基本是強(qiáng)烈推薦,在需要遍歷一個(gè)數(shù)組的時(shí)候都使用增強(qiáng)式for循環(huán)。

for (int score:scores ) {
   System.out.println("學(xué)生分?jǐn)?shù):"+score);
}

這個(gè)程序片段會(huì)取得scores數(shù)組第一個(gè)元素,指定給score變量后執(zhí)行循環(huán)體,接著取得scores中第二個(gè)元素,指定給score變量后執(zhí)行循環(huán)體。依此類推,直到scores數(shù)組中所有元素都訪問完為止。將這段for循環(huán)片段取代Score類中的for循環(huán),執(zhí)行結(jié)果相同。實(shí)際上,增強(qiáng)式for循環(huán)也是Java提供的方便功能。
如果要給數(shù)組的某個(gè)元素賦值,也是要通過下標(biāo)。例如:

scores[3]=86;
System.out.println(scores[3]);

上面這個(gè)程序片段將數(shù)組中第4個(gè)元素(因?yàn)橄聵?biāo)從0開始,下標(biāo)3就是第4個(gè)元素)指定86,所以會(huì)顯示86,所以會(huì)顯示86的結(jié)果。
一維數(shù)組使用一個(gè)下標(biāo)存取數(shù)組元素,你也可以聲明二維數(shù)組,二維數(shù)組使用兩個(gè)下標(biāo)存取數(shù)組元素。例如,聲明數(shù)組來儲(chǔ)存XY坐標(biāo)位置要放的值。

/**
 * XY.java
 * @author mouyo
 */
public class XY {
    public static void main(String[] args) {
        int[][] cords={
            {1,2,3},
            {4,5,6}
        };//聲明二維數(shù)組并賦值初始值
        for(int x=0;x<cords.length;x++){//獲得有幾行
            for(int y=0;y<cords[x].length;y++){//獲得每行有幾個(gè)元素
                System.out.print(cords[x][y]+"  ");
            }
            System.out.println("");
        }
    }
}

要聲明二維數(shù)組,就是在類型關(guān)鍵詞旁加上[][]。初學(xué)者暫時(shí)將二維數(shù)組看作是一個(gè)表格會(huì)比較容易理解,由于有兩個(gè)維度,所以首先得通過cords.length得到有幾行,然后再使用cords[x].length獲得每行有幾個(gè)元素,之后再一個(gè)一個(gè)進(jìn)行輸出。
二維數(shù)組有兩個(gè)下標(biāo),所以也要使用二重嵌套循環(huán)來完成取值遍歷的代碼,同樣由于這里對(duì)下標(biāo)并沒有特別需要,所以也可以使用增強(qiáng)for循環(huán)來完成

       for(int[] row:cords){//獲得有幾行
            for(int value:row){//獲得每行幾個(gè)元素
                System.out.print(value+"  ");
            }
            System.out.println("");
        }

最后執(zhí)行結(jié)果相同。


圖4.10 二維數(shù)組執(zhí)行結(jié)果
提示:如果是三維數(shù)組,就是在類型關(guān)鍵字后使用三個(gè)[],如果是四維就是四個(gè)[]。依此類推。不過基本上是用不到如此復(fù)雜的維度,現(xiàn)代編程通常一維就足夠了,二維都基本上不用的。

4.3.2 操作數(shù)組對(duì)象

前面都是知道元素值來建立數(shù)組的例子,如果事先不知道元素值,只知道元素個(gè)數(shù),那可以使用new關(guān)鍵字指定長度的方式創(chuàng)建數(shù)組。例如:

int[] scores=new int[5];
數(shù)據(jù)類型 初始值
byte 0
short 0
int 0
long 0L
float 0.0F
double 0.0
char \u0000(即’’)
boolean false
null

在Java中只要看到new,就一定是創(chuàng)建對(duì)象(默然說話:計(jì)算機(jī)的實(shí)際操作是劃分一塊內(nèi)存空間供對(duì)象使用),這個(gè)語法其實(shí)已經(jīng)說明數(shù)組就是一個(gè)對(duì)象。使用new創(chuàng)建數(shù)組之后,數(shù)組中每個(gè)元素都會(huì)被初始化,如表4.1所示:
表4.1 數(shù)組元素初始值

數(shù)據(jù)類型 初始值
byte 0
short 0
int 0
long 0L
float 0.0F
double 0.0
char \u0000(即’’)
boolean false
null

如果默認(rèn)值不符合你的需求,可以使用java.util.Arrays的fill()方法來設(shè)定新建數(shù)組的元素值。例如,每個(gè)學(xué)生的成績默認(rèn)60分:

import java.util.Arrays;

/**
 * Score2.java
 * @author mouyong
 */
public class Score2 {
    public static void main(String[] args) {
        int[] scores=new int[10];
        System.out.println("默認(rèn)初始值");
        for(int score:scores){
            System.out.print(score+"  ");
        }
        System.out.println("\n初始填充后");
        Arrays.fill(scores, 60);
         for(int score:scores){
            System.out.print(score+"  ");
        }
    }
}

執(zhí)行結(jié)果如下:


圖4.11學(xué)生分?jǐn)?shù)數(shù)組的初始化值
數(shù)組既然是對(duì)象,再加上我們講過,對(duì)象是根據(jù)類而建立的實(shí)例,那么代表數(shù)組的類定義在哪里呢?答案是由JVM動(dòng)態(tài)產(chǎn)生。你可以將int[]看作是類名稱,這樣,根據(jù)int[]聲明的變量就是一個(gè)引用變量,那么下面這段代碼會(huì)是什么結(jié)果?

         int[] scores1={88,66,48,99,12,45,55,76};
         int[] scores2=scores1;
         
         scores2[0]=99;
         System.out.println(scores1[0]);

因?yàn)閿?shù)組是對(duì)象,而scores1與scores2是引用名稱,所以將scores1賦值給scores2的意思就是將scores1引用的對(duì)象內(nèi)存地址賦值給scores2,所以兩個(gè)變量指向了同一塊內(nèi)存,那么,當(dāng)你通過scores2[0]對(duì)這個(gè)數(shù)組的第1個(gè)元素進(jìn)行修改之后,scores1也能看到變化(默然說話:記住,因?yàn)樗鼈兊闹赶蚴峭粋€(gè)地址,再想想前面給大家的引用變量聲明的動(dòng)畫)。
所以最后的輸出scores1[0]的值也是99。
再來看前面提過的二維數(shù)組:

int[][] cords=new int[2][3];

這個(gè)語法其實(shí)是建立了一個(gè)int[][]類型的對(duì)象,里面有2個(gè)int[]類型的對(duì)象。這2個(gè)一維的數(shù)組對(duì)象的長度都是3。初始值為0。


圖4.12二維數(shù)組的對(duì)象引用示意
對(duì),從上圖中我們可以得到一個(gè)結(jié)論,其實(shí)Java的二維數(shù)組根本不是一個(gè)表格,所以Java完全可以建立一個(gè)不規(guī)則的數(shù)組。例如:

/**
 * IrregularArray.java
 * @author mouyo
 */
public class IrregularArray {
    public static void main(String[] args) {
        int[][] arr=new int[2][];//聲明arr對(duì)象為二維數(shù)組
        arr[0]=new int[]{1,2,3,4,5};//arr[0]是一個(gè)長度為5的一維數(shù)組
        arr[1]=new int[]{1,2,3};//arr[1]是一個(gè)長度為3的一維數(shù)組
        //從輸出可以看出來,第一個(gè)輸出了5個(gè)數(shù),第二個(gè)輸出了3個(gè)數(shù),并非一個(gè)表格
        for(int[] row:arr){
            for(int value:row){
                System.out.print(value+"  ");
            }
            System.out.println();
        }
        
    }
}

這個(gè)例子我們可以看到,在new一個(gè)二維數(shù)組時(shí)可以只寫最高維,而不用寫最后一個(gè)維度的數(shù)量。然后再給每個(gè)數(shù)組下標(biāo)實(shí)例化不同的低維度數(shù)組。而具體的數(shù)值就放在最低維度指向的空間里。(默然說話:我驚訝的發(fā)現(xiàn),當(dāng)寫了二維聲明之后,不能再使用直接初始化的語法了,也就是說,不能寫成arr[0]={1,2,3,4,5},必須寫成arr[0]=new int[]{1,2,3,4,5},可能是因?yàn)橐婚_始聲明時(shí)沒有給出低維度的長度,所以必須重新對(duì)低維度劃分空間罷)。
當(dāng)然,其實(shí)這個(gè)初始化的代碼也可以寫為:

        int[][] arr={
            {1,2,3,4,5},
            {1,2,3}
        };

以上都是基本類型創(chuàng)建的數(shù)組,那么引用類型創(chuàng)建的數(shù)組會(huì)是什么樣的情況呢?首先看看如何用new關(guān)鍵字建立Integer數(shù)組:

Integer[] scores=new Integer[3];

看上去不過就是把int換成了類Integer而已。那想想這個(gè)數(shù)組創(chuàng)建了幾個(gè)Integer對(duì)象呢?錯(cuò)誤!不是3個(gè),而是一個(gè)Integer對(duì)象都沒有創(chuàng)建。回頭看表4.1,對(duì)象類型的默認(rèn)值是null。這里只創(chuàng)建出一個(gè)Integer[]對(duì)象,它可以容納3個(gè)Integer對(duì)象,但是因?yàn)閷?duì)象型的默認(rèn)初始化值為null,所以現(xiàn)在這三個(gè)對(duì)象都還沒有產(chǎn)生。我們必須在給它們的每個(gè)下標(biāo)都賦值時(shí),才會(huì)有Integer對(duì)象產(chǎn)生。

/**
 * IntegerArray.java
 * @author mouyong
 */
public class IntegerArray {
    public static void main(String[] args) {
        Integer[] scores=new Integer[3];
        System.out.println("僅實(shí)例化了數(shù)組之后,數(shù)組中的初始化值:");
        for(Integer score:scores){
            System.out.println(score);
        }
        scores[0]=new Integer(98);
        scores[1]=new Integer(99);
        scores[2]=new Integer(87);
        
        System.out.println("實(shí)例化每個(gè)元素之后,數(shù)組中的元素值:");
         for(Integer score:scores){
            System.out.println(score);
        }
        
    }
}

代碼的執(zhí)行結(jié)果如下:


4.13對(duì)象類型的數(shù)組初始化
所以每次講對(duì)象類型數(shù)組,我總是說,對(duì)象類型數(shù)組需要new兩次,一次是new出對(duì)象數(shù)組,另一次是new出一系列放在數(shù)組中的對(duì)象。
上面的代碼之所以這樣寫,主要是為了突出對(duì)象的特點(diǎn),其實(shí)JDK5.0之后有了自動(dòng)裝箱和拆箱,所以數(shù)組元素賦值可以寫成這樣:

        scores[0]=98;
        scores[1]=99;
        scores[2]=87;

對(duì)象類型其實(shí)也可以使用大括號(hào)進(jìn)行初始化,只是寫得要長些:

Integer[] scores={new Integer(98),new Integer(99),new Integer(87)};

同樣,上面的寫法也是為了強(qiáng)調(diào)對(duì)象型需要先new,JDK5.0之后有了自動(dòng)裝箱和拆箱,所以也可以寫成這樣:

Integer[] scores={99,98,87};

4.3.3 數(shù)組復(fù)制

在知道了數(shù)組其實(shí)是一種對(duì)象,你就要知道,下面的代碼不是復(fù)制:

int[] scores1={88,66,48,99,12,45,55,76};
int[] scores2=scores1;

復(fù)制應(yīng)該是出現(xiàn)兩個(gè)內(nèi)容相同的對(duì)象,但這只是讓兩個(gè)變量指向了同一個(gè)對(duì)象,也就是對(duì)象只有一個(gè),并沒有兩個(gè)。所以真正的復(fù)制應(yīng)該是這樣的。

int[] scores1={88,66,48,99,12,45,55,76};
int[] scores2=new int[scores1.length];
for(int i=0;i<scores1.length;i++){
    scores2[i]=scores1[i];
}

這是自己使用循環(huán)來完成每一個(gè)值的復(fù)制,其實(shí)可以使用System.arraycopy()方法來直接完成這個(gè)過程,比我們用循環(huán)來得快:

int[] scores1={88,66,48,99,12,45,55,76};
int[] scores2=new int[scores1.length];
System.arraycopy(scores1,0,scores2,0,scores1.length);

System.arraycopy()有五個(gè)參數(shù),分別是源數(shù)組,源數(shù)組開始下標(biāo),目標(biāo)數(shù)組,目標(biāo)數(shù)組開始下標(biāo),復(fù)制長度。如果使用JDK6以上,還有個(gè)更方便的Arrays.copyOf()方法,你不用另行建立數(shù)組,Arrays.copyOf()會(huì)幫你創(chuàng)建:

import java.util.Arrays;

/**
 * CopyArray.java
 * @author mouyong
 */
public class CopyArray {
    public static void main(String[] args) {
        int[] scores1={88,81,75,68,79,95,93};
        int[] scores2=Arrays.copyOf(scores1, scores1.length);
        System.out.println("scores2數(shù)組的元素:");
        for(int score:scores2){
            System.out.print(score+"  ");
        }
        System.out.println("");
        scores2[0]=99;
        System.out.println("修改了scores2第1個(gè)元素之后,scores1的元素仍然不變");
        for(int score:scores1){
            System.out.print(score+"  ");
        }
    }
}

執(zhí)行結(jié)果如下所示:


圖4.14Arrays.copyOf()進(jìn)行數(shù)組復(fù)制無需自行創(chuàng)建數(shù)組
Java中,數(shù)組一旦創(chuàng)建,長度就是固定的,如果長度不夠,就只能創(chuàng)建新的數(shù)組,將原來的內(nèi)容復(fù)制到新數(shù)組中。如:

int[] scores1={88,81,75,68,79,95,93};
int[] scores2=Arrays.copyOf(scores1, scores1.length*2);
System.out.println("scores2數(shù)組的元素:");
for(int score:scores2){
    System.out.print(score+"  ");
}

Arrays.copyOf()的第二個(gè)參數(shù)就是指定新數(shù)組的長度。上面程序讓新創(chuàng)建的數(shù)組長度是原來數(shù)組長度的2倍,輸出時(shí)會(huì)看到增加部分元素的值均為默認(rèn)值0。
無論是System.arraycopy()還是Arrays.copyOf(),用在類類型聲明的數(shù)值時(shí),都是執(zhí)行淺層復(fù)制(默然說話:也就是說,如果你的數(shù)組元素是對(duì)象,那么復(fù)制一個(gè)新的數(shù)組時(shí),新數(shù)組還在引用原數(shù)組的對(duì)象,并不會(huì)把原數(shù)組的對(duì)象進(jìn)行復(fù)制!)。如果真的要連同對(duì)象一同復(fù)制,你得自行操作,因?yàn)榛旧现挥凶约翰胖溃總€(gè)對(duì)象復(fù)制時(shí),有哪些屬性必須復(fù)制。

4.4 字符串對(duì)象

在Java中,字符串本質(zhì)是打包字符數(shù)組的對(duì)象。它同樣也有屬性和方法。不過在Java中基于效率的考慮,給予字符串某些特別且必須注意的性質(zhì)。

4.4.1 字符串基礎(chǔ)

由字符組成的文字符號(hào)稱為字符串。例如,“Hello”字符串就是由’H’、’e’、’l’、’l’、’o’、五個(gè)字符組成,在某些程序語言中,字符串是以字符數(shù)組的方式存在,然而在Java中,字符串是java.lang.String實(shí)例,用來打包字符數(shù)組。所有用””包括的一串字符都是字符串。

        String name="sophie";//創(chuàng)建String對(duì)象
        System.out.println(name);//輸出sophie
        System.out.println(name.length());//顯示長度為6
        System.out.println(name.charAt(0));//顯示第1個(gè)字符s
        System.out.println(name.toUpperCase());//顯示全大寫SOPHIE

因?yàn)樽址贘ava中是對(duì)象,所以它有很多的方法,上面的示例給大家看到了幾個(gè)很常用的字符串方法,length()可以獲得字符串長度;charAt()可以獲得指定下標(biāo)的字符,toUpperCase()可以把所有小寫字母轉(zhuǎn)成大寫字母。
如果已有一個(gè)char[]數(shù)組,也可以使用new來創(chuàng)建String對(duì)象。如:

        char[] ch={'H','e','l','l','o'};
        String str=new String(ch);

也可以使用toCharArray()方法,將字符串以char[]的形式返回。

char[] ch2=str.toCharArray()

Java中可以使用+運(yùn)算來連接字符串。前面我們一直在用。
為了認(rèn)識(shí)數(shù)組與字符串,可以看看程序入口main()方法的String[] args參數(shù),在啟動(dòng)JVM并指定執(zhí)行類時(shí),可以一并指定命令行參數(shù)。

/**
 * Avarage.java
 * @author mouyong
 */
public class Avarage {
    public static void main(String[] args) {
        long sum=0;
        for(String arg:args){
            sum+=Long.parseLong(arg);//把字符串轉(zhuǎn)化為長整型
        }
        System.out.println("平均:"+(float)sum/args.length);
    }
}

在NetBeans中如果要提供命令行參數(shù),可以這樣進(jìn)行操作。

  • (1)在項(xiàng)目上右擊,在彈出的快捷菜單中選擇“屬性”,打開“項(xiàng)目屬性”對(duì)話框,在左邊的“類別”列表中選擇“運(yùn)行”。


圖4.15配置命令行參數(shù)

  • (2)單擊右側(cè)上方“配置”列表框旁邊的“新建…”按鈕,打開“創(chuàng)建新的配置”對(duì)話框,在“類別”文本框中填入配置的名稱,我填的是“命令行參數(shù)”。


圖4.16創(chuàng)建新的配置

  • (3)單擊“主類”文本框右側(cè)的“瀏覽…”按鈕,從中選擇你寫的示例。
  • (4)在“參數(shù)”文本框中手工輸入?yún)?shù)1 2 3 4,注意,每個(gè)數(shù)字之間要用空格分開,不然JVM會(huì)認(rèn)為你只輸入了一個(gè)參數(shù)。
    這樣設(shè)定之后,點(diǎn)擊工具欄上的“運(yùn)行”按鈕,就會(huì)按你所設(shè)置的配置調(diào)用程序了。

4.4.2 字符串特性

各程序語言會(huì)有細(xì)微、重要且不容忽視的特性。在Java的字符串來說,就有一些必須注意的特性:
? 字符串常量和字符串池。
? “不可變”(Immutable)的字符串。
*1.字符串常量與字符串池
來看下面的片段:

String name1=new String("Hello");
String name2=new String("Hello");
System.out.println(name1==name2);

希望現(xiàn)在的你會(huì)很自信的回答:結(jié)果是false。是的,結(jié)果的確是false。因?yàn)閚ame1和name2引用了不同的對(duì)象,盡管它們的內(nèi)容一樣,但內(nèi)存地址不同,所以==的比較結(jié)果就是false。


圖4.17片段執(zhí)行結(jié)果

再看下面的片段:

String name1="Hello";
String name2="Hello";
System.out.println(name1==name2);

這個(gè)代碼和上面似乎沒啥區(qū)別嘛,只不過沒有顯式new而已。但是如果你運(yùn)行一下,你就會(huì)驚訝的發(fā)現(xiàn):結(jié)果是true!!!


圖4.18片段執(zhí)行結(jié)果
難道這里使用了不同的規(guī)則?答案是:沒有,和前面的顯式new的規(guī)則是一致的!所以正確的推論是:name1和name2都指向了同一個(gè)對(duì)象!
在Java中為了效率的考慮,以””包括的字符串,只要內(nèi)容相同(序列、大小寫相同),無論在程序中出現(xiàn)幾次,JVM都只會(huì)建立一個(gè)String對(duì)象,并在字符串池中維護(hù)。在上面這個(gè)程序片段的第一行,JVM會(huì)建立一個(gè)String實(shí)例放在字符串池中,并把地址賦值給name1,而第二行則是讓name2直接引用了字符串池中的同一個(gè)String對(duì)象。
用””寫下的字符串稱為字符串常量(String Literal),既然你用”Hello”寫死了字符串內(nèi)容,基于節(jié)省內(nèi)存的考慮,自然就不用為這些字符串常量分別建立String實(shí)例。
前面一直強(qiáng)調(diào),如果想比較對(duì)象的內(nèi)容是否相同,不要使用==,要使用equals()。這個(gè)同樣適用String。
2.不可變動(dòng)字符串
在Java中,字符串對(duì)象一旦建立,就無法更改對(duì)象中任何內(nèi)容,對(duì)象沒有提供任何方法可以更改字符串內(nèi)容。那么+連字符串是怎么做到的呢?

String name1=”Java”;
String name2=name1+”World”;
System.out.println(name2);

上面這個(gè)程序片段會(huì)顯示JavaWorld,由于無法更改字符串對(duì)象內(nèi)容,所以絕不是在name1引用的字符串對(duì)象之后附加World。而創(chuàng)建了java.lang.StringBuilder對(duì)象,使用其append()方法來進(jìn)行+左右兩邊字符串附加,最后再轉(zhuǎn)換為toString()返回。
簡(jiǎn)單地說,使用+連接字符串會(huì)產(chǎn)生新的String對(duì)象,這并不是告訴你,不要使用+連接字符串,畢竟這種做法非常方便。但是不要將+用在重復(fù)性的連接場(chǎng)合,比如循環(huán)或遞歸時(shí)。這會(huì)因?yàn)轭l繁產(chǎn)生新對(duì)象,造成效能上的負(fù)擔(dān)。
比如,如果我們想輸出一個(gè)從1加到100的算式(注意,不是1到100相加的結(jié)果,而是顯示描述1加到100的這個(gè)算式:1+2+3+4+5……+100),你會(huì)怎么寫?

也許是這樣寫?
for(int i=1;i<100;i++){
    System.out.print(i+"+");
}

System.out.println(100);

這樣寫代碼很簡(jiǎn)潔,但是一個(gè)一個(gè)循環(huán)輸出效能是很低的。有沒有更好的辦法?

String str="";
for(int i=1;i<100;i++){
    str+=i+"+";
}
System.out.println(str+100);

只有一個(gè)輸出語句,效能大大提高!但是使用了連接字符串,會(huì)造成頻繁產(chǎn)生新對(duì)象的問題。象上面這樣的情況下,強(qiáng)烈建議使用StringBuilder!

/**
 * OneTo100.java
 * @author mouyong
 */
public class OneTo100 {
    public static void main(String[] args) {
        StringBuilder builder=new StringBuilder();
        for(int i=1;i<100;i++){
            builder.append(i).append("+");
        }
        System.out.println(builder.append(100).toString());
    }
}

StringBuilder每次append()調(diào)用之后,都會(huì)返回原StringBuilder對(duì)象,所以我們可以連接調(diào)用append()方法。這個(gè)程序只產(chǎn)生一個(gè)StringBuilder對(duì)象,只進(jìn)行一次輸出,無論是從計(jì)算效能還是內(nèi)存使用效能上來說,都是非常棒的!

提示:java.lang.StringBuilder是JDK5之后新增的類,在該版本之前,我們有java.lang.StringBuffer,StringBuilder和StringBuffer其實(shí)是一樣的。但是StringBuilder的效率更高,因?yàn)樗豢紤]多線程情況下的同步問題。所以如果你的程序會(huì)涉及到多線程的情況,可以直接改用StringBuffer

4.4.3 字符串編碼

你我都是中國人(默然說話:對(duì)的!下面要談?wù)摰膯栴}與中文有關(guān),如果你就不使用中國字,那可以略過),在Java中你必然要處理中文,所以你要了解Java如何處理中文。
要知道,java源代碼文檔在NetBeans中是UTF-8編碼。在windows簡(jiǎn)體中文版下默認(rèn)是GB2312。在Eclipse中情況又會(huì)不同,Eclipse會(huì)自動(dòng)讓java源代碼文件的編碼是所在操作系統(tǒng)的默認(rèn)編碼。所以,如果你的Eclipse在Windows簡(jiǎn)體中文下就是GB2312,如果是在Mac下,就會(huì)是UTF-8。
如果你使用的是GB2312編碼,在編譯器編譯你的代碼時(shí),會(huì)自動(dòng)把所有的中文都轉(zhuǎn)為Unicode編碼。比如”哈啰”就會(huì)變成”\u54C8\u56C9”。這個(gè)”\uxxxx”就是Unicode的編碼形式。
那么編譯器是如何知道要將中國字轉(zhuǎn)成哪種Unicode編碼呢?當(dāng)你使用javac指令沒有指定-encodding參數(shù)時(shí),會(huì)使用操作系統(tǒng)默認(rèn)編碼,如果你的源代碼文件采用了不同的編碼形式,則必須指定-encoding參數(shù)。
提示:在Windows下不要使用純文本編輯器轉(zhuǎn)存UTF-8文件來編寫源代碼,因?yàn)橛浭卤緯?huì)在文檔頭加BOM,這樣會(huì)造成Java編譯器無法編譯。建議使用NotePad++。
IDE也是允許你自定義編碼的,如果是NetBeans,可以在項(xiàng)目上右擊,在彈出的快捷菜單中選擇“屬性”,打開“項(xiàng)目屬性”對(duì)話框,在左邊“類別”列表中選擇“源”。然后在右側(cè)最下方的“編碼”選擇框中選擇代碼的編碼。

4.5 查詢Java API文件

書上提到的各種Java類是如何知道應(yīng)該調(diào)用什么方法呢?是通過查詢Java API文檔知道的。
http://docs.oracle.com/javase/8/docs/api/
這個(gè)鏈接就是Java API文檔,里面包括了所有Java類的方法屬性及使用介紹、特點(diǎn)介紹。
不過在平時(shí)如果知道一個(gè)Java類,想知道怎么用,我更習(xí)慣用下面這個(gè)鏈接。
http://www.baidu.com/
以前喜歡用谷歌,現(xiàn)在用不了,只好將就著用了。

4.6 重點(diǎn)復(fù)習(xí)

要產(chǎn)生對(duì)象必須先定義類,類是對(duì)象的模板,對(duì)象是類的實(shí)例。定義類使用class關(guān)鍵字,實(shí)例化對(duì)象使用new關(guān)鍵字。
想在建立對(duì)象時(shí),一并進(jìn)行某個(gè)初始流程,可以定義構(gòu)造函數(shù),構(gòu)造函數(shù)是與類名同名的方法,它不能寫返回值。參數(shù)根據(jù)需要指定,也可以沒有參數(shù)。
Java遵守IEEE 754浮點(diǎn)運(yùn)算規(guī)范,使用分?jǐn)?shù)與指數(shù)來表示浮點(diǎn)數(shù)。如果要求精確度,那就要小心使用浮點(diǎn)數(shù)。不要使用==直接比較浮點(diǎn)數(shù)運(yùn)算結(jié)果。
要讓基本類型象對(duì)象一樣的操作,可以使用Long、Integer、Double、Float等類來打包基本類型。JDK5之后提供了自動(dòng)裝箱和拆箱,媽媽再也不擔(dān)心我不會(huì)裝箱和拆箱了。
數(shù)組在Java中就是對(duì)象,下標(biāo)從0開始,下標(biāo)超出范圍會(huì)拋異常。
無論是System.arraycopy()還是Arrays.copyOf(),用在類的數(shù)組時(shí),都是執(zhí)行淺層復(fù)制。
字符串也是對(duì)象。
字符串對(duì)象一旦建立,無法更改對(duì)象內(nèi)容。不要將+用在重復(fù)性的連接場(chǎng)合。
使用javac指令沒有指定-encoding參數(shù)時(shí),會(huì)使用操作系統(tǒng)默認(rèn)編碼。

4.7 課后練習(xí)

4.7.1 選擇題

  1. 如果有以下的程序代碼:
int x=100;
int y=100;
Integer wx=x;
Integer wy=y;
System.out.println(x==y);
System.out.println(wx==wy);

在JDK 5以上的環(huán)境編譯與執(zhí)行,則顯示結(jié)果是()
A.true、true
B.true、false
C.false、true
D.編譯失敗

  1. 如果有以下的程序代碼:
int x=200;
int y=200;
Integer wx=x;
Integer wy=y;
System.out.println(x==y);
System.out.println(wx==wy);
在JDK 5以上的環(huán)境編譯與執(zhí)行,則顯示結(jié)果是()
A.true、true 
B.true、false 
C.false、true    
D.編譯失敗
  1. 如果有以下的程序代碼:
int x=300;
int y=300;
Integer wx=x;
Integer wy=y;
System.out.println(wx.equals(x));
System.out.println(wy.equals(y));

在JDK 5以上的環(huán)境編譯與執(zhí)行,則顯示結(jié)果是()
A.true、true
B.true、false
C.false、true
D.編譯失敗

  1. 如果有以下的程序代碼:
int[] arr1={1,2,3};
int[] arr2=arr1;
arr2[1]=20;
System.out.println(arr1[1]);

在JDK 5以上的環(huán)境編譯與執(zhí)行,則顯示結(jié)果是()
A.執(zhí)行時(shí)顯示2
B.執(zhí)行時(shí)顯示20
C.執(zhí)行時(shí)出現(xiàn)ArrayIndexOfBuondException
D.編譯失敗

  1. 如果有以下的程序代碼:
int[] arr1={1,2,3};
int[] arr2=new int[arr1.length]
arr2=arr1;
for(int value:arr2){
    System.out.print(value);
}

在JDK 5以上的環(huán)境編譯與執(zhí)行,則顯示結(jié)果是()
A.執(zhí)行時(shí)顯示123
B.執(zhí)行時(shí)顯示12300
C.執(zhí)行時(shí)出現(xiàn)ArrayIndexOfBuondException
D.編譯失敗

  1. 如果有以下的程序代碼:
String[] strs=new String[5]

以下描述正確的是()
A.產(chǎn)生5個(gè)String對(duì)象
B.產(chǎn)生1個(gè)String對(duì)象
C.產(chǎn)生0個(gè)String對(duì)象
D.編譯失敗

  1. 如果有以下的程序代碼:
    String[] strs={“java”, “java”, “java”, “java”, “java”}
    以下描述正確的是()
    A.產(chǎn)生5個(gè)String對(duì)象 B.產(chǎn)生1個(gè)String對(duì)象
    C.產(chǎn)生0個(gè)String對(duì)象 D.編譯失敗

  2. 如果有以下的程序代碼:

String[][] strs=new String[2][5]

以下描述正確的是()
A.產(chǎn)生10個(gè)String對(duì)象
B.產(chǎn)生2個(gè)String對(duì)象
C.產(chǎn)生0個(gè)String對(duì)象
D.編譯失敗

  1. 如果有以下的程序代碼:
String[][] strs={
{“java”, “java”, “java”},
{“java”, “java”, “java”, “java”}
};
System.out.println(strs.length);
System.out.println(strs[0].length);
System.out.println(strs[1].length);

以下描述正確的是()
A.顯示2、3、4
B.顯示2、0、1
C.顯示1、2、3
D.編譯失敗

  1. 如果有以下的程序代碼:
String[][] strs={
{“java”, “java”, “java”},
{“java”, “java”, “java”, “java”}
};
for(row:strs){
for(value:row){
    …
}
}

空白處應(yīng)該分別填上()
A.String、String
B.String、String[]
C.String[]、String
D.String[]、String[]

4.7.2 操作題

1.Fibonacci為13 歐洲數(shù)學(xué)家,在他的著作中提過,若一只兔子每月生一只小兔子,一個(gè)月后小兔子也開始生產(chǎn)。起初只有一只小兔子,一個(gè)月后有兩只兔子,兩個(gè)月后有三只兔子,三個(gè)月后有五只 …,也就是每個(gè)月兔子總數(shù)會(huì)是1、1、2、3、5、8、13、21、34、89,這就是費(fèi)氏數(shù)列,可用公式定義如下:
fn=fn-1+fn-2 if n>1
fn=n if n=0,1
編寫程序,可以讓用戶輸入想計(jì)算的費(fèi)氏數(shù)列的個(gè)數(shù),由程序全部顯示出來。
2.請(qǐng)編寫一個(gè)簡(jiǎn)單的洗 程序,可以在文本模式下顯示洗牌結(jié)果。
3.下面是一個(gè)數(shù)組,請(qǐng)使用程序使其中元素排序?yàn)橛尚〉酱螅?br> int[] number={70,80,31,37,10,1,48,60,33,80};
4.下面是一個(gè)排序后的數(shù)組,請(qǐng)編寫程序可讓用戶在數(shù)組中尋找指定數(shù)字,找到就顯示索引值,找不到就顯示-1:
int number={1,10,31,33,37,48,60,70,80};

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,711評(píng)論 19 139
  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,692評(píng)論 0 4
  • 醫(yī)院是最無情的地方也是最有情的地方。在我還沒有踏上學(xué)醫(yī)之旅的時(shí)候,我一直很害怕到醫(yī)院去,因?yàn)樽约盒r(shí)候就...
    小爬姑娘閱讀 319評(píng)論 0 0
  • iOS逆向入門實(shí)踐 — 逆向微信,偽裝定位(一) iOS 逆向開發(fā)小試-釘釘篇 粉絲福利,Pokemon Go 鎖...
    愛我你就抱抱我閱讀 202評(píng)論 0 0
  • 公司今年事情特別多,無論是外面來的,還是內(nèi)部的,各種風(fēng)波漩渦,處在這中心,深深地感覺人生無常。 就在上個(gè)星期二,我...
    黑土錢閱讀 137評(píng)論 0 2

友情鏈接更多精彩內(nèi)容