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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© jiahuiting 中级黑马   /  2013-9-26 20:45  /  1384 人查看  /  2 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 jiahuiting 于 2013-9-26 21:24 编辑

有个疑惑,为什么int age不能用compareTo 比较,而当把它用Integer封装后就可以用了呢哪些实现了compareable接口可以默认的使用这个方法呢,

2 个回复

正序浏览
楼上说的对
你的问题不在于 “哪些实现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内部机制的观点,均来自自我推断。。毫无典据可言。。观看有风险。。欢迎拍砖。

评分

参与人数 1技术分 +2 收起 理由
滔哥 + 2

查看全部评分

回复 使用道具 举报
compareTo比较的是对象,int类型时基本数据类型,Integer封装后数据就成了对象,所以就可以进行比较了
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马