泛型

hashMap例子

public static void test(){
        HashMap<String, Integer> map = new HashMap<>();
        map.put("name",14);
        map.put("pwd",123);
        map.put("age",24);
        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
        while (iterator.hasNext()){
            Map.Entry<String, Integer> next = iterator.next();
            System.out.println("key:"+next.getKey()+",value:"+next.getValue());
        }
    }
/** result:
key:name,value:14
key:pwd,value:123
key:age,value:24
*/

泛型类、方法

自定义泛型类

例如:

class Person4<T> {
    private String name;
    private T t;

    public Person4(){
        T[] arr = new T[10] //编译不通过
        T[] arrT = (T[]) new Object[10]; //可以这样做
    }

    public Person4(String name, T t){
        this.name = name;
        this.t = t;
    }

    public T getT(){
        return t;
    }
    public void setT(T t){
        this.t = t;
    }

    @Override
    public String toString() {
        return "Person4{" +
                "name='" + name + '\'' +
                ", t=" + t +
                '}';
    }
    //静态方法中不能使用类的泛型
    public static void show(T t){ //编译错误
        System.out.println(t);
    }
}
//异常类不能是泛型的
class MyException<T> extends Exception{ } //编译错误

try{

}catch(T t){ //编译错误

} 

总结

  • 集合接口或集合类在jdk5.0时都修改为带泛型的结构。
  • 在实例化集合类时,可以指明具体的泛型类型,指明完以后,
    在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)
    使用到类的泛型的位置,都指定为实例化的泛型类型。比如:add(E e)--->实例化以后:add(Integer e)
  • 泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,用包装类替换
  • 如果实例化时,没有指明泛型的类型。默认类型为为java.Lang.Object类型
  • 静态方法中不能使用类的泛型
  • 异常类不能是泛型的

泛型方法

  • 在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。
  • 换句话说,泛型方法所属的类是不是泛型类都没有关系。
  • 泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。
/**
  格式:类型变量(这里是T)放在修饰符(这里是 public static) 的后面,返回类型(这里是test01)的前面。
  该方法里面有泛型结构:<T>所以它是泛型方法
*/
class Person<T>{

    public static <E> E test01(E e){  //T 和 E 不相干
        return e;
    }
}

/**
 可以通过对类型变量T设置限定(bound)
 T 可以实现多个接口 并且只能继承一个类,这里都用extends表示,
 如果T继承了类,则这个类一定是限定列表的第一个。
public static <T extends Comparable> T test01(T t)
 也可用多个限定,此时用 & 分隔开
public static <T extends Comparable & Serializable> T test01(T t)
*/

泛型类型的继承原则

  • 假设employeemanager的超类,则ABC<Manager> 不是ABC<Employee>的子类。
  • 即无论 E 与 T 有什么联系,ABC<E>ABC<T>没有什么联系.
    如下:
ABC<Manager> managerBuddies = ...;
ABC<Employee> employeeBuddies = managerBuddies; // 编译时就会出错

类型擦除(方法擦除,变量擦除)

1. Java 泛型转换的事实:

  • 虚拟机中没有泛型, 只有普通的类和方法。
  • 所有的类型参数都用它们的限定类型替换。
  • 桥方法被合成来保持多态。
  • 为保持类型安全性,必要时插人强制类型转换。
    2. 例子
  • 泛型类型都有一个原始类型与之对应,原始类型就是删除类型参数后的泛型类型名。
  • 其中类型变量,替换为限定类型,若有多个类型,则替换为第一个限定类型。
    无限定类型时 用Object代替。如
public class Generic<T>{
      T name;//变量
      public static <T> T test01(T t){ //方法    
      }
}
//对应的原始类型为
public class Generic{
      Object name;
      public static Object test01(T t){
      }
}
//当有多个限定时
public class ABC<T extends Comparable & Serializable>{
      T name;//变量
      public static <T> T test01(T t){ //方法    
      }
}
//对应的原始类型为
public class ABC{
      Comparable  name;//变量
      public static Comparable  test01(T t){ //方法    
      }
}

Java 泛型 约定和局限

  • 不能用基本类型实例化类型参数,如不能使用ABC<double>,可以用ABC<Double>
  • 运行时类型查询只适用于原始类型。如
if (a instanceof Pair<String>) // Error
if (a instanceof Pair<T>) // Error
Pair<String> p = (Pair<String>) a; // Warning-can only test that a is a Pair
Pair<String> stringPair = . .
Pair<Employee〉employeePair = . .
if (stringPair.getClass() == employeePair.getClass()) // they are equal
//其比较的结果是 true, 这是因为两次调用 getClass 都将返回 Pair.class。

通配符类型

通配符:?

例子1:

    List<Object> list1 = null;
    List<String> list2 = null;
    list1 = list2; //编译不通过

    List<?> list = ...
    list = list1;
    list = list2;  //可以这样做

例子2:

        List<String> stringList = new ArrayList<>();
        stringList.add("AA");
        stringList.add("BB");
        stringList.add("CC");
        List<?> list = stringList;
        //对于List<?> 不能向里面添加数据,但是可以添加null
        //list.add("dd");//编译报错
        Object o = list.get(0);
        System.out.println(o); //result: AA

有限制条件的通配符

  • ABC<? extends Employee> 其中问号可以是一切类型,但需要是employee的子类。此时泛型之间的继承可以有如下关系:
    ABC<Manager>ABC<? extends Employee> 的子类型
  • 上届:<? extend ABC> ?处要匹配的类型需要是ABC的子类或者ABC(即?需要小于等于ABC)
  • 下届:<? super ABC> ?处要匹配的类型需要是ABC的超类或者ABC(即?需要大于等于ABC)可以为方法提供参数, 但不能使用返回值。
  • 直观地讲,带有超类型限定的通配符可以向泛型对象写人,带有子类型限定的通配符可以从泛型对象读取。
    例如
    public static void test(){
        List<? extends Person4> list1 = null;
        List<? super Person4> list2 = null;

        List<subPerson4> list3 = null;
        List<Person4> list4 = null;
        List<Object> list5 = null;

        list1 = list3;
        list1 = list4;
        //list1 = list5; //编译不通过

        //list2 = list3; //编译不通过
        list2 = list4;
        list2 = list5;

        list1 = list3;
        list2 = list4;

        //读数据
        Person4 person4 = list1.get(0);
        Object o = list2.get(0);

        //写数据
        //list1.add(new subPerson4()); //编译不通过
        list2.add(new Person4());
        list2.add(new subPerson4()); //多态形式
        //Person4的父类 编译不通过
        //list2.add(new Object()); //编译不通过
    }
posted @ 2021-01-17 09:27  先生胡  阅读(30)  评论(0编辑  收藏  举报