我已经完成了这个演讲.
幻灯片编号: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将不会阻止您.
除了由埃瓦尔德答案,这里是一个小的演示显示,它实际上是可能的过载基于返回类型有.可以有一个具有两个具有相同名称和参数的方法的类,它们只在返回类型上有所不同.
(事实上,这是一个纯粹的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], "", "stackoverflow.returntypes.Generated", instructionList, constantPool_cp); instructionList.append(InstructionFactory.createLoad(Type.OBJECT, 0)); instructionList.append(instructionFactory.createInvoke( "java.lang.Object", " ", 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
显示具有相同名称签名的方法出现两次,只在返回类型上有所不同 - 并且,使用反射,仍然可以调用这两种方法.