9

扩展和装箱 Java 原语。

我知道不可能将包装类从一个扩展到另一个,因为它们不是来自同一个继承树。为什么不能将一个基元扩展为另一种基元类型并自动装箱扩展的基元?

鉴于可以将字节参数传递给需要 int 的方法,为什么不能将以下示例中的字节扩展为 int,然后将其装箱为 Integer?

class ScjpTest{
    static void goInteger(Integer x){
        System.out.println("Going with an Integer");
    }

    static void goInt(int x){
        System.out.println("Going with an int");
    }

    public static void main(String args[]){
        byte b = 5;
        goInt(b);
        goInteger(b);
    }
}

在上面的示例中,goInt(b)编译器接受但goInteger(b)被拒绝。

4

5 回答 5

7

简短的回答

java 语言只支持某种程度的粗心。

更长的答案

我相信添加自动装箱是为了支持开发人员的粗心大意。特别是在这样的情况下:“我需要一个 Integer 作为我要调用的方法的参数,但我有一个 int。不知何故,new Integer(int) 永远不会出现在我的脑海中。相反,我只发送一个 int并且 java 编译器会为我执行 new Integer() 调用。感谢 java 粗心支持组!

设计自动装箱的人愿意支持 1 级粗心(int => Integer 和返回),但不愿意支持将较小的原始类型自动转换为较大的原始类型以及自动创建和从原始类型包装类中提取。我怀疑这个决策矩阵会比当前自动装箱方案的决策矩阵大一些。

于 2011-08-10T16:26:13.503 回答
4

为什么?因为装箱/自动装箱只是一些编译器糖而不是新的类型系统。它的设计很糟糕,并且至少在简化事情时经常引起麻烦。

但这里有一些解决您的编译错误的方法:

goInteger((int) b);

// these are equivalent
goInteger(((Byte) b).intValue());
goInteger(Byte.valueOf(b).intValue());
于 2011-08-10T16:23:47.020 回答
1

如果我们允许太多的魔法转换,它会变得非常混乱。

现有的转换规则已经超出人们的理解。甚至语言规范也弄错了!请参阅这个有趣的 Java 转换示例:是编译器错误,还是语言规范错误,还是我错了?

于 2011-08-10T20:03:43.100 回答
1

在 Java 中,允许使用Boxing + Widening ,但不允许Widening + Boxing .. 要接受 goInteger,首先需要扩展原始数据类型(byte -> int),这可以,然后需要 Boxing(int -> Integer)。请找到 Widening、Boxing 和 Vararg 的 5 条黄金法则:

  1. 原始扩展>拳击>可变参数。
  2. 不允许加宽和拳击(WB)。
  3. 允许装箱和加宽(BW)。
  4. 重载时, Widening + vararg 和 Boxing + vararg 只能以互斥方式使用,即不能一起使用。
  5. 不允许在包装类之间扩大

我希望这能帮到您。关于,Sudipta Deb。

于 2012-05-10T22:25:36.280 回答
0

我觉得这个顺序很吸引人。我制作了以下操场以查看所有可能的组合。这是我的功能:

static void doSomeThing(short i) {
    System.out.println("short");
}

static void doSomeThing(short... i) {
    System.out.println("short...");
}

static void doSomeThing(Short i) {
    System.out.println("SHORT");
}

static void doSomeThing(Short... i) {
    System.out.println("SHORT...");
}

static void doSomeThing(long i) {
    System.out.println("long");
}

static void doSomeThing(long... i) {
    System.out.println("long...");
}

static void doSomeThing(Long i) {
    System.out.println("LONG");
}

static void doSomeThing(Long... i) {
    System.out.println("LONG...");
}

static void doSomeThing(int i) {
    System.out.println("int");
}

static void doSomeThing(int... i) {
    System.out.println("int...");
}

static void doSomeThing(Integer i) {
    System.out.println("INTEGER");
}

static void doSomeThing(Integer... i) {
    System.out.println("INTEGER...");
}

static void doSomeThing(Object i) {
    System.out.println("Object");
}

static void doSomeThing(Object... i) {
    System.out.println("Object...");
}

规则:

 1.Searches for exactly the same type (int -> int)
 2.Widening (int -> long)
 3.Boxing (int-> Integer, it is NEVER possible to implicit box AND wide (int -> Long NOT possible without cast))
 !!Multiple boxing go BEFORE var args!!
 int -> Object will be chosen before int -> int...
 4.Var args (int -> int...)
 5.Widening + var args (int -> long...)
 6.Boxing + var args (int -> Integer...)
 7.Boxing + widening + var args (int -> Object...)

public class Main{

    public static void main(String...args) {
        //primitive int
        int i = 0;
        doSomeThing(i); //int
        //commented out doSomeThing(int i){}
        doSomeThing(i); //long. It is not possible to narrow, so short, short... Short and Short... will NEVER be called when the input is larger than a short.
        //commented out doSomeThing(long i){}
        doSomeThing(i); //INTEGER
        //commented out doSomething(Integer i){}
        doSomeThing(i); //Object. Notice that there can be multiple boxing before moving to var args
                            //Error occured: compiler if confused: can either execute int..., long..., Object... or Integer...
        //Object... and Integer... are commented out, because in the real world int... will be called first
        doSomeThing(i); //int...
        //commented out int...
        doSomeThing(i); //long...
        //commented out long... and uncommented Integer...
        doSomeThing(i); //Integer...
        //commented out Integer... and uncommented Object...
        doSomeThing(i); //Object...

                //Integer
        //Integer
        Integer i = new Integer(0);
        doSomeThing(i); //INTEGER
        //commented out doSomeThing(Integer i)
        doSomeThing(i); //Object
        //commented out doSomeThing(Object i)
        doSomeThing(i); //int
        //commented out doSomeThing(int i)
        doSomeThing(i); //long so NOT int... it goes widening again
        //commented out doSomeThing(long i)
                        //Error occured: compliler refused: not both have int..., long..., Integer... and Object...
        //int... and long... are commented out
        doSomeThing(i); //INTEGER...
        //commented out doSomeThing(Integer... i)
        doSomeThing(i); //Object...
        //commented out doSomeThing(Object... i)
        //uncommented doSomeThing(int... and long...)
        doSomeThing(i); //int...
        //uncommented doSomeThing(int... i)
        doSomeThing(i); //long...
    }
于 2018-02-08T09:27:17.370 回答