Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/342.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么不能将基元类型与多态返回类型一起使用?_Java_Polymorphism_Primitive_Return Type - Fatal编程技术网

Java 为什么不能将基元类型与多态返回类型一起使用?

Java 为什么不能将基元类型与多态返回类型一起使用?,java,polymorphism,primitive,return-type,Java,Polymorphism,Primitive,Return Type,考虑以下两类: public interface Foo<T> { public T moo(); } public class IntFoo implements Foo<Integer> { public int moo() { return 0; } } 必须这样做,因为JVM在解析方法时会区分不同的返回类型,而且由于Foo.moo的擦除返回类型是Object,编译器生成了一个具有与方法相同签名的桥接方法 我想知道

考虑以下两类:

public interface Foo<T>
{
    public T moo();
}

public class IntFoo implements Foo<Integer>
{
    public int moo()
    {
        return 0;
    }
}
必须这样做,因为JVM在解析方法时会区分不同的返回类型,而且由于
Foo.moo
的擦除返回类型是
Object
,编译器生成了一个具有与方法相同签名的桥接方法

我想知道为什么这对原始多态返回类型也不起作用:

public class IntFoo implements Foo<Integer>
{
    public <synthetic> <bridge> Object moo()
    {
        return Integer.valueOf(this.moo());
    }

    public int moo()
    {
        return 0;
    }
}
公共类IntFoo实现Foo
{
公共对象moo()
{
返回Integer.valueOf(this.moo());
}
公共信息办公室
{
返回0;
}
}
似乎没有任何理由不使用此功能:

IntFoo intFoo = new IntFoo();
Foo<Integer> foo = intFoo;
Integer i = foo.moo(); // calls the synthetic method, which boxes the result of the actual implementation
IntFoo IntFoo=new IntFoo();
Foo-Foo=intFoo;
整数i=foo.moo();//调用合成方法,该方法将实际实现的结果装箱
事实上,这个REPL会话的屏幕截图显示,我甚至能够在我的(编译成Java字节码)中实现这一点:


原语的问题是它们在堆栈上需要不同数量的空间。。。与对象引用相反,对象引用占用堆栈上相同的空间。而且你不能有一个可变大小的stackframe,因为否则在运行时堆栈就不知道在方法exit时返回到哪里了。依我的拙见,原因纯粹是语法上的。正如您在问题中所演示的,可以生成返回
int
的方法和在字节码中实现返回
Object
Foo
接口方法的方法

但是,如果您从Java语法的角度(即不是字节码)来看问题

公共类IntFoo实现Foo{
public int moo(){return 0;}
}

应该重写一个方法
Integer moo()
,但它没有重写。正如您自己所说,Java区分返回类型,并且
int moo()
Integer moo()

与这些问题一样,答案是您必须询问语言设计者。我看不出有什么理由不能这样做。然而,在我看来,这个功能将是相当没有意义的。正如您在问题中指出的,只有在对静态类型的变量调用
IntFoo
时才会返回原语;对于类型为
Foo
的变量,无论如何都会返回
整数。因此,通过这样做,您可以实现基本相同的目标

public class IntFoo implements Foo<Integer> {

    @Override
    public Integer moo() { return mooAsInt(); }

    public int mooAsInt() { return 0; }
}
公共类IntFoo实现Foo{
@凌驾
公共整数moo(){return mooAsInt();}
public int mooAsInt(){return 0;}
}

就我个人而言,我认为这更好,因为当拳击比赛进行/不进行时,这更为明显。在您的方案中,
moo()
可以返回
int
Integer
,这取决于变量的静态类型,这将非常令人困惑。

在我的示例中,哪里需要不同的堆栈大小?如果直接调用重写的方法,则从实现中获得一个
int
,否则将调用桥方法并为您处理装箱。很高兴了解syntetic桥方法,我并不认为这个特性毫无意义:一个具体的例子是扩展
Set
BitSet
类。这样,您就可以获得位集的无框高性能,并且在某些东西需要一个通用集时仍然使用集功能。@Clashsoft我完全同意这一点。我自己也提出过类似的观点(参见问题“Sparsarray vs HashMap”),我认为android的
Sparsarray
应该实现
Map
。这样,当需要时,它可以被视为
映射
,但只处理基本键。这很好,但是你已经可以通过重载方法来实现了——不需要新的规则。但是你只能重载参数类型,不能重载返回类型。这使得在您的场景中无法重写Map,这意味着您需要一个额外的包装器来实现Map接口并委托给SparArray实例。@Clashsoft您是对的,我的意思不是在更改返回类型时重载-该方法必须具有不同的名称。您完全可以使用
SparseArray
使用继承而不是像我所做的那样使用组合<代码>公共最终类SparseMap扩展SparseArray实现映射{@Override public T get(Object i){return get((int)(Integer)i);}//etc}
。我遇到的主要问题是,你必须抛弃总是对接口编程的规则。我期待着Java 9(或者它是10?),那时我们可以有一个真正的
Foo
。实际上,
int moo()
覆盖
T moo()
(使用
T=Integer
)。但是如果你能写
Foo
,事情就会变得更加明显。我想我们必须等待Java 10,然后:/
public class IntFoo implements Foo<Integer> {
    public int moo() { return 0; }
}
public class IntFoo implements Foo<Integer> {

    @Override
    public Integer moo() { return mooAsInt(); }

    public int mooAsInt() { return 0; }
}