关于泛型与多态的问题

c#中推荐使用list而不用arraylist是为了避免拆箱装箱,但是我有个疑问,比如List<animal>这种父类的集合,存进了很多cat,dog这种类型的子类对象,这样效率是不是也不高呢,还是分别放在List<cat>和List<dog>中????

阅读 2.9k
评论
    4 个回答

    楼上两位都不懂C#。

    1. C#在存class对象的时候也是指针,如果是ArrayList这种非泛型,或者List<Object>这种指定Object的泛型,存进去的struct/primitive(合称value type)数据,也是boxing之后得到一个地址然后存这个地址到集合里面;

    2. Java没区别是因为类型擦除,C#里面List<class type>是没有这个boxing/unboxing的事情的。

    3. cat、dog如果能派生自animal,就说明那不是struct。class对象在内存layout里面是包含了一个sync block和一个RTTI(就是具体类型的描述符),见此处。根据这个RTTI就可以判断具体类型,这个跟boxing/unboxing没半毛钱关系。class对象是不需要boxing和unboxing的。

    4. value type之所以必须boxing/unboxing,是因为他的语义是:a.作为一个整体直接layout到当前位置,比如一个struct局部变量就是直接躺在栈上的,如果是class里面的一个field则直接躺到这个class对象所占的内存,而不是另外从别的地方分一片内存然后用个指针指向它(这种是class);以及b. 因此每次赋值都必须拷贝,而不是用个指针一指了事。正因为他是直接躺的,对于ArrayList这种无泛型的系统,如果允许各种不同大小的struct躺在ArrayList里面,那么元素大小就不等长,arrayList[i]就不能通过offset + i * elemSize计算获得,只能挨个元素遍历。这就变成了查找第N个元素的时间复杂度为O(N)的LinkedList,而不是O(1)的ArrayList了,显然是不符合你的预期的,并且实现代码会变得很艰难也很奇怪。

    5. 这种东西其实你不需要问,网上很多现成的答案,当然你得翻墙。自己google:dotnet memory layout,甚至最好自己看ECMA Spec,然后用Windbg然后!loadby sos clr自己看。

    6. 已经帮你贴了这么多链接了,继续伸手党就得剁手了。

      • 4.2k

      你指的是C++还是C#,这2个是不一样的,C++里面的list不会直接存对象的,都是存对象指针,因为只有对象指针和引用才有多态的

        • 412

        Java里没有区别,编译器编译时类型统一擦除为List,也就是元素是以Object类型对待的,在get时再自动转为指定的类型。

          子类转父类没有额外开销的

            撰写回答

            登录后参与交流、获取后续更新提醒