扩展和装箱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)
。
答案 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格式:
- 原始加宽>拳击>可变参数。
- 不允许加宽和装箱(WB)。
- 允许拳击和加宽(BW)。
- 在超载时,Widening + vararg和Boxing + vararg只能以互斥的方式使用,即不能一起使用。
- 不允许在包装类之间扩展
醇>
我希望这会对你有所帮助。 带着敬意, 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...
}