扩展和装箱Java原语

时间:2011-08-10 16:15:00

标签: java wrapper primitive-types boxing autoboxing

扩展和装箱Java原语。

我知道不可能将包装类从一个扩展到另一个,因为它们不是来自同一个继承树。为什么不能将原语扩展到另一个原始类型并自动放大加宽的原语?

鉴于可以将一个byte参数传递给一个需要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)

5 个答案:

答案 0 :(得分:6)

简短回答

java语言只支持某种程度的疏忽。

更长的答案

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

设计自动装箱的人愿意支持1级粗心(int =>整数和后退),但是不愿意支持将较小的原始类型自动转换为较大的原始类型,同时结合自动创建和从原始语言中提取类型包装类。我怀疑这个descision矩阵会比当前自动装箱方案的决策矩阵稍大。

答案 1 :(得分:4)

为什么呢?因为装箱/自动装箱只是一些编译器糖而不是新型系统。 它的设计很糟糕,并且至少会像简化事情一样频繁地引起麻烦。

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

goInteger((int) b);

// these are equivalent
goInteger(((Byte) b).intValue());
goInteger(Byte.valueOf(b).intValue());

答案 2 :(得分:1)

如果我们允许过多的魔术转换,那就会非常混乱。

现有的转换规则已经超出了人们的理解范围。甚至语言规范都错了!看到这个有趣的例子Java casting: is the compiler wrong, or is the language spec wrong, or am I wrong?

答案 3 :(得分:1)

在Java中,允许拳击+加宽,但不允许加宽+拳击 .. 要使goInteger被接受,首先需要扩展原始数据类型(byte - > int),这样就可以了,然后需要Boxing(int - > Integer)。 请找到5个金色的加宽,拳击和Vararg格式:

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

我希望这会对你有所帮助。 带着敬意, Sudipta Deb。

答案 4 :(得分: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...
    }