标签: jls

Java - 使用相同的方法和不同的返回类型实现多个接口

请考虑以下代码:

public interface A {
  public A another();
}

public interface B {
  public B another();
}

public interface AB extends A,B {
  public AB another();
}
Run Code Online (Sandbox Code Playgroud)

这会导致编译错误AB:

B型和A型不兼容; 两者都定义了另一个(),但具有不相关的返回类型

我已经看到了这个问题,并按照接受的答案中的不兼容性示例 - 即

public interface C { 
  public void doSomething();
}

public interface D {
  public boolean doSomething();
}

public interface CD extends C,D { 
}
Run Code Online (Sandbox Code Playgroud)

但是,在这种情况下,返回类型实际上是不兼容的 - 返回类型不能同时为void和布尔值.然而,在上面的示例中,another()返回类型AB是a A和a B,因此可以实现两个扩展接口.

此外,看过JLS(8.4.8,8.4.8.3,8.4.8.4)后,我不太明白为什么我的上面的例子非法.任何人都可以向我解释这个吗?

其次,是否有任何解决方案/解决方法,此除重复的合同要求ABAB

java overriding interface jls

5
推荐指数
1
解决办法
4711
查看次数

是否允许Java编译器对静态调用具有流敏感性?

以下是JLS第8.4.8.2节的简要示例.

class Super {
    static String greeting() { return "Goodnight"; }
    String name() { return "Richard"; }
}
class Sub extends Super {
    static String greeting() { return "Hello"; }
    String name() { return "Dick"; }
}
class Test {
    public static void main(String[] args) {
        Super s = new Sub();
        System.out.println(s.greeting() + ", " + s.name());
    }
}
Run Code Online (Sandbox Code Playgroud)

根据该例子的讨论,跑步的输出main()将是"晚安,迪克".这是因为静态方法是根据调用它们的变量/表达式的静态类型调用的.

这是我的问题:任何即使是中等流量敏感的编译器都可以确定s在调用时存储的任何对象的类型必须始终如此Sub,因此如果允许编译器使用该信息,即使调用静态方法也可能有一些动态绑定的感觉.为什么不允许这样做?Java是否有明确的目标,即每个编译器生成的行为完全相同的字节码还是有其他原因?

java jls

5
推荐指数
1
解决办法
122
查看次数

JLS完全重新定义方法是否覆盖和泛型?

所以,我正在尝试编写一个方法来回答我之前的一个问题:如何判断一个任意的java.lang.Method是否会覆盖另一个?为此,我正在阅读JLS,并且在一个案例中似乎缺少一些部分.

想象一下,您有以下课程:

public class A<T> {
    public void foo(T param){};
}

public class B extends A<String> {
    public void foo(String param){};
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,很明显是B.foo覆盖A.foo,但我不明白这种情况如何符合规范.

关于方法覆盖,JLS§8.4.8.1规定:

在类C中声明的实例方法m1将覆盖在类A中声明的另一个实例方法m2,如果以下所有条件都为真:

  1. C是A的子类.

  2. m1的签名是m2签名的子签名(§8.4.2).

  3. 或者:

    • m2在与C相同的包中是公共的,受保护的或声明的,具有默认访问权限
    • m1覆盖方法m3(m3与m1不同,m3与m2不同),使得m3覆盖m2.

显然,在我们的案例中,第1点和第3点是满意的.让我们在JLS中看一下子签名意味着什么.该JLS§8.4.2说:

如果两个方法具有相同的名称和参数类型,则它们具有相同的签名.

如果满足以下所有条件,则两个方法或构造函数声明M和N具有相同的参数类型:

  1. 它们具有相同数量的形式参数(可能为零)

  2. 它们具有相同数量的类型参数(可能为零)

  3. 设A1,...,An为M的类型参数,让B1,...,Bn为N的类型参数.将N的类型中每次出现的Bi重命名为Ai后,相应类型变量的界限为同样,M和N的形式参数类型是相同的.

在我们的例子中,第1点显然是正确的(都有1个参数).

第2点有点混乱(这就是我不确定规范究竟意味着什么):两种方法都没有声明它们自己的类型参数,而是A.foo使用T哪种类型变量来对类进行参数化.

所以我的第一个问题是:在这个上下文中,是否在类计数中声明类型变量?

好的,现在让我们假设T不计算,因此第2点是假的(我不知道在这种情况下我怎么能应用第3点).我们的两种方法没有相同的签名,但这并不妨碍B.foo成为其子签名A.foo.

JLS§8.4.2中稍微进一步说:

方法m1的签名是方法m2的签名的子签名,如果:

  1. m2与m1具有相同的签名,或

  2. m1的签名与m2签名的擦除(§4.6)相同.

我们已经确定第1点是错误的.

根据JLS§4.6的方法的擦除签名是a signature consisting of the same name …

java generics jls

5
推荐指数
1
解决办法
190
查看次数

getDeclaredConstructors()列出了2个构造函数,但只有一个

鉴于这一小部分代码:

import java.util.Arrays;

public class Sample {
    private final int test;

    private Sample(int test) {
        this.test = test;
    }

    public static void main(String[] args) {
        System.out.println(Arrays.toString(Hello.class.getDeclaredConstructors()));
    }

    public static class Hello {
        private final int i;

        private Hello(int i) {
            this.i = i;
        }

        public int getI() {
            return i;
        }

        public static class Builder {
            private int i;

            private Builder() {

            }

            public static Builder builder() {
                return new Builder();
            }

            public void add(int i) {
                this.i = i; …
Run Code Online (Sandbox Code Playgroud)

java reflection constructor jls

5
推荐指数
1
解决办法
139
查看次数

为什么内部类不能使用静态初始化器?

Quoth JLS#8.1.3:

内部类可能不会声明静态初始化器(第8.7节)......

这表现如下:

class A {
    class B {
        static { // Compile-time Error: Cannot define static initializer in inner type A.B
            System.out.println("Class is initializing...");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

既然Java的内部(非静态)类是由类加载器加载的,就像其他类一样,为什么我们不能为它们安装静态初始化器?

这种限制背后的原因是什么?

java inner-classes static-initializer jls

5
推荐指数
1
解决办法
2174
查看次数

Java语法定义完整性

虽然JLS规范中似乎非常精确地描述了Java语法,但是有一些具体案例我无法应用于给定的定义.

例如,采用ClassInstanceCreationExpressionJLS8第15.9章中的规则,非限定new表达式应采用以下形式:

new [TypeArguments] {Annotation} Identifier [TypeArgumentsOrDiamond] ( [ArgumentList] ) [ClassBody] 
Run Code Online (Sandbox Code Playgroud)

Identifier是一个标准的Java标识符(基本上是Java字母/数字,没有点).

该定义如何应用于静态嵌套类instanciation等有效表达式:

new C1.C2();
Run Code Online (Sandbox Code Playgroud)

或包合格的类instanciation:

new java.lang.String("foo");
Run Code Online (Sandbox Code Playgroud)

鉴于点不能成为一部分Identifier

请注意,对于非限定new表达式,此定义从JLS7更改为JLS8,其中JLS7 表示:

new [TypeArguments] TypeDeclSpecifier [TypeArgumentsOrDiamond]( [ArgumentList] ) [ClassBody]
Run Code Online (Sandbox Code Playgroud)

TypeDeclSpecifier 被定义为:

TypeDeclSpecifier:
    TypeName
    ClassOrInterfaceType . Identifier 
Run Code Online (Sandbox Code Playgroud)

允许new静态嵌套类和包限定类的非限定表达式.

java grammar jls

5
推荐指数
1
解决办法
427
查看次数

为什么这个程序用Java 7而不是Java 8编译?

考虑这个程序:

public class xx<T> {

    <T> Iterable<T> createIterable(Class<T> cls) {
        return null;
    }

    Iterable<? extends Number> createNumberIterable(boolean floatingPoint) {
        return this.createIterable(floatingPoint ? Integer.class : Float.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

在Java 7下,它编译:

$ java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
$ javac xx.java
$
Run Code Online (Sandbox Code Playgroud)

在Java 8下它没有:

$ java -version
java version "1.8.0_40"
Java(TM) SE Runtime Environment (build 1.8.0_40-b25)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
$ javac xx.java …
Run Code Online (Sandbox Code Playgroud)

java javac jls

5
推荐指数
1
解决办法
189
查看次数

Java JLS是否指定了原始包装类型的提升?

我对这个程序的输出感到有些神秘:

public class xx {
    public static void main(String[] args) throws Exception {
        Number x = false ? new Long(123) : new Integer(456);
        System.out.println(x + " isa " + x.getClass().getName());
    }
}
Run Code Online (Sandbox Code Playgroud)

这是它输出的内容:

456 isa java.lang.Long
Run Code Online (Sandbox Code Playgroud)

它出现在编译器"促进"类型的对象IntegerLong,就像它通常会促进原始值.我从来没有听说过对象推广,这种行为似乎非常令人惊讶.

我的问题:根据JLS,这是非常正确的行为吗?如果是这样,我希望尽可能看到参考.

或者这是一种autoboxing-gone-wild编译器错误?

我正在使用:

java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
Run Code Online (Sandbox Code Playgroud)

java jls

5
推荐指数
1
解决办法
99
查看次数

Java必须编译为字节码吗?

Java语言规范是否要求将Java编译为Java字节代码?

据我所知,事实并非如此:

JLS 1

编译时通常包括将程序转换为与机器无关的字节代码[表示.

[...]

Java编程语言通常被编译为Java虚拟机规范Java SE 9 Edition中定义的字节码指令集和二进制格式.

(强调我的)

我在规范中找不到任何其他提到的"字节码"或"字节码".

这是否意味着所有字节码操作在技术上都不被JLS定义的"Java语言"所涵盖,并且在技术上依赖于实现细节?

java bytecode language-implementation jls

5
推荐指数
1
解决办法
347
查看次数

为什么从Java模块中打开一个不存在的包?

JLS 11 “ 7.7.2。导出和打开的包”说:

允许opens指定一个与当前模块关联的编译单元未声明的包。

这将是什么情况?为什么需要这个?

java jls java-module

5
推荐指数
1
解决办法
172
查看次数