【Java】Java基礎

1:計算機概述(瞭解)

(1)計算機
(2)計算機硬件
(3)計算機軟件
系統軟件:window,linux,mac
應用軟件:qq,yy
(4)軟件開發(理解)
軟件:是由數據和指令組成的。(計算器)
開發:就是把軟件做出來。
如何實現軟件開發呢?
就是使用開發工具和計算機語言做出東西來
(5)語言
自然語言:人與人交流溝通的
計算機語言:人與計算機交流溝通的
C,C++,C#,Java
(6)人機交換
圖形界面:操作方便只管
DOS命令:需要記憶一些常見的命令

 

2:鍵盤功能鍵的認識和快捷鍵(掌握)

(1)功能鍵的認識
tab
shift
ctrl
alt
windos
空格
上下左右
回車
截圖
(2)快捷鍵
全選 Ctrl+A
複製 Ctrl+C
粘貼 Ctrl+V
剪切 Ctrl+X
撤銷 Ctrl+Z
保存 Ctrl+S

 

3:常見的DOS命令(掌握)

(1)常見的如下
盤符的切換
d:回車
目錄的進入
cd javase
cd javase\code
目錄的回退
cd..
cd\
清屏
cls
退出
exit
(2)其他的幾個(瞭解)
創建目錄
刪除目錄
創建文件
刪除文件
顯示目錄下的內容
刪除帶內容的目錄

 

4:Java語言概述(瞭解)

(1)Java語言的發展史
Java之父

JDK1.4.2
JDK5
JDK7
(2)Java語言的特點
有很多小特點,重點有兩個開源,跨平臺
(3)Java語言是跨平臺的,請問是如何保證的呢?(理解)
我們是通過翻譯的案例講解的。

針對不同的操作系統,提高不同的jvm來實現的。
(4)Java語言的平臺
JavaSE
JavaME--Android
JavaEE

 

5:JDK,JRE,JVM的作用及關係(掌握)

(1)作用
JVM:保證Java語言跨平臺
JRE:Java程序的運行環境
JDK:Java程序的開發環境
(2)關係
JDK:JRE+工具
JRE:JVM+類庫


 

6:JDK的下載,安裝,卸載(掌握)

(1)下載到官網。
A:也可以到百度搜索即可。
B:我給你。
(2)安裝
A:綠色版 解壓就可以使用
B:安裝版 必須一步一步的安裝,一般只要會點擊下一步即可

注意:
建議所有跟開發相關的軟件都不要安裝在有中文或者空格的目錄下。
(3)卸載
A:綠色版 直接刪除文件夾
B:安裝版
a:控制面板 -- 添加刪除程序
b:通過專業的軟件卸載工具。(比如360的軟件管家卸載)

 

7:第一個程序:HelloWorld案例(掌握)

class HelloWorld {
public static void main(String[] args) {
System.out.println("HelloWorld");
}
}
(1)程序解釋:
A:Java程序的最基本單位是類,所以我們要定義一個類。
格式:class 類名
舉例:class HelloWorld
B:在類中寫內容的時候,用大括號括起來。
C:Java程序要想執行,必須有main方法。
格式:public static void main(String[] args)
D:要指向那些東西呢,也用大括號括起來。
E:你要做什麼呢?今天我們僅僅做了一個簡單的輸出
格式:System.out.println("HelloWorld");
注意:""裏面的內容是可以改動的。

(2)Java程序的開發執行流程:
A:編寫java源程序(.java)
B:通過javac命令編譯生成.class文件
C:通過java命令運行.class文件
 

8:常見的問題(掌握)

(1)擴展名被隱藏
如何找到:工具--文件夾選項--查看--去除隱藏擴展名的那個勾勾
(2)我要求文件名稱和類名一致。
實際上不這樣做也是可以的。
但是,注意:
javac後面跟的是文件名+擴展名
java後面跟的類名不帶擴展名

(3)Java語言嚴格區分大小寫,請注意。
還有就是單詞不要寫錯了。
(4)見到非法字符: \65307肯定是中文問題。
我們寫程序要求標點符號必須全部是英文狀態。
(5)括號的配對問題。
一般來說,括號都是成對出現的。
(6)遇到
在類 HelloWorld 中找不到主方法, 請將主方法定義爲
肯定是主方法的格式問題。

 

9:path環境變量(掌握)

(1)path環境變量的作用
保證javac命令可以在任意目錄下運行。
同理可以配置qq等
(2)path配置的兩種方案:
A:方案1(瞭解)
B:方案2
找到環境變量的位置,在系統變量裏面
新建:
變量名:JAVA_HOME
變量值:D:\develop\Java\jdk1.7.0_60
修改:
變量名:Path
變量值:%JAVA_HOME%\bin;以前的內容

 

10:classpath環境變量(理解)

(1)classpath環境變量的作用
保證class文件可以在任意目錄下運行
(2)classpath環境變量的配置
找到環境變量的位置,在系統變量裏面
新建:
變量名:classpath

變量值:E:\JavaSE\code\HelloWorld案例

============================================================================

 

1:關鍵字(掌握)

(1)被Java語言賦予特定含義的單詞
(2)特點:
全部小寫
(3)注意事項:
A:goto和const作爲保留字存在。
B:類似於Notepad++這樣的高級記事本會對關鍵字有特殊顏色標記

 

2:標識符(掌握)

(1)就是給類,接口,方法,變量等起名字的字符序列
(2)組成規則:
A:英文大小寫字母
B:數字
C:$_
(3)注意事項:
A:不能以數字開頭
B:不能是java中的關鍵字
C:區分大小寫
(4)常見的命名規則(見名知意)
A:包 全部小寫
單級包:小寫
舉例:liuyi,com
多級包:小寫,並用.隔開
舉例:com.baidu
B:類或者接口
一個單詞:首字母大寫
舉例:Student,Demo
多個單詞:每個單詞首字母大寫
舉例:HelloWorld,StudentName
C:方法或者變量
一個單詞:首字母小寫
舉例:name,main
多個單詞:從第二個單詞開始,每個單詞首字母大寫
舉例:studentAge,showAllNames()
D:常量
全部大寫

一個單詞:大寫
舉例:PI
多個單詞:大寫,並用_隔開
舉例:STUDENT_MAX_AGE

 

3:註釋(掌握)

(1)就是對程序進行解釋說明的文字
(2)分類:
A:單行註釋 //
B:多行註釋 /**/
C:文檔註釋(後面講) /** */
(3)把HelloWorld案例寫了一個帶註釋的版本。
後面我們要寫一個程序的過程。
需求:
分析:
實現:
代碼體現:
(4)註釋的作用
A:解釋說明程序,提高了代碼的閱讀性。
B:可以幫助我們調試程序。
後面我們會講解一個更高端的一個調試工具

 

4:常量(掌握)

(1)在程序執行的過程中,其值不發生改變的量
(2)分類:
A:字面值常量
B:自定義常量
(後面講)
(3)字面值常量
A:字符串常量    "hello"
B:整數常量 12,23
C:小數常量 12.345
D:字符常量 'a','A','0'
E:布爾常量 true,false
F:空常量 null(後面講)
(4)在Java中針對整數常量提供了四種表現形式
A:二進制         由0,1組成。以0b開頭。
B:八進制         由0,1,...7組成。以0開頭。
C:十進制         由0,1,...9組成。整數默認是十進制
D:十六進制     由0,1,...9,a,b,c,d,e,f(大小寫均可)組成。以0x開頭。

 

5:進制轉換(瞭解)

(1)其他進制到十進制
係數:就是每一個位上的數值
基數:x進制的基數就是x
權:對每一個位上的數據,從右,並且從0開始編號,對應的編號就是該數據的權。

結果:係數*基數^權次冪之和。
(2)十進制到其他進制
除基取餘,直到商爲0,餘數反轉。
(3)進制轉換的快速轉換法
A:十進制和二進制間的轉換
8421碼。
B:二進制到八進制,十六進制的轉換

 

6:變量(掌握)

(1)在程序的執行過程中,其值在某個範圍內可以發生改變的量
(2)變量的定義格式:
A:數據類型 變量名 = 初始化值;
B:數據類型 變量名;
  變量名 = 初始化值;

 

7:數據類型(掌握)

(1)Java是一種強類型語言,針對每種數據都提供了對應的數據類型。
(2)分類:
A:基本數據類型:4類8種
B:引用數據類型:類,接口,數組。
(3)基本數據類型
A:整數 佔用字節數
byte         1
short        2
int            4
long         8

B:浮點數
float         4
double     8
C:字符
char         2
D:布爾
boolean   1

注意:
整數默認是int類型,浮點數默認是double

長整數要加L或者l。
單精度的浮點數要加F或者f。


 

8:數據類型轉換(掌握)

(1)boolean類型不參與轉換
(2)默認轉換
A:從小到大
B:byte,short,char -- int -- long -- float -- double
C:byte,short,char之間不相互轉換直接轉成int類型參與運算
(3)強制轉換
A:從大到小
B:可能會有精度的損失,一般不建議這樣使用。
C:格式:
目標數據類型 變量名 = (目標數據類型) (被轉換的數據);
(4)思考題和麪試題:
A:下面兩種方式有區別嗎?
float f1 = 12.345f;
float f2 = (float)12.345;
B:下面的程序有問題嗎,如果有,在哪裏呢?
byte b1 = 3;
byte b2 = 4;
byte b3 = b1 + b2;  // 報錯。

正確寫法如下:

byte b3 = (byte) (b1 + b2);

byte b4 = 3 + 4;
C:下面的操作結果是什麼呢?
byte b = (byte)130; // -126
D:字符參與運算
是查找ASCII裏面的值
'a' 97
'A' 65
'0' 48

System.out.println('a');
System.out.println('a' + 1);
E:字符串參與運算
這裏其實是字符串的連接

System.out.println("hello"+'a'+1);
System.out.println('a'+1+"hello");
System.out.println("5+5="+5+5);

System.out.println(5+5+"=5+5");

 

============================================================================

1:運算符(掌握)

(1)算術運算符
A:+,-,*,/,%,++,--
B:+的用法
a:加法
b:正號
c:字符串連接符
C:/和%的區別
數據做除法操作的時候,/取得是商,%取得是餘數
D:++和--的用法
a:他們的作用是自增或者自減
b:使用
**單獨使用
放在操作數據的前面和後面效果一樣。

a++或者++a效果一樣。
**參與操作使用
放在操作數的前面:先自增或者自減,再參與操作

int a = 10;
int b = ++a;
放在操作數的後面:先參與操作,再自增或者自減
int a = 10;
int b = a++;
(2)賦值運算符
A:=,+=,-=,*=,/=,%=等
B:=叫做賦值運算符,也是最基本的賦值運算符
int x = 10; 把10賦值給int類型的變量x。
C:擴展的賦值運算符的特點
隱含了自動強制轉換。

面試題:
short s = 1;
s = s + 1;

short s = 1;
s += 1;
請問上面的代碼哪個有問題?

(3)比較運算符
A:==,!=,>,>=,<,<=
B:無論運算符兩端簡單還是複雜最終結果是boolean類型。
C:千萬不要把==寫成了=
(4)邏輯運算符
A:&,|,^,!,&&,||
B:邏輯運算符用於連接boolean類型的式子
C:結論
&:有false則false
|:有true則true
^:相同則false,不同則true。
情侶關係。
!:非true則false,非false則true

&&:結果和&是一樣的,只不過有短路效果。左邊是false,右邊不執行。
||:結果和|是一樣的,只不過有短路效果。左邊是true,右邊不執行

(5)位運算符(瞭解)
A:^的特殊用法
一個數據針對另一個數據位異或兩次,該數不變
B:面試題
a:請實現兩個變量的交換
**採用第三方變量
**用位異或運算符
左邊a,b,a
右邊a^b
b:請用最有效率的方式計算出2乘以8的結果
2<<3
(6)三元運算符
A:格式
比較表達式?表達式1:表達式2;
B:執行流程:
首先計算比較表達式的值,看是true還是false。
如果是true,表達式1就是結果。
如果是false,表達式2就是結果。
C:案例:
a:比較兩個數據是否相等
b:獲取兩個數據中的最大值
c:獲取三個數據中的最大值

2:鍵盤錄入(掌握)

(1)實際開發中,數據是變化的,爲了提高程序的靈活性,我們加入鍵盤錄入數據。
(2)如何實現呢?目前就記住
A:導包
import java.util.Scanner;
位置:在class的上邊
B:創建對象
Scanner sc = new Scanner(System.in);
C:獲取數據
int x = sc.nextInt();
(3)把三元運算符的案例加入鍵盤錄入改進。
 

3:流程控制語句

(1)順序結構         從上往下,依次執行
(2)選擇結構 按照不同的選擇,執行不同的代碼
(3)循環結構         做一些重複的代碼
 

4:if語句(掌握)

(1)三種格式
A:格式1
if(比較表達式) {
語句體;
}

執行流程:
判斷比較表達式的值,看是true還是false
如果是true,就執行語句體
如果是false,就不執行語句體

B:格式2
if(比較表達式) {
語句體1;
}else {
語句體2;
}

執行流程:
判斷比較表達式的值,看是true還是false
如果是true,就執行語句體1
如果是false,就執行語句體2

C:格式3
if(比較表達式1) {
語句體1;
}else if(比較表達式2){
語句體2;
}
...
else {
語句體n+1;
}

執行流程:
判斷比較表達式1的值,看是true還是false
如果是true,就執行語句體1
如果是false,就繼續判斷比較表達式2的值,看是true還是false
如果是true,就執行語句體2
如果是false,就繼續判斷比較表達式3的值,看是true還是false
...
如果都不滿足,就執行語句體n+1
(2)注意事項
A:比較表達式無論簡單還是複雜,結果是boolean類型
B:if語句控制的語句體如果是一條語句,是可以省略大括號的;如果是多條,不能省略。
建議:永遠不要省略。
C:一般來說,有左大括號,就沒有分號,有分號,就沒有左大括號。
D:else後面如果沒有if,是不會出現比較表達式的。
E:三種if語句其實都是一個語句,只要有一個執行,其他的就不再執行。
(3)案例:
A:比較兩個數是否相等
B:獲取兩個數中的最大值
C:獲取三個數中的最大值(if語句的嵌套)
D:根據成績輸出對應的等級
E:根據月份,輸出對應的季節
F:根據x計算對應y的值並輸出
(4)三元運算符和if語句第二種格式的關係
所有的三元運算符能夠實現的,if語句的第二種格式都能實現。
反之不成立。

如果if語句第二種格式控制的語句體是輸出語句,就不可以。
因爲三元運算符是一個運算符,必須要有一個結果返回,不能是一個輸出語句。

============================================================================

1:switch語句(掌握)

(1)格式:
switch(表達式) {
case 值1:
語句體1;
break;
case 值2:
語句體2;
break;
...
default:
語句體n+1;
break;
}


格式解釋說明:
switch:說明這是switch語句。
表達式:可以是byte,short,int,char
JDK5以後可以是枚舉
JDK7以後可以是字符串
case:後面的值就是要和表達式進行比較的值
break:表示程序到這裏中斷,跳出switch語句
default:如果所有的情況都不匹配,就執行這裏,相當於if語句中的else
(2)面試題
switch語句的表達式可以是byte嗎?可以是long嗎?可以是String嗎?
可以,不可以,JDK7以後可以
(3)執行流程:
A:首先計算表達式的值
B:和每一個case進行匹配,如果有就執行對應的語句體,看到break就結束。
C:如果沒有匹配,就執行default的語句體n+1。

(4)注意事項:
A:case後面只能是常量,不能是變量,而且,多個case後面的值不能出現相同的
B:default可以省略嗎?
可以省略,但是不建議,因爲它的作用是對不正確的情況給出提示。
特殊情況:
case就可以把值固定。
A,B,C,D
C:break可以省略嗎?
可以省略,但是結果可能不是我們想要的。
會出現一個現象:case穿透。
最終我們建議不要省略

D:default一定要在最後嗎?
不是,可以在任意位置。但是建議在最後。
E:switch語句的結束條件
a:遇到break就結束了
b:執行到末尾就結束了

(5)案例:
A:鍵盤錄入一個數字(1-7),輸出對應的星期幾。
B:單項選擇題
C:鍵盤錄入一個字符串的問題
String s = sc.nextLine();
D:根據給定的月份,輸出對應的季節
(6)if語句和switch語句各自的場景
A:if
針對boolean類型的判斷
針對一個範圍的判斷
針對幾個常量的判斷
B:switch
針對幾個常量的判斷
 

2:循環語句(掌握)

(1)有三種:for,while,do...while
(2)for循環語句
A:格式
for(初始化語句;判斷條件語句;控制條件語句){
循環體語句;
}

執行流程:
a:執行初始化語句
b:執行判斷條件語句
如果這裏是true,就繼續
如果這裏是false,循環就結束
c:執行循環體語句
d:執行控制條件語句
e:回到b
B:注意事項
a:判斷條件語句無論簡單還是複雜,結果是boolean類型
b:循環體語句如果是一條,可以省略大括號,但是不建議
c:有分號就沒有左大括號,有左大括號就沒有分號
C:案例
a:輸出10次HelloWorld
b:輸出1-10的數據
c:輸出10-1的數據
d:求1-10的和
e:求1-100的和,求1-100的偶數和,求1-100的奇數和
f:求5的階乘
g:在控制檯打印水仙花數
h:統計水仙花個數
i:改進版的迴文數
一個五位數
個位 = 萬位
十位 = 千位
個位 + 十位 + 千位 + 萬位 = 百位
j:統計1-1000之間同時滿足如下條件的數據有多少個
x%3==2
x%5==3
x%7==2
(3)while循環
A:基本格式
while(判斷條件語句) {
循環體語句;
}

擴展格式:
初始化語句;
while(判斷條件語句){
循環體語句;
控制條件語句;
}

通過查看這個格式,我們就知道while循環可以和for循環等價轉換。
B:while的練習
把for語句的練習用while改進
C:for和while的區別
a:使用上的區別
for語句的那個控制條件變量,在循環結束後不能在使用了。
而while的可以繼續使用。
b:理解上的區別
for適合於一個範圍的判斷
while適合次數不明確的
舉例:喫葡萄

D:案例:
a:珠穆朗瑪峯問題
b:小芳存錢問題(break以後才能做)
(4)do...while循環
A:基本格式
do {
循環體語句;
}while(判斷條件語句);

擴展格式:
初始化語句;
do {
循環體語句;
控制條件語句;
}while(判斷條件語句);

通過查看格式,我們就可以看出其實三種循環的格式可以是統一的。
B:三種循環的區別
a:do...while循環至少執行一次循環體
b:for和while必須先判斷條件是否是true,然後後才能決定是否執行循環體

(5)循環使用的注意事項(死循環)
A:一定要注意修改控制條件,否則容易出現死循環。
B:最簡單的死循環格式
a:while(true){...}

b:for(;;){}

3:控制跳轉語句(掌握)

(1)break:中斷的意思
A:用在循環switch語句中,離開此應用場景無意義。
B:作用
a:跳出單層循環
b:跳出多層循環,需要標籤語句的配合
(2)continue:繼續
A:用在循環中,離開此應用場景無意義。
B:作用
a:跳出單層循環的一次,可以繼續下一次
C:填空題
for(int x=1; x<=10; x++) {
if(x%3 == 0) {
//補齊代碼
}
System.out.println("Java");
}
如何讓控制檯輸出2次:Java
如何讓控制檯輸出7次:Java
如何讓控制檯輸出13次:Java

(3)return:返回
A:用於結束方法的,後面還會在繼續講解和使用。
B:一旦遇到return,程序就不會在繼續往後執行

============================================================================

1:方法(掌握)

(1)方法:就是完成特定功能的代碼塊。
注意:在很多語言裏面有函數的定義,而在Java中,函數被稱爲方法。
(2)格式:
修飾符 返回值類型 方法名(參數類型 參數名1,參數類型 參數名2...) {
方法體語句;
return 返回值;
}

修飾符:目前就用 public static。後面再詳細講解其他修飾符
返回值類型:就是功能結果的數據類型
方法名:就是起了一個名字,方便我們調用該方法。
參數類型:就是參數的數據類型
參數名:就是變量
參數分類:
實參:實際參與運算的數據
形參:方法上定義的,用於接收實際參數的變量
方法體語句:就是完成功能的代碼塊
return:結束方法
返回值:就是功能的結果,由return帶給調用者。
(3)兩個明確:
返回值類型:結果的數據類型
參數列表:參數的個數及對應的數據類型
(4)方法調用
A:有明確返回值的方法
a:單獨調用,沒有意義
b:輸出調用,不是很好,因爲我可能需要不結果進行進一步的操作。但是講課一般我就用了。
c:賦值調用,推薦方案
B:void類型修飾的方法
a:單獨調用
(5)案例:
A:求和方案
B:獲取兩個數中的較大值
C:比較兩個數據是否相同
D:獲取三個數中的最大值
E:輸出m行n列的星形
F:輸出nn乘法表
(6)方法的注意事項
A:方法不調用不執行
B:方法之間是平級關係,不能嵌套定義
C:方法定義的時候,參數是用,隔開的
D:方法在調用的時候,不用在傳遞數據類型
E:如果方法有明確的返回值類型,就必須有return語句返回。
(7)方法重載
在同一個類中,方法名相同,參數列表不同。與返回值無關。


參數列表不同:
參數的個數不同。
參數的對應的數據類型不同。

(8)方法重載案例
不同的類型的多個同名方法的比較。

2:數組(掌握)

(1)數組:存儲同一種數據類型的多個元素的容器。
(2)特點:每一個元素都有編號,從0開始,最大編號是長度-1。
         編號的專業叫法:索引
(3)定義格式
A:數據類型[] 數組名;
B:數據類型 數組名[];

推薦是用A方式,B方法就忘了吧。
但是要能看懂
(4)數組的初始化
A:動態初始化
只給長度,系統給出默認值

舉例:int[] arr = new int[3];
B:靜態初始化
給出值,系統決定長度

舉例:int[] arr = new int[]{1,2,3};
簡化版:int[] arr = {1,2,3};
(5)Java的內存分配
A:棧                      存儲局部變量
B:堆                      存儲所有new出來的
C:方法區               (面向對象部分詳細講解)
D:本地方法區        (系統相關)
E:寄存器               (CPU使用)

注意:
a:局部變量     在方法定義中或者方法聲明上定義的變量。
b:棧內存和堆內存的區別
棧:數據使用完畢,就消失。
堆:每一個new出來的東西都有地址


    每一個變量都有默認值
byte,short,int,long         0
float,double                   0.0
char                                '\u0000'
boolean                         false
引用類型                         null

    

                                    數據使用完畢後,在垃圾回收器空閒的時候回收。
(6)數組內存圖
A:一個數組
B:二個數組
C:三個數組(兩個棧變量指向同一個堆內存)
(7)數組的常見操作
A:遍歷
方式1:
public static void printArray(int[] arr) {
for(int x=0; x<arr.length; x++) {
System.out.println(arr[x]);
}
}

方式2:
public static void printArray(int[] arr) {
System.out.print("[");
for(int x=0; x<arr.length; x++) {
if(x == arr.length-1) {
System.out.println(arr[x]+"]");
}else {
System.out.println(arr[x]+", ");
}
}
}
B:最值
最大值:
public static int getMax(int[] arr) {
int max = arr[0];

for(int x=1; x<arr.length; x++) {
if(arr[x] > max) {
max = arr[x];
}
}

return max;
}

最小值:
public static int getMin(int[] arr) {
int min = arr[0];

for(int x=1; x<arr.length; x++) {
if(arr[x] < min) {
min = arr[x];
}
}

return min;
}
C:逆序
方式1:
public static void reverse(int[] arr) {
for(int x=0; x<arr.length/2; x++) {
int temp = arr[x];
arr[x] = arr[arr.length-1-x];
arr[arr.length-1-x] = temp;
}
}

方式2:
public static void reverse(int[] arr) {
for(int start=0,end=arr.length-1; start<=end; start++,end--) {
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
}
}
D:查表
public static String getString(String[] strArray,int index) {
return strArray[index];
}
E:基本查找
方式1:
public static int getIndex(int[] arr,int value) {
for(int x=0; x<arr.length; x++) {
if(arr[x] == value) {
return x;
}
}

return -1;
}

方式2:
public static int getIndex(int[] arr,int value) {
int index = -1;

for(int x=0; x<arr.length; x++) {
if(arr[x] == value) {
index = x;
break;
}
}

return index;
}

============================================================================

1:二維數組(理解)

(1)元素是一維數組的數組。
(2)格式:
A:數據類型[][] 數組名 = new 數據類型[m][n];
B:數據類型[][] 數組名 = new 數據類型[m][];
C:數據類型[][] 數組名 = new 數據類型[][]{{...},{...},{...}};
D:數據類型[][] 數組名 = {{...},{...},{...}};
(3)案例(掌握):
A:二維數組的遍歷
B:二維數組的求和
C:楊輝三角形
 

2:兩個思考題(理解)

(1)Java中的參數傳遞問題
Java中只有值傳遞

基本類型:形式參數的改變不影響實際參數
引用類型:形式參數的改變直接影響實際參數
(2)數據加密問題
綜合的小案例。

3:面向對象(掌握)

(1)面向對象
面向對象是基於面向過程的編程思想
(2)面向對象的思想特點
A:是一種更符合我們思考習慣的思想
B:把複雜的事情簡單化
C:讓我們從執行者變成了指揮者

舉例:
買電腦
洗衣服
做飯
...
萬事萬物皆對象
(3)把大象裝進冰箱(理解)
A:面向過程實現
B:面向對象實現

注意:如何讓我們的操作更符合面向對象思想呢?
A:有哪些類
B:每個類有哪些成員
C:類與類的關係
(4)類與對象
A:現實世界的事物
屬性 事物的基本描述
行爲 事物的功能
B:Java語言中最基本的單位是類。所以,我們要用類來體現事物
C:類
成員變量 事物屬性
成員方法 事物行爲

D:    類:是一組相關的屬性和行爲的集合。是一個抽象的概念。
       對象:是該類事物的具體存在,是一個具體的實例。(對象)

  
  舉例:
學生:類
班長:對象
(5)類的定義及使用
A:類的定義
成員變量 定義格式和以前一樣,就是位置不同,在類中,方法外。
成員方法 定義格式和以前一樣,就是去掉了static。
B:使用類的內容
a:創建對象? 格式
類名 對象名 =  new 類名();
b:如何使用成員變量和成員方法呢
對象名.成員變量
對象名.成員方法()
(6)案例:
A:學生類的定義和使用
B:手機類的定義和使用
(7)內存圖
A:一個對象的內存圖
B:二個對象的內存圖
C:三個對象的內存圖
(8)Java程序的開發,設計和特徵
A:開發:就是不斷的創建對象,通過對象調用功能
B:設計:就是管理和維護對象間的關係
C:特徵
a:封裝
b:繼承
c:多態

============================================================================

1:成員變量和局部變量的區別(理解)

(1)在類中的位置不同
成員變量:類中方法外
局部變量:方法定義中或者方法聲明上
(2)在內存中的位置不同
成員變量:在堆中
局部變量:在棧中
(3)生命週期不同
成員變量:隨着對象的創建而存在,隨着對象的消失而消失
局部變量:隨着方法的調用而存在,隨着方法的調用完畢而消失
(4)初始化值不同
成員變量:有默認值
局部變量:沒有默認值,必須定義,賦值,然後才能使用

2:類作爲形式參數的問題?(理解)

(1)如果你看到一個方法需要的參數是一個類名,就應該知道這裏實際需要的是一個具體的對象
 

3:匿名對象(理解)

(1)沒有名字的對象
(2)應用場景
A:調用方法,僅僅只調用一次的時候
b:可以作爲實際參數傳遞

4:封裝(理解)

(1)隱藏實現細節,提供公共的訪問方式
(2)好處:
A:隱藏實現細節,提供公共的訪問方式
B:提高代碼的複用性
C:提高代碼的安全性
(3)設計原則
把不想讓外界知道的實現細節給隱藏起來,提供公共的訪問方式
(4)private是封裝的一種體現。
封裝:類,方法,private修飾成員變量
 

5:private關鍵字(掌握)

(1)私有的意義,可以修飾成員變量和成員方法
(2)特點:
被private修飾的後的成員只能在本類中被訪問
(3)private的應用:
以後再寫一個類的時候:
把所有的成員變量給private了
提供對應的getXxx()/setXxx()方法
 

6:this關鍵字(掌握)

(1)代表當前類的引用對象
記住:哪個對象調用方法,該方法內部的this就代表那個對象
(2)this的應用場景:
A:解決了局部變量隱藏成員變量的問題
B:其實this還有其他的應用,明天講解。
 

7:構造方法(掌握)

(1)作用:用於對對象的數據進行初始化
(2)格式:
A:方法名和類名相同
B:沒有返回值類型,連void都不能有
C:沒有返回值


思考題:構造方法中可不可以有return語句呢?
可以。而是我們寫成這個樣子就OK了:return;
其實,在任何的void類型的方法的最後你都可以寫上:return;
(3)構造方法的注意事項
A:如果我們沒寫構造方法系統將提供一個默認的無參構造方法
B:如果我們給出了構造方法,系統將不再提供默認構造方法
如果這個時候,我們要使用無參構造方法,就必須自己給出。
推薦:永遠手動自己給出無參構造方法。
(4)給成員變量賦值的方式
A:setXxx()
B:帶參構造方法
(5)標準案例
class Student {
private String name;
private int age;

public Student(){}

public Student(String name,int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}

測試:
class StudentDemo {
public static void main(String[] args) {
//方式1
Student s1 = new Student();
s1.setName("林青霞");
s1.setAge(27);
System.out.println(s1.getName()+"---"+s1.getAge());

//方式2
Student s2 = new Student("劉意",30);
System.out.println(s2.getName()+"---"+s2.getAge());
}
}

 

8:代碼:Student s = new Student();做了哪些事情?(理解)

(1)把Student.class文件加載到內存
(2)在棧內存爲s開闢空間
(3)在堆內存爲學生對象申請空間
(4)給學生的成員變量進行默認初始化。null,0
(5)給學生的成員變量進行顯示初始化。林青霞,27
(6)通過構造方法給成員變量進行初始化。劉意,30
(7)對象構造完畢,把地址賦值給s變量

9:面向對象的練習題(掌握)

(1)標準的手機類的定義和測試
(2)Demo類有求和方法,Test類進行測試。
什麼時候定義成員變量?
當該變量是用來描述一個類的時候。
(3)長方形案例
(4)員工案例
(5)MyMath案例(自己提供加減乘除並測試)

10:static關鍵字(理解)

(1)靜態的意思。可以修飾成員變量和成員方法。
(2)靜態的特點:
A:隨着類的加載而加載
B:優先於對象存在
C:被類的所有對象共享
這其實也是我們判斷該不該使用靜態的依據。
舉例:飲水機和水杯的問題思考

D:可以通過類名調用
既可以通過對象名調用,也可以通過類名調用,建議通過類名調用。
(3)靜態的內存圖
靜態的內容在方法區的靜態區
(4)靜態的注意事項;
A:在靜態方法中沒有this對象
B:靜態只能訪問靜態(代碼測試過)
(5)靜態變量和成員變量的區別
A:所屬不同
靜態變量:屬於類,類變量
成員變量:屬於對象,對象變量,實例變量
B:內存位置不同
靜態變量:方法區的靜態區
成員變量:堆內存
C:生命週期不同
靜態變量:靜態變量是隨着類的加載而加載,隨着類的消失而消失
成員變量:成員變量是隨着對象的創建而存在,隨着對象的消失而消失
D:調用不同
靜態變量:可以通過對象名調用,也可以通過類名調用
成員變量:只能通過對象名調用

(6)main方法是靜態的
public:權限最大
static:不用創建對象調用
void:返回值給jvm沒有意義
main:就是一個常見的名稱。
String[] args:可以接收數據,提供程序的靈活性
格式:java MainDemo hello world java
  java MainDemo 10 20 30

============================================================================

1:如何製作幫助文檔(瞭解)

(1)寫一個類
(2)加入文檔註釋
(3)通過javadoc工具生成即可
javadoc -d 目錄 -author -version ArrayTool.java
 

2:通過JDK提供的API學習了Math類(掌握)

(1)API(Application Programming Interface)
應用程序編程接口(幫助文檔)
(2)如何使用呢?
請參照
day08\code\02_如何使用JDK提供的幫助文檔\如何使用幫助文檔.txt
(3)Math類
A:是針對數學進行操作的類
B:沒有構造方法,因爲它的成員都是靜態的
C:產生隨機數
public static double random(): [0.0,1.0)
D:如何產生一個1-100之間的隨機數
int number = (int)(Math.random()*100)+1;
E:猜數字小遊戲
 

3:代碼塊(理解)

(1)用{}括起來的代碼。
(2)分類:
A:局部代碼塊
用於限定變量的生命週期,及早釋放,提高內存利用率。
B:構造代碼塊
把多個構造方法中相同的代碼可以放到這裏,每個構造方法執行前,首先執行構造代碼塊。
C:靜態代碼塊
對類的數據進行初始化,僅僅只執行一次。
(3)靜態代碼塊,構造代碼塊,構造方法的順序問題?
靜態代碼塊 > 構造代碼塊 > 構造方法

4:繼承(掌握)

(1)把多個類中相同的成員給提取出來定義到一個獨立的類中。然後讓這多個類和該獨立的類產生一個關係,
   這多個類就具備了這些內容。這個關係叫繼承。
(2)Java中如何表示繼承呢?格式是什麼呢?
A:用關鍵字extends表示
B:格式:
class 子類名 extends 父類名 {}
(3)繼承的好處:
A:提高了代碼的複用性
B:提高了代碼的維護性
C:讓類與類產生了一個關係,是多態的前提
(4)繼承的弊端
A:讓類的耦合性增強。這樣某個類的改變,就會影響其他和該類相關的類。
原則:低耦合,高內聚。
耦合:類與類的關係
內聚:自己完成某件事情的能力
B:打破了封裝性
(5)Java中繼承的特點
A:Java中類只支持單繼承
B:Java中可以多層(重)繼承(繼承體系)
(6)繼承的注意事項:
A:子類不能繼承父類的私有成員
B:子類不能繼承父類的構造方法,但是可以通過super去訪問
C:不要爲了部分功能而去繼承

(7)什麼時候使用繼承呢?
A:繼承體現的是:is a的關係。
B:採用假設法
(8)Java繼承中的成員關係
A成員變量
a:子類的成員變量名稱和父類中的成員變量名稱不一樣,這個太簡單
b:子類的成員變量名稱和父類中的成員變量名稱一樣,這個怎麼訪問呢?
子類的方法訪問變量的查找順序:
在子類方法的局部範圍找,有就使用。
在子類的成員範圍找,有就使用。
在父類的成員範圍找,有就使用。
找不到,就報錯。

B:構造方法
a:子類的構造方法默認會去訪問父類的無參構造方法
是爲了子類訪問父類數據的初始化
b:父類中如果沒有無參構造方法,怎麼辦?
子類通過super去明確調用帶參構造
子類通過this調用本身的其他構造,但是一定會有一個去訪問了父類的構造
讓父類提供無參構造

C:成員方法
a:子類的成員方法和父類中的成員方法名稱不一樣,這個太簡單
b:子類的成員方法和父類中的成員方法名稱一樣,這個怎麼訪問呢?
通過子類對象訪問一個方法的查找順序:
在子類中找,有就使用
在父類中找,有就使用
找不到,就報錯

(9)兩個面試題:
A:Override和Overload的區別?Overload是否可以改變返回值類型?
B:this和super的區別和各自的作用?
:
(10)數據初始化的面試題
A:一個類的初始化過程
B:子父類的構造執行過程
C:分層初始化
(11)案例:
A:學生和老師案例
繼承前
繼承後
B:貓狗案例的分析和實現

============================================================================

1:final關鍵字(掌握)

(1)是最終的意思,可以修飾類,方法,變量
(2)特點:
A:它修飾的類,不能被繼承
B:它修飾的方法,不能被重寫
C:它修飾的變量,是一個常量
(3)面試相關:
A:局部變量
a:基本類型 不能發生改變
b:引用類型 地址值不能發生改變,但是對象的內容是可以改變
B:初始化時機
a:只能初始化一次。
b:常見的給值
定義的時候。(推薦)
構造方法中。

2:多態(掌握)

(1)同一個對象在不同時刻體現出來的不同狀態
(2)多態的前提:
A:有繼承或者實現關係。
B:有方法重寫
C:有父類或者父接口引用指向子類對象。

多態的分類:
a:具體類多態
class Fu {}
class Zi extends Fu {}

Fu f = new Zi();
b:抽象類多態
abstract class Fu {}
class Zi extends Fu {}

Fu f = new Zi();
c:接口多態
interface Fu {}
class Zi implements Fu {}

Fu f = new Zi();
(3)多態中的成員訪問特點
A:成員變量
編譯看左邊,運行看左邊
B:構造方法
子類的構造都會默認訪問父類構造
C:成員方法
編譯看左邊,運行看右邊
D:靜態方法
編譯看左邊,運行看左邊


爲什麼?
因爲成員方法有重寫。
(4)多態的好處:
A:提高代碼的維護性(繼承體現)
B:提高代碼的擴展性(多態體現)
(5)多態的弊端:
父不能使用子的特有功能。


現象:
子可以當作父使用,父不能當作子使用。
(6)多態中的轉型
A:向上轉型
從子到父
B:向下轉型
從父到子

(7)孔子裝爹的案例幫助大家理解多態
(8)多態的練習
A:貓狗案例
B:老師和學生案例
 

3:抽象類(掌握)

(1)把多個共性的東西提取到一個類中,這是繼承的做法。
   但是呢,這多個共性的東西,在有些時候,方法聲明一樣,但是方法體。
   也就是說,方法聲明一樣,但是每個具體的對象在具體實現的時候內容不一樣。
   所以,我們在定義這些共性的方法的時候,就不能給出具體的方法體。
   而一個沒有具體的方法體的方法是抽象的方法
   在一個類中如果有抽象方法,該類必須定義爲抽象類
(2)抽象類的特點
A:抽象類和抽象方法必須用關鍵字abstract修飾
B:抽象類中不一定有抽象方法,但是有抽象方法的類一定是抽象類
C:抽象類不能實例化
D:抽象類的子類
a:是一個抽象類
b:是一個具體類。這個類必須重寫抽象類中的所有抽象方法
(3)抽象類的成員特點:
A:成員變量
有變量,有常量
B:構造方法
有構造方法
C:成員方法
有抽象,有非抽象
(4)抽象類的練習
A:貓狗案例練習
B:老師案例練習
C:學生案例練習
D:員工案例練習
(5)抽象類的幾個小問題
A:抽象類有構造方法,不能實例化,那麼構造方法有什麼用?
用於子類訪問父類數據的初始化

B:一個類如果沒有抽象方法,卻定義爲了抽象類,有什麼用?
爲了不讓創建對象

C:abstract不能和哪些關鍵字共存
a:final        衝突
b:private   衝突
c:static      無意義

 

4:接口(掌握)

(1)回顧貓狗案例,它們僅僅提供一些基本功能。
   比如:貓鑽火圈,狗跳高等功能,不是動物本身就具備的,
   是在後面的培養中訓練出來的,這種額外的功能,java提供了接口表示。
(2)接口的特點:
A:接口用關鍵字interface修飾
interface 接口名 {}
B:類實現接口用implements修飾
class 類名 implements 接口名 {}
C:接口不能實例化
D:接口的實現類
a:是一個抽象類。
b:是一個具體類,這個類必須重寫接口中的所有抽象方法。

(3)接口的成員特點:
A:成員變量
只能是常量
默認修飾符:public static final

B:構造方法
沒有構造方法
C:成員方法
只能是抽象的
默認修飾符:public abstract
(4)類與類,類與接口,接口與接口
A:類與類
繼承關係,只能單繼承,可以多層繼承
B:類與接口
實現關係,可以單實現,也可以多實現。
類還可以在繼承一個類的同時,實現多個接口
C:接口與接口
繼承關係,可以單繼承,也可以多繼承

(5)抽象類和接口的區別

                A:成員區別
                抽象類:
            成員變量:可以變量,也可以常量
            構造方法:有
            成員方法:可以抽象,也可以非抽象
                接口:
            成員變量:只可以常量
            成員方法:只可以抽象

                B:關係區別
                 類與類
               繼承,單繼承
                類與接口
                實現,單實現,多實現
                接口與接口
                繼承,單繼承,多繼承

                C:設計理念區別
                抽象類     被繼承體現的是:”is a”的關係。抽象類中定義的是該繼承體系的共性功能。
                接口         被實現體現的是:”like a”的關係。接口中定義的是該繼承體系的擴展功能。

        (6)練習:
A:貓狗案例,加入跳高功能
B:老師和學生案例,加入抽菸功能0

 

============================================================================

1:形式參數和返回值的問題(理解)

(1)形式參數:
類名:需要該類的對象
抽象類名:需要該類的子類對象
接口名:需要該接口的實現類對象
(2)返回值類型:
類名:返回的是該類的對象
抽象類名:返回的是該類的子類對象
接口名:返回的是該接口的實現類的對象
(3)鏈式編程
對象.方法1().方法2().......方法n();

這種用法:其實在方法1()調用完畢後,應該一個對象;
      方法2()調用完畢後,應該返回一個對象。
  方法n()調用完畢後,可能是對象,也可以不是對象。
 

2:包(理解)

(1)其實就是文件夾
(2)作用:
A:區分同名的類
B:對類進行分類管理
a:按照功能
b:按照模塊
(3)包的定義(掌握)
package 包名;

多級包用.分開。
(4)注意事項:(掌握)
A:package語句必須在文件中的第一條有效語句
B:在一個java文件中,只能有一個package
C:如果沒有package,默認就是無包名
(5)帶包的編譯和運行
A:手動式
B:自動式(掌握)
javac -d . HelloWorld.java

3:導包(掌握)

(1)我們多次使用一個帶包的類,非常的麻煩,這個時候,Java就提供了一個關鍵字import。
(2)格式:
import 包名...類名;
另一種:
import 包名...*;(不建議)
(3)package,import,class的順序
package > import > class

4:權限修飾符(掌握)

(1)權限修飾符
本類 同一個包下 不同包下的子類 不同包下的無關類
private Y
默認         Y Y
protected Y Y Y
public Y Y Y Y

(2)這四種權限修飾符在任意時刻只能出現一種
public class Demo {}
 

5:常見的修飾符(理解)

(1)分類:
權限修飾符:private,默認,protected,public
狀態修飾符:static,final
抽象修飾符:abstract
(2)常見的類及其組成的修飾

默認,public,final,abstract

常用的:public

成員變量
private,默認,protected,public,static,final

常用的:private

構造方法
private,默認,protected,public

常用的:public

成員方法
private,默認,protected,public,static,final,abstract

常用的:public
(3)另外比較常見的:
public static final int X = 10;
public static void show() {}
public final void show() {}
public abstract void show();
 

6:內部類(理解)

(1)把類定義在另一個類的內部,該類就被稱爲內部類。
舉例:把類B定義在類A中,類B就被稱爲內部類。
(2)內部類的訪問規則
A:可以直接訪問外部類的成員,包括私有
B:外部類要想訪問內部類成員,必須創建對象
(3)內部類的分類
A:成員內部類
B:局部內部類
(4)成員內部類
A:private 爲了數據的安全性
B:static 爲了訪問的方便性

成員內部類不是靜態的:
外部類名.內部類名 對象名 = new 外部類名.new 內部類名();
成員內部類是靜態的:
外部類名.內部類名 對象名 = new 外部類名.內部類名();
(5)成員內部類的面試題(填空)
30,20,10

class Outer {
public int num = 10;

class Inner {
public int num = 20;

public viod show() {
int num  = 30;

System.out.println(num);
System.out.println(this.num);
System.out.println(Outer.this.num);
}
}
}
(6)局部內部類
A:局部內部類訪問局部變量必須加final修飾
B:爲什麼呢?
因爲局部變量使用完畢就消失,而堆內存的數據並不會立即消失。
所以,堆內存還是用該變量,而改變量已經沒有了。
爲了讓該值還存在,就加final修飾。
通過反編譯工具我們看到了,加入final後,堆內存直接存儲的是值,而不是變量名。
(7)匿名內部類(掌握)
A:是局部內部類的簡化形式
B:前提
存在一個類或者接口
C:格式:
new 類名或者接口名() {
重寫方法;
}

D:本質:
其實是繼承該類或者實現接口的子類匿名對象
(8)匿名內部類在開發中的使用
我們在開發的時候,會看到抽象類,或者接口作爲參數。
而這個時候,我們知道實際需要的是一個子類對象。
如果該方法僅僅調用一次,我們就可以使用匿名內部類的格式簡化

interface Person {
public abstract void study();
}

class PersonDemo {
public void method(Person p) {
p.study();
}
}

class PersonTest {
public static void main(String[] args) {
PersonDemo pd = new PersonDemo();
pd.method(new Person() {
public void study() {
System.out.println("好好學習,天天向上");
}
});
}
}

(9)匿名內部類的面試題(補齊代碼)
interface Inter {
void show();
}

class Outer {
//補齊代碼
public static Inter method() {
return new Inter() {
public void show() {
System.out.println("HelloWorld");
}
};
}
}

class OuterDemo {
public static void main(String[] args) {
Outer.method().show(); //"HelloWorld"
}
}

============================================================================

1:Eclipse的概述使用(掌握)

請參照ppt和課堂練習.txt

2:API的概述(瞭解)

(1)應用程序編程接口。
(2)就是JDK提供給我們的一些提高編程效率的java類。
 

3:Object類(掌握)

(1)Object是類層次結構的根類所有的類都直接或者間接的繼承自Object類
(2)Object類的構造方法有一個,並且是無參構造
這其實就是理解當時我們說過,子類構造方法默認訪問父類的構造是無參構造
(3)要掌握的方法:
A:toString()
返回對象的字符串表示,默認是由類的全路徑+'@'+哈希值的十六進制表示。
這個表示其實是沒有意義的,一般子類都會重寫該方法。
如何重寫呢?過程我也講解過了,基本上就是要求信息簡單明瞭。
但是最終還是自動生成。
B:equals()
比較兩個對象是否相同。默認情況下,比較的是地址值是否相同。
比較地址值是沒有意義的,所以,一般子類也會重寫該方法。
重寫過程,我也詳細的講解和分析了。
但是最終還是自動生成。
(4)要了解的方法:
A:hashCode()      返回對象的哈希值。不是實際地址值,可以理解爲地址值。
B:getClass()         返回對象的字節碼文件對象,反射中我們會詳細講解
C:finalize()           用於垃圾回收,在不確定的時間
D:clone()             可以實現對象的克隆,包括成員變量的數據複製,但是它和兩個引用指向同一個對象是有區別的
(5)兩個注意問題;
A:直接輸出一個對象名稱,其實默認調用了該對象的toString()方法。System.out.println()
B:面試題 
==和equals()的區別?
A:==
基本類型:比較的是值是否相同
引用類型:比較的是地址值是否相同
B:equals()
只能比較引用類型。默認情況下,比較的是地址值是否相同。
但是,我們可以根據自己的需要重寫該方法。

============================================================================

1:Scanner的使用(瞭解)

(1)在JDK5以後出現的用於鍵盤錄入數據的類。
(2)構造方法:
A:講解了System.in這個東西。
它其實是標準的輸入流,對應於鍵盤錄入
B:構造方法
InputStream is = System.in;

Scanner(InputStream is)
C:常用的格式
Scanner sc = new Scanner(System.in);
(3)基本方法格式:
A:hasNextXxx() 判斷是否是某種類型的
B:nextXxx() 返回某種類型的元素
(4)要掌握的兩個方法
A:public int nextInt()
B:public String nextLine()
(5)需要注意的小問題
A:同一個Scanner對象,先獲取數值,再獲取字符串會出現一個小問題。
B:解決方案:
a:重新定義一個Scanner對象
b:把所有的數據都用字符串獲取,然後再進行相應的轉換

2:String類的概述和使用(掌握)

(1)多個字符組成的一串數據。
其實它可以和字符數組進行相互轉換。

                字符串字面值"abc"也可以看成是一個字符串對象。

(2)構造方法:

                public String()                                                                空構造
  public String(byte[] bytes)                                             把字節數組轉成字符串
  public String(byte[] bytes,int index,int length)              把字節數組的一部分轉成字符串,第二個參數index表示從

                                                                                                       當前索引開始


  public String(char[] value)                                              把字符數組轉成字符串
  public String(char[] value,int index,int count)                把字符數組的一部分轉成字符串
  public String(String original)                                          把字符串常量值轉成字符串

                

                下面的這一個雖然不是構造方法,但是結果也是一個字符串對象
        String s = "hello";

 

public static void main(String[] args) {
    /**
     * public String():空構造
     */
    String s1 = new String();
    System.out.println("s1:" + s1);//s1:
    System.out.println("s1.length():" + s1.length());//s1.length():0
    System.out.println("--------------------------");

    /**
     * public String(byte[] bytes):把字節數組轉成字符串
     */
    byte[] bys = { 97, 98, 99, 100, 101 };
    String s2 = new String(bys);
    System.out.println("s2:" + s2);//abcde
    System.out.println("s2.length():" + s2.length());//5
    System.out.println("--------------------------");


    /**
     * public String(byte[] bytes,int index,int length):把字節數組的一部分轉成字符串
     * 第二個參數index表示從當前索引開始
     */
    // 我想得到字符串"bcd"
    String s3 = new String(bys, 1, 3);
    System.out.println("s3:" + s3);//bcd
    System.out.println("s3.length():" + s3.length());//3
    System.out.println("--------------------------");

    /**
     * public String(char[] value):把字符數組轉成字符串
     */
    char[] chs = { 'a', 'b', 'c', 'd', 'e', '愛', '林', '親' };
    String s4 = new String(chs);
    System.out.println("s4:" + s4);//abcde愛林親
    System.out.println("s4.length():" + s4.length());//8
    System.out.println("--------------------------");

    /**
     * public String(char[] value,int index,int count):把字符數組的一部分轉成字符串
     * 第二個參數index表示從當前索引開始
     */
    String s5 = new String(chs, 2, 4);
    System.out.println("s5:" + s5);//cde愛
    System.out.println("s5.length():" + s5.length());//4
    System.out.println("--------------------------");

    /**
     * public String(String original):把字符串常量值轉成字符串
     */
    String s6 = new String("abcde");
    System.out.println("s6:" + s6);//adcde
    System.out.println("s6.length():" + s6.length());//5
    System.out.println("--------------------------");

    /**
     * 字符串字面值"abc"也可以看成是一個字符串對象。
     */
    String s7 = "abcde";
    System.out.println("s7:"+s7);//abcde
    System.out.println("s7.length():"+s7.length());//5
}


(3)字符串的特點
A:字符串一旦被賦值,就不能改變
注意:這裏指的是字符串的內容不能改變,而不是引用不能改變。     

     

    String s = "hello";
    s += "world";
    s += "haha";
    System.out.println("s:" + s); // helloworldhaha

B:字面值作爲字符串對象和通過構造方法創建對象的不同
String s = new String("hello");  和String s = "hello" 的區別?

                  答:有。前者會創建2個對象,後者創建1個對象。

                         ==:比較引用類型比較的是地址值是否相同
                         equals:比較引用類型默認也是比較地址值是否相同,而String類重寫了equals()方法,比較的是內容是否相同。

 

 

    String s1 = new String("hello");
    String s2 = "hello";

    System.out.println(s1 == s2);// false
    System.out.println(s1.equals(s2));// true

(4)字符串的面試題(看程序寫結果)
A:==和equals()

String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2);// false
System.out.println(s1.equals(s2));// true

String s3 = new String("hello"); 
String s4 = "hello";
// 前者會創建2個對象,後者創建1個對象
System.out.println(s3 == s4);// false
System.out.println(s3.equals(s4));// true

String s5 = "hello";
String s6 = "hello";
System.out.println(s5 == s6);// true 引用的同一個方法區裏的常量池對象
System.out.println(s5.equals(s6));// true

B:字符串的拼接

                     字符串如果是 變量 相加,先開空間,再拼接。
                     字符串如果是 常量 相加,是先加,然後在常量池找,如果有就直接返回,否則,就創建。

String s1 = "hello";
String s2 = "world";
String s3 = "helloworld";

System.out.println(s3 == s1 + s2);// false
System.out.println(s3.equals((s1 + s2)));// true

System.out.println(s3 == "hello" + "world");// false 這個我們錯了,應該是true
System.out.println(s3.equals("hello" + "world"));// true

// 通過反編譯看源碼,我們知道這裏已經做好了處理。
// System.out.println(s3 == "helloworld");
// System.out.println(s3.equals("helloworld"));


(5)字符串的功能(自己補齊方法中文意思)
A:判斷功能
 * boolean equals(Object obj):                 比較字符串的內容是否相同,區分大小寫
 * boolean equalsIgnoreCase(String str): 比較字符串的內容是否相同,忽略大小寫
 * boolean contains(String str):                判斷大字符串中是否包含小字符串
 * boolean startsWith(String str):             判斷字符串是否以某個指定的字符串開頭
 * boolean endsWith(String str):              判斷字符串是否以某個指定的字符串結尾
 * boolean isEmpty():                                判斷字符串是否爲空。

字符串內容爲空和字符串對象爲空。
String s = "";
String s = null;

對象都不存在,所以不能調用方法,空指針異常

B:獲取功能
int length()                                             返回此字符串的長度
char charAt(int index)                            獲取指定索引位置的字符
int indexOf(int ch)                                  返回指定字符在此字符串中第一次出現處的索引。

                                                                                            爲什麼這裏是int類型,而不是char類型?
                                                                                            原因是:'a'和97其實都可以代表'a'


int indexOf(String str)                             返回指定字符串在此字符串中第一次出現處的索引
int indexOf(int ch,int fromIndex)            返回指定 字符 在此字符串中從指定位置後第一次出現處的索引。
int indexOf(String str,int fromIndex)      返回指定 字符串 在此字符串中從指定位置後第一次出現處的索引。
String substring(int start)                        從指定位置開始截取字符串,默認到末尾。
String substring(int start,int end)            從指定位置開始到指定位置結束截取字符串。

 

                 
C:轉換功能
byte[] getBytes()                             把字符串轉換爲字節數組。
char[] toCharArray()                        把字符串轉換爲字符數組。
static String valueOf(char[] chs)     把字符數組轉成字符串。
static String valueOf(int i)               把int類型的數據轉成字符串。

                                                      注意:String類的valueOf方法可以把任意類型的數據轉成字符串。


String toLowerCase()                      把字符串轉成小寫。
String toUpperCase()                      把字符串轉成大寫。
String concat(String str)                 把字符串拼接。

 

D:其他功能
a:替換功能 
String replace(char old,char new)
String replace(String old,String new)
b:去空格功能 去掉兩端空格,中間的空格不能取
String trim()
c:按字典比較功能
int compareTo(String str)
int compareToIgnoreCase(String str) 
(6)字符串的案例
A:模擬用戶登錄

// 定義用戶名和密碼。已存在的。
String username = "admin";
String password = "admin";

// 給三次機會,用循環改進,最好用for循環。
for (int x = 0; x < 3; x++) {
    // x=0,1,2
    // 鍵盤錄入用戶名和密碼。
    Scanner sc = new Scanner(System.in);
    System.out.println("請輸入用戶名:");
    String name = sc.nextLine();
    System.out.println("請輸入密碼:");
    String pwd = sc.nextLine();

    // 比較用戶名和密碼。
    if (name.equals(username) && pwd.equals(password)) {
        // 如果都相同,則登錄成功
        System.out.println("登錄成功,開始玩遊戲");
        //猜數字遊戲
        GuessNumberGame.start();
        break;
    } else {
        // 如果有一個不同,則登錄失敗
        // 2,1,0
        // 如果是第0次,應該換一種提示
        if ((2 - x) == 0) {
            System.out.println("帳號被鎖定,請與班長聯繫");
        } else {
            System.out.println("登錄失敗,你還有" + (2 - x) + "次機會");
        }
    }
}

B:字符串遍歷

// 定義字符串
String s = "helloworld";

// 如果長度特別長,我不可能去數,所以我們要用長度功能
for (int x = 0; x < s.length(); x++) {
    // char ch = s.charAt(x);
    // System.out.println(ch);
    // 僅僅是輸出,我就直接輸出了
    System.out.println(s.charAt(x));
}

C:統計字符串中大寫,小寫及數字字符的個數

//定義一個字符串
String s = "Hello123World";

//定義三個統計變量
int bigCount = 0;
int smallCount = 0;
int numberCount = 0;

//遍歷字符串,得到每一個字符。
for (int x=0; x < s.length(); x++) {
    char ch = s.charAt(x);

    // TODO 判斷該字符到底是屬於那種類型的***********
    if (ch>='a' && ch<='z') {
        smallCount ++;
    } else if (ch >= 'A' && ch <= 'Z'){
        bigCount ++;
    } else if (ch >= '0' && ch <= '9'){
        numberCount ++;
    }
}

//輸出結果。
System.out.println("大寫字母"+bigCount+"個");
System.out.println("小寫字母"+smallCount+"個");
System.out.println("數字"+numberCount+"個");

D:把字符串的首字母轉成大寫,其他小寫

// 定義一個字符串
String s = "helloWORLD";

// 鏈式編程
String result = s.substring(0, 1).toUpperCase()
        .concat(s.substring(1).toLowerCase());

System.out.println(result);

E:把int數組拼接成一個指定格式的字符串

public static void main(String[] args) {
       // 前提是數組已經存在
       int[] arr = {1, 2, 3};

       // 寫一個功能,實現結果
       String result = arrayToString(arr);
       System.out.println("最終結果是:" + result);
   }

/*
 * 兩個明確: 返回值類型:String 參數列表:int[] arr
 */
   public static String arrayToString(int[] arr) {
       // 定義一個字符串
       String s = "";

       // 先把字符串拼接一個"["
       s += "[";

       // 遍歷int數組,得到每一個元素
       for (int x = 0; x < arr.length; x++) {
           // 先判斷該元素是否爲最後一個
           if (x == arr.length - 1) {
               // 就直接拼接元素和"]"
               s += arr[x];
               s += "]";
           } else {
               // 就拼接元素和逗號以及空格
               s += arr[x];
               s += ", ";
           }
       }

       return s;
   }

F:字符串反轉

// 定義一個新字符串
String result = "";

// 把字符串轉成字符數組
char[] chs = s.toCharArray();

// 倒着遍歷字符串,得到每一個字符
for (int x = chs.length - 1; x >= 0; x--) {
    // 用新字符串把每一個字符拼接起來
    result += chs[x];
}

return result;

G:統計大串中小串出現的次數

public static void main(String[] args) {
      // 定義大串
      String maxString = "woaijavawozhenaijavawozhendeaijavawozhendehenaijavaxinbuxinwoaijavagun";
      // 定義小串
      String minString = "java";

      // 寫功能實現
      int count = getCount(maxString, minString);
      System.out.println("Java在大串中出現了:" + count + "次");
  }

  /*
   * 兩個明確: 返回值類型:int 參數列表:兩個字符串
   */
  public static int getCount(String maxString, String minString) {
      // 定義一個統計變量,初始化值是0
      int count = 0;
      int index;
      //先查,賦值,判斷
      while((index = maxString.indexOf(minString)) != -1){
          count++;
          maxString = maxString.substring(index + minString.length());
      }

      return count;
  }

圖解:

============================================================================

1:StringBuffer(掌握)

(1)用字符串做拼接,比較耗時並且也耗內存,而這種拼接操作又是比較常見的,爲了解決這個問題,Java就提供了
   一個字符串緩衝區類。StringBuffer供我們使用。

 

線程安全(多線程講解)
 * 安全 -- 同步 -- 數據是安全的
 * 不安全 -- 不同步 -- 效率高一些

 * 安全和效率問題是永遠困擾我們的問題。
 * 安全:醫院的網站,銀行網站
 * 效率:新聞網站,論壇之類的
 *
 * StringBuffer:
 * 線程安全的可變字符串。
 *
 * StringBuffer和String的區別?
 * 前者長度和內容可變,後者不可變。
 * 如果使用前者做字符串的拼接,不會浪費太多的資源。

 *
 * StringBuffer的構造方法:
 * public StringBuffer():無參構造方法
 * public StringBuffer(int capacity):指定容量的字符串緩衝區對象  默認16
 * public StringBuffer(String str):指定字符串內容的字符串緩衝區對象
 *
 * StringBuffer的方法:
 * public int capacity():返回當前容量。默認值16+當前長度 理論值
 * public int length():返回長度(字符數)。 實際值

 

/**
 * public StringBuffer()
 * 無參構造方法
 */
StringBuffer sb = new StringBuffer();
System.out.println("sb:" + sb);
System.out.println("sb.capacity():" + sb.capacity()); // 16
System.out.println("sb.length():" + sb.length()); // 0
System.out.println("--------------------------");

/**
 * public StringBuffer(int capacity)
 * 指定容量的字符串緩衝區對象
 */
StringBuffer sb2 = new StringBuffer(50);
System.out.println("sb2:" + sb2);
System.out.println("sb2.capacity():" + sb2.capacity()); //50
System.out.println("sb2.length():" + sb2.length()); // 0
System.out.println("--------------------------");

/**
 * public StringBuffer(String str)
 * 指定字符串內容的字符串緩衝區對象
 */
StringBuffer sb3 = new StringBuffer("hello");
System.out.println("sb3:" + sb3);
System.out.println("sb3.capacity():" + sb3.capacity()); // 16+5 = 21
System.out.println("sb3.length():" + sb3.length()); //5

(3)StringBuffer的常見功能(自己補齊方法的聲明和方法的解釋)
A:添加功能

 * public StringBuffer append(String str):可以把任意類型數據添加到字符串緩衝區裏面,並返回字符串緩衝區本身
 * public StringBuffer insert(int offset,String str):在指定位置把任意類型的數據插入到字符串緩衝區裏面,並返回字符串緩衝區本身

 

// 創建字符串緩衝區對象
StringBuffer sb = new StringBuffer();

/**
 * public StringBuffer append(String str)
 * 可以把任意類型數據添加到字符串緩衝區裏面,並返回字符串緩衝區本身
 */
sb.append("hello").append(true).append(12).append(34.56);
System.out.println("sb:" + sb);

/**
 * public StringBuffer insert(int offset,String str)
 * 在指定位置把任意類型的數據插入到字符串緩衝區裏面,並返回字符串緩衝區本身
 */
sb.insert(5, "world");
System.out.println("sb:" + sb);

B:刪除功能

 * public StringBuffer deleteCharAt(int index):刪除指定位置的字符,並返回本身
 * public StringBuffer delete(int start,int end):刪除從指定位置開始指定位置結束的內容,並返回本身

 

// 創建對象
StringBuffer sb = new StringBuffer();

// 添加功能
sb.append("hello").append("world").append("java");
System.out.println("sb:" + sb);

/**
 * public StringBuffer deleteCharAt(int index)
 * 刪除指定位置的字符,並返回本身
 */
// 需求:我要刪除e這個字符,腫麼辦?
sb.deleteCharAt(1);
System.out.println("deleteCharAt:" + sb);
// 需求:我要刪除第一個l這個字符,腫麼辦?
// sb.deleteCharAt(1);

/**
 * public StringBuffer delete(int start,int end):刪除從指定位置開始指定位置結束的內容,並返回本身
 */
// 需求:我要刪除world這個字符串,腫麼辦?
sb.delete(4, 9);
System.out.println(sb);

// 需求:我要刪除所有的數據
sb.delete(0, sb.length());
System.out.println("sb:" + sb);

C:替換功能

 * public StringBuffer replace(int start,int end,String str):從start開始到end用str替換

// 創建字符串緩衝區對象
StringBuffer sb = new StringBuffer();

// 添加數據
sb.append("hello");
sb.append("world");
sb.append("java");
System.out.println("sb:" + sb);//helloworldjava

/**
 * public StringBuffer replace(int start,int end,String str)
 * 從start開始到end用str替換
 */
// 需求:我要把world這個數據替換爲"節日快樂"
sb.replace(5, 10, "節日快樂");
System.out.println("sb:" + sb); //hello節日快樂java

D:反轉功能

* public StringBuffer reverse()

// 創建字符串緩衝區對象
StringBuffer sb = new StringBuffer();

// 添加數據
sb.append("霞青林愛我");
System.out.println("sb:" + sb);

// public StringBuffer reverse()
sb.reverse();
System.out.println("sb:" + sb); // 我愛林青霞

E:截取功能(注意這個返回值)

 * StringBuffer的截取功能:注意返回值類型不再是StringBuffer本身了,而是string
 * public String substring(int start)
 * public String substring(int start,int end)

// 創建字符串緩衝區對象
StringBuffer sb = new StringBuffer();

// 添加元素
sb.append("hello").append("world").append("java");
System.out.println("sb:" + sb);

/**
 * public String substring(int start)
 */
String s = sb.substring(5);
System.out.println("s:" + s);
System.out.println("sb:" + sb);

/**
 * public String substring(int start,int end)
 */
String ss = sb.substring(5, 10);
System.out.println("ss:" + ss);
System.out.println("sb:" + sb);

(4)StringBuffer的練習
A:String和StringBuffer相互轉換
String -- StringBuffer
構造方法
StringBuffer -- String
toString()方法

// String -- StringBuffer
String s = "hello";
// StringBuffer sb = "hello"; 錯誤
// StringBuffer sb = s; 錯誤
/**
 * 給StringBuffer賦值,不能把字符串的值直接賦值給StringBuffer
 * // StringBuffer sb = "hello"; 錯誤
 * // StringBuffer sb = s; 錯誤
 * 正確做法:
 * 方式1:通過構造方法
 * 方式2:通過append()方法
 */
// 方式1:通過構造方法
StringBuffer sb = new StringBuffer(s);
// 方式2:通過append()方法
StringBuffer sb2 = new StringBuffer();
sb2.append(s);
System.out.println("sb:" + sb);
System.out.println("sb2:" + sb2);
System.out.println("---------------");

/**
 * StringBuffer轉化String
 * 方式1:通過構造方法String(StringBuffer buffer)
 * 方式2:通過toString()方法
 */
StringBuffer buffer = new StringBuffer("java");
// 方式1:通過構造方法
String str = new String(buffer);
// 方式2:通過toString()方法
String str2 = buffer.toString();
System.out.println("str:" + str);
System.out.println("str2:" + str2);

B:字符串的拼接

public static void main(String[] args) {
    // 定義一個數組
    int[] arr = { 44, 33, 55, 11, 22 };

    // 定義功能
    // 方式1:用String做拼接的方式
    String s1 = arrayToString(arr);
    System.out.println("s1:" + s1);

    // 方式2:用StringBuffer做拼接的方式
    String s2 = arrayToString2(arr);
    System.out.println("s2:" + s2);
}

// 用StringBuffer做拼接的方式
public static String arrayToString2(int[] arr) {
    StringBuffer sb = new StringBuffer();

    sb.append("[");
    for (int x = 0; x < arr.length; x++) {
        if (x == arr.length - 1) {
            sb.append(arr[x]);
        } else {
            sb.append(arr[x]).append(", ");
        }
    }
    sb.append("]");

    return sb.toString();
}

// 用String做拼接的方式
public static String arrayToString(int[] arr) {
    String s = "";

    s += "[";
    for (int x = 0; x < arr.length; x++) {
        if (x == arr.length - 1) {
            s += arr[x];
        } else {
            s += arr[x];
            s += ", ";
        }
    }
    s += "]";

    return s;
}

C:把字符串反轉

public static void main(String[] args) {
    // 鍵盤錄入數據
    Scanner sc = new Scanner(System.in);
    System.out.println("請輸入數據:");
    String s = sc.nextLine();

    // 方式1:用String做拼接
    String s1 = myReverse(s);
    System.out.println("s1:" + s1);
    // 方式2:用StringBuffer的reverse()功能
    String s2 = myReverse2(s);
    System.out.println("s2:" + s2);
}

/**
 * 最佳實踐
 */
// 用StringBuffer的reverse()功能
public static String myReverse2(String s) {

    return new StringBuffer(s).reverse().toString();
}

// 用String做拼接
public static String myReverse(String s) {
    String result = "";

    char[] chs = s.toCharArray();
    for (int x = chs.length - 1; x >= 0; x--) {
        // char ch = chs[x];
        // result += ch;
        result += chs[x];
    }

    return result;
}

D:判斷一個字符串是否對稱

public static void main(String[] args) {
    // 創建鍵盤錄入對象
    Scanner sc = new Scanner(System.in);
    System.out.println("請輸入一個字符串:");
    String s = sc.nextLine();

    // 一個一個的比較
    boolean b = isSame(s);
    System.out.println("b:" + b);

    //用字符串緩衝區的反轉功能
    boolean b2 = isSame2(s);
    System.out.println("b2:"+b2);
}

/**
 * 最佳實踐
 */
public static boolean isSame2(String s) {
    return new StringBuffer(s).reverse().toString().equals(s);
}

public static boolean isSame(String s) {
    boolean flag = true;

    // 把字符串轉成字符數組
    char[] chs = s.toCharArray();

    for (int start = 0, end = chs.length - 1; start <= end; start++, end--) {
        if (chs[start] != chs[end]) {
            flag = false;
            break;
        }
    }

    return flag;
}

(5)面試題
小細節:
StringBuffer:同步的,數據安全,效率低。
StringBuilder:不同步的,數據不安全,效率高。

                A:String,StringBuffer,StringBuilder的區別

答: 

* A:String是內容不可變的,而StringBuffer,StringBuilder都是內容可變的。
* B:StringBuffer是同步的,數據安全,效率低;StringBuilder是不同步的,數據不安全,效率高


B:StringBuffer和數組的區別?

答:

 * 二者都可以看出是一個容器,裝其他的數據。
 * 但是呢,StringBuffer的數據最終是一個字符串數據。
 * 而數組可以放置多種數據,但必須是同一種數據類型的。


(6)注意的問題:
String作爲形式參數,StringBuffer作爲形式參數。

答:

 * String作爲參數傳遞。效果和基本類型作爲參數傳遞是一樣的。
 * StringBuffer作爲參數傳遞
 *
 * 形式參數:
 * 基本類型:形式參數的改變不影響實際參數
 * 引用類型:形式參數的改變直接影響實際參數

 *
 * 注意:
 * String作爲參數傳遞,效果和基本類型作爲參數傳遞是一樣的。
 */

public static void main(String[] args) {
    String s1 = "hello";
    String s2 = "world";
    System.out.println(s1 + "---" + s2);// hello---world
    change(s1, s2);
    // TODO String作爲參數傳遞,效果和基本類型作爲參數傳遞是一樣的,不改變原值*******
    System.out.println(s1 + "---" + s2);// hello---world

    StringBuffer sb1 = new StringBuffer("hello");
    StringBuffer sb2 = new StringBuffer("world");
    System.out.println(sb1 + "---" + sb2);// hello---world
    change(sb1, sb2);
    // TODO
    System.out.println(sb1 + "---" + sb2);// hello---worldworld

}

public static void change(String s1, String s2) {
    s1 = s2;
    System.out.println("String Change s1 before:"+s1); // world
    System.out.println("String Change s2 before:"+s2); // world
    s2 = s1 + s2; // 開闢新的地址
    System.out.println("String Change later s1:"+s1); // world
    System.out.println("String Change later s2:"+s2); // worldworld

}

public static void change(StringBuffer sb1, StringBuffer sb2) {
    sb1 = sb2;
    System.out.println("StringBuffer Change s1 before:"+sb1); // world
    System.out.println("StringBuffer Change s2 before:"+sb2); // world
    sb2.append(sb1);

    System.out.println("StringBuffer Change later s1:"+sb1); //worldworld
    System.out.println("StringBuffer Change later s2:"+sb2); //worldworld
}

2:數組高級以及Arrays(掌握)

(1)排序
A:冒泡排序
相鄰元素兩兩比較,大的往後放,第一次完畢,最大值出現在了最大索引處。同理,其他的元素就可以排好。

public static void bubbleSort(int[] arr){
    for (int x = 0; x < arr.length - 1; x++) {
        for (int y = 0; y < arr.length - 1 - x; y++) {
            if (arr[y] > arr[y + 1]) {
                int temp = arr[y];
                arr[y] = arr[y + 1];
                arr[y + 1] = temp;
            }
        }
    }
}		

B:選擇排序
把0索引的元素,和索引1以後的元素都進行比較,第一次完畢,最小值出現在了0索引。同理,其他的元素就可以排好。

public static void selectSort(int[] arr){
    for(int x=0; x<arr.length-1; x++){
        for(int y=x+1; y<arr.length; y++){
            if(arr[y] <arr[x]){
                int temp = arr[x];
                arr[x] = arr[y];
                arr[y] = temp;
            }
        }
    }
}					

(2)查找
A:基本查找
針對數組無序的情況

public static int getIndex(int[] arr,int value) {
int index = -1;

for(int x=0; x<arr.length; x++) {
if(arr[x] == value) {
index = x;
break;
}
}

return index;
}
B:二分查找(折半查找)
針對數組有序的情況(千萬不要先排序,在查找)

public static int getIndex(int[] arr,int value){
    //定義最大索引,最小索引
    int max = arr.length -1;
    int min = 0;

    //計算出中間索引
    int mid = (max +min)/2;

    //拿中間索引的值和要查找的值進行比較
    while(arr[mid] != value){
        if(arr[mid]>value){
            max = mid - 1;
        }else if(arr[mid]<value){
            min = mid + 1;
        }

        //加入判斷
        if(min > max){
            return -1;
        }

        mid = (max +min)/2;
    }

    return mid;
}

(3)Arrays工具類
A:是針對數組進行操作的工具類。包括排序查找等功能。
B:要掌握的方法(自己補齊方法)

 * 1:public static String toString(int[] a)                    把數組轉成字符串
 * 2:public static void sort(int[] a)                              對數組進行排序
 * 3:public static int binarySearch(int[] a,int key)      二分查找

// 定義一個數組
int[] arr = { 24, 69, 80, 57, 13 };

/**
 * public static String toString(int[] a)
 * 把數組轉成字符串
 */
System.out.println("排序前:" + Arrays.toString(arr));

/**
 * public static void sort(int[] a)
 * 對數組進行排序
 */
Arrays.sort(arr);
System.out.println("排序後:" + Arrays.toString(arr));

/**
 * public static int binarySearch(int[] a,int key)
 * 二分查找
 */
// [13, 24, 57, 69, 80]
System.out.println("binarySearch:" + Arrays.binarySearch(arr, 57)); // 2
System.out.println("binarySearch:" + Arrays.binarySearch(arr, 577));

(4)Arrays工具類的源碼解析
(5)把字符串中的字符進行排序
舉例:
"edacbgf"
得到結果
"abcdefg"
 

3:Integer(掌握)

(1)爲了讓基本類型的數據進行更多的操作,Java就爲每種基本類型提供了對應的包裝類類型
byte          Byte
short         Short
int             Integer
long          Long
float          Float
double      Double
char          Character
boolean    Boolean
(2)Integer的構造方法
A:Integer i = new Integer(100);
B:Integer i = new Integer("100");
注意:這裏的字符串必須是由數字字符組成

/**
 * public Integer(int value)
 */
int i = 100;
Integer ii = new Integer(i);
System.out.println("ii:" + ii);

/**
 * public Integer(String s)
 */
String s = "100";
// NumberFormatException
// String s = "abc";
Integer iii = new Integer(s);
System.out.println("iii:" + iii);

(3)String和int的相互轉換
A:String -- int
Integer.parseInt("100");
B:int -- String
String.valueOf(100);
(4)其他的功能(瞭解)
進制轉換

// 十進制到二進制,八進制,十六進制
System.out.println(Integer.toBinaryString(100));
System.out.println(Integer.toOctalString(100));
System.out.println(Integer.toHexString(100));

(5)JDK5的新特性
自動裝箱 基本類型--引用類型
自動拆箱 引用類型--基本類型

把下面的這個代碼理解即可:
Integer i = 100;
i += 200;
(6)面試題
-128到127之間的數據緩衝池問題

                針對-128到127之間的數據,做了一個數據緩衝池,如果數據是該範圍內的,每次並不創建新的空間

 

4:Character(瞭解)

(1)Character構造方法
Character ch = new Character('a');
(2)要掌握的方法:

 * public static boolean isUpperCase(char ch)           判斷給定的字符是否是大寫字符
 * public static boolean isLowerCase(char ch)            判斷給定的字符是否是小寫字符
 * public static boolean isDigit(char ch)                     判斷給定的字符是否是數字字符
 * public static char toUpperCase(char ch)                 把給定的字符轉換爲大寫字符
 * public static char toLowerCase(char ch)                 把給定的字符轉換爲小寫字符
(3)案例:
統計字符串中大寫,小寫及數字字符出現的次數

// 定義三個統計變量。
int bigCount = 0;
int smallCount = 0;
int numberCount = 0;

// 鍵盤錄入一個字符串。
Scanner sc = new Scanner(System.in);
System.out.println("請輸入一個字符串:");
String line = sc.nextLine();

// 把字符串轉換爲字符數組。
char[] chs = line.toCharArray();

// 歷字符數組獲取到每一個字符
for (int x = 0; x < chs.length; x++) {
    char ch = chs[x];

    // 判斷該字符
    if (Character.isUpperCase(ch)) {
        bigCount++;
    } else if (Character.isLowerCase(ch)) {
        smallCount++;
    } else if (Character.isDigit(ch)) {
        numberCount++;
    }
}

// 輸出結果即可
System.out.println("大寫字母:" + bigCount + "個");
System.out.println("小寫字母:" + smallCount + "個");
System.out.println("數字字符:" + numberCount + "個");

============================================================================

1:正則表達式(理解)

(1)就是符合一定規則的字符串
(2)常見規則
A:字符
x 字符 x。舉例:'a'表示字符a
\\ 反斜線字符。
\n 新行(換行)符 ('\u000A') 
\r 回車符 ('\u000D')

B:字符類
[abc] a、b 或 c(簡單類) 
[^abc] 任何字符,除了 a、b 或 c(否定) 
[a-zA-Z] a到 z 或 A到 Z,兩頭的字母包括在內(範圍) 
[0-9] 0到9的字符都包括

C:預定義字符類
. 任何字符。我的就是.字符本身,怎麼表示呢? \.
\d 數字:[0-9]
\w 單詞字符:[a-zA-Z_0-9]
在正則表達式裏面組成單詞的東西必須有這些東西組成


D:邊界匹配器
^ 行的開頭 
$ 行的結尾 
\b 單詞邊界
就是不是單詞字符的地方。
舉例:hello world?haha;xixi

E:Greedy 數量詞 
X? X,一次或一次也沒有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次 
X{n,} X,至少 n 次 
X{n,m} X,至少 n 次,但是不超過 m 次 
(3)常見功能:(分別用的是誰呢?)
A:判斷功能
String類的public boolean matches(String regex)
B:分割功能
String類的public String[] split(String regex)

        //定義一個年齡搜索範圍
        String ages = "18-24";

        //定義規則
        String regex = "-";

        //調用方法
        String[] strArray = ages.split(regex);

        //如何得到int類型的呢?
        int startAge = Integer.parseInt(strArray[0]);
        int endAge = Integer.parseInt(strArray[1]);

        //鍵盤錄入年齡
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入你的年齡:");
        int age = sc.nextInt();

        if(age>=startAge && age<=endAge) {
            System.out.println("你就是我想找的");
        }else {
            System.out.println("不符合我的要求,gun");
        }

C:替換功能
String類的public String replaceAll(String regex,String replacement)

// 定義一個字符串
String s = "helloqq12345worldkh622112345678java";

// 直接把數字幹掉
String regex = "\\d+";
String ss = "";

String result = s.replaceAll(regex, ss);
System.out.println(result); // helloqqworldkhjava

D:獲取功能
Pattern和Matcher
Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");

find():查找存不存在
group():獲取剛纔查找過的數據

(4)案例
A:判斷電話號碼和郵箱
B:按照不同的規則分割數據
C:把論壇中的數字替換爲*
D:獲取字符串中由3個字符組成的單詞

2:Math(掌握)

(1)針對數學運算進行操作的類
(2)常見方法(自己補齊)

 * 成員變量:
 * public static final double PI
 * public static final double E
 * 成員方法:
 * public static int abs(int a):絕對值
 * public static double ceil(double a):向上取整
 * public static double floor(double a):向下取整
 * public static int max(int a,int b):最大值 (min自學)
 * public static double pow(double a,double b):a的b次冪
 * public static double random():隨機數 [0.0,1.0)
 * public static int round(float a) 四捨五入(參數爲double的自學)
 * public static double sqrt(double a):正平方根

(3)案例:
A:猜數字小遊戲
B:獲取任意範圍的隨機數

3:Random(理解)

(1)用於產生隨機數的類
(2)構造方法:
A:Random() 默認種子,每次產生的隨機數不同
B:Random(long seed) 指定種子,每次種子相同,隨機數就相同
(3)成員方法:
A:int nextInt() 返回int範圍內的隨機數
B:int nextInt(int n) 返回[0,n)範圍內的隨機數
 

4:System(掌握)

(1)系統類,提供了一些有用的字段和方法,它不能被實例化。


      成員方法:
 * public static void gc():                                        運行垃圾回收器。

Person p = new Person("笑嘻嘻", 60);
System.out.println(p);

p = null; // 讓p不再指定堆內存
System.gc();

 * public static void exit(int status) 退出jvm。         終止當前正在運行的 Java 虛擬機。參數用作狀態碼;根據慣                                                                                                     例, 非 0  的狀態碼錶示異常終止。 

System.out.println("我們喜歡林青霞(東方不敗)");
System.exit(0);
System.out.println("我們也喜歡趙雅芝(白娘子)"); // 不執行

 * public static long currentTimeMillis()                   獲取當前時間的毫秒值

System.out.println(System.currentTimeMillis()); // 1528449538842

// 單獨得到這樣的實際目前對我們來說意義不大
// 那麼,它到底有什麼作用呢?
// 要求:請大家給我統計這段程序的運行時間
long start = System.currentTimeMillis();
for (int x = 0; x < 100; x++) {
    System.out.println("hello" + x);
}
long end = System.currentTimeMillis();
System.out.println("共耗時:" + (end - start) + "毫秒"); // 共耗時:1毫秒

 * public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length)    數組複製。

                                                     從指定源數 組中複製一個數組,複製從指定的位置開始,到目標數組的指定位置結束。

// 定義數組
int[] arr = { 11, 22, 33, 44, 55 };
int[] arr2 = { 6, 7, 8, 9, 10 };

// 請大家看這個代碼的意思
System.arraycopy(arr, 1, arr2, 2, 2);

System.out.println(Arrays.toString(arr)); // [11, 22, 33, 44, 55]
System.out.println(Arrays.toString(arr2)); // [6, 7, 22, 33, 10]

 

5:BigInteger(理解)

(1)針對大整數的運算
(2)構造方法
A:BigInteger(String s)
(3)成員方法(自己補齊)
 * public BigInteger add(BigInteger val):            加
 * public BigInteger subtract(BigInteger val):     減
 * public BigInteger multiply(BigInteger val):     乘
 * public BigInteger divide(BigInteger val):         除
 * public BigInteger[] divideAndRemainder(BigInteger val):        返回商和餘數的數組

 

BigInteger bi1 = new BigInteger("100");
BigInteger bi2 = new BigInteger("50");

System.out.println("add:" + bi1.add(bi2));

System.out.println("subtract:" + bi1.subtract(bi2));

System.out.println("multiply:" + bi1.multiply(bi2));

System.out.println("divide:" + bi1.divide(bi2));

// public BigInteger[] divideAndRemainder(BigInteger val):返回商和餘數的數組
BigInteger[] bis = bi1.divideAndRemainder(bi2);
System.out.println("商:" + bis[0]);
System.out.println("餘數:" + bis[1]);

6:BigDecimal(理解)

(1)浮點數據做運算,會丟失精度。所以,針對浮點數據的操作建議採用BigDecimal。(金融相關的項目)

* 看程序寫結果:結果和我們想的有一點點不一樣,這是因爲float類型的數據存儲和整數不一樣導致的。它們大部分的時候,都是帶有有效數字位。
 * 由於在運算的時候,float類型和double很容易丟失精度,演示案例。所以,爲了能精確的表示、計算浮點數,Java提供了BigDecimal
 * BigDecimal類:不可變的、任意精度的有符號十進制數,可以解決數據丟失問題。

System.out.println(0.09 + 0.01); // 0.09999999999999999
System.out.println(1.0 - 0.32); // 0.6799999999999999
System.out.println(1.015 * 100); // 101.49999999999999
System.out.println(1.301 / 100); // 0.013009999999999999
System.out.println(1.0 - 0.12); // 0.88

(2)構造方法
A:BigDecimal(String s)

BigDecimal bd1 = new BigDecimal("0.09");
BigDecimal bd2 = new BigDecimal("0.01");
System.out.println("add:" + bd1.add(bd2));
System.out.println("-------------------");

(3)成員方法:


 * public BigDecimal add(BigDecimal augend)
 * public BigDecimal subtract(BigDecimal subtrahend)
 * public BigDecimal multiply(BigDecimal multiplicand)
 * public BigDecimal divide(BigDecimal divisor)
 * public BigDecimal divide(BigDecimal divisor,int scale,int roundingMode):商,幾位小數,如何舍取

 

BigDecimal bd1 = new BigDecimal("0.09");
BigDecimal bd2 = new BigDecimal("0.01");
System.out.println("add:" + bd1.add(bd2));
System.out.println("-------------------");

BigDecimal bd3 = new BigDecimal("1.0");
BigDecimal bd4 = new BigDecimal("0.32");
System.out.println("subtract:" + bd3.subtract(bd4));
System.out.println("-------------------");

BigDecimal bd5 = new BigDecimal("1.015");
BigDecimal bd6 = new BigDecimal("100");
System.out.println("multiply:" + bd5.multiply(bd6));
System.out.println("-------------------");

BigDecimal bd7 = new BigDecimal("1.301");
BigDecimal bd8 = new BigDecimal("100");
System.out.println("divide:" + bd7.divide(bd8));
System.out.println("divide:" + bd7.divide(bd8, 3, BigDecimal.ROUND_HALF_UP));
System.out.println("divide:" + bd7.divide(bd8, 8, BigDecimal.ROUND_HALF_UP));

7:Date/DateFormat(掌握)

(1)Date是日期類,可以精確到毫秒。
A:構造方法
Date()
Date(long time)

// 創建對象
Date d = new Date();
System.out.println("d:" + d); // Mon Jun 11 10:12:23 CST 2018

// 創建對象
// long time = System.currentTimeMillis();
long time = 1000 * 60 * 60; // 1小時
// TODO 時間???**************
Date d2 = new Date(time);
System.out.println("d2:" + d2); // Thu Jan 01 09:00:00 CST 1970

B:成員方法
* public long getTime():獲取時間,以毫秒爲單位 和System.currentTimeMillis()得到的一樣
 * public void setTime(long time):設置時間
 
 * 從Date得到一個毫秒值
   getTime()
 * 把一個毫秒值轉換爲Date
   構造方法
   setTime(long time)

// 創建對象
Date d = new Date();

// 獲取時間
long time = d.getTime();
System.out.println(time); // 1528688513055
System.out.println(System.currentTimeMillis()); // 1528688513056

System.out.println("d:" + d); // Mon Jun 11 11:41:53 CST 2018
// 設置時間 1970-01-01 8:00:00 基礎上加
d.setTime(1000);
System.out.println("d:" + d); // Thu Jan 01 08:00:01 CST 1970

C:日期和毫秒值的相互轉換
案例:你來到這個世界多少天了?

(2)DateFormat針對日期進行格式化和針對字符串進行解析的類,但是是抽象類,所以使用其子類SimpleDateFormat

 *  年 y
 *  月 M
 *  日 d
 *  時 H
 *  分 m
 *  秒 s
A: SimpleDateFormat的構造方法

             *  SimpleDateFormat():默認模式 18-6-11 上午11:45
             *  SimpleDateFormat(String pattern):給定的模式   yyyy-MM-dd HH:mm:ss 

                                             SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
B:日期和字符串的轉換 

                        SimpleDateFormat的對象進行調用
a:Date --> String
public final String format(Date date)

b:String --> Date
public Date parse(String source)

/**
 * Date --> String
 */
Date d = new Date();
// 創建格式化對象
// 默認模式
// SimpleDateFormat sdf = new SimpleDateFormat(); // 18-6-11 上午11:45
// 給定模式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
// public final String format(Date date)
String s = sdf.format(d);
System.out.println(s); // 2018年06月11日 11:50:57

/**
 * String --> Date
 */
String str = "2008-08-08 12:12:12";
//在把一個字符串解析爲日期的時候,請注意格式必須和給定的字符串格式匹配
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// public Date parse(String source)
Date dd = sdf2.parse(str);
System.out.println(dd); // Fri Aug 08 12:12:12 CST 2008

C:案例:
製作了一個針對日期操作的工具類。

/**
 * 這是日期和字符串相互轉換的工具類
 */
public class Date4Util {

    // TODO 爲什麼要有個無參構造************
    private Date4Util() {
    }

    /**
     * 這個方法的作用就是把日期轉成一個字符串
     *
     * @param d
     *            被轉換的日期對象
     * @param format
     *            傳遞過來的要被轉換的格式
     * @return 格式化後的字符串
     */
    public static String dateToString(Date d, String format) {
        return new SimpleDateFormat(format).format(d);
    }

    /**
     * 這個方法的作用就是把一個字符串解析成一個日期對象
     *
     * @param s
     *            被解析的字符串
     * @param format
     *            傳遞過來的要被轉換的格式
     * @return 解析後的日期對象
     * @throws ParseException
     */
    public static Date stringToDate(String s, String format) throws ParseException {
        return new SimpleDateFormat(format).parse(s);
    }
}

測試類:

 

Date d = new Date();
// yyyy-MM-dd HH:mm:ss
String s = Date4Util.dateToString(d, "yyyy年MM月dd日 HH:mm:ss");
System.out.println(s); // 2018年06月11日 12:15:24

String s2 = Date4Util.dateToString(d, "yyyy年MM月dd日");
System.out.println(s2); // 2018年06月11日

String s3 = Date4Util.dateToString(d, "HH:mm:ss");
System.out.println(s3); // 12:15:24

String str = "2014-10-14";
Date dd = Date4Util.stringToDate(str, "yyyy-MM-dd");
System.out.println(dd); // Tue Oct 14 00:00:00 CST 2014

8:Calendar(掌握)

(1)日曆類,封裝了所有的日曆字段值(YEAR、MONTH、DAY_OF_MONTH、HOUR 等),通過統一的方法根據傳入不同的日曆字段可以獲取值。日曆類中的每個日曆字段都是靜態的成員變量,並且是int類型。

(2)如何得到一個日曆對象呢?
Calendar rightNow = Calendar.getInstance();
本質返回的是子類對象
(3)成員方法
A:根據日曆字段得到對應的值 public int get(int field)

/**
 * 獲取當前的日曆時間
 */
Calendar c = Calendar.getInstance();

// 獲取年
int year = c.get(Calendar.YEAR);
// 獲取月
int month = c.get(Calendar.MONTH);
// 獲取日
int date = c.get(Calendar.DATE);
System.out.println(year + "年" + (month + 1) + "月" + date + "日");

B:根據日曆字段和一個正負數確定是添加還是減去對應日曆字段的值 public void add(int field,int amount)

/**
 * 三年前的今天
 */
c.add(Calendar.YEAR, -3);
// 獲取年
year = c.get(Calendar.YEAR);
// 獲取月
month = c.get(Calendar.MONTH);
// 獲取日
date = c.get(Calendar.DATE);
System.out.println(year + "年" + (month + 1) + "月" + date + "日");

/**
 * 5年後的10天前
 */
c.add(Calendar.YEAR, 5);
c.add(Calendar.DATE, -10);
// 獲取年
year = c.get(Calendar.YEAR);
// 獲取月
month = c.get(Calendar.MONTH);
// 獲取日
date = c.get(Calendar.DATE);
System.out.println(year + "年" + (month + 1) + "月" + date + "日");
System.out.println("--------------");

C:設置日曆對象的年月日 public final void set(int year,int month,int date)

/**
 * 設置日曆
 */
c.set(2011, 11, 11);
// 獲取年
year = c.get(Calendar.YEAR);
// 獲取月
month = c.get(Calendar.MONTH);
// 獲取日
date = c.get(Calendar.DATE);
System.out.println(year + "年" + (month + 1) + "月" + date + "日");

(4)案例:
計算任意一年的2月份有多少天?

// 鍵盤錄入任意的年份
Scanner sc = new Scanner(System.in);
System.out.println("請輸入年份:");
int year = sc.nextInt();

// 設置日曆對象的年月日
Calendar c = Calendar.getInstance();
c.set(year, 2, 1); // 其實是這一年的3月1日
// 把時間往前推一天,就是2月的最後一天
c.add(Calendar.DATE, -1);

// 獲取這一天輸出即可
System.out.println(c.get(Calendar.DATE));

============================================================================

1:對象數組(掌握)

(1)數組既可以存儲基本數據類型,也可以存儲引用類型。它存儲引用類型的時候的數組就叫對象數組。
(2)案例:
用數組存儲5個學生對象,並遍歷數組。

// 創建學生數組(對象數組)。
Student[] students = new Student[5];

// 創建5個學生對象,並賦值。
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("風清揚", 30);
Student s3 = new Student("劉意", 30);
Student s4 = new Student("趙雅芝", 60);
Student s5 = new Student("王力宏", 35);

// 把C步驟的元素,放到數組中。
students[0] = s1;
students[1] = s2;
students[2] = s3;
students[3] = s4;
students[4] = s5;

// 遍歷
for (int x = 0; x < students.length; x++) {
    Student s = students[x];
    System.out.println(s.getName()+"---"+s.getAge());
}

2:集合(Collection)(掌握)

(1)集合的由來?
我們學習的是Java -- 面向對象 -- 操作很多對象 -- 存儲 -- 容器(數組和StringBuffer) -- 數組
而數組的長度固定,所以不適合做變化的需求,Java就提供了集合供我們使用。

(2)集合和數組的區別?
A:長度區別
數組固定
集合可變
B:內容區別
數組可以是基本類型,也可以是引用類型。
集合只能是引用類型。
C:元素內容
數組只能存儲同一種類型
集合可以存儲不同類型(其實集合一般存儲的也是同一種類型)
(3)集合的繼承體系結構?
由於需求不同,Java就提供了不同的集合類。這多個集合類的數據結構不同,但是它們都是要提供存儲和遍歷功能的,
我們把它們的共性不斷的向上提取,最終就形成了集合的繼承體系結構圖。

Collection
|--List
  |--ArrayList
  |--Vector
  |--LinkedList
|--Set
  |--HashSet
  |--TreeSet

(4)Collection的功能概述(自己補齊)
A:添加功能

*  boolean add(Object obj):添加一個元素
 * boolean addAll(Collection c):添加一個集合的元素

/**
 * boolean add(Object obj)
 * 添加一個元素
 */
c.add("hello");
c.add("world");
c.add("java");


/**
 * boolean addAll(Collection c)
 * 添加一個集合的元素
 */
Collection c1 = new ArrayList();
c1.add("嘻嘻");
c.addAll(c1);

B:刪除功能

 * void clear():移除所有元素
 * boolean remove(Object o):移除一個元素
 * boolean removeAll(Collection c):移除一個集合的元素(是一個還是所有)

/**
 * void clear()
 * 移除所有元素
 */
c.clear(); // []

/**
 * boolean remove(Object o)
 * 移除一個元素
 */
System.out.println("remove:" + c.remove("hello"));
System.out.println("remove:" + c.remove("嘻嘻"));
System.out.println("removeAll:" + c.removeAll(c1));

C:判斷功能

*  boolean contains(Object o):判斷集合中是否包含指定的元素
 * boolean containsAll(Collection c):判斷集合中是否包含指定的集合元素(是一個還是所有)
 * boolean isEmpty():判斷集合是否爲空

/**
 * boolean contains(Object o)
 * 判斷集合中是否包含指定的元素
 */
System.out.println("contains:"+c.contains("hello"));
System.out.println("contains:"+c.contains("android"));

/**
 * boolean isEmpty()
 * 判斷集合是否爲空
 */
System.out.println("isEmpty:"+c.isEmpty());

D:獲取功能

                        Iterator<E> iterator()(重點)
E:長度功能

                        int size():元素的個數

 *         面試題:數組有沒有length()方法呢?字符串有沒有length()方法呢?集合有沒有length()方法呢?

/**
 * int size()
 * 元素的個數
 */
System.out.println("size:"+c.size());
System.out.println("c:" + c);

F:交集(瞭解)

                        boolean retainAll(Collection c):兩個集合都有的元素?思考元素去哪了,返回的boolean又是什麼意思呢?
G:把集合轉數組(瞭解)

                        Object[] toArray()
(5)Collection集合的遍歷
A:把集合轉數組(瞭解)

        // 創建集合對象
        Collection c = new ArrayList();

        // 創建學生對象
        Student s1 = new Student("林青霞", 27);
        Student s2 = new Student("風清揚", 30);
        Student s3 = new Student("令狐沖", 33);
        Student s4 = new Student("武鑫", 25);
        Student s5 = new Student("劉曉曲", 22);

        // 把學生添加到集合
        c.add(s1);
        c.add(s2);
        c.add(s3);
        c.add(s4);
        c.add(s5);

        System.out.println(c);
        // [com.shiki.common.basic.collection.Student@1d44bcfa,
        // com.shiki.common.basic.collection.Student@266474c2,
        // com.shiki.common.basic.collection.Student@6f94fa3e,
        // com.shiki.common.basic.collection.Student@5e481248,
        // com.shiki.common.basic.collection.Student@66d3c617]

        // 把集合轉成數組
        Object[] objs = c.toArray();
        System.out.println(objs); // [Ljava.lang.Object;@63947c6b

        // 遍歷數組
        for (int x = 0; x < objs.length; x++) {
//          System.out.println(objs[x]); com.shiki.common.basic.collection.Student@1d44bcfa
            Student s = (Student) objs[x];
            System.out.println(s.getName() + "---" + s.getAge());
        }

B:迭代器(集合專用方式)

 *         Iterator iterator():迭代器,集合的專用遍歷方式 Iterator it = c.iterator(); 
 *         Object next():獲取元素,並移動到下一個位置。
 * NoSuchElementException:沒有這樣的元素,因爲你已經找到最後了。
 *         boolean hasNext():如果仍有元素可以迭代,則返回 true。

// 創建集合對象
Collection c = new ArrayList();

// 創建並添加元素
c.add("hello");
c.add("world");
c.add("java");

/**
 * Iterator iterator()
 * 迭代器,集合的專用遍歷方式
 */
Iterator it = c.iterator(); // 實際返回的肯定是子類對象,這裏是多態

// 最終版代碼
while (it.hasNext()) {
// System.out.println(it.next()); 放開報錯:NoSuchElementException
   String s = (String) it.next();
   System.out.println(s);
}

String s = (String) it.next(); System.out.println(s);} (6)迭代器
A:是集合的獲取元素的方式。
B:是依賴於集合而存在的。
C:迭代器的原理和源碼。
a:爲什麼定義爲了一個接口而不是實現類?
b:看了看迭代器的內部類實現。

(7)Collection集合的案例(遍歷方式 迭代器)
集合的操作步驟:
A:創建集合對象
B:創建元素對象
C:把元素添加到集合
D:遍歷集合

A:存儲字符串並遍歷

// 創建集合對象
Collection c = new ArrayList();

// 把字符串對象添加到集合中
c.add("林青霞");
c.add("風清揚");
c.add("劉意");
c.add("武鑫");
c.add("劉曉曲");

// 遍歷集合
// 通過集合對象獲取迭代器對象
Iterator it = c.iterator();
// 通過迭代器對象的hasNext()方法判斷有沒有元素
while (it.hasNext()) {
    // 通過迭代器對象的next()方法獲取元素
    String s = (String) it.next();
    System.out.println(s);
}	

B:存儲自定義對象並遍歷
public class Student {
private String name;
private int age;

public Student(){}

public Student(String name,int age) {
this.name = name;
this.age = age;
}

//getXxx()/setXxx()
}

import java.util.Collection;
import java.util.ArrayList;
import java.util.Iterator;

public class StudentDemo {
public static void main(String[] args) {
//創建集合對象
Collection c = new ArrayList();

//創建學生對象
Student s1 = new Student("林青霞",27);
Student s2 = new Student("風清揚",30);
Student s3 = new Student("劉意",30);
Student s4 = new Student("武鑫",25);
Student s5 = new Student("劉曉曲",16);

//添加元素
c.add(s1);
c.add(s2);
c.add(s3);
c.add(s4);
c.add(s5);

//遍歷集合
Iterator it = c.iterator();
while(it.hasNext()) {
Student s = (Student)it.next();
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
 

3:集合(List)(掌握)

(1)List是Collection的子接口
特點:有序(存儲順序和取出順序一致),可重複
(2)List的特有功能:(自己補齊)
 * A:添加功能
 * void add(int index,Object element):在指定位置添加元素
 * B:獲取功能
 * Object get(int index):獲取指定位置的元素
 * C:列表迭代器
 * ListIterator listIterator():List集合特有的迭代器
 * D:刪除功能
 * Object remove(int index):根據索引刪除元素,返回被刪除的元素
 * E:修改功能
 * Object set(int index,Object element):根據索引修改元素,返回被修飾的元素

System.out.println("list:" + list);
/**
 * void add(int index,Object element)
 * 在指定位置添加元素
 */
 list.add(1, "android");//沒有問題
System.out.println("list:" + list);
// Object get(int index):獲取指定位置的元素
// System.out.println("get:" + list.get(1));
// IndexOutOfBoundsException
// System.out.println("get:" + list.get(11));

/**
 * Object remove(int index)
 * 根據索引刪除元素,返回被刪除的元素
 */
System.out.println("remove:" + list.remove(1));
// IndexOutOfBoundsException
// System.out.println("remove:" + list.remove(11));

/**
 * Object set(int index,Object element)
 * 根據索引修改元素,返回被修改的元素
 */
System.out.println("set:" + list.set(1, "javaee"));

System.out.println("list:" + list);

(3)List集合的特有遍歷功能
A:由size()和get()結合。
B:代碼演示

// 創建集合對象
List list = new ArrayList();

// 創建學生對象
Student s1 = new Student("林黛玉", 18);
Student s2 = new Student("劉姥姥", 88);
Student s3 = new Student("王熙鳳", 38);

// 把學生添加到集合中
list.add(s1);
list.add(s2);
list.add(s3);

// 遍歷
// 迭代器遍歷
Iterator it = list.iterator();
while (it.hasNext()) {
    Student s = (Student) it.next();
    System.out.println(s.getName() + "---" + s.getAge());
}
System.out.println("--------");

// 普通for循環
for (int x = 0; x < list.size(); x++) {
    Student s = (Student) list.get(x);
    System.out.println(s.getName() + "---" + s.getAge());
}

(4)列表迭代器的特有功能;(瞭解)
可以逆向遍歷,但是要先正向遍歷,所以無意義,基本不使用。

// 創建List集合對象
        List list = new ArrayList();
        list.add("hello");
        list.add("world");
        list.add("java");

        // ListIterator listIterator()
        ListIterator lit = list.listIterator(); // 子類對象
         while (lit.hasNext()) {
         String s = (String) lit.next();
         System.out.println(s);
         }
         System.out.println("-----------------");

        /**
         * Object previous()
         * 獲取上一個元素
         */
//        System.out.println(lit.previous());
//         System.out.println(lit.previous());
//         System.out.println(lit.previous());
        // NoSuchElementException
        // System.out.println(lit.previous());
        System.out.println("while:-----------------");
        while (lit.hasPrevious()) {
            String s = (String) lit.previous();
            System.out.println(s);
        }
        System.out.println("-----------------");

        // 迭代器
        Iterator it = list.iterator();
        while (it.hasNext()) {
            String s = (String) it.next();
            System.out.println(s);
        }
        System.out.println("-----------------");

(5)併發修改異常
A:出現的現象
迭代器遍歷集合,集合修改集合元素
B:原因
迭代器是依賴於集合的,而集合的改變迭代器並不知道。
C:解決方案

// 創建List集合對象
List list = new ArrayList();
// 添加元素
list.add("hello");
list.add("world");
list.add("java");
System.out.println(list); // [hello, world, java]

a:迭代器遍歷,迭代器修改(ListIterator)
元素添加在剛纔迭代的位置

ListIterator lit = list.listIterator();
while (lit.hasNext()) {
    String s = (String) lit.next();
    if ("world".equals(s)) {
    lit.add("javaee");
    }
} // [hello, world, javaee, java]

b:集合遍歷,集合修改(size()和get())
元素添加在集合的末尾

for (int x = 0; x < list.size(); x++) {
    String s = (String) list.get(x);
    if ("world".equals(s)) {
        list.add("javaee");
    }
} //[hello, world, java, javaee]


(6)常見數據結構
A:棧 先進後出
B:隊列 先進先出
C:數組 查詢快,增刪慢
D:鏈表 查詢慢,增刪快

(7)List的子類特點(面試題)
ArrayList
底層數據結構是數組,查詢快,增刪慢。
線程不安全,效率高。
Vector
底層數據結構是數組,查詢快,增刪慢。
線程安全,效率低。
LinkedList
底層數據結構是鏈表,查詢慢,增刪快。
線程不安全,效率高。


到底使用誰呢?看需求?
分析:
要安全嗎?
要:Vector(即使要,也不使用這個,後面再說)
不要:ArrayList或者LinkedList
查詢多;ArrayList
增刪多:LinkedList


什麼都不知道,就用ArrayList。
(8)List集合的案例(遍歷方式 迭代器和普通for)
A:存儲字符串並遍歷
B:存儲自定義對象並遍歷

============================================================================

 

1:List的子類(掌握)

(1)List的子類特點
ArrayList:
底層數據結構是數組,查詢快,增刪慢
線程不安全,效率高
Vector:
底層數據結構是數組,查詢快,增刪慢
線程安全,效率低
LinkedList:
底層數據結構是鏈表,查詢慢,增刪快
線程不安全,效率高

(2)ArrayList
A:沒有特有功能需要學習
B:案例
a:ArrayList存儲字符串並遍歷

b:ArrayList存儲自定義對象並遍歷

 

// 創建集合對象
ArrayList array = new ArrayList();

// 創建學生對象
Student s1 = new Student("武松", 30);
Student s2 = new Student("魯智深", 40);
Student s3 = new Student("林沖", 36);
Student s4 = new Student("楊志", 38);

// 添加元素
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);

// 遍歷
Iterator it = array.iterator();
while (it.hasNext()) {
    Student s = (Student) it.next();
    System.out.println(s.getName() + "---" + s.getAge());
}

System.out.println("----------------");

for (int x = 0; x < array.size(); x++) {
    // ClassCastException 注意,千萬要搞清楚類型
    // String s = (String) array.get(x);
    // System.out.println(s);

    Student s = (Student) array.get(x);
    System.out.println(s.getName() + "---" + s.getAge());
}

(3)Vector
A:有特有功能
* 1:添加功能
 * public void addElement(Object obj) -- add()

 * 2:獲取功能
 * public Object elementAt(int index) --  get()
 * public Enumeration elements() -- Iterator iterator()
 * boolean hasMoreElements() hasNext()
 * Object nextElement() next()
B:案例
a:Vector存儲字符串並遍歷

b:Vector存儲自定義對象並遍歷

(4)LinkedList
A:有特有功能
        A:添加功能
 *     public void addFirst(Object e)
 *     public void addLast(Object e)
 *         B:獲取功能
 *     public Object getFirst()
 *     public Obejct getLast()
 *         C:刪除功能
 *     public Object removeFirst()
 *     public Object removeLast()
B:案例
a:LinkedList存儲字符串並遍歷

b:LinkedList存儲自定義對象並遍歷

// 創建集合對象
LinkedList link = new LinkedList();

// 添加元素
link.add("hello");
link.add("world");
link.add("java");
System.out.println("link:" + link);

/**
 * public void addFirst(Object e)
 */
// 
 link.addFirst("javaee");
/**
 * public void addLast(Object e)
 */
 link.addLast("android");
System.out.println("link:" + link);

/**
 * public Object getFirst()
 */
// 
 System.out.println("getFirst:" + link.getFirst());
/**
 * public Obejct getLast()
 */
 System.out.println("getLast:" + link.getLast());

/**
 * public Object removeFirst()
 */
System.out.println("removeFirst:" + link.removeFirst());
/**
 * public Object removeLast()
 */
System.out.println("removeLast:" + link.removeLast());

// 輸出對象名
System.out.println("link:" + link);

(5)案例:
A:去除集合中的多個字符串的重複元素

如果字符串的內容相同,即爲重複元素

// 創建集合對象
ArrayList array = new ArrayList();

// 添加多個字符串元素(包含內容相同的)
array.add("hello");
array.add("world");
array.add("java");
array.add("world");
array.add("java");
array.add("world");
array.add("world");
array.add("world");
array.add("world");
array.add("java");
array.add("world");

// 由選擇排序思想引入,我們就可以通過這種思想做這個題目
// 拿0索引的依次和後面的比較,有就把後的幹掉
// 同理,拿1索引...
for (int x = 0; x < array.size() - 1; x++) {
    for (int y = x + 1; y < array.size(); y++) {
        if (array.get(x).equals(array.get(y))) {
            array.remove(y);
            y--;
        }
    }
}

// 遍歷集合
Iterator it = array.iterator();
while (it.hasNext()) {
    String s = (String) it.next();
    System.out.println(s);
}

B:去除集合中的多個自定義對象的重複元素

如果自定義對象的成員變量值都相同,即爲重複元素

// 創建集合對象
ArrayList array = new ArrayList();

// 創建學生對象
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("林志玲", 40);
Student s3 = new Student("鳳姐", 35);
Student s4 = new Student("芙蓉姐姐", 18);
Student s5 = new Student("翠花", 16);
Student s6 = new Student("林青霞", 27);
Student s7 = new Student("林青霞", 18);

// 添加元素
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);
array.add(s5);
array.add(s6);
array.add(s7);

// 創建新集合
ArrayList newArray = new ArrayList();

// 遍歷舊集合,獲取得到每一個元素
Iterator it = array.iterator();
while (it.hasNext()) {
    Student s = (Student) it.next();

    // 拿這個元素到新集合去找,看有沒有
    if (!newArray.contains(s)) {
        newArray.add(s);
    }
}

// 遍歷新集合
for (int x = 0; x < newArray.size(); x++) {
    Student s = (Student) newArray.get(x);
    System.out.println(s.getName() + "---" + s.getAge());
}

 

C:用LinkedList模擬一個棧數據結構的集合類,並測試。

你要定義一個集合類,只不過內部可以使用LinkedList來實現。

// A: LinkedList的特有添加功能addFirst()
// B:棧的特點先進後出
// 創建集合對象
 LinkedList link = new LinkedList();

 // 添加元素
 link.addFirst("hello");
 link.addFirst("world");
 link.addFirst("java");

 // 遍歷
 Iterator it = link.iterator();
 while (it.hasNext()) {
 String s = (String) it.next();
 System.out.println(s);
 }
 // 先進後出
 // java
 // world
 // hello

 

2:泛型(掌握)

(1)泛型概述
是一種把明確類型的工作推遲到創建對象或者調用方法的時候纔去明確的特殊的類型。
(2)格式:
<數據類型>
注意:該數據類型只能是引用類型
(3)好處:
A:把運行時期的問題提前到了編譯期間
B:避免了強制類型轉換
C:優化了程序設計,解決了黃色警告線問題,讓程序更安全
(4)泛型的前世今生
A:泛型的由來
Object類型作爲任意類型的時候,在向下轉型的時候,會隱含一個轉型問題

B:泛型類

public class ObjectToolClass<T> {
    private T obj;

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}
ObjectToolClass<String> ot = new ObjectToolClass<String>();
// ot.setObj(new Integer(27)); //這個時候編譯期間就過不去
ot.setObj(new String("林青霞"));
String s = ot.getObj();
System.out.println("姓名是:" + s);

ObjectToolClass<Integer> ot2 = new ObjectToolClass<Integer>();
// ot2.setObj(new String("風清揚"));//這個時候編譯期間就過不去
ot2.setObj(new Integer(27));
Integer i = ot2.getObj();
System.out.println("年齡是:" + i);

C:泛型方法

public class ObjectToolMethod {
    public <T> void show(T t) {
        System.out.println(t);
    }
}

 

// 如果還聽得懂,那就說明泛型類是沒有問題的
// 但是呢,誰說了我的方法一定要和類的類型的一致呢?
// 我要是類上沒有泛型的話,方法還能不能接收任意類型的參數了呢?

// 定義泛型方法後
ObjectToolMethod ot = new ObjectToolMethod();
ot.show("hello");
ot.show(100);
ot.show(true);

D:泛型接口

public interface ObjectToolInterface<T> {
    public abstract void show(T t);
}
public class ObjectToolInterfaceImpl<T>  implements ObjectToolInterface<T> {

    @Override
    public void show(T t) {
        System.out.println(t);
    }
}
// 第一種情況的測試
// Inter<String> i = new InterImpl();
// i.show("hello");

// // 第二種情況的測試
ObjectToolInterface<String> i = new ObjectToolInterfaceImpl<String>();
i.show("hello");

ObjectToolInterface<Integer> ii = new ObjectToolInterfaceImpl<Integer>();
ii.show(100);

E:泛型高級通配符
 
 * ?:任意類型,如果沒有明確,那麼就是Object以及任意的Java類了
 * ? extends E:向下限定,E及其子類

 * ? super E:向上限定,E及其父類

public class GenericAdvanced {
    public static void main(String[] args) {
        // 泛型如果明確的寫的時候,前後必須一致
        Collection<Object> c1 = new ArrayList<Object>();
        // 以下爲錯誤示範:
        // Collection<Object> c2 = new ArrayList<Animal>();
        // Collection<Object> c3 = new ArrayList<Dog>();
        // Collection<Object> c4 = new ArrayList<Cat>();

        // ?表示任意的類型都是可以的
        Collection<?> c5 = new ArrayList<Object>();
        Collection<?> c6 = new ArrayList<Animal>();
        Collection<?> c7 = new ArrayList<Dog>();
        Collection<?> c8 = new ArrayList<Cat>();

        // ? extends E:向下限定,E及其子類
        // Collection<? extends Animal> c9 = new ArrayList<Object>();
        Collection<? extends Animal> c10 = new ArrayList<Animal>();
        Collection<? extends Animal> c11 = new ArrayList<Dog>();
        Collection<? extends Animal> c12 = new ArrayList<Cat>();

        // ? super E:向上限定,E極其父類
        Collection<? super Animal> c13 = new ArrayList<Object>();
        Collection<? super Animal> c14 = new ArrayList<Animal>();
        // Collection<? super Animal> c15 = new ArrayList<Dog>();
        // Collection<? super Animal> c16 = new ArrayList<Cat>();
    }
}

class Animal {
}

class Dog extends Animal {
}

class Cat extends Animal {
}

(5)我們在哪裏使用呢?
一般是在集合中使用。

 

3:增強for循環(掌握)

(1)是for循環的一種
(2)格式:
for(元素的數據類型 變量名 : 數組或者Collection集合的對象) {
使用該變量即可,該變量其實就是數組或者集合中的元素。
}
(3)好處:
簡化了數組和集合的遍歷
(4)弊端
增強for循環的目標不能爲null。建議在使用前,先判斷是否爲null。

// 創建集合對象
ArrayList<Student> array = new ArrayList<Student>();

// 創建學生對象
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("貂蟬", 22);
Student s3 = new Student("楊玉環", 24);
Student s4 = new Student("西施", 21);
Student s5 = new Student("王昭君", 23);

// 把學生對象添加到集合中
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);
array.add(s5);

// 迭代器
Iterator<Student> it = array.iterator();
while (it.hasNext()) {
    Student s = it.next();
    System.out.println(s.getName() + "---" + s.getAge());
}
System.out.println("---------------");

// 普通for
for (int x = 0; x < array.size(); x++) {
    Student s = array.get(x);
    System.out.println(s.getName() + "---" + s.getAge());
}
System.out.println("---------------");

// 增強for
for (Student s : array) {
    System.out.println(s.getName() + "---" + s.getAge());
}

 

4:靜態導入(瞭解)

(1)可以導入到方法級別的導入
(2)格式:
import static 包名....類名.方法名;
(3)注意事項:
A:方法必須是靜態
B:如果多個類下有同名的方法,就不好區分了,還得加上前綴
所以一般我們並不使用靜態導入,但是一定要能夠看懂。

import static java.lang.Math.max;
import static java.lang.Math.pow;

/*
 * 靜態導入:
 * 格式:import static 包名….類名.方法名;
 * 可以直接導入到方法的級別
 *
 * 靜態導入的注意事項:
 *        A:方法必須是靜態的
 *        B:如果有多個同名的靜態方法,容易不知道使用誰?這個時候要使用,必須加前綴。由此可見,意義不大,所以一般不用,但是要能看懂。
 */
public class StaticImport {
    public static void main(String[] args) {
        // System.out.println(java.lang.Math.abs(-100));
        // System.out.println(java.lang.Math.pow(2, 3));
        // System.out.println(java.lang.Math.max(20, 30));
        // 太複雜,我們就引入到import

        System.out.println(Math.abs(-100));
        System.out.println(Math.pow(2, 3));
        System.out.println(Math.max(20, 30));
        // 太複雜,有更簡單

//    System.out.println(abs(-100));
        System.out.println(java.lang.Math.abs(-100));
        System.out.println(pow(2, 3));
        System.out.println(max(20, 30));
    }

    public static void abs(String s){
        System.out.println(s);
    }
}

5:可變參數(掌握)

(1)如果我們在寫方法的時候,參數個數不明確,就應該定義可變參數
(2)格式:
修飾符 返回值類型 方法名(數據類型... 變量) {}

注意:
A:該變量其實是一個數組名

B:如果一個方法有多個參數,並且有可變參數,可變參數必須在最後

public static void main(String[] args) {
    // 4個數據的求和
    int d = 30;
    result = sum(a, b, c, d);
    System.out.println("result:" + result);

    // 需求:我要寫一個求和的功能,到底是幾個數據求和呢,我不太清楚,但是我知道在調用的時候我肯定就知道了
    // 爲了解決這個問題,Java就提供了一個東西:可變參數
    result = sum(a, b, c, d, 40);
    System.out.println("result:" + result);

    result = sum(a, b, c, d, 40, 50);
    System.out.println("result:" + result);
}

public static int sum(int... a) {
    int s = 0;

    for(int x : a){
        s +=x;
    }

    return s;
}

(3)Arrays工具類的一個方法
asList()把數組轉成集合。

注意:這個集合的長度不能改變。

List<String> list = Arrays.asList("hello", "world", "java");
        // UnsupportedOperationException 雖然可以把數組轉成集合,但是集合的長度不能改變。
//         list.add("javaee");
        // UnsupportedOperationException
        // list.remove(1);
        list.set(1, "javaee");

        for (String s : list) {
            System.out.println(s);
        }

6:練習(掌握)

A:集合的嵌套遍歷

 *               需求:
 * 我們班有學生,每一個學生是不是一個對象。所以我們可以使用一個集合表示我們班級的學生。ArrayListString<Student>
 * 但是呢,我們旁邊是不是還有班級,每個班級是不是也是一個ArrayList<Student>。
 * 而我現在有多個ArrayList<Student>。也要用集合存儲,怎麼辦呢?

 * 就是這個樣子的:ArrayListString<ArrayListString<Student>>

// 創建大集合
ArrayList<ArrayList<Student>> bigArrayList = new ArrayList<ArrayList<Student>>();

// 創建第一個班級的學生集合
ArrayList<Student> firstArrayList = new ArrayList<Student>();
// 創建學生
Student s1 = new Student("唐僧", 30);
Student s2 = new Student("孫悟空", 29);
Student s3 = new Student("豬八戒", 28);
Student s4 = new Student("沙僧", 27);
Student s5 = new Student("白龍馬", 26);
// 學生進班
firstArrayList.add(s1);
firstArrayList.add(s2);
firstArrayList.add(s3);
firstArrayList.add(s4);
firstArrayList.add(s5);
// 把第一個班級存儲到學生系統中
bigArrayList.add(firstArrayList);

// 創建第二個班級的學生集合
ArrayList<Student> secondArrayList = new ArrayList<Student>();
// 創建學生
Student s11 = new Student("諸葛亮", 30);
Student s22 = new Student("司馬懿", 28);
Student s33 = new Student("周瑜", 26);
// 學生進班
secondArrayList.add(s11);
secondArrayList.add(s22);
secondArrayList.add(s33);
// 把第二個班級存儲到學生系統中
bigArrayList.add(secondArrayList);

// 創建第三個班級的學生集合
ArrayList<Student> thirdArrayList = new ArrayList<Student>();
// 創建學生
Student s111 = new Student("宋江", 40);
Student s222 = new Student("吳用", 35);
Student s333 = new Student("高俅", 30);
Student s444 = new Student("李師師", 22);
// 學生進班
thirdArrayList.add(s111);
thirdArrayList.add(s222);
thirdArrayList.add(s333);
thirdArrayList.add(s444);
// 把第三個班級存儲到學生系統中
bigArrayList.add(thirdArrayList);

// 遍歷集合
for (ArrayList<Student> array : bigArrayList) {
    for (Student s : array) {
        System.out.println(s.getName() + "---" + s.getAge());
    }
}

B:產生10個1-20之間的隨機數,要求隨機數不能重複

// 創建產生隨機數的對象
Random r = new Random();

// 創建一個存儲隨機數的集合。
ArrayList<Integer> array = new ArrayList<Integer>();

// 定義一個統計變量。從0開始。
int count = 0;

// 判斷統計遍歷是否小於10
while (count < 10) {
    //先產生一個隨機數
    int number = r.nextInt(20) + 1;

    //判斷該隨機數在集合中是否存在。
    if(!array.contains(number)){
        //如果不存在:就添加,統計變量++。
        array.add(number);
        count++;
    }
}

//遍歷集合
for(Integer i : array){
    System.out.println(i);
}

C:鍵盤錄入多個數據,以0結束,並在控制檯輸出最大值

 *             鍵盤錄入多個數據,以0結束,要求在控制檯輸出這多個數據中的最大值
 *
 * 分析:
 * A:創建鍵盤錄入數據對象
 * B:鍵盤錄入多個數據,我們不知道多少個,所以用集合存儲
 * C:以0結束,這個簡單,只要鍵盤錄入的數據是0,我就不繼續錄入數據了
 * D:把集合轉成數組
 * E:對數組排序
 * F:獲取該數組中的最大索引的值

public static void main(String[] args) {
    // 創建鍵盤錄入數據對象
    Scanner sc = new Scanner(System.in);

    // 鍵盤錄入多個數據,我們不知道多少個,所以用集合存儲
    ArrayList<Integer> array = new ArrayList<Integer>();

    // 以0結束,這個簡單,只要鍵盤錄入的數據是0,我就不繼續錄入數據了
    while (true) {
        System.out.println("請輸入數據:");
        int number = sc.nextInt();
        if (number != 0) {
            array.add(number);
        } else {
            break;
        }
    }

    // 把集合轉成數組
    // public <T> T[] toArray(T[] a)
    Integer[] i = new Integer[array.size()];
    // Integer[] ii = array.toArray(i);
    array.toArray(i);
    // System.out.println(i);
    // System.out.println(ii);

    // 對數組排序
    // public static void sort(Object[] a)
    Arrays.sort(i);

    // 獲取該數組中的最大索引的值
    System.out.println("數組是:" + arrayToString(i) + "最大值是:"
            + i[i.length - 1]);
}

public static String arrayToString(Integer[] i) {
    StringBuilder sb = new StringBuilder();

    sb.append("[");
    for (int x = 0; x < i.length; x++) {
        if (x == i.length - 1) {
            sb.append(i[x]);
        } else {
            sb.append(i[x]).append(", ");
        }
    }
    sb.append("]");

    return sb.toString();
}

 

7:要掌握的代碼

集合存儲元素,加入泛型,並可以使用增強for遍歷。

 

============================================================================

1:登錄註冊案例(理解)

 

2:Set集合(理解)

(1)Set集合的特點
無序,唯一
(2)HashSet集合(掌握)
A:底層數據結構是哈希表(是一個元素爲鏈表的數組)
B:哈希表底層依賴兩個方法:hashCode()和equals()
  執行順序:
首先比較哈希值是否相同
相同:繼續執行equals()方法
返回true:元素重複了,不添加
返回false:直接把元素添加到集合
不同:就直接把元素添加到集合

C:如何保證元素唯一性的呢?
由hashCode()和equals()保證的
D:開發的時候,代碼非常的簡單,自動生成即可。
E:HashSet存儲字符串並遍歷

// 創建集合對象
        HashSet<String> hs = new HashSet<String>();

        // 創建並添加元素
         hs.add("hello");
        hs.add("world");
        hs.add("java");
        hs.add("world");

        // 遍歷集合
        for (String s : hs) {
            System.out.println(s);
        }
//        world
//        java
//        hello

F:HashSet存儲自定義對象並遍歷(對象的成員變量值相同即爲同一個元素)

// 創建集合對象
        HashSet<Student> hs = new HashSet<Student>();

        // 創建學生對象
        Student s1 = new Student("林青霞", 27);
        Student s2 = new Student("柳巖", 22);
        Student s3 = new Student("王祖賢", 30);
        Student s4 = new Student("林青霞", 27);
        Student s5 = new Student("林青霞", 20);
        Student s6 = new Student("范冰冰", 22);

        // 添加元素
        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);
        hs.add(s5);
        hs.add(s6);

        // 遍歷集合
        for (Student s : hs) {
            System.out.println(s.getName() + "---" + s.getAge());
        }

//        林青霞---20
//        范冰冰---22
//        柳巖---22
//        王祖賢---30
//        林青霞---27

        (3)LinkedHashSet集合

 * LinkedHashSet:底層數據結構由哈希表鏈表組成。
 * 哈希表保證元素的唯一性。
 * 鏈表保證元素有序。(存儲和取出是一致)

// 創建集合對象
        LinkedHashSet<String> hs = new LinkedHashSet<String>();

        // 創建並添加元素
        hs.add("hello");
        hs.add("world");
        hs.add("java");
        hs.add("world");
        hs.add("java");

        // 遍歷
        for (String s : hs) {
            System.out.println(s);
        }

//        hello
//        world
//        java

        (4)TreeSet集合
A:底層數據結構是紅黑樹(是一個自平衡的二叉樹)
B:保證元素的排序方式
a:自然排序(元素具備比較性)
讓元素所屬的類實現Comparable接口 public class Student1 implements Comparable<Student1> {

年齡排序:

@Override
public int compareTo(Student1 s) {
    // 這裏返回什麼,其實應該根據我的排序規則來做
    // 按照年齡排序,主要條件
    int num = this.age - s.age;
    // 次要條件
    // 年齡相同的時候,還得去看姓名是否也相同
    // 如果年齡和姓名都相同,纔是同一個元素
    int num2 = num == 0 ? this.name.compareTo(s.name) : num;
    return num2;
}
        // 創建集合對象
        TreeSet<Student1> ts = new TreeSet<Student1>();

        // 創建元素
        Student1 s1 = new Student1("linqingxia", 27);
        Student1 s2 = new Student1("zhangguorong", 29);
        Student1 s3 = new Student1("wanglihong", 23);
        Student1 s4 = new Student1("linqingxia", 27);
        Student1 s5 = new Student1("liushishi", 22);
        Student1 s6 = new Student1("wuqilong", 40);
        Student1 s7 = new Student1("fengqingy", 22);

        // 添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
        ts.add(s7);

        // 遍歷
        for (Student1 s : ts) {
            System.out.println(s.getName() + "---" + s.getAge());
        }

//        fengqingy---22
//        liushishi---22
//        wanglihong---23
//        linqingxia---27
//        zhangguorong---29
//        wuqilong---40

姓名長度排序:

@Override
public int compareTo(Student2 s) {
    // 主要條件 姓名的長度
    int num = this.name.length() - s.name.length();
    // 姓名的長度相同,不代表姓名的內容相同
    int num2 = num == 0 ? this.name.compareTo(s.name) : num;
    // 姓名的長度和內容相同,不代表年齡相同,所以還得繼續判斷年齡
    int num3 = num2 == 0 ? this.age - s.age : num2;
    return num3;
}

 

// 創建集合對象
        TreeSet<Student2> ts = new TreeSet<Student2>();

        // 創建元素
        Student2 s1 = new Student2("linqingxia", 27);
        Student2 s2 = new Student2("zhangguorong", 29);
        Student2 s3 = new Student2("wanglihong", 23);
        Student2 s4 = new Student2("linqingxia", 27);
        Student2 s5 = new Student2("liushishi", 22);
        Student2 s6 = new Student2("wuqilong", 40);
        Student2 s7 = new Student2("fengqingy", 22);
        Student2 s8 = new Student2("linqingxia", 29);

        // 添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
        ts.add(s7);
        ts.add(s8);

        // 遍歷
        for (Student2 s : ts) {
            System.out.println(s.getName() + "---" + s.getAge());
        }
//        wuqilong---40
//        fengqingy---22
//        liushishi---22
//        linqingxia---27
//        linqingxia---29
//        wanglihong---23
//        zhangguorong---29

b:比較器排序(集合具備比較性)
讓集合構造方法接收Comparator的實現類對象

public class Student3 {
    private String name;
    private int age;

    public Student3() {
        super();
    }

    public Student3(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public class TreeSetMyComparator implements Comparator<Student3> {

    @Override
    public int compare(Student3 s1, Student3 s2) {
        // 姓名長度
        int num = s1.getName().length() - s2.getName().length();
        // 姓名內容
        int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
        // 年齡
        int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
        return num3;
    }
}

 

        // 創建集合對象
        // TreeSet<Student> ts = new TreeSet<Student>(); //自然排序
        // public TreeSet(Comparator comparator) //比較器排序
        // TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());

        // 如果一個方法的參數是接口,那麼真正要的是接口的實現類的對象
        // 而匿名內部類就可以實現這個東西
        TreeSet<Student3> ts = new TreeSet<Student3>(new Comparator<Student3>() {
            @Override
            public int compare(Student3 s1, Student3 s2) {
                // 姓名長度
                int num = s1.getName().length() - s2.getName().length();
                // 姓名內容
                int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
                // 年齡
                int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
                return num3;
            }
        });

        // 創建元素
        Student3 s1 = new Student3("linqingxia", 27);
        Student3 s2 = new Student3("zhangguorong", 29);
        Student3 s3 = new Student3("wanglihong", 23);
        Student3 s4 = new Student3("linqingxia", 27);
        Student3 s5 = new Student3("liushishi", 22);
        Student3 s6 = new Student3("wuqilong", 40);
        Student3 s7 = new Student3("fengqingy", 22);
        Student3 s8 = new Student3("linqingxia", 29);

        // 添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
        ts.add(s7);
        ts.add(s8);

        // 遍歷
        for (Student3 s : ts) {
            System.out.println(s.getName() + "---" + s.getAge());
        }

//        wuqilong---40
//        fengqingy---22
//        liushishi---22
//        linqingxia---27
//        linqingxia---29
//        wanglihong---23
//        zhangguorong---29


C:把我們講過的代碼看一遍即可

(4)案例:
A:獲取無重複的隨機數

/*
 * 編寫一個程序,獲取10個1至20的隨機數,要求隨機數不能重複。
 *
 * 分析:
 *        A:創建隨機數對象
 *        B:創建一個HashSet集合
 *        C:判斷集合的長度是不是小於10
 *           是:就創建一個隨機數添加
 *           否:不搭理它
 *        D:遍歷HashSet集合
 */
public class HashSetTest {
    public static void main(String[] args) {
        // 創建隨機數對象
        Random r = new Random();

        // 創建一個Set集合
        HashSet<Integer> ts = new HashSet<Integer>();

        // 判斷集合的長度是不是小於10
        while (ts.size() < 10) {
            int num = r.nextInt(20) + 1;
            ts.add(num);
        }

        // 遍歷Set集合
        for (Integer i : ts) {
            System.out.println(i);
        }
    }
}


B:鍵盤錄入學生按照總分從高到底輸出

/*
 * 鍵盤錄入5個學生信息(姓名,語文成績,數學成績,英語成績),按照總分從高到低輸出到控制檯
 *
 * 分析:
 *        A:定義學生類
 *        B:創建一個TreeSet集合
 *        C:總分從高到底如何實現呢?
 *        D:鍵盤錄入5個學生信息
 *        E:遍歷TreeSet集合
 */
public class TreeSetTest {
    public static void main(String[] args) {
        // 創建一個TreeSet集合
        TreeSet<Student4> ts = new TreeSet<Student4>(new Comparator<Student4>() {
            @Override
            public int compare(Student4 s1, Student4 s2) {
                // 總分從高到低
                int num = s2.getSum() - s1.getSum();
                // 總分相同的不一定語文相同
                int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
                // 總分相同的不一定數序相同
                int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;
                // 總分相同的不一定英語相同
                int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3;
                // 姓名還不一定相同呢
                int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName())
                        : num4;
                return num5;
            }
        });

        System.out.println("學生信息錄入開始");
        // 鍵盤錄入5個學生信息
        for (int x = 1; x <= 5; x++) {
            Scanner sc = new Scanner(System.in);
            System.out.println("請輸入第" + x + "個學生的姓名:");
            String name = sc.nextLine();
            System.out.println("請輸入第" + x + "個學生的語文成績:");
            String chineseString = sc.nextLine();
            System.out.println("請輸入第" + x + "個學生的數學成績:");
            String mathString = sc.nextLine();
            System.out.println("請輸入第" + x + "個學生的英語成績:");
            String englishString = sc.nextLine();

            // 把數據封裝到學生對象中
            Student4 s = new Student4();
            s.setName(name);
            s.setChinese(Integer.parseInt(chineseString));
            s.setMath(Integer.parseInt(mathString));
            s.setEnglish(Integer.parseInt(englishString));

            // 把學生對象添加到集合
            ts.add(s);
        }
        System.out.println("學生信息錄入完畢");

        System.out.println("學習信息從高到低排序如下:");
        System.out.println("姓名\t語文成績\t數學成績\t英語成績");
        // 遍歷集合
        for (Student4 s : ts) {
            System.out.println(s.getName() + "\t" + s.getChinese() + "\t"
                    + s.getMath() + "\t" + s.getEnglish());
        }
    }
}

 

3:Collection集合總結(掌握)

 

Collection
|--List 有序,可重複
|--ArrayList
底層數據結構是數組,查詢快,增刪慢。
線程不安全,效率高
|--Vector
底層數據結構是數組,查詢快,增刪慢。
線程安全,效率低
|--LinkedList
底層數據結構是鏈表,查詢慢,增刪快。
線程不安全,效率高
|--Set 無序,唯一
|--HashSet
底層數據結構是哈希表。
如何保證元素唯一性的呢?
依賴兩個方法:hashCode()和equals()
開發中自動生成這兩個方法即可
|--LinkedHashSet
底層數據結構是鏈表和哈希表
由鏈表保證元素有序
由哈希表保證元素唯一
|--TreeSet
底層數據結構是紅黑樹。
如何保證元素排序的呢?
自然排序
比較器排序
如何保證元素唯一性的呢?
根據比較的返回值是否是0來決定

4:針對Collection集合我們到底使用誰呢?(掌握)

唯一嗎?
是:Set
排序嗎?
是:TreeSet
否:HashSet
如果你知道是Set,但是不知道是哪個Set,就用HashSet。

否:List
要安全嗎?
是:Vector
否:ArrayList或者LinkedList
查詢多:ArrayList
增刪多:LinkedList
如果你知道是List,但是不知道是哪個List,就用ArrayList。

如果你知道是Collection集合,但是不知道使用誰,就用ArrayList。

如果你知道用集合,就用ArrayList。

5:在集合中常見的數據結構(掌握)

ArrayXxx:底層數據結構是數組,查詢快,增刪慢
LinkedXxx:底層數據結構是鏈表,查詢慢,增刪快
HashXxx:底層數據結構是哈希表。依賴兩個方法:hashCode()和equals()
TreeXxx:底層數據結構是二叉樹。兩種方式排序:自然排序和比較器排序

============================================================================

 

1:Map(掌握)

(1)將鍵映射到值的對象。一個映射不能包含重複的鍵每個鍵最多隻能映射到一個值。 

 *             注意:
 * Map集合的數據結構值針對鍵有效,跟值無關
 * HashMap,TreeMap等會講。
 * Collection集合的數據結構是針對元素有效

(2)Map和Collection的區別?
A:Map 存儲的是鍵值對形式的元素,鍵唯一,值可以重複。夫妻對
B:Collection 存儲的是單獨出現的元素,子接口Set元素唯一,子接口List元素可重複。光棍
(3)Map接口功能概述(自己補齊)
 * 1:添加功能
 * V put(K key,V value):添加元素。這個其實還有另一個功能?先不告訴你,等會講
 * 如果鍵是第一次存儲,就直接存儲元素,返回null
 * 如果鍵不是第一次存在,就用值把以前的值替換掉,返回以前的值

 * 2:刪除功能
 * void clear():移除所有的鍵值對元素
 * V remove(Object key):根據鍵刪除鍵值對元素,並把值返回
 * 3:判斷功能
 * boolean containsKey(Object key):判斷集合是否包含指定的鍵
 * boolean containsValue(Object value):判斷集合是否包含指定的值
 * boolean isEmpty():判斷集合是否爲空
 * 4:獲取功能
 * Set<Map.Entry<K,V>> entrySet():???
 * V get(Object key):根據鍵獲取值
 * Set<K> keySet():獲取集合中所有鍵的集合
 * Collection<V> values():獲取集合中所有值的集合
 * 5:長度功能

 * int size():返回集合中的鍵值對的對數

// 創建集合對象
Map<String, String> map = new HashMap<String, String>();

/**
 * 添加元素。
 * V put(K key,V value)
 * 這個其實還有另一個功能?先不告訴你,等會講
 */
System.out.println("put:" + map.put("文章", "馬伊俐")); // null 如果鍵是第一次存儲,就直接存儲元素,返回null
System.out.println("put:" + map.put("文章", "姚笛")); // 馬伊俐 如果鍵不是第一次存在,就用值把以前的值替換掉,返回以前的值

map.put("鄧超", "孫儷");
map.put("黃曉明", "楊穎");
map.put("周杰倫", "蔡依林");
map.put("劉愷威", "楊冪");

/**
 * 刪除功能
 * void clear():移除所有的鍵值對元素
 */
//map.clear();

/**
 * V remove(Object key)
 * 根據鍵刪除鍵值對元素,並把值返回
 */
//System.out.println("remove:" + map.remove("黃曉明"));
//System.out.println("remove:" + map.remove("黃曉波"));

/**
 * boolean containsKey(Object key)
 * 判斷集合是否包含指定的鍵
 */
 System.out.println("containsKey:" + map.containsKey("黃曉明"));
 System.out.println("containsKey:" + map.containsKey("黃曉波"));

/**
 * boolean containsValue(Object value):判斷集合是否包含指定的值
 */
System.out.println("containsValue:" + map.containsValue("楊1冪"));

/**
 * boolean isEmpty()
 * 判斷集合是否爲空
 */
 System.out.println("isEmpty:"+map.isEmpty());

/**
 * int size()
 * 返回集合中的鍵值對的對數
 */
System.out.println("size:"+map.size());

// 輸出集合名稱
System.out.println("map:" + map);
// 創建集合對象
Map<String, String> map = new HashMap<String, String>();

// 創建元素並添加元素
map.put("鄧超", "孫儷");
map.put("黃曉明", "楊穎");
map.put("周杰倫", "蔡依林");
map.put("劉愷威", "楊冪");

/**
 * V get(Object key)
 * 根據鍵獲取值
 */
System.out.println("get:" + map.get("周杰倫"));
System.out.println("get:" + map.get("周杰")); // 返回null
System.out.println("----------------------");

/**
 * Set<K> keySet()
 * 獲取集合中所有鍵的集合
 */
Set<String> set = map.keySet();
for (String key : set) {
    System.out.println(key);
}
System.out.println("----------------------");

/**
 * Collection<V> values()
 * 獲取集合中所有值的集合
 */
Collection<String> con = map.values();
for (String value : con) {
    System.out.println(value);
}

(4)Map集合的遍歷
A:鍵找值
a:獲取所有鍵的集合
b:遍歷鍵的集合,得到每一個鍵
c:根據鍵到集合中去找值

// 創建集合對象
Map<String, String> map = new HashMap<String, String>();

// 創建元素並添加到集合
map.put("楊過", "小龍女");
map.put("郭靖", "黃蓉");
map.put("楊康", "穆念慈");
map.put("陳玄風", "梅超風");

// 遍歷
// 獲取所有的鍵
Set<String> set = map.keySet();
// 遍歷鍵的集合,獲取得到每一個鍵
for (String key : set) {
    // 根據鍵去找值
    String value = map.get(key);
    System.out.println(key + "---" + value);
}


B:鍵值對對象找鍵和值
a:獲取所有的鍵值對對象的集合
b:遍歷鍵值對對象的集合,獲取每一個鍵值對對象
c:根據鍵值對對象去獲取鍵和值

// 創建集合對象
Map<String, String> map = new HashMap<String, String>();

// 創建元素並添加到集合
map.put("楊過", "小龍女");
map.put("郭靖", "黃蓉");
map.put("楊康", "穆念慈");
map.put("陳玄風", "梅超風");

System.out.println(map); // {陳玄風=梅超風, 楊過=小龍女, 楊康=穆念慈, 郭靖=黃蓉}
// 獲取所有鍵值對對象的集合
Set<Map.Entry<String, String>> set = map.entrySet();

System.out.println(set); // [陳玄風=梅超風, 楊過=小龍女, 楊康=穆念慈, 郭靖=黃蓉]
// 遍歷鍵值對對象的集合,得到每一個鍵值對對象
for (Map.Entry<String, String> me : set) {
    // 根據鍵值對對象獲取鍵和值
    String key = me.getKey();
    String value = me.getValue();
    System.out.println(key + "---" + value);
}


代碼體現:
Map<String,String> hm = new HashMap<String,String>();

hm.put("it002","hello");
hm.put("it003","world");
hm.put("it001","java");

//方式1 鍵找值
Set<String> set = hm.keySet();
for(String key : set) {
String value = hm.get(key);
System.out.println(key+"---"+value);
}

//方式2 鍵值對對象找鍵和值
Set<Map.Entry<String,String>> set2 = hm.entrySet();
for(Map.Entry<String,String> me : set2) {
String key = me.getKey();
String value = me.getValue();
System.out.println(key+"---"+value);
}
(5)HashMap集合的練習

A:HashMap<String,String>

// 創建集合對象
HashMap<String, String> hm = new HashMap<String, String>();

hm.put("it001", "馬雲");
hm.put("it003", "馬化騰");
hm.put("it004", "喬布斯");
hm.put("it005", "張朝陽");
hm.put("it002", "裘伯君"); // wps
hm.put("it001", "比爾蓋茨");

// 遍歷
Set<String> set = hm.keySet();
for (String key : set) {
    String value = hm.get(key);
    System.out.println(key + "---" + value);
}

B:HashMap<Integer,String>

// 創建集合對象
HashMap<Integer, String> hm = new HashMap<Integer, String>();

hm.put(27, "林青霞");
hm.put(30, "風清揚");
hm.put(28, "劉意");
hm.put(29, "林青霞");

// 下面的寫法是八進制,但是不能出現8以上的單個數據
// hm.put(003, "hello");
// hm.put(006, "hello");
// hm.put(007, "hello");
// hm.put(008, "hello");

// 遍歷
Set<Integer> set = hm.keySet();
for (Integer key : set) {
    String value = hm.get(key);
    System.out.println(key + "---" + value);
}

// 下面這種方式僅僅是集合的元素的字符串表示
System.out.println("hm:" + hm); // {27=林青霞, 28=劉意, 29=林青霞, 30=風清揚}

C:HashMap<String,Student>

// 創建集合對象
HashMap<String, Student> hm = new HashMap<String, Student>();

// 創建學生對象
Student s1 = new Student("周星馳", 58);
Student s2 = new Student("劉德華", 55);
Student s3 = new Student("梁朝偉", 54);
Student s4 = new Student("劉嘉玲", 50);

// 添加元素
hm.put("9527", s1);
hm.put("9522", s2);
hm.put("9524", s3);
hm.put("9529", s4);

// 遍歷
Set<String> set = hm.keySet();
for (String key : set) {
    // 注意了:這次值不是字符串了
    // String value = hm.get(key);
    Student value = hm.get(key);
    System.out.println(key + "---" + value.getName() + "---"
            + value.getAge());
}

D:HashMap<Student,String>

// 創建集合對象
HashMap<Student, String> hm = new HashMap<Student, String>();

// 創建學生對象
Student s1 = new Student("貂蟬", 27);
Student s2 = new Student("王昭君", 30);
Student s3 = new Student("西施", 33);
Student s4 = new Student("楊玉環", 35);
Student s5 = new Student("貂蟬", 27);

// 添加元素
hm.put(s1, "8888");
hm.put(s2, "6666");
hm.put(s3, "5555");
hm.put(s4, "7777");
hm.put(s5, "9999");

// 遍歷
Set<Student> set = hm.keySet();
for (Student key : set) {
    String value = hm.get(key);
    System.out.println(key.getName() + "---" + key.getAge() + "---"
            + value);
}

        (6) LinkedHashMap:

                是Map接口的哈希表和鏈接列表實現,具有可預知的迭代順序。

 * 由哈希表保證鍵的唯一性

 * 由鏈表保證鍵盤的有序(存儲和取出的順序一致)

// 創建集合對象
        LinkedHashMap<String, String> hm = new LinkedHashMap<String, String>();

        // 創建並添加元素
        hm.put("2345", "hello");
        hm.put("1234", "world");
        hm.put("3456", "java");
        hm.put("1234", "javaee"); // 代替
        hm.put("3456", "android");

        // 遍歷
        Set<String> set = hm.keySet();
        System.out.println(set);
        for (String key : set) {
            String value = hm.get(key);
            System.out.println(key + "---" + value);
        }
//        2345---hello
//        1234---javaee
//        3456---android


(7TreeMap集合的練習

A:TreeMap<String,String>

// 創建集合對象
        TreeMap<String, String> tm = new TreeMap<String, String>();

        // 創建元素並添加元素
        tm.put("hello", "你好");
        tm.put("world", "世界");
        tm.put("java", "爪哇");
        tm.put("world", "世界2");
        tm.put("javaee", "爪哇EE");

        // 遍歷集合
        Set<String> set = tm.keySet();
        for (String key : set) {
            String value = tm.get(key);
            System.out.println(key + "---" + value);
        }
        // 默認按鍵的升序排序 
//        hello---你好
//        java---爪哇
//        javaee---爪哇EE
//        world---世界2

 

B:TreeMap<Student,String>

// 創建集合對象
        TreeMap<Student1, String> tm = new TreeMap<Student1, String>(
                new Comparator<Student1>() {
                    @Override
                    public int compare(Student1 s1, Student1 s2) {
                        // 主要條件
                        int num = s1.getAge() - s2.getAge();
                        // 次要條件
                        int num2 = num == 0 ? s1.getName().compareTo(
                                s2.getName()) : num;
                        return num2;
                    }
                });

        // 創建學生對象
        Student1 s1 = new Student1("潘安", 30);
        Student1 s2 = new Student1("柳下惠", 35);
        Student1 s3 = new Student1("唐伯虎", 33);
        Student1 s4 = new Student1("燕青", 32);
        Student1 s5 = new Student1("唐伯虎", 33);

        // 存儲元素
        tm.put(s1, "宋朝");
        tm.put(s2, "元朝");
        tm.put(s3, "明朝");
        tm.put(s4, "清朝");
        tm.put(s5, "漢朝");

        // 遍歷
        Set<Student1> set = tm.keySet();
        for (Student1 key : set) {
            String value = tm.get(key);
            System.out.println(key.getName() + "---" + key.getAge() + "---"
                    + value);
        }
//        潘安---30---宋朝
//        燕青---32---清朝
//        唐伯虎---33---漢朝
//        柳下惠---35---元朝


(8)案例

A:統計一個字符串中每個字符出現的次數

/*
 * 需求 :"aababcabcdabcde",獲取字符串中每一個字母出現的次數要求結果:a(5)b(4)c(3)d(2)e(1)
 *
 * 分析:
 *        A:定義一個字符串(可以改進爲鍵盤錄入)
 *        B:定義一個TreeMap集合
 *           鍵:Character
 *           值:Integer
 *        C:把字符串轉換爲字符數組
 *        D:遍歷字符數組,得到每一個字符
 *        E:拿剛纔得到的字符作爲鍵到集合中去找值,看返回值
 *           是null:說明該鍵不存在,就把該字符作爲鍵,1作爲值存儲
 *           不是null:說明該鍵存在,就把值加1,然後重寫存儲該鍵和值
 *        F:定義字符串緩衝區變量
 *        G:遍歷集合,得到鍵和值,進行按照要求拼接
 *        H:把字符串緩衝區轉換爲字符串輸出
 *
 * 錄入:linqingxia
 * 結果:result:a(1)g(1)i(3)l(1)n(2)q(1)x(1)
 */
public class TreeMap3TestCharCount {
    public static void main(String[] args) {
        // 定義一個字符串(可以改進爲鍵盤錄入)
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入一個字符串:");
        String line = sc.nextLine();

        // 定義一個TreeMap集合
        TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();

        //把字符串轉換爲字符數組
        char[] chs = line.toCharArray();

        //遍歷字符數組,得到每一個字符
        for(char ch : chs){
            //拿剛纔得到的字符作爲鍵到集合中去找值,看返回值
            Integer i =  tm.get(ch);

            //是null:說明該鍵不存在,就把該字符作爲鍵,1作爲值存儲
            if(i == null){
                tm.put(ch, 1);
            }else {
                //不是null:說明該鍵存在,就把值加1,然後重寫存儲該鍵和值
                i++;
                tm.put(ch,i);
            }
        }

        //定義字符串緩衝區變量
        StringBuilder sb=  new StringBuilder();

        //遍歷集合,得到鍵和值,進行按照要求拼接
        Set<Character> set = tm.keySet();
        for(Character key : set){
            Integer value = tm.get(key);
            sb.append(key).append("(").append(value).append(")");
        }

        //把字符串緩衝區轉換爲字符串輸出
        String result = sb.toString();
        System.out.println("result:"+result);
//        aababcabcdabcde
//        result:a(5)b(4)c(3)d(2)e(1)
    }
}

B:集合的嵌套遍歷

a:HashMap嵌套HashMap

/*
 * HashMap嵌套HashMap
 *
 *        a班
 *                小紅  20
 *                小綠  22
 *
 *        b班
 *                小藍   21
 *             小紫  23
 * 先存儲元素,然後遍歷元素
 */
public class NestHashMapInHashMap {
    public static void main(String[] args) {
        // 創建集合對象
        HashMap<String, HashMap<String, Integer>> czbkMap = new HashMap<String, HashMap<String, Integer>>();

        // 創建a班集合對象
        HashMap<String, Integer> aMap = new HashMap<String, Integer>();
        // 添加元素
        aMap.put("小紅", 20);
        aMap.put("小綠", 22);
        // 把a班添加到大集合
        czbkMap.put("a", aMap);

        // 創建b班集合對象
        HashMap<String, Integer> bMap = new HashMap<String, Integer>();
        // 添加元素
        bMap.put("小藍", 21);
        bMap.put("小紫", 23);
        // 把b班添加到大集合
        czbkMap.put("b", bMap);

        //遍歷集合
        System.out.println(czbkMap); // {a={小紅=20, 小綠=22}, b={小藍=21, 小紫=23}}
        Set<String> czbkMapSet = czbkMap.keySet();
        System.out.println(czbkMapSet); // [a, b]

        for(String czbkMapKey : czbkMapSet){
            System.out.println(czbkMapKey);
            HashMap<String, Integer> czbkMapValue = czbkMap.get(czbkMapKey);
            Set<String> czbkMapValueSet = czbkMapValue.keySet();
            for(String czbkMapValueKey : czbkMapValueSet){
                Integer czbkMapValueValue = czbkMapValue.get(czbkMapValueKey);
                System.out.println("\t"+czbkMapValueKey+"---"+czbkMapValueValue);
            }
        }
    }
}

b:HashMap嵌套ArrayList

/*
 *需求:
 *假設HashMap集合的元素是ArrayList。有3個。
 *每一個ArrayList集合的值是字符串。
 *元素我已經完成,請遍歷。
 *結果:
 *     三國演義
 *       呂布
 *       周瑜
 *     笑傲江湖
 *       令狐沖
 *       林平之
 *     神鵰俠侶
 *       郭靖
 *       楊過
 */
public class NestHashMapInArrayList {
    public static void main(String[] args) {
        // 創建集合對象
        HashMap<String, ArrayList<String>> hm = new HashMap<String, ArrayList<String>>();

        // 創建元素集合1
        ArrayList<String> array1 = new ArrayList<String>();
        array1.add("呂布");
        array1.add("周瑜");
        hm.put("三國演義", array1);

        // 創建元素集合2
        ArrayList<String> array2 = new ArrayList<String>();
        array2.add("令狐沖");
        array2.add("林平之");
        hm.put("笑傲江湖", array2);

        // 創建元素集合3
        ArrayList<String> array3 = new ArrayList<String>();
        array3.add("郭靖");
        array3.add("楊過");
        hm.put("神鵰俠侶", array3);

        //遍歷集合
        Set<String> set = hm.keySet();
        for(String key : set){
            System.out.println(key);
            ArrayList<String> value = hm.get(key);
            for(String s : value){
                System.out.println("\t"+s);
            }
        }
    }
}

c:ArrayList嵌套HashMap

/*
 ArrayList集合嵌套HashMap集合並遍歷。
 需求:
 假設ArrayList集合的元素是HashMap。有3個。
 每一個HashMap集合的鍵和值都是字符串。
 元素我已經完成,請遍歷。
 結果:
 周瑜---小喬
 呂布---貂蟬

 郭靖---黃蓉
 楊過---小龍女

 令狐沖---任盈盈
 林平之---嶽靈珊
 */
public class NestHashMapInArrayList {
    public static void main(String[] args) {
        // 創建集合對象
        ArrayList<HashMap<String, String>> array = new ArrayList<HashMap<String, String>>();

        // 創建元素1
        HashMap<String, String> hm1 = new HashMap<String, String>();
        hm1.put("周瑜", "小喬");
        hm1.put("呂布", "貂蟬");
        // 把元素添加到array裏面
        array.add(hm1);

        // 創建元素1
        HashMap<String, String> hm2 = new HashMap<String, String>();
        hm2.put("郭靖", "黃蓉");
        hm2.put("楊過", "小龍女");
        // 把元素添加到array裏面
        array.add(hm2);

        // 創建元素1
        HashMap<String, String> hm3 = new HashMap<String, String>();
        hm3.put("令狐沖", "任盈盈");
        hm3.put("林平之", "嶽靈珊");
        // 把元素添加到array裏面
        array.add(hm3);

        // 遍歷
        for (HashMap<String, String> hm : array) {
            Set<String> set = hm.keySet();
            for (String key : set) {
                String value = hm.get(key);
                System.out.println(key + "---" + value);
            }
        }
    }
}

d:多層嵌套

// 創建大集合
HashMap<String, HashMap<String, ArrayList<Student>>> czbkMap = new HashMap<String, HashMap<String, ArrayList<Student>>>();

// 北京數據
HashMap<String, ArrayList<Student>> bjCzbkMap = new HashMap<String, ArrayList<Student>>();
ArrayList<Student> array1 = new ArrayList<Student>();
Student s1 = new Student("林xx", 27);
Student s2 = new Student("風xx", 30);
array1.add(s1);
array1.add(s2);
ArrayList<Student> array2 = new ArrayList<Student>();
Student s3 = new Student("趙xx", 28);
Student s4 = new Student("武xx", 29);
array2.add(s3);
array2.add(s4);
bjCzbkMap.put("A班", array1);
bjCzbkMap.put("B班", array2);
czbkMap.put("BJ", bjCzbkMap);

// 西安校區數據
HashMap<String, ArrayList<Student>> xaCzbkMap = new HashMap<String, ArrayList<Student>>();
ArrayList<Student> array3 = new ArrayList<Student>();
Student s5 = new Student("範xx", 27);
Student s6 = new Student("劉xx", 30);
array3.add(s5);
array3.add(s6);
ArrayList<Student> array4 = new ArrayList<Student>();
Student s7 = new Student("李xx", 28);
Student s8 = new Student("張xx", 29);
array4.add(s7);
array4.add(s8);
xaCzbkMap.put("A班", array3);
xaCzbkMap.put("B班", array4);
czbkMap.put("XA", xaCzbkMap);

// 遍歷集合
Set<String> czbkMapSet = czbkMap.keySet();
for (String czbkMapKey : czbkMapSet) {
    System.out.println(czbkMapKey);
    HashMap<String, ArrayList<Student>> czbkMapValue = czbkMap
            .get(czbkMapKey);
    Set<String> czbkMapValueSet = czbkMapValue.keySet();
    for (String czbkMapValueKey : czbkMapValueSet) {
        System.out.println("\t" + czbkMapValueKey);
        ArrayList<Student> czbkMapValueValue = czbkMapValue
                .get(czbkMapValueKey);
        for (Student s : czbkMapValueValue) {
            System.out.println("\t\t" + s.getName() + "---"
                    + s.getAge());
        }
    }
}

 

2:Collections(理解)

(1)是針對集合進行操作的工具類
(2)面試題:Collection和Collections的區別
A:Collection 是單列集合的頂層接口,有兩個子接口List和Set
B:Collections 是針對集合進行操作的工具類,可以對集合進行排序和查找等

(3)常見的幾個小方法:
 * public static <T> void sort(List<T> list)                            排序 默認情況下是自然順序。
 * public static <T> int binarySearch(List<?> list,T key)       二分查找
 * public static <T> T max(Collection<?> coll)                     最大值
 * public static void reverse(List<?> list)                               反轉

* public static void shuffle(List<?> list)                                隨機置換

// 創建集合對象
List<Integer> list = new ArrayList<Integer>();

// 添加元素
list.add(30);
list.add(20);
list.add(50);
list.add(10);
list.add(40);

System.out.println("list:" + list); // [30, 20, 50, 10, 40]

/**
 * public static <T> void sort(List<T> list)
 * 排序 默認情況下是自然順序。
 */
 Collections.sort(list);
 System.out.println("list:" + list); // [10, 20, 30, 40, 50]

/**
 * public static <T> int binarySearch(List<?> list,T key)
 * 二分查找
 */
 System.out.println("binarySearch:" + Collections.binarySearch(list, 30)); // 2
 System.out.println("binarySearch:" + Collections.binarySearch(list, 300)); // -6

/**
 * public static <T> T max(Collection<?> coll)
 * 最大值
 */
 System.out.println("max:"+Collections.max(list)); // 50

/**
 * public static void reverse(List<?> list)
 * 反轉
 */
 Collections.reverse(list);
 System.out.println("list:" + list); // [50, 40, 30, 20, 10]

/**
 * public static void shuffle(List<?> list)
 * 隨機置換
 */
Collections.shuffle(list);
System.out.println("list:" + list); // [50, 40, 30, 20, 10]

(4)案例 

A:ArrayList集合存儲自定義對象的排序

// 創建集合對象
        List<Student> list = new ArrayList<Student>();

        // 創建學生對象
         Student s1 = new Student("林青霞", 27);
        Student s2 = new Student("風清揚", 30);
        Student s3 = new Student("劉曉曲", 28);
        Student s4 = new Student("武鑫", 29);
        Student s5 = new Student("林青霞", 27);

        // 添加元素對象
         list.add(s1);
        list.add(s2);
        list.add(s3);
        list.add(s4);
        list.add(s5);

        // 排序
         // 自然排序
         // Collections.sort(list);
        // 比較器排序
         // 如果同時有自然排序和比較器排序,以比較器排序爲主
        Collections.sort(list, new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num = s2.getAge() - s1.getAge();
                int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
                        : num;
                return num2;
            }
        });

        // 遍歷集合
        for (Student s : list) {
            System.out.println(s.getName() + "---" + s.getAge());
        }
//        風清揚---30
//        武鑫---29
//        劉曉曲---28
//        林青霞---27
//        林青霞---27

B:模擬鬥地主洗牌和發牌

/*
 * 模擬鬥地主洗牌和發牌
 *
 * 分析:
 *        A:創建一個牌盒
 *        B:裝牌
 *        C:洗牌
 *        D:發牌
 *        E:看牌
 */
public class Collections3PokerGameTest {
    public static void main(String[] args) {
        // 創建一個牌盒
        ArrayList<String> array = new ArrayList<String>();

        // 裝牌
        // 黑桃A,黑桃2,黑桃3,...黑桃K
        // 紅桃A,...
        // 梅花A,...
        // 方塊A,...
        // 定義一個花色數組
        String[] colors = { "♠", "♥", "♣", "♦" };
        // 定義一個點數數組
        String[] numbers = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                "J", "Q", "K" };
        // 裝牌
        for (String color : colors) {
            for (String number : numbers) {
                array.add(color.concat(number));
            }
        }
        array.add("小王");
        array.add("大王");

        // 洗牌
        Collections.shuffle(array);

        // System.out.println("array:" + array);

        // 發牌
        ArrayList<String> fengQingYang = new ArrayList<String>();
        ArrayList<String> linQingXia = new ArrayList<String>();
        ArrayList<String> liuYi = new ArrayList<String>();
        ArrayList<String> diPai = new ArrayList<String>();

        for (int x = 0; x < array.size(); x++) {
            if (x >= array.size() - 3) {
                diPai.add(array.get(x));
            } else if (x % 3 == 0) {
                fengQingYang.add(array.get(x));
            } else if (x % 3 == 1) {
                linQingXia.add(array.get(x));
            } else if (x % 3 == 2) {
                liuYi.add(array.get(x));
            }
        }

        // 看牌
        lookPoker("風清揚", fengQingYang);
        lookPoker("林青霞", linQingXia);
        lookPoker("劉意", liuYi);

        lookPoker("底牌", diPai);
    }

    public static void lookPoker(String name, ArrayList<String> array) {
        System.out.print(name + "的牌是:");
        for (String s : array) {
            System.out.print(s + " ");
        }
        System.out.println();
    }
}

C:模擬鬥地主洗牌和發牌並對牌進行排序

/*
 * 思路:
 *        A:創建一個HashMap集合
 *        B:創建一個ArrayList集合
 *        C:創建花色數組和點數數組
 *        D:從0開始往HashMap裏面存儲編號,並存儲對應的牌
 *        同時往ArrayList裏面存儲編號即可。
 *      E:洗牌(洗的是編號)
 *      F:發牌(發的也是編號,爲了保證編號是排序的,就創建TreeSet集合接收)
 *      G:看牌(遍歷TreeSet集合,獲取編號,到HashMap集合找對應的牌)
 */
public class Collections3PokerGameTest1 {
    public static void main(String[] args) {
        // 創建一個HashMap集合
        HashMap<Integer, String> hm = new HashMap<Integer, String>();

        // 創建一個ArrayList集合
        ArrayList<Integer> array = new ArrayList<Integer>();

        // 創建花色數組和點數數組
        // 定義一個花色數組
        String[] colors = { "♠", "♥", "♣", "♦" };
        // 定義一個點數數組
        String[] numbers = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q",
                "K", "A", "2", };

        // 從0開始往HashMap裏面存儲編號,並存儲對應的牌,同時往ArrayList裏面存儲編號即可。
        int index = 0;

        for (String number : numbers) {
            for (String color : colors) {
                String poker = color.concat(number);
                hm.put(index, poker);
                array.add(index);
                index++;
            }
        }
        hm.put(index, "小王");
        array.add(index);
        index++;
        hm.put(index, "大王");
        array.add(index);

        // 洗牌(洗的是編號)
        Collections.shuffle(array);

        // 發牌(發的也是編號,爲了保證編號是排序的,就創建TreeSet集合接收)
        TreeSet<Integer> fengQingYang = new TreeSet<Integer>();
        TreeSet<Integer> linQingXia = new TreeSet<Integer>();
        TreeSet<Integer> liuYi = new TreeSet<Integer>();
        TreeSet<Integer> diPai = new TreeSet<Integer>();

        for (int x = 0; x < array.size(); x++) {
            if (x >= array.size() - 3) {
                diPai.add(array.get(x));
            } else if (x % 3 == 0) {
                fengQingYang.add(array.get(x));
            } else if (x % 3 == 1) {
                linQingXia.add(array.get(x));
            } else if (x % 3 == 2) {
                liuYi.add(array.get(x));
            }
        }

        // 看牌(遍歷TreeSet集合,獲取編號,到HashMap集合找對應的牌)
        lookPoker("風清揚", fengQingYang, hm);
        lookPoker("林青霞", linQingXia, hm);
        lookPoker("劉意", liuYi, hm);
        lookPoker("底牌", diPai, hm);
    }

    // 寫看牌的功能
    public static void lookPoker(String name, TreeSet<Integer> ts,
                                 HashMap<Integer, String> hm) {
        System.out.print(name + "的牌是:");
        for (Integer key : ts) {
            String value = hm.get(key);
            System.out.print(value + " ");
        }
        System.out.println();
    }
}

============================================================================

1:異常(理解)

(1)程序出現的不正常的情況。
(2)異常的體系
Throwable
|--Error 嚴重問題,我們不處理。
|--Exception
|--RuntimeException 運行期異常,我們需要修正代碼
|--非RuntimeException    編譯期異常,必須處理的,否則程序編譯不通過
(3)異常的處理:
A:JVM的默認處理
把異常的名稱,原因,位置等信息輸出在控制檯,但是呢程序不能繼續執行了。
B:自己處理
a:try...catch...finally
自己編寫處理代碼,後面的程序可以繼續執行
b:throws
把自己處理不了的,在方法上聲明,告訴調用者,這裏有問題
(4)面試題
A:編譯期異常和運行期異常的區別?
編譯期異常 必須要處理的,否則編譯不通過
運行期異常 可以不處理,也可以處理
B:throw和throws是的區別
throw:
在方法體中,後面跟的是異常對象名,並且只能是一個
throw拋出的是一個異常對象,說明這裏肯定有一個異常產生了
throws:
在方法聲明上,後面跟的是異常的類名,可以是多個
throws是聲明方法有異常,是一種可能性,這個異常並不一定會產生
(5)finally關鍵字及其面試題
A:finally用於釋放資源,它的代碼永遠會執行。特殊情況:在執行到finally之前jvm退出了
B:面試題
a:final,finally,finalize的區別?
b:如果在catch裏面有return,請問finally還執行嗎?如果執行,在return前還是後
會,前。

實際上在中間。這個上課我們講過
C:異常處理的變形
try...catch...finally
try...catch...
try...catch...catch...
try...catch...catch...fianlly
try...finally
(6)自定義異常
繼承自Exception或者RuntimeException,只需要提供無參構造和一個帶參構造即可
(7)異常的注意實現
A:父的方法有異常拋出,子的重寫方法在拋出異常的時候必須要小於等於父的異常 
B:父的方法沒有異常拋出,子的重寫方法不能有異常拋出
C:父的方法拋出多個異常,子的重寫方法必須比父少或者小

 

2:File(掌握)

(1)IO流操作中大部分都是對文件的操作,所以Java就提供了File類供我們來操作文件

                File:文件和目錄(文件夾)路徑名的抽象表示形式

(2)構造方法

 * File(String pathname):根據一個路徑得到File對象
 * File(String parent, String child):根據一個目錄和一個子文件/目錄得到File對象
 * File(File parent, String child):根據一個父File對象和一個子文件/目錄得到File對象

/**
 * File(String pathname)
 * 根據一個路徑得到File對象
 */
// 把e:\\demo\\a.txt封裝成一個File對象
File file = new File("D:\\demo\\a.txt");
System.out.println(file); // D:\demo\a.txt

/**
 * File(String parent, String child)
 * 根據一個目錄和一個子文件/目錄得到File對象
 */
File file2 = new File("D:\\demo", "a.txt");
System.out.println(file2); // D:\demo\a.txt

/**
 * File(File parent, String child)
 * 根據一個父File對象和一個子文件/目錄得到File對象
 */
File file3 = new File("d:\\demo");
System.out.println(file3); // d:\demo

File file4 = new File(file3, "a.txt");
System.out.println(file4); // d:\demo\a.txt

// 以上三種方式其實效果一樣

A:File file = new File("e:\\demo\\a.txt");
B:File file = new File("e:\\demo","a.txt");
C:File file = new File("e:\\demo");
  File file2 = new File(file,"a.txt");
(3)File類的功能
A:創建功能

 *public boolean createNewFile()              創建文件 如果存在這樣的文件,就不創建了
 *public boolean mkdir()                           創建文件夾 如果存在這樣的文件夾,就不創建了
 *public boolean mkdirs()                          創建文件夾,如果父文件夾不存在,會幫你創建出來

        /**
         * public boolean mkdir()
         * 創建文件夾 如果存在這樣的文件夾,就不創建了
         */
        // 需求:我要在e盤目錄下創建一個文件夾demo
        File file = new File("e:\\demo");
        System.out.println("mkdir:" + file.mkdir());

        /**
         * public boolean createNewFile()
         * 創建文件 如果存在這樣的文件,就不創建了
         */
        // 需求:我要在e盤目錄demo下創建一個文件a.txt
        File file2 = new File("e:\\demo\\a.txt");
        System.out.println("createNewFile:" + file2.createNewFile());

        /**
         * public boolean mkdirs()
         * 創建文件夾,如果父文件夾不存在,會幫你創建出來
         */
        // 需求:我要在e盤目錄test下創建aaa目錄
        File file4 = new File("e:\\aaa\\bbb\\ccc\\ddd");
        System.out.println("mkdir:" + file4.mkdirs());

        // 需求:我要在e盤目錄test下創建一個文件b.txt
        // Exception in thread "main" java.io.IOException: 系統找不到指定的路徑。
        // 注意:要想在某個目錄下創建內容,該目錄首先必須存在。
//         File file3 = new File("e:\\test\\b.txt");
//         System.out.println("createNewFile:" + file3.createNewFile());


B:刪除功能

 *   public boolean delete()
 *
 * 注意:
 * A:如果你創建文件或者文件夾忘了寫盤符路徑,那麼,默認在項目路徑下。
 * B:Java中的刪除不走回收站。
 * C:要刪除一個文件夾,請注意該文件夾內不能包含文件或者文件夾

/ 創建文件
// File file = new File("e:\\a.txt");
// System.out.println("createNewFile:" + file.createNewFile());

// 我不小心寫成這個樣子了
File file = new File("a.txt");
System.out.println("createNewFile:" + file.createNewFile());

// 繼續玩幾個
File file2 = new File("aaa\\bbb\\ccc");
System.out.println("mkdirs:" + file2.mkdirs());

File file6 = new File("aaa\\bbb\\ccc");
File file7 = new File("aaa\\bbb");
File file8 = new File("aaa");
System.out.println("delete:" + file6.delete());
System.out.println("delete:" + file7.delete());
System.out.println("delete:" + file8.delete());


C:重命名功能

 *       public boolean renameTo(File dest)
 *         如果路徑名相同,就是改名。
 *         如果路徑名不同,就是改名並剪切。
 *
 * 路徑以盤符開始:絕對路徑   c:\\a.txt
 * 路徑不以盤符開始:相對路徑   a.txt

// 創建一個文件對象
//         File file = new File("林青霞.jpg");
//         System.out.println("create:" + file.createNewFile());
        // // 需求:我要修改這個文件的名稱爲"東方不敗.jpg"
//         File newFile = new File("東方不敗.jpg");
//         System.out.println("renameTo:" + file.renameTo(newFile));

        File file2 = new File("東方不敗.jpg");
        File newFile2 = new File("e:\\林青霞.jpg");
        System.out.println("renameTo:" + file2.renameTo(newFile2));


D:判斷功能

 * public boolean isDirectory()       判斷是否是目錄
 * public boolean isFile()                 判斷是否是文件
 * public boolean exists()                判斷是否存在
 * public boolean canRead()           判斷是否可讀
 * public boolean canWrite()          判斷是否可寫
 * public boolean isHidden()          判斷是否隱藏

// 創建文件對象
File file = new File("a.txt");
File file1 = new File("a.jpg");
System.out.println(file1.createNewFile());

System.out.println("isDirectory:" + file.isDirectory());// false
System.out.println("isFile:" + file.isFile());// true
System.out.println("exists:" + file.exists());// true
System.out.println("canRead:" + file.canRead());// true
System.out.println("canWrite:" + file.canWrite());// true
System.out.println("isHidden:" + file.isHidden());// false

System.out.println("isDirectory:" + file1.isDirectory());// false
System.out.println("isFile:" + file1.isFile());// true
System.out.println("exists:" + file1.exists());// true
System.out.println("canRead:" + file1.canRead());// true
System.out.println("canWrite:" + file1.canWrite());// true
System.out.println("isHidden:" + file1.isHidden());// false


E:獲取功能

 * public String getAbsolutePath()         獲取絕對路徑
 * public String getPath()                        獲取相對路徑
 * public String getName()                     獲取名稱
 * public long length()                            獲取長度。字節數
 * public long lastModified()                  獲取最後一次的修改時間,毫秒值 1529030658301

// 創建文件對象
File file = new File("test.txt");
System.out.println("create:" + file.createNewFile());

System.out.println("getAbsolutePath:" + file.getAbsolutePath()); // D:\workspace\shiki\demo\test.txt
System.out.println("getPath:" + file.getPath()); // demo\test.txt
System.out.println("getName:" + file.getName()); // test.txt
System.out.println("length:" + file.length()); // aa啊  4
System.out.println("lastModified:" + file.lastModified()); // 1529030902787

// 1529030658301
Date d = new Date(1529030658301L);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = sdf.format(d);
System.out.println(s);

 

F:高級獲取功能

 * public String[] list()           獲取指定目錄下的所有文件或者文件夾的名稱數組
 * public File[] listFiles()        獲取指定目錄下的所有文件或者文件夾的File數組

        // 指定一個目錄
        File file = new File("D:\\workspace\\shiki");

        /**
         * public String[] list()
         * 獲取指定目錄下的所有文件或者文件夾的名稱數組
         */
        String[] strArray = file.list();
        for (String s : strArray) {
            System.out.println(s);
        }
//        .idea
//        common-base-platform
//        controller-platform
//        pom.xml
//        shiki.iml
//        test.txt
        System.out.println("------------");
        
        /**
         * public File[] listFiles()
         * 獲取指定目錄下的所有文件或者文件夾的File數組
         */
        //
        File[] fileArray = file.listFiles();
        for (File f : fileArray) {
            System.out.println(f);
        }
//        D:\workspace\shiki\.idea
//        D:\workspace\shiki\common-base-platform
//        D:\workspace\shiki\controller-platform
//        D:\workspace\shiki\pom.xml
//        D:\workspace\shiki\shiki.iml
//        D:\workspace\shiki\test.txt


G:過濾器功能

// 封裝e判斷目錄
File file = new File("e:\\");

// 獲取該目錄下所有文件或者文件夾的File數組
File[] fileArray = file.listFiles();

// 遍歷該File數組,得到每一個File對象,然後判斷
for (File f : fileArray) {
    // 是否是文件
    if (f.isFile()) {
        // 繼續判斷是否以.jpg結尾
        if (f.getName().endsWith(".jpg")) {
            // 就輸出該文件名稱
            System.out.println(f.getName());
        }
    }
}
// 封裝e判斷目錄
File file = new File("e:\\");

// 獲取該目錄下所有文件或者文件夾的String數組
// public String[] list(FilenameFilter filter)
String[] strArray = file.list(new FilenameFilter() {
    @Override
    public boolean accept(File dir, String name) {
        // return false;
        // return true;
        // 通過這個測試,我們就知道了,到底把這個文件或者文件夾的名稱加不加到數組中,取決於這裏的返回值是true還是false
        // 所以,這個的true或者false應該是我們通過某種判斷得到的
        return new File(dir, name).isFile() && name.endsWith(".jpg");
    }
});

// 遍歷
for (String s : strArray) {
    System.out.println(s);
}


(4)案例:
A:輸出指定目錄下指定後綴名的文件名稱
a:先獲取所有的,在遍歷的時候判斷,再輸出
b:先判斷,再獲取,最後直接遍歷輸出即可
B:批量修改文件名稱

============================================================================

1:遞歸(理解)

(1)方法定義中調用方法本身的現象
舉例:老和尚給小和尚講故事,我們學編程
(2)遞歸的注意事項;
A:要有出口,否則就是死遞歸
B:次數不能過多,否則內存溢出
C:構造方法不能遞歸使用
(3)遞歸的案例:
A:遞歸求階乘
B:兔子問題
C:遞歸輸出指定目錄下所有指定後綴名的文件絕對路徑
D:遞歸刪除帶內容的目錄(小心使用)

 

2:IO流(掌握)

(1)IO用於在設備間進行數據傳輸的操作
(2)分類:
 * IO流的分類:
 * 流向:
 * 輸入流 讀取數據
 * 輸出流   寫出數據
 * 數據類型:
 * 字節流
 * 字節輸入流 讀取數據     InputStream
 * 字節輸出流 寫出數據     OutputStream
 * 字符流
 * 字符輸入流 讀取數據     Reader
 * 字符輸出流 寫出數據     Writer
 *
 * 注意:一般我們在探討IO流的時候,如果沒有明確說明按哪種分類來說,默認情況下是按照數據類型來分的。
 *
 * 需求:我要往一個文本文件中輸入一句話:"hello,io"
 *
 * 分析:
 * A:這個操作最好是採用字符流來做,但是呢,字符流是在字節流之後纔出現的,所以,今天我先講解字節流如何操作。
 * B:由於我是要往文件中寫一句話,所以我們要採用字節輸出流。
 *
 * 通過上面的分析後我們知道要使用:OutputStream
 * 但是通過查看API,我們發現該流對象是一個抽象類,不能實例化。
 * 所以,我們要找一個具體的子類。
 * 而我們要找的子類是什麼名字的呢?這個時候,很簡單,我們回想一下,我們是不是要往文件中寫東西。
 * 文件是哪個單詞:File
 * 然後用的是字節輸出流,聯起來就是:FileOutputStream
 * 注意:每種基類的子類都是以父類名作爲後綴名。
 * XxxOutputStream
 * XxxInputStream
 * XxxReader
 * XxxWriter
 * 查看FileOutputStream的構造方法:
 * FileOutputStream(File file)
 * FileOutputStream(String name)
 *
 * 字節輸出流操作步驟:
 * A:創建字節輸出流對象
 * B:寫數據
 * C:釋放資源


(3)FileOutputStream寫出數據
A:操作步驟
a:創建字節輸出流對象

                                FileOutputStream fos = new FileOutputStream("fos.txt");
b:調用write()方法

                                fos.write("hello".getBytes());

                             * public void write(int b):寫一個字節
                             * public void write(byte[] b):寫一個字節數組
                             * public void write(byte[] b,int off,int len):寫一個字節數組的一部分
c:釋放資源
        fos.close();
B:代碼體現:

// 創建字節輸出流對象
      FileOutputStream fos = new FileOutputStream("fos.txt");

/*
 * 創建字節輸出流對象了做了幾件事情:
 * A:調用系統功能去創建文件
 * B:創建fos對象
 * C:把fos對象指向這個文件
 */

      //寫數據
      fos.write("hello,IO".getBytes());
      fos.write("java".getBytes());

      //釋放資源
      //關閉此文件輸出流並釋放與此流有關的所有系統資源。
      fos.close();
/*
 * 爲什麼一定要close()呢?
 * A:讓流對象變成垃圾,這樣就可以被垃圾回收器回收了
 * B:通知系統去釋放跟該文件相關的資源
 */
      //java.io.IOException: Stream Closed
      //fos.write("java".getBytes());		

C:要注意的問題?
a:創建字節輸出流對象做了幾件事情?
b:爲什麼要close()?

                                       * A:讓流對象變成垃圾,這樣就可以被垃圾回收器回收了
                                       * B:通知系統去釋放跟該文件相關的資源

c:如何實現數據的換行?

                             * windows:\r\n
                             * linux:\n
                             * Mac:\r

// 寫數據
for (int x = 0; x < 10; x++) {
    fos.write(("hello" + x).getBytes());
    fos.write("\r\n".getBytes());
}

d:如何實現數據的追加寫入?

                                 * 用構造方法帶第二個參數true的情況即可

// 創建字節輸出流對象
// FileOutputStream fos = new FileOutputStream("fos3.txt");
// 創建一個向具有指定 name 的文件中寫入數據的輸出文件流。如果第二個參數爲 true,則將字節寫入文件末尾處,而不是寫入文件開始處。
FileOutputStream fos = new FileOutputStream("fos3.txt", true);

// 寫數據
for (int x = 0; x < 10; x++) {
    fos.write(("hello" + x).getBytes());
    fos.write("\r\n".getBytes());
}

// 釋放資源
fos.close();

加了異常:

// 爲了在finally裏面能夠看到該對象就必須定義到外面,爲了訪問不出問題,還必須給初始化值
FileOutputStream fos = null;
try {
    // fos = new FileOutputStream("z:\\fos4.txt");
    fos = new FileOutputStream("fos4.txt");
    fos.write("java".getBytes());
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    // 如果fos不是null,才需要close()
    if (fos != null) {
        // 爲了保證close()一定會執行,就放到這裏了
        try {
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

(4)FileInputStream讀取數據
A:操作步驟
a:創建字節輸入流對象
b:調用read()方法

                                    * A:int read():一次讀取一個字節
                                    * B:int read(byte[] b):一次讀取一個字節數組
c:釋放資源

                         
B:代碼體現:
FileInputStream fis = new FileInputStream("fos.txt");

//方式1
int by = 0;
while((by=fis.read())!=-1) {
System.out.print((char)by);
}

// FileInputStream(String name)
// FileInputStream fis = new FileInputStream("fis.txt");
FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java");

// 最終版代碼
int by = 0;
// 讀取,賦值,判斷
while ((by = fis.read()) != -1) {
    System.out.print((char) by);
}

// 釋放資源
fis.close();

//方式2
byte[] bys = new byte[1024];
int len = 0;
while((len=fis.read(bys))!=-1) {
System.out.print(new String(bys,0,len));
}

// 創建字節輸入流對象
// FileInputStream fis = new FileInputStream("fis2.txt");
FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java");

// 最終版代碼
// 數組的長度一般是1024或者1024的整數倍
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
    System.out.print(new String(bys, 0, len));
}

// 釋放資源
fis.close();


fis.close();
(5)案例:2種實現
A:複製文本文件

// 封裝數據源 必須存在該文件
FileInputStream fis = new FileInputStream("a.txt");
// 封裝目的地 該文件可以不存在
FileOutputStream fos = new FileOutputStream("b.txt");

int by = 0;
while ((by = fis.read()) != -1) {
    fos.write(by);
}

// 釋放資源(先關誰都行)
fos.close();
fis.close();

 

B:複製圖片

// 封裝數據源
FileInputStream fis = new FileInputStream("e:\\林青霞.jpg");
// 封裝目的地
FileOutputStream fos = new FileOutputStream("mn.jpg");

// 複製數據
int by = 0;
while ((by = fis.read()) != -1) {
    fos.write(by);
}

// 釋放資源
fos.close();
fis.close();


C:複製視頻

// 封裝數據源
FileInputStream fis = new FileInputStream("e:\\hehe.mp4");
// 封裝目的地
FileOutputStream fos = new FileOutputStream("copy.mp4");

// 複製數據
int by = 0;
while ((by = fis.read()) != -1) {
    fos.write(by);
}

// 釋放資源
fos.close();
fis.close();


(6)字節緩衝區流
A:BufferedOutputStream

// 簡單寫法
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));

// 寫數據
bos.write("hello".getBytes());

// 釋放資源
bos.close();

 

B:BufferedInputStream

// BufferedInputStream(InputStream in)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bos.txt"));

// 讀取數據
// int by = 0;
// while ((by = bis.read()) != -1) {
// System.out.print((char) by);
// }
// System.out.println("---------");

byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
    System.out.print(new String(bys, 0, len));
}

// 釋放資源
bis.close();


(7)案例:4種實現
A:複製文本文件
B:複製圖片
C:複製視頻

3:自學字符流

IO流分類
字節流:
InputStream
FileInputStream
BufferedInputStream
OutputStream
FileOutputStream
BufferedOutputStream

字符流:
Reader
FileReader
BufferedReader
Writer
FileWriter
BufferedWriter

============================================================================

1:字符流(掌握)

(1)字節流操作中文數據不是特別的方便,所以就出現了轉換流
   轉換流的作用就是把字節流轉換字符流來使用
(2)轉換流其實是一個字符流
字符流 = 字節流 + 編碼表
(3)編碼表
A:就是由字符和對應的數值組成的一張表
B:常見的編碼表
ASCII
ISO-8859-1
GB2312
GBK
GB18030
UTF-8
C:字符串中的編碼問題
編碼
String -- byte[]
解碼
byte[] -- String
(4)IO流中的編碼問題
A:OutputStreamWriter
OutputStreamWriter(OutputStream os):默認編碼,GBK
OutputStreamWriter(OutputStream os,String charsetName):指定編碼。
B:InputStreamReader
InputStreamReader(InputStream is):默認編碼,GBK
InputStreamReader(InputStream is,String charsetName):指定編碼
C:編碼問題其實很簡單
編碼只要一致即可
(5)字符流
Reader
|--InputStreamReader
|--FileReader
|--BufferedReader
Writer
|--OutputStreamWriter
|--FileWriter
|--BufferedWriter
(6)複製文本文件(5種方式)
 

2:IO流小結(掌握)

IO流
|--字節流
|--字節輸入流
InputStream
int read():一次讀取一個字節
int read(byte[] bys):一次讀取一個字節數組

|--FileInputStream
|--BufferedInputStream
|--字節輸出流
OutputStream
void write(int by):一次寫一個字節
void write(byte[] bys,int index,int len):一次寫一個字節數組的一部分

|--FileOutputStream
|--BufferedOutputStream
|--字符流
|--字符輸入流
Reader
int read():一次讀取一個字符
int read(char[] chs):一次讀取一個字符數組

|--InputStreamReader
|--FileReader
|--BufferedReader
String readLine():一次讀取一個字符串
|--字符輸出流
Writer
void write(int ch):一次寫一個字符
void write(char[] chs,int index,int len):一次寫一個字符數組的一部分

|--OutputStreamWriter
|--FileWriter
|--BufferedWriter
void newLine():寫一個換行符

void write(String line):一次寫一個字符串
 

3:案例(理解 練習一遍)

A:複製文本文件 5種方式(掌握)
B:複製圖片(二進制流數據) 4種方式(掌握)
C:把集合中的數據存儲到文本文件
D:把文本文件中的數據讀取到集合並遍歷集合
E:複製單級文件夾
F:複製單級文件夾中指定的文件並修改名稱
回顧一下批量修改名稱
G:複製多級文件夾
H:鍵盤錄入學生信息按照總分從高到低存儲到文本文件
I:把某個文件中的字符串排序後輸出到另一個文本文件中
J:用Reader模擬BufferedReader的特有功能
K:模擬LineNumberReader的特有功能

============================================================================

1:登錄註冊IO版本案例(掌握)

要求,對着寫一遍。

cn.itcast.pojo User
cn.itcast.dao UserDao
cn.itcast.dao.impl UserDaoImpl(實現我不管)
cn.itcast.game GuessNumber
cn.itcast.test UserTest
 

2:數據操作流(操作基本類型數據的流)(理解)

(1)可以操作基本類型的數據
(2)流對象名稱
DataInputStream
DataOutputStream
 

3:內存操作流(理解)

(1)有些時候我們操作完畢後,未必需要產生一個文件,就可以使用內存操作流。
(2)三種
A:ByteArrayInputStream,ByteArrayOutputStream
B:CharArrayReader,CharArrayWriter
C:StringReader,StringWriter
 

4:打印流(掌握)

(1)字節打印流,字符打印流
(2)特點:
A:只操作目的地,不操作數據源
B:可以操作任意類型的數據
C:如果啓用了自動刷新,在調用println()方法的時候,能夠換行並刷新
D:可以直接操作文件
問題:哪些流可以直接操作文件呢?
看API,如果其構造方法能夠同時接收File和String類型的參數,一般都是可以直接操作文件的
(3)複製文本文件
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
PrintWriter pw = new PrintWriter(new FileWriter("b.txt"),true);

String line = null;
while((line=br.readLine())!=null) {
pw.println(line);
}

pw.close();
br.close();

5:標準輸入輸出流(理解)

(1)System類下面有這樣的兩個字段
in 標準輸入流
out 標準輸出流
(2)三種鍵盤錄入方式
A:main方法的args接收參數
B:System.in通過BufferedReader進行包裝
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
C:Scanner
Scanner sc = new Scanner(System.in);
(3)輸出語句的原理和如何使用字符流輸出數據
A:原理
System.out.println("helloworld");

PrintStream ps = System.out;
ps.println("helloworld");
B:把System.out用字符緩衝流包裝一下使用
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 

6:隨機訪問流(理解)

(1)可以按照文件指針的位置寫數據和讀數據。
(2)案例:
A:寫數據
B:讀數據
C:獲取和改變文件指針的位置
 

7:合併流(理解)

(1)把多個輸入流的數據寫到一個輸出流中。
(2)構造方法:
A:SequenceInputStream(InputStream s1, InputStream s2) 
B:SequenceInputStream(Enumeration<? extends InputStream> e) 
 

8:序列化流(理解)

(1)可以把對象寫入文本文件或者在網絡中傳輸
(2)如何實現序列化呢?
讓被序列化的對象所屬類實現序列化接口。
該接口是一個標記接口。沒有功能需要實現。
(3)注意問題:
把數據寫到文件後,在去修改類會產生一個問題。
如何解決該問題呢?
在類文件中,給出一個固定的序列化id值。
而且,這樣也可以解決黃色警告線問題
(4)面試題:
什麼時候序列化?
如何實現序列化?
什麼是反序列化?
 

9:Properties(理解)

(1)是一個集合類,Hashtable的子類
(2)特有功能
A:public Object setProperty(String key,String value)
B:public String getProperty(String key)
C:public Set<String> stringPropertyNames()
(3)和IO流結合的方法
把鍵值對形式的文本文件內容加載到集合中
public void load(Reader reader)
public void load(InputStream inStream)


把集合中的數據存儲到文本文件中
public void store(Writer writer,String comments)
public void store(OutputStream out,String comments)
(4)案例:
A:根據給定的文件判斷是否有鍵爲"lisi"的,如果有就修改其值爲100
B:寫一個程序實現控制猜數字小遊戲程序不能玩超過5次
 

10:NIO(瞭解)

(1)JDK4出現的NIO,對以前的IO操作進行了優化,提供了效率。但是大部分我們看到的還是以前的IO
(2)JDK7的NIO的使用
Path:路徑
Paths:通過靜態方法返回一個路徑
Files:提供了常見的功能
複製文本文件
把集合中的數據寫到文本文件

============================================================================

1:多線程(理解)

(1)多線程:一個應用程序有多條執行路徑


進程:正在執行的應用程序,是系統進行資源分配和調用的獨立單位。每一個進程都有它自己的內存空間和系統資源。
線程進程的執行單元,執行路徑。是進程中的單個順序控制流,是一條執行路徑
單線程:一個應用程序只有一條執行路徑
多線程:一個應用程序有多條執行路徑

多進程的意義?
提高CPU的使用率
多線程的意義?
提高應用程序的使用率


 *  舉例:
 *   掃雷程序,迅雷下載
 
                並行和併發:
 *         並行:前者是邏輯上同時發生,指在某一個時間內同時運行多個程序。
 *         併發:後者是物理上同時發生,指在某一個時間點同時運行多個程序。
 

(2)Java程序的運行原理及JVM的啓動是多線程的嗎?
A:由java命令啓動JVM,JVM啓動就相當於啓動了一個進程。接着有該進程創建了一個主線程去調用main方法。。
B:JVM的啓動是多線程的,因爲它最低有兩個線程啓動了,主線程和垃圾回收線程
(3)多線程的實現方案(自己補齊步驟及代碼 掌握)
A:繼承Thread類

步驟:
 * A:自定義類MyThread繼承Thread類。

 * B:MyThread類裏面重寫run()?
  爲什麼是run()方法呢?

            答:

                * 不是類中的所有代碼都需要被線程執行的。
                * 而這個時候,爲了區分哪些代碼能夠被線程執行,java提供了Thread類中的run()用來包含那些被線程執行的代碼。

 * C:創建對象
 * D:啓動線程

run()和start()的區別?
        run():僅僅是封裝被線程執行的代碼,直接調用是普通方法
        start():首先啓動了線程,然後再由jvm去調用該線程的run()方法。

/*
 * 該類要重寫run()方法,爲什麼呢?
 * 不是類中的所有代碼都需要被線程執行的。
 * 而這個時候,爲了區分哪些代碼能夠被線程執行,java提供了Thread類中的run()用來包含那些被線程執行的代碼。
 */
public class b_MyThread extends Thread{
    @Override
    public void run() {
        // 自己寫代碼
        // System.out.println("好好學習,天天向上");
        // 一般來說,被線程執行的代碼肯定是比較耗時的。所以我們用循環改進
        for (int x = 0; x < 200; x++) {
            System.out.println(x);
        }
    }
}
// 創建線程對象
// MyThread my = new MyThread();
// // 啓動線程
// my.run();
// my.run();
// 調用run()方法爲什麼是單線程的呢?
// 因爲run()方法直接調用其實就相當於普通的方法調用,所以你看到的是單線程的效果
// 要想看到多線程的效果,就必須說說另一個方法:start()
// 面試題:run()和start()的區別?
// run():僅僅是封裝被線程執行的代碼,直接調用是普通方法
// start():首先啓動了線程,然後再由jvm去調用該線程的run()方法。
// MyThread my = new MyThread();
// my.start();
// // IllegalThreadStateException:非法的線程狀態異常
// // 爲什麼呢?因爲這個相當於是my線程被調用了兩次。而不是兩個線程啓動。
// my.start();

// 創建兩個線程對象
b_MyThread my1 = new b_MyThread();
b_MyThread my2 = new b_MyThread();

my1.start();
my2.start();


 * public final String getName()                    :獲取線程的名稱。
 * public final void setName(String name)    :設置線程的名稱
 
 * 針對不是Thread類的子類中如何獲取線程對象名稱呢?
 * public static Thread currentThread()            :返回當前正在執行的線程對象
 * Thread.currentThread().getName()

   // 創建線程對象
        /**
         * 方式一:無參構造+setXxx()
         */
//        c_MyThread my1 = new c_MyThread();
//        c_MyThread my2 = new c_MyThread();
//         //調用方法設置名稱
//         my1.setName("線程一");
//         my2.setName("線程二");
//         my1.start();
//         my2.start();

        /**
         * 方式二:帶參構造方法給線程起名字
         */
        c_MyThread my1 = new c_MyThread("線程一");
        c_MyThread my2 = new c_MyThread("線程二");
         my1.start();
         my2.start();

        //我要獲取main方法所在的線程對象的名稱,該怎麼辦呢?
        //遇到這種情況,Thread類提供了一個很好玩的方法:
        /**
         * public static Thread currentThread():返回當前正在執行的線程對象
         */
        System.out.println(Thread.currentThread().getName());

                B:實現Runnable接口

 * 方式2:實現Runnable接口
 * 步驟:
 * A:自定義類MyRunnable實現Runnable接口
 * B:重寫run()方法
 * C:創建MyRunnable類的對象
 * D:創建Thread類的對象,並把C步驟的對象作爲構造參數傳遞

public class a_MyRunnable implements Runnable{

    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            // 由於實現接口的方式就不能直接使用Thread類的方法了,但是可以間接的使用
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }
    }
}

 

// 創建MyRunnable類的對象
a_MyRunnable my = new a_MyRunnable();

// 創建Thread類的對象,並把C步驟的對象作爲構造參數傳遞
// Thread(Runnable target)
// Thread t1 = new Thread(my);
// Thread t2 = new Thread(my);
// t1.setName("林青霞");
// t2.setName("劉意");

// Thread(Runnable target, String name)
Thread t1 = new Thread(my, "林青霞");
Thread t2 = new Thread(my, "劉意");

t1.start();
t2.start();


(4)線程的調度和優先級問題
A:線程的調度
a:分時調度
b:搶佔式調度 (Java採用的是該調度方式)
B:獲取和設置線程優先級
a:默認是5
b:範圍是1-10  數字越大 越先執行

 * 我們的線程沒有設置優先級,肯定有默認優先級。
 * 那麼,默認優先級是多少呢?
 * 如何獲取線程對象的優先級?
 * public final int getPriority():返回線程對象的優先級
 * 如何設置線程對象的優先級呢?
 * public final void setPriority(int newPriority):更改線程的優先級。
 *
 * 注意:
 * 線程優先級高僅僅表示線程獲取的 CPU時間片的機率高,但是要在次數比較多,或者多次運行的時候才能看到比較好的效果。
 *
 * IllegalArgumentException:非法參數異常。
 * 拋出的異常表明向方法傳遞了一個不合法或不正確的參數。

d_ThreadPriority tp1 = new d_ThreadPriority();
        d_ThreadPriority tp2 = new d_ThreadPriority();
        d_ThreadPriority tp3 = new d_ThreadPriority();

        tp1.setName("東方不敗");
        tp2.setName("嶽不羣");
        tp3.setName("林平之");

        // 獲取默認優先級 5
        System.out.println(tp1.getPriority()); // 5
        System.out.println(tp2.getPriority()); // 5
        System.out.println(tp3.getPriority()); // 5

        // 設置線程優先級 只能在1-10之間
//        tp1.setPriority(100000); // IllegalArgumentException:非法參數異常。

        //設置正確的線程優先級
        tp1.setPriority(1);
        tp2.setPriority(2);
        tp3.setPriority(10);

        tp1.start();
        tp2.start();
        tp3.start();


(5)線程的控制(常見方法)
A:休眠線程

                        public static void sleep(long millis)

                                Thread.sleep(1000); // 一秒鐘

@Override
public void run() {
    for (int x = 0; x < 100; x++) {
        System.out.println(getName() + ":" + x + ",日期:" + new Date());
        // 睡眠
        // 困了,我稍微休息1秒鐘
        try {
            Thread.sleep(1000); // 一秒鐘
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

B:加入線程


C:禮讓線程

 * public static void yield():暫停當前正在執行的線程對象,並執行其他線程。
 * 讓多個線程的執行更和諧,但是不能靠它保證一人一次。

@Override
public void run() {
    for (int x = 0; x < 1000; x++) {
        System.out.println(getName() + ":" + x);
        Thread.yield();
    }
}
f_YieldThread ty1 = new f_YieldThread();
f_YieldThread ty2 = new f_YieldThread();

ty1.setName("哈哈");
ty2.setName("呱呱");

ty1.start();
ty2.start();

D:後臺線程
E:終止線程(掌握)

public final void join():等待該線程終止。

e_JoinThread tj1 = new e_JoinThread();
e_JoinThread tj2 = new e_JoinThread();
e_JoinThread tj3 = new e_JoinThread();

tj1.setName("李淵");
tj2.setName("李世民");
tj3.setName("李元霸");

tj1.start();
try {
    tj1.join(); // 等待該線程終止
} catch (InterruptedException e) {
    e.printStackTrace();
}

tj2.start();
tj3.start();

F:中斷線程

 * public final void stop():讓線程停止,過時了,但是還可以使用。
 * public void interrupt():中斷線程。 把線程的狀態終止,並拋出一個InterruptedException。

@Override
public void run() {
    System.out.println("開始執行:" + new Date());

    // 我要休息10秒鐘,親,不要打擾我哦
    try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {
        // e.printStackTrace();
        System.out.println("線程被終止了");
    }

    System.out.println("結束執行:" + new Date());
}
h_StopThread ts = new h_StopThread();
ts.start();

// 你超過三秒不醒過來,我就乾死你
try {
    Thread.sleep(3000);
    // ts.stop();
    ts.interrupt();
} catch (InterruptedException e) {
    e.printStackTrace();
}

G:守護線程

 * public final void setDaemon(boolean on):將該線程標記爲守護線程或用戶線程。
 * 當正在運行的線程都是守護線程時,Java 虛擬機退出。 該方法必須在啓動線程前調用。
 *
 * 遊戲:坦克大戰。

@Override
public void run() {
    for (int x = 0; x < 100; x++) {
        System.out.println(getName() + ":" + x);
    }
}
i_DaemonThread td1 = new i_DaemonThread();
i_DaemonThread td2 = new i_DaemonThread();

td1.setName("關羽");
td2.setName("張飛");

// 設置守護線程
td1.setDaemon(true);
td2.setDaemon(true);

td1.start();
td2.start();

Thread.currentThread().setName("劉備"); // main
for (int x = 0; x < 5; x++) {
    System.out.println(Thread.currentThread().getName() + ":" + x);
}


(6)線程的生命週期(參照 線程生命週期圖解.bmp)
A:新建
B:就緒
C:運行
D:阻塞
E:死亡
(7)電影院賣票程序的實現
A:繼承Thread類

// 定義100張票
// private int tickets = 100;
// 爲了讓多個線程對象共享這100張票,我們其實應該用靜態修飾
private static int tickets = 100;

@Override
public void run() {
    // 定義100張票
    // 每個線程進來都會走這裏,這樣的話,每個線程對象相當於買的是自己的那100張票,這不合理,所以應該定義到外面
    // int tickets = 100;

    // 是爲了模擬一直有票
    while (true) {
        if (tickets > 0) {
            System.out.println(getName() + "正在出售第" + (tickets--) + "張票");
        }
    }
}
// 創建三個線程對象
a_extendThread st1 = new a_extendThread();
a_extendThread st2 = new a_extendThread();
a_extendThread st3 = new a_extendThread();

// 給線程對象起名字
st1.setName("窗口1");
st2.setName("窗口2");
st3.setName("窗口3");

// 啓動線程
st1.start();
st2.start();
st3.start();


B:實現Runnable接口

// 定義100張票
private int tickets = 100;

@Override
public void run() {
    while (true) {
        if (tickets > 0) {
            System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票");
        }
    }
}
// 創建資源對象
b_implRunnable st = new b_implRunnable();

// 創建三個線程對象
Thread t1 = new Thread(st, "窗口1");
Thread t2 = new Thread(st, "窗口2");
Thread t3 = new Thread(st, "窗口3");

// 啓動線程
t1.start();
t2.start();
t3.start();


(8)電影院賣票程序出問題
A:爲了更符合真實的場景,加入了休眠100毫秒。
B:賣票問題
a:同票多次
b:負數票

public class c_implRunnable implements Runnable{
    // 定義100張票
    private int tickets = 100;

    @Override
    public void run() {
        while (true) {
            // t1,t2,t3三個線程
            // 這一次的tickets = 1;
            if (tickets > 0) {
                // 爲了模擬更真實的場景,我們稍作休息
                try {
                    Thread.sleep(100); //t1進來了並休息,t2進來了並休息,t3進來了並休息,
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "正在出售第"
                        + (tickets--) + "張票");
                //窗口1正在出售第1張票,tickets=0
                //窗口2正在出售第0張票,tickets=-1
                //窗口3正在出售第-1張票,tickets=-2
            }
        }
    }
}
/*
 * 實現Runnable接口的方式實現
 *
 * 通過加入延遲後,就產生了連個問題:
 * A:相同的票賣了多次
 *        CPU的一次操作必須是原子性的
 * B:出現了負數票
 *      窗口3正在出售第-1張票
 *        隨機性和延遲導致的
 */
public class c_implRunnableDemo_somethingwrong {
    public static void main(String[] args) {
        // 創建資源對象
        c_implRunnable st = new c_implRunnable();

        // 創建三個線程對象
        Thread t1 = new Thread(st, "窗口1");
        Thread t2 = new Thread(st, "窗口2");
        Thread t3 = new Thread(st, "窗口3");

        // 啓動線程
        t1.start();
        t2.start();
        t3.start();

        // 窗口3正在出售第-1張票
    }
}


(9)多線程安全問題的原因(也是我們以後判斷一個程序是否有線程安全問題的依據)
A:是否有多線程環境
B:是否有共享數據
C:是否有多條語句操作共享數據


(10)同步解決線程安全問題
A:同步代碼塊
synchronized(對象) {
需要被同步的代碼;
}


這裏的鎖對象可以是任意對象。

public class e_synchronized implements Runnable{
    // 定義100張票
    private int tickets = 100;

    // 定義同一把鎖
    private Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            // t1,t2,t3都能走到這裏
            // 假設t1搶到CPU的執行權,t1就要進來
            // 假設t2搶到CPU的執行權,t2就要進來,發現門是關着的,進不去。所以就等着。
            // 門(開,關)
            synchronized (obj) { // 發現這裏的代碼將來是會被鎖上的,所以t1進來後,就鎖了。(關)
                if (tickets > 0) {
                    try {
                        Thread.sleep(100); // t1就睡眠了
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()
                            + "正在出售第" + (tickets--) + "張票 ");
                    //窗口1正在出售第100張票
                }
            } //t1就出來了,然後就開門。(開)
        }
    }
}
/*
 * 舉例:
 *        火車上廁所。
 *
 * 同步的特點:
 *        前提:
 *           多個線程
 *    解決問題的時候要注意:
 *       多個線程使用的是同一個鎖對象
 * 同步的好處
 *    同步的出現解決了多線程的安全問題。
 * 同步的弊端
 *    當線程相當多時,因爲每個線程都會去判斷同步上的鎖,這是很耗費資源的,無形中會降低程序的運行效率。
 */
public class e_synchronizedDemo {
    public static void main(String[] args) {
        // 創建資源對象
        e_synchronized st = new e_synchronized();

        // 創建三個線程對象
        Thread t1 = new Thread(st, "窗口1");
        Thread t2 = new Thread(st, "窗口2");
        Thread t3 = new Thread(st, "窗口3");

        // 啓動線程
        t1.start();
        t2.start();
        t3.start();
    }
}


B:同步方法
把同步加在方法上。
這裏的鎖對象是this

C:靜態同步方法
把同步加在方法上。

這裏的鎖對象是當前類的字節碼文件對象(反射再講字節碼文件對象)
(11)回顧以前的線程安全的類
A:StringBuffer
B:Vector
C:Hashtable

D:如何把一個線程不安全的集合類變成一個線程安全的集合類
用Collections工具類的方法即可。List<String> list2 = Collections.synchronizedList(new ArrayList<String>()); // 線程安全

// 線程安全的類
StringBuffer sb = new StringBuffer();
Vector<String> v = new Vector<String>();
Hashtable<String, String> h = new Hashtable<String, String>();

// Vector是線程安全的時候纔去考慮使用的,但是我還說過即使要安全,我也不用你
// 那麼到底用誰呢?
// public static <T> List<T> synchronizedList(List<T> list)
List<String> list1 = new ArrayList<String>();// 線程不安全
List<String> list2 = Collections.synchronizedList(new ArrayList<String>()); // 線程安全

 

============================================================================

1:多線程(理解)

(1)JDK5以後的針對線程的鎖定操作和釋放操作
Lock鎖

 * 雖然我們可以理解同步代碼塊和同步方法的鎖對象問題,但是我們並沒有直接看到在哪裏加上了鎖,在哪裏釋放了鎖,
 * 爲了更清晰的表達如何加鎖和釋放鎖,JDK5以後提供了一個新的鎖對象Lock。
 *
 * Lock:
 * void lock(): 獲取鎖。
 * void unlock():釋放鎖。
 * ReentrantLock是Lock的實現類.

public class a_SellTicket implements Runnable{
    // 定義票
    private int tickets = 100;

    // 定義鎖對象
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                // 加鎖
                lock.lock();
                if (tickets > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()
                            + "正在出售第" + (tickets--) + "張票");
                }
            } finally {
                // 釋放鎖
                lock.unlock();
            }
        }
    }
}
// 創建資源對象
a_SellTicket st = new a_SellTicket();

// 創建三個窗口
Thread t1 = new Thread(st, "窗口1");
Thread t2 = new Thread(st, "窗口2");
Thread t3 = new Thread(st, "窗口3");

// 啓動線程
t1.start();
t2.start();
t3.start();


(2)死鎖問題的描述和代碼體現

 * 同步的弊端:
 * A:效率低
 * B:容易產生死鎖

 *
 * 死鎖:
 * 兩個或兩個以上的線程在爭奪資源的過程中,發生的一種相互等待的現象。

public class b_DieLock extends Thread{
    private boolean flag;

    public b_DieLock(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        if (flag) {
            synchronized (b_MyLock.objA) {
                System.out.println("if objA");
                synchronized (b_MyLock.objB) {
                    System.out.println("if objB");
                }
            }
        } else {
            synchronized (b_MyLock.objB) {
                System.out.println("else objB");
                synchronized (b_MyLock.objA) {
                    System.out.println("else objA");
                }
            }
        }
    }
}
/*
 * 同步的弊端:
 *        A:效率低
 *        B:容易產生死鎖
 *
 * 死鎖:
 *        兩個或兩個以上的線程在爭奪資源的過程中,發生的一種相互等待的現象。
 *
 * 舉例:
 *        中國人,美國人喫飯案例。
 *        正常情況:
 *           中國人:筷子兩支
 *           美國人:刀和叉
 *        現在:
 *           中國人:筷子1支,刀一把
 *           美國人:筷子1支,叉一把
 */
public class b_DieLockDemo{
    public static void main(String[] args) {
        b_DieLock dl1 = new b_DieLock(true);
        b_DieLock dl2 = new b_DieLock(false);

        dl1.start();
        dl2.start();
    }
}
/**
 * 鎖對象
 */
public class b_MyLock{
    // 創建兩把鎖對象
    public static final Object objA = new Object();
    public static final Object objB = new Object();
}


(3)生產者和消費者多線程體現(線程間通信問題)
以學生作爲資源來實現的

資源類:Student
設置數據類:SetThread(生產者)
獲取數據類:GetThread(消費者)
測試類:StudentDemo

代碼:
A:最基本的版本,只有一個數據。

資源類:Student

public class Student {
    String name;
    int age;
}


設置數據類:SetThread(生產者)

public class SetThread implements Runnable {

    private Student s;

    public SetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        // Student s = new Student();
        s.name = "林青霞";
        s.age = 27;
    }
}


獲取數據類:GetThread(消費者)

public class GetThread implements Runnable {
    private Student s;

    public GetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        // Student s = new Student();
        System.out.println(s.name + "---" + s.age);
    }

}


測試類:StudentDemo

/*
 * 分析:
 * 		資源類:Student
 * 		設置學生數據:SetThread(生產者)
 * 		獲取學生數據:GetThread(消費者)
 * 		測試類:StudentDemo
 *
 * 問題1:按照思路寫代碼,發現數據每次都是:null---0
 * 原因:我們在每個線程中都創建了新的資源,而我們要求的時候設置和獲取線程的資源應該是同一個
 * 如何實現呢?
 * 		在外界把這個數據創建出來,通過構造方法傳遞給其他的類。
 *
 */
public class StudentDemo {
    public static void main(String[] args) {
        //創建資源
        Student s = new Student();

        //設置和獲取的類
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);

        //線程類
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);

        //啓動線程
        t1.start();
        t2.start();
    }
}


B:改進版本,給出了不同的數據,並加入了同步機制

public class Student {
    String name;
    int age;
}
public class SetThread implements Runnable {

    private Student s;
    private int x = 0;

    public SetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (s) {
                if (x % 2 == 0) {
                    s.name = "哈哈";//剛走到這裏,就被別人搶到了執行權
                    s.age = 27;
                } else {
                    s.name = "嘻嘻"; //剛走到這裏,就被別人搶到了執行權
                    s.age = 30;
                }
                x++;
            }
        }
    }
}
public class GetThread implements Runnable {
    private Student s;

    public GetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (s) {
                System.out.println(s.name + "---" + s.age);
            }
        }
    }
}
public static void main(String[] args) {
        //創建資源
        Student s = new Student();

        //設置和獲取的類
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);

        //線程類
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);

        //啓動線程
        t1.start();
        t2.start();
    }


C:等待喚醒機制改進該程序,讓數據能夠實現依次的出現

* 分析:
*     資源類:Student
*     設置學生數據:SetThread(生產者)
*     獲取學生數據:GetThread(消費者)
*     測試類:StudentDemo
*
* 問題1:按照思路寫代碼,發現數據每次都是:null---0
* 原因:我們在每個線程中都創建了新的資源,而我們要求的時候設置和獲取線程的資源應該是同一個
* 如何實現呢?
*     在外界把這個數據創建出來,通過構造方法傳遞給其他的類。
*
* 問題2:爲了數據的效果好一些,我加入了循環和判斷,給出不同的值,這個時候產生了新的問題
*     A:同一個數據出現多次
*     B:姓名和年齡不匹配
* 原因:
*     A:同一個數據出現多次
*        CPU的一點點時間片的執行權,就足夠你執行很多次。
*     B:姓名和年齡不匹配
*        線程運行的隨機性
* 線程安全問題:
*     A:是否是多線程環境    是
*     B:是否有共享數據     是
*     C:是否有多條語句操作共享數據    是
* 解決方案:
*     加鎖。
*     注意:
*        A:不同種類的線程都要加鎖。
*        B:不同種類的線程加的鎖必須是同一把。
*
* 問題3:雖然數據安全了,但是呢,一次一大片不好看,我就想依次的一次一個輸出。
* 如何實現呢?
*     通過Java提供的等待喚醒機制解決。
*
* 等待喚醒:
*     Object類中提供了三個方法:
*        wait():等待
*        notify():喚醒單個線程
*        notifyAll():喚醒所有線程
*     爲什麼這些方法不定義在Thread類中呢?
*        這些方法的調用必須通過鎖對象調用,而我們剛纔使用的鎖對象是任意鎖對象。
*        所以,這些方法必須定義在Object類中。
*
* 最終版代碼中:
*     把Student的成員變量給私有的了。
*     把設置和獲取的操作給封裝成了功能,並加了同步。
*     設置或者獲取的線程裏面只需要調用方法即可。

資源類:Student

    String name;
    int age;
    boolean flag; // 默認情況是沒有數據,如果是true,說明有數據


設置數據類:SetThread(生產者)

public class SetThread implements Runnable {

    private Student s;
    private int x = 0;

    public SetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (s) {
                //判斷有沒有
                if(s.flag){
                    try {
                        s.wait(); //t1等着,釋放鎖
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                if (x % 2 == 0) {
                    s.name = "哈哈";
                    s.age = 27;
                } else {
                    s.name = "嘻嘻";
                    s.age = 30;
                }
                x++; //x=1

                //修改標記
                s.flag = true;
                //喚醒線程
                s.notify(); //喚醒t2,喚醒並不表示你立馬可以執行,必須還得搶CPU的執行權。
            }
            //t1有,或者t2有
        }
    }
}


獲取數據類:GetThread(消費者)

public class GetThread implements Runnable {
    private Student s;

    public GetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (s) {
                if(!s.flag){
                    try {
                        s.wait(); //t2就等待了。立即釋放鎖。將來醒過來的時候,是從這裏醒過來的時候
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                System.out.println(s.name + "---" + s.age);
                //林青霞---27
                //劉意---30

                //修改標記
                s.flag = false;
                //喚醒線程
                s.notify(); //喚醒t1
            }
        }
    }
}


測試類:StudentDemo

public static void main(String[] args) {
        //創建資源
        Student s = new Student();

        //設置和獲取的類
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);

        //線程類
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);

        //啓動線程
        t1.start();
        t2.start();
    }

wait()
notify()
notifyAll() (多生產多消費)
D:等待喚醒機制的代碼優化。把數據及操作都寫在了資源類中(最終版)

資源類:Student

public class Student {
    private String name;
    private int age;
    private boolean flag; // 默認情況是沒有數據,如果是true,說明有數據

    public synchronized void set(String name, int age) {
        // 如果有數據,就等待
        if (this.flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 設置數據
        this.name = name;
        this.age = age;

        // 修改標記
        this.flag = true;
        this.notify();
    }

    public synchronized void get() {
        // 如果沒有數據,就等待
        if (!this.flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 獲取數據
        System.out.println(this.name + "---" + this.age);

        // 修改標記
        this.flag = false;
        this.notify();
    }
}

設置數據類:SetThread(生產者)

public class SetThread implements Runnable {

    private Student s;
    private int x = 0;

    public SetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true) {
            if (x % 2 == 0) {
                s.set("張三", 27);
            } else {
                s.set("李四", 30);
            }
            x++;
        }
    }
}


獲取數據類:GetThread(消費者)

public class GetThread implements Runnable {
    private Student s;

    public GetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true) {
            s.get();
        }
    }
}


測試類:StudentDemo

public static void main(String[] args) {
        //創建資源
        Student s = new Student();

        //設置和獲取的類
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);

        //線程類
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);

        //啓動線程
        t1.start();
        t2.start();
    }


(4)線程組

* 線程組: 把多個線程組合到一起。
* 線程類裏面的方法:public final ThreadGroup getThreadGroup()
* 線程組裏面的方法:public final String getName()
* ThreadGroup(String name)
* Thread(ThreadGroup group, Runnable target, String name)
* 它可以對一批線程進行分類管理,Java允許程序直接對線程組進行控制。
* 通過結果我們知道了:線程默認情況下屬於main線程組
* 默任情況下,所有的線程都屬於同一個組
        MyRunnable my = new MyRunnable();
        Thread t1 = new Thread(my, "哈哈");
        Thread t2 = new Thread(my, "嘻嘻");
        // 我不知道他們屬於那個線程組,我想知道,怎麼辦
        // 線程類裏面的方法:public final ThreadGroup getThreadGroup()
        ThreadGroup tg1 = t1.getThreadGroup();
        ThreadGroup tg2 = t2.getThreadGroup();
        // 線程組裏面的方法:public final String getName()
        String name1 = tg1.getName();
        String name2 = tg2.getName();
        System.out.println(name1);
        System.out.println(name2);
        // 通過結果我們知道了:線程默認情況下屬於main線程組
        // 通過下面的測試,你應該能夠看到,默任情況下,所有的線程都屬於同一個組
        System.out.println(Thread.currentThread().getThreadGroup().getName());
        /**
         * ThreadGroup(String name)
         */
        ThreadGroup tg = new ThreadGroup("這是一個新的組");

        MyRunnable my = new MyRunnable();
        /**
         * Thread(ThreadGroup group, Runnable target, String name)
         */
        Thread t1 = new Thread(tg, my, "哈哈");
        Thread t2 = new Thread(tg, my, "嘻嘻");

        System.out.println(t1.getThreadGroup().getName());
        System.out.println(t2.getThreadGroup().getName());

        //通過組名稱設置後臺線程,表示該組的線程都是後臺線程
        tg.setDaemon(true);

(5)線程池

* 線程池的好處:線程池裏的每一個線程代碼結束後,並不會死亡,而是再次回到線程池中成爲空閒狀態,等待下一個對象來使用。
* 
* 如何實現線程的代碼呢?
*     A:創建一個線程池對象,控制要創建幾個線程對象。
*        public static ExecutorService newFixedThreadPool(int nThreads)
*     B:這種線程池的線程可以執行:
*        可以執行Runnable對象或者Callable對象代表的線程
*        做一個類實現Runnable接口。
*     C:調用如下方法即可
*        Future<?> submit(Runnable task)
*        <T> Future<T> submit(Callable<T> task)
*     D:我就要結束,可以嗎?
*        可以。
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }
    }
}
public static void main(String[] args) {
        // 創建一個線程池對象,控制要創建幾個線程對象。
        // public static ExecutorService newFixedThreadPool(int nThreads)
        ExecutorService pool = Executors.newFixedThreadPool(2);

        // 可以執行Runnable對象或者Callable對象代表的線程
        pool.submit(new MyRunnable());
        pool.submit(new MyRunnable());

        //結束線程池
        pool.shutdown();
    }

(6)多線程實現的第三種方案

* 多線程實現的方式3:
*      A:創建一個線程池對象,控制要創建幾個線程對象。
*        public static ExecutorService newFixedThreadPool(int nThreads)
*     B:這種線程池的線程可以執行:
*        可以執行Runnable對象或者Callable對象代表的線程
*        做一個類實現Runnable接口。
*     C:調用如下方法即可
*        Future<?> submit(Runnable task)
*        <T> Future<T> submit(Callable<T> task)
*     D:我就要結束,可以嗎?
*        可以。
public class MyCallable implements Callable{
    @Override
    public Object call() throws Exception {
        for (int x = 0; x < 100; x++) {
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }
        return null;
    }
}
        //創建線程池對象
        ExecutorService pool = Executors.newFixedThreadPool(2);

        //可以執行Runnable對象或者Callable對象代表的線程
        pool.submit(new MyCallable());
        pool.submit(new MyCallable());

        //結束
        pool.shutdown();

===========線程求和案例============:

public class MyCallable implements Callable<Integer> {

    private int number;

    public MyCallable(int number) {
        this.number = number;
    }

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int x = 1; x <= number; x++) {
            sum += x;
        }
        return sum;
    }

}
        // 創建線程池對象
        ExecutorService pool = Executors.newFixedThreadPool(2);

        // 可以執行Runnable對象或者Callable對象代表的線程
        Future<Integer> f1 = pool.submit(new MyCallable(2));
        Future<Integer> f2 = pool.submit(new MyCallable(3));
        Future<Integer> f3 = pool.submit(new MyCallable(4));

        // V get()
        Integer i1 = f1.get();
        Integer i2 = f2.get();
        Integer i3 = f3.get();

        System.out.println(i1); // 3
        System.out.println(i2); // 6
        System.out.println(i3); // 10

        // 結束
        pool.shutdown();

(6)匿名內部類的格式

* 匿名內部類的格式:
*     new 類名或者接口名() {
*        重寫方法;
*     };
*     本質:是該類或者接口的子類對象。
/*
 * 匿名內部類的格式:
 * 		new 類名或者接口名() {
 * 			重寫方法;
 * 		};
 * 		本質:是該類或者接口的子類對象。
 */
public class ThreadDemo {
    public static void main(String[] args) {
        // 繼承Thread類來實現多線程
        new Thread() {
            @Override
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println(Thread.currentThread().getName() + ":" + x);
                }
            }
        }.start();

        // 實現Runnable接口來實現多線程
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println(Thread.currentThread().getName() + ":" + x);
                }
            }
        }) {
        }.start();

        // 更有難度的
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println("hello" + ":" + x);
                }
            }
        }) {
            @Override
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println("world" + ":" + x);
                }
            }
        }.start();
    }
}

(7)定時器

* 定時器:可以讓我們在指定的時間做某件事情,還可以重複的做某件事情。
* 依賴Timer和TimerTask這兩個類:
* Timer:定時
*     public Timer()
*     public void schedule(TimerTask task,long delay)
*     public void schedule(TimerTask task,long delay,long period)
*     public void cancel()
* TimerTask:任務
public class TimerDemo {
    public static void main(String[] args) {
        // 創建定時器對象
        Timer t = new Timer();
        // 3秒後執行爆炸任務
        // t.schedule(new MyTask(), 3000);
        //結束任務
        t.schedule(new MyTask(t), 3000);
    }
}

// 做一個任務
class MyTask extends TimerTask {

    private Timer t;

    public MyTask(){}

    public MyTask(Timer t){
        this.t = t;
    }

    @Override
    public void run() {
        System.out.println("bang,爆炸了");
        t.cancel();
    }
}
public class TimerDemo2 {
    public static void main(String[] args) {
        // 創建定時器對象
        Timer t = new Timer();
        // 3秒後執行爆炸任務第一次,如果不成功,每隔2秒再繼續炸
        t.schedule(new MyTask2(), 3000, 2000);
    }
}

// 做一個任務
class MyTask2 extends TimerTask {
    @Override
    public void run() {
        System.out.println("bang,爆炸了");
    }
}
/*
 * 需求:在指定的時間刪除我們的指定目錄(你可以指定c盤,但是我不建議,我使用項目路徑下的demo)
 */

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

class DeleteFolder extends TimerTask {

    @Override
    public void run() {
        File srcFolder = new File("demo");
        deleteFolder(srcFolder);
    }

    // 遞歸刪除目錄
    public void deleteFolder(File srcFolder) {
        File[] fileArray = srcFolder.listFiles();
        if (fileArray != null) {
            for (File file : fileArray) {
                if (file.isDirectory()) {
                    deleteFolder(file);
                } else {
                    System.out.println(file.getName() + ":" + file.delete());
                }
            }
            System.out.println(srcFolder.getName() + ":" + srcFolder.delete());
        }
    }
}

public class TimerTest {
    public static void main(String[] args) throws ParseException {
        Timer t = new Timer();

        String s = "2018-07-17 14:46:00";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d = sdf.parse(s);

        t.schedule(new DeleteFolder(), d);
    }
}

(8)多線程的面試題

1:多線程有幾種實現方案,分別是哪幾種?
    兩種。
    
    繼承Thread類
    實現Runnable接口
    
    擴展一種:實現Callable接口。這個得和線程池結合。

2:同步有幾種方式,分別是什麼?
    兩種。
    
    同步代碼塊
    同步方法

3:啓動一個線程是run()還是start()?它們的區別?
    start();
    
    run():封裝了被線程執行的代碼,直接調用僅僅是普通方法的調用
    start():啓動線程,並由JVM自動調用run()方法

4:sleep()和wait()方法的區別
    sleep():必須指時間;不釋放鎖。
    wait():可以不指定時間,也可以指定時間;釋放鎖。

5:爲什麼wait(),notify(),notifyAll()等方法都定義在Object類中
    因爲這些方法的調用是依賴於鎖對象的,而同步代碼塊的鎖對象是任意鎖。
    而Object代碼任意的對象,所以,定義在這裏面。

6:線程的生命週期圖
    新建 -- 就緒 -- 運行 -- 死亡
    新建 -- 就緒 -- 運行 -- 阻塞 -- 就緒 -- 運行 -- 死亡
    建議:畫圖解釋。

2:設計模式(理解)

(1)面試對象的常見設計原則
單一
開閉
里氏
依賴注入
接口
迪米特
(2)設計模式概述和分類
A:經驗的總結
B:三類
創建型
結構型
行爲型
(3)改進的設計模式
A:簡單工廠模式
B:工廠方法模式
C:單例模式(掌握)
a:餓漢式
b:懶漢式
(4)Runtime
JDK提供的一個單例模式應用的類。
還可以調用dos命令。

public static void main(String[] args) throws IOException {
		Runtime r = Runtime.getRuntime();
//		r.exec("winmine");
		r.exec("notepad"); // 打開記事本
		r.exec("calc"); // 打開計算器
//		r.exec("shutdown -s -t 10000");
//		r.exec("shutdown -a");
	}

============================================================================

1:如何讓Netbeans的東西Eclipse能訪問。

在Eclipse中創建項目,把Netbeans項目的src下的東西給拿過來即可。
注意:修改項目編碼爲UTF-8

2:GUI(瞭解)

(1)用戶圖形界面
GUI:方便直觀
CLI:需要記憶一下命令,麻煩
(2)兩個包:
java.awt:和系統關聯較強
javax.swing:純Java編寫
(3)GUI的繼承體系
組件:組件就是對象
容器組件:是可以存儲基本組件和容器組件的組件。
基本組件:是可以使用的組件,但是必須依賴容器。
(4)事件監聽機制(理解)
A:事件源
B:事件
C:事件處理
D:事件監聽
(5)適配器模式(理解)
A:接口
B:抽象適配器類
C:實現類
(6)案例:
A:創建窗體案例
B:窗體關閉案例
C:窗體添加按鈕並對按鈕添加事件案例。
界面中的組件佈局。
D:把文本框裏面的數據轉移到文本域
E:更改背景色
F:設置文本框裏面不能輸入非數字字符
G:一級菜單
H:多級菜單
(7)Netbeans的概述和使用
A:是可以做Java開發的另一個IDE工具。
B:使用
A:四則運算
a:修改圖標
b:設置皮膚
c:設置居中
d:數據校驗
B:登錄註冊

============================================================================

1:網絡編程(理解)

(1)網絡編程:用Java語言實現計算機間數據的信息傳遞和資源共享
(2)網絡編程模型
(3)網絡編程的三要素
A:IP地址
a:點分十進制
b:IP地址的組成
c:IP地址的分類
d:dos命令
e:InetAddress

* InetAddress的成員方法:
* public static InetAddress getByName(String host):根據主機名或者IP地址的字符串表示得到IP地址對象
* public String getHostName(): 獲取主機名
* public String getHostAddress(): 獲取IP地址
/**
		 * public static InetAddress getByName(String host)
		 * 根據主機名或者IP地址的字符串表示得到IP地址對象
		 */
		// InetAddress address = InetAddress.getByName("liuyi");
		// InetAddress address = InetAddress.getByName("192.168.12.92");
		InetAddress address = InetAddress.getByName("192.168.12.54");

		/**
		 * 獲取主機名
		 */
		String name = address.getHostName();

		/**
		 * 獲取IP地址
		 */
		String ip = address.getHostAddress();

		System.out.println(name + "---" + ip);

B:端口
是應用程序的標識。範圍:0-65535。其中0-1024不建議使用。
C:協議
UDP:數據打包,有限制,不連接,效率高,不可靠

/*
 * UDP協議發送數據:
 * A:創建發送端Socket對象:new DatagramSocket()
 * B:創建數據,並把數據打包:new DatagramPacket(bys, length, address, port);
 * C:調用Socket對象的發送方法發送數據包
 * D:釋放資源
 */
public class SendDemo {
	public static void main(String[] args) throws IOException {
		// 創建發送端Socket對象:DatagramSocket()
		DatagramSocket ds = new DatagramSocket();

		// 創建數據,並把數據打包 DatagramPacket(byte[] buf, int length, InetAddress address, int port)
		byte[] bys = "hello,udp,我來了".getBytes();
		// 長度
		int length = bys.length;
		// IP地址對象
		InetAddress address = InetAddress.getByName("10.104.7.122");
		// 端口
		int port = 10086;
		DatagramPacket dp = new DatagramPacket(bys, length, address, port);

		// 調用Socket對象的發送方法發送數據包 public void send(DatagramPacket p)
		ds.send(dp);

		// 釋放資源
		ds.close();
	}
}
/*
 * UDP協議接收數據:
 * A:創建接收端Socket對象:DatagramSocket(int port)
 * B:創建一個數據包(接收容器)
 * C:調用Socket對象的接收方法接收數據
 * D:解析數據包,並顯示在控制檯
 * E:釋放資源
 */
public class ReceiveDemo {
	public static void main(String[] args) throws IOException {
		// 創建接收端Socket對象:DatagramSocket(int port)
		DatagramSocket ds = new DatagramSocket(10086);

		// 創建一個數據包(接收容器):DatagramPacket(byte[] buf, int length)
		byte[] bys = new byte[1024];
		int length = bys.length;
		DatagramPacket dp = new DatagramPacket(bys, length);

		// 調用Socket對象的接收方法接收數據:public void receive(DatagramPacket p)
		ds.receive(dp); // 阻塞式

		// 解析數據包,並顯示在控制檯
		// 獲取對方的ip
		// public InetAddress getAddress()
		InetAddress address = dp.getAddress();
		String ip = address.getHostAddress();
		// public byte[] getData():獲取數據緩衝區
		// public int getLength():獲取數據的實際長度
		byte[] bys2 = dp.getData();
		int len = dp.getLength();
		String s = new String(bys2, 0, len);
		System.out.println(ip + "傳遞的數據是:" + s);

		// 釋放資源
		ds.close();
	}
}


TCP:建立數據通道,無限制,效率低,可靠
(3)Socket機制
A:通信兩端都應該有Socket對象
B:所有的通信都是通過Socket間的IO進行操作的
(4)UDP協議發送和接收數據(掌握 自己補齊代碼)
發送:
創建UDP發送端的Socket對象
創建數據並把數據打包
發送數據
釋放資源

接收:
創建UDP接收端的Socket對象
創建數據包用於接收數據
接收數據
解析數據包
釋放資源
(5)TCP協議發送和接收數據(掌握 自己補齊代碼)
發送:
創建TCP客戶端的Socket對象
獲取輸出流,寫數據
釋放資源

接收:
創建TCP服務器端的Socket對象
監聽客戶端連接
獲取輸入流,讀取數據
釋放資源
(6)案例:
A:UDP
a:最基本的UDP協議發送和接收數據
b:把發送數據改進爲鍵盤錄入
c:一個簡易聊天小程序並用多線程改進
B:TCP
a:最基本的TCP協議發送和接收數據
b:服務器給出反饋
c:客戶端鍵盤錄入服務器控制檯輸出
d:客戶端鍵盤錄入服務器寫到文本文件
e:客戶端讀取文本文件服務器控制檯輸出
f:客戶端讀取文本文件服務器寫到文本文件
g:上傳圖片
h:多線程改進上傳文件

============================================================================

1:反射(理解)

(1)類的加載及類加載器
(2)反射:
通過字節碼文件對象,去使用成員變量,構造方法,成員方法
(3)反射的使用
A:通過反射獲取構造方法並使用
B:通過反射獲取成員變量並使用
C:通過反射獲取成員方法並使用
(4)反射案例
A:通過反射運行配置文件的內容
B:通過反射越過泛型檢查
C:通過反射給任意的一個對象的任意的屬性賦值爲指定的值
(5)動態代理

2:設計模式

(1)裝飾設計模式
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

Scanner sc = new Scanner(System.in);
(2)模版設計模式

3:JDK新特性

(1)JDK5(掌握)
裝箱和拆箱
泛型
增強for
靜態導入
可變參數
枚舉
(2)JDK6(瞭解)
(3)JDK7(理解)
二進制的表現形式
用_分隔數據
switch語句可是用字符串
泛型推斷(菱形泛型)
多catch的使用
自動釋放資源的用法
(4)JDK8(瞭解)
可以去網上了解資料

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章