JLS - Java语言规范 - https://docs.oracle.com/javase/specs/jls/se9/html/index.html
JSR - Java规范请求 - https://jcp.org/aboutJava/communityprocess/final/jsr376/index.html(模块系统)正式文档,描述了用于添加到Java平台的建议规范和技术.
JEP - JDK增强提案- http://openjdk.java.net/jeps/0,http://openjdk.java.net/jeps/261(模块系统)
这三者有什么区别?
关于类加载的文章指出getClass()不应该在构造函数中调用该方法,因为:
对象初始化仅在构造函数代码的出口处完成.
他们给出的例子是:
public class MyClassLoader extends ClassLoader{
public MyClassLoader(){
super(getClass().getClassLoader()); // should not call getClass() because object
// initialization will be complete only at
// the exit of the constructor code.
}
}
Run Code Online (Sandbox Code Playgroud)
但是据我所知,本机final方法getClass()将始终返回该java.lang.Class对象实例的对象,无论它在何处被调用(在构造函数内或不在构造函数内).
将调用getClass()构造函数中曾经给我们带来的问题?
如果是这样,getClass()在构造函数中调用会给我们带来错误的一些例子是什么?
我注意到JLS谈到5.1.10捕获转换,但我不明白它们是什么.
任何人都可以向我解释/举例吗?
我有以下课程:
import java.util.HashSet;
import java.util.List;
public class OverloadTest<T> extends HashSet<List<T>> {
private static final long serialVersionUID = 1L;
public OverloadTest(OverloadTest<? extends T> other) {}
public OverloadTest(HashSet<? extends T> source) {}
private OverloadTest<Object> source;
public void notAmbigious() {
OverloadTest<Object> o1 = new OverloadTest<Object>(source);
}
public void ambigious() {
OverloadTest<Object> o2 = new OverloadTest<>(source);
}
}
Run Code Online (Sandbox Code Playgroud)
这在JDK 7的javac以及eclipse(兼容性设置为1.7或1.8)下编译得很好.但是,尝试在JDK 8的javac下编译,我收到以下错误:
[ERROR] src/main/java/OverloadTest.java:[18,35] reference to OverloadTest is ambiguous
[ERROR] both constructor <T>OverloadTest(OverloadTest<? extends T>) in OverloadTest and constructor <T>OverloadTest(java.util.HashSet<? extends T>) in OverloadTest match …Run Code Online (Sandbox Code Playgroud) 我目前正在尝试了解有关最终字段的 JLS 部分。
为了更好地理解 JLS 中的文本,我还在阅读Jeremy Manson(JMM 的创建者之一)撰写的The Java Memory Model。
该论文包含让我感兴趣的示例:如果o具有 final 字段的对象对另一个线程可见t两次:
o的构造函数完成之前首先“不正确地”o的构造函数完成后的下一个“正确”然后即使仅通过“正确”发布的路径访问它,也t可以看到半构造的o。
这是论文中的部分:
图 7.3:简单最终语义示例
f1 是最后一个字段;它的默认值为 0
主题 1 主题 2 主题 3 Run Code Online (Sandbox Code Playgroud)o.f1 = 42; p = o; freeze o.f1; q = o; Run Code Online (Sandbox Code Playgroud)r1 = p; i = r1.f1; r2 = q; if (r2 == r1) k = r2.f1; Run Code Online (Sandbox Code Playgroud)r3 = q; j = r3.f1;我们假设 r1、r2 和 …
给出以下课程:
public class FooTest {
public static class Base {
}
public static class Derived extends Base {
}
public interface Service<T extends Base> {
void service(T value);
}
public abstract class AbstractService<T extends Derived> implements Service<T> {
public void service(T value) {
}
}
private AbstractService service;
public void bar(Base base) {
if(base instanceof Derived) {
service.service(base); // compile error at this line
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用以下内容构建类时pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mgm-tp</groupId>
<artifactId>java-compiler-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build> …Run Code Online (Sandbox Code Playgroud) Java SE 11 的JLS §5.2包含一些 Java 8 的 JLS 没有的新类型转换案例,请参阅列表中的第 4 项和第 5 项:
赋值上下文允许使用以下之一:
- 身份转换
- 扩大原始转换
- 扩大参考转换
- 一个扩大的参考转换,然后是一个拆箱转换
- 扩展引用转换,然后是拆箱转换,然后是扩展基元转换
- 拳击转换
- 一个装箱转换,然后是一个扩大的参考转换
- 拆箱转换
- 一个拆箱转换,然后是一个扩大的原始转换
我不明白列表中的案例 4和案例 5。谁能用例子给我一些解释?如果可能,还请说明其实际用途。
更新:
正如@Naman 所评论的,这里是更改 JLS 的提议 - JDK-8166326:5.2:允许在拆箱前加宽,这是自 Java-9 以来生效的。在报告中,它提到:
这种行为对于与 capture 的互操作性尤其重要:各种现有程序都希望能够将 a 的元素
List<? extends Integer>视为整数。Run Code Online (Sandbox Code Playgroud)List<? extends Integer> li = null; int i = li.get(0);
这可能暗示着这次 JLS 的改变确实有实际的必要性。但我还是不明白为什么 <? extends Integer> 很重要。什么是与捕获的互操作性意味着,它为什么如此重要?这些现有的各种程序是什么样的?它们是 Java …
正当我认为我理解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) 你们每个人都知道JMM的这个特性,有时候对象的引用可以在完成这个对象的构造函数之前获得值.
在JLS7中,p.17.5 最后的字段语义我们也可以阅读:
final字段的使用模型很简单:final在该对象的构造函数中设置对象的字段; 并且在对象的构造函数完成之前,不要在另一个线程可以看到的地方写入对正在构造的对象的引用.如果遵循这一点,那么当另一个线程看到该对象时,该线程将始终看到该对象的final字段的正确构造版本.(1)
在JLS之后,接下来的示例演示了如何不保证非最终字段的初始化(1Example 17.5-1.1) (2):
class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}
static void writer() {
f = new FinalFieldExample();
}
static void reader() {
if (f != null) {
int i = f.x; // guaranteed to see 3
int j = f.y; // could …Run Code Online (Sandbox Code Playgroud) 考虑这两个类:
public abstract class Bar {
protected Bar() {
System.out.println(getValue());
}
protected abstract int getValue();
}
public class Foo extends Bar {
private final int i = 20;
public Foo() {
}
@Override
protected int getValue() {
return i;
}
public static void main(String[] args) {
new Foo();
}
}
Run Code Online (Sandbox Code Playgroud)
如果我执行Foo,则输出为20.
如果我使字段非final,或者我在Foo构造函数中初始化它,则输出为0.
我的问题是:在最终字段的情况下,初始化顺序是什么?JLS中描述了这种行为?
我希望找到最终的领域一些特殊的规则在这里,但除非我错过了什么,没有.
请注意,我知道我永远不应该从构造函数中调用可覆盖的方法.这不是问题的关键.
java ×10
jls ×10
final ×3
constructor ×2
eclipse ×2
autoboxing ×1
capture ×1
class ×1
classloader ×1
concurrency ×1
ecj ×1
java-11 ×1
java-8 ×1
javac ×1
jep ×1
jsr ×1