标签: jls

Java:重载方法解析和varargs - 令人困惑的例子

正当我认为我理解JLS15.12应用于varargs时,这是这个例子:

package com.example.test.reflect;

public class MethodResolutionTest2 {
    public int compute(Object obj1, Object obj2) {
        return 42;
    }   
    public int compute(String s, Object... objects)
    {
        return 43;
    }

    public static void main(String[] args) {
        MethodResolutionTest2 mrt2 = new MethodResolutionTest2();
        System.out.println(mrt2.compute("hi",  mrt2));  
        System.out.println(mrt2.compute("hi",  new Object[]{mrt2}));    
        System.out.println(mrt2.compute("hi",  new Object[]{mrt2, mrt2, mrt2}));
    }
}
Run Code Online (Sandbox Code Playgroud)

打印出来的

42
43
43
Run Code Online (Sandbox Code Playgroud)

我理解第一行:JLS15.12表示方法解决是分阶段进行的,而第1阶段和第2阶段忽略了varargs方法,以确定是否存在兼容方法,仅当阶段1和阶段2失败时才会发生阶段3(包括变量).(参见JLS和这个问题.)compute(String s, Object... objects)如果compute(Object obj1, Object obj2)适用,总是被忽略.

但我不明白为什么43为其他两行打印.An Object[]也是一个实例Object,为什么它与varargs方法匹配?


编辑:

...还有这个

Object arg2 …
Run Code Online (Sandbox Code Playgroud)

java variadic-functions jls

13
推荐指数
1
解决办法
2168
查看次数

Java"新型变量"

What does "fresh type variable" mean in the JLS Conversions and Promotions chapter?

java jls

12
推荐指数
1
解决办法
1093
查看次数

为什么Java常量除以零会产生编译时错误?

可能重复:
1/0是合法的Java表达式吗?

为什么这段代码会编译?

class Compiles {
    public final static int A = 7/0;
    public final static int B = 10*3;

    public static void main(String[] args) {}
}
Run Code Online (Sandbox Code Playgroud)

如果我查看已编译的类文件,我可以看到B已经被评估为30,而A仍然是7/0.

据我所知,JSL是一个除以零的表达式,它不是常数.

参考:JLS 15.28

我的上述陈述是由于这一行:

编译时常量表达式是表示基本类型值的表达式

因此,除以零不会被评估为原始值.

我真的不明白为什么编译器允许这样做呢?为了清楚起见,上面的代码使用"java.lang.ExceptionInInitializerError"崩溃了运行时

在我看来,编译器威胁任何最终的静态变量作为常量并评估它的编译时间.这意味着编译器已经尝试评估A,但由于它是零除以它只是让它通过.没有编译时错误.但这看起来非常奇怪...编译器知道它是零除以它会崩溃运行时但是它不会标记编译错误!

任何人都可以向我解释原因吗?

java constants compile-time-constant jls constant-expression

12
推荐指数
1
解决办法
3753
查看次数

Enum类型中wrt到构造函数的静态块的执行顺序

这来自Effective Java:

// Implementing a fromString method on an enum type
  private static final Map<String, Operation> stringToEnum
      = new HashMap<String, Operation>();

  static { // Initialize map from constant name to enum constant
    for (Operation op : values())
      stringToEnum.put(op.toString(), op);
  }

  // Returns Operation for string, or null if string is invalid
  public static Operation fromString(String symbol) {
    return stringToEnum.get(symbol);
  }
Run Code Online (Sandbox Code Playgroud)

请注意,Operation常量将从创建常量后运行的静态块放入stringToEnum映射中.试图使每个常量从其自己的构造函数放入映射将导致编译错误.这是一件好事,因为如果它是合法的,它会导致NullPointerException.除编译时常量字段外,不允许枚举构造函数访问枚举的静态字段.这种限制是必要的,因为在构造函数运行时尚未初始化这些静态字段.

我的问题是关于这条线:

"请注意,操作常量将从创建常量后运行的静态块放入stringToEnum映射中".

我认为静态块在构造函数运行之前执行.实际上是在类加载时执行的.

我在这里错过了什么?

java enums jls

12
推荐指数
1
解决办法
4532
查看次数

为什么对隐藏的静态方法强制执行返回类型协方差?

由于in 的String返回类型,此代码将无法编译.staticMethodChild

class Parent {
    static void staticMethod() {    
    }
}

class Child extends Parent {
    static String staticMethod() {
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道§8.4.8.3中的JLS 8,"覆盖和隐藏的要求"说:

如果具有返回类型R1的方法声明d1覆盖或隐藏具有返回类型R2的另一个方法d2的声明,则对于d2,d1必须是return-type-substitutable(第8.4.5节),否则会发生编译时错误.

我的问题是在静态方法的特定情况下进行编译时检查的动机是什么,这个例子说明在编译期间未能进行此验证会产生任何问题是理想的.

java jls

12
推荐指数
1
解决办法
512
查看次数

Java 中的孵化器模块与预览功能

JEP 11:孵化器模块

概括

孵化器模块是将非最终 API 和非最终工具交到开发人员手中的一种方法,而 API/工具则在未来版本中朝着最终确定或删除的方向发展。

目标

使 JDK 发布项目能够分发一组有限的 API 和工具(网站上可能缺少“是”),这些 API 和工具不是最终的和完整的,并且可以从开发人员或用户的反馈中受益。这将减少 Java SE 平台和 JDK 中出现代价高昂的错误的机会。


JEP 12:预览功能

概括

预览功能是 Java 语言、Java 虚拟机或 Java SE API 的一项新功能,它是完全指定、完全实现的,但不是永久的。它在 JDK 功能版本中可用,以激发开发人员根据实际使用情况提供反馈;这可能会导致它在未来的 Java SE 平台中永久存在。

目标

允许 Java 平台开发人员传达新功能是否会在未来 12 个月内以其当前形式“来到 Java”。


我想知道分别拥有这两个在概念上(甚至在语义上)非常相似的方面有什么意义?

是的,JEP 12 有更多的目标,定义和总结略有不同;而且它似乎与 JVM 内部有更密切的联系;然而,这两个 JEP 对我来说似乎很重叠。

有任何想法吗?

java jls jep

12
推荐指数
1
解决办法
2754
查看次数

JLS的哪一部分表示匿名类不能拥有public/protected/private成员类

考虑一下这段代码:

public class TopLevelClass {
    Cloneable c = new Cloneable() {
        private int privateField;
        private void privateMethod() {};
    };
}
Run Code Online (Sandbox Code Playgroud)

有一个匿名类,它有一个private成员字段和一个private成员方法.它已成功编译.

然后考虑这个:

public class TopLevelClass {
    Cloneable c = new Cloneable() {
        private class PrivateInnerClass {}
    };
}
Run Code Online (Sandbox Code Playgroud)

有一个匿名类,它有一个private成员类.然而...

  • javac说: error: modifier private not allowed here
  • 日食说:Illegal modifier for the local class PrivateInnerClass; only abstract or final is permitted 真的是本地课吗?

什么?为什么匿名类不能有public,protectedprivate(以下简称为those)成员类而它们可具有those构件的字段和方法? …

java access-modifiers anonymous-class inner-classes jls

11
推荐指数
2
解决办法
639
查看次数

java volatile访问是否无法重新排序?

注意
通过说可以(或不能)重新排序存储器访问,并且它可以在发出字节代码字节时由编译器重新排序,或者在发出机器代码时由JIT重新排序,或者在执行顺序执行时由CPU重新排序(最终要求相对于任何其他内存访问,阻止这种情况的障碍.


如果经常读取volatile由于Happens-Before关系(HBR)而无法重新排序对变量的访问.

我发现在给定线程的每两个连续(按程序顺序)动作之间存在HBR,但它们可以重新排序.

也是易失性访问HB,只能访问相同的变量/字段.

我认为这是volatile不可重新解决的

写入易失性字段(第8.3.1.4节)发生在每个后续读取[该字段的任何线程]之前.

如果存在其他线程,则变量的重新排序将变为可见,如此简单示例中所示

        volatile int a, b;            

Thread 1                Thread 2

a = 1;                  while (b != 2); 
b = 2;                  print(a);       //a must be 1
Run Code Online (Sandbox Code Playgroud)

因此,不是HBR本身阻止了排序,而是volatile 扩展了与其他线程的这种关系的事实,其他线程的存在是阻止重新排序的元素.
如果编译器可以证明易失性变量的重新排序不会改变程序语义,即使存在HBR,它也可以重新排序.

如果其他线程从不访问volatile变量,则可以重新排序其访问

      volatile int a, b, c;            

Thread 1                Thread 2

a = 1;                  while (b != 2); 
b = 2;                  print(a);       //a must be 1
c = 3;                  //c never accessed by Thread 2 …
Run Code Online (Sandbox Code Playgroud)

java volatile compiler-optimization jls

11
推荐指数
1
解决办法
674
查看次数

JLS是否需要内联最终的String常量?

我在操作一些字节码时遇到了一个问题,其中final Stringjava编译器(Java 8)没有内联某个常量,请参阅下面的示例:

public class MyTest
{
  private static final String ENABLED  = "Y";
  private static final String DISABLED = "N";

  private static boolean isEnabled(String key) {
      return key.equals("A");
  }

  private static String getString(String key, String value) {
      return key + value;
  }

  public static void main(String[] args) throws Exception {
    String flag = getString("F", isEnabled("A") ? ENABLED : DISABLED);
    System.out.println(flag);

    String flag2 = getString("F", isEnabled("A") ? ENABLED : DISABLED);
    System.out.println(flag2);
  }
}
Run Code Online (Sandbox Code Playgroud)

使用javac生成的字节码(1.8.0_101)

public static void main(java.lang.String[]) …
Run Code Online (Sandbox Code Playgroud)

java javac jls language-lawyer java-8

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

即使它是关键字,使用“record”作为变量名是否合法?

这令人惊讶:我能够用该名称声明一个变量,record即使它现在已成为关键字。看看这个:

public class Main {
    
    static class Foo {
        void bar() { System.out.println("Foo.bar"); }
    }
    
    record R (int a) {}
    
    public static void main(String[] args) {
        Foo record = new Foo();
        record.bar();
        
        R r = new R(5);
        System.out.println(r);
    }
}
Run Code Online (Sandbox Code Playgroud)

当使用 Java 17 编译并运行时,会给出:

Foo.bar
R[a=5]
Run Code Online (Sandbox Code Playgroud)

我原以为这会导致错误,就像尝试声明名为 的变量时的情况一样class。据我所知,Java 人员非常小心,不破坏现有代码,因此我认为这可能是一个经过深思熟虑的选择。

(你甚至不能声明一个名为 name 的变量,const因为它const Java 中的关键字。)

java jls java-record java-17

11
推荐指数
2
解决办法
2034
查看次数