java holder详解_Java泛型详解

泛型是Java 5引入的机制, 允许编写不关心具体类型的类或方法. 泛型最著名的应用是Collection框架.

List list = new ArrayList<>();

泛型类List在定义时并不关心元素类型, 只有在实例化时才获得具体的元素类型.

泛型类

声明泛型需要使用<>声明类型参数, 如, . 下面的示例中声明了一个Holder类, 它的item域可以存储任意类型的引用.

classHolder{

T item;

publicvoidset(T t){

item = t;

}

publicTget(){

return item;

}

publicstaticvoidmain(String[] args){

Holder holder = new Holder<>();

holder.set("Hello World");

System.out.println(holder.get());

}

}

在Java 7之前必须在创建实例时指定类型参数:

Holder holder = new Holder();

Java 7提供了类型推断功能, 可以根据声明推断实例的类型参数:

Holder holder = new Holder<>(); // 不必在new对象时再写一次类型参数了

或者在return时推断类型:

publicstaticHoldergetInstance(){

return new Holder<>();

}

示例中的Holder类没有对类型参数T做任何限制, T可以实例化为任意类型. Java允许我们限制对其进行限制.

: T必须为MyClass或其子类

: T必须为MyClass或其父类

比较常用的是extends限定, 因为子类必然定义了父类的方法(和域), 因此我们可以安全地访问父类声明的方法(和域).

下面的示例中访问item.length()是安全的, 因为T的基类String定义了该方法.

classHolder{

T item;

publicvoidset(T t){

item = t;

}

publicTget(){

return item;

}

publicintlength(){

return item.length();

}

publicstaticvoidmain(String[] args){

Holder holder = new Holder<>();

holder.set("Hello World");

System.out.println(holder.length());

}

}

泛型方法

Java也允许只为方法而非整个类声明类型参数:

public classMain{

public static voidlog(T t){

System.out.println(t);

}

publicstaticvoidmain(String[] args){

log(1);

}

}

类型通配符

在上文示例中, 我们总是在实例化泛型类时指定具体的类代替类型参数, 比如Holder使用String代替类型参数T.

类型通配符允许在实例化泛型类时不指定具体类:

Holder> holder = new Holder<>();

上述示例初始化了一个没有类型限制的Holder实例. 无任何限制的类型通配符可以被省略:

Holder holder = new Holder();

除非因为绝对必要的原因, 否则不建议使用无限制的类型通配符. 类型通配符同样可以使用extends和super进行范围限定.

Holder extends String> holder = new Holder<>();

上述示例中, holder的set方法不能正常编译. 类型通配符通常用于声明方法的参数类型:

classHolder{

T item;

publicvoidset(T t){

item = t;

}

publicTget(){

return item;

}

publicstaticvoidprint(Holder<?extendsString> holder){

System.out.println(holder.get());

}

publicstaticvoidmain(String[] args){

Holder holder = new Holder<>();

holder.set("Hello World");

print(holder);

}

}

类型擦除

java的泛型采用运行时类型擦除的方式实现泛型, 也就是说类型参数仅存在于编译期, 运行时虚拟机并不知道泛型参数的存在.

publicstaticvoidmain(String[] args){

List strings = new ArrayList<>();

List longs = new ArrayList<>();

System.out.println(strings.getClass() == longs.getClass());

}

上文示例输出true, 说明了运行期无法访问类型参数. 泛型是通过编译时添加了类型检查和自动转型的字节码来实现的.

数组也受到了类型擦除影响:

public classMain{

public static voidprint(T[] arr){

for (T t : arr) {

System.out.println(t);

}

}

publicstaticvoidmain(String[] args){

String[] strings = {"a", "b", "c", "d"};

print(strings);

}

}

上面的代码是可以正常运行的, 但是Java禁止直接创建泛型数组:

public static voidtest(){

T[] arr = new T[5];

}

禁止创建泛型数组的原因可以在Java Language Specification中窥见端倪:

[It is a compile-time error if the component type of the array being initialized is not reifiable(4.7)

看一下reifiable(物化)的定义:

A type is reifiable if and only if one of the following holds:

It refers to a non-generic class or interface type declaration.

It is a parameterized type in which all type arguments are unbounded wildcards (§4.5.1).

It is a raw type (§4.8).

It is a primitive type (§4.2).

It is an array type (§10.1) whose element type is reifiable.

因为类型擦除的原因, java.util.ArrayList采用了Object[]来存储元素.

0b1331709591d260c1c78e86d0c51c18.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值