開學就要大四了,校招也要開始了。想想自己的能力,感覺差了太多太多,暑假都不敢出去玩,想着多花點時間複習總結一下以前的知識,找工作時能用的到。
Java是我大一時自學的,現在會寫但是很多沒用到的概念全給忘了,於是就想複習一下。因爲我已經有了一定的基礎知識,所以這個筆記並不是一個詳盡的Java筆記,而只是記錄我所遺忘或需要加強記憶的部分。
基礎
發展歷史
1995年sun公司推出Java語言,2009年Oracle公司收購sun公司
JDK環境變量配置
JAVA_HOME:配置JDK安裝路徑
PATH/path:配置JDK命令文件的位置,bin
CLASSPATH:配置類庫文件的位置,lib
Java中的註釋
Java有三種類型:單行註釋、多行註釋、文檔註釋
public class HelloWorld{
/**
* 文檔註釋
* @author niujiajun
* @version v1.0
*/
public static void main(String[] args) {
//System.out.println("Java"); 單行註釋
System.out.println("imooc");
/* 多行註釋,以/*開始,以*/結束
* System.out.println("Oracle");
* System.out.println("MySQL");
*/
}
}
文檔註釋:以/*開始,以/結束
使用文檔註釋時還可以使用 javadoc 標記,生成更詳細的文檔信息:
@author 標明開發該類模塊的作者
@version 標明該類模塊的版本
@see 參考轉向,也就是相關主題
@param 對方法中某參數的說明
@return 對方法返回值的說明
@exception 對方法可能拋出的異常進行說明
- 多行註釋:以/開始,以/結束
- 單行註釋:在行前加//
輸出
在System.out.println()輸出時,需要比較變量或處理變量只要加括號就可以了,如:
int a=16;
double b=9.5;
System.out.println("a等於b:" + (a == b));
輸出結果是
a等於b: false
print和println的區別是後者會換行
輸入
輸入需要用到java.util.Scanner包
Scanner input = new Scanner(System.in);//建立Scanner對象
int i = input.nextInt();//新建整型變量接收輸入的數據
javadoc生成文檔
通過javadoc命令從文檔註釋中提取內容,生成程序的 API 幫助文檔
javadoc -d 文件夾名稱 java文件
運算符
算術運算符++,–
++自增1,–自減1,自增和自減運算符只能用於操作變量,不能直接用於操作數值或常量!例如 5++ 、 8– 等寫法都是錯誤的。
++ 和 – 既可以出現在操作數的左邊,也可以出現在右邊,但結果是不同滴
左邊
運行結果:
右邊
運行結果:
賦值運算符
關於switch
1、switch 後面小括號中表達式的值必須是整型或字符型
2、case 後面的值可以是常量數值,如 1、2;也可以是一個常量表達式,如 2+2 ;但不能是變量或帶有變量的表達式,如 a * 2。
3、可以把功能相同的 case 語句合併起來,如
數組
聲明數組
數組的聲明有兩種方式
數組的元素類型 數組名[];
數組的元素類型[] 數組名;
分配空間
語法:
數組名 = new 數據類型[數組長度];
也可同時進行聲明和分配空間:
數據類型[] 數組名 = new 數據類型[數組長度];
此時數組長度不能爲空
初始化
數據類型 數組名[] = {值1,值2,值3...};
又或者
數據類型 數組名[] = new 數據類型[]{值1,值2,值3...};
此時數據類型後的[]中應爲空
操作
以升序排序
Arrays.sort(數組名);
轉爲String
Arrays.toString(數組名);
PS:此方法並不是返回排序後的數組而是將原數組排序
Class類
重載
如果同一個類中包含了兩個或兩個以上方法名相同、方法參數的個數、順序或類型不同的方法,則稱爲方法的重載,也可稱該方法被重載了。如下所示 4 個方法名稱都爲 show ,但方法的參數有所不同,因此都屬於方法的重載:
PS:方法的重載與方法的修飾符或返回值沒有關係
成員變量和局部變量的區別
Java會給成員變量賦一個初始值
Java不會給局部變量賦初始值
成員變量和局部變量同名時,在方法內局部變量有更高的優先級
構造方法
構造方法是定義在Java類中的一個用來初始化對象的方法,名稱與類名相同沒有返回值。
當沒有指定構造方法時,系統會自動添加無參的構造方法。
當有指定的構造方法時,無論是有參,無參的構造方法,都不會自動添加無參的構造方法。
static
使用 static 可以修飾變量、方法和代碼塊。被static修飾的變量叫類變量,否則叫實例變量;被static修飾的方法叫類方法或靜態方法,否則叫實例方法。
類變量和類方法屬於類,實例變量和實例方法屬於對象。當類第一次使用時,只會給類方法和類變量分配內存,而不會給實例變量和實例方法分配內存。只有創建對象後,纔會給實例變量和實例方法分配內存。類的所有對象共用類變量和類方法,而實例變量和實例方法只被所創建的對象使用。
靜態成員可以使用類名直接訪問,也可以使用對象名進行訪問,推薦用類名訪問。
實例方法可以調用該類中的實例方法或類方法,而類方法只能調用該類的類方法,不能直接調用實例方法。如果希望在靜態方法中調用非靜態變量,可以通過創建類的對象,然後通過對象來訪問非靜態變量。
在類的聲明中,可以包含多個初始化塊,當創建類的實例時,就會依次執行這些代碼塊。如果使用 static 修飾初始化塊,就稱爲靜態初始化塊。
需要特別注意:靜態初始化塊只在類加載時執行,且只會執行一次,同時靜態初始化塊只能給靜態變量賦值,不能初始化普通的成員變量
例如:
運行結果:
通過輸出結果,我們可以看到,程序運行時靜態初始化塊最先被執行,然後執行普通初始化塊,最後才執行構造方法。由於靜態初始化塊只在類加載時執行一次,所以當再次創建對象 hello2 時並未執行靜態初始化塊。
封裝
面向對象的三大特性:繼承,封裝和多態
封裝的概念:將類的信息隱藏在類的內部,不允許外部程序直接訪問,而是通過該類提供的方法實現對隱藏信息的操作和訪問。
封裝的好處:
- 只能通過規定的方法訪問數據。
- 隱藏類的實例細節,方便修改和實現。
訪問修飾符
訪問修飾符 | 本類 | 同包 | 子類 | 其他 |
---|---|---|---|---|
private | √ | |||
缺省/默認 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
內部類
定義:
內部類( Inner Class )就是定義在另外一個類裏面的類。與之對應,包含內部類的類被稱爲外部類。作用
內部類提供了更好的封裝,可以把內部類隱藏在外部類之內,不允許同一個包中的其他類訪問該類
內部類的方法可以直接訪問外部類的所有數據,包括私有的數據
內部類所實現的功能使用外部類同樣可以實現,只是有時使用內部類更方便
3.分類
成員內部類
靜態內部類
方法內部類
匿名內部類
成員內部類
內部類定義在外部類的內部,相當於外部類的一個成員變量的位置,內部類可以使用任意訪問控制符,如 public 、 protected 、 private 等
內部類中定義的 test() 方法可以直接訪問外部類中的數據,而不受訪問控制符的影響,如直接訪問外部類中的私有屬性a
定義了成員內部類後,必須使用外部類對象來創建內部類對象,而不能直接去 new 一個內部類對象,即:內部類 對象名 = 外部類對象.new 內部類( );
外部類是不能直接使用內部類的成員和方法滴
可先創建內部類的對象,然後通過內部類的對象來訪問其成員變量和方法。
5.如果外部類和內部類具有相同的成員變量或方法,內部類默認訪問自己的成員變量或方法,如果要訪問外部類的成員變量,可以使用 this 關鍵字。如:
靜態內部類
1、 靜態內部類不能直接訪問外部類的非靜態成員,但可以通過* new 外部類().成員* 的方式訪問
2、 如果外部類的靜態成員與內部類的成員名稱相同,可通過“類名.靜態成員”訪問外部類的靜態成員;如果外部類的靜態成員與內部類的成員名稱不相同,則可通過“成員名”直接調用外部類的靜態成員
3、 創建靜態內部類的對象時,不需要外部類的對象,可以直接創建 內部類 對象名= new 內部類();
方法內部類
方法內部類就是內部類定義在外部類的方法中,方法內部類只在該方法的內部可見,即只在該方法內可以使用。
注意:由於方法內部類不能在外部類的方法以外的地方使用,因此方法內部類不能使用訪問控制符和 static 修飾符。
繼承
繼承是Java面向對象編程的一個重要特點,指一種由已有類創建新類的機制。利用繼承,可以先編寫一個共有屬性的一般類,再根據一般類編寫具有特殊屬性的新類。新類繼承一般類的屬性和方法,並根據需要增加新的屬性和方法。
所謂子類繼承父類的成員變量和方法,就好像他們是在子類中直接聲明的一樣,可以被子類中自己定義的任何實例方法操作和調用。
子類對父類成員變量和方法的繼承性:
private | 缺省/默認 | protected | public |
---|---|---|---|
同一包 | √ | √ | |
不同包 | √ |
繼承的初始化順序
先初始化父類再初始化子類
先初始化屬性,再初始化構造方法
總的順序是先初始化父類的屬性,再初始化父類的構造方法,然後初始化子類的屬性,最後初始化子類的構造方法。
重寫@override
如果子類對繼承父類的方法不滿意,可以重寫從父類繼承的方法,當調用方法時會優先調用子類的方法。
注意:
* 返回值類型
* 方法名
* 參數類型及個數
都要與父類繼承的方法相同,才叫方法的重寫
final
final關鍵字可以修飾類,方法,屬性和變量
final修飾類,則類不允許被繼承
final修飾方法,則方法不允許被覆蓋(重寫)
final修飾屬性,則該類的屬性不會進行隱式的初始化(java自動賦初值),初始化時必須賦一個值,或在構造方法中賦值(二選一)
final修飾變量,則該變量只能賦一次值,即爲常量
super
在子類的內部使用,可以代表父類對象。既可以訪問父類的屬性也可以訪問父類的方法。
注意:
子類的構造過程中必須調用父類的構造方法。
如果子類的構造方法中沒有顯式調用父類的構造方法,則系統默認調用父類無參的構造方法,即隱式調用,super();
如果顯式調用構造方法,必須在子類構造方法的第一行。
如果子類構造中既沒有顯式調用父類的構造方法,而父類又沒有無參的構造方法,則編譯出錯。
Object類
Object類是所有類的父類,如果一個類沒有使用extends關鍵字明確標識繼承另一個類,那麼這個類默認繼承Object類。
Object類中的方法,適合所有子類。
多態
java中的多態
字面上的意思是對象的多種形態。
- 引用多態:父類的引用既可以指向本類的對象,也可以指向子類的對象,如:
Animal obj1 = new Animal();//指向本類
Animal obj2 = new Dog();//指向子類
方法多態:
創建本類對象時,調用的方法爲本類方法
創建子類對象時,調用的方法是子類重寫的方法或繼承的方法,不能調用子類獨有的方法。
/**
* 接上段代碼
*/
obj1.eat();//調用本類方法
obj2.eat();//調用子類重寫或繼承的方法
//obj2.watchDoor();不能調用子類獨有的方法
多態中的引用類型轉換
- 向上類型轉換(隱式/自動類型轉換),是小類型到大類型的轉換
Dog dog = new Dog();
Animal animal = dog;//向上類型轉換
- 向下類型轉換(強制類型轉換),是大類型到小類型的轉換,存在溢出的風險
Dog dog = new Dog();
Animal animal = dog;
Dog dog = (Dog)animal;
/*
* Animal animal = new Animal();
* Dog dog = (Dog)animal;
* 編譯不出錯,運行過程中出錯。
*/
instanceof
instanceof運算符是二目運算符,左邊的操作元是一個對象,右邊是一個類。當左邊的對象是右邊的類或子類創建的對象時,返回true,否則返回false。
/**
* 此例可以轉換
*/
Dog dog = new Dog();
Animal animal = dog;
if(animal instanceof Dog){
Dog dog = (Dog) animals;
}else{
System.out.println("無法轉換");
}
抽象類abstract
定義
使用abstract修飾的類叫抽象類
應用場景
在某些情況下,某個父類只是知道其子類應該包含怎樣的方法,但無法準確知道子類如何實現這些方法
從多個具有相同特徵的類中抽象出一個抽象類,以這個抽象類作爲子類的模板,從而避免了子類設計的隨意性
作用
限制規定子類必須實現某些方法,但不關注實現細節。
使用規則
abstract定義抽象類
abstract定義抽象方法,只有聲明,不需要實現
包含抽象方法的類是抽象類
抽象類中可以包含普通方法,也可以沒有抽象方法
抽象類不能直接創建,可以定義引用變量
/**
* 父類
*/
public abstract class Animal {//abstract定義抽象類
public abstract void eat();
public abstract void work();//abstract定義抽象方法,只有聲明,不需要實現
}
/**
* 子類1
*/
public class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨頭");
}
@Override
public void work() {
System.out.println("看門");
}
}
/**
* 子類2
*/
public class Cat extends Animal{
public void eat(){
System.out.println("貓吃魚");//子類要實現父類的抽象方法
}
@Override
public void work() {
System.out.println("捉老鼠");
}
}
/**
* 初始化
*/
public class test {
public static void main(String[] args) {
Animal dog = new Dog();//抽象類不能直接創建,可以定義引用變量,
//不能直接創建,Animal animal = new Animal();
dog.eat();
dog.work();
Animal cat = new Cat();
cat.eat();
cat.work();
}
}
接口
概念
類是一種具體實現體,而接口定義了某一些類所需要遵守的規範,接口不關心這些類的內部數據,也不關心這些類裏方法的實現細節,它只規定這些類裏必須提供某些方法。
定義
接口通過interface關鍵字來定義:
修飾符 interface 接口的名字
接口就是用來被繼承,被實現的,修飾符不能使用private和protected,一般建議用public。
接口中的屬性只能是常量,即定義是不添加* public static final *修飾符,系統也會加上。
接口中的方法只能是抽象方法,即使定義時不添加pubic abstract 修飾符,系統也會自動加上。
即使不給接口添加abstract關鍵字,系統也會默認加上。
使用
接口可以同時實現多個,必須放在繼承之後。
同abstract類似,接口不能直接創建,但可以用接口的引用指向一個實現了接口的對象:
//ClassA implements InterfaceA
InterfaceA a = new ClassA();
abstract類與接口的比較
abstract類和接口都可以有abstract方法
接口只可以有常量,不能有變量,而abstract類中既可以有常量也可以有變量
abstract類可以有非abstract方法,接口不可以
在設計程序時應當根據具體的分析來確定是使用抽象類還是接口。abstract類除了提供重要的需要子類去實現的abstract方法外,還可以提供子類可以繼承的變量和非abstract方法。如果某個問題需要使用繼承才能更好的解決,比如子類除了需要實現父類的abstract方法外,還需要從父類繼承一些變量或一些重要的非abstract方法,就可以考慮使用abstract類。如果某個問題不需要繼承,只是需要若干個類給出某些重要的abstract方法的實現細節,就可以考慮使用接口。
匿名內部類
- 實例1:不使用匿名內部類來實現抽象方法
abstract class Person {
public abstract void eat();
}
class Child extends Person {
public void eat() {
System.out.println("eat something");
}
}
public class Demo {
public static void main(String[] args) {
Person p = new Child();//從這對比下面的例子可以看出匿名類實際上是子類
p.eat();
}
}
**運行結果:**eat something
可以看到,我們用Child繼承了Person類,然後實現了Child的一個實例,將其向上轉型爲Person類的引用
但是,如果此處的Child類只使用一次,那麼將其編寫爲獨立的一個類豈不是很麻煩?
這個時候就引入了匿名內部類
- 實例2:匿名內部類的基本實現
abstract classPerson {
public abstract void eat();//匿名類的類體不可以聲明static成員變量和static方法
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
**運行結果:**eat something
可以看到,我們直接將抽象類Person中的方法在大括號中實現了
這樣便可以省略一個類的書寫
並且,匿名內部類還能用於接口上
- 實例3:在接口上使用匿名內部類
interface Person {
public void eat();
}
public class Demo {
public static void main(String[] args) {
Person p =new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
**運行結果:**eat something
由上面的例子可以看出,只要一個類是抽象的或是一個接口,那麼其子類中的方法都可以使用匿名內部類來實現
摘自匿名內部類的解釋
- 高階:
interface Product{
public double getPrice();
public String getName();
}
public class TestAnonymous{
public void test(Product p){
System.out.println("購買了一個"+p.getName()+",花掉了"+p.getPrice());
}
public static void main(String[] args){
TestAnonymous ta = new TestAnonymous();
ta.test(new Product(){
public double getPrice(){
return 567;
}
public String getName(){
return "AGP顯卡";
}
});
}
}
異常類
所謂異常就是程序運行時可能出現一些錯誤。
所有的異常類都是Exception的子類,而Exception和Error又同爲Throwable的子類。
Error類的子類又有虛擬機錯誤(VitrualMachineError)和線程鎖死(ThreadDeath)等一類,這類錯誤一般不會出現,出現的話程序就徹底崩潰了。
Exception類一般是由編碼,環境,用戶操作輸入出現等問題所引起的,其子類包括運行時異常(RunTimeException)和檢查異常。
運行時異常又包含空指針異常,數組下標越界異常,類型轉換異常,算術異常等子類,它們都是由JVM自動捕獲自動拋出,出現運行時異常一般是代碼編寫問題。
檢查異常則多種多樣,如文件異常(IOException),SQL異常(SQLException)等,這類異常需要自己手動添加捕獲處理語句。
try-catch語句
try-catch語句可以用來處理異常,其中try部分捕獲異常,catch部分處理異常。
try{
//包含可能發生異常的語句
}
catch(ExceptionSubClass e){
//處理
}
catch(ExceptionSubClass2 e){
...
}
catch中的參數都是Exception類或Exception的子類,捕獲異常時應遵循先小後大的原則。
異常對象可以通過以下方法得到或輸出錯誤信息:
public String getMessage();
public void printStackTrace();
public String toString();
finally子語句
語法格式:
try{}
catch(ExceptionSubClass e){}
finally{}
其執行機制是,在執行try-catch語句後,執行finally子語句。也就是說,無論在try部分是否發生過異常,finally子語句都會被執行。
注意:
如果在try-catch語句中執行了return語句,那麼finally子語句仍然會被執行
如果在try-catch語句中執行了程序退出代碼,即執行了System.exit(0);,將不執行finally子語句。
如果try-catch-finally語句都沒有return,則會調用語句塊之外的return,注意,如果方法體中執行了return語句,則其後的語句都不會再執行。
異常拋出
public void 方法名(參數) throws 異常{
//調用會拋出異常的方法或:
throw new Exception();
}
throw
將產生的異常拋出,用在方法體內
throws
聲明將要拋出何種類型的異常,可以拋出一個或多個異常
自定義異常
需要繼承Exception類或其子類。
異常鏈
一個異常如果是由另一個異常引起的,這種鏈式反應就可以叫做異常鏈。如在try-catch捕獲到一個異常後再創建一個新的異常,從而將舊的異常包裝成新的異常,然後拋出新的異常。
void test(){
try{
...
}catch(Exception1 e){
Exception2 e2 = new Exception2("異常");
e2.initCause(e2);
throw e2;
//或者
// Exception2 e2 = new Exception2(e);
}
}
String
首先需要注意的是,和Java中的包裝類一樣,當通過賦值等號給變量賦相同的值的時候,系統會默認將其指向同一塊內存,而通過new方法創建對象時,不管內容是否相同,都會分配一塊新的內存,此時使用 ”==” 比較時也爲 ”false”。如果只需比較內容是否相同,應使用 ”equals()” 方法。
* ==: 判斷兩個字符串在內存中首地址是否相同,即判斷是否是同一個字符串對象 *
* equals(): 比較存儲在兩個字符串對象中的內容是否一致 *
如:
結果:
字符串的不變性
String 對象創建後則不能被修改,是不可變的,所謂的修改其實是創建了新的對象,所指向的內存空間不同。如果需要一個可以改變的字符串,我們可以使用StringBuffer或者StringBuilder。
String類常用方法
注意:
字符串 str 中字符的索引從0開始,範圍爲 0 到 str.length()-1
使用 indexOf 進行字符或字符串查找時,如果匹配返回位置索引;如果沒有匹配結果,返回 -1
使用 substring(beginIndex , endIndex) 進行字符串截取時,包括 beginIndex 位置的字符,不包括 endIndex 位置的字符
StringBuilder和StringBuffer
因爲String字符串具有不變性,每次操作字符串都要創建新的字符串對象,當頻繁操作字符串時,就會額外產生很多臨時變量。使用 StringBuilder 或 StringBuffer 就可以避免這個問題。至於 StringBuilder 和StringBuffer ,它們基本相似,不同之處,StringBuffer 是線程安全的,而 StringBuilder 則沒有實現線程安全功能,所以性能略高。因此一般情況下,如果需要創建一個內容可變的字符串對象,應優先考慮使用 StringBuilder 類。
常用方法:
相比String類,StringBuilder和StringBuffer多了追加和插入操作。這些操作修改了 str 對象的值,而沒有創建新的對象,這就是 StringBuilder 和 String 最大的區別。
Java中的包裝類
Java中有int、float、double、boolean、char 等基本數據類型,基本類型不具備對象的特性的,不能調用方法、功能簡單。。。,爲了讓基本數據類型也具備對象的特性, Java 爲每個基本數據類型都提供了一個包裝類,這樣我們就可以像操作對象那樣來操作基本數據類型。
基本類型和包裝類之間的對應關係:
包裝類主要提供了兩大類方法:
將本類型和其他基本類型進行轉換的方法
將字符串和本類型及包裝類互相轉換的方法
以Interger舉例
Integer 包裝類的構造方法:
如下代碼所示:
Integer包裝類的常用方法:
基本類型和包裝類之間的互相轉換(以 Integer 爲例)
在 JDK1.5 引入自動裝箱和拆箱的機制後,包裝類和基本類型之間的轉換就更加輕鬆便利了。
裝箱:把基本類型轉換成包裝類,使其具有對象的性質,又可分爲手動裝箱和自動裝箱
拆箱:和裝箱相反,把包裝類對象轉換成基本類型的值,又可分爲手動拆箱和自動拆箱
Java 中基本類型和字符串之間的轉換(以 Integer 爲例)
基本類型轉換爲字符串有三種方法:
使用包裝類的 toString() 方法
使用String類的 valueOf() 方法
用一個空字符串加上基本類型,得到的就是基本類型數據對應的字符串
字符串轉換成基本類型有兩種方法:
調用包裝類的 parseXxx 靜態方法
調用包裝類的 valueOf() 方法轉換爲基本類型的包裝類,會自動拆箱
PS:其他基本類型與字符串的相互轉化這裏不再一一列出,方法都類似
常用類
使用 Date 和 SimpleDateFormat 類表示時間
在程序開發中,經常需要處理日期和時間的相關數據,此時我們可以使用 java.util 包中的 Date 類。這個類最主要的作用就是獲取當前時間,我們來看下 Date 類的使用:
使用 Date 類的默認無參構造方法創建出的對象就代表當前時間,我們可以直接輸出 Date 對象顯示當前的時間,顯示的結果如下:
其中, Wed 代表 Wednesday (星期三), Jun 代表 June (六月), 11 代表 11 號, CST 代表 China Standard Time (中國標準時間,也就是北京時間,東八區)。
從上面的輸出結果中,我們發現,默認的時間格式不是很友好,與我們日常看到的日期格式不太一樣,如果想要按指定的格式進行顯示,如 2014-06-11 09:22:30 ,那該怎麼做呢?
此時就到了 java.text 包中的 SimpleDateFormat 類大顯身手的時候了!!可以使用 SimpleDateFormat 來對日期時間進行格式化,如可以將日期轉換爲指定格式的文本,也可將文本轉換爲日期。
- 使用 format() 方法將日期轉換爲指定格式的文本
代碼中的 “yyyy-MM-dd HH : mm : ss” 爲預定義字符串, yyyy 表示四位年, MM 表示兩位月份, dd 表示兩位日期, HH 表示小時(使用24小時制), mm 表示分鐘, ss 表示秒,這樣就指定了轉換的目標格式,最後調用 format() 方法將時間轉換爲指定的格式的字符串。
運行結果:* 2014-06-11 09:55:48 *
2 . 使用 parse() 方法將文本轉換爲日期
代碼中的 “yyyy年MM月dd日 HH : mm : ss” 指定了字符串的日期格式,調用 parse() 方法將文本轉換爲日期。
運行結果:
一定要注意哦:
1、 調用 SimpleDateFormat 對象的 parse() 方法時可能會出現轉換異常,即 ParseException ,因此需要進行異常處理
2、 使用 Date 類時需要導入 java.util 包,使用 SimpleDateFormat 時需要導入 java.text 包
Calendar 類的應用
Date 類最主要的作用就是獲得當前時間,同時這個類裏面也具有設置時間以及一些其他的功能,但是由於本身設計的問題,這些方法卻遭到衆多批評,不建議使用,更推薦使用 Calendar 類進行時間和日期的處理。
java.util.Calendar 類是一個抽象類,可以通過調用 getInstance()靜態方法獲取一個 Calendar 對象,此對象已由當前日期時間初始化,即默認代表當前時間,如 Calendar c = Calendar.getInstance();
那麼如何使用 Calendar 獲取年、月、日、時間等信息呢?我們來看下面的代碼:
其中,調用 Calendar 類的 getInstance() 方法獲取一個實例,然後通過調用 get() 方法獲取日期時間信息,參數爲需要獲得的字段的值, Calendar.Year 等爲 Calendar 類中定義的靜態常量。
運行結果:
Calendar 類提供了 getTime() 方法,用來獲取 Date 對象,完成 Calendar 和 Date 的轉換,還可通過 getTimeInMillis() 方法,獲取此 Calendar 的時間值,以毫秒爲單位。如下所示:
運行結果:
使用 Math 類操作數據
Math 類位於 java.lang 包中,包含用於執行基本數學運算的方法, Math 類的所有方法都是靜態方法,所以使用該類中的方法時,可以直接使用類名.方法名,如: Math.round();
常用的方法:
Java集合框架
Java中的集合類是一種工具,就像是容器,儲存任意數量的具有共同屬性的對象
作用
在類的內部,對數據進行組織
簡單而快速的搜索大數量的條目
有的集合接口,提供了一系列排列有序的元素,並且可以在序列中間快速的插入或者刪除有關元素
有的集合接口,提供了映射關係,可以通過關鍵字(key)去快速查找到對應的唯一對象,而這個關鍵字可以是任意類型
與數組的對比–爲何選擇集合而不是數組
數組的長度固定,集合長度可變
數組只能通過下標訪問元素,類型固定,而有的集合可以通過任意類型查找所映射的具體對象
集合框架
Collection存儲單個對象,而Map存儲鍵值對。
泛型
集合中的元素可以是任意的對象(其保存的是對象的引用),如果把某個對象放入集合,則會忽略他的類型,而把他當作Object處理,所以通過get方法取出後還需強制類型轉化。
泛型則是規定了某個集合只可以存放特定類型及其子類型的對象,會在編譯期間進行類型檢查,可以直接按指定類型獲取集合元素,不需要類型轉換。
泛型的聲明方法只比普通的集合多一個尖括號加指定類型,如:
public List<Course> courses= new ArrayList<Course>();
操作與普通集合完全相同。
* 注意:*
泛型集合中的限定類型,不能使用基本數據類型
可以通過使用包裝類限定允許存入的基本數據類型
PS:不適用泛型的普通集合能添加基本類型是因爲自動裝箱將基本類型轉成了包裝類。
Collection
Collection接口是List,Set和Queue接口的父類,定義了增刪改查的操作。
List
List是元素有序並且可以重複的集合,被稱爲序列
List可以精確的控制每個元素的插入位置,或刪除某個位置的元素
ArrayList–數組序列,是List的一個重要實現類,因爲List是接口不能直接創建對象,需要通過ArrayList創建,如:
public List coursesToSelect= new ArrayList();
List中,多次添加某個對象,則會創建多個對象,但其指向同一塊內存
ArrayList底層是由數組實現的
Add
Course cr1 = new Course("1", "數據結構");
coursesToSelect.add(cr1);//直接添加對象
Course cr2 = new Course("2", "C語言");
coursesToSelect.add(0, cr2);//將對象添加到指定位置,原位置已有內容則和後面內容一起順延一位
// 當添加的位置沒有按順序遞增時會拋出數組下標越界異常
// Course cr3 = new Course("3", "test");
// coursesToSelect.add(4, cr3);
Course[] course = { new Course("3", "離散數學"), new Course("4", "彙編語言") };
coursesToSelect.addAll(Arrays.asList(course));//通過Array.asList()添加一個對象數組
Course[] course2 = { new Course("5", "高等數學"), new Course("6", "大學英語") };
coursesToSelect.addAll(2, Arrays.asList(course2));//將對象數組添加到指定位置
Remove
coursesToSelect.remove(cr1);//刪除指定某位置對象
Course cr1 = (Course) coursesToSelect.get(0);
coursesToSelect.remove(cr1);//刪除指定對象,此時cr1獲得的是引用,所以如果list中有兩個執向相同地址的引用,不管get方法取自誰,都會先刪除排序靠前的那個元素,當執行兩次刪除方法時,則刪除掉兩個元素
//注意
//Course cr1 = new Course("參數");
//coursesToSelect.remove(cr1);
//這樣並不能刪除指定對象,即便參數相同,但因爲引用不同,指向內存不同,故無法刪除
Course[] courses = { (Course) coursesToSelect.get(4), (Course) coursesToSelect.get(5) };
coursesToSelect.removeAll(Arrays.asList(courses));//批量刪除,即使取出序號不相鄰也可執行,其內部機制是將對象數組取出,分別執行刪除單個對象
Modify
coursesToSelect.set(4, new Course("7", "毛概"));//修改指定位置元素
Get
/**
* 通過for循環取得List中的元素的方法
*
* @param args
*/
public void testGet() {
int size = coursesToSelect.size();
System.out.println("有如下課程待選:");
for (int i = 0; i < size; i++) {
Course cr = (Course) coursesToSelect.get(i);
System.out.println("課程:" + cr.id + ":" + cr.name);
}
}
/**
* 通過迭代器Iterator來遍歷List
*
* @param args
*/
public void testIterator() {
// 通過集合的iterator方法,取得迭代器的實例
Iterator<Course> it = coursesToSelect.iterator();
System.out.println("有如下課程待選(通過迭代器訪問):");
while (it.hasNext()) {
Course cr = it.next();
System.out.println("課程:" + cr.id + ":" + cr.name);
}
}
/**
* 通過for each方法訪問集合元素
*
* @param args
*/
public void testForEach() {
System.out.println("有如下課程待選(通過for each訪問):");
for (Object obj : coursesToSelect) {
Course cr = (Course) obj;
System.out.println("課程:" + cr.id + ":" + cr.name);
}
}
Set
Set與Collection最大的不同是其內部元素是無序且不可重複的,被稱爲集(這裏的無序是指引用不同)
HashSet–哈希集,是Set的一個重要實現類,同ArrayList的地位一樣,在創建對象時使用:
Set courses = new HashSet();
因爲Set是無序的,所以沒有get方法,也不能通過for循環get出遍歷全部對象,自能通過foreach和iterator遍歷出全部對象,並且每次遍歷出的順序都不一樣。
Set中,添加某個對象,無論添加多少次, 最終只會保留一個該對象(的引用), 並且,保留的是第一次添加的那一個
Set中還可以添加一個null元素,但也只能添加一個
Map
Map提供了一種映射關係,其中的元素是以鍵值對(key-value)的形式存儲的,能夠實現根據key快速查找value
Map中的鍵值對以Entry類型的對象實例形式存在
鍵(key值)不可重複,value值可以
每個鍵最多隻能映射到一個值
Map接口提供了分別返回key值集合,value值集合以及Entry(鍵值對)集合的方法
Map支持泛型,形式如:Map < k,V >
HashMap類
HashMap是Map的一個重要實現類,也是最常用,基於哈希表實現
HashMap中的Entry對象是無序排列的
key值和value值都可以爲null,但是一個HashMap只能有一個key值爲null的映射(key值不可重複)
增
通過put方法就可以添加新的元素,已存在key則修改Value值,不存在則創建
students.put(ID, newStudent);
刪
通過remove方法就可以指定key值的元素,當key值不存在時返回null
students.remove(ID);
改
put和replace都支持修改元素操作,replace是JDK8中新增加的方法,實現機制更簡單。二者都會首先判斷key值是否存在,不存在會返回null,存在則修改。
students.put(ID,newValue);
students.replace(k, v);
查
利用keySet遍歷Map:keySet方法返回是key值的Set集,遍歷此Set集然後通過key就可get到對應的value。通過get方法取出Value時,當存在key就返回對應Value,不存在則返回null。
Set<String> keySet = students.keySet();
// 遍歷keySet,取得每一個鍵,再調用get方法取得每個鍵對應的value
for (String stuId : keySet) {
Student st = students.get(stuId);
if (st != null)
System.out.println("學生:" + st.name);
System.out.println("取得鍵:" + stuId);
}
利用entrySet遍歷Map:entrySet方法返回的是Entry鍵值對的對象,通過getkey和getvalue取出鍵值對的鍵和值
Set<Entry<String, Student>> entrySet = students.entrySet();
for (Entry<String, Student> entry : entrySet) {
System.out.println("取得鍵:" + entry.getKey());
System.out.println("對應的值爲:" + entry.getValue().name);
}
關於集合框架的其他知識點
Contains
List中的contains
一些方法如contains,內部機制是首先遍歷集合再對比object,相同返回true,不同返回false,這些方法都要用到equals,但equals默認對比的是兩個對象,即使兩個對象內容相同,如果內存不同還是會返回false,此時就要重寫equals方法
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;//首先比較對象引用,引用相同返回true
if (obj == null)
return false;//當對象是null時,則返回false
if (!(obj instanceof Course))
return false; // 當obj不是由Course或其子類創建的對象時返回false
Course other = (Course) obj;//此時開始對比對象內容,先將Object類轉爲子類
if (name == null) {
if (other.name != null)
return false; //噹噹前name爲null,而對比對象name不爲null,返回false
} else if (!name.equals(other.name))
return false;//噹噹前對象不爲null,對比對象name不等於當前對象name,返回false
return true;//其他則返回true
}
此例可以作爲重寫equals的模板
Set中的contains
Map中的contains和List的不同是其要對比HashCode和equals兩個方法,所以只比較內容應重寫這兩個方法。eclipse提供了自動重寫HashCode和equals,在源碼(Alt + Shift + S)中可以找到
hashCode的重寫
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
Map中的contains
Map中有containsKey和ContainsValue兩個方法判斷是否包含對應的key和value,也是遍歷和equals,同Set一樣需要重寫HashCode和equals方法。
indexOf和lastIndexOf
indexOf和lastIndexOf的實現機制是首先遍歷所有整個集合,當集合中的對象等於指定對象時返回序號,不包含則返回-1,當出現同樣的元素時,index返回正序第一個,lastindex返回倒序第一個。
因爲也要調用equals方法,所以當需要對比內容時也要重寫equals。
Collections.sort排序
此方法可以對序列進行排序,數字按升序,字符串按先數字,再大寫字母,再小寫字母的順序。
sort()中傳入的參數需要實現* Comparable *接口或一個list,一個Comparator(比較規則)
另外Collections還有其他的方法:
Collections.shuffle();//隨機打亂順序
Collections.reverse();//倒序排列
Collections類操作集合時是對集合進行操作,並不會產生新的集合,不需要定義集合接收。
Comparable接口–可比較的
實現該接口表示:這個實例可以比較大小,可以進行自然排序
定義了默認的比較規則
其實現類需實現comparaTo()方法
comparaTo()方法返回正數表示大,負數表示小,0表示相等
具體使用方法:
首先要領List中的對象實現Comparable接口,Comparable接口中有compareTo方法定義比較規則
public class Student implements Comparable<Student> {
//Comparable接口也支持泛型
...
//@Override
public int compareTo(Student o) {
return this.id.compareTo(o.id);//規則是比較Student的id
}
}
Comparator接口–比較工具接口
用於定義臨時比較規則,而不是默認比較規則
其實現類需要實現conpara()方法
Comparator和Comparable都是Java集合框架的成員
使用Comparator時不需要實現Comparable接口,而是要定義一個新的類實現Comparator接口定義比較規則
public class StudentComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);//規則是比較Student的name
}
}
使用時要在sort中傳入list和比較規則兩個參數
Collections.sort(studentList, new StudentComparator());