这里写目录标题
1,匹配任意类型的通配符
在开发中,对象的引用传递是最常见的,但是如果在泛型类的操作中,在进行引用传递的时候,泛型类型必须匹配才可以传递,否则是无法传递的。
class Info<T>{
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo12{
public static void main(String args[]){
Info<String> i = new Info<String>() ; // 使用String为泛型类型
i.setVar("MLDN") ; // 设置内容
fun(i) ;
}
public static void fun(Info<Object> temp){ // 接收Object泛型类型的Info对象
System.out.println("内容:" + temp) ;
}
};
运行结果:
发现报错了,编译报错提示,object类型的泛型不能接收string类型的泛型。Info<String> Info<Object>
泛型对象进行引用传递的时候,类型必须一致,否则无法传递,因为泛型本身就是一个标识符,具体的类型是从外面确定外面传入的,
编译器只判断是不是相同的标识符,不是相同的标识符就编译报错了
问题:
对于上面的问题,泛型类型不一致所以无法传递引用数据类型,但是如果现在我坚持,非要这么传递呢?该怎么办呢?
解决
其实,也简单,可以将fun方法中Info参数的泛型取消掉。
class Info<T>{
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo13{
public static void main(String args[]){
Info<String> i = new Info<String>() ; // 使用String为泛型类型
i.setVar("MLDN") ; // 设置内容
fun(i) ;
}
public static void fun(Info temp){ // 接收Object泛型类型的Info对象
System.out.println("内容:" + temp) ;
}
};
解决的不彻底,引入了新问题
发现,执行没有任何问题,取消掉参数的泛型以后,可以正常执行,但是这样似乎不太妥当,因为毕竟Info在声明的时候是指定了泛型的,
那么,如何解决这个不太妥当的问题呢?
整理一下现状:
在这个fun方法的参数中,加入泛型,会可能导致类型不匹配而报异常无法执行程序,不加泛型,又似乎不太妥当,代码并不是那么严密,在精细的开发中这样是不允许的,
那么这个问题,怎么解决呢?
解决
对于这个问题,就需要使用泛型的通配符来处理了。
class Info<T>{
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo14{
public static void main(String args[]){
Info<String> i = new Info<String>() ; // 使用String为泛型类型
i.setVar("MLDN") ; // 设置内容
fun(i) ;
}
public static void fun(Info<?> temp){ // 可以接收任意的泛型对象
System.out.println("内容:" + temp) ;
}
};
在程序的fun()
方法中使用Info<?>
的代码形式,表示可以使用任意泛型类型对象,这样做的话,fun()
方法定义的就比较合理了,
但是在使用以上语法的时候,也需要注意一点:
如果使用了“?”
接收泛型对象的时候,则不能修改接收到的内容。
也就是说,使用了“?”
可以接收任意的内容,但是此内容无法直接使用<?>修饰的泛型对象进行修改。
什么意思呢,比如说:
class Info<T>{
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo15{
public static void main(String args[]){
Info<?> i = new Info<String>() ; // 使用 ?接收String泛型类型
i.setVar("MLDN") ; // 设置内容
}
};
发现编译时报错了,在使用“?”的时候,只能接收,不能修改。
?
并不表示某个具体的泛型类型,问号表示并不知道内部是什么泛型,只是黑盒接收该泛型过来而已,并不能修改。
使用?
只能接收,不能修改;
2,受限泛型
之前设置泛型的时候,实际上都是可以任意设置的,只要是类就可以设置,比如String,Float,Integer。。。。。。但是在Java的泛型中可以指定一个泛型的 上限和下限。即表示,泛型最大到哪个父类,最小到哪个子类;
在应用传递中,泛型的曹组可以设置一个泛型对象的范围上限和范围下限。
范围上限使用extends关键字声明,表示参数化的类型可能是所指定的类型,或者是此类型的子类;而范围下限使用super进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至object类。
设置上限,使用extends:
上限及表示,最大是本类及本类的子类。
class Info<T extends Number>{
<T extends Number>
表示上限:最高就是Number的类型,或者是Number的子类的数据类型。不能高于Number,比如Number之上的Object就是不可以的
class Info<T>{
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo17{
public static void main(String args[]){
Info<Integer> i1 = new Info<Integer>() ; // 声明Integer的泛型对象
Info<Float> i2 = new Info<Float>() ; // 声明Float的泛型对象
i1.setVar(30) ; // 设置整数,自动装箱
i2.setVar(30.1f) ; // 设置小数,自动装箱
fun(i1) ;
fun(i2) ;
}
public static void fun(Info<? extends Number> temp){ // 只能接收Number及其Number的子类
System.out.print(temp + "、") ;
}
};
错误用法:
class Info<T>{
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo18{
public static void main(String args[]){
Info<String> i1 = new Info<String>() ; // 声明String的泛型对象
i1.setVar("hello") ;
fun(i1) ;
}
public static void fun(Info<? extends Number> temp){ // 只能接收Number及其Number的子类
System.out.print(temp + "、") ;
}
};
在类上使用泛型上限:最大是Number或者是Number的子类。String并不是Number的子类,所以fun()
方法并不能接收String的泛型对象,编译会报错。
class Info<T extends Number>{ // 此处泛型只能是数字类型
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo19{
public static void main(String args[]){
Info<Integer> i1 = new Info<Integer>() ; // 声明Integer的泛型对象
// 错误,无法声明String的泛型对象,Info在定义的
Info<String> i1 = new Info<String>() ;
}
};
class Info<T extends Number>{ // 此处泛型只能是数字类型
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo20{
public static void main(String args[]){
// 错误,无法声明String的泛型对象,Info在定义的时候已经声明,只能接收Number及其子类的泛型类型
Info<String> i1 = new Info<String>() ;
}
};
Info在定义的时候已经声明,只能接收Number及其子类的泛型类型,最高不能超过Number。传入String类型,编译时候肯定会报错,因为String并不是Number的子类,。
设置下限,使用super
下限表示,最低到哪个类型。
当使用的泛型只能在本类以及父类类型上应用的时候,就必须使用泛型的范围下限配置。使用super。
class Info<T>{
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo21{
public static void main(String args[]){
Info<String> i1 = new Info<String>() ; // 声明String的泛型对象
Info<Object> i2 = new Info<Object>() ; // 声明Object的泛型对象
i1.setVar("hello") ;
i2.setVar(new Object()) ;
fun(i1) ;
fun(i2) ;
}
public static void fun(Info<? super String> temp){ // 只能接收String或Object类型的泛型
System.out.print(temp + "、") ;
}
};
运行结果,看到没有任何问题。
Info<? super String>
泛型的上限是String或者String的父类,也就是Object。如果使用Integer作为作为泛型类型,则不满足泛型类型的下限。
class Info<T>{
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo22{
public static void main(String args[]){
Info<Integer> i1 = new Info<Integer>() ; // 声明Integer的泛型对象
i1.setVar(30) ;
fun(i1) ;
}
public static void fun(Info<? super String> temp){ // 只能接收String或Object类型的泛型
System.out.print(temp + "、") ;
}
};
运行结果看到了,fun(Info<? super String>)
方法中泛型最低的下限到String,现在传入的是Integer,并不符合条件,所以无法设置。
泛型的上限,下限就是extends与super关键字。
3,泛型与子类继承的限制
一个类的子类可以通过对象的多态性,为其父类实例化,也就是父类可以接收子类对象,
但是在泛型的操作中,子类的泛型类型是无法使用父类的泛型类型接收的,泛型类型必须完全一致才可以接收。但是可以使用通配符进行接收,这样的话当然接得接收收后不能修改的限制。。
比如:Info<String>
不能使用Info<Object>
接收。但是可以使用通配符进行接收。
class Info<T>{
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
};
public class GenericsDemo23{
public static void main(String args[]){
Info<String> i1 = new Info<String>() ; // 泛型类型为String
Info<Object> i2 = null ;
Info<?> i3=null;
i2 = i1 ;//这是错误的
i3=i1;//这就没问题了,正确
}
};
这是无法执行的,只能使用通配符来接收。
总结:
1,使用“?”
可以接收任意的泛型对象。
2,泛型的上限:Info<? extends Number>
泛型数据类型是Number或者Number的子类。
3,泛型的下限:Info<? super String>
泛型的数据类型是String以及String的父类都是可以的
4,为什么泛型子类之间的继承无法直接转换的原因。子类的泛型类型是无法使用父类的泛型类型接收的,泛型类型必须完全一致才可以接收。但是可以使用通配符进行接收,这样的话当然接得接收收后不能修改的限制。