Java之泛型參數化使用於類,接口,方法上知識


第一:參數類型用於類上案例:

編寫泛型類GenericClass:

package com.test.cgb;

/**
 * 
 * @Description: 定義泛型類,在類名后添加 對尖括號
   *  並在尖括號中填寫類型參數,參數可以有多個,多個參數使用逗號分隔
 * T表示的是任意類型  type
 * E表示的是元素的類型 element
 * K表示的是key/value中的key
 * V表示的是key/value中的value
   *    通常類型參數我們都是使用大寫。
 * @author: caigb
 * @createTime: 2020年2月29日
 * @version:
 */
public class GenericClass<T> {
	
	public T value;

	public T getValue() {
		return value;
	}

	public void setValue(T value) {
		this.value = value;
	}
	
}

  編寫測試類:

public class GenericDemo {
	public static void main(String[] args) {
                // 參數類型為String
		GenericClass<String> genericClassOfString = new GenericClass<>();
		genericClassOfString.setValue("用於類上的泛型");
		String str = genericClassOfString.getValue();
		System.out.println("str = " + str);
		
                // 參數類型為Integer
		GenericClass<Integer> genericClassOfInteger = new GenericClass<>();
		genericClassOfInteger.setValue(111);
		Integer intNum = genericClassOfInteger.getValue();
		System.out.println("intNum = " + intNum);
}                            

  輸出結果為:

str = 用於類上的泛型
intNum = 111

==================================================================================================================================

第二個:泛型接口:

定義接口如:

/**
 * 
 * @Description: 用於接口上的泛型
 * @author: caigb28355
 * @createTime: 2020年2月29日
 * @version:
 */
public interface GenericInterface<T> {
	void show(T value);
}

 那么針對這個接口我們可以分別定義多種類型的實現類如:

IntegerShowGenericInterfaceImpl:

package com.test.cgb;
// 泛型類型參數為Integer
public class IntegerShowGenericInterfaceImpl implements GenericInterface<Integer>{

	@Override
	public void show(Integer value) {
		System.out.println(" 整數型 "+ value);
	}

}

  StringShowGenericInterfaceImpl:

package com.test.cgb;
// 泛型類型參數為String
public class StringShowGenericInterfaceImpl implements GenericInterface<String>{

	@Override
	public void show(String value) {
		System.out.println(" 字符串 "+ value);		
	}

}

  編寫測試類如下:

public class GenericDemo {
	public static void main(String[] args) {
		GenericInterface IntFace = new IntegerShowGenericInterfaceImpl(); // 向上轉型
		IntFace.show(200);
		GenericInterface StringFace = new StringShowGenericInterfaceImpl(); // 向上轉型
		StringFace.show("字符串");

}

// 輸出結果為:
 整數型 200
 字符串 字符串

==================================================================================================================================

第三:泛型方法,可以定義在泛型類中,也可以定義在普通類中。如果可以定義泛型方法,那就盡量定義泛型方法

泛型方法類定義如:

package com.test.cgb;
/**
 * 
 * @Description: 泛型方法,可以定義在泛型類中,也可以定義在普通類中
  *    定義泛型方法,在返回值前邊,修飾符后邊添加尖括號,並在其中填寫類型參數 
  *    如果可以定義泛型方法,那就盡量定義泛型方法
 * @author: caigb
 * @createTime: 2020年2月29日
 * @version:
 */
public class GenericFun {
	public static<T> void saveScore(T score) {
		// 這是一個保存分數的方法,分數的類型可以是int,double,float...數值類型
		// 我們對分數進行復雜操作......
		System.out.println("score = " + score);
	}
}

  編寫測試類如下:

public class GenericDemo {
	public static void main(String[] args) {
		GenericFun.saveScore(20.0);
		GenericFun.saveScore(20);
}
打印結果如下:
score = 20.0
score = 20

  但是上面這個例子有個不足的就是,命名這個方法是用來保存分數的,由於使用了static<T>形式,所以可以接收所有類型的值比如字符串中文,那么就有點違背最初的想法了,如:

	public static void main(String[] args) {
		GenericFun.saveScore(20.0);
		GenericFun.saveScore(20);
		GenericFun.saveScore("保存分數的入參竟然是中文");
}
打印結果有:
score = 20.0
score = 20
score = 保存分數的入參竟然是中文

  所以為了改進上面的缺陷,我們需要限制一下參數類型,於是要對引入類型參數做一下限定,這個限定可以是類,也可以是接口,而且可以同時限定多個,如果有多個,可以使用&符號連接,如果限定中既有類又有接口,那么類一定要寫在前面<T extends Number>或者<T extends Number & Comparable>如:

public class GenericFun {
	// T extends Number表示T這個類型必須繼承自Number類型,也就是一定要是Number類的字類,那么也就不能是String類型了
	public static<T extends Number> void saveScore(T score) {
		// 這是一個保存分數的方法,分數的類型可以是int,double,float...數值類型
		// 我們對分數進行復雜操作......
		System.out.println("score = " + score);
	}
	// Double 和Float都是繼承字Number類如:
//	public final class Double extends Number implements Comparable<Double> {
//	    /**
//	     * A constant holding the positive infinity of type
//	     * {@code double}. It is equal to the value returned by
//	     * {@code Double.longBitsToDouble(0x7ff0000000000000L)}.
//	     */
//	    public static final double POSITIVE_INFINITY = 1.0 / 0.0;
//	}
	
//	public final class Float extends Number implements Comparable<Float> {
//	    /**
//	     * A constant holding the positive infinity of type
//	     * {@code float}. It is equal to the value returned by
//	     * {@code Float.intBitsToFloat(0x7f800000)}.
//	     */
//	    public static final float POSITIVE_INFINITY = 1.0f / 0.0f;

}

  

  這樣改造之后,在測試類中如果還是調用GenericFun.saveScore("保存分數的入參竟然是中文")方法的話就會報錯如:

public class GenericDemo {
	public static void main(String[] args) {
		GenericFun.saveScore(20.0);
		GenericFun.saveScore(20);
// 下面這句報錯信息就是The method saveScore(T) in the type GenericFun is not applicable for the arguments (String)
		GenericFun.saveScore("這里有中文");
}

===============================================================================================================================

泛型之類型擦出重要知識點擴展:下面讓我們一起學習下泛型是如何擦出的,我們要知道,對於JVM來說,根本沒有泛型這個概念,只有具體類型也就是說在運行期間根本就沒有GenericClass<String>,有的只是普通類和方法。JVM都會自動提供了一個相應的原始類型替換。在編譯期間必要時會插入強制類型轉換方法。

JVM在泛型編譯時,做兩件事:

1.去掉類名后的尖括號和尖括號的類型參數,剩下的名字就是對應的類名

2.對於類中使用了類型參數的變量的類型,如果沒有限制類型的情況下,使用Object替換,如果有類型限定,使用限定的類型替換。下面我們一起看看:

首先我們在工作空間找到對應的class字節碼文件路徑,然后在該路徑打開命令符窗口:

 

最初我們的源文件GenericClass.java代碼如:

public class GenericClass<T> {
	
	public T value;

	public T getValue() {
		return value;
	}

	public void setValue(T value) {
		this.value = value;
	}
	
}

第二步我們可以在cmd.exe窗口輸入命令javap -help可以看到各種命令:

 

 第三步我們可以輸入輸入命令javap -c -s GenericClass.class,我們可以看到Object類

 

 那么如果源代碼是這樣的呢?就是有類型限定的如:

public class GenericClass<T extends Number> {
	
	public T value;

	public T getValue() {
		return value;
	}

	public void setValue(T value) {
		this.value = value;
	}
	
}

  

那么就替換成Number了:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM