Day10_2 JavaSE 泛型

JavaSE 泛型(Generic)

一、为什么要有泛型Generic?

  • 为了保证只有指定类型添加到集合中,类型安全

  • 举例说明:

    package com.generic.demo01;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Demo01 {
        public static void main(String[] args) {
            //未使用泛型的集合任意类型可接受
          	List list = new ArrayList();
            list.add(111);
            list.add("SSS");
            list.add(true);
            
            //需求:保证集合仅添加一个类型的数据
            List<String> list1 = new ArrayList<String>();
            list1.add("aaaa");
            list1.add(111); //该语句出错,不能添加
        }
    }
    

注意:

​ (1) Java中的泛型,只在编译阶段有效。

​ (2)泛型信息不会进入到运行时阶段。

二、泛型的使用

1 泛型类

  • 对象实例化若不指定泛型,默认为:Object

  • 泛型不同的引用不能互相赋值

package com.generic.demo01;

public class Demo02 {
    public static void main(String[] args) {
        A<String> a1 = new A<String>(); //在new A对象时指定泛型类型为String
        a1.setKey("xxxx"); //对象使用setKey(T,key)方法,其中的key形参为String类型
        String s = a1.getKey();//T getKey() 返回值就是new对象确定返回值时String

        A<Integer> a2 = new A<Integer>();
        a2.setKey(1);
        Integer a = a2.getKey();

        A a3 = new A(); //相当于A<Object> a3 = new A<Object>();
        a3.setKey(new Object());
        Object obj = a3.getKey();

        //同样的类,但是在new对象时泛型指定了不同的数据类型,这些对象不能互相赋值
        //a1 = a2; //错误语句
    }
}

//此处的泛型T可以任意取名,A,B,V
//一般使用<T> --type
class A<T>{  //泛型类
    private T key;
    public void setKey(T key){
        this.key = key;
    }
    public T getKey(){
        return this.key;
    }
}

2 泛型接口

  • 定义语句:
//定义一个泛型接口
interface Generator<T>{
	T next();
}
  • 在声明类的时候,需要将泛型的声明也一起加到类中,否则会报错:“Unknown class”
  • 即:
    • class FruitGenerator<T> implements Generator<T>{...}
    • class FruitGenerator implements Generator<String>{...}
  • 实现接口语句:
class FruitGenerator1<T> implements Generator<T>{
  @Override
  public T next(){
    return null;
  }
}
//
class FruitGenerator2 implements Generator<String>{
  @Override
  public String next(){
    return null;
  }
}

案例展示:

package com.generic.demo02;

public class Demo01 {
    public static void main(String[] args) {
        B1<Object> b1 = new B1<Object>();
        B1<String> b2 = new B1<String>();

        //B2<Integer> b3 = new B2<Integer>();//不能执行,只能为String
        B2 b3 = new B2();
    } 
}

interface IB<T>{
    T test(T t);
}

//未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加入到类中
class B1<T> implements IB<T>{ //接口没有具体类型,则实现类也是一个泛型
    @Override
    public T test(T t) {
        return null;
    }
}

//若实现接口时,指定了接口泛型的具体数据类型,这个类实现接口所有方法的位置都要泛型替换实际的具体数据类型。
class B2 implements IB<String>{  //接口有具体类型,实现类创建对象时不用再声明泛型,声明反而会出错
    @Override
    public String test(String s) {
        return null;
    }
}

3 泛型方法

泛型方法有以下几种:

  • 无返回值的泛型方法
  • 有返回值的泛型方法
  • 形参为可变参数的泛型方法
  • 静态方法的泛型方法

泛型方法注意:

  • 泛型方法在调用之前没有固定的数据类型,调用时确定

  • 在调用时传入的参数是什么类型,泛型就会改为什么类型

案例展示:

package com.generic.demo03;

public class Demo01 {
    public static void main(String[] args) {
        Cc<Object> c = new Cc<Object>();
        c.test("xxx");
        //泛型方法在调用之前没有固定的数据类型
        //在调用时传入的参数是什么类型,泛型就会改为什么类型
        //泛型方法会在调用时确定泛型具体是什么类型
        Integer i = c.test1(2);//传递的参数是Integer,泛型就固定为Integer,并返回Integer
        Boolean b = c.test1(true);//传递参数是Boolean,泛型就固定为Boolean,并返回Boolean
    }
}

class Cc<E>{
    private E e;
    //静态方法的泛型方法
    public static <T> void test3(T t){
        //在静态方法中,不能使用类定义泛型,如果要使用泛型,只能使用静态方法自己定义的泛型
        //System.out.println(this.e);
        System.out.println(t);
    }
  
    //无返回值的泛型方法
    public <T> void test(T s){
        //在类上定义的泛型,可以在普通的方法中使用
        System.out.println(this.e);
        T t = s;
    }

    //有返回值的泛型方法
    public <T> T test1(T s){
        return s;
    }

    //形参为可变参数的泛型方法
    public <T> void test2(T... strs){
        for (T s : strs){
            System.out.println(s);
        }
    }
}

4 通配符<?>

不确定集合中的元素具体的数据类型,使用?表示所有类型。

  • 无限制的通配符

    案例展示:

    package com.generic.demo04;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Demo01 {
        public static void main(String[] args) {
            Dd d = new Dd();
            List<String> li1 = new ArrayList<>();
            d.test(li1);//可放入
    
            List<Integer> li2 = new ArrayList<Integer>();
            d.test(li2);//可放入
        }
    }
    
    class Dd{
        public void test(List<?> list){ //test方法需要一个list集合的参数,不确定list集合中元素数据类型
    
        }
    }
    
  • 有限制的通配符

    分为三种:

    • <? extends Person>//只允许泛型为Person及Person子类的引用调用。
    • <? super Person>//只允许泛型为Person及Person父类的引用调用。
    • <? extends Comparable>//只允许泛型为实现Comparable接口的实现类的引用调用。

    案例展示:

    package com.generic.demo04;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Demo01 {
        public static void main(String[] args) {
          
            List<C1> lc = new ArrayList<C1>();
            d.test1(lc); //可以放入
    
            List<D1> ld = new ArrayList<D1>();
            d.test1(ld); //可以放入
    
            List<B1> lb = new ArrayList<B1>();
            d.test1(lb); //不可以放入,出错!
            d.test2(lb); //可以放入
    
            List<IAImpl> lia = new ArrayList<IAImpl>();
            d.test3(lia); //可以放入
        }
    }
    
    class Dd{
        public void test1(List<? extends C1> list){//list参数的元素数据类型是C1及其子类
    
        }
        public void test2(List<? super C1> list){//list参数元素数据类型是C1及其父类
    
        }
        public void test3(List<? extends IA> list){//list元素数据类型为IA的实现类
    
        }
    }
    class A1{}
    class B1 extends A1{}
    class C1 extends B1{}
    class D1 extends C1{}
    
    interface IA{}
    
    class IAImpl implements IA{}
    
    

写在最后

Let us not become weary in doing good, for at the proper time we will reap a harvest if we do not give up.

To Demut!

发布了32 篇原创文章 · 获赞 39 · 访问量 1736

猜你喜欢

转载自blog.csdn.net/qq_44958172/article/details/104687173