这是否有效的Java? [英] Is this valid Java?

查看:121
本文介绍了这是否有效的Java?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是否是有效的Java?

  import java.util.Arrays; 
import java.util.List;

class TestWillThatCompile {

public static String f(List< String> list){
System.out.println(strings);
返回null;


public static Integer f(List< Integer> list){
System.out.println(numbers);
返回null;


public static void main(String [] args){
f(Arrays.asList(asdf));
f(Arrays.asList(123));
}

}




  • Eclipse 3.5说

  • Eclipse 3.6说

  • Intellij 9说
  • .com / questions / 3105177 / why-is-one-class-valid-while-the-other-is-not>以前的Stackoverflow问题说 no


我对java理论的理解是 no

了解 JLS 对此有何评论。

解决方案

这取决于您希望如何调用这些方法。如果您希望从其他Java源代码调用这些方法,那么它会被视为无效,原因如 Edwin的回答。这是Java语言的限制。然而,并非所有的类都需要从Java源代码生成(考虑所有使用JVM作为其运行时的语言: JRuby,Jython等)。 在字节码级别,JVM可以消除这两种方法的歧义,因为字节码指令指定了它们期望的返回类型。例如,以下是 Jasmin 中可以调用以下任一方法的类:

  .class public CallAmbiguousMethod 
.super java / lang / Object

.method public static main([Ljava / lang / String;)V
.limit栈3
.limit locals 1

;调用返回String的方法
aconst_null
invokestatic TestWillThatCompile / f(Ljava / util / List;)Ljava / lang / String;

;调用返回Integer的方法
aconst_null
invokestatic TestWillThatCompile / f(Ljava / util / List;)Ljava / lang / Integer;

返回

.end方法

I使用以下命令将其编译为类文件:

 
java -jar jasmin.jar CallAmbiguousMethod.j

然后调用它:

 
java CallAmbiguousMethod

注意,输出结果是:

CallAmbiguousMethod
字符串
数字

更新

Simon发布了示例程序,用于调用这些方法:

  import java.util.Arrays; 
import java.util.List;

class RealyCompilesAndRunsFine {

public static String f(List< String> list){
return list.get(0);


public static Integer f(List< Integer> list){
return list.get(0);


public static void main(String [] args){
final String string = f(Arrays.asList(asdf));
final Integer integer = f(Arrays.asList(123));
System.out.println(string);
System.out.println(integer);
}

}

以下是生成的Java字节码:

 
> javap -c RealyCompilesAndRunsFine
从RealyCompilesAndRunsFine.java编译
class RealyCompilesAndRunsFine extends java.lang.Object {
RealyCompilesAndRunsFine();
代码:
0:aload_0
1:invokespecial#1; //方法java / lang / Object。:(:)V
4:return

public static java.lang.String f(java.util.List);
代码:
0:aload_0
1:iconst_0
2:invokeinterface#2,2; // InterfaceMethod java / util / List.get:(I)Ljava / lang / Object;
7:支票#3; // class java / lang / String
10:areturn

public static java.lang.Integer f(java.util.List);
代码:
0:aload_0
1:iconst_0
2:invokeinterface#2,2; // InterfaceMethod java / util / List.get:(I)Ljava / lang / Object;
7:支票#4; // class java / lang / Integer
10:areturn

public static void main(java.lang.String []);
代码:
0:iconst_1
1:anewarray#3; // class java / lang / String
4:dup
5:iconst_0
6:ldc#5; // String asdf
8:aastore
9:invokestatic#6; //方法java / util / Arrays.asList:([Ljava / lang / Object;)Ljava / util / List;
12:invokestatic#7; //方法f:(Ljava / util / List;)Ljava / lang / String;
15:astore_1
16:iconst_1
17:anewarray#4; // class java / lang / Integer
20:dup
21:iconst_0
22:bipush 123
24:invokestatic#8; //方法java / lang / Integer.valueOf:(I)Ljava / lang / Integer;
27:aastore
28:invokestatic#6; //方法java / util / Arrays.asList:([Ljava / lang / Object;)Ljava / util / List;
31:invokestatic#9; //方法f:(Ljava / util / List;)Ljava / lang / Integer;
34:astore_2
35:getstatic#10; // Field java / lang / System.out:Ljava / io / PrintStream;
38:aload_1
39:invokevirtual#11; //方法java / io / PrintStream.println:(Ljava / lang / String;)V
42:getstatic#10; // Field java / lang / System.out:Ljava / io / PrintStream;
45:aload_2
46:invokevirtual#12; //方法java / io / PrintStream.println:(Ljava / lang / Object;)V
49:return

它结果是Sun编译器正在生成消除方法歧义所需的字节码(请参阅上一个方法中的指令12和31)。

更新#2



Java语言规范表明,这实际上可能是有效的Java源代码。在页449(§15.12方法调用表达式),我们看到:


有可能没有方法是最具体的,因为有两个或
更多的方法是最具体的。在这种情况下:


  • 如果所有最大特定方法都有覆盖等价(§8.4.2)签名,则



    • 如果其中一个最具体的方法没有被声明为抽象的,
      就是最具体的方法。
    • 否则,如果所有最具体的方法都被声明为抽象的,
      并且所有最具体方法的签名具有相同的
      擦除(§4.6),那么则最具体的方法在具有最具体的
      返回类型
      的最具体方法的子集
      中任意选择。但是,当且仅当在
      中声明该异常或其擦除被抛出时,最具体的方法才会抛出
      检查异常。每个最具体方法的抛出子句。


  • 否则,我们说方法调用是不明确的,并且会发生编译时
    错误。

除非我误解,否则此行为仅适用于声明为抽象的方法,尽管...

Update#3



感谢ILMTitan的评论:

lockquote

@Adam Paynter:您的粗体文本确实是
无关紧要,因为只有两种方法是
覆盖 - 等值时才是
,Dan显示
并非如此。因此,如果当
确定最具体的方法时,如果JLS
考虑通用类型,
决定因子必须是。 -
ILMTitan



Is this valid Java?

import java.util.Arrays;
import java.util.List;

class TestWillThatCompile {

    public static String f(List<String> list) {
        System.out.println("strings");
        return null;
    }

    public static Integer f(List<Integer> list) {
        System.out.println("numbers");
        return null;
    }

    public static void main(String[] args) {
        f(Arrays.asList("asdf"));
        f(Arrays.asList(123));
    }

}

  • Eclipse 3.5 says yes
  • Eclipse 3.6 says no
  • Intellij 9 says yes
  • Sun javac 1.6.0_20 says yes
  • GCJ 4.4.3 says yes
  • GWT compiler says yes
  • Crowd at my previous Stackoverflow question says no

My java theory understanding says no!

It would be interesting to know what the JLS is saying about it.

解决方案

It depends upon how you wish to call these methods. If you wish to call these methods from other Java source code, then it is considered invalid for reasons illustrated in Edwin's answer. This is a limitation of the Java Language.

However, not all classes need to be generated from Java source code (consider all the languages that use the JVM as their runtime: JRuby, Jython, etc...). At the bytecode level, the JVM can disambiguate the two methods because the bytecode instructions specify the return type they are expecting. For example, here is a class written in Jasmin that can call either of these methods:

.class public CallAmbiguousMethod
.super java/lang/Object

.method public static main([Ljava/lang/String;)V
  .limit stack 3
  .limit locals 1

  ; Call the method that returns String
  aconst_null
  invokestatic   TestWillThatCompile/f(Ljava/util/List;)Ljava/lang/String;

  ; Call the method that returns Integer
  aconst_null
  invokestatic   TestWillThatCompile/f(Ljava/util/List;)Ljava/lang/Integer;

  return

.end method

I compile it to a class file using the following command:

java -jar jasmin.jar CallAmbiguousMethod.j

And call it using:

java CallAmbiguousMethod

Behold, the output is:

> java CallAmbiguousMethod
strings
numbers

Update

Simon posted an example program that calls these methods:

import java.util.Arrays;
import java.util.List;

class RealyCompilesAndRunsFine {

    public static String f(List<String> list) {
        return list.get(0);
    }

    public static Integer f(List<Integer> list) {
        return list.get(0);
    }

    public static void main(String[] args) {
        final String string = f(Arrays.asList("asdf"));
        final Integer integer = f(Arrays.asList(123));
        System.out.println(string);
        System.out.println(integer);
    }

}

Here is the Java bytecode generated:

>javap -c RealyCompilesAndRunsFine
Compiled from "RealyCompilesAndRunsFine.java"
class RealyCompilesAndRunsFine extends java.lang.Object{
RealyCompilesAndRunsFine();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   return

public static java.lang.String f(java.util.List);
  Code:
   0:   aload_0
   1:   iconst_0
   2:   invokeinterface #2,  2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
   7:   checkcast       #3; //class java/lang/String
   10:  areturn

public static java.lang.Integer f(java.util.List);
  Code:
   0:   aload_0
   1:   iconst_0
   2:   invokeinterface #2,  2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
   7:   checkcast       #4; //class java/lang/Integer
   10:  areturn

public static void main(java.lang.String[]);
  Code:
   0:   iconst_1
   1:   anewarray       #3; //class java/lang/String
   4:   dup
   5:   iconst_0
   6:   ldc     #5; //String asdf
   8:   aastore
   9:   invokestatic    #6; //Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
   12:  invokestatic    #7; //Method f:(Ljava/util/List;)Ljava/lang/String;
   15:  astore_1
   16:  iconst_1
   17:  anewarray       #4; //class java/lang/Integer
   20:  dup
   21:  iconst_0
   22:  bipush  123
   24:  invokestatic    #8; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   27:  aastore
   28:  invokestatic    #6; //Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
   31:  invokestatic    #9; //Method f:(Ljava/util/List;)Ljava/lang/Integer;
   34:  astore_2
   35:  getstatic       #10; //Field java/lang/System.out:Ljava/io/PrintStream;
   38:  aload_1
   39:  invokevirtual   #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   42:  getstatic       #10; //Field java/lang/System.out:Ljava/io/PrintStream;
   45:  aload_2
   46:  invokevirtual   #12; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   49:  return

It turns out the Sun compiler is generating the bytecode necessary to disambiguate the methods (see instructions 12 and 31 in the last method).

Update #2

The Java Language Specification suggests that this may, in fact, be valid Java source code. On page 449 (§15.12 Method Invocation Expressions) we see this:

It is possible that no method is the most specific, because there are two or more methods that are maximally specific. In this case:

  • If all the maximally specific methods have override-equivalent (§8.4.2) signatures, then:
    • If exactly one of the maximally specific methods is not declared abstract, it is the most specific method.
    • Otherwise, if all the maximally specific methods are declared abstract, and the signatures of all of the maximally specific methods have the same erasure (§4.6), then the most specific method is chosen arbitrarily among the subset of the maximally specific methods that have the most specific return type. However, the most specific method is considered to throw a checked exception if and only if that exception or its erasure is declared in the throws clauses of each of the maximally specific methods.
  • Otherwise, we say that the method invocation is ambiguous, and a compiletime error occurs.

Unless I am mistaken, this behavior should only apply to methods declared as abstract, though...

Update #3

Thanks to ILMTitan's comment:

@Adam Paynter: Your bolded text does not matter, because it is only a case when two methods are override-equivalent, which Dan showed was not the case. Thus, the determining factor must be if the JLS takes generic types into account when determining most specific method. – ILMTitan

这篇关于这是否有效的Java?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆