摘要:如果需要收集參數化類型對象,只有使用警告這節討論,向參數可變的方法傳遞一個泛型類型的實例。異常不能拋出或捕獲泛型類的實例實際上,泛型類擴展也是不合法的。
Object:所有類的超類
java中每個類都是由它擴展而來,但是并不需要這樣寫:class Employee extends Object.如果沒有明確指出超類,Object類就被認為是這個的超類。
可以使用Object類型的變量引用任何類型的對象Object obj=new Employee().
在java中,只有基本類型(int,boolean,...)不是對象,所有的數組類型,不管是對象數組還是基本類型的數組都擴展自Object類。
Employee[] staff=new Employee[10]; Object obj=staff;//ok obj=new int[10];//ok對象包裝器與自動裝箱
有時需要將int這樣的基本類型轉換為對象,所有基本對象都有一個與之對應的類。如int->Integer.這些類稱為包裝類(wrapper).具體的,包括Integer,Long,Float,Double,Short,Byte,Character,Void,Boolean,前6個派生于它們公共的超類Number.
對象包裝類是不可變的,一旦創建,就不允許更改包裝在其中的值。
對象包裝類還是final,不能定義它們的子類。
java5之后,調用list.add(3)將自動變換成list.add(Integer.valueOf(3)),這種變換稱為自動裝箱。相反的,將一個Integer對象賦值給一個int值時,會自動拆箱。
Listlist=new ArrayList (); list.add(3); int n=list.get(0);//等同于list.get(0).intValue();
在算術表達式中,也可以自動裝箱,自動拆箱。
Integer n=3; n++;//拆箱->自增->裝箱
==運算符用于比較包裝器對象,只不過檢測的是對象是否指向同一個存儲區域。因此,下面比較不會成立
Integer a=1000; Integer b=1000; System.out.println(a==b);//false
但是如果包裝的值經常出現,==比較就有可能相等
Integer a=100; Integer b=100; System.out.println(a==b);//true
這個和python類似
python并不是對創建的所有對象都會重新申請新的一塊內存空間。作為一種優化,python會緩存不變的對象(如數值較小的數字,字符串,元組等)并對其進行復用。
因此,java設定了自動裝箱規范
boolean
byte
char<=127
介于-128和127之間的short,int
被包裝到固定的對象中。
上面例子a,b是100,第二次賦值時,java不會重新申請新的一塊內存空間,存儲100這個值。
接口特性
接口不是類,不能使用new運算符實例化一個接口
可以聲明接口變量,但必須引用實現了接口的類對象
可以使用instanceof檢查一個對象是否實現了某個特定的接口
接口可以繼承接口InterfaceA extends InterfaceB
接口中不能包含實例變量或靜態方法,卻可以包含常量
public interface Interface { String name="aaa";//a public static final constant }
常量會自動被設為public static final
盡管每個類只允許擁有一個超類,卻可以實現多個接口class Concrete implements InterfaceA,InterfaceB
內部類內部類方法可以訪問該類所在的作用域中的數據,包括私有數據
內部類可以對同一個包中的其他類隱藏起來
當想要定義一個回調函數且不想寫大量代碼時,使用匿名內部類比較方便
泛型 泛型類泛型類:具有一個或多個類型變量的類。類型變量可以指定方法的返回類型以及類變量和局部變量的類型
public class Pair{ T first; T second; Pair(){ this.first=null; this.second=null; } Pair(T first,T second){ this.first=first; this.second=second; } public T getFirst() { return first; } public void setFirst(T first) { this.first = first; } public T getSecond() { return second; } public void setSecond(T second) { this.second = second; } }
Pair類引入一個類型變量T,用尖括號(<>)括起來,并放在類名的后面。
泛型可以有多個類型變量``
public class Pair{ ... }
實例化Pair
泛型方法可以定義在普通類中。
publicT getMethod(T... a){}
類型變量放在修飾符(這里是public)的后面,返回類型的前面
調用class.
如果是上面情況,大多數時候,方法調用可以省略
但是,如果是下面代碼
double result=class.getMethod(1.23,123,0);
編譯器會自動將參數打包為1個Double和2個Integer對象,然后尋找這些類的共同超類型,最終找到兩個這樣的超類Number和Comparable,其本身也是泛型類型,這種情況下,只有將所有的參數寫成double值。
如果想知道一個泛型方法最終推斷出哪種類型,可以有目的的引入一個錯誤,看產生的錯誤信息,比如
class.getMethod("aaa",0,null); //found:java.lang.Object&java.io.Serializable&java.util.Comparable...
意思是可以將結果賦給Object,Serializable或Comparable.
類型變量的限定T min(T[] a);
上面代碼將T限制為實現了Comparable接口的類,這樣min方法只能被實現了實現了Comparable接口的類(如String,Date類)的數組調用。
注意這里用的是extends關鍵字
一個類型變量或通配符可以有多個限定,如T extends Serializable&Comparable.&隔開限定類型,,隔開類型變量。
由于對類是單繼承,對接口多重繼承,如果限定類型中有類又有接口,必須將類作為限定列表中的第一個。
大多數限制都是由類型擦除引起的,類型擦除可以參見Java泛型:類型擦除
不能用基本類型實例化類型參數。
沒有Pair
運行時類型查詢只試用于原始類型。
虛擬機中的對象總有一個特定的非泛型類型,因此所有的類型查詢只產生原始類型。
if(a instanceof Pair)...//error if(a instanceof Pair )...//error Pair p=(Pair ) a;//warning,can only test that a is a Pair
同樣的道理,getClass方法總是返回原始類型。
PairstringPair=...; Pair employeePair=...; if(stringPair.getClass()==employeePair.getClass())...//they are equal
上面代碼兩次調用getClass都將返回Pair.class.
不能創建參數化類型的數組
Pair[] paris=new Pair [10]; //error,The type of the expression must be an array type but it resolved to Pair
上面代碼的問題在于,類型擦除后,paris的類型是Pair[],可以轉換為Object[]
Object[] objarray=pairs;
數組會記住它的元素類型,如果試圖存儲其他類型的元素,就會拋出Array-StoreException.
只是不允許這樣創建數組,而聲明類型為Pair
可以聲明通配類型的數組,然后類型轉換
Pair[] pairs=(Pair []) new Pair>[10];
但這樣類型是不安全的。
如果需要收集參數化類型對象,只有使用ArrayList
Varargs警告
這節討論,向參數可變的方法傳遞一個泛型類型的實例。
staticvoid addAll(Collection coll,T... ts){ for(T t:ts) coll.add(t); } Collection > coll=...; Pair pair1=...; Pair pair2=...; addAll(coll,pair1,pair2);
為了調用addAll方法,java虛擬機必須建立一個Pair
不過,對于這種情況,規則有所放松,只會得到一個警告,而不是錯誤。
有兩種方法抑制這個警告
為包含addAll調用的方法添加標注@SuppressWarnings("unchecked").
如果是java7或其后面版本,用@SafeVarargs直接標注addAll方法。
@SafeVarargs staticvoid addAll(Collection coll,T... ts)
不能實例化類型變量
不能使用像new T(),new T[],T.class這樣的表達式中的類型變量。
泛型類中靜態類型變量無效
不能在靜態域或方法中引用類型變量
public class singleton{ static T instance;//error static T getInstance(){//error ... } }
類型擦除后,Singleton類只包含一個instance域變量。
異常不能拋出或捕獲泛型類的實例
實際上,泛型類擴展Throwable也是不合法的。
Class Problemextends Exception{...}//error,can"t extend Throwable
catch子句中不能使用類型變量。
void dowork(T t) throws T{ try{ ... }catch(T t){//error ... } }
不過在其中使用類型變量是允許的。
void dowork(T t) throws T{ try{ ... }catch(Throwable realCause){//error t.initCause(realCause); throw t; } }
注意擦除后的沖突
類型擦除后,無法創建引發沖突的條件。
public class Pair{ ... boolean equals(T value){ return this.first.equals(value)&&this.second.equals(value); } }
上面代碼類型擦除后boolean equals(T)變成boolean equals(Object),與Object類本身的equals方法發生沖突。所以編譯器會發出警告,equals(T)方法沒有override Object類中的equals(Object).
泛型類型的繼承規則考慮一個類和一個子類,如Employee和Manager.顯然Pair
注意泛型和數組間的重要區別,可以將一個Manager[]數組賦值給一個類型為Employee[]的變量。
public class Manager extends Employee{ public static void main(String[] args){ Manager ceo=new Manager(); Manager cto=new Manager(); Manager[] managers=new Manager[]{ceo,cto}; Employee[] employs=managers; System.out.println(employs.length);//2 } }
另外,可以參數化類型轉換為原始類型,如Pair
public class Pair{ T first; T second; Pair(T first,T second){ this.first=first; this.second=second; } public T getFirst() { return first; } public void setFirst(T first) { this.first = first; } }
public class Manager{ public static void main(String[] args){ Manager ceo=new Manager(); Manager cto=new Manager(); Pairpair=new Pair<>(ceo,cto); Pair pair1=pair;//ok pair1.setFirst(new File(""));//類型警告,但是可運行 Manager manager=(Manager)pair1.getFirst(); //ClassCastException,java.io.File cannot be cast to com.Manager Manager manager1=pair.getFirst(); //ClassCastException,java.io.File cannot be cast to com.Manager } }
最后,泛型類可以擴展或實現其他泛型類,這和普通類沒什么區別。如ArrayList類實現List接口,這意味著ArrayList
但是如前面所見,ArrayList
Pair extends Employee>表示類型參數是Employee類的子類.
看下面代碼
void print(Pairp){ Employee first=p.getFirst(); Employee second=p.getSecond(); ... }
正如前面所說,這里不能將Pair
void print(Pair extends Employee> p)
類型Pair
下面考慮
Pairmanager=new Pair<>(); Pair extends Employee> pair=manager;//ok pair.setFirst(manager); //編譯錯誤,The method setFirst(capture#1-of ? extends Employee) in the type //Pair is not applicable for the arguments (Pair )
不過將getFirst方法的返回值賦值給一個Employee引用就不存在問題。
通配符的超類型限定如? super Manager,這個通配符限制類型變量為Manager的所有超類型。
上面代碼 extends Manager>如果換成 super Manager>,將會表現為可以為方法通過參數(set),但不能使用返回值(get).
帶有超類型限定的通配符( super Manager>)可以向泛型對象寫入,帶有子類型限定的( extends Manager>)可以從泛型對象讀取
如Pair>有方法
? getFirst()
void setFirst(?)
getFirst的返回值只能賦值給一個Object,而setFirst方法不能被調用,甚至用Object做參數也不能。
可以調用setFirst(null)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/64680.html
摘要:關鍵字作用調用超類方法調用超類構造器關鍵字作用引用隱式參數如調用該類的其他構造器在覆蓋一個方法時,子類方法可見性不能低于超類方法阻止繼承類和方法目的確保它們不會在子類中改變語義。但是如果將一個類聲明為后面可以改變類變量的值了。 數據類型 整型 int 存儲要求:4byte 取值范圍:-2147483648 -- 2147483647(超過20億) short 存儲要求:2byte 取...
摘要:然而,這兩個方法都只是讀取對象狀態,如果只是讀取操作,就可以允許線程并行,這樣讀取效率將會提高。分配線程執行子任務執行子任務獲得子任務進行完成的結果 Lock Lock接口主要操作類是ReentrantLock,可以起到synchronized的作用,另外也提供額外的功能。用Lock重寫上一篇中的死鎖例子 import java.util.concurrent.locks.Lock; ...
摘要:注本文內容來深入面向對象模式與實踐中節。面向對象設計與過程式編程面向對象設計和過程式編程有什么不同呢可能有些人認為最大的不同在于面向對象編程中包含對象。面向對象編程和過程式編程的一個核心區別是如何分配職責。 注:本文內容來中6.2節。 6.2 面向對象設計與過程式編程 ??面向對象設計和過程式編程有什么不同呢?可能有些人認為最大的不同在于面向對象編程中包含對象。事實上,這種說法不準確。...
摘要:一讓廣播明星黯然失色要建立頁面,需要創建用超文本標記語言,編寫的文件,把它們放在一個服務器上二服務器能做什么服務器在互聯網上有一份全天候的工作。一、Web讓廣播明星黯然失色 要建立Web頁面,需要創建用超文本標記語言(HyperText Markup Language,HTML)編寫的文件,把它們放在一個Web服務器上二、Web服務器能做什么? Web服務器在互聯網上有一份全天候的工...
摘要:包括元素的高度上下內邊距上下邊框值,如果元素的的值為那么該值為。該值為元素的包含元素。最后,所有這些偏移量都是只讀的,而且每次訪問他們都需要重新計算。為了避免重復計算,可以將計算的值保存起來,以提高性能。 offsetHeight 包括元素的高度、上下內邊距、上下邊框值,如果元素的style.display的值為none,那么該值為0。offsetWidth 包括元素的寬度、左...
閱讀 693·2023-04-25 19:53
閱讀 4274·2021-09-22 15:13
閱讀 2569·2019-08-30 10:56
閱讀 1324·2019-08-29 16:27
閱讀 2938·2019-08-29 14:00
閱讀 2415·2019-08-26 13:56
閱讀 438·2019-08-26 13:29
閱讀 1616·2019-08-26 11:31