楼上说的对
你的问题不在于 “哪些实现comparable接口的类可以用compareTo”
这个问题是必然的,接口的意义就在意协定了其实现类的某些必要特征(如此处的compareTo方法)。
你的问题应该是为什么int类型不能用compareTo方法~
public static void main(String[] args) {
int a=2;
int b=2;
Integer c=3;
Integer d;
//编译无法通过,a不是对象,当然也没有所谓的compareTo方法
//这里显然没有出现什么“自动装箱”
a.compareTo(b);
//编译仍无法通过,所谓的强制类型转换?或者是“显示装箱”?,
//不管怎样,a仍旧是int基础数据类型,并没有变成Integer类
//甚至称不上类
(Integer)a.compareTo(b);
//successed!编译通过!那个该死的自动封装终于起作用了!
//让我们来看看他做了什么。
//我想所有人都清楚,a引用的常量所在的地址赋值给了Integer引用类型,
//然后,jvm发现类型不一样,他查了查内部规则,发现int型都特殊对待~
//于是,他启动了“自动装箱”程序。
//很显然,整个过程跟a没有太大的关系,他是int或其他等等(引用的内存内存储的对象的类型来自己内存中的记录,而非引用变量的类型,
//其类型只在a引用该内存时,用于判断是否允许引用而已。)~~
b=a;
//成功!
c.compareTo(a);
}
经过这个例子,我想你应该看到了点什么,让我来告诉你!
这是一个认识错误!
很多人认为java的语法规则是作用于 引用变量!
这是一个非常大的错误!
int a 说的并不是a是int型,而是说a只能引用存放int类型的内存地址!!
那么问题迎刃而解了:
所谓的“自动装箱”是隐式的将基础数据类型自动包装成对象(复合数据类型)
他绝对不是对a而言的,而是作用于a所引用的对象!
让我们回过头来解释一下例子中的代码:
a.compareTo(b);
在编译阶段,编译器会判断语法是否符合规则(从反射调用方法中我们可以看到:它的判断并是不依据内存中的类型特征,
而是引用对象的特征(包括引用对象所在的类是否有该方法,函数的参数是否符合他的规则)),
在这里编译器判断a所在的类是否拥有compareTo方法!(这一句话充分说明了为什么父类引用指向子类对象,该引用只能使用父类所有的方法,但是用该引用反射所在的类时却显示的仍是子类!
编译器在判断引用是否可以调用该方法时,是以引用所属的类型为参照(not引用的对象的类型!!)!)(请注意jvm此时关注的是引用变量本身a,那么自然不会引发“自动装箱”。)
(Integer)a.compareTo(b);
事实上根据我的试验,这样的写法解释器并不会将(Integer)解释成强制类型转换,而是认为括号里面有一个Integer变量会报Integer cannot be resolved to a variable
只有在有赋值的情况下会解释成强制类型转换如Integer e = (Integer)a;而Integer e =(Integer)a.compareTo(b);显然强转的是compareTo的返回值。。
c.compareTo(c);
唔,按照咱们上面的推断由于compareTo方法的参数类型是Object类型,而咱们传入的却是连class都算不上的int,这是为什么呢?
很简单,编译器作弊了!他将Object参数或者基础数据类型相对应的包装类为参数的规则,都放行了基础数据类型的引用变量通过!
这是为什么呢?!这种作弊编译器难道不知道运行的时候会出问题吗!!
很遗憾,不会出问题!原因来自于“自动装箱”!当运行时jvm遇到这种情况就会创建一个相对的包装类的对象,同时将基础数据的值放到相应的内存中。
以上从运行时规避了可能出现的风险!而对原有的编译规则是否有影响呢?答案也是否定的。他只是特例,并没有和其他规则交叉。
b=a;
无可厚非!编译器在规则上对这种跨种族的“无耻”行为选择了无视,而运行时jvm则对a引用的对象启动了“自动那个装箱”。
【免责声明】本人所有有关java内部机制的观点,均来自自我推断。。毫无典据可言。。观看有风险。。欢迎拍砖。
|