重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
//是这样吗?
创新互联长期为千余家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为北海企业提供专业的网站设计制作、成都网站制作,北海网站改版等技术服务。拥有十载丰富建站经验和众多成功案例,为您定制开发。
public class FTestDraw {
public static void main(String[] args) {
DrawMethodShape dm = new DrawMethodShape(new Circle());
dm.shape.draw();
}
}
abstract class Shape{
abstract void draw();
}
class Circle extends Shape{
@Override
void draw() {
System.out.println("这是圆形");
}
}
class Rectangle extends Shape{
@Override
void draw(){
System.out.println("这是长方形");
}
}
class Triangle extends Shape{
@Override
void draw(){
System.out.println("这是三角形");
}
}
class DrawMethodT extends Shape{
T shape = null;
public DrawMethod(T tt){
shape = tt;
}
}
您好,我用断点调试解释吧[真的很高兴能与你讨论][啊啦上回不好意思但还是说对一部分滴].
1-----你在go方法中,没有给list限制泛型约束,所以1.1不加check的存储进arraylist了.
2-----"1.1"是被内部机制转换为Double存储进arraylist的:
[在System.out.println(list.get(1));处下断点,点调试.可以看到list里是
[1, 1.1],
elementData[]为
[1, 1.1, null, null, null, null, null, null, null, null].
elementData[0]的值是"1",
elementData[1]的值为Double (标识=37).]
也就是说,go方法add时因为没有约束,所以由内部机制将1.1转换为Double存入了以String为约束的list里.
3-----点"单步跳入",看到代码跳到了arraylist的get里:
public E get(int index) {
RangeCheck(index);
return elementData[index];
}
关键点就在这了,由第2步看到elementData[1]的类型为Double,而在main里为list设置的约束是String,所以E 为String.上面的代码就变为:
public String get(int index) {
RangeCheck(index);
return 1.1; //double
}
继续跳,
看到他照样返回了一个加着String标签的double值.
4-----继续点然后报错了.这个是由于syso输出是输出String.这个后面会说.
如果你加一个方法:
public static void go1(List list)
{
System.out.println(list.get(1));
}
这样没约束的情况下syso,是没有错的.因为get后的对象没有加类型标签,会由内部机制判断他到底是哪个类.
而加了String返回类型标签后就不做判断直接调用syso(String)的方法来输出Double了.所以报告了class cast错误.
如果你继续看,会看到是String类的init出现的错误.
因为前面调试中看到syso(args)的args为String[],而返回的却是Double.类型没匹配上.
正确的那个例子不用说了吧,调试一下会发现他syso时String.valueof(obj)了,"1.1"肯定满足条件.[如果不满足条件,会打印object,这也是能输出syso(list)的原因][SYSO在控制台输出的是字符,如果是double会转为字符输出]
而错的那个因为返回标明了是String,所以程序不加判断就直接write了,输出字符却给个double,就出错了.
上班了...打一中午,555,可能说的有错误,楼主自己调试一下,以自己的方式理解一下吧_
PS:其实俺上回说的有一部分对...我楼上那位5级大哥说的也部分对,但1.1是double传进去的,没转换成int.调试过我就明白了,一开始我也那么想.
1.1 list.get()返回类型为?,所以你只能用Object接收,Object足以确保type-safe,因为java中任何class都是Object的subclass。(当然,如果你非要使用类型强制转换,转换成什么阿猫阿狗的class,也没人拦得住你,对此只能说“编译器尽力了,你行你上啊”,反正ClassCastException什么的最有爱了)
2.2 list.put()除了null以外,任何参数都不接收。这也足以确保list中类型的type-safe,要知道,java的泛型的implementation是基于ERASURE(擦除)的,举个具体的例子,LinkedListE的内部数据结构肯定是基于NodeE,那么一个Node有2个field,E element和NodeE next,而实际上在runtime环境中,LinkedListString中的Node并不是NodeString,仅仅是Node,Node里面的element的类型也不是String,仅仅是Object,也就是说,compile-time的type-information都被抹除了(Quote: For backward-compatibility)。试想这么一个情景,Tom传了一个ListDog给Mike,Mike的interface是List?,Mike往list中放了一个Cat(假设compiler没有阻止Mike),然后Tom取出该List中所有的object并当成Dog使用(compiler会自动加上类型转换的代码——which is how java generics worked),然后Tom就悲剧地得到了一个ClassCastException——这就是为什么除了null其他参数都不接收的原因——阻止Mike随便放东西进去。
2、List
raw-type就是这么个情况,相当于你对compiler说:“我并不在乎这个List里面的element的runtime-type是什么,不管我怎么操作这个list或者list中取出来的object,你都别管,实在看不过去就给我个warning就行了”。这种情况下:
2.1 list.get()返回类型为Object,当然,也是type-safe的(如果你不强制转换的话)
2.2 list.put()的参数类型为Object,也就是说,你爱往里面放什么object就放什么object,还是上面那个例子,就算Tom给Mike的是ListString,但由于Mike的interface是List,所以Mike放个BigInteger甚至什么Cat、Dog,compiler都不会阻止Mike(但是,要知道,Mike是无法得知其他人会怎么使用这个List的,比如说Mike无法得知Tom相信编译器确保了list中的object都是String,但是由于Mike的raw-type interface,Tom就难免吃ClassCastException咯)