JAVA泛型詳解與使用技巧

1:爲什麼要使用Java泛型

看看下面程序例子(不使用泛型):

public static void main(String[] args) {
		
		List list = new ArrayList();
		list.add("zhangsan");
		list.add("lisi");
		list.add(102);//沒有使用泛型,代碼出現黃色警告
		
		for(int i= 0; i < list.size();i++){
			//list裝載默認是Object類型,由於第三項裝載Integer類型,所以在取對象時強制轉換報錯。
			String name = (String) list.get(i);
			System.out.println(name);
		}
	}

出現如下錯誤:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at com.java.test.genericity.GenericityMain.main(GenericityMain.java:40)

由於list沒有使用泛型,代碼出現黃色警告,list裝載默認是Object類型,由於第三項裝載Integer類型,所以在取對象時強制轉換報錯。

List使用泛型帶有String形參:

public static void main(String[] args) {
		
		List<String> list = new ArrayList<String>();
		list.add("zhangsan");
		list.add("lisi");
//		list.add(102); 類型已經限定編譯直接報錯通不過,默認是String類型
		
		for(int i= 0; i < list.size();i++){
			String name = list.get(i);
			System.out.println(name);
		}
	}

此時list添加第三項數據直接編譯報錯,類型已經限定編譯直接報錯通不過,默認是String類型

2:Java泛型的作用

1:通過結合代碼繼承封裝,減少Java代碼重複冗餘,使得代碼的結構和架構更合理。
2:消除了強制類型轉換 使得代碼可讀性好,減少了很多出錯的機會。
3:Java語言引入泛型的好處是安全簡單。泛型的好處是在編譯的時候檢查類型安全,並且所有的強制轉換都是自動和隱式的,這樣編譯器就可以在一個高的程度上驗證這個類型。

3:泛型幾種使用類型和繼承關係

  1. 自定義泛型類
  2. 自定義泛型接口
  3. 自定義泛型方法
  4. 瞭解泛型參數繼承關係
  1. 自定義泛型類
    /***
     * @ClassName Car
     * @Description 定義泛型類
     * 
     * ***/
    public class Car<M> {
    	
    	private M m;
    	
    	public void openCar(M m){
    		System.out.println("開車");
    	};
    	
    	
    	public M endCar(){
    		System.out.println("關車");
    		return m;
    	}
    }

    這裏的M表示泛型形參,由於接收來自外部使用時候傳入的類型實參。那麼對於不同傳入的類型實參,生成的相應對象實例的類型是不是一樣的呢?看如下例子:

Car<Person> pCar = new Car<Person>();
		Car<Animal> aCar = new Car<Animal>();
		
		System.out.println(pCar.getClass());//class com.java.test.genericity.Car
		System.out.println(aCar.getClass());//class com.java.test.genericity.Car
		System.out.println(aCar.getClass()== pCar.getClass());//true

看了以上例子,我們可以發現,在使用泛型類時,雖然傳入了不同的泛型實參,但並沒有真正意義上生成不同的類型,傳入不同泛型實參的泛型類在內存上只有一個,即還是原來的最基本的類型(本實例中爲Car),當然,在邏輯上我們可以理解成多個不同的泛型類型,在於Java中的泛型這一概念提出的目的,導致其只是作用於代碼編譯階段,在編譯過程中,對於正確檢驗泛型結果後,會將泛型的相關信息擦出,也就是說,成功編譯過後的class文件中是不包含任何泛型信息的。泛型信息不會進入到運行時階段。

2:泛型接口,泛型接口和泛型類的使用差不多,其中T表示泛型參數:

public interface Map<T> {

	public void load(T t);
	
}

實現泛型接口類的寫法,傳參形式如下:(在實現類實現泛型接口時,如已將泛型類型傳入實參類型,則所有使用泛型的地方都要替換成傳入的實參類型)

public class BaiduMap implements Map<String>{

	@Override
	public void load(String t) {
		// TODO Auto-generated method stub
		
	}

}

實現泛型接口類,不傳形參寫法如下:(不傳形參,與泛型類的定義相同,在聲明類的同時,需要將泛型的形參也一起加進去)

public class BaiduMap<T> implements Map<T>{

	@Override
	public void load(T t) {
		// TODO Auto-generated method stub
		
	}

}

3:泛型方法使用:(如果當前方法所在的Java類中沒有定義T泛型參數,則在方法的前面聲明泛型形參<T>)

public class BaiduMap implements Map<String>{

	
	@Override
	public void load(String t) {
		
	}
	
	
	//如果當前方法所在的Java類中沒有定義T泛型參數,則在方法的前面聲明泛型形參<T>
	public  <T> T getMethod(Class<T> czz) throws InstantiationException, IllegalAccessException{
		T t = czz.newInstance();
		return t;
	}
	
	
	
}

區別泛型方法和泛型類方法:

	//我們在當前類中已經定義了T類型,下面load含有泛型參數,所以泛型T不是泛型方法
	@Override
	public void load(T t) {
		
	}
	
	
	//我們在當前方法中getMethod已經定義了M類型,下面getMethod含有泛型參數,所有getMethod是泛型方法
	public  <M> M getMethod(Class<M> czz) throws InstantiationException, IllegalAccessException{
		M m = czz.newInstance();
		return m;
	}

4:瞭解泛型的繼承關係以及泛型參數的上下行邊界:

//當前定義了一個類Car 約定了M形參繼承Person類。
public class Car<M extends Person> {
	
	private M m;
	
	public void openCar(M m){
		System.out.println("開車");
	};
	
	
	public M endCar(){
		System.out.println("關車");
		return m;
	}
}



public class Person {

	private String name;
	private String age;

	public String getName() {
		return name;
	}

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

	public String getAge() {
		return age;
	}

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

}


public class Man extends Person{
	
	
}


public class Sedan extends Car<Man>{

	@Override
	public void openCar(Man m) {
		// TODO Auto-generated method stub
		super.openCar(m);
	}

	@Override
	public Man endCar() {
		// TODO Auto-generated method stub
		return super.endCar();
	}
	
	

}

我定義了一個Car類,約束當前的形參M繼承Person,此時我定義一個Man的類作爲形參,繼承了Person,Sedan類繼承Car在Sedan類中我傳遞形參Man,正因爲形參Man,重寫方法openCar,endCar的參數纔會顯示Man參數,這樣就約定了泛型的邊界,使得子類傳遞的參數必須是泛型約定的參數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章