您的位置 首页 java

java之用故事来理解泛型

  大家好,我是一个 泛型 ,我的出现是为了代表不同的参数类型,以减少因为参数类型对代码造成的束缚,同时使代码更简洁。     比如小明为公司开发一个接口,这个接口可以传入不同的参数类型,那么在我没诞生前,小明需要写多个接口,如下:

public
 
interface
 
ICommonGeneric
 
{
 
String
 
get
(
String
 a
);
 
Integer
 
get
(
Integer
 a
);
}
 

实现类需要实现每一个接口,尽管处理逻辑相同:

public
 
class
 
CommonGenericImpl
 
implements
 
ICommonGeneric
 
{
 
@Override
 
public
 
String
 
get
(
String
 a
)
 
{
 
//do something
 
return
 a
;
 
}
 
@Override
 
public
 
Integer
 
get
(
Integer
 a
)
 
{
 
//do something
 
return
 a
;
 
}
}
 

    那么有没有一种方式可以代表不同参数的类型呢,也就是说不用在接口中具体指定到底是String还是Integer,而是在实现时确定呢?于是我便出现了。     大家可以叫我 泛型化参数 ,因为我也代表一个参数,只是我代表的是参数的类型,我也有 形参 和实参。     形参 一般通过一对尖括号 加 T(一般用一个大写字母表示)等,也可以包括多个形参,实参就是调用者传给我的,如果是接口泛型,需要在类上指明泛型类型,如果是泛型方法的话,通过编译器的类型参数推断得到,不用码农们指定啦。下面介绍下简单泛型,接口泛型和方法泛型的使用:

简单泛型 : 在类上通过声明泛型,可以看到通过引用泛型提高了类的可重用性,使得方法可以接受不同类型的参数, 在实例化类时指定泛型的实参

public
 
class
 
SimpleGeneric
<
T
>
 
{
 
 void 
 doSomething
(
T t
)
 
{
 
//do  something 
 
}
 T getT
(
 T t 
)
 
{
 doSomething 
(
t
);
 
return
 t
;
 
}
 
public
 
 static 
 
void
 main
(
String
[]
 args
)
 
{
 
SimpleGeneric
<
String
>
 stringSimpleGeneric 
=
 
new
 
SimpleGeneric
<>
 
();
 stringSimpleGeneric
.
doSomething 
(
" nothing "
);
 
String
 result 
=
 stringSimpleGeneric
.
getT 
(
"nothing"
);
 
}
}
 

可以看到,使用泛型类似于一个工厂模式,只是工厂的条件变成了泛型的实参而已。

接口泛型 :如上面小明的代码,可以通过添加一个接口泛型来代表传入的参数类型,而在具体的实现时,在实现类指定泛型的实参

public
 
interface
 
IImprove
<
T
>
 
{
 T 
get
(
T t
);
}
 

实现类,指定泛型实参:

public
 
class
 
ImproveImpl
 
implements
 
IImprove
<
String
>
 
{
 
@Override
 
public
 
String
 
get
(
String
 s
)
 
{
 
//do something
 
return
 s
;
 
}
}
 

接下来看一下 方法泛型 :

public
 
class
 
GenericityTest1
 
{
 
public
 
static
 
<
T
>
 T saySomething
(
T t
){
 
//do something 
 
System
.
out
.
println 
(
" She say "
 
+
 t
);
 
return
 t
;
 
}
 
public
 
static
 
void
 main
(
String
[]
 args
)
 
{
 
String
 something 
=
 
GenericityTest1
.
saySomething 
(
" good morning "
);
 
}
}
 

    泛型方法一般通过在方法前加一个来声明一个泛型,方法泛型的实参通过 编译器 对具体调用的参数的类型获得,比如在main函数中调用saySomething时,编译器推断出这个参数为String类型,因此确定泛型T类型为String     问题来了,如果码农们想指定泛型所代表的类型范围时,该怎么办呢?java为泛型重用了extends关键字。

public
 
static
 
<
T 
extends
 
Integer
>
 T saySamethingUserful
(
T t
)
 
{
 
//do something
 
System
.
out
.
println 
(
" She say "
 
+
 t
);
 
return
 t
;
}
public
 
static
 
void
 main
(
String
[]
 args
)
 
{
 
GenericityTest1
.
saySamethingUserful 
(
1
);
}
 

    比如上面的泛型方法,在调用时,就只能使用Integer或其子类类型的泛型,感觉一下子回到了解放前,因为我们知道Integer是final的,实际上这个例子限制了只可以使用Integer类型的参数。     这里一个典型的应用就是我们需要传入的参数是某个接口的实现类时:     比如一个接口

public
 
interface
 
IGenericInterface
 
{
 
void
 sayGeneric
();
}
 

在方法中限定参数必须为这个接口的实现类,那么在调用时传入这个接口的实现类,以解耦代码

public
 
static
 
<
T 
extends
 
IGenericInterface
>
 T genericFunc
(
T t
){
 
return
 t
;
}
public
 
static
 
void
 main
(
String
[]
 args
)
 
{
 
GenericTestImpl
.
genericFunc 
(
new
 
IGenericInterface
 
()
 
{
 
@Override
 
public
 
void
 sayGeneric
()
 
{
 
//do something
 
}
 
});
}
 

    最后需要注意泛型的擦除,泛型只在编译时起效果,在编译后的 class文件 中是看不到泛型的。因为泛型的开发者为了保证java的向后兼容性而采取的一种做法。所以我们无法使用 instanceof 关键字

public
 
static
 
<
T 
extends
 
IGenericInterface
>
 T genericFunc
(
T t
){
 t 
instanceof
 T
;
 
//error
 
return
 t
;
 

关注加私信回复学习免费领取最新学习资料

文章来源:智云一二三科技

文章标题:java之用故事来理解泛型

文章地址:https://www.zhihuclub.com/182169.shtml

关于作者: 智云科技

热门文章

网站地图