A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© liuzhming 中级黑马   /  2013-7-23 18:58  /  1065 人查看  /  6 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

在下面的代码中为什么最后一句会编译失败?
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class GenericTest<T>
{
        private T foo;
        public T getFoo()
        {
                return foo;
        }

        public void setFoo(T foo)
        {
                this.foo = foo;
        }
       
        public static void main(String[] args)
        {
                GenericTest<? extends List> ge = null;
                ge = new GenericTest<ArrayList>();
                ge = new GenericTest<LinkedList>();
               
                GenericTest<? super List> ge2 = null;
                ge2 = new GenericTest<Object>();
               
                GenericTest<String> ge3 = new GenericTest<String>();
                ge3.setFoo("hello world");
               
                GenericTest<?> ge4 = ge3;
                System.out.println(ge4.getFoo());
                ge4.setFoo(null);
                System.out.println(ge4.getFoo());
            ge4.setFoo("welcome");//在前面可以将null传给它,为什么这条语句会失败呢?
        }
}

6 个回复

倒序浏览
  ge4.setFoo(null);
                 System.out.println(ge4.getFoo());
             ge4.setFoo("welcome");//
已经赋值为空了再赋值“welcome”当然编译出错了,字符串具有不变性;

评分

参与人数 1技术分 +1 收起 理由
杨兴庭 + 1 赞一个!

查看全部评分

回复 使用道具 举报
问题错误之处在于通配符的使用:
注意两点:
1.通配符修饰的泛型不能用来直接创建变量对象。
2.通配符修饰相当于声明了一种变量,它可以作为参数在方法中传递。
  这么做带来的好处就是我们可以将应用于包含某些数据类型的列表的方法也应用到包含其子类型的列表中。
  相当于可以在列表中用到一些面向对象的特性。
GenericTest<?> ge4 = ge3;//错在此句
改为:
GenericTest<String> ge4 = ge3;

评分

参与人数 1技术分 +1 收起 理由
杨兴庭 + 1 赞一个!

查看全部评分

回复 使用道具 举报
我觉的也像是通配符有问题
GenericTest<?> ge4 = ge3;
应该是String

评分

参与人数 1技术分 +1 收起 理由
杨兴庭 + 1

查看全部评分

回复 使用道具 举报
首先,要去了解泛型使用通用类型通配符的具体规则。

当使用A<?>这种形式来定义泛型类型的时候,称之为通配符定义,
而使用通配符声明的名称实例化的对象不能对其加入新的信息,只能获取或删除,即get()或者remove();
也就是说使用GenericTest<?> ge4 = ge3;
这时候ge4. set()方法是不能被调用的。
然后ge4.setFoo(null);的作用是将里面的信息值空,也就是起到了删除的功能,
所以你的代码中能够使用ge4.setFoo(null);而不能调用ge4.setFoo("welcome");

要想调用ge4.setFoo("welcome");的话,就不能再这里使用通配符声明 GenericTest<?> ge4 = ge3;
改为使用 GenericTest<String> ge4 = ge3;

评分

参与人数 1技术分 +1 收起 理由
杨兴庭 + 1 赞一个!

查看全部评分

回复 使用道具 举报
本帖最后由 toShareBeauty 于 2013-7-23 20:38 编辑

楼主好问题,这个问题已经超出我对泛型的认识,我一直认为这是可以的,但是编译器确实报错了。经过查资料得到下面结果。主要是因为在使用 泛型通配符的时候,编译器限制了一些东西。为什么这么限制,因为为了强制的让你用了泛型就不能用强制类型转换。



按照上面的说法,楼主的用法只能使用get不能使用set,当然 null 不同,set null 是移除信息。



评分

参与人数 1技术分 +1 收起 理由
杨兴庭 + 1 赞一个!

查看全部评分

回复 使用道具 举报
首先,定义了一个泛型类GenericTest<T>,然后  GenericTest<String> ge3 = new GenericTest<String>();GenericTest<?> ge4 = ge3;
相当于GenericTest<?> ge4 = new GenericTest<String>();对象中的类型是string类型。引用ge4也指向堆内存中的GenericTest<String>();“?”是通配符,表示类型不确定。调用ge4.setFoo("welcome");会失败,我觉得有点像多态中:父类引用不能调用子类对象特有的方法   一样。
改为:GenericTest<String> ge4 = ge3;
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马