Java 虚拟机是否允许重载 return 类型?
Does Java virtual machine allow overloading on return type?
我经历过这个presentation。
幻灯片 No:26 引用
Java language does not allow overloading on return type
Java Virtual machine does allow overloading on return type
这些说法是真的吗?如果两个语句都为真,如何使代码可编译以便 jvm 运行 代码?
我有一个关于这个主题的 SE 问题:
Java - why no return type based method overloading?
提前致谢。
这些说法完全正确。
请记住 Java 是两件事 - 一是语言,二是虚拟机。虽然限制语言不允许基于类型的方法重载使 Java 成为一种更易于使用的语言,但 JVM 仍然可以允许这样做以使其更强大。
作为一种语言,Java 有一个编译器,它执行规则,使 Java 成为一种比允许这样做的编程语言更简单、更容易的编程语言。为此,它限制了您可以做的事情,但仅限于 Java 语言本身。 运行 JVM 上的 Scala 或 Ruby 之类的东西需要不同的规则和功能,在这个级别上,重要的是 JVM 允许灵活性,这使 JVM 取得了如此巨大的成功,它在这么多平台和设备。
在一种可以通过 return 类型进行重载的语言中,这很容易出错,不支持该功能的决定是故意使 Java 更少 error-prone编程语言。编译器如何知道您打算调用哪个函数?
另一方面,JVM 是 low-level 高度优化的虚拟机,存在于 运行 字节码,而不是 Java。因此,以这种方式限制 JVM 是不明智的,因为它应该能够 运行 根本不是从 Java 生成的字节码。
另一个例子是多重继承,它在 Java 中不可用,但没有什么能阻止您编写支持多重继承的语言并将其编译为字节码。它会使您的语言更难使用并且可能更容易出错,但如果您需要该功能,JVM 不会阻止您。
除了 之外,这里有一个小演示,显示实际上 是 可以基于 return 类型进行重载。可以有一个 class 具有两个具有相同名称和参数的方法,仅在 return 类型上不同。
(这是一个纯 Java 程序的事实模糊了语言和 JVM 之间的界限,并且回答了 "Java" 是否允许这种重载的问题更难,但我认为 Ewald 已经很好地解释了这一点 - 当然,我是 "cheating" 这个演示...:)
该程序使用 Apache ByteCode Engineering Library (BCEL) 在运行时生成并加载这样的 class。然后,它创建此 class 的实例,并列出和调用所有(声明的)方法。
package Whosebug.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(
"Whosebug.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("Whosebug.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>",
"Whosebug.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",
"Whosebug.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",
"Whosebug.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 Whosebug.returntypes.Generated.print()
return int
public float Whosebug.returntypes.Generated.print()
return float
显示具有相同名称签名的方法出现 两次 ,仅在 return 类型上有所不同 - 而且,使用反射,这两个方法仍然可以被调用。
我经历过这个presentation。
幻灯片 No:26 引用
Java language does not allow overloading on return type
Java Virtual machine does allow overloading on return type
这些说法是真的吗?如果两个语句都为真,如何使代码可编译以便 jvm 运行 代码?
我有一个关于这个主题的 SE 问题:
Java - why no return type based method overloading?
提前致谢。
这些说法完全正确。
请记住 Java 是两件事 - 一是语言,二是虚拟机。虽然限制语言不允许基于类型的方法重载使 Java 成为一种更易于使用的语言,但 JVM 仍然可以允许这样做以使其更强大。
作为一种语言,Java 有一个编译器,它执行规则,使 Java 成为一种比允许这样做的编程语言更简单、更容易的编程语言。为此,它限制了您可以做的事情,但仅限于 Java 语言本身。 运行 JVM 上的 Scala 或 Ruby 之类的东西需要不同的规则和功能,在这个级别上,重要的是 JVM 允许灵活性,这使 JVM 取得了如此巨大的成功,它在这么多平台和设备。
在一种可以通过 return 类型进行重载的语言中,这很容易出错,不支持该功能的决定是故意使 Java 更少 error-prone编程语言。编译器如何知道您打算调用哪个函数?
另一方面,JVM 是 low-level 高度优化的虚拟机,存在于 运行 字节码,而不是 Java。因此,以这种方式限制 JVM 是不明智的,因为它应该能够 运行 根本不是从 Java 生成的字节码。
另一个例子是多重继承,它在 Java 中不可用,但没有什么能阻止您编写支持多重继承的语言并将其编译为字节码。它会使您的语言更难使用并且可能更容易出错,但如果您需要该功能,JVM 不会阻止您。
除了
(这是一个纯 Java 程序的事实模糊了语言和 JVM 之间的界限,并且回答了 "Java" 是否允许这种重载的问题更难,但我认为 Ewald 已经很好地解释了这一点 - 当然,我是 "cheating" 这个演示...:)
该程序使用 Apache ByteCode Engineering Library (BCEL) 在运行时生成并加载这样的 class。然后,它创建此 class 的实例,并列出和调用所有(声明的)方法。
package Whosebug.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(
"Whosebug.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("Whosebug.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>",
"Whosebug.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",
"Whosebug.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",
"Whosebug.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 Whosebug.returntypes.Generated.print()
return int
public float Whosebug.returntypes.Generated.print()
return float
显示具有相同名称签名的方法出现 两次 ,仅在 return 类型上有所不同 - 而且,使用反射,这两个方法仍然可以被调用。