黑马程序员技术交流社区
标题:
关于泛型通配符
[打印本页]
作者:
罗海云
时间:
2013-3-1 12:28
标题:
关于泛型通配符
本帖最后由 罗海云 于 2013-3-1 15:23 编辑
package com.itheima.p1.text;
class Text{
public static void main(String[] args){
demo<String> d = new demo<String>();
d.setName("a");
System.out.println(d.getName());
demo<?> d1 = d; // 为什么这句都成功了..
System.out.println(d1.getName());//这儿也可以取..就是不能赋值..
d1.setName("sss");//这儿设置不了值呢? 不是?通配符类似于Object的吗?
//这是什么原理呢?大家来解释解释..
}
}
class demo<T>{
private T name;
public T getName()
{
return name;
}
public void setName(T name)
{
this.name = name;
}
}
复制代码
作者:
唐长智
时间:
2013-3-1 13:19
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。
但是为什么不能参与调用参数化有关方法的原理不知道。
作者:
谢达
时间:
2013-3-1 13:39
void printCollection(Collection<?> c){
作者:
谢达
时间:
2013-3-1 13:48
因为不知道d1是具体是什么类型的,所以不能去设置其值,一个未知的引用无论是作为变量还是形参都是“只读的",
d1.setName("sss");//public void setName(T name) 因为这里的T不知道具体是类型,所以这里会出错
void printCollection1(Collection<Object> c); //这里只能接收Collection<Object>类型的参数
void printCollection1(Collection<?> c);//这个就可以接收任意类型Collection参数
所以?与Object不类似吧,个人见解,
作者:
付玉光
时间:
2013-3-1 14:10
本帖最后由 付玉光 于 2013-3-1 14:17 编辑
class Text3{
public static void main(String[] args){
demo<String> d = new demo<String>();
d.setName("a");
System.out.println(d.getName());
//demo<?> d1 表示它可接收demo类中泛型类型为任意引用类型的demo对象的引用。
//此处它的用法类似于多态
demo<?> d1 = d;
//这里可以取值,是因为该方法是与泛型类型参数无关的方法(该方法不用接收泛型类型参数)。
//也就是说:你上面因事先就声明了它里面的类型,里面声明的什么类型,
//我调用该方法时就返回什么类型就行了。
System.out.println(d1.getName());
//这里不能赋值是因为,d1中的泛型类型为不具体类型,
//也就是说,连它自己都不知道它中的泛型类型是什么
//具体类型(它不知道自己是什么类型的,并不表示你就可以像其中放任何引用类型),
//你怎么能给它赋String类型的呢?
d1.setName("sss");
}
}
class demo<T>{
private T name;
public T getName()
{
return name;
}
public void setName(T name)
{
this.name = name;
}
}
希望对你有帮助{:soso_e100:}
作者:
罗海云
时间:
2013-3-1 15:22
额.谢谢楼上几位的解答..我懂了
作者:
李易烜
时间:
2013-3-1 15:29
通配符的一个好处是允许编写可以操作泛型类型变量的代码,并且不需要了解其具体类型。
--------------------------------------------------
例如
demo<String> d = new demo<String>();
d.setName("a");
demo<?> d1 = d;
System.out.println(d1.getName());//这儿也可以取..就是不能赋值..
d1.setName("sss");//这儿设置不了值呢? 不是?通配符类似于Object的吗?
//这是什么原理呢?大家来解释解释..
--------------------------------------------------
其实上面语句能做许多工作:它能调用 get() 方法,并且能调用任何从 Object 继承而来的方法(比如 hashCode())。
它惟一不能做的事是调用 set() 方法,这是因为在不知道该 Demo 实例的类型参数 T 的情况下它不能检验这个操作的安全性。
由于 d1 是一个 Demo<?> 而不是一个原始的 Demo,编译器知道存在一些 T 充当 demo 的类型参数,
但由于不知道 T 具体是什么,您不能调用 set() ,因为不能检验这么做不会违反 Demo 的类型安全限制
(实际上,您可以在一个特殊的情况下调用 set():当您传递 null 字母时。我们可能不知道 T 类型代表什么,但我们知道 null 字母对任何引用类型而言是一个空值)。
--------------------------------------------------
关于 d1.get() 的返回类型,d1 了解哪些内容呢?
它知道 demo.get() 是某些未知 T 的 T,因此它可以推断出 get() 的返回类型是 T 的擦除(erasure),
对于一个无上限的通配符就是 Object。因此上面的表达式 d1.getName() 具有 Object 类型,可以打印a。
--------------------------------------------------
d1.setName("sss"):为什么报错?(“capture#1 of ?”)
“capture#1 of ?” 表示什么?
当编译器遇到一个在其类型中带有通配符的变量,
比如 Demo<?> d1,它认识到必然有一些 T ,对这些 T 而言 d1 是 Demo<T>。
它不知道 T 代表什么类型,但它可以为该类型创建一个占位符来指代 T 的类型。
占位符被称为这个特殊通配符的捕获(capture)。
这种情况下,编译器将名称 “capture#1 of ?” 以 d1 类型分配给通配符。
每个变量声明中每出现一个通配符都将获得一个不同的捕获,因此在泛型声明 foo(Pair<?,?> x, Pair<?,?> y) 中,编译器将给每四个通配符的捕获分配一个不同的名称,因为任意未知的类型参数之间没有关系。
错误消息告诉我们不能调用 Set(),因为它不能检验 set() 的实参类型与其形参类型是否兼容:
因为形参的类型是未知的。在这种情况下,由于 ? 实际表示 “?extends Object” ,
编译器已经推断出 d1.get() 的类型是 Object,而不是 “capture#1 of ?”。
它不能静态地检验对由占位符 “capture#1 of ?” 所识别的类型而言 Object 是否是一个可接受的值。
作者:
李易烜
时间:
2013-3-1 15:36
--------------------------------------------------
说白了就是demo<?>这种定义的泛型中调用带泛型参数并且要去改变其内部值的方法,在调用时都不知道自己内部值的原类型了。
不过你怎么会这么用呢?
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2