Java虚拟机是否允许在返回类型上重载



我已经完成了这个演示。

幻灯片编号:26引用

Java language does not allow overloading on return type
Java Virtual machine does allow overloading on return type

这些说法是真的吗?如果这两条语句都是真的,如何使代码可编译,以便jvm运行代码

关于这个话题,我有一个SE问题:

Java-为什么没有基于返回类型的方法重载?

提前谢谢。

这些语句完全正确。

请记住,Java是两样东西——一是语言,二是虚拟机。虽然限制语言不允许基于类型的方法重载使Java成为一种更简单的语言,但JVM仍然可以允许这样做,使其更强大。

作为一种语言,Java有一个编译器,它强制执行规则,使Java成为一种比允许这样做的语言更简单、更容易的编程语言。要做到这一点,它限制了您可以做的事情,但只能在Java语言本身中进行。在JVM上运行Scala或Ruby之类的东西需要不同的规则和功能,在这个级别上,JVM允许灵活性是很重要的,这使得JVM在许多平台和设备上都取得了巨大成功。

在一种可能按返回类型重载的语言中,它非常容易出错,而不支持该功能的决定是为了使Java成为一种不太容易出错的编程语言。编译器如何知道您要调用哪个函数?

另一方面,JVM是一个低级别、高度优化的虚拟机,它的存在是为了运行字节码,而不是Java。因此,以这种方式限制JVM是不明智的,因为它应该能够运行根本不是从Java生成的字节码。

另一个例子是多重继承,这在Java中是不可用的,但没有什么可以阻止您编写一种支持多重继承的语言,并将其编译为字节码。这会使您的语言更难使用,并且可能更容易出错,但如果您需要该功能,JVM不会阻止您。

除了Ewald的答案外,这里还有一个小演示,它表明实际上有可能基于返回类型进行重载。一个类可能有两个方法,它们的名称和参数相同,只是返回类型不同。

(事实上,这是一个纯Java程序,模糊了语言和JVM之间的边界,并使回答"Java"是否允许这种重载的问题变得更加困难,但我认为Ewald已经很好地解释了这一点-当然,我在为这个演示"作弊"…:)

该程序使用Apache ByteCode工程库(BCEL)在运行时生成并加载这样的类。然后,它创建这个类的一个实例,列出并调用所有(声明的)方法。

package stackoverflow.returntypes;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import org.apache.bcel.Constants;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.PUSH;
import org.apache.bcel.generic.Type;
public class DifferentReturnTypesDemo
{
    public static void main(String[] args) throws Exception
    {
        ClassGenerator classGenerator = new ClassGenerator();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        classGenerator.create(baos);
        ByteArrayClassLoader byteArrayClassLoader = new ByteArrayClassLoader(
            baos.toByteArray());
        Class<?> c = byteArrayClassLoader.loadClass(
            "stackoverflow.returntypes.Generated");
        byteArrayClassLoader.close();
        Object instance = c.newInstance();
        for (Method method : c.getDeclaredMethods())
        {
            System.out.println(method);
            method.invoke(instance, (Object[]) null);
        }
    }
}
class ByteArrayClassLoader extends URLClassLoader
{
    private final byte data[];
    ByteArrayClassLoader(byte data[])
    {
        super(new URL[0]);
        this.data = data;
    }
    @Override
    protected Class<?> findClass(final String name)
        throws ClassNotFoundException
    {
        return defineClass(name, data, 0, data.length);
    }
}
class ClassGenerator
{
    private InstructionFactory instructionFactory;
    private ConstantPoolGen constantPool_cp;
    private ClassGen classGen;
    public ClassGenerator()
    {
        classGen = new ClassGen("stackoverflow.returntypes.Generated",
            "java.lang.Object", "Generator.java", Constants.ACC_PUBLIC |
                Constants.ACC_SUPER, new String[] {});
        constantPool_cp = classGen.getConstantPool();
        instructionFactory = new InstructionFactory(classGen, constantPool_cp);
    }
    public void create(OutputStream out) throws IOException
    {
        createCreateConstructor();
        createMethodReturningInt();
        createMethodReturningFloat();
        classGen.getJavaClass().dump(out);
    }
    private void createCreateConstructor()
    {
        InstructionList instructionList = new InstructionList();
        MethodGen method = new MethodGen(Constants.ACC_PUBLIC, Type.VOID,
            Type.NO_ARGS, new String[0], "<init>",
            "stackoverflow.returntypes.Generated", instructionList,
            constantPool_cp);
        instructionList.append(InstructionFactory.createLoad(Type.OBJECT, 0));
        instructionList.append(instructionFactory.createInvoke(
            "java.lang.Object", "<init>", Type.VOID, Type.NO_ARGS,
            Constants.INVOKESPECIAL));
        instructionList.append(InstructionFactory.createReturn(Type.VOID));
        method.setMaxStack();
        method.setMaxLocals();
        classGen.addMethod(method.getMethod());
        instructionList.dispose();
    }
    private void createMethodReturningInt()
    {
        // Create a public, no-arguments method named "print" that
        // returns an int value
        InstructionList instructionList = new InstructionList();
        MethodGen method = new MethodGen(Constants.ACC_PUBLIC, Type.INT,
            Type.NO_ARGS, new String[0], "print",
            "stackoverflow.returntypes.Generated", instructionList,
            constantPool_cp);
        // Generate the "System.out.println" instructions
        instructionList.append(instructionFactory.createFieldAccess(
            "java.lang.System", "out", new ObjectType("java.io.PrintStream"),
            Constants.GETSTATIC));
        instructionList.append(new PUSH(constantPool_cp, "return int"));
        instructionList.append(instructionFactory.createInvoke(
            "java.io.PrintStream", "println", Type.VOID,
            new Type[] { Type.STRING }, Constants.INVOKEVIRTUAL));
        // Generate the return instruction
        instructionList.append(new PUSH(constantPool_cp, 123));
        instructionList.append(InstructionFactory.createReturn(Type.INT));
        method.setMaxStack();
        method.setMaxLocals();
        classGen.addMethod(method.getMethod());
        instructionList.dispose();
    }
    private void createMethodReturningFloat()
    {
        // Create a public, no-arguments method named "print" that
        // returns a float value
        InstructionList instructionList = new InstructionList();
        MethodGen method = new MethodGen(Constants.ACC_PUBLIC, Type.FLOAT,
            Type.NO_ARGS, new String[0], "print",
            "stackoverflow.returntypes.Generated", instructionList,
            constantPool_cp);
        // Generate the "System.out.println" instructions
        instructionList.append(instructionFactory.createFieldAccess(
            "java.lang.System", "out", new ObjectType("java.io.PrintStream"),
            Constants.GETSTATIC));
        instructionList.append(new PUSH(constantPool_cp, "return float"));
        instructionList.append(instructionFactory.createInvoke(
            "java.io.PrintStream", "println", Type.VOID,
            new Type[] { Type.STRING }, Constants.INVOKEVIRTUAL));
        // Generate the return instruction
        instructionList.append(new PUSH(constantPool_cp, 456.789f));
        instructionList.append(InstructionFactory.createReturn(Type.FLOAT));
        method.setMaxStack();
        method.setMaxLocals();
        classGen.addMethod(method.getMethod());
        instructionList.dispose();
    }
}

输出为

public int stackoverflow.returntypes.Generated.print()
return int
public float stackoverflow.returntypes.Generated.print()
return float

显示具有相同名称签名的方法出现两次,只是返回类型不同-并且,使用反射,仍然可以调用这两个方法。

最新更新