问题标签 [jls]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
java - JLS 如何指定不能在方法中正式使用通配符?
我一直想知道 Java 泛型的一些奇怪方面以及通配符的使用。假设,我有以下 API:
然后,假设我们声明了以下方法:
根据我的“直觉”理解,X<?>
实际上与 相同X<T>
,只是未知对于客户端代码<T>
来说是形式上未知的。但是在里面foo()
,我猜编译器可以推断(伪 JLS 代码)<T0> := <?>[0], <T1> := <?>[1], etc...
。这是大多数程序员明确而直观地做的事情。他们委托给一个私有的辅助方法,这导致了很多无用的样板代码:
另一个例子:
换句话说,编译器知道通配符 inx.set()
形式上与通配符 in 相同x.get()
。为什么它不能使用这些信息?JLS中是否有一个正式的方面来解释这个缺乏编译器的“功能”?
java - 编译器如何不检查 RuntimeExceptions,即使它们扩展了 Exception 类?
当我们通过扩展 Exception 类创建CustomException 时,编译器会对其进行检查,但即使 RuntimeExceptions 扩展了 Exception 类,编译器也不会对其进行检查。
这是如何在编译器中建立的。我在JLS中找到了一个部分说明原因。
为什么不检查
运行时异常 运行时异常类(RuntimeException 及其子类)免于编译时检查,因为根据 Java 编程语言设计者的判断,必须声明此类异常不会显着帮助确定正确性的节目。Java 编程语言的许多操作和构造都可能导致运行时异常。编译器可用的信息以及编译器执行的分析级别通常不足以确定不会发生此类运行时异常,即使这对程序员来说可能是显而易见的。要求声明这样的异常类只会让程序员感到恼火。
在标记接口的情况下,幕后是否发生了一些事情。
我正在寻找一些可以解释它是如何完成的以及为什么所有检查的异常都没有父类的来源?
java - 有人可以解释一下这个 hashcode() 合约中应用程序的实际含义吗?
来自 JLS:
每当在应用程序执行期间对同一个对象多次调用它时,hashCode 方法必须始终返回相同的整数,前提是没有修改对象上的 equals 比较中使用的信息。该整数不需要从应用程序的一次执行到同一应用程序的另一次执行保持一致。
这里的应用程序一词是什么意思 ,为什么hashcode()
允许 for on 对象在同一应用程序的不同执行之间有所不同?
java - 类声明中的成员接口是否隐式公开?
代码
我有以下带有成员接口的类:
另一个类试图访问它:
错误
在 Main 我从 javac 收到以下错误:SomeInterface is not public in SomeClass; cannot be accessed from outside package
.
在 Eclipse 中:SomeInterface is not public in SomeClass; cannot be accessed from outside package
.
两者都编译为 Java 7。如果我制作 SomeInterface ,一切都编译得很好public
。
但规格说
Java 7的Java 语言规范是这样说的:
成员接口是其声明直接包含在另一个类或接口声明中的接口。
除非指定访问修饰符,否则类声明中的成员接口是隐式公共的(第 6.6 节)。
Java 5的Java 语言规范似乎没有第二句话。
问题
那么 SomeInterface 不应该被认为是公共的,不应该 Main 编译吗?
更新
正如Ajay George所建议的,这确实是 Java 语言规范 7 中的一个错误(感谢JamesB)。与此同时,规范被纠正,不正确的句子被删除。Archive.org 中的最后一个版本,带有不正确的句子。
java - 枚举类型中静态块的执行顺序 wrt 到构造函数
这是来自有效的 Java :
请注意,Operation 常量从创建常量后运行的静态块放入 stringToEnum 映射。试图让每个常量从其自己的构造函数中将自己放入映射中会导致编译错误。这是一件好事,因为如果它是合法的,它会导致 NullPointerException。不允许枚举构造函数访问枚举的静态字段,编译时常量字段除外。这个限制是必要的,因为这些静态字段在构造函数运行时还没有被初始化。
我的问题是关于这条线:
“请注意,操作常量是从创建常量后运行的静态块中放入 stringToEnum 映射的”。
我认为静态块在构造函数运行之前被执行。它们实际上是在类加载期间执行的。
我在这里想念什么?
java - Java 内存模型中具有数据竞争的正确同步程序示例
在JLS 中,第 17.4.5 节。Happens-before Order,它说
当且仅当所有顺序一致的执行都没有数据竞争时,程序才能正确同步。
根据是否正确同步的程序仍然允许数据竞争?(第一部分)中的讨论,我们得到以下结论:
程序可以正确同步并具有数据竞争。
两个结论的结合意味着它必须存在这样一个例子:
程序的所有顺序一致执行都是无数据竞争的,但此类程序的正常执行(除顺序一致执行之外的执行)包含数据竞争。
经过深思熟虑,我仍然找不到这样的代码示例。那你呢?
java - JLS 是否完全涉及方法覆盖和泛型?
因此,我试图编写一种方法来回答我之前的一个问题:如何确定任意 java.lang.Method 是否覆盖另一个?为此,我正在阅读 JLS,在一个案例中似乎缺少一些部分。
假设您有以下课程:
在这种情况下,很明显B.foo
overrides A.foo
,但是我不明白这种情况如何符合规范。
关于方法覆盖,JLS §8.4.8.1指出:
在类 C 中声明的实例方法 m1 覆盖在类 A 中声明的另一个实例方法 m2,前提是满足以下所有条件:
C 是 A 的子类。
m1 的签名是 m2 签名的子签名(第 8.4.2 节)。
任何一个:
- m2 是公共的、受保护的或在与 C 相同的包中声明为具有默认访问权限,或
- m1 覆盖方法 m3(m3 不同于 m1,m3 不同于 m2),这样 m3 会覆盖 m2。
显然第 1 点和第 3 点在我们的案例中得到满足。让我们在 JLS 中更深入地了解子签名的含义。JLS §8.4.2说:
如果两个方法具有相同的名称和参数类型,则它们具有相同的签名。
如果满足以下所有条件,则两个方法或构造函数声明 M 和 N 具有相同的参数类型:
它们具有相同数量的形式参数(可能为零)
它们具有相同数量的类型参数(可能为零)
令 A1, ..., An 为 M 的类型参数,令 B1, ..., Bn 为 N 的类型参数。将 N 的类型中出现的 Bi 重命名为 Ai 后,相应类型变量的边界为相同,并且M和N的形参类型相同。
在我们的例子中,第 1 点显然是正确的(两者都有 1 个参数)。
第 2 点有点混乱(这就是我不确定规范的确切含义的地方):这两种方法都没有声明自己的类型参数,而是A.foo
使用T
which 是对类进行参数化的类型变量。
所以我的第一个问题是:在这种情况下,在类中声明的类型变量是否计数?
好的,现在让我们假设这T
不算数,因此第 2 点是错误的(在这种情况下,我什至不知道如何应用第 3 点)。我们的两个方法没有相同的签名,但这并不妨碍B.foo
成为A.foo
.
在JLS §8.4.2中更进一步,它说:
方法 m1 的签名是方法 m2 签名的子签名,如果:
m2 与 m1 具有相同的签名,或
m1 的签名与 m2 签名的擦除(第 4.6 节)相同。
我们已经确定第 1 点是错误的。
根据JLS §4.6的方法的擦除签名是a signature consisting of the same name as s and the erasures of all the formal parameter types given in s
. 所以 A.foo 的擦除是foo(Object)
并且 B.foo 的擦除是foo(String)
。这两个是不同的签名,因此第 2 点也是错误的,并且 B.foo 不是 A.foo 的子签名,因此 B.foo 不会覆盖 A.foo。
除了它...
我错过了什么?是否有一些我没有看到的难题,或者在这种情况下规范真的不完整?
java - JLS 的哪些部分证明能够像未经检查一样抛出已检查异常?
我最近发现并在博客中提到了这样一个事实,即可以通过 javac 编译器偷偷检查一个已检查的异常并将其抛出到不应抛出的地方。这在 Java 6 和 7 中编译并运行,抛出一个SQLException
无throws
orcatch
子句:
生成的字节码表明 JVM 并不真正关心已检查/未检查的异常:
JVM 接受这一点是一回事。但我对Java 语言是否应该存在一些疑问。JLS 的哪些部分证明了这种行为?它是一个错误吗?还是 Java 语言的一个隐藏得很好的“特性”?
我的感受是:
doThrow0()
's<E>
必然RuntimeException
在doThrow()
. 因此,不需要遵循JLS §11.2的throws
条款。doThrow()
RuntimeException
与 赋值兼容,因此编译器不会生成Exception
强制转换(这将导致 a )。ClassCastException
java - 像这样压缩做……会违反 JLS 的理念吗?
在用 Java 编写另一个do ... while
循环时,我开始思考它的语法。一个典型的程序员会写类似
然而,Java 有一种内置的压缩方式,允许程序员在循环内只有一行时删除大括号(这对于 Java 表达式很典型):
这可以被认为和写成
甚至作为
这很有趣。这引起了我的注意,这是一个必须跨两行读取和运行的 Java 语句,这意味着在运行该行之后do
,直到该行运行时操作才完成while
。请记住,其他表达式只有一行:
所以我开始思考,不是关于为什么会这样,而是关于如何进一步压缩这个陈述。
假设“行”是以分号 ( ;
) 结尾或包含在大括号 ( {
and }
) 中的任何内容,让我们了解这一点:一条do
语句必然需要运行两行,而一条do
语句必须至少继续运行直到它到达一个空while
语句。
那么为什么要使用牙套呢?
让我们看一些使用这种语法的场景。do...while
带有一个封闭语句的语句怎么样:
好吧,这里没有什么新鲜事。do...while
带有三个封闭语句的语句怎么样:
在这里,Java 将看到它是一个语句,它会在看到空语句do
之前运行第 2、3 和 4 行。while
此时,它知道我们已准备好结束循环,计算表达式,并可能返回do
或退出循环。
您可能认为会破坏它的东西怎么样?嵌套while
循环:
在这里,Java 看到它是一个do
语句并输入它,然后正常运行第 2 行。在 line 3
,它看到它是一个while
语句。此时它必须决定这是否是循环的结束。它检查while
语句并发现它不是空的,因此不是do
循环的结尾。它进入while
语句并循环第 3 行和第 4 行,直到不再循环。然后它会看到另一个while
语句,并且在检查时发现它是空的,因此是do
语句的结尾。它评估它,可能会或可能不会返回到第 2 行,但我们现在不在乎。
但是Supuhstar,这肯定看起来很多计算!这不会减慢 JVM 的速度吗?
不必要!这都可以在编译时完成,就像 Java 确定上面列出的任何其他语句是否为空(例如,尝试编译while(true);
将导致下一行编译时出现错误“ unreachable statement
”)。
所以,很像
编译成
然后
可以编译成
但是 Supuhstar,Java 不关心缩进!你的可以写任何缩进,或者根本没有?
当然!编译器同样容易编译
就像它会
这两者都会做同样的事情。
是否有其他人同意将这作为 Java 语法包含在内是一件好事,或者是否有一些明显的原因我错过了这不能完成?