泛型与无边界通配符

资料整理:

Java泛型知识点

夯实JAVA基本之二 —— 反射(1):基本类周边信息获取_启舰的博客-CSDN博客

使用整理:

泛型:

泛型是约束类型,分“显示”泛型和“隐示”泛型

显示泛型:

内部定义指定类型,外部调用只能传入指定类型,否则报错

如:

List<String>   只能添加String类数据

隐示泛型:

隐示泛型就是不明确表示类型,而用字母T代表

它跟接口有点类似,实现方不用担心这个类是由谁来调用,只要在有需要的地方编写功能即可,T的具体类型由调用者来决定

(这里的T可以是任意字母,只代表了Type的缩写,是规范,例如Key,Value的缩写是K,V)

隐士泛型类定义:

class Point<T>

调用:

Point<类型> p = new Point<类型>() ;

隐士多泛型定义:

class MorePoint<T,U>​​​​​​

调用:

MorePoint<类型,类型> p = new MorePoint<类型,类型>() ;

声明时每个之间用逗号隔开,调用时按顺序每个之间用逗号隔开,无最大限度,如果在实例化时想给自定义类型赋值,构造方法里可执行

泛型接口定义:

interface Info<T>

非泛型类直接调用:

class InfoImpl implements Info<String>

泛型类"可"间接调用:

class InfoImpl<T> implements Info<T>

这里把类的T类型直接赋值给接口的T,也就导致最外部调用传的是什么类型,接口也将是什么类型

泛型函数定义:

返回值前定义<T>

public class StaticFans {
    //静态函数
    public static  <T> void StaticMethod(T a){
        Log.d("harvic","StaticMethod: "+a.toString());
    }
    //普通函数
    public  <T> void OtherMethod(T a){
        Log.d("harvic","OtherMethod: "+a.toString());
    }
}
调用:

//静态方法
StaticFans.StaticMethod("adfdsa");//使用方法一,根据传入的值来确定泛型的类型
StaticFans.<String>StaticMethod("adfdsa");//使用方法二
//普通函数
除了需要实例化,与上面一样

​方法一: 直接传值,任何值都可以(但必须是派生自Object类型,比如String,Integer等),不要用这种隐式传递方式,代码不利于维护。从外观看不出调用的是泛型函数。 ​​​​​​

方法二:在调用前加了一个<String>来指定<T>的值,这是我们建议的方式。

返回值中存在泛型\Class类泛型:


public static <T> List<T> parseArray(String response,Class<T> object){
    List<T> modelList = JSON.parseArray(response, object);
    return modelList;
}

Class<T>类传递:

Class<T>传值:

XXXX类.class

定义泛型数组:

定义:
public static <T> T[] fun1(T...arg){  // 接收可变参数  
       return arg ;            // 返回泛型数组  
}  
使用:
public static void main(String args[]){  
       Integer i[] = fun1(1,2,3,4,5,6) ;
       Integer[] result = fun1(i) ;

该示例利用到可变长参数,这里不讲解,不懂可去学

类型绑定:

在运行时,编译器不知道方法内部的T代表什么类型,只有调用者给出类型,它才知道是什么类型

所以在编写时的T默认只能调用Object方法,T肯定是Object的子类

如果我们在编写时,需要泛型类是某一部分类型,这样我们在编写时,可以调用其方法,就可以用到类型绑定

定义:

<T extends BoundingType>

此时的T表示是自定义类的子类型,传入的T可以是类,也可以是接口,BoundingType一样

这时的T就是在父类基础上创建的,拥有父类的所有功能,所以在编写时,就可以调用父类的函数,该继承和正常的extends开销更小,生命周期更短,称之为绑定,脱离了这个范围,它们的继承关系就没了

调用:

参考之前的调用,不同位置会有不同的调用方式

绑定多个类型:

同时绑定多个类型,用&连接

<T extends Fruit&Serializable>

如果是多个泛型,且每个泛型都带绑定,那应该是这个样子

public static <T extends Comparable & Serializable, U extends Runnable> T foo(T a, U b)

调用:

参考之前的调用,不同位置会有不同的调用方式

泛型定义字母规范:

在定义泛型时,用于指定泛型的变量是一个大写字母,为了提高可读性,用有意义的字母比较好,在不同的情境下使用的字母意义如下:

  •  E      — Element,常用在java Collection里,如:List<E>,Iterator<E>,Set<E>
  •  K,V   — Key,Value,代表Map的键值对
  •  N      — Number,数字
  •  T       — Type,类型,如String,Integer等等

无边界通配符:

?就是无边界通配符

?与T的区别:

T只能在类,接口,函数中声明时使用

无边界通配符在定义变量时只是用于填充泛型T,在实例化时才给实际值,实例化给的是什么类型,?就是什么类型 

例如:

Point<?> point=new Point<Integer>(3,3);

Point<?> point=Point<Float>(4.3f,4.3f);

构造泛型实例时,如果省略了填充类型,则默认为无边界通配符

Point point=Point<Float>(4.3f,4.3f);

通配符?的extends:

代表该类型实例化时必须直接或间接继承了XX类型,外部只能传入类型不能实例化,T所在类实例化,外部调用继承方法

该继承和正常的extends相比开销更小,生命周期更短,称之为类型绑定,脱离了这个范围,它们的继承关系就没了

声明:

Point<? extends Number> point

示例:

public class myTestClassP extends CommonTools {

}

public class myTestClass<T> {
    T testT;
    void initT() {
        //实例化
        testT = (T) new myTestClassP();
    }
}

使用:

myTestClass<? extends CommonTools> point = new myTestClass<>();
if (point.testT == null) {
    point.initT();
}
//调用继承方法
point.testT.annalLog("1111", false);

通配符?的super绑定:

代表该类型实例化时必须直接或间接继承了XX类型,外部和T所在类都能实例化,外部调用继承方法

(判断是否为继承是包含边界的,也就是XXX类本身)

声明:

<? super XXX>                                   表示填充为任意XXX类的子类

示例:

public class myTestClass<T> {
    T testT;
}

使用:

myTestClass<? super CommonTools> point = new myTestClass<>();
if (point.testT == null) {
    //实例化
    point.testT = new SellFragmentDom();
}
//调用父类方法
((SellFragmentDom) point.testT).annalLog("super 2222", false);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值