正当我认为我理解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) What does "fresh type variable" mean in the JLS Conversions and Promotions chapter?
可能重复:
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
这来自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映射中".
我认为静态块在构造函数运行之前执行.实际上是在类加载时执行的.
我在这里错过了什么?
由于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节),否则会发生编译时错误.
我的问题是在静态方法的特定情况下进行编译时检查的动机是什么,这个例子说明在编译期间未能进行此验证会产生任何问题是理想的.
概括
孵化器模块是将非最终 API 和非最终工具交到开发人员手中的一种方法,而 API/工具则在未来版本中朝着最终确定或删除的方向发展。
目标
使 JDK 发布项目能够分发一组有限的 API 和工具(网站上可能缺少“是”),这些 API 和工具不是最终的和完整的,并且可以从开发人员或用户的反馈中受益。这将减少 Java SE 平台和 JDK 中出现代价高昂的错误的机会。
概括
预览功能是 Java 语言、Java 虚拟机或 Java SE API 的一项新功能,它是完全指定、完全实现的,但不是永久的。它在 JDK 功能版本中可用,以激发开发人员根据实际使用情况提供反馈;这可能会导致它在未来的 Java SE 平台中永久存在。
目标
允许 Java 平台开发人员传达新功能是否会在未来 12 个月内以其当前形式“来到 Java”。
我想知道分别拥有这两个在概念上(甚至在语义上)非常相似的方面有什么意义?
是的,JEP 12 有更多的目标,定义和总结略有不同;而且它似乎与 JVM 内部有更密切的联系;然而,这两个 JEP 对我来说似乎很重叠。
有任何想法吗?
考虑一下这段代码:
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成员类.然而...
error: modifier private not allowed hereIllegal modifier for the local class PrivateInnerClass; only abstract or final is permitted 真的是本地课吗?什么?为什么匿名类不能有public,protected或private(以下简称为those)成员类而它们可具有those构件的字段和方法? …
注意
通过说可以(或不能)重新排序存储器访问,并且它可以在发出字节代码字节时由编译器重新排序,或者在发出机器代码时由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) 我在操作一些字节码时遇到了一个问题,其中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) 这令人惊讶:我能够用该名称声明一个变量,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 中的关键字。)