Java SE核心I

1.1.1 Object類

在Java繼承體系中,java.lang.Object類位于頂端(是所有對象的直接或間接父類)。如果一個類沒有寫extends關鍵字聲明其父類,則該類默認繼承java.lang.Object類。Object類定義了“對象”的基本行為,被子類默認繼承。

1)toString方法:返回一個可以表示該對象屬性內容的字符串。

 MyObject obj=new MyObject(); 
 String info=obj.toString(); 
System.out.println(info);

A.上例為什么我有toString方法?

因為所有的類都繼承自Object,而toString方法是Ojbect定義的,我們直接繼承了這個方法。Object的toString方法幫我們返回一個字符串,這個字符串的格式是固定的:類型@hashcode,這個hashcode是一串數字,在java中叫句柄,或叫地址(但不是真實的物理地址,是java自己的一套虛擬地址,防止直接操作內存的)。

 public String toString(){//只能用public,重寫的方法訪問權限要大于等于父類中方法的權限

 return "這個是我們自己定義的toString方法的返回值MyObject!"; }

B.上例為什么要重寫toString方法?

toString定義的原意是返回能夠描述當前這個類的實例的一串文字,我們看一串hashcode沒意義,所以幾乎是要重寫的。

 public static void main(String[] args){ 
//System.out.println(toString());//不行!編譯錯誤!

 Point p=new Point(1,2); 
System.out.println(p);//輸出p對象的toString方法返回值 
}

C.上例為何有編譯錯誤?

不能直接使用toString方法,因為該方法不是靜態的。ava語法規定:靜態方法中不能直接引用非靜態的屬性和方法,想引用必需創建對象。非靜態方法中可以直接引用靜態屬性和方法。

2)equals方法:用于對象的“相等”邏輯。

A.在Object中的定義: public boolean equals(Object obj){ return (this==obj); }

由此可見,this==obj與直接的==(雙等于)效果一樣,僅僅是根據對象的地址(句柄,那個hashcode值)來判斷對象是否相等。因此想比較對象與給定對象<u>內容</u>是否一致,則必須重寫equals方法。

B.“==”與equals的區別:

用“==”比較對象時,描述的是兩個對象是否為同一個對象!<u>根據地址值</u>判斷。而equals方法力圖去描述兩個<u>對象的內容</u>是否相等,內容相等取決于業務邏輯需要,可以自行定義比較規則。

C.equals方法的重寫:如,判斷兩點是否相等。

 public boolean equals(Object obj){//注意參數

 /**若給定的對象obj的地址和當前對象地址一致,那么他們是同一個對象,equals方法中有大量的內容比較邏輯時,加上這個判斷會節省性能的開銷!*/

 if(this == obj){ return true; }

 /** equals比較前要進行安全驗證,確保給定的對象不是null!若obj是null,說明該引用變量沒有指向任何對象,那么就不能引用ojb所指象的對象(因為對象不存在)的屬性和方法!若這么做就會引發NullPointException,空指針異常!*/

 if(obj == null){ return false; }

 /**直接將Object轉為子類是存在風險的!我們不能保證Object和我們要比較的對象是同一個類型的這會引發ClassCastException!我們稱為:類造型異常。*/

 /**重寫equals時第一件要做的事情就是判斷給定的對象是否和當前對象為同一個類型,不是同類型直接返回false,因為不具備可比性!*/

 if(!(obj instanceof Point)){ return false; }

 Point p=(Point)obj;

 /**不能隨便把父類轉成子類,因為Object是所有類的父類,任何類型都可以傳給它所以不能保證obj傳進來的就是相同類型(點類型)*/

 return this.x==p.x && this.y==p.y;//內容比較邏輯定義 }

1.1.2 String類

是字符串類型,是引用類型,是“不可變”字符串,無線程安全問題。在java.lang.String中。

u 注意事項:String str =“abc”;和String str=new String(“abc”);的區別!

1)String在設計之初,虛擬機就對他做了特殊的優化,將字符串保存在虛擬機內部的字符串常量池中。一旦我們要創建一個字符串,虛擬機先去常量池中檢查是否創建過這個字符串,如有則直接引用。String對象因為有了上述的優化,就要保證該對象的內容自創建開始就不能改變!所以對字符串的任何變化都會創建新的對象,而不是影響以前的對象!

2)String的equals方法:兩個字符串進行比較的時候,我們通常使用equals方法進行比較,字符串重寫了Object的equals方法,用于比較字符串內容是否一致。雖然java虛擬機對字符串進行了優化,但是我們不能保證任何時候“==”都成立!

3)編程習慣:當一個字符串變量和一個字面量進行比較的時候,用字面量.equals方法去和變量進行比較,即:if("Hello".equals(str))因為這樣不會產生空指針異常。而反過來用,即:if(str.equals("Hello"))則我們不能保證變量不是null,若變量是null,我們在調用其equals方法時會引發空指針異常,導致程序退出。若都為變量則if(str!=null&&str.equals(str1))也可。

4)String另一個特有的equals方法:euqalsIgnoreCase,該方法的作用是忽略大小寫比較字符串內容,常用環境:驗證碼。if("hello".equalsIgnoreCase(str))。

5)String的基本方法:

①String toLowerCase():返回字符串的小寫形式。如:str.toLowerCase()

②String toUpperCase():返回字符串的大寫形式。如:str.toUpperCase()

③String trim():去掉字符串兩邊的空白(空格\t\n\r),中間的不去。如:str.trim()

④boolean startsWith():判斷字符串是否以參數字符串開頭。如:str.startsWith("s")

⑤boolean endsWith():判斷字符串是否以參數字符串結尾。如:str.endsWith("s")

⑥int length():返回字符串字符序列的長度。如:str.length()

eg:如何讓HelloWorld這個字符串以hello開頭成立

 if(str.toLowerCase().startsWith("hello"))//有返回值的才能繼續 . 先轉成小寫再判斷

6)indexOf方法(檢索):位置都是從0開始的。

①int indexOf(String str):在給定的字符串中檢索str,返回其第一次出現的位置, 找不到則返回-1。

②int indexOf(String str,int from):在給定的字符串中從from位置開始檢索str,返 回其第一次出現的位置,找不到則返回-1(包含from位置,from之前的不看)。

eg:查找Think in Java中in后第一個i的位置

 index=str.indexOf("in"); 
   index=str.indexOf("i",index+"in".length());

//這里對from參數加in的長度的目的是 從in之后的位置開始查找

③int lastIndexOf(String str):在給定的字符串中檢索str,返回其最后一次 出現的 位置,找不到則返回-1(也可認為從右往左找,第一次出現的位置)。

④int lastIndexOf(String str,int from):在給定的字符串中從from位置開始檢索str, 返回其最后一次出現的位置,找不到則返回-1(包含from位置,from之后的不看)。

7)charAt方法:char charAt(int index):返回字符串指定位置(index)的字符。

eg:判斷是否是回文:上海自來水來自海上

 boolean tf=true; 
for(int i=0;i<str2.length()/2;i++){

 //char first=str2.charAt(i);  //char 
last=str2.charAt(str2.length()-i-1);

 if(str2.charAt(i)!=str2.charAt(str2.length()-i-1)){//優化

 tf = false; 
 break;//已經不是回文了,就沒有必要再繼續檢查了 }   }

8)substring方法(子串):字符串的截取,下標從0開始的。

①String substring(int start,int end):返回下標從start開始(包含)到end結束的字 符串(不包含)。

②String substring(int start):返回下標從start開始(包含)到結尾的字符串。

9)getBytes方法(編碼):將字符串轉換為相應的字節。

①byte[] getBytes():以當前系統默認的字符串編碼集,返回字符串所對應的二進制 序列。如:byte[] array=str.getBytes(); System.out.println(Arrays.toString(array));

②byte[] getBytes(String charsetName):以指定的字符串編碼集,返回字符串所對應 的二進制序列。這個重載方法需要捕獲異常,這里可能引發沒有這個編碼集的異常, UnsupportedEncodingException,如:str="常"; byte[] bs=info.getBytes("UTF-8");

u 注意事項:

v Windows的默認編碼集GBK:英文用1個字節描述,漢字用2個字節描述;ISO-8859-1歐洲常用編碼集:漢字用3個字節描述;GBK國標;GB2312國標;UTF-8編碼集是最常用的:漢字用3個字節描述。

v 編碼:將數據以特定格式轉換為字節;解碼:將字節以特定格式轉換為數據。

v String(byte[] bytes, String charsetName) :通過使用指定的charset解碼指定的byte數組,構造一個新的String。如:String str=new String(bs,"UTF-8");

10)split方法(拆分):字符串的拆分。

String[] split(String regex):參數regex為正則表達式,以regex所表示的字符串為 分隔符,將字符串拆分成字符串數組。其中,regex所表示的字符串不被保留,即 不會存到字符串數組中,可理解為被一刀切,消失!

eg:對圖片名重新定義,保留圖片原來后綴

 String name="me.jpg";     String[] nameArray=name.split("\\.");

 //以正則表達式拆分 .有特殊含義,所以用\\. 轉義

 System.out.println("數組長度:"+nameArray.length);//如果不用\\.則長度為0

 System.out.println(Arrays.toString(nameArray));//任意字符都切一刀,都被切沒了

 String newName="123497643."+nameArray[1];

 System.out.println("新圖片名:"+newName);

u 注意事項:分隔符放前、中都沒事,放最后將把無效內容都忽略。

 String str="123,456,789,456,,,";

 String[] array=str.split(",");//分隔符放前、中都沒事,放最后將把無效內容都忽略

 System.out.println(Arrays.toString(array));//[123, 456, 789, 456]

11)replace方法:字符串的替換。

String replaceAll(String regex,String replacement):將字符串中匹配正則表達式regex 的字符串替換成replacement。如:String str1=str.replaceAll("[0-9]+", "chang");

12)String.valueOf()方法:重載的靜態方法,用于返回各類型的字符串形式。

 String.valueOf(1);//整數,返回字符串1 
String.valueOf(2.1);//浮點數,返回字符串1.2

1.1.3 StringUtils類

針對字符串操作的工具類,提供了一系列靜態方法,在Apache阿帕奇Commons-lang包下中,需下載。

StringUtils常用方法:

1)String repeat(String str,int repeat):重復字符串repeat次后返回。

2)String join(Object[] array,String):將一個數組中的元素連接成字符串。

3)String leftPad(String str,int size,char padChar):向左邊填充指定字符padChar,以達到指定長度size。

4)String rightPad(String str,int size,char padChar):向右邊填充指定字符padChar,以達到指定長度size。

1.1.4 StringBuilder類

與String對象不同,StringBuilder封裝“可變”的字符串,有線程安全問題。對象創建后,可通過調用方法改變其封裝的字符序列。

StringBuilder常用方法:

1)追加字符串:StringBuilder append(String str):

2)插入字符串:StringBuilder insert(int index,String str):插入后,原內容依次后移

3)刪除字符串:StringBuilder delete(int start,int end):

4)替換字符串:StringBuilder replace(int start,int end,String str):含頭不含尾

5)字符串反轉:StringBuilder reverse():

eg:各類操作

 StringBuilder builder=new StringBuilder();

 builder.append("大家好!") .append("好好學習") .append("天天向上");

 //返回的還是自己:builder,所以可以再 .

 System.out.println(builder.toString());

 builder.insert(4, "!"); System.out.println(builder.toString());

 builder.replace(5,9,"Good Good Study!"); System.out.println(builder.toString());

 builder.delete(9, builder.length()); System.out.println(builder.toString());

u 注意事項:

v 該類用于對某個字符串頻繁的編輯操作,使用StringBuilder可以在大規模修改字符串時,不開辟新的字符串對象,從而節約內存資源,所以,對有著大量操作字符串的邏輯中,不應使用String而應該使用StringBuilder。

v append是有返回值的,返回類型是StringBuilder,而返回的StringBuilder其實就是自己(this),append方法的最后一句是return this;

v StringBuilder與StringBuffer區別:效果是一樣的。

StringBuilder是線程不安全的,效率高,需JDK1.5+。

StringBuffer是線程安全的,效率低,“可變”字符串。

在多線程操作的情況下應使用StringBuffer,因為StringBuffer是線程安全 的,他難免要顧及安全問題,而進行必要的安全驗證操作。所以效率上要 比StringBuilder低,根據實際情況選擇。

1.1.5 正則表達式

實際開發中,經常需要對字符串數據進行一些復雜的匹配、查找、替換等操作,通過正則表達式,可以方便的實現字符串的復雜操作。

正則表達式是一串特定字符,組成一個“規則字符串”,這個“規則字符串”是描述文本規則的工具,正則表達式就是記錄文本規則的代碼。

[]表示一個字符

[abc]表示a、b、c中任意一個字符

[^abc]除了a、b、c的任意一個字符

[a-z]表示a到z中的任意一個字符

[a-zA-Z0-9_]表示a到z、A到Z、0到9以及下滑線中的任意一個字符

[a-z&&[^bc]]表示a到z中除了b、c之外的任意一個字符,&&表示“與”的關系

.表示任意一個字符

\d任意一個數字字符,相當于[0-9]

\D任意一個非數字字符,相當于[^0-9]

\s空白字符,相當于[\t\n\f\r\x0B]

\S非空白字符,相當于[^\s]

\w任意一個單詞字符,相當于[a-zA-Z0-9_]

\W任意一個非單詞字符,相當于[^\w]

^表示字符串必須以其后面約束的內容開始

$表示字符串必須以其前面約束的內容結尾

?表示前面的內容出現0到1次

*表示前面的內容出現0到多次

+表示前面的內容出現1到多次

{n}表示前面的字符重復n次

{n,}表示前面的字符至少重復n次

{n,m}表示前面的字符至少重復n次,并且小于m次 X>=n && X<m

u 注意事項:

v 郵箱格式的正則表達式 @無特殊含義,可直接寫,也可[@]

v 使用Java字符串去描述正則表達式的時候,會出現一個沖突,即如何正確描述正則表達式的“.”。

起因:在正則表達式中我們想描述一個“.”,但“.”在正則表達式中有特殊含義,他代表任意字符,所以我們在正則表達式中想描述“.”的愿義就要寫成“\.”但是我們用java字符串去描述正則表達式的時候,因為“.”在java字符串中沒有特殊意義,所以java認為我們書寫String s="\.";是有語法錯誤的,因為“.”不需要轉義,這就產生了沖突。

處理:我們實際的目的很簡單,就是要讓java的字符串描述"\."又因為在java中""是有特殊含義的,代表轉義字符我們只需要將""轉義為單純的斜杠,即可描述"\."了所以我們用java描述“\.”的正確寫法是String s="\.";

v 若正則表達式不書寫^或$,正則表達式代表匹配部分內容,都加上則表示權匹配

eg:測試郵箱正則表達式:Pattern的作用是描述正則表達式的格式支持,使用靜態方法compile注冊正則表達式,生成實例。

 String regStr="^[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.com|\\.cn|\\.net)+$";

 Pattern pattern=Pattern.compile(regStr);//注冊正則表達式

 String mailStr="chang_2013@chang.com.cn";

 //匹配字符串,返回描述匹配結果的Matcher實例

 Matcher matcher=pattern.matcher(mailStr);

 //通過調用Matcher的find方法得知是否匹配成功

 if(matcher.find()){ System.out.println("郵箱匹配成功!"); }

 else{  System.out.println("郵箱格式錯誤!");   }

1.1.6 Date類

java.util.Date類用于封裝日期及時間信息,一般僅用它顯示某個日期,不對他作任何操作處理,作處理用Calendar類,計算方便。

 Date date=new Date();//創建一個Date實例,默認的構造方法創建的日期代表當前系統時間

 System.out.println(date);//只要輸出的不是類名@hashcode值,就說明它重寫過toString()

 long time=date.getTime();//查看date內部的毫秒值

 date.setTime(time+1000*60*60*24);//設置毫秒數讓一個時間Date表示一天后的當前時間

 int year=date.getYear();//畫橫線的方法不建議再使用:1、有千年蟲問題。2、不方便計算

1.1.7 Calendar類

java.util.Calendar類用于封裝日歷信息,其主作用在于其方法可以對時間分量進行運算。

1)通過Calendar的靜態方法獲取一個實例該方法會根據當前系統所在地區來自行決定時區,幫我們創建Calendar實例,這里要注意,實際上根據不同的地區,Calendar有若干個子類實現。而Calendar本身是抽象類,不能被實例化!我們不需要關心創建的具體實例為哪個子類,我們只需要根據Calendar規定的方法來使用就可以了。

2)日歷類所解決的根本問題是簡化日期的計算,要想表示某個日期還應該使用Date類描述。Calendar是可以將其描述的時間轉化為Date的,我們只需要調用其getTime()方法就可以獲取描述的日期的Date對象了。

3)通過日歷類計算時間:為日歷類設置時間,日歷類設置時間使用通用方法set。

set(int field,int value),field為時間分量,Calendar提供了相應的常量值,value為對應的值。

4)只有月份從0開始:0為1月,以此類推,11為12月,其他時間是正常的從1開始。也可以使用Calendar的常量 calendar.NOVEMBER……等.

5)Calendar.DAY_OF_MONTH 月里邊的天---號;

Calendar.DAY_OF_WEEK 星期里的天---星期幾

Calendar.DAY_OF_YEAR 年里的天

 Calendar calendar=Calendar.getInstance();//構造出來表示當前時間的日歷類

 Date now=calendar.getTime();//獲取日歷所描述的日期

 calendar.set(Calendar.YEAR, 2012);//設置日歷表示2012年

 calendar.set(Calendar.DAY_OF_MONTH,15);//設置日歷表示15號

 calendar.add(Calendar.DAY_OF_YEAR, 22);//想得到22天以后是哪天

 calendar.add(Calendar.DAY_OF_YEAR, -5);//5天以前是哪天

 calendar.add(Calendar.MONTH, 1);得到1個月后是哪天

 System.out.println(calendar.getTime());

6)獲取當前日歷表示的日期中的某個時間單位可以使用get方法.

 int year=calendar.get(Calendar.YEAR);

 int month=calendar.get(Calendar.MONTH);

 int day=calendar.get(Calendar.DAY_OF_MONTH);

 System.out.println(year+"年"+(month+1)+"月"+day+"日");//month要處理

1.1.8 SimpleDateFormat類

java.text.SimpleDateFormat類,日期轉換類,該類的作用是可以很方便的在字符串和日期類之間相互轉換。

1)這里我們在字符串與日期類間相互轉換是需要一些約束的,"2012-02-02"這個字符串如何轉換為Date對象?Date對象又如何轉為字符串?

parse方法用于按照特定格式將表示時間的字符串轉化成Date對象。

format方法用于將日期數據(對象)按照指定格式轉為字符串。

2)常用格式字符串

yyyy年-2013年;yy年-13年

MM月-01月;M月-1月

dd日-06日;d日-6日-E-星期日(Sun)

AM或PMa-下午(PM)

H24小時制

a h時-小午12時

HH:mm:ss-12:46:33

hh(a):mm:ss-12(下午):47:48

h12小時制

m分鐘

s秒

eg:字符串轉成Date對象

 //創建一個SimpleDateFormat并且告知它要讀取的字符串格式

 SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");

 String dateFormat="2013-05-14";//創建一個日期格式字符串

 //將一個字符串轉換為相應的Date對象

 Date date=sdf.parse(dateFormat);//要先捕獲異常

 System.out.println(date);//輸出這個Date對象

eg:Date對象轉成字符串

 SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");

 Date now=new Date(); 
String nowStr=sdf.format(now);//把日期對象傳進去

3)在日期格式中 - 和 空格 無特殊意義,無特殊含義的都將原樣輸出。 eg:將時間轉為特定格式

 //將當前系統時間轉換為2012/05/14 17:05:22的效果

 SimpleDateFormat format1=new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");

 nowStr=format1.format(now); 
System.out.println(nowStr);

1.1.9 DateFormat類

java.text.DateFormat類(抽象類)是SimpleDateFormat類的父類,用的少,沒SimpleDateFormat靈活。

創建用于將Date對象轉換為日期格式的字符串的DateFormat,創建DateFormat對象的實例,使用靜態方法getDateInstance(style,aLocale),style為輸出日期格式的樣式:DateFormat有對應的常量;aLocale為輸出的地區信息,影響字符串的語言和表現形式。

 Date now=new Date(); 
 DateFormat format=DateFormat.getDateInstance(   DateFormat.MEDIUM,Locale.CHINA);

1.1.10 包裝類

Java語言的8種基本類型分別對應了8種“包裝類”。每一種包裝類都封裝了一個對應的基本類型成員變量,同時還提供了針對該數據類型的實用方法。

1)包裝類的目的:用于將基本類型數據當作引用類型看待。

2)包裝類的名字:除了Integer(int),Character(char)外,其余包裝類名字都是基本類型名首字母大寫。

3)拆、裝箱:Integer i=new Integer(1);創建一個以對象形式存在的整數1,這種從基本類型轉為引用類型的過程稱之為“裝箱”,反之叫“拆箱”。

4)裝箱:方式一:Double d=new Double(2.2);//裝箱

方式二:Double d=Double.valueOf(2.2);//基本類型都有valueOf方法

5)拆箱:double num=d.doubleValue();//拆箱

6)包裝類使用前提:JDK1.5+

public static void say(Object obj){ System.out.println(obj);  }

int a=1;//基本類型,不是Object子類!

say(a);//在java 1.4版本的時候,這里還是語法錯誤的!因為int是基本類型,不是Object對象,要自己寫8種基本類型對應的方法

7)包裝類的使用:實例化一個對象,該對象代表整數1;Integer的作用是讓基本類型int作為一個引用類型去看待。這樣就可以參與到面向對象的編程方式了。由此我們可以將一個int當作一個Object去看待了,也成為了Object的子類。

 Integer i=new Integer(a);//裝箱,或者寫Integer i=new Integer(1);

 Integer ii=Integer.valueOf(a);//裝箱另一種方式

 int num=i.intValue();//拆箱
 say(i);//Integer是Object的子類,可以調用!

8)JDK1.5包裝類自動拆裝箱(原理):在編譯源程序的時候,編譯器會預處理,將未作拆箱和裝箱工作的語句自動拆箱和裝箱。可通過反編譯器發現。

say(Integer.valueOf(a));自動裝箱 
num=i;//引用類型變量怎么能復制給基本類型呢?

 //num=i.intValuse();//自動拆箱

9)包裝類的一些常用功能:將字符串轉換為其類型,方法是:parseXXX,XXX代表其類型。這里要特別注意!一定要保證待轉換的字符串描述的確實是或者兼容要轉換的數據類型!否則會拋出異常!

 String numStr="123"; 
System.out.println(numStr+1);//1231

 int num=Integer.parseInt(numStr); 
System.out.println(num+1)//124

long longNum=Long.parseLong(numStr); System.out.println(longNum);//123

 double doubleNum=Double.parseDouble(numStr); System.out.println(doubleNum);//123.0

10)Integer提供了幾個有趣的方法:將一個整數轉換為16進制的形式,并以字符串返回;將一個整數轉換為2進制的形式,并以字符串返回。

String bStr=Integer.toBinaryString(num);
String hStr=Integer.toHexString(num);

11)所有包裝類都有幾個共同的常:獲取最大、最小值。

 int max=Integer.MAX_VALUE;//int最大值 int min=Integer.MIN_VALUE;//int最小值

System.out.println(Integer.toBinaryString(max)); System.out.println(Integer.toBinaryString(min));

1.1.11 BigDecimal類

表示精度更高的浮點型,在java.math.BigDecimal包下,該類可以進行更高精度的浮點運算。需要注意的是,BigDecimal可以描述比Double還要高的精度,所以在轉換為基本類型時,可能會丟失精度!

1)BigDecimal的使用:創建一個BigDecimal實例,可以使用構造方法BigDecimal(String numberFormatString)用字符串描述一個浮點數作為參數傳入。

 BigDecimal num1=new BigDecimal("3.0");

 BigDecimal num2=new BigDecimal("2.9"); //運算結果依然為BigDecimal表示的結果

 BigDecimal result=num1.subtract(num2);//num1-num2 System.out.println(result);

float f=result.floatValue();//將輸出結果轉換為基本類型float

 int i=result.intValue();//將輸出結果轉換為基本類型int

2)BigDecimal可以作加add、減subtract、乘multiply、除divide等運算:這里需要注意除法,由于除法存在結果為無限不循環小數,所以對于除法而言,我們要制定取舍模式,否則會一直計算下去,直到報錯(內存溢出)。

result=num1.divide(num2,8,BigDecimal.ROUND_HALF_UP);

 //小數保留8位,舍去方式為四舍五入

1.1.12 BigInteger類

使用描述更長位數的整數“字符串”,來表示、保存更長位數的整數,在java.math.BigInteger包下。

1)BigInteger的使用:創建BigInteger

 BigInteger num=new BigInteger("1");//num=new BigInteger(1);不可以,沒有這樣的構造器

//這種方式我們可以將一個整數的基本類型轉換為BigInteger的實例

 num=BigInteger.valueOf(1);

2)理論上:BigInteger存放的整數位數只受內存容量影響。

3)BigInteger同樣支持加add、減subtract、乘multiply、除divide等運算。

eg:1-200的階乘

 for(int i=1;i<=200;i++){
 num=num.multiply(BigInteger.valueOf(i)); 
}

 System.out.println("結果"+num.toString().length()+"位"); System.out.println(num);

1.1.13 Collection集合框架

在實際開發中,需要將使用的對象存儲于特定數據結構的容器中。而JDK提供了這樣的容器——集合框架,集合框架中包含了一系列不同數據結構(線性表、查找表)的實現類。

image.png

1)Collection常用方法:

①int size():返回包含對象個數。 ②boolean isEmpty():返回是否為空。

③boolean contains(Object o):判斷是否包含指定對象。

④void clear():清空集合。 ⑤boolean add(E e):向集合中添加對象。

⑥boolean remove(Object o):從集合中刪除對象。

⑦boolean addAll(Collection<? extends E > c):另一個集合中的所有元素添加到集合

⑧boolean removeAll(Collection<?> c):刪除集合中與另外一個集合中相同的原素

⑨Iterator<E> iterator():返回該集合的對應的迭代器

2)Collection和Collentions的區別

Collection是java.util下的接口,它是各種集合的父接口,繼承于它的接口主要有Set 和List;Collections是個java.util下的類,是針對集合的幫助類,提供一系列靜態方法實現對各種集合的搜索、排序、線程安全化等操作。

1.1.14 List集合的實現類ArrayList和LinkedList

List接口是Collection的子接口,用于定義線性表數據結構,元素可重復、有序的;可以將List理解為存放對象的數組,只不過其元素個數可以動態的增加或減少。

1)List接口的兩個常見的實現類:ArrayList和LinkedList,分別用動態數組和鏈表的方式實現了List接口。List、ArrayList和LinkedList均處于java.util包下。

2)可以認為ArrayList和LinkedList的方法在邏輯上完全一樣,只是在性能上有一定的差別,ArrayList更適合于隨機訪問,而LinkedList更適合于插入和刪除,在性能要求不是特別苛刻的情形下可以忽略這個差別。

image.png

ArrayList LinkedList

3)使用List我們不需要在創建的時候考慮容量集合的容量是根據其所保存的元素決定的換句話說,集合的容量是可以自動擴充的。

4)List的實現類會重寫toString方法,依次調用所包含對象的toString方法,返回集合中所包含對象的字符串表現。

5)常用方法:

①add(Object obj):向想集合末尾追加一個新元素,從該方法的參數定義不難看出,集合可以存放任意類型的元素,但在實際編程中我們發現,幾乎不會向集合中存放一種以上的不同類型的元素。

②size()方法:返回當前集合中存放對象的數量。

③clear()方法:用于清空集合。

④isEmpty()方法:用于返回集合是否為空。

 List list=new ArrayList(); list.add("One");  
list.add("Two"); 
list.add("Three");

 //list.add(1);//不建議這樣的操作!盡量不在同一個集合中存放不用類型元素

 System.out.println("集合中元素的數量:"+list.size());

 System.out.println(list);//System.out.println(list.toString());

 //ArrayList重寫了toString()方法返回的字符串是每個元素的toString()返回值的序列

 list.clear();//清空 System.out.println("清空后元素的數量:"+list.size());

 System.out.println("集合是否為空?:"+list.isEmpty());

⑤contains(Object obj)方法:檢查給定對象是否被包含在集合中,檢查規則是將obj對象與集合中每個元素進行equals比較,若比對了所有元素均沒有equals為true的則返回false。

u 注意事項:根據情況重寫equals:若比較是否是同一個對象,則不需要重寫,直接用contains里的equals比較即可。若重寫equals為內容是否相同,則按內容比較,不管是否同一個對象。是否重寫元素的equals方法對集合的操作結果有很大的效果不同!

⑥boolean remove(Object obj)方法:刪除一個元素,不重寫equals,不會有元素被刪除(因為比較的是對象的地址,都不相同),重寫equals為按內容比較,則刪除第一個匹配的就退出,其他即使內容相同也不會被刪除。

 List list=new ArrayList();//多態的寫法 //ArrayList arrayList=new ArrayList();//正常的寫法

 list.add(new Point(1,2)); //Point point =new Point(1,2); list.add(point);等量代換

 list.add(new Point(3,4)); 
 list.add(new Point(5,6));

 System.out.println("集合中元素的數量:"+list.size()); System.out.println(list);

 Point p=new Point(1,2);//創建一個Point對象

 System.out.println("p在集合中存在么?"+list.contains(p));//不重寫為false 重寫為true

 System.out.println("刪前元素:"+list.size());

 list.remove(p);//將p對象刪除,不重寫equals,不會有元素被刪除

 System.out.println("刪后元素:"+list.size());
 System.out.println(list);

⑦E remove(int index)方法:移除此列表中指定位置上的元素。向左移動所有后續元素(將其索引減1)。因此在做刪除操作時集合的大小為動態變化的,為了防止漏刪,必須從后往前刪!

ArrayList list=new ArrayList();  list.add("java"); list.add("aaa");        

 list.add("java"); list.add("java"); list.add("bbb");

//相鄰的元素刪不掉!

for(int i=0;i<list.size();i++){ if( "java".equals(list.get(i))); list.remove(i); }

//可以刪干凈!

 for(int i=list.size()-1;i>=0;i--){ if("java".equals(list.get(i))){ list.remove(i); }

⑧addAll(Collection c)方法:允許將c對應的集合中所有元素存入該集合,即并集。注意,這里的參數為Collection,所以換句話說,任何集合類型都可以將其元素存入其他集合中!

⑨removeAll(Collection c)方法:刪除與另一個集合中相同的元素。它的“相同”邏輯通過equals方法來判斷。

⑩retainAll(Collection c)方法:保留與另一個集合中相同的元素,即交集。它的“相同”邏輯通過equals方法來判斷。

 list1.addAll(list2);//并集

 list1.removeAll(list3);//從list1中刪除list3中相同(equals為true)的元素

 list1.retainAll(list2);//保留list1中刪除list2中相同(equals為true)的元素

?Object get(int index)方法:根據元素下標獲取對應位置的元素并返回,這里元素的下標和數組相似。

?Object set(int index,Object newElement)方法:將index位置的元素修改為newElement修改后會將被修改的元素返回。因此,可實現將List中第i個和第j個元素交換的功能:list.set ( i , list.set ( j , list.get ( i ) ) ) ;

?add(int index,Object newElement)方法:使用add的重載方法,我們可以向index指定位置插入newElement,原位置的元素自動向后移動,即所謂的“插隊”。

?Object remove(int index)方法:將集合中下標為index的元素刪除,并將被刪除的元素返回(不根據equals,根據下標刪除元素)。

 List list=new ArrayList(); list.add("One"); list.add("Two"); list.add("Three");

 //因為get方法是以Object類型返回的元素,所以需要造型,默認泛型Object

 String element=(String)list.get(2);//獲取第三個元素 System.out.println(element);

 for(int i=0;i<list.size();i++){//遍歷集合 System.out.println(list.get(i)); }

 Object old=list.set(2, "三");

 System.out.println("被替換的元素:"+old);  System.out.println(list);

 list.add(2, "二");//在Two與“三”之間插入一個“二” System.out.println(list);

 Object obj=list.remove(1); System.out.println("被刪除的元素:"+obj);

?indexOf(Object obj)方法:用于在集合中檢索對象,返回對象第一次出現的下標。

?lastIndexOf(Object obj)方法:用于在集合中檢索對象,返回對象最后一次出現的下標。

?Object[] toArray()方法:該方法繼承自Collection的方法,該方法會將集合以對象數組的形式返回。

?toArray()的重載方法,T[] toArray(T[] a):可以很方便的讓我們轉換出實際的數組類型,如下例,參數new Point[0]的作用是作為返回值數組的類型,所以參數傳入的數組不需要有任何長度,因為用不到,就沒有必要浪費空間。

 Object[] array=list.toArray();//將集合以對象數組的形式返回

 for(int i=0;i<array.length;i++){ Point p=(Point)array[i]; System.out.println(p.getX()); }

 Point[] array1=(Point[])list.toArray(new Point[0]);//toArray()的重載方法

 for(int i=0;i<array1.length;i++){ Point p=array1[i];//不需要每次都強轉了

 System.out.println(p.getX()); }

?List<E> subList(int fromIndex, int toIndex)方法:獲取子集合,但在獲取子集后,若對子集合的元素進行修改,則會影響原來的集合。

 List<Integer> list=new ArrayList<Integer>();

 for(int i=0;i<10;i++){ list.add(i); }

 List<Integer> subList=list.subList(3, 8);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 取子集(3-7)

 System.out.println(subList);//[3, 4, 5, 6, 7]

 //我們在獲取子集后,若對自己元素進行修改,會影響原來的集合

 for(int i=0;i<subList.size();i++){ int element=subList.get(i);

 element*=10; subList.set(i, element);

 //subList.set(i, subList.get(i)*10);同上三步 }

 System.out.println(list);//原集合內容也被修改了

?Comparable接口:針對對象數組或者集合中的元素進行排序時,首選需要確定對象元素的“比較”邏輯(即哪個大哪個小)。Comparable接口用于表示對象間的大小關系,我們需要實現Comparable接口,并重寫compareTo()方法定義比較規則。

 public int compareTo(ComparablePoint o){ int r=x*x+y*y;//自身點到原點的距離

 int other=o.x*o.x+o.y*o.y;//參數點到原點的距離

//返回結果大于0,自身比參數大;小于0,自身比參數小;等于0,自身和參數相等; //equals返回true的時候,comparTo的返回值應該為0

 return r-other; }

21Collections.sort()方法:需要集合中的對象實現Comparable接口,從而可以調用其compareTo方法判斷對象的大小,否則sort將無法判斷。該方法會依次調用集合中每個元素的compareTo方法,并進行自然排序(從小到大)。

 List<ComparablePoint> list=new ArrayList<ComparablePoint>();

 list.add(new ComparablePoint(1,5)); list.add(new ComparablePoint(3,4));

 list.add(new ComparablePoint(2,2)); System.out.println(list);//輸出順序與存方時一致

 Collections.sort(list);  System.out.println(list);

22Comparator接口:比較器。一旦Java類實現了Comparable,其比較邏輯就已經確定了,如果希望在排序中的操作按照“臨時指定規則”,即自定義比較規則。可以采用Comparator接口回調方式。

Comparator比較器創建步驟:A.定義一個類并實現Comparator接口。B.實現接口中的抽象方法compare(E o1,E o2)。C.實例化這個比較器D.調用Collections的重載方法:sort(Collection c,Comparator comparator)進行排序。通常使用匿名類方式創建一個實例來定義比較器。

   Comparator<ComparablePoint> c=new Comparator<ComparablePoint>(){

 public int compare(ComparablePoint o1,ComparablePoint o2){

 return o1.getX()-o2.getX();//兩個點的X值大的大 } };

 Collections.sort(list, c); System.out.println(list);

1.1.15 Iterator迭代器

所有Collection的實現類都實現了iterator方法,該方法返回一個Iterator接口類型的對象,用于實現對集合元素迭代的便利。在java.util包下。

1)Iterator定義有三個方法:

①boolean hasNext()方法:判斷指針后面是否有元素。

②E next()方法:指針后移,并返回當前元素。E代表泛型,默認為Object類型。

③void remove()方法:在原集合中刪除剛剛返回的元素。

2)對于List集合而言,可以通過基于下標的get方法進行遍歷;而iterator方法是針對Collection接口設計的,所以,所有實現了Collection接口的類,都可以使用Iterator實現迭代遍歷。

3)迭代器的使用方式:先問后拿。問:boolean hasNext()該方法詢問迭代器當前集合是否還有元素;拿:E next()該方法會獲取當前元素。迭代器的迭代方法是while循環量身定制的。

 List list=new ArrayList(); list.add("One"); list.add("#");

 Iterator it=list.iterator();

 while(it.hasNext()){//集合中是否還有下一個元素

 Object element=it.next();//有就將其取出

 System.out.println(element); }

4)迭代器中的刪除問題:在迭代器迭代的過程中,我們不能通過“集合”的增刪等操作,來改變該集合的元素數量!否則會引發迭代異常!若想刪除迭代出來的元素,只能通過Iterator。迭代器在使用自己的remove()方法時,可以將剛剛獲取的元素從集合中刪除,但是不能重復調用兩次!即在不迭代的情況下,不能在一個位置刪兩次。

 while(it.hasNext()){//集合中是否還有下一個元素

 String element=(String)it.next();//有就將其取出,next返回值為E(泛型)默認為Object所以需要強轉

 if("#".equals(element)){ //list.remove(element);不可以!

 it.remove();//刪除當前位置元素 }  }

1.1.16 泛型

1)泛型是 JDK1.5引入的新特性,泛型的本質是參數化類型。在類、接口、方法的定義過程中,所操作的數據類型為傳入的指定參數類型。所有的集合類型都帶有泛型參數,這樣在創建集合時可以指定放入集合中的對象類型。同時,編譯器會以此類型進行檢查。

2)ArrayList支持泛型,泛型尖括號里的符號可隨便些,但通常大寫E。

3)迭代器也支持泛型,但是迭代器使用的泛型應該和它所迭代的集合的泛型類型一致!

4)泛型只支持引用類型,不支持基本類型,但可以使用對應的包裝類

5)如果泛型不指定類型的話,默認為Object類型。

 ArrayList<Point> list=new ArrayList<Point>();

 list.add(new Point(1,2)); list.add(new Point(3,4));

 //list.add("哈哈");//定義泛型后,只運行Point類型,否則造型異常

 for(int i=0;i<list.size();i++){ Point p=/*(Point)也不需要強轉造型了*/list.get(i);

 System.out.println(p.getX()); }

 Iterator<Point> it=list.iterator(); while(it.hasNext()){  Point p=it.next();

 //也不需要強轉了 System.out.println(p); }

6)自定義泛型

 Point p=new Point(1,2);//只能保存整數

 //把Point類的int都改成泛型E,或者也可設置多個泛型Point<E,Z>

 Point<Double> p1=new Point<Double>(1.0,2.3);//設置一個泛型

 Point<Double,Long> p2=new Point<Double,Long>(2.3,3L);//設置多個泛型

1.1.17 增強型for循環

JDK在1.5版本推出了增強型for循環,可以用于數組和集合的遍歷。

u 注意事項:集合中要有值,否則直接退出(不執行循環)。

1)老循環:自己維護循環次數, 循環體自行維護獲取元素的方法。

 int[] array=new int[]{1,2,3,4,5,6,7};

 for(int i=0;i<array.length;i++){//維護循環次數

 int element=array[i];//獲取數組元素 System.out.print(element); }

2)新循環:自動維護循環次數(由遍歷的數組或集合的長度決定),自動獲取每次迭代的元素。

 int[] array=new int[]{1,2,3,4,5,6,7};

 for(int element:array){ System.out.print(element); }

3)新循環執行流程:遍歷數組array中的每個元素,將元素一次賦值給element后進入循環體,直到所有元素均被迭代完畢后退出循環。

u 注意事項:使用新循環,element的類型應與循環迭代的數組或集合中的元素類型一致!至少要是兼容類型!

4)新循環的內部實現是使用迭代器完成的Iterator。

5)使用新循環遍歷集合:集合若使用新循環,應該為其定義泛型,否則我們只能使用Object作為被接收元素時的類型。通常情況下,集合都要加泛型,要明確集合中的類型,集合默認是Object。

 ArrayList<String> list=new ArrayList<String>();

 list.add("張三"); list.add("李四"); list.add("王五");

 for(String str:list){//默認是Object自己加泛型String  System.out.println(str); }

1.1.18 List高級-數據結構:Queue隊列

隊列(Queue)是常用的數據結構,可以將隊列看成特殊的線性表,隊列限制了對線性表的訪問方式:只能從線性表的一端添加(offer)元素,從另一端取出(poll)元素。Queue接口:在包java.util.Queue。

1)隊列遵循先進先出原則:FIFO(First Input First Output)隊列不支持插隊,插隊是不道德的。

2)JDK中提供了Queue接口,同時使得LinkedList實現了該接口(選擇LinkedList實現Queue的原因在于Queue經常要進行插入和刪除的操作,而LinkedList在這方面效率較高)。

3)常用方法:

①boolean offer(E e):將一個對象添加至隊尾,如果添加成功則返回true。

②poll():從隊列中取出元素,取得的是最早的offer元素,從隊列中取出元素后,該元素會從隊列中刪除。若方法返回null說明 隊列中沒有元素了。

③peek():獲取隊首的元素(不刪除該元素!)

eg:隊列相關操作

 Queue<String> queue=new LinkedList<String>();

 queue.offer("A");  queue.offer("B"); queue.offer("C");

 System.out.println(queue);//[A, B, C]

 System.out.println("隊首:"+queue.peek());//獲取隊首元素,但不令其出隊

 String element=null; while((element=queue.poll())!=null){

 System.out.println(element); }

1.1.19 List高級-數據結構:Deque棧

棧(Deque)是常用的數據結構,是Queue隊列的子接口,因此LinkedList也實現了Deque接口。棧將雙端隊列限制為只能從一端入隊和出隊,對棧而言即是入棧和出棧。子彈夾就是一種棧結構。在包java.util.Deque下。

1)棧遵循先進后出的原則:FILO(First Input Last Output)。

2)常用方法:

①push:壓入,向棧中存入數據。

②pop:彈出,從棧中取出數據。

③peek:獲取棧頂位置的元素,但不取出。

u 注意事項:我們在使用pop獲取棧頂元素之前,應現使用peek方法獲取該元素,確定該元素不為null的情況下才應該將該元素從棧中彈出”,否則若棧中沒有元素后,我們調用pop會拋出異常“NoSuchElementException”。

eg:棧相關操作

 Deque<Character> deque=new LinkedList<Character>();

 for(int i=0;i<5;i++){ deque.push((char)('A'+i)); }

 System.out.println(deque);

 //注意使用peek判斷棧頂是否有元素

 while(deque.peek()!=null){ System.out.print(deque.pop()+" "); }

1.1.20 Set集合的實現類HashSet

Set是無序,用于存儲不重復的對象集合。在Set集合中存儲的對象中,不存在兩個對象equals比較為true的情況。

1)HashSet和TreeSet是Set集合的兩個常見的實現類,分別用hash表和排序二叉樹的方式實現了Set集合。HashSet是使用散列算法實現Set的。

2)Set集合沒有get(int index)方法,我們不能像使用List那樣,根據下標獲取元素。想獲取元素需要使用Iterator。

3)向集合添加元素也使用add方法,但是add方法不是向集合末尾追加元素,因為無序。

4)宏觀上講:元素的順序和存放順序是不同的,但是在內容不變的前提下,存放順序是相同的,但在我們使用的時候,要當作是無序的使用。

 Set<String> set=new HashSet<String>();//多態

 //也可HashSet<String> set=new HashSet<String>();

 set.add("One"); set.add("Two"); set.add("Three"); Iterator<String> it=set.iterator();

 while(it.hasNext()){  String element=it.next(); System.out.print(element+" "); }

 for(String element:set){ System.out.print(element+" "); }//新循環遍歷Set集合

5)hashCode對HashSet的影響:若我們不重寫hashCode,那么使用的就是Object提供的,而該方法是返回地址(句柄)!換句話說,就是不同的對象,hashCode不同。

6)對于重寫了equals方法的對象,強烈要求重寫繼承自Object類的hashCode方法的,因為重寫hashCode方法與否會對集合操作有影響!

7)重寫hashCode方法需要注意兩點:

①與equals方法的一致性,即equals比較返回為true的對象其hashCode方法返回值應該相同。

②hashCode返回的數值應該符合hash算法要求,如果有很多對象的hashCode方法返回值都相同,則會大大降低hash表的效率。一般情況下,可以使用IDE(如Eclipse)提供的工具自動生成hashCode方法。

8)boolean contains(Object o)方法:查看對象是否在set中被包含。下例雖然有新創建的對象,但是通過散列算法找到了位置后,和里面存放的元素進行equals比較為true,所以依然認為是被包含的(重寫equals了時)。

 Set<Point> set=new HashSet<Point>(); set.add(new Point(1,2));

 set.add(new Point(3,4));   System.out.println(set.contains(new Point(1,2)));

9)HashCode方法和equals方法都重寫時對hashSet的影響:將兩個對象同時放入HashSet集合,發現存在,不再放入(不重復集)。當我們重寫了Point的equals方法和hashCode方法后,我們發現雖然p1和p2是兩個對象,但是當我們將他們同時放入集合時,p2對象并沒有被添加進集合。因為p1在放入后,p2放入時根據p2的hashCode計算的位置相同,且p2與該位置的p1的equals比較為true, hashSet認為該對象已經存在,所以拒絕將p2存入集合。

 Set<Point> set=new HashSet<Point>();

 Point p1=new Point(1,2); Point p2=new Point(1,2);

 System.out.println("兩者是否同一對象:"+(p1==p2));

 System.out.println("兩者內容是否一樣:"+p1.equals(p2));

 System.out.println("兩者HashCode是否一樣:"+ (p1.hashCode()==p2.hashCode()));

 set.add(p1); set.add(p2); System.out.println("hashset集合的元素數"+set.size());

 for(Point p:set){ System.out.println(p); }

10)不重寫hashCode方法,但是重寫了equals方法對hashSet的影響:兩個對象都可以放入HashStet集合中,因為兩個對象具有不用的hashCode值,那么當他們在放入集合時,通過hashCode值進行的散列算法結果就不同。那么他們會被放入集合的不同位置,位置不相同,HashSet則認為它們不同,所以他們可以全部被放入集合。

11)重寫了hashCode方法,但是不重寫equals方法對hashSet的影響:在hashCode相同的情況下,在存放元素時,他們會在相同的位置,hashSet會在相同位置上將后放入的對象與該位置其他對象一次進行equals比較,若不相同,則將其存入在同一個位置存入若干元素,這些元素會被放入一個鏈表中。由此可以看出,我們應該盡量使得多種類的不同對象的hashcode值不同,這樣才可以提高HashSet在檢索元素時的效率,否則可能檢索效率還不如List。

12)結論:不同對象存放時,不會保存hashCode相同并且equals相同的對象,缺一不可。否則HashSet不認為他們是重復對象。

1.1.21 Map集合的實現類HashMap

Map接口定義的集合又稱為查找表,用于存儲所謂“Key-Value”鍵值對。Key可以看成是Value的索引。而往往Key是Value的一部分內容。

1)Key不可以重復,但所保存的Value可以重復。

2)根據內部結構的不同,Map接口有多種實現類,其中常用的有內部為hash表實現的HashMap和內部為排序二叉樹實現的TreeMap。同樣這樣的數據結構在存放數據時,也不建議存放兩種以上的數據類型,所以,通常我們在使用Map時也要使用泛型約束存儲內容的類型。

3)創建Map時使用泛型,這里要約束兩個類型,一個是key的類型,一個是value的類型。

4)基本原理圖:

image.png

5)HashMap集合中常用的方法:

①V put(K Key,V value):將元素以Key-Value的形式放入map。若重復保存相同的key時,實際的操作是替換Key所對應的value值。

②V get(Object key):返回key所對應的value值。如果不存在則返回null。

③boolean containsKey(Object Key):判斷集合中是否包含指定的Key。

④boolean containsValue(Object value):判斷集合中是否包含指定的Value。

6)若給定的key在map中不存在則返回null,所以,原則上在從map中獲取元素時要先判斷是否有該元素,之后再使用,避免空指針異常的出現。Map在獲取元素時非常有針對性,集合想獲取元素需要遍歷集合內容,而Map不需要,你只要給他特定的key就可以獲取該元素。

 Map<String,Point> map=new HashMap<String,Point>();

 map.put("1,2", new Point(1,2)); map.put("3,4", new Point(3,4));

 Point p=map.get("1,2");  System.out.println("x="+p.getX()+",y="+p.getY());

 map.put("1,2", new Point(5,6));//會替換之前的

 p=map.get("1,2");  System.out.println("x="+p.getX()+",y="+p.getY());

 p=map.get("haha"); System.out.println("x="+p.getX()+",y="+p.getY());//會報空指異常

eg:統計每個數字出現的次數。步驟:①將字符串str根據“,”拆分。②創建map。③循環拆分后的字符串數組。④蔣梅一個數字作為key在map中檢查是否包含。⑤包含則對value值累加1。⑥不包含則使用該數字作為key,value為1存入map。

 String str="123,456,789,456,789,225,698,759,456";

 String[] array=str.split(",");

 Map<String,Integer> map=new HashMap<String,Integer>();

 for(String number:array){ if(map.containsKey(number)){

 int sum=map.get(number);//將原來統計的數字取出 sum++; //對統計數字加1

 map.put(number, sum); //放回 map.put(number, map.get(number)+1);等同上三部

 }else{ map.put(number, 1);//第一次出現value為1 } }

 System.out.println(map);//HashMap也重寫了toString()

7)計算機中有這么一句話:越靈活的程序性能越差,顧及的多了。

8)遍歷HashMap方式一:獲取所有的key并根據key獲取value從而達到遍歷的效果(即迭代Key)。keySet()方法:是HashMap獲取所有key的方法,該方法可以獲取保存在map下所有的key并以Set集合的形式返回。

 Map<String,Point> map=new HashMap<String,Point>();

 map.put("1,2", new Point(1,2)); map.put("2,3", new Point(2,3));

 map.put("3,4", new Point(3,4)); map.put("4,5", new Point(4,5));

 /** 因為key在HashMap的泛型中規定了類型為String,所以返回的Set中的元素也是String,為了更好的使用,我們在定義Set類型變量時也應該加上泛型 */

 Set<String> keyset=map.keySet();

 for(String key:keyset){ Point p=map.get(key);//根據key獲取value

 System.out.println(key+":"+p.getX()+","+p.getY()); }

 for(Iterator<String> it=keyset.iterator()  ; it.hasNext() ; ){//普通for循環

 String key=it.next();  Point p=map.get(key);

 System.out.println(key+":"+p.getX()+","+p.getY()); }

9)LinkedHashMap:用法和HashMap相同,內部維護著一個鏈表,可以使其存放元素時的順序與迭代時一致。

10)Entry類,遍歷HashMap方式二:以“鍵值對”的形式迭代。Map支持另一個方法entrySet():該方法返回一個Set集合,里面的元素是map中的每一組鍵值對,Map以Entry類的實例來描述每一個鍵值對。其有兩個方法:getKey()獲取key值;getValue()獲取value值。Entry也需要泛型的約束,其約束的泛型應該和Map相同!Entry所在位置:java.util.Map.Entry。

 Map<String,Point> map=new LinkedHashMap<String,Point>();

 map.put("1,2", new Point(1,2)); map.put("2,3", new Point(2,3));

 map.put("3,4", new Point(3,4)); map.put("4,5", new Point(4,5)); //泛型套泛型

 Set<Entry<String,Point>> entrySet=map.entrySet();//Set的泛型不會變,就是Entry

 for(Entry<String,Point> entry:entrySet){

 String key=entry.getKey();//獲取key Point p=entry.getValue();//獲取value

 System.out.println(key+","+p.getX()+","+p.getY()); }

11)List、Map、Set三個接口存儲元素時各有什么特點:

①List:是有序的Collection,使用此接口能夠精確的控制每個元素插入的位置。用戶能夠使用索引(元素在List中的位置,類似于數組下標)來訪問List中的元素,這類似于Java的數組。

②Set:是一種不包含重復的元素的Collection,即任意的兩個元素e1和e2都有e1.equals(e2)=false,Set最多有一個null元素。

③Map:請注意,Map沒有繼承Collection接口,Map提供key到value的映射。

1.1.22 單例模式和模版方法模式

設計模式是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。

1)使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。簡單的說:設計模式是經典問題的模式化解決方法。

2)經典設計模式分為三種類型,共23類。

創建模型式:單例模式、工廠模式等

結構型模式:裝飾模式、代理模式等

行為型模式:模版方法模式、迭代器模式等

3)單例設計模式:意圖:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。適用性:當類只能有一個實例而且客戶可以從一個眾所周知的訪問點訪問它。任何情況下,該類只能創建一個實例!

4)單例設計模式創建步驟:
①定義一個私有的靜態的當前類型的屬性。
②私有化構造方法。
③定義一個靜態的可以獲取當前類實例的方法。這個方法中我們可以判斷是否創建過實例,創建過就直接返回,從而達到單例的效果。

 private static DemoSingleton obj;

 //或private static DemoSingleton obj=new DemoSingleton();

 private DemoSingleton(){ }

 public static DemoSingleton getInstance(){

 if(obj==null){ obj= new DemoSingleton(); }

 return obj;        
}

5)模版方法模式:意圖:定義一個操作中的算法過程的框架,而將一些步驟延遲到子類中實現。類似于定義接口或抽象類,子類去實現抽象方法。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。