38-7 泛型

95 阅读6分钟
/*
    泛型的好处:  1.避免强制类型转换的麻烦
        2.将运行时异常,提前到了编译时期,降低了程序员的工作量
        3.一旦指定泛型,数据类型将被统一
        4.实现代码的模板化,把数据类型当做参数传递
泛型是不存在多态的,左侧<>中写的类型必须和右侧<>中的类型保持一致
    泛型可以定义在哪些地方?
        1.可以定义在类 和方法(静态方法/非静态方法)上 和接口上
*/
        //创建集合,指定存储数据的类型String
        ArrayList<String> list = new ArrayList<>(); 
        //2.将运行时异常,提前到了编译时期,降低了程序员的工作量
         list.add(new Student("zs",18));
   //创建集合全部按照Object类型处理,不指定存储数据的类型String  
        ArrayList list2 = new ArrayList();  
        //增强for进行遍历
        for (Object obj : list2) {
            //把String提升为Object,不能调用String的特有方法
            //必须进行强制类型转换
            System.out.println(obj+"的长度: "+((String)obj).length());
        }
 泛型类定义
/*  泛型类: 定义的类上有属于类自己的泛型  
        定义类时,该类中需要处理某种类型的数据,但是什么类型,不确定,所以定义成泛型
        泛型变量一般用大写字母表示:
            T(Type),E(Element),K(Key),V(Value)

    泛型类的定义格式:     public class 类名<泛型变量><T> { } 
  泛型类上定义的泛型,什么时间确定具体的类型呢?
        创建该类的对象时,<>中写的是什么类型,泛型就代表什么类型
         泛型类中可以把泛型当成某种具体的类型提前使用
   方法上定义的泛型,什么时间确定具体的类型呢?     调用方法时,根据方法参数的类型,确定方法上定义的泛型的具体类型      
*/
public class MyClass03<T> {
    //定义变量
    private T t;
    //空参构造方法
    public MyClass03() {
    }
    //满参构造方法
    public MyClass03(T t) {
        this.t = t;
    }

    //set和get方法
    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}
//测试泛型类
public class Demo04GenericClass {
    public static void main(String[] args) {
        //空参构造创建对象 //确定泛型T的类型: String
        MyClass03<String> mc = new MyClass03<>();//右侧<>中可以不写东西,但是需要保留<>
     //set方法给成员变量赋值 /只能传String
        mc.setT("hello");
        //创建对象时,确定泛型为String 只能传String
        //mc.setT(100);//错误 
        //get方法获取成员变量的值
        String str = mc.getT();
        System.out.println(str);        
    }
}
 

非静态泛型方法

//泛型方法的定义
/* 不知道怎么处理就定义泛型方法
T: 属于类上定义的泛型,该类中所有非静态方法中都可以直接使用
 */
 非静态泛型方法: 定义的方法上有属于方法自己的泛型 
     
 非静态泛型方法的定义格式: 
    修饰符 <泛型变> <T> 返回值类型 方法名称(泛型变量 变量名称)(T t) {
        ...
    } 
        静态方法不能使用类上的泛型,必须自己定义  多了修饰符 static <泛型变> 
    修饰符 static <泛型变>  <T> 返回值类型 方法名称(泛型变量 变量名称) (T t){
        ...
    } 
public class MyClass04<T> {
    //不叫泛型方法 叫使用类上泛型的方法,因为泛型T不属于方法本身
    public void method(T t) {
        System.out.println(t);
    }

    //叫  非静态泛型方法 /泛型E只属于方法show自己
    public <E> void show(E e) {
        System.out.println(e);
    }
     /*
        静态方法: 不能使用类上定义的泛型
            静态方法直接有类名调用,此时没有对象,
            而类上的泛型,必须在创建对象时确定,
            既然没有对象,类上的泛型没有确定
     */
    /*public static void method(T t) {

    }*/
  静态泛型方法
    public static <E> void fun(E e) {
        System.out.println(e);
    }
}
//测试类
public class Demo05GenericMethod {
    public static void main(String[] args) {
        //创建对象,类上的泛型T被确定为: String
        MyClass04<String> mc = new MyClass04<>(); 
        mc.method("hello");
        //使用类上的泛型,只能传递String
        //mc.method(200); 
        //show方法上有自己的泛型 根据传递的参数,确定泛型的具体类型 使用更灵活
        mc.show("java");
        mc.show(100);可传除字符串之外的类型
        mc.show(new Student("zs",18));        
    }
           MyClass04.fun("Hello");
        MyClass04.fun(200);
        MyClass04.fun(new Student("ls",28));
}

##泛型接口

定义接口的定义格式:定义接口时,该接口中不确定 什么类型就定义成泛型
    public interface 接口名称<泛型变量><T> { ...  }
  接口中的所有非静态方法,都可以使用该泛型   
接口上定义的泛型,什么时间确定具体的类型呢?
    1.实现类实现接口时,确定接口上泛型的具体类型的话,  直接指定具体类型 
    2.定义实现类时,也不确定接口上的泛型   该实现类必须定义为泛型类
        而且实现类上的泛型和接口上的泛型要保持一致
        创建实现类对象时,确定具体的类型
public interface MyInter<T> {
    //抽象方法
    public abstract void method(T t);
}
/*
    实现类实现接口时,确定接口上泛型的具体类型的话,
    直接指定具体类型
 */
public class MyInterImplA implements MyInter<String> {

    @Override
    public void method(String s) {
        System.out.println(s);
    }
}
/*
    定义实现类时,也不确定接口上的泛型
    该实现类必须定义为泛型类
 */
public class MyInterImplB<T> implements MyInter<T> {
    @Override
    public void method(T t) {
        System.out.println(t);
    }
}
//测试类
public class Demo04GenericInterface {
    public static void main(String[] args) {
        MyInterImplA mia = new MyInterImplA();
        
        mia.method("hello");

        MyInterImplB<Student> mib = new MyInterImplB<>();

        mib.method(new Student("ww",38));
        //泛型被确定为Student
        //mib.method(100);
    }
}

泛型通配符--泛型通配符: ? 用来匹配泛型的,但是不能使用?定义泛型

使用泛型通配符,定义变量:  List<?> list 可以接收哪些对象?  (创建对象时,只要在<>中写上一种引用类型就可以)都可以
public class Demo05TongPeiFu {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("AAA");
        list.add("BBB");
        list.add("CCC");

        Set<Integer> list2 = new HashSet<>();
        list2.add(111);
        list2.add(222);
        list2.add(333);

        //调用方法
        print(list);
        print(list2);
        System.out.println("-------------");

        //调用方法

        print2(list);
        print2(list2);
    }
    /*  定义一个方法,完成以上两个集合的遍历String Integer  使用了泛型统配符?  */
    不存在多态不能使用object
    public static void print(Collection<?> coll) {
        for (Object s : coll) {
            System.out.println(s);
        }
    } 
    /*
        定义泛型方法  */
    public static <E> void print2(Collection<E> coll) {
        for (E e : coll) {
            System.out.println(e);
        }
    }
}
 List<Object> list2 = new ArrayList<Object>();

泛型的上限

    父类: Person  子类: Worker  子类: Teacher   子类: JavaTeacher 
    泛型的上限:     ? extends E : 表示Person类型或者Person类型的任意子类型
            //调用方法 
          print(list3);
      不管是Worker类还是Teacher类还是JavaTeacher类,都是Person的子类
        ? extends Person: Person类型或者Person类型的任意子类型
        //print(list4);//错误,因为String不是Person的子类
        //print(list5);//错误,因为Integer不是Person的子类
     /*
        定义一个方法,只能完成以上3个集合的遍历
        	ArrayList<Person>/ArrayList<Worker>/ArrayList<Teacher> 
     */
    public static void print(ArrayList<? extends Person> list) {
        for (Person p : list) {
            System.out.println(p);
        }
    } 
    

泛型的下限

    //使用3.7中定义的Person/Worker/Teacher/JavaTeacher类
    子类: JavaTeacher 父类: Teacher 父类: Worker  父类: Person 
        一个子类的父类可以有任意多个 
        如何表示出一个子类的任意父类呢?
        ?: 任意一种引用类型 
        ? super E: 表示E类型或者E类型的任意父类型  
        ArrayList<String> list4 = new ArrayList<>(); 
        ArrayList<Integer> list5 = new ArrayList<>(); 
        print(list3);
        //print(list4);//错误,因为String不是Teacher的父类
        //print(list5);//错误,因为Integer不是Teacher的父类
    *
        定义一个方法,只能完成以上3个集合的遍历
        ArrayList<Person>/ArrayList<Worker>/ArrayList<Teacher>
        不管是Person类还是Worker类都是Teacher类的父类
        ? super Teacher: Teacher类型或者Teacher类型的任意父类型 
    public static void print(ArrayList<? super Teacher> list) {
        for (Object o : list) {
            System.out.println(o);
        } 
        }