java和kotlin泛型

java泛型

1:为什么需要泛型?
适用于多种数据类型执行相同的代码,泛型中的类型在使用时指定,不需要强制类型转换。
2:如何定义泛型类与泛型方法?
泛型即“参数化类型”,操作的数据类型被指定为一个参数。
3:泛型类与泛型接口的定义
引用一个类型变量T(其他大写字母都可以)并且用<>括起来,并放在类名的后面,泛型是用允许有多个类型变量的。
public interface Genertor {
public T next();
}

public class ImplGenertor implements Genertor {
@Override
public T next() {
return null;
}
}
4:泛型方法的定义
泛型方法,是在调用方法的时候指明泛型的具体类型,泛型方法可以在任何地方和任何场景中使用,包括普通类和泛型类。
public T genericMethod(T…a){
return a[a.length/2];
}

//使用了泛型却不是一个泛型方法,这只是类中的一个普通成员方法,只不过他的返回值是泛型类中已经声明了的泛型。
public T genericMethod(T…a){
return a[a.length/2];
}
5:怎么限定类型变量?
有时候我们需要对类型变量加以约束,比如计算两个变量的最小最大值。
为了确保传入的两个变量一定有compareTo方法,将T限制为实现了接口Comparable的类。
public static T min(T a,T b){
if(a.comapareTo(b)>0) return a; else return b;
}
6:泛型有什么局限性?
因为java中的泛型是利用泛型擦除实现的,目前还有以下局限性。
不能再静态域或者方法中引用类型变量。因为泛型是要在对象创建的时候才知道是什么类型,而对象创建的代码执行先后顺序是static的部分,然后才是构造函数等等。所以再对象初始化之前static的部分已经执行了,如果再静态部分引用的泛型,那么毫无疑问虚拟机根本不知道是什么东西,这个时候类还没有初始化。

7:泛型类型的继承规则是怎么样的?
泛型类可以继承或者扩展其他泛型类,比如List和ArrayList。

虚拟机是如何是如何实现泛型的?什么是泛型擦除?

早期java没有出现泛型的时候,只能通过Object是所有类型的父类和类型强制转换两个特点的配合来实现类型泛化。
java语言中的泛型只在程序源码中存在,在编译后的字节码文件中,就已经替换为原来的原生类型(Raw Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码,因此,对于运行期的Java语言来说,ArrayList<int>与ArrayList<String>就是同一个类,所以泛型技术实际上是Java语言的一颗语法糖。
java语言中泛型的实现方法称为类型擦除。

为什么泛型擦除后get不需要类型转换?

因为擦除问题,所有的泛型类型变量最后都会被替换为原始类型。这样就引起了一个问题,既然都被替换为原始问题,那么为什么我们在获取的时候,不需要进行强制类型转换呢?看下ArrayList和get方法:
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
再return之前,会根据泛型变量进行强转。写了个简单的测试代码:
public class Test {
public static void main(String[] args) {
ArrayList list=new ArrayList();
list.add(new Date());
Date myDate=list.get(0);
}
然后反编了下字节码,如下:
public static void main(java.lang.String[]);
Code:
0: new #16 // class java/util/ArrayList
3: dup
4: invokespecial #18 // Method java/util/ArrayList."<init
😦)V
7: astore_1
8: aload_1
9: new #19 // class java/util/Date
12: dup
13: invokespecial #21 // Method java/util/Date.""😦)

16: invokevirtual #22 // Method java/util/ArrayList.add:(L
va/lang/Object;)Z
19: pop
20: aload_1
21: iconst_0
22: invokevirtual #26 // Method java/util/ArrayList.get:(I
java/lang/Object;
25: checkcast #19 // class java/util/Date
28: astore_2
29: return
看第22 ,它调用的是ArrayList.get()方法,方法返回值是Object,说明类型擦除了。然后第25,它做了一个checkcast操作,即检查类型#19, 在在上面找#19引用的类型,他是9: new #19 // class java/util/Date是一个Date类型,即做Date类型的强转。所以不是在get方法里强转的,是在你调用的地方强转的

kotlin泛型

kotlin泛型中引入了in和out

Out(协变)

如果你的类是将泛型作为内部方法的返回,那么可以用 out:

interface Production {
fun produce(): T
}

可以称其为 production class/interface,因为其主要是产生(produce)指定泛型对象。因此,可以这样来记:produce = output = out。
相当于Java中的? extends T

In(逆变)

如果你的类是将泛型对象作为函数的参数,那么可以用 in:
interface Consumer {
fun consume(item: T)
}

可以称其为 consumer class/interface,因为其主要是消费指定泛型对象。因此,可以这样来记:consume = input = in。
相当于Java中的? super T

Invariant(不变)

如果既将泛型作为函数参数,又将泛型作为函数的输出,那就既不用 in 或 out。
interface ProductionConsumer {
fun produce(): T
fun consume(item: T)
}

“父类泛型对象可以赋值给子类泛型对象,用 in;
子类泛型对象可以赋值给父类泛型对象,用 out。”

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值