论坛首页 Java企业应用论坛

关于类型逆变(contravariant)的困惑

浏览 9553 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2004-05-24  
协变:covariant, 就是子类型方法能够接受的参数,包含于父类型所接受的参数
逆变:contravariant,是指字类型同名方法,接受的参数包含父类型所能接受的参数。

参见:
http://icecloud.51.net/nemo/archives/000098.html
http://icecloud.51.net/nemo/archives/000071.html

看如下代码:
public class AncestorClass {
}

public class ParentClass extends AncestorClass {

    int set(ParentClass p);{
        System.out.println("set Parent");;
        return 1;
    }
}

public class ChildClass extends ParentClass {
    int set(AncestorClass c);{
        System.out.println("set Ancestor");;
        return 2;
    }
    public static void main(String[] agrs);{
        ChildClass s = new ChildClass();;
        System.out.println(s.set(new ChildClass();););;  // 1
        System.out.println(s.set(new ParentClass();););; // 2
        System.out.println(s.set(new AncestorClass();););; //3 
    }
}


执行ChildClass
理论上,1,2应该是出现编译错误。在Eclipse2.1,M8,Jbuilder中测试都是出错。
而在EclipseM9中,居然编译和执行通过了。把class的类型选为1.3,就和上面的版本一样报错。而用JDK1.4编译也能够通过!!

结果分别是:
set Parent
1
set Parent
1
set Ancestor
2


这就很令人困惑了。是1.4修改了类型逆变的规则?
同样是1.4,为什么M8编译不过?
难道EclipseM9之前的版本都自带了词法分析器来进行语法检查,而这次升级了编译器?

实在是郁闷。
   发表时间:2004-05-24  
我先后在同样的文件路径里装了两个不同的jdk,并在eclipse里指定该文件为jre路径:
一个是1.4.2_03-b02
一个是1.4.2_04-b05

结果:
dos下,前一个无法编译,后一个输出同贴主
eclipse2.1.3 都是无法编译
eclipse3.0m9 都可以编译,输出同贴主

可见
1.eclipse编译并不是通过jdk这么简单,具体还请高人指点
2.贴主说"类型逆变规则的修改"确实在jdk里发生了,不过修改后不是更清楚?在调用方法时先按继承体系从下往上寻找有相同类型的args的方法,找不到则upcast,再寻找,...
0 请登录后投票
   发表时间:2004-05-24  
是啊,修改是好事,但是问题是兼容性。
如果同样是1.4.2的不同版本都不一样
那这样的代码适应范围就太小了阿
0 请登录后投票
   发表时间:2004-05-24  
public class Overwrite {
	public static void main(String[] agrs); {
		ChildClass s = new ChildClass();;
		//right
		System.out.println(s.set(new AncestorClass();, new ChildClass();););;
		//wrong
		//System.out.println(s.set(new ChildClass();, new ParentClass();););;
	}
}

class AncestorClass {
}

class ParentClass extends AncestorClass {
	int set(AncestorClass c, ParentClass d); {
		return 1;
	}
}
class ChildClass extends ParentClass {
	int set(ParentClass d, AncestorClass c); {
		return 2;
	}
}

为什么
		//right
		System.out.println(s.set(new AncestorClass();, new ChildClass();););;
		//wrong
		System.out.println(s.set(new ChildClass();, new ParentClass();););; 

一个是right,一个是wrong?

去掉System.out.println(s.set(new ChildClass(), new ParentClass()));
的注释,强行执行

m9报致命错误:
java.lang.Error: Unresolved compilation problem:
The method set(ParentClass, AncestorClass) is ambiguous for the type ChildClass

at japp.sample.syntax.Overwrite.main(Overwrite.java:17)
Exception in thread "main"
0 请登录后投票
   发表时间:2004-05-25  
不明白 @@
0 请登录后投票
   发表时间:2004-05-25  
System.out.println(s.set(new ChildClass();, new ParentClass();););;

这一句,按照规则,上面两个 set 方法:
class ParentClass extends AncestorClass {
   int set(AncestorClass c, ParentClass d); {
      return 1;
   }
}
class ChildClass extends ParentClass {
   int set(ParentClass d, AncestorClass c); {
      return 2;
   }
}

似乎都符合,所以编译器感觉困惑了。
这样的代码还是尽量少写,想办法绕过它。因为写这样代码的必要性不大,而且还影响了程序的可读性,我认为是代码的臭味之一。
0 请登录后投票
   发表时间:2004-05-25  
dlee说的有理!  程序要方便阅读,干嘛写那么复杂有歧义的。 受教了~
0 请登录后投票
   发表时间:2004-05-25  
C++爱好者一般喜欢研究这种机巧的东西
0 请登录后投票
   发表时间:2004-05-26  
这个和Eclipse,Jb没什么关系把,
0 请登录后投票
   发表时间:2004-05-27  
不知道大家是在什么情况下才有的呢??

我试过用 1.4.0_01的JDK和eclipse 2.1.1,没有这个问题呀!!
[补:原来少继承了一层]
..
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics