java發展概述
一、
Java由SUN公司研發,SUN 被 Oracle 收購
Java 由1995年發佈,正式版本由1996年1月發佈(jdk1.0)
Java之父: James Gosling
二、
面向對象
分佈式
多線程
簡單化
安全
跨平臺移植 ------ JVM Java Virtual Machine Java虛擬機
三、
JavaSE Java Standard Edition : Java標準版本
JavaEE Java Enterprise Edition : Java企業版本
JavaME Java Micro Edition : Java微型版 ---------------- Android
四、搭建開發環境
JVM Java Virtual Machine Java虛擬機 : 用於與操作系統進行交互
JRE Java Runtime Enviroment Java運行環境: JVM + Java核心類庫
JDK Java Development Kit Java開發工具包 : JRE + Java開發工具集(java.exe javac.exe javadoc.exe)
2.
①下載安裝JDK
②通過命令提示符到JDK安裝路徑的bin路徑下,執行 javac
③配置path環境變量:JDK安裝路徑的bin路徑下
流程:先在當前路徑下找是否有 javac.exe,若沒有再到 path 環境變量中從前往後依次查找
目的:在任意路徑下執行 javac
④JAVA_HOME : JDK安裝根路徑
五、開發第一個應用程序
步驟:
①創建一個 .java 結尾的文件,被稱爲 java源文件。 如: 【HelloWorld.java】
public class HelloWorld{
public static void main(String[] args){
System.out.println("HelloWorld!");
}
}
②編譯: 通過 javac + 源文件名稱 命令進行編譯, 生成一個或多個 .class 字節碼文件。 如:【javac HelloWorld.java】
③運行: 通過 java + .class 字節碼文件名 命令進行運行。(JVM會將一個或多個.class 字節碼文件加載到內存中)。 如:【java HelloWorld】
2. 開發第一個應用程序的注意:
①以 .java 結尾的文件,被稱爲 java源文件。
②一個 .java 源文件中可以有多個類,但是,只能有一個 public 修飾的類
③public 修飾類的名稱必須與 .java 源文件名稱一致
④每條語句以 “;” 結束
⑤Java 嚴格區分大小寫
六、註釋語句: 不會被JVM解釋執行的語句
//單行註釋
/*
多行註釋:不能嵌套
*/
/**
文檔註釋: 可以通過 javadoc -d mydoc -author -version HelloWorld.java 命令生成說明文檔
*/
Java基礎語法
一、
標識符:凡是自己命名的地方都叫標識符。 如: 包名、類名、接口名、方法名、變量名、常量名
關鍵字:被Java賦予了特殊含義的單詞。
1. 命名的規則 (必須遵守,若不遵守編譯不能通過)
①可使用 字母 A-Z a-z 數字 0-9 特殊字符 下劃線 "_" 和 美元符 “$”
②數字不能開頭
③其中不能包含空格
④不能使用關鍵字和保留字,但是可以包含關鍵字和保留字
⑤Java嚴格區分大小寫,但是長度無限制。
2. 命名的規範 (可以不遵守,但是會收到鄙視)
①包名: 所有字母都小寫。 如: xxxyyyzzz
②類名、接口名:若出現多個單詞,每個單詞首字母都大寫。如: XxxYyyZzz
③方法名、變量名: 若出現多個單詞,第一個單詞的首字母小寫,其餘單詞首字母都大寫。如: xxxYyyZzz
④常量名: 所有字母都大寫,每個單詞之間以 "_" 分隔。 如: XXX_YYY_ZZZ
二、
變量:用於保存數據
局部變量 & 成員變量
1. 變量的格式: 數據類型 變量名 = 值;
//聲明一個變量
數據類型 變量名; 如: int var;
//爲變量賦值
變量名 = 值; 如: var = 10;
//聲明一個變量並賦值
int var = 10;
2. 變量的概念:
①在內存中開闢一塊內存空間
②該空間有名稱(變量名)有類型(數據類型)
③變量可以在指定的範圍內不斷的變化
3. 變量的注意:
①作用域:變量作用在所屬的那對 {} 內
②局部變量在使用前必須賦初始值
③先聲明,後使用
三、進制之間的轉換(瞭解)
四、變量的數據類型
基本數據類型(8種):
整型: byte(8位) short(16位) int(32位)-默認類型 long(64位)
浮點型: float(32位) double(64位)---默認類型
字符型: char(2個字節---16位)
布爾型: boolean
引用數據類型:
|---類(class) -------------------- String 字符串
|---接口(interface)
|---數組([])
聲明變量的注意:
①聲明 long 型變量,值後需要加 L 或 l . 如: long l = 123456l; long l1 = 123456L;
②聲明 float 型變量,值後必須加 F 或 f 。 如: float f = 15.6f;
③聲明 double 型變量,值後可以加 D 或 d 。 如: double d1 = 167.7D;
④聲明 char 型變量,值必須使用單引號。只能存儲單個字符
存儲 Unicode 編碼(ASCII 、 中文、日文、特殊字符等等)
⑤聲明 String 變量,值必須使用雙引號
五、變量的運算
數據類型的轉換:
自動類型轉換(自動升級):小容量轉大容量。(系統自動完成)
①byte short char ---> int ---> long ---> float ---> double
②byte short char 三者之間不進行運算,若運算自動提升成 int 再做運算
char c1 = 'A';
char c2 = 'B';
int i = c1 + c2;
③boolean 不參與運算
④String與任何基本數據類型使用連接符(+) 進行運算,都將自動串接成 String 類型
強制類型轉換:大容量轉小容量。需要使用強轉符 "(需要轉換的類型)"
但是可能損失精度。
六、運算符
算數運算符 : + - + - * / % 前++ 後++ 前-- 後-- +(連接符)
//除法
int a = 12;
int b = 5;
int c = a / b; //2
//取模
int c = 12 % 5;
//前後++
int i = 10;
int j = i++;
System.out.println(i);//11
System.out.println(j);//10
System.out.println(++i);
int i = 10;
i = i++; //10
賦值運算符: = += -= *= /= %=
int i = 10;
i += 5; //i = i + 5;
System.out.println(i); //15
【面試題】
short s = 5;
s = s + 1;//編譯? NO
s += 1; //編譯? YES s = (short)(s + 1);
比較運算符(關係運算符) : == != > < >= <= (運算後結果都爲 boolean 型)
int a = 10;
int b = 20;
boolean b1 = a == b;
邏輯運算符: && -短路與 ||-短路或 !-邏輯非 &-邏輯與 |-邏輯或 ^-異或 (運算後結果都爲 boolean 型)
//需求:判斷一個數是否大於10 小於20
int a = 10;
//10 < a < 20; 錯誤的做法
boolean b2 = a > 10 && a < 20;
【面試題】 && 和 & 的區別?
&& : 稱爲短路與,當左邊表達式結果爲 false 時,右邊表達式將不再運算
& : 是位運算符,當用於邏輯運算時,無論左邊表達式結果爲true還是false,右邊都運算
位運算符 : ~ | & ^ << >> >>> 注意:沒有 <<<
三元運算符(三目運算符)
條件表達式 ? 表達式1 : 表達式2;
①當條件表達式結果爲 true 時,執行表達式1 ,否則執行表達式2
②表達式1和表達式2的結果類型需要保持一致!
一、流程控制:
順序結構
分支結構
條件判斷:
if(條件表達式){
//當條件表達式結果爲 true 時,需要執行的語句
}
if(條件表達式){
//當條件表達式結果爲 true 時,需要執行的語句
}else{
//當條件表達式結果爲 false 時,需要執行的語句
}
if(條件表達式1){
//當條件表達式1 結果爲 true 時,需要執行的語句
}else if(條件表達式2){
//當條件表達式2 結果爲 true 時,需要執行的語句
}else if(條件表達式3){
//當條件表達式3 結果爲 true 時,需要執行的語句
}
……
else{
//當上述條件表達式結果都爲 false 時,需要執行的語句
}
注意:
①當某個條件表達式結果爲true, 執行相應的語句,其他 else if 將不再執行
②if-else 語句可以嵌套的
選擇結構:
switch(表達式){
case 值1 :
//執行的語句
break;
case 值2 :
//執行的語句
//break;
case 值3 :
//執行的語句
break;
……
default :
//執行的語句
break;
}
注意:
①表達式結果的數據類型,只能是 byte short char int 枚舉 String(jdk1.7後)
②表達式結果的數據類型要與case後值的類型需要保持一致!
③default 是可選的
④break 也是可選的,若與某個case後的值匹配成功,依次向下執行,直到遇到break爲止。'
⑤case 後只能寫常量值,不能寫表達式
//需求:若一個數大於2 小於5 打印 “2-5”
int i = 2;
switch(i){
case 1:
System.out.println("一");
break;
case 2:
case 3:
case 4:
case 5:
System.out.println("2-5");
break;
}
循環結構:
①初始化值
②循環條件
③迭代條件
④循環體
for(① ; ② ; ③){
④
}
①②④③②④③②④③②……④③②
①
while(②){
④
③
}
①
do{
④
③
}while(②);
while 和 do-while 的區別?
while : 先判斷循環條件,再執行循環體
do-while : 先執行循環體,再判斷循環條件。(至少執行一次)
二、嵌套循環: 一個循環充當了另一個循環的循環體
打印100以內的質數:
boolean flag = true;
for(int i = 2; i <= 100; i++){
for(int j = 2; j < i; j++){
if(i % j == 0){
flag = false;
break;
}
}
if(flag){
System.out.println(i);
}
flag = true;
}
三、特殊流程控制語句
break: 結束“當前”循環 。當用於switch-case語句時,用於結束當前 switch-case 語句
continue: 結束“當次”循環
label:for(int i = 0; i < 100; i++){
for(int j = 0; j < 100; j++){
if(j == 13){
System.out.println(j);
break label;
}
}
}
02.方法的聲明和使用
作者: 風離紫竹
方法的聲明和使用
一、方法:也叫函數,是一個功能的定義。是一個類中最基本的功能單元
//需求: 計算一個數 * 2 + 1 的結果
int a = 10;
System.out.println(a * 2 + 1);
a = 5;
System.out.println(a * 2 + 1);
a = 8;
System.out.println(a * 2 + 1);
1.方法的格式:
修飾符 返回值類型 方法名(參數列表){
//功能語句
return 返回值;
}
返回值類型:說明方法運行後有結果,那個結果的數據類型。
參數列表:就是局部變量,可以有0個或多個,每個參數之間以 “,” 分隔
return : 用於結束當前方法
返回值:方法運行結束後,返回具體結果的值
public static int result(int a){ //形式參數: 用於接收調用者傳遞的實際參數
return a * 2 + 1;
}
result(10);//實際參數
2. 方法的注意:
①“返回值類型”與 “返回值”的數據類型需要保持一致
②調用方法通過方法名和參數列表,注意方法名和參數列表(參數的個數、參數的類型)必須一致
③若聲明瞭“返回值類型”說明該方法運行後有結果,若調用者需要用到該結果
可以聲明同類型變量接收。
④若方法運行結束後,不需要返回任何結果給調用者時,方法“返回值類型”處聲明爲 void
void : 表示沒有返回值
⑤方法中只能調用方法,不能聲明其他方法
3. 聲明方法的兩點明確
①方法是否需要返回結果給調用者
明確是否需要返回值類型,返回值類型是什麼
②方法是否有未知的數據參與運算
明確是否需要參數列表,需要幾個
二、跨類調用方法:
通過“類名.方法名" 方式調用。 (暫時使用static修飾的方法爲例)
一、參數的值傳遞
基本數據類型:將基本數據類型作爲參數,傳遞給方法,方法運行結束後,原值不會發生改變
//改變兩個數的值
public static void add(int a, int b){
a += 1;
b += 2;
}
public static void main(String[] args){
int a = 10;
int b = 20;
add(a, b);
System.out.println("a=" + a + " b=" + b);//a=10, b=20
}
引用數據類型:
方法重載 Overload :
前提:在同一個類中
①方法名相同
②參數列表不同(參數的個數、參數的類型)
注意:與返回值類型無關
public void show(char c, int a){}
public void show(int a, char c){}
public void show(int a, char c, double d){}
public void show(String str, int a){}
public void shows(char c, int a){}
03. 面向對象編程(上)
作者: 風離紫竹
一、面向對象編程(OOP)
面向對象和麪向過程:
面向過程:強調的是功能行爲
面向對象:將功能行爲封裝進對象,強調的是具備了功能行爲的對象
(理解)把大象裝冰箱一共分幾步?
①打開冰箱 ②把大象裝進去(存儲大象) ③關閉冰箱
如何使用面向對象思想思考上述問題呢?
人{
拉(冰箱){
冰箱.打開()
}
指揮(動物){
動物.進入()
}
推(冰箱){
冰箱.關閉()
}
}
冰箱{
打開(){}
存儲(){}
關閉(){}
}
大象{
進入(){}
}
猴{
進入(){}
}
獅子{
進入(){}
}
面向對象更加註重前期的設計
①就是對類的設計
②設計類就是設計類的成員:屬性 & 方法
面向對象:將現實生活中一類事物的共性內容進行提取,抽象成相應Java類,用Java中類對其進行描述
現實生活中的事物: 小貓 小狗 大象
共性內容: 名稱 性別 年齡 喫飯的功能 睡覺的功能
class Animal{
//屬性
String name;
char gender;
int age;
//方法-行爲
public void eat(){
System.out.println("喫飯");
}
public void sleep(){
System.out.println("睡覺");
}
}
若需要具體到某一個事物,通過 new 關鍵字創建對象
Animal a1 = new Animal(); //
a1.name = "大象";
a1.gender = '男';
a1.age = 2;
a1.eat();
a1.sleep();
System.out.println(a1.name + "," + a1.age);
類和對象:
類:對現實生活中一類事物的描述,抽象的
對象:是一個實實在在的個體
一、屬性:也叫成員變量,也叫實例變量
成員變量 & 局部變量 的區別?
①作用域不同
②內存中的位置不同
③成員變量有默認值,而局部變量沒有默認值(局部變量使用前必須賦初始值)
成員變量的默認值:
基本數據類型:
byte short int ---> 0
long ---> 0L
float ---> 0.0F
double ---> 0.0D
char ---> '\u0000'
boolean ---> false
引用數據類型: ---> null
|-- 類(class)
|-- 接口(interface)
|-- 數組([])
2.爲屬性賦初始化值的方式
①使用默認值
②直接顯示賦值
二、參數的值傳遞:
基本數據類型: 將基本數據類型作爲參數,傳遞給方法,方法運行結束後,原值不會發生改變
引用數據類型: 將引用數據類型作爲參數,傳遞給方法,方法運行結束後,原值會發生改變
內存管理:
分配: JVM自動爲其分配內存空間
釋放:JVM通過垃圾回收機制自動的釋放內存空間
垃圾回收機制: 將內存中的垃圾對象釋放
垃圾對象:不再被任何引用指向的對象
Person p = new Person();
p = null;
System.gc(); //通知垃圾回收機制可以釋放內存,但是並不能保證立即釋放,加快釋放。
一、面向對象的特性之一:封裝性
封裝的理解: 該隱藏的隱藏起來,該暴露的暴露出來
訪問控制修飾符:
public : 公共的,可用於修飾屬性、方法、類。 在任何地方都可以訪問
private : 私有的,可用於修飾屬性、方法。 只能在本類中訪問
封裝的步驟:
①屬性私有化(private)
②提供公共的(public) get/set 方法
class Animal{
//1.
private String name;
private int legs; //描述腿的個數
//2.
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
public ovid setLegs(int l){
if(l > 0 && l <= 4){
legs = l;
}
}
public int getLegs(){
return legs;
}
}
Animal ani = new Animal();
ani.name = "大象";
ani.legs = -1000;
一、this 關鍵字:使用在本類中,代表當前對象。可以用於調用屬性、方法、構造器
this.屬性
this.方法
this(……):
①this調用本類構造器,必須寫在構造器中可執行代碼的首行
②若一個類中有多個構造器,至少有一個構造器中不使用this (避免遞歸構造器調用)
誰讓擁有this關鍵字的方法運行,誰就是當前對象
class Person{
private String name;
private int age;
public void setName(String name){
this.name = name;//可以區分局部變量和成員變量
}
}
Person p = new Person();
p.setName("張三");
一、構造器:也叫構造器方法,是類的成員之一。
屬性
方法
構造器
1. 構造器的格式
訪問控制修飾符 類名(參數列表){
//初始化語句
}
2. 構造器的作用
①創建對象
②爲對象進行初始化
3. 構造器的注意:
①構造器的名稱必須與類名一致!
②若一個類中沒有顯示提供任何構造器,系統會自動提供一個默認無參構造器
public Person(){}
③若一個類中顯示的提供了任何構造器,系統默認構造器將不再提供
④構造器只能調用一次,並且是在創建對象時調用
4. 構造器的重載
①構造器的名稱必須相同
②構造器的參數列表必須不同(參數的個數、參數的類型)
5. 爲屬性賦初始值的方式
①使用默認賦值
②直接顯示賦值
③構造器
順序:①②③
class Person{
private String name;
private int age;
private char gender;
public Person(){
cry();
}
public Person(String name){
this.name = name;
}
public Person(String name, int age){
this(name);
this.age = age;
}
public Person(String name, int age, char gender){
this(name, age);
this.gender = gender;
}
public void setName(String name){
this.name = name;//可以區分局部變量和成員變量
}
public void cry(){
System.out.println("哭");
}
}
Person p = new Person("張三");
//p.cry();
Person p1 = new Person();
//p1.cry();
一、包的作用:
①用於區分重命名
②用於控制訪問權限
③用於劃分項目的結構層次,通常將功能相近的類劃分到同一個包中。
package : 用於確定當前類的位置
①使用在當前 .java 源文件可執行代碼的首行
②包的命名規範:所有字母都小寫。 (通常將所在公司域名的倒置)
如: com.atguigu.項目名.模塊名;
③每個“.”代表一層目錄
import : 用於確定需要引入那個類的位置
①使用在 package 和 class 之間
②可以有多條,並排列出
③ import com.atguigu.aaa.* : 代表導入 aaa 包中所有的類或接口。 注意:包除外
④ 若在一個類中使用了兩個相同類名不同包名的兩個類。 如: java.util.Date; java.sql.Date;
選擇一個使用導入的方式: import java.util.Date;
選擇另外一個使用全限定類名(全類名)的方式: java.sql.Date date = new java.sql.Date();
⑤靜態導入:
import static com.atguigu.aaa.StaticClass.*; // 導入一個類中所有的靜態內容
04.聲明和使用數組
作者: 風離紫竹
一、數組:用於批量保存一類數據。是引用數據類型之一。
//變量的格式 : 數據類型 變量名 = 值;
int j = 0;
int j;
j = 0;
2. 聲明數組
int[] scores;
String[] names;
Person[] persons;
3.爲數組初始化並賦值
//靜態初始化: 初始化操作和賦值操作同時進行
scores = new int[]{0,1,2,3,4,5};
//動態初始化:初始化操作和賦值操作分開進行
names = new String[5]; //{null, "張三", null, "李四", null}
names[1] = "張三";
names[3] = "李四";
4. 獲取數組中的元素
String str = names[0];
System.out.println(str);
System.out.println(names[1]);
System.out.println(names[2]);
System.out.println(names[3]);
System.out.println(names[4]);
5. 遍歷數組的兩種方式
方式一:使用普通for循環遍歷數組
for(int i = 0; i < names.length; i++){
System.out.println(names[i]);
}
方式二:使用增強for循環遍歷數組
for(被遍歷數組中元素的數據類型 變量名 : 被遍歷的數組){
}
for(String s : names){
System.out.println(s);
}
6. 數組的注意:
①無論是靜態初始化還是動態初始化必須指明長度
②數組中每個元素都有索引值(下角標、下標),索引值從0開始,到 數組的長度 - 1
③數組的屬性: length 用於獲取數組的長度
7. 數組的默認值
基本數據類型:
byte shor int ---> 0
long ---> 0L
float ---> 0.0F
double ---> 0.0D
char ---> '\u0000'
boolean ---> false
引用數據類型: ---> null
|-- 類(class)
|-- 接口(interface)
|-- 數組([])
二、二維數組
//聲明一個二維數組
int[][] arr;
//爲二維數組初始化並賦值
//靜態初始化:初始化和賦值操作同時進行
arr = new int[][]{ {1,2,3}, {4,5,6}, {7,8} }
//動態初始化
//動態初始化-1
arr = new int[5][6]; //{ {0,0,11,0,0,0}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, {0,0,0,15,0,0}, {0,0,0,0,0,0} }
arr[0][2] = 11;
arr[3][3] = 15;
//動態初始化-2
arr = new int[5][]; //{ null, {0,11,0}, null, {0,0,0,22,0}, null };
arr[1] = new int[3];
arr[3] = new int[5];
arr[1][1] = 11;
arr[3][3] = 22;
//遍歷二維數組
for(int i = 0; i < arr.length; i++){
for(int j = 0; j < arr[i].length; j++){
System.out.prin
for(int a : as){t(arr[i][j] + "\t");
}
System.out.println();
}
for(int[] as : arr){
for(int a : as){
System.out.print(a + "\t");
}
System.out.println();
}
三、用於操作數組的工具類: java.util.Arrays;
四、命令行參數
通過: java HelloWorld abc ddd eee "Jane Smith"
public static void main(String[] args){
for(int i = 0; i < args.length; i++){
System.out.println(args[i]);
}
}
五、可變參數
//需求:計算兩個整數的和
/*public int add(int a, int b){
return a + b;
}
public int add(int a, int b, int c){
return a + b + c;
}*/
/*public int add(int[] arr){//可變參數與數組參數之間不能構成重載
int sum = 0;
for(int i = 0; i < arr.length; i++){
sum += arr[i];
}
return sum;
}*/
public int add(int ... args){ //當調用方法時,可以傳遞0個或多個 int 型實際參數
int sum = 0;
for(int i = 0; i < args.length; i++){
sum += args[i];
}
return sum;
}
public int add(String str, int ... args){//可變參數要寫在參數列表的末尾
}
05.面向對象編程(下)
作者: 風離紫竹
一、面向對象的特性之二: 繼承
1. 爲什麼使用繼承
①提高代碼的複用性
②提高維護性
③有了繼承讓類與類之間產生了關係,能夠創建出更加特殊的類型(多態)
2. 如何使用繼承
關鍵字: extends ----- "擴展" 明確子類是父類的擴展
如:
class A extends B{
}
子類: A 父類(超類、基類、SuperClass):B
3. 通過繼承,子類可以繼承父類中所有的屬性和方法。(包括私有的)
私有的屬性也會被繼承,但是因爲 private 修飾符的作用,子類不能直接訪問
需要通過 公共的 get / set 方法進行訪問
4. 繼承的注意:
①不能爲了簡化代碼,獲取某功能而繼承,若要完成繼承兩個類之間要有一定的所屬關係:is a
②Java只支持單繼承,不支持多繼承。(一個父類可以有多個子類,但是一個子類只能有一個父類)
③Java支持多層繼承。
class A{
void test1(){}
void test2(){}
}
class B extends A{
//void test1(){}
//void test2(){}
}
---------------------------
class A{
void test1(){
//111111111111
}
}
class B{
void test1(){
//22222222222
}
}
class C extends A, B{}
C c = new C();
c.test1();
二、方法的重寫:當父類中的方法對於子類來說不適用的情況下,子類可以對父類中方法進行“重寫”
前提: 要有繼承關係,使用在子類中
①方法名和參數列表必須相同
②返回值類型可以不同,但是有規則(若重寫方法返回值類型是父類被重寫方法返回值類型的子類)
③子類重寫方法的訪問控制修飾符不能小於父類被重寫方法的訪問控制修飾符
【面試題】 Override 和 Overload 的區別?
三、super 和 this 的使用方式完全一致!
this : 使用在本類中,代表當前對象的引用
super : 使用在子類中,代表父類對象的引用
super.屬性
super.方法
super(……); 調用父類構造器
①當子類繼承父類後,子類“所有”構造器中默認第一行第一句都有一句: super()
super : 當子類繼承父類後,子類繼承父類中所有的屬性和方法,子類需要知道父類如何爲對象進行初始化
②若父類中沒有提供無參構造器,子類“所有”構造器中必須顯示調用父類有參構造器
(無論如何必須保證創建子類對象前,先初始化父類)
③super() 調用父類構造器,必須寫在構造器中可執行代碼的首行
因此,this() 和 super() 不能同時出現
四、四種訪問控制修飾符
public : 公共的,可用於修飾 屬性、方法、類。 在任何地方都可以使用
protected: 受保護的,可用於修飾 屬性、方法。 可以在 本類中、本包中、子類中
default : 默認的(缺省的) ,可用於修飾 屬性、方法、類。 可以在 本類中、本包中
注意:default 並不是訪問控制修飾符的關鍵字,在什麼都不加的情況下就是 default
private : 私有的,可用於修飾 屬性、方法。 只能在 本類中 使用
一、多態:一類事物的多種表現形態。 人 - 男人 女人
1. 多態的體現: ①方法的重載與重寫 ②對象的多態性
2.對象的多態性:父類的引用指向子類的對象
Person p = new Man(); // 多態-向上轉型
p.eat();
p.walk(); //虛擬方法調用
//p.smoking();
Man man = (Man)p; //向下轉型
man.smoking();
Java程序的運行分爲兩種狀態:
在多態的情況下,編譯時, “看左邊”,看的是父類的引用(父類中不具備子類特有的方法)
運行時,“看右邊”,看的是子類對象,實際運行的是子類重寫父類的方法
———— 以上過程被稱爲“虛擬方法調用(動態綁定)”
3. 多態的前提:①要有繼承關係 ②方法的重寫(完成虛擬方法調用)
4. 引用數據類型之間的轉換:
前提:要有繼承關係
向上轉型: 子類轉父類。系統自動完成轉換
向下轉型: 父類轉子類。需要使用強轉符 “(需要轉換的類型)”
可能引發 java.lang.ClassCastException
Person p = new Man();
Woman woman = (Woman)p; //編譯? YES 運行? NO
5. Java 爲了解決上述問題,提供了相應的解決辦法
instanceof 運算符:
如:
p instanceof Man : 判斷 p 引用指向的對象是不是 Man 的本類類型及 Man 的子類類型,如果是返回 true
Person p = new Man();
if(p instanceof Woman){
Woman woman = (Woman)p;
}
二、多態的應用
多態的應用之一:多態數組
Person[] persons = new Person[3];//該多態數組中可以存放Person本類類型的對象及Person子類類型的對象
persons[0] = new Person();
persons[1] = new Man();
persons[2] = new Woman();
for(int i = 0; i < persons.length; i++){
persons[i].eat();//虛擬方法調用
}
多態的應用之二: 多態參數
//需求:展示一個男人喫飯和走路的功能
/*public void show(Man man){
man.eat();
man.walk()
}
public void show(Woman woman){
woman.eat();
woman.walk();
}*/
public void show(Person p){ //多態參數:當調用方法時,可以傳遞Person本類類型的對象及Person子類類型的對象
p.eat();
p.walk();//虛擬方法調用
if(p instanceof Man){
Man man = (Man)p;
man.smoking();
}
}
一、對象的關聯:簡單的說,是指一個對象中使用了另一個對象
class Teacher{
String name;
int age;
Computer com;
}
class Computer{
String cpu;
String ram;
String hdd;
}
二、java.lang.Object 類: 是所有類的父類。若一個類沒有顯示的 extends 任何類時,默認的 extends java.lang.Object
①既然 java.lang.Object 類是所有類的父類,那麼Object類中的內容是最具共性的,所有類都適用
②既然 java.lang.Object 類是所有類的父類,那麼Object類中方法都會被“繼承”
③既然 java.lang.Object 類是所有類的父類,若Object類中的方法對於子類來說不適用,子類可以重寫Object類中的方法
1. public boolean equals(Object obj) : 用於比較當前對象與參數對象是否相等
①在 java.lang.Object 類中
②只能比較引用數據類型是否相等
③Object類中的equals方法比較兩個對象的地址值。(通過查看源代碼發現實際上使用 == 完成)
④若Object類中的equals() 方法對於我們來說不適用,我們可以重寫 Object類中 equals()
“==”運算符:
基本數據類型: 比較兩個基本數據類型的值是否相等,若相等返回 true
引用數據類型: 比較兩個引用數據類型的地址值是否相等,若相等返回 true
class Person /* extends java.lang.Object*/{
String name;
int age;
public Person(){}
public Person(String name, int age){
this.name = name;
this.age = age;
}
//重寫
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(obj instanceof Person){
Person p = (Person)obj;
if(this.name.equals(p.name) && this.age == p.age){
return true;
}
}
return false;
}
public String toString(){
return "姓名:" + name + “年齡:” + age;
}
}
//需求:若兩個人的姓名年齡都一樣,視爲同一個人
Person p1 = new Person("張三", 18);
Person p2 = new Person("張三", 18);
System.out.println(p1.equals(p2)); //重寫equals之前- false----重寫後:true
System.out.println(p1);
System.out.println(p1.toString());
2. public String toString() : 返回當前對象的字符串表現形式
①在 java.lang.Object 類中
②Object類中的toString方法返回的格式爲:
getClass.getName() + '@' + Integer.toHexString(hashCode());
因此,Object類中的toString() 方法對於我們來說不適用,我們可以重寫toString()
③當直接輸出對象的引用時,默認調用 toString();
一、static 修飾符:代表靜態的,可用於修飾 屬性、方法、代碼塊、**內部類
1. static 修飾的屬性(靜態變量或類變量)
①隨着類的加載而加載,隨着類的消失而消失(生命週期最長)
②靜態變量被該類所有對象所共享
③一旦某個對象修改該屬性值,其他對象也會隨之改變
④靜態變量的存在優先於對象
⑤可以通過 “類名.類變量”的方式調用
2. static 修飾的方法(靜態方法或類方法)
①隨着類的加載而加載
②靜態方法的存在優先於對象
③通過“類名.類方法”的方式調用
④靜態方法中不能調用非靜態成員,非靜態方法中可以調用靜態成員
⑤靜態方法中不能使用 this 和 super
3. 類變量和實例變量的區別?
①生命週期不同
②內存中的位置不同
二、類的成員之一: 代碼塊
非靜態代碼塊:
①格式: 類的一對 { }
②每次創建對象時執行
③非靜態代碼塊的執行優先於構造器
④用於爲對象進行初始化。(通常爲共性內容進行初始化)
⑤代碼塊可以有多個,依次向下的順序執行
靜態代碼塊:
①格式:static{ }
②隨着類的加載而加載,並且只加載一次
③靜態代碼塊的執行優先於非靜態代碼塊
④靜態代碼塊中不可以調用非靜態成員
⑤靜態代碼塊可以有多個,依次向下的順序執行
三、final 修飾符: 代表最終的,可用於修飾 變量、方法、類。
final 修飾的類不能被繼承
final 修飾的方法不能被重寫
final 修飾的變量叫常量,一旦被賦值,值不能改變
①常量的命名規範:所有字母都大寫,每個單詞之間以 "_" 分隔
②常量沒有默認值,因此在使用前必須爲常量賦初始值
賦值方式(直接顯示賦值、構造器、代碼塊)
若選擇使用構造器爲常量賦值,必須保證“所有”構造器都爲該常量賦值
06. 高級類特性
作者: 風離紫竹
一、抽象類
創建類用於描述現實生活中一類事物,類中有屬性有方法,方法都有方法體。
某種情況下,父類只能知道子類應該具備一個怎樣的方法,但是不能明確知道子類如何實現該方法。
例如:幾何圖形(多態練習),所有幾何圖形都應該具備一個計算面積的方法,但是不同幾何圖形計算面積的方式不同
Java爲上述問題提供了相應的解決辦法
Java允許父類中只是提供一個方法的聲明,不提供具體的實現
具體的實現交給子類來完成,該方法被稱“抽象方法”
擁有一個或多個抽象方法的類,稱爲“抽象類”
二、如何使用抽象 : abstract 關鍵字
1. 使用 abstract 修飾的類稱爲“抽象類”
①格式: 訪問控制修飾符 abstract class 類名{}
②擁有一個或多個抽象方法的類必須是抽象類
③抽象類中可以有非抽象方法
④抽象類中可以沒有抽象方法的
⑤***抽象類不能創建實例
⑥抽象類中可以聲明構造器。作用:當子類繼承父類後繼承父類中所有的屬性和方法,因此子類需要知道父類如何爲對象進行初始化
2. 使用 abstract 修飾的方法稱爲“抽象方法”
①格式: 訪問控制修飾符 abstract 返回值類型 方法名(參數列表);
注意:抽象方法沒有方法體,因此也不需要那對 {}
②當子類繼承父類後,若重寫了父類中“所有”的抽象方法,該類爲具體類,可以創建實例
③當子類繼承父類後,若沒有重寫父類中“所有”的抽象方法,該類必須是抽象類,不可以創建實例
3.
abstract 和 static 不能同時使用
abstract 和 final 不能同時使用
abstract 和 private 不能同時使用
一、接口:可以定義多個不相關事物的相同功能
二、如何使用接口
①接口與類是平級的
關鍵字: interface
public interface Flyer{}
②可以把接口理解爲一個特殊的抽象類,因爲接口中只能定義“全局靜態常量”和“抽象方法”
//全局靜態常量
int NUM = 10;//public static final
//抽象方法
void fly();//public abstract
③接口中不能定義一般方法、變量、構造器、代碼塊
④**接口不能創建實例
⑤接口就是用來被實現的
關鍵字 : implements
public class Bird implements Flyer{}
⑥實現接口的類被稱爲“實現類”,實現類的功能和“繼承”功能一致, 都可以獲取接口中所有的成員
⑦若實現類實現了接口中“所有”的抽象方法,該類爲具體類,可以創建實例
若實現類沒有實現接口中“所有”的抽象方法,該類必須是抽象類,不能創建實例
⑧接口可以多實現 ----- 解決了Java中單繼承的侷限性
如:
public class Bird implements Flyer, Runner{}
⑨接口不可以繼承任何類, 接口可以繼承接口,接口可以多繼承接口
⑩一個類可以繼承另一個類,同時實現多個接口
如:
public class Bird extends Animal implements Flyer, Runner{}
注意:先繼承,後實現
一、內部類:在一個類中聲明另一個類。 裏面的類:內部類 外面的類:外部類
1. 成員內部類:
①是類的成員之一。 (屬性、方法、構造器、代碼塊)
②內部類可以使用四種訪問控制修飾符(public protected default private)
③static final
//創建靜態內部類對象
Person.Mobile pm = new Person.Mobile();
pm.message();
//創建非靜態內部類對象
//Person p = new Person();
//Person.Computer pc = p.new Computer();
Person.Computer pc = new Person().new Computer();
pc.show();
④內部類的外部類擁有相同的特性。
class Person{
Stirng name;
int age;
//成員內部類
public class Computer{
String name;
public void show(){
System.out.println(this.name);
System.out.println(Person.this.name);//區分內部類屬性和外部類屬性
}
}
static class Mobile{
public void message(){
}
}
}
2. 局部內部類:
//如下方式使用非常少
public void show(){
class InnerClass{}
}
//若某個類僅適用於當前方法時,可以聲明爲局部內部類
public Comparator getComparator(){
class MyComparator implements Comparator{
public int compare(Object o1, Object o2){
return 0;
}
}
return new MyComparator();
}
public Comparator getComparotor(){
//匿名內部類
Comparator com = new Comparator(){
public int compare(Object o1, Object o2){
return 0;
}
};
return com;
}
pulbic Comparator getComparator(){
return new Comparator(){
public int compare(Object o1, Object o2){
return 0;
}
};
}
一、枚舉類:jdk1.5後出的新特性,可以定義有限數量的可窮舉數據集。
簡而言之,當確定一個類有幾個對象時,使用枚舉。
1. 自定義枚舉類
①私有化構造器
②類內部創建對象
class Season{
//類內部創建對象
public static final Season SPRING = new Season();
public static final Season SUMMER = new Season();
public static final Season AUTUMN = new Season();
public static final Season WINTER = new Season();
//私有化構造器
private Season(){}
}
2. 使用 enum 關鍵字創建枚舉類
enum Season{
SPRING,
SUMMER,
AUTUMN,
WINTER;
}
枚舉類常用方法:
> valueOf(String name) : 根據name枚舉類對象名稱,獲取指定的枚舉類對象
> values() : 獲取當前枚舉類中所有枚舉類對象的數組
3. 枚舉類實現接口
public enum Season implements MyInterface{
SPRING{
public void show(){
System.out.println("春天");
}
},
SUMMER{
public void show(){
System.out.println("夏天");
}
},
AUTUMN{
public void show(){
System.out.println("秋天");
}
},
WINTER{
public void show(){
System.out.println("冬天");
}
};
// @Override
// public void show() {
// System.out.println("季節");
// }
}
一、註解: jdk1.5後出的新特性,註解是一個元數據。是一個代碼級別的說明。
在 Java 中以 “@註解名”的方式呈現
1. JDK 內置的常用註解
@Override: 限定重寫父類方法, 該註釋只能用於方法
@Deprecated: 用於表示某個程序元素(類, 方法等)已過時
@SuppressWarnings: 抑制編譯器警告
2. 自定義註解
public @interface MyAnnotation{
String value() default "atguigu";
}
3. 元註解
* @Retention : 描述註解的生命週期
* @Target : 描述註解可以修飾哪些程序元素
* @Documented : 描述註解可以隨之生成說明文檔 (該註解生命週期必須爲 RUNTIME)
* @Inherited: 被它修飾的 Annotation 將具有繼承性.
07.基礎API與異常處理
作者: 風離紫竹
一、包裝類(包裹類 Wrapper)
Java針對八種基本數據類型提供了對應的包裝類
基本數據類型 包裝類
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
1. 基本數據類型與包裝類之間的轉換
* 裝箱:將基本數據類型轉換成對應的包裝類
* ①通過對應包裝類的構造器
* ②通過對應包裝類的靜態方法 valueOf()
*
* 拆箱:將包裝類轉換成對應的基本數據類型
* ①通過對應包裝類 xxxValue() 方法。 xxx:表示基本數據類型
2. 自動裝箱和自動拆箱
int i = 10;
Integer num = i; //自動裝箱
int i1 = num; //自動拆箱
注意: Integer提供了一個小的緩存(-128~127)之間,若需要裝箱的值在該取值範圍內
則從緩存中取一個實例。若超出該取值範圍則重新 new 一個 Integer 實例
Integer num1 = 100;
Integer num2 = 100;
System.out.println(num1 == num2);//true
Integer num3 = 129;
Integer num4 = 129;
System.out.println(num3 == num4); //false
3. 基本數據類型、包裝類 與 String之間的轉換
* 1.基本數據類型、包裝類 轉 String
* ① String str = i + "";
* ② 使用 String 類的靜態方法 valueOf()
* ③ 通過對應包裝類的靜態方法 toString()
*
* 2.String 轉 基本數據類型、包裝類
* ① 通過對應包裝類的構造器
* ② 通過對應包裝類的靜態方法 parseXxx() : Xxx :表示基本數據類型
* 注意:沒有parseChar()
* ③ 通過對應包裝類的靜態方法 valueOf()
二、java.lang.String 類: 不可變的字符序列
String str1 = "abc";
String str2 = new String("abc");
二者之間的區別?
str1 : 代表一個對象,至少在內存中開闢一塊內存空間
str2 : 代表兩個對象,至少在內存中開闢兩塊內存空間
2. String 類的常用方法
* 1. 獲取字符串的方法:
* ①String concat(String str):串接字符串
* ②String substring(int beginIndex):獲取取字符串的子串
* String substring(int beginIndex, endIndex) : 包含頭不包含尾
* ③String toLowerCase()和String toUpperCase():轉換爲小寫/大寫
* ④String trim():刪除首尾空格或製表符
* 2. 搜索方法:
* ①int indexOf(int ch) : 獲取指定字符在字符串中的位置,若沒有指定的字符,返回 -1
* int indexOf(int ch, int fromIndex) : 從指定位置開始搜索
* int indexOf(String str)
* int indexOf(String str, int fromIndex)
* int lastIndexOf(int ch) : 反向獲取指定字符位置
* 3. 判斷方法:
* ① boolean equals(Object obj):判斷是否相等
* boolean equalsIgnoreCase(String str):判斷是否相等,不考慮大小寫
* ② boolean contains(String str) :判斷是否包含某字符串
* ③ boolean startsWith(String str)和 boolean endsWith(String str):判斷是否以指定字符串開始/結尾
* ④ boolean isEmpty():判斷字符串是否爲空
* 4. 其它方法:
* ①length():返回字符串長度
* ②char charAt(int index):返回索引處的字符
* ③將字符數組轉換爲字符串
* 構造器:
* String(char[] ch)
* String(char[] ch, offset, count) : 將數組中一部分轉換爲字符串
* 靜態方法:
* static String copyValueOf(char[] ch)
* static String copyValueOf(char[] ch, offset, count)
* static String valueOf(char[])
* 將字符串轉換字符數組: char[] toCharArray()
* ④String replace(char oldCahr, char newCahr) : 替換字符串中字符
* String replace(String oldStr, String newStr):替換字符串中字符串
* ⑤String[] split(String r):根據指定符號切割
三、StringBuffer 和 StringBuilder : 可變的字符序列,二者具備相同的API
StringBuffer 和 StringBuilder 的區別?
StringBuffer : 是線程安全的,因此效率低
StringBuilder : 是線程不安全的,因此效率高
* StringBuffer 和 StringBuilder 的常用方法:
* ① StringBuffer append(String str) : 添加
* StringBuffer insert(int offset, String str) : 插入
* StringBuffer replace(int start, int end, String str):替換
*
* ② int indexOf(String str) :返回子串的位置索引
* int lastIndexOf()
*
* ③ String substring(int start, int end):取子字符串序列
* ④ StringBuffer delete(int start, int end):刪除一段字符串
* StringBuffer deleteCharAt(int index):刪除指定位置字符
* ⑤ String toString():轉換爲String對象
四、其他常用類
1、java.util.Date : 表示特定的瞬間,精確到毫秒
2、java.text.DateFormat : 用於格式化時間/日期。但是是一個抽象類
|---java.text.SimpleDateFormat : 是 DateFormat 的子類
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
String strDate = sdf.format(date);
System.out.println(strDate);//2015-12-07 09:23:37 星期一
Date newDate = sdf.parse(strDate);
System.out.println(newDate);
3、java.lang.Math : 用於操作數學運算
double ceil(double d) : 返回不小於d的最小整數
double floor(double d): 返回不大於d的最大整數
int round(float f) : 返回最接近f的int型(四捨五入)
long round(double d):返回最接近d的long型
double abs(double d): 絕對值
double max(double d1, double d2) : 返回較大值
int min(int i1, int i2) : 返回較小值
double random() : 返回一個大於等於0.0並且小於1.0的隨機數
五【瞭解】
java.lang.System : 系統類
java.util.Calendar : 日曆類
java.math.BigInteger : 支持任意精度的整數
java.math.BigDecimal : 支持任意精度的小數
一、異常:不可預知的非正常情況
Java中的異常都是以對象形式存在的,一旦某句代碼發生異常,會在該代碼處生成一個異常對象
然後以堆棧式拋出,若不對其進行處理,程序終止運行。
二、異常的結構體系:
java.lang.Throwable : 是所有錯誤和異常的父類
|--- java.lang.Error: 錯誤,一些嚴重的錯誤。 如: 內存溢出,系統錯誤等。 我們在代碼中不做處理
|--- java.lang.Exception: 異常,我們需要儘可能預知並處理的異常。如: 用於輸入有誤、網絡連接中斷等等。
|--- 編譯時異常(受檢異常 checked):編譯時對其進行檢查,若不處理編譯不能通過
|--- 運行時異常(非受檢異常 unchecked):可以保證程序的正常運行。一旦發生該異常,會在該代碼處生成一個異常對象
以堆棧式拋出,若不處理,系統終止運行。
三、異常的處理機制: Java中異常的處理採用的是抓拋模型
“拋”:一旦某句代碼發生異常,會在該代碼處生成一個異常對象然後以堆棧式拋出。(自動拋出/手動拋出)
“抓”:將上述拋出的異常進行捕獲處理
異常的處理方式一:
try{
//可能發生異常的語句
}catch(Exception1 e1){//異常的類型 變量名
//異常的處理語句
}catch(Exception2 e2){
//異常的處理語句
}
……
finally{
//一定被執行的語句
}
①catch 塊可以有多個,一旦與某個catch塊匹配成功,執行相應的語句,其他catch塊將不再執行
②catch 塊可以有多個,若catch塊中的異常類型具備子父類關係,必須“子上父下”
③try-catch可以嵌套的
④finally 是可選的,一旦寫上,一定會被執行,即便有 return
異常的處理方式二: throws 關鍵字 (處理異常的方式是將異常拋出給調用者做具體的處理)
格式:使用在方法的聲明處,後面跟異常的類型
如:
public static void dic(int a, int b) throws NumberFormatException, Exception{}
四、throw 關鍵字: 製造異常
格式: 使用在方法體內,後面跟異常的對象
如:
public static void div(int a, int b){
if(b == 0){
throw new RuntimeException("除數不能爲零");
}
}
【面試題】 throw 和 throws 的區別?
throw 不僅可以拋出Java提供的異常,還可以拋出自定義異常
五、自定義異常
①聲明一個類繼承一個異常類(繼承Exception 該異常爲編譯時異常,繼承RuntimeException該異常爲運行時異常)
②編寫構造器(通常利用構造器爲 getMessage() 方法設置值)
六、異常處理的常用方法
printStackTrace() : 打印異常的詳細信息。
String getMessage() : 返回異常的描述信息
08.集合與泛型
作者: 風離紫竹
一、集合:就像是一種容器。用於存儲、獲取、操作對象的容器。
1. 數組的弊端
①數組的長度不可變 ②數組沒有提供可以查看有效元素個數的方法
2. 集合的特點
①集合的長度是可變的
②集合可以存儲任意類型的對象
③集合只能存儲對象
3. 集合框架
java.util.Collection : 集合層次的根接口
|--- java.util.List: 有序的,可以重複的。
|--- ArrayList: 採用數組結構存儲元素。 查詢操作多時選擇
|--- LinkedList: 採用鏈表結構存儲元素。 增刪操作多時選擇
|--- Vector:
|--- java.util.Set: 無序的,不允許重複。
|--- HashSet : 是 Set 接口的典型實現類。
判斷元素是否存在的依據是:先比較 hashCode 值,若 hashCode 存在,再通過 equals() 比較內容
若 hashCode 值不存在,則直接存儲
注意:重寫 hashCode 和 equals 二者需要保持一致!
|--- LinkedHashSet: 相較於 HashSet 多了鏈表維護元素的順序。遍歷效率高於 HashSet , 增刪效率低於 HashSet
|--- TreeSet : 擁有自己排序方式
|-- 自然排序(Comparable):
①需要添加 TreeSet 集合中對象的類實現 Comparable 接口
②實現 compareTo(Object o) 方法
|-- 定製排序(Comparator)
①創建一個類實現 Comparator 接口
②實現 compare(Object o1, Object o2) 方法
③將該實現類的實例作爲參數傳遞給 TreeSet 的構造器
4. 集合的遍歷
① 增強 for 循環
for(被遍歷集合中元素的數據類型 變量名 : 被遍歷的集合){
}
ArrayList al = new ArrayList();
al.add("AA");
al.add("BB");
for(Object obj : al){
System.out.println(obj);
}
② 使用 Iterator 迭代器
//1)獲取當前集合的迭代器
Iterator it = al.iterator();
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj);
}
/*錯誤的做法:通常一個 hasNext() 配合一個 next() 使用
Iterator it = al.iterator();
while(it.hasNext()){
Object obj = it.next();
System.out.println(it.next());
}*/
③ ListIterator : 列表迭代器,是List特有的迭代器(瞭解)
ListIterator li = al.listIterator();
while(li.hasNext()){
Object obj = li.next();
if(obj.equals("BB")){
li.set("BBBBBBBBBBb");
}
}
二、Map系列集合
java.util.Map : 用於存儲成對對象的集合。具有 key(鍵)-value(值)對映射關係的集合。一個 key 對應着一個 value。 key不允許重複的。
|--- HashMap:是 Map接口的典型實現類。
|--- LinkedHashMap: 相較於 HashMap 多了鏈表維護元素的順序
|--- Hashtable: 是線程安全的,因此效率低
|--- Properties : 用於操作屬性文件
|--- TreeMap : 根據 key 擁有自己的排序方式
|-- 自然排序(Comparable):
|-- 定製排序(Comparator):
//使用 Properties 操作屬性文件
@Test
public void test1() throws FileNotFoundException, IOException{
//1. 創建 Properties 對象
Properties props = new Properties();
//2. 通過 load() 方法加載屬性文件
props.load(new FileInputStream("hello.properties"));
//3. 通過 getProperty() 方法根據key獲取對應的value
String userName = props.getProperty("username");
String password = props.getProperty("password");
System.out.println(userName);
System.out.println(password);
}
1. Map的常用方法:
添加、刪除操作:
Object put(Object key,Object value)
Object remove(Object key)
void putAll(Map t)
void clear()
元素查詢的操作:
Object get(Object key)
boolean containsKey(Object key)
boolean containsValue(Object value)
int size()
boolean isEmpty()
boolean equals(Object obj)
2. Map 的遍歷:
Map map = new HashMap();
map.put("AA", 123);
map.put("BB", 456);
keySet();
//遍歷Map的方式一: 獲取 Map 中所有的 key
Set set = map.keySet();
values();
//遍歷Map的方式二:獲取 Map中所有的 value
Collection coll = map.values();
//遍歷Map的方式三: 獲取Map中所有的 Entry (是Map 的一個內部類,一個Entry對應着Map中的一個key和一個value)
Set entrySet = map.entrySet();
for(Object obj : entrySet){
Entry entry = (Entry)obj;
Object key = entry.getKey();
Object value = entry.getValue();
}
Iterator it = entrySet.iterator();
while(it.hasNext()){
Entry entry = (Entry)it.next();
Object key = entry.getKey();
Object value = entry.getValue();
}
三、
爲什麼使用泛型:若集合中不使用泛型,意味着集合中可以添加任意類型的對象。若需要具體到某一個類型時,需要強制類型轉換
可能引發 ClassCastException
泛型: 在 Java 中以 "<>" 的形式呈現,<> 中寫引用數據類型
用於限制集合中存放元素的類型
1. 在集合中應用泛型
2. 自定義泛型類、接口、方法
class DAO<T>{ // T : Type E:Element K:Key V:Value
private List<T> list = new ArrayList<T>();
public void add(T t){
list.add(t);
}
public T get(int id){
return list.get(id);
}
//自定義泛型方法
public <E> E[] srot(E[] e){
}
}
3. 通配符 ?
雖然 Person 是 Student 的父類,但是 List<Person> 就不是 List<Student> 的父類
//需求:
//public void show(List<Student> list){}
//public void show1(List<Man> list){}
public void show(List<? extends Person> list){}
List<?> : 可以接收任意帶泛型類型的集合
List<? extends Person> : 可以接收 Person 本類類型及 Person子類類型帶泛型類型的集合
List<? super Person> : 可以接收 Person 本類類型及 Person父類類型帶泛型類型的集合
09.IO流與多線程
作者: 風離紫竹
一、IO流的分類
1.按流向不同:輸入流、輸出流(以程序爲主體)
2.按數據不同:字節流、字符流(字節流操作非文本文件 .jpg .avi .rmvb .mp3 字符流操作文本本件 .txt .java)
3.按角色不同:節點流、處理流
二、IO流的結構體系
抽象基類 節點流 緩衝流(處理流的一種)
InputStream FileInputStream BufferedInputStream
OutputStream FileOutputStream BufferedOutputStream(flush() - 用於清空緩衝區)
Reader FileReader BufferedReader (readLine())
Writer FileWriter BufferedWriter (newLine() )
//使用緩衝流完成文件的複製
public static void copyFile(String src, String dest){
//2. 創建緩衝流對象(BufferedInputStream),包裝現有節點流
BufferedInputStream bis = null;
//4. 創建緩衝流對象(BufferedOutputStream), 包裝現有節點流
BufferedOutputStream bos = null;
try {
//1. 創建 FileInputStream 對象,同時打開指定文件
FileInputStream fis = new FileInputStream(src);
bis = new BufferedInputStream(fis);
//3. 創建 FileOutputStream 對象,同時打開指定文件
FileOutputStream fos = new FileOutputStream(dest);
bos = new BufferedOutputStream(fos);
//5. 使用緩衝流讀取指定文件的內容
byte[] b = new byte[1024];
int len = 0;
while((len = bis.read(b)) != -1){
//6. 使用緩衝流將讀取的內容寫到目標文件
bos.write(b, 0, len);
}
// bos.flush(); //用於強制清空緩衝區
} catch (IOException e) {
e.printStackTrace();
} finally {
//7. 關閉流
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
三、對象流: ObjectInputStream & ObjectOutputStream
序列化:將內存中的對象永久的以二進制形式保存到磁盤中
①創建節點流對象
②使用緩衝流包裝節點流(可選的)
③使用對象流包裝緩衝流對象
④進行序列化操作
⑤關閉流
⑥需要序列化對象所屬的類需要實現 java.io.Serializable 接口
⑦提供一個序列號 private static final long serialVersionUID = 1234256L;
注意:static 和 transient 修飾的屬性不能被序列化
// 對象的序列化
@Test
public void test3() {
Person p1 = new Person("張三", 18, new Computer(), "唐朝");
Person p2 = new Person("李四", 28, new Computer(), "唐朝");
Person p3 = new Person("王五", 25, new Computer(), "唐朝");
ObjectOutputStream oos = null;
try {
FileOutputStream fos = new FileOutputStream("person.dat");
BufferedOutputStream bos = new BufferedOutputStream(fos);
oos = new ObjectOutputStream(bos);
oos.writeObject(p1);
oos.writeObject(p2);
oos.writeObject(p3);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
反序列化:將磁盤中的對象讀取
//對象的反序列化
@Test
public void test4() {
ObjectInputStream ois = null;
try {
FileInputStream fis = new FileInputStream("person.dat");
BufferedInputStream bis = new BufferedInputStream(fis);
ois = new ObjectInputStream(bis);
Person p1 = (Person) ois.readObject();
Person p2 = (Person) ois.readObject();
Person p3 = (Person) ois.readObject();
System.out.println(p1);
System.out.println(p2);
System.out.println(p3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
四、控制檯IO :
System.in : “標準”的輸入流
System.out : “標準”的輸出流 ---- 通過 System 類中 setOut() 方法可以改變 println() 的默認輸出位置
System.err : “標準”的錯誤輸出流
打印流 : PrintStream & PrintWriter
五、轉換流: InputStreamReader & OutputStreamWriter
@Test
public void test1(){
BufferedReader br = null;
try {
InputStream in = System.in;
InputStreamReader isr = new InputStreamReader(in);
br = new BufferedReader(isr);
String str = null;
while((str = br.readLine()) != null){
System.out.println("--" + str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(br != null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
七、其他IO流
數據流: DataInputStream & DataOutputStream
隨即存取文件流: RandomAccessFile
>seek(long l)
>getFilePointer();
八、java.io.File 類 : 用於表示文件/目錄。可用於新建、刪除、重命名等基本功能的操作
但是若需要操作文件的內容,File 就無能爲力,需要使用IO流
通常File對象與IO流配合使用
訪問文件名:
getName()
getPath()
getAbsoluteFile()
getAbsolutePath()
getParent()
renameTo(File newName)
文件檢測
exists()
canWrite()
canRead()
isFile()
isDirectory()
獲取常規文件信息
lastModified()
length()
文件操作相關
createNewFile()
delete()
目錄操作相關
mkDir()
mkDirs()
list()
listFiles()
一、多線程
什麼是程序? 爲了完成某項特定的任務,使用某種語言,編寫一組指令的集合。
什麼是進程? 一個正在進行中的程序。
什麼是線程? 在一個進程中執行的一套功能流程,稱爲線程
在一個進程中執行的多套功能流程,稱爲多線程
二、爲什麼使用多線程?
搶佔式策略系統: 系統會分配給每個執行任務的線程一個很小的時間段,當該時間段用完後
系統會剝奪其使用權,交給其他線程去執行
1. 多線程可以提高程序的效率,可以儘可能的利用cpu的資源
2. 增強用戶體驗
三、如何使用多線程?
創建執行線程的方式一:
①創建一個類繼承 Thread 類
②重寫 run() 方法,同時編寫線程執行體
③創建該子類的實例
④調用 start() 方法,啓動線程。默認執行 run() 方法
創建執行線程的方式二:
①創建一個類實現 Runnable 接口
②實現接口中的 run() 方法,同時編寫線程執行體
③創建該實現類的實例
④創建 Thread 實例,將實現類的實例作爲參數,傳遞給Thread的構造器
⑤調用 Thread 類的 start() 方法,啓動線程。默認執行 run() 方法
繼承方式與實現方式的區別?
①當需要多個線程訪問共享數據時,首選使用實現 Runnable 接口的方式
②實現 Runnable 接口,解決了Java中單繼承的侷限性
四、線程的常用方法
currentThread() : 獲取當前線程
getName() : 獲取線程名稱
setName() : 設置線程名稱
start() : 啓動線程
sleep(long millis) : 是一個靜態方法,使當前線程進入睡眠狀態
join() / join(long millis) : 是一個實例方法, 使當前線程進入阻塞狀態
interrupt() : 用於喚醒阻塞狀態的線程
yield() : 線程讓步
isAlive() : 判斷線程是否處於存活狀態
五、線程的優先級(1-10):默認的優先級爲 5。 優先級高並不意味着線程一定先執行, 只不過更多的獲取cpu的資源
MAX_PRIORITY : 10
NORM_PRIORITY : 5
MIN_PRIORITY : 1
getPriority() : 獲取線程的優先級
setPriority() : 設置線程的優先級
六、線程的生命週期
七、線程同步:
模擬售票程序:實現三個窗口同時售票100張
問題: 當三個線程同時訪問共享數據時,出現了 無序、重複、超額售票等多線程安全問題
解決辦法:將多個線程需要訪問的共享數據包裝起來,確保一次只能有一個線程執行流訪問該共享數據
Java爲上述問題也提供了相應的解決辦法
1. 同步代碼塊:
synchronized(同步監視器){
//需要訪問的共享數據
}
同步監視器:俗稱“鎖”,可以使用任意對象充當。但是確保多個線程持有同一把鎖(同一個對象)
2. 同步方法:使用在方法的聲明處,加 synchronized 關鍵字
如:
public synchronized void show(){ }
3. 同步鎖: Lock 接口
注意:必須保證手動的釋放鎖 (unlock())