JAVA5新特性
1>Java在逐漸與C++融合
2>五小點,四大點
一、五小點
1、自動封箱AutoBoxing/自動解封
自動封箱和自動拆箱,它實現了簡單類型和封裝類型的相互轉化時,實現了自動轉化。
byte b -128~127
Byte b 在以上數量的基礎上多一個null
簡單類型和封裝類型之間的差別
封裝類可以等於null ,避免數字得0時的二義性。
Integer i=null;
int ii=i; //會拋出NullException 異常。相當於 int ii=i.intValue();
Integer i=1; //相當於Integer i=new Integer(1);
i++; // i = new Integer(i.intValue()+1);
在基本數據類型和封裝類之間的自動轉換
5.0之前
Integer i=new Integer(4);
int ii= i.intValue();
5.0之後
Integer i=4;
Long l=4.3;
public void m(int i){......}
public void m(Integer i){......}
以上兩個函數也叫方法重載
自動封箱解箱只在必要的時候才進行。能不封箱找到匹配的就不封箱。
注意:Integer 和 int 的默認值是不一樣的,Integer 是null(對象嘛),int 是0(基本數據類型嘛);
2、靜態引入 StaticImport
使用類中靜態方法時不用寫類名
System.out.println(Math.round(PI));
可以用以下代碼實現:
import static java.lang.System.*; //注意,要寫" 類名.* "
import static java.lang.Math.*;
out.println(round(PI));
注意:靜態引入的方法不能重名
3、for-each
統一了遍歷 數組 和遍歷 集合 的方式
for(Object o:list){ //Object o 表示每個元素的類型 ,list 表示要遍歷的數組或集合的名字
System.out.println(o); //打印集合或數組中的每個元素
}
4、可變長參數
處理方法重載中,參數類型相同,個數不同的情況
public void m(int... is){.....}
int... is 相當於一個 int[] is
編譯器會把給定的參數封裝到一個數組中,再傳給方法
在一個方法中只能有一個可變長參數,而且,必須放在最後一個參數的位置
5、格式化輸入/輸出
java.util.Formatter類 對格式的描述
System.out.printf("Hello %s",str); //打印字符串類型的變量,用一個佔位符
格式化I/O(Formatted I/O)
java.util.Sacner類可以進行格式化的輸入,可以使用控制檯輸入,結合了BufferedReader和StringTokener的功能。
二、四大點
1、枚舉(Enum)
枚舉是一個類,並且這個類的對象是現成的,在定義類的時候,即定義好了對象
程序員要使用的時候,只能從中選擇,無權創建
enum 枚舉名{
枚舉值1(..),枚舉值2(..),.....;
}
(1) 在5.0之前使用模式做出一個面向對象的枚舉
final class Season{
public static final Season SPRING=new Season();
public static final Season WINTER=new Season();
public static final Season SUMMER=new Season();
public static final Season AUTUMN=new Season();
private Season(){}
}
完全等價於
enum Season2{
SPRING(..),//枚舉值
SUMMER(..),
AUTUMN(..),
WINTER(..)
}
枚舉本質上也是一個類,Enum是枚舉的父類。
這個類編譯以後生成一個.class類
這個類有構造方法,但是是私有的
枚舉中的values()方法會返回枚舉中的所有枚舉值
枚舉中可以定義方法和屬性,最後的一個枚舉值要以分號和類定義分開,枚舉中可以定義的構造方法。
枚舉不能繼承類(本身有父類),但可以實現接口,枚舉不能有子類也就是final的,枚舉的構造方法是private(私有的)。
枚舉中可以定義抽象方法,可以在枚舉值的值中實現抽象方法。
枚舉值就是枚舉的對象,枚舉默認是final,枚舉值可以隱含的匿名內部類來實現枚舉中定義抽象方法。
(2)枚舉類(Enumeration Classes)和類一樣,具有類所有特性。Season2的父類是java.lang.Enum;
隱含方法: 每個枚舉類型都有的方法。
Season2[] ss=Season2.values(); ----獲得所有的枚舉值
for(Season2 s:ss){
System.out.println(s.name()); ----- 打印枚舉值
System.out.println(s.ordinal()); ----- 打印枚舉值的編號
}
(3) enum可以switch中使用(不加類名)。
switch( s ){
case SPRING:
…………….
case SUMMER:
…………….
…………..
}
(4)枚舉的有參構造
enum Season2{
SPRING(“春”),-------------------------------逗號
SUMMER(“夏”),-----------------------------逗號
AUTUMN(“秋”),-----------------------------逗號
WINTER(“冬”);------------------------------ 分號
private String name;
Season2(String name){ //構造方法必須是私有的,可以不寫private,默認就是私有的
this.name=name;
}
String getName(){
return name;
}
}
Season2.SPRING.getName() ---------------------春
(5)枚舉中定義的抽象方法,由枚舉值實現:
enum Operation{
ADD('+'){
public double calculate(double s1,double s2){
return s1+s2;
}
},
SUBSTRACT('-'){
public double calculate(double s1,double s2){
return s1-s2;
}
},
MULTIPLY('*'){
public double calculate(double s1,double s2){
return s1*s2;
}
},
DIVIDE('/'){
public double calculate(double s1,double s2){
return s1/s2;
}
};
char name;
public char getName(){
return this.name;
}
Operation(char name){
this.name=name;
}
public abstract double calculate(double s1 ,double s2);
}
有抽象方法枚舉元素必須實現該方法。
Operator[] os = Operator.values();
for(Operator o:os){
System.out.println("8 "+o.name()+" 2="+o.calculate(8,2));
}
for(Operator o:os){
System.out.println("8 "+o.getName()+" 2="+o.calculate(8,2));
}
運行結果:
8 ADD 2=10.0
8 SUBSTRACT 2=6.0
8 MULTIPLY 2=16.0
8 DIVIDE 2=4.0
8 + 2=10.0
8 - 2=6.0
8 * 2=16.0
8 / 2=4.0
2、泛型 (Generic)
(1)增強了java的類型安全,可以在編譯期間對容器內的對象進行類型檢查,在運行期不必進行類型的轉換。
而在java se5.0之前必須在運行期動態進行容器內對象的檢查及轉換,泛型是編譯時概念,運行時沒有泛型
減少含糊的容器,可以定義什麼類型的數據放入容器
(2)List<Integer> aList = new ArrayList<Integer>();
aList.add(new Integer(1));
// ...
Integer myInteger = aList.get(0); //從集合中得到的元素不必強制類型轉換
支持泛型的集合,只能存放制定的類型,或者是指定類型的子類型。
HashMap<String,Float> hm = new HashMap<String,Float>();
不能使用原始類型
GenList<int> nList = new GenList<int>(); //編譯錯誤
編譯類型的泛型和運行時類型的泛型一定要一致。沒有多態。
List<Dog> as = new ArrayList<Dog>();
List<Animal> l = as; //error Animal與Dog的父子關係不能推導出List<Animal> 與 List<Dog> 之間的父子類關係
(3)泛型的通配符"?"
? 是可以用任意類型替代。
<?> 泛型通配符表示任意類型
<? extends 類型> 表示這個類型是某個類型或接口的子類型。
<? super 類型> 表示這個類型是某個類型的父類型。
import java.util.*;
import static java.lang.System.*;
public class TestTemplate {
public static void main(String[] args) {
List<Object> l1=new ArrayList<Object>();
List<String> l2=new ArrayList<String>();
List<Number> l3=new ArrayList<Number>(); //Number --- Object的子類,所有封裝類的父類
List<Integer> l4=new ArrayList<Integer>();
List<Double> l5=new ArrayList<Double>();
print(l1);
print(l2);
print(l3);
print(l4);
print(l5);
}
static void print(List<? extends Number> l){ //所有Number及其子類 l3,l4,l5通過
for(Number o:l){
out.println(o);
}
}
static void print(List<? extends Comparable> l){……} //任何一個實現Comparable接口的類 l2,l4,l5通過
static void print(List<? super Number> l){……} //所有Number及其父類 l1,l3通過
// "?"可以用來代替任何類型, 例如使用通配符來實現print方法。
public static void print(GenList<?> list){……} //表示任何一種泛型
}
(4)泛型方法的定義 --- 相當於方法的模版
把數組拷貝到集合時,數組的類型一定要和集合的泛型相同。
<...>定義泛型,其中的"..."一般用大寫字母來代替,也就是泛型的命名,其實,在運行時會根據實際類型替換掉那個泛型。
在方法的修飾符和返回值之間定義泛型
<E> void copyArrayToList(E[] os,List<E> lst){……}
static <E extends Number & Comparable> void copyArrayToList(E[] os,List<E> lst){……} //定義泛型的範圍 類在前接口在後
static<E , V extends E> void copyArrayToList(E[] os,List<E> lst){……} //定義多個泛型
"super"只能用在泛型的通配符上,不能用在泛型的定義上
import java.util.*;
public class TestGenerics3 {
public static void main(String[] args) {
List<String> l1=new ArrayList<String>();
List<Number> l2=new ArrayList<Number>();
List<Integer> l3=new ArrayList<Integer>();
List<Double> l4=new ArrayList<Double>();
List<Object> l5=new ArrayList<Object>();
String[] s1=new String[10];
Number[] s2=new Number[10];
Integer[] s3=new Integer[10];
Double[] s4=new Double[10];
Object[] s5=new Object[10];
copyFromArray(l1,s1);
copyFromArray(l2,s2);
copyFromArray(l3,s3);
copyFromArray(l4,s4);
copyFromArray(l5,s5);
}
//把數組的數據導入到集合中
public static <T extends Number&Comparable> void copyFromArray(List<T> l,T[] os){
for(T o:os){
l.add(o);
}
}
}
受限泛型是指類型參數的取值範圍是受到限制的. extends關鍵字不僅僅可以用來聲明類的繼承關係, 也可以用來聲明類型參數(type parameter)的受限關係.
泛型定義的時候,只能使用extends不能使用 super,只能向下,不能向上。
調用時用<?>定義時用 <E>
(5)泛型類的定義
類的靜態方法不能使用泛型,因爲泛型類是在創建對象的時候產生的。
class MyClass<E>{
public void show(E a){
System.out.println(a);
}
public E get(){
return null;
}
}
受限泛型
class MyClass <E extends Number>{
public void show(E a){
}
}
3、註釋(Annotation)
(1)、定義:Annotation描述代碼的代碼(區:描述代碼的文字)
給機器看 給人看的
(2)、註釋的分類:
1>、標記註釋:沒有任何屬性的註釋。@註釋名
2>、單值註釋:只有一個屬性的註釋。@註釋名(value=___)
在單值註釋中如果只有一個屬性且屬性名就是value,則“value=”可以省略。
3>、多值註釋:有多個屬性的註釋。多值註釋又叫普通註釋。
@註釋名(多個屬性附值,中間用逗號隔開)
(3)、內置註釋:
1>、Override(只能用來註釋方法)
表示一個方法聲明打算重寫超類中的另一個方法聲明。如果方法利用此註釋類型進行註解但沒有重寫超類方法,則編譯器會生成一條錯誤消息。
2>、Deprecated
用 @Deprecated 註釋的程序元素,不鼓勵程序員使用這樣的元素,通常是因爲它很危險或存在更好的選擇。在使用不被贊成的程序元素或在不被贊成的代碼中執行重寫時,編譯器會發出警告。
3>、SuppressWarnings(該註釋無效)
指示應該在註釋元素(以及包含在該註釋元素中的所有程序元素)中取消顯示指定的編譯器警告。
(4)、自定義註釋
自定義註釋
public @interface Test{
}
在自定義註釋時,要用註釋來註釋(描述)註釋。
@target(),用來描述(註釋)註釋所能夠註釋的程序員元素。
@Retention(),描述(註釋)註釋要保留多久。
註釋的屬性類型可以是
8種基本類型
String
Enum
Annotation
以及它們的數組
(5)、註釋的註釋:java.lang. annotation包中======元註釋
(1)、Target:指示註釋類型所適用的程序元素的種類。
例:@Target(value = {ElementType.METHOD});
說明該註釋用來修飾方法。
(2)、Retention:指示註釋類型的註釋要保留多久。如果註釋類型聲明中不存在 Retention 註釋,則保留策略默認爲 RetentionPolicy.CLASS。
例:Retention(value = {RetentionPolicy.xxx}
當x爲CLASS表示保留到類文件中,運行時拋棄。
當x爲RUNTIME表示運行時仍保留
當x爲SOURCE時表示編譯後丟棄。
(3)、Documented:指示某一類型的註釋將通過 javadoc 和類似的默認工具進行文檔化。應使用此類型來註釋這些類型的聲明:其註釋會影響由其客戶端註釋的元素的使用。
(4)、Inherited:指示註釋類型被自動繼承。如果在註釋類型聲
明中存在 Inherited 元註釋,並且用戶在某一類聲明中查詢該註釋類型,同時該類聲明中沒有此類型的註釋,則將在該類的超類中自動查詢該註釋類型。
注:在註釋中,一個屬性既是屬性又是方法。
■ 標註:描述代碼的文字
描述代碼的代碼。給編譯器看的代碼,作用是規範編譯器的語法。
class Student{
@Override
public String toString(){
return “student”;
}
}
■ 註釋類型 java.lang
1、標記註釋(沒有屬性)
@Override
2、單值註釋
@註釋名(a="liucy")
@註釋名(prameter=10)
int parameter
特例:
@註釋名 (value=“134” )
等價於 @註釋名 (“134” )
3.普通註釋(多值註釋)
(key1=value,……)
@__(a="liucy,b=10)
■ @Override 只能放在方法前面
@Deprecated 用於描述過期
@SuppressWarnings 抑制警告
@SuperessWarning({“ddd”,”aaa”,”ccc”}) //JVM還沒有實現這個註釋
4、Java5.0中的併發
1>、所在的包:Java.util.concurrent
2>、重寫線程的原因:
(1)何一個進程的創建(連接)和銷燬(釋放資源)的過程都 是一個不可忽視的開銷。
(2)run方法的缺陷:沒有返回值,沒有拋例外。
3>、對比1.4和5.0的線程
5.0 1.4
ExecutorService 取代 Thread
Callable Future 取代 Runnable
Lock 取代 Synchronized
SignalAll 取代 notifyAll()
await() 取代 wait()
三個新加的多線程包
Java 5.0裏新加入了三個多線程包:java.util.concurrent, java.util.concurrent.atomic,
java.util.concurrent.locks.
java.util.concurrent包含了常用的多線程工具,是新的多線程工具的主體。
這樣Java創建線程有 3 種方式:
1. 繼承Thread基類。實現run()方法,run()方法就是線程執行流。
啓動:
a. 創建Thread子類的對象。
b. 調用該對象的start()方法來啓動它。
2. 實現Runnable接口。實現run()方法,run()方法就是線程執行流。
啓動:
a. 創建Runnable實現類的對象。
b. 以Runnable實現類的對象作爲target參數,創建Thread對象
c. 調用Thread對象的start()方法來啓動它。
前面兩種方式的線程執行體(也就是run()方法)不能聲明拋出異常,也不能有返回值。
3. 實現Callable接口(它是Runnable的增強版)。
實現call()(run()的增強版)方法,call()方法就是線程執行流。
a. 創建Callable實現類的對象。
b. 將Callable實現類的對象包裝FutureTask,它代表了call()方法的返回值將來纔會返回。
c. 以FutureTask的對象作爲target參數,創建Thread對象
d. 調用Thread對象的start()方法來啓動它。
實現Runnable接口和實現Callable接口本質相同,
通常我們認爲通過實現實現Runnable接口或實現Callable接口的多線程實現方式比較理想。