泛型擦除:
泛型只是在 編譯期 保證對象類型相同的技術,編譯後就被擦除了。真正在代碼的運行期,jvm會擦除泛型的存在。(所以也可以不反編譯,使用反射來驗證泛型擦除!)
- 泛型擦除
- 無限制類型擦除
- 有限制類型擦除
- 泛型方法的類型擦除
- 橋接方法
1、無限制類型擦除
//無限制類型擦除
public class Orange<T>{
private T color;
public void setColor(T color) {
this.color = color;
}
public T getColor() {
return color;
}
}
反編譯後
public class Orange
{
private Object color;
public Orange(){}
public void setColor(Object color)
{
this.color = color;
}
public Object getColor()
{
return color;
}
}
注:類型形參T都變成了Object
使用反射也可以驗證 !
//無限制的類型擦除!
public class TypeErasure<T> {
private T name;
public T getName(){
return this.name;
}
public void setName(T name){
this.name = name;
}
public static void main(String[] args) {
TypeErasure<Integer> te = new TypeErasure<>();
TypeErasure<String> te2 = new TypeErasure<>();
System.out.println(te.getClass().getSimpleName());
System.out.println(te2.getClass().getSimpleName());
System.out.println(te.getClass() == te2.getClass()); //屬於同一個類!
//利用反射獲取字節碼文件,看成員變量的類型!
Class<TypeErasure> clazz = TypeErasure.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
// Name:name Type:Object
System.out.println("Name:"+field.getName()+"\tType:"+field.getType().getSimpleName());
}
}
}
2、有限制類型擦除
// 有限制類型擦除
public class Watermelon<T extends Number>{
private T weight;
public T getWeight() {
return weight;
}
public void setWeight(T weight) {
this.weight = weight;
}
}
反編譯後
public class Watermelon
{
private Number weight;
public Watermelon()
{
}
public Number getWeight()
{
return weight;
}
public void setWeight(Number weight)
{
this.weight = weight;
}
}
注:類型形參T都變成了上限Number
3、泛型方法的類型擦除
// 泛型方法的類型擦除
public class Peach {
public static <T> T getName(T name){
return name;
}
public static <T extends Number> T getWeight(T weight){
return weight;
}
}
反編譯後
public class Peach
{
public Peach(){}
public static Object getName(Object name)
{
return name;
}
public static Number getWeight(Number weight)
{
return weight;
}
}
注:其實本質上和上面1、2點都類似!
4、橋接
// 泛型接口
public interface Info<T>{
T info(T var);
}
class InfoImple implements Info<Integer>{
@Override
public Integer info(Integer var) {
return var;
}
}
反編譯後
public interface Info
{
// 無限制的類型擦除
public abstract Object info(Object obj);
}
class InfoImple implements Info
{
InfoImple(){}
public Integer info(Integer var)
{
return var;
}
public volatile Object info(Object obj)
{
return info((Integer)obj);
}
}
5、補充
public class Test {
public static void main(String[] args) {
List<Integer> intList = new ArrayList<>(Arrays.asList(1,2));
/**
* 1.當一個具有泛型信息的對象賦給另一個沒有泛型信息的變量時,編譯器就會丟失前者的泛型信息,這時典型的擦除
* 例子:這裏intList就丟失了泛型的信息!
*
* 2.java中直接允許將List對象賦給一個List<Type>, Type是任何類型!
*/
List list = intList;
List<String> strList = list;
System.out.println(strList.get(0));//java.lang.ClassCastException
//System.out.println((String)strList.get(0)); 反編譯後上一句是這樣的!!
}
}
泛型數組
泛型數組的創建:
1.可以聲明帶泛型的數組引用。但是不能直接創建帶泛型的數組對象!
(特例:java允許創建無上限的通配符泛型數組)
2.可以通過java.lang.reflect包下的Array.newInstance(Class, int) 創建T[]數組注:開發中儘量使用泛型集合來代替泛型數組
1、不能直接創建帶泛型的數組對象
public class Demo {
public static void main(String[] args) {
// List<String>[] lists; // 只能聲明帶泛型的數組
// lists = new ArrayList<String>[5]; //(編譯報錯)不能直接創建帶泛型的數組
// 如果真想創建泛型數組,可以這樣創建(new的時候不帶泛型),但是會出現編譯警告!,也就是說可能發生ClassCastException
List<String>[] lists = new ArrayList[5];
// 強轉成Object[]數組
Object[] objs = (Object[])lists;
List<Integer> intList = new ArrayList<>();
intList.add(20);
objs[0] = intList;
//下面代碼引起ClassCastException異常
String s = lists[0].get(0);
System.out.println(s); // java.lang.ClassCastException
}
}
- 創建無上限的通配符泛型數組
public class Demo2 {
public static void main(String[] args) {
// java允許創建無上限的通配符泛型數組
List<?>[] genericArray = new ArrayList<?>[10];
Object[] objs = (Object[])genericArray;
List<String> intList = new ArrayList<>(Arrays.asList("10"));
objs[0] = intList;
//強轉前應該instanceof判斷下
Object target = genericArray[0].get(0);
if(target instanceof String){
String s = (String)target;
System.out.println(s+"\t"+s.getClass().getSimpleName());
}
}
}
- 不能直接對類型參數T實例化
public <T> T[] makeArray(Collection<T> c){
return new T[c.size()]; //導致編譯錯誤, 類型參數T不能直接被實例化
}
2、通過Array.newInstance()來創建泛型數組
package cn.itcast.genericType;
import java.lang.reflect.Array;
import java.util.Arrays;
public class Fruit<T> {
// private T[] array = new T[3]; // 參數類型T不能直接被實例化!
private T[] array;
public Fruit(Class<T> clazz, int length){
// 通過Array.newInstance()創建一個泛型數組
array = (T[])Array.newInstance(clazz, length);
}
// 1.往指定位置填充元素
public void put(int index, T item){
array[index] = item;
}
// 2.獲取指定位置的元素
public T get(int index){
return array[index];
}
// 3.獲取數組
public T[] getArray(){
return this.array;
}
public static void main(String[] args) {
Fruit<String> fruit = new Fruit(String.class,3);
fruit.put(0,"蘋果");
fruit.put(1,"香蕉");
fruit.put(2,"橘子");
System.out.println(Arrays.toString(fruit.getArray())); //[蘋果, 香蕉, 橘子]
}
}
來自:雖然帥,但是菜的cxy
peace