javaAPI-3(泛型)

用泛型控制集合元素

泛型即泛指任意类型,又叫参数化类型(ParameterizedType),对具体类型的使用起到辅助作用,常用在集合中,用于指定存放元素的类型;例如:

//等号前半部分指定泛型,等号后半部分在JDK7开始可以省略泛型指定
List<Integer> list=new ArrayList<>();
list.add(1);
list.add(2);
list.add("3");//添加非指定类型的元素就会编译报错

使用泛型的好处:类型安全,避免了取出元素后的类型转换

泛型类型只能是引用数据类型,若要指定基本数据类型,需要写基本数据类型的包装类名

定义泛型类

//在类名后面加泛型尖括号,里面注明泛型种类名称,举例:
public class 类名<T>{}

泛型种类名称并没有规定,无论使用哪个字母都能达到同样的效果,但是以下几个名称是常用到的:

        E-Element(在集合中使用,因为集合中存放的是元素)

        T -Type (java类)

        K-Key (键)

        V-Value(值)

        N-Number(数值类型)

        ?-表示不确定的java类型

定义带有泛型的接口与带泛型的类类似

//在类名后面加泛型尖括号,里面注明泛型种类名称,举例:
public interface 接口名<T>{}

接口中的抽象方法可以使用泛型作为方法的参数或者返回值


//后面的这个泛型也可以省略掉(省略不会在实现类报错,但是后面不写,同样的方法就不能算作重写)
修饰符 class 类名<泛型> implements 接口名<泛型>

举个例子:
public interface TestInter<T> {//先定义一个接口,引入泛型T
    public abstract int getNum(T t);//将T作为方法参数

    public abstract T getT(T t);//同时作为返回值类型和方法参数
}

//这里TestInterImpl后面的T不写,就会报错,因为下面的实现方法用到了T,
//但如果上面全部泛型不写,下面的T类型改为Object类型的话也不会报错,且同样算作实现方法
//这里TestInterImplT写了,后面TestInter位置的T不写,在类定义这一行不会报错,
//但是下面方法会报错,因为这里的T没有限定和接口T一同做限定,就会被判断为不同的方法签名,不能算作实现方法
public class TestInterImpl<T> implements TestInter<T> {
    @Override
    public int getNum(T t) {
        return 0;
    }

    @Override
    public T getT(T t) {
        return null;
    }
}

定义带泛型的方法

修饰符 <泛型> 返回值类型 方法名(参数列表(此处可用泛型)){方法体}

普通方法和静态方法都可以使用泛型,传递什么类型的参数,泛型就是什么类型

普通方法和静态方法都可以使用泛型

泛型通配符

<?>代表未知的数据类型,即通配符,可以通过在泛型中对?作范围限制来控制集合中存储的数据类型
泛型上限:类型名称<? extends> 对象名称
意义:只能接收指定类型及其子类
泛型下限:类型名称<? super> 对象名称
意义:只能接收该类型及其父类

PECS原则(Prodecer Extends Consumer Super):

频繁向外读取内容的,适合限制上界extends

频繁向内吸入内容的,适合限制下界super

extends可以作为返回类型限定,不能用于参数类型限定

super可以用于参数类型限定,不能用于返回类型限定

?既不能用于方法参数传入,也不能用作返回值类型

举例:

public class CardTest {
    public static void main(String[] args) {
        /*
        这里泛型的限制是P1的子类,但是是相对于集合内的元素来说的,
        在存入元素时,并不会判断该存入的元素是否是P1的子类
        因此第二行会编译报错
        */
        List<? extends P1> list1=new ArrayList<>();
        list1.add(new P2());
		
		/*
		这里限定了泛型是P1的父类,第二行就可以顺利存入了,这里的判断逻辑是:
		P1的父类型 集合内元素=P2的子类型 赋值来的数据
		这里就是多态的写法,对应的取出时就变成了
		? 要接受P1的变量=P1的子类型 集合内元素
		这样?处就只能时P1的父类了,没有定义P1的父类,因此只能拿Objext类型接收
		*/
        List<? super P1> list2=new ArrayList<>();
        list2.add(new P2());
        Object o = list2.get(0);

		/*
		这里同样,虽然没有存入元素,但是可以演示下取出元素时的逻辑
		? 要接受P3的变量=P3的子类型 集合内元素
		?处的类型只要是P3的父类都能顺利接收到,P1P2或者Object都可以
		*/
        List<? extends P3> list3=new ArrayList<>();
        P2 p2=list3.get(0);
    }
}
//下面简单定义了三个层层继承的类
class P1{

}
class P2 extends P1{

}
class P3 extends P2{

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值