Does Java virtual machine allow overloading on return type?

痞子三分冷 提交于 2019-12-02 05:48:41

问题


I have gone through this presentation.

Slide No:26 quote that

Java language does not allow overloading on return type

Java Virtual machine does allow overloading on return type

Are these statements true? If both statements are true, how to make the code compilable so that jvm run the code?

I have one SE question on this topic :

Java - why no return type based method overloading?

Thanks in advance.


回答1:


These statements are perfectly true.

Remember that Java is two things - one,a language and two, a virtual machine. While restricting the language to not allow type based method overloading makes Java a simpler language to use, the JVM can still allow this to be done to make it more powerful.

As a language, Java has a compiler that enforces the rules that make Java a simpler, easier programming language than one that does allow this. To do this, it restricts what you can do, but only in the Java language itself. Running something like Scala or Ruby on the JVM requires different rules and features, and at this level it is important that the JVM allows the flexibility that has made the JVM such a big success that it is found on so many platforms and devices.

In a language where overloading by return type is possible, it would be very error prone and the decision to not support that feature was deliberate to make Java a less error-prone programming language. How would the compiler know which function you intended to call?

The JVM on the other hand is a low-level, highly optimised virtual machine that exists to run bytecode, not Java. It is therefore not wise to restrict the JVM in this fashion as it should be able to run bytecode not generated from Java at all.

Another example would be multiple inheritance, which is not available in Java, yet nothing prevents you to write a language that supports multiple inheritance and have it compile to bytecode. It would make your language more difficult to use and potentially more error prone, but if you require that feature, the JVM will not stop you.




回答2:


In addition to the answer by Ewald, here is a small demo that shows that it actually is possible to have overloading based on return types. It is possible to have a single class that has two methods with the same name and arguments, that only differ in the return type.

(The fact that this is a pure Java program blurs the border between the language and the JVM, and makes answering the question whether "Java" allows this sort of overloading even harder, but I think that Ewald already explained this pretty well - and of course, I'm "cheating" for this demo...:)

The program uses the Apache ByteCode Engineering Library (BCEL) to generate and load such a class at runtime. Then, it creates an instance of this class, and lists and calls all (declared) methods.

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();
    }
}

The output is

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

showing that the method with the same name signature appears twice, only differing in the return type - and, using reflection, both methods can still be called.



来源:https://stackoverflow.com/questions/34613075/does-java-virtual-machine-allow-overloading-on-return-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!