考虑以下类:
class Temp {
private final int field = 5;
int sum() {
return 1 + this.field;
}
}
Run Code Online (Sandbox Code Playgroud)
然后我编译和反编译这个类:
> javac --version
javac 11.0.5
> javac Temp.java
> javap -v Temp.class
...
int sum();
descriptor: ()I
flags: (0x0000)
Code:
stack=2, locals=1, args_size=1
0: iconst_1
1: aload_0
2: invokestatic #3 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
5: pop
6: iconst_5
7: iadd
8: ireturn
Run Code Online (Sandbox Code Playgroud)
简单来说,javac编译sum()成这样:
int sum() {
final int n = 1;
Objects.requireNonNull(this); // <---
return n + …Run Code Online (Sandbox Code Playgroud) 我有以下课程:
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) 让我们用Eclipse Mars.2捆绑包中的ECJ编译器编译以下代码:
import java.util.stream.*;
public class Test {
String test(Stream<?> s) {
return s.collect(Collector.of(() -> "", (a, t) -> {}, (a1, a2) -> a1));
}
}
Run Code Online (Sandbox Code Playgroud)
编译命令如下:
$ java -jar org.eclipse.jdt.core_3.11.2.v20160128-0629.jar -8 -g Test.java
成功编译后,让我们检查生成的类文件javap -v -p Test.class.最有趣的是为(a, t) -> {}lambda 生成的合成方法:
private static void lambda$1(java.lang.String, java.lang.Object);
descriptor: (Ljava/lang/String;Ljava/lang/Object;)V
flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=0, locals=2, args_size=2
0: return
LineNumberTable:
line 5: 0
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 a Ljava/lang/String;
0 1 …Run Code Online (Sandbox Code Playgroud) 我在回答一个问题时遇到了一个我无法解释的场景。考虑这个代码:
interface ConsumerOne<T> {
void accept(T a);
}
interface CustomIterable<T> extends Iterable<T> {
void forEach(ConsumerOne<? super T> c); //overload
}
class A {
private static CustomIterable<A> iterable;
private static List<A> aList;
public static void main(String[] args) {
iterable.forEach(a -> aList.add(a)); //ambiguous
iterable.forEach(aList::add); //ambiguous
iterable.forEach((A a) -> aList.add(a)); //OK
}
}
Run Code Online (Sandbox Code Playgroud)
我不明白为什么显式键入 lambda 的参数(A a) -> aList.add(a)会使代码编译。此外,为什么它链接到 inIterable而不是in 的重载CustomIterable?
对此是否有一些解释或规范相关部分的链接?
注意:iterable.forEach((A a) -> aList.add(a));仅在CustomIterable<T>扩展时编译Iterable<T>(完全重载方法CustomIterable导致歧义错误)
在两者上都得到这个: …
以下代码创建一个Collector产生UnmodifiableSortedSet:
package com.stackoverflow;
import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collector;
import java.util.stream.Collectors;
public class SOExample {
public static <T extends Comparable<T>> Collector<T, ?, SortedSet<T>> toSortedSet() {
return Collectors.toCollection(TreeSet::new);
}
public static <T extends Comparable<T>> Collector<T, ?, SortedSet<T>> toUnmodifiableSortedSet() {
return Collectors.collectingAndThen(toSortedSet(), Collections::<T> unmodifiableSortedSet);
}
}
Run Code Online (Sandbox Code Playgroud)
代码在ecj编译器下编译:
$ java -jar ~/Downloads/ecj-3.13.101.jar -source 1.8 -target 1.8 SOExample.java
Picked up _JAVA_OPTIONS: -Duser.language=en -Duser.country=GB
Run Code Online (Sandbox Code Playgroud)
但是在javac下:
$ javac -version
Picked up _JAVA_OPTIONS: -Duser.language=en -Duser.country=GB
javac 1.8.0_73
$ javac SOExample.java
Picked …Run Code Online (Sandbox Code Playgroud) 我有以下代码:
package test;
import java.util.stream.IntStream;
public class A {
public static void main(String[] args) {
IntStream.range(0, 10).mapToObj(n -> new Object() {
int i = n;
}).mapToInt(o -> o.i).forEachOrdered(System.out::println);
}
}
Run Code Online (Sandbox Code Playgroud)
使用javac 1.8.0_101编译时,此代码工作正常,并按预期生成数字0到9.
但是当我在Eclipse中使用这段代码时,它会告诉我o.i:
i cannot be resolved or is not a field
Run Code Online (Sandbox Code Playgroud)
执行此操作时产生错误:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
i cannot be resolved or is not a field
at test.A.main(A.java:9)
Run Code Online (Sandbox Code Playgroud)
为什么我需要使用javac来编译这段代码?
我如何让Eclipse表现出来?
编辑:
我做了一些测试,只要我不在lambda中创建实例,它就可以在ecj中工作:
package test;
import java.util.Optional;
import java.util.function.Supplier;
public class B …Run Code Online (Sandbox Code Playgroud) 我在玩Java Unicode Escapes时无意中发现了以下有趣的奇怪之处。这是我写的代码:
static void main(String... args) {
/*
* \u0027 - single quote
*/
char e = \u0027\n\u0027;
char f = '\'';
System.out.println(e == f);
//output: true
}
Run Code Online (Sandbox Code Playgroud)
查看编译后的代码,Java 编译器将它们翻译成相同的字符文字。
char e = '\'';
char f = '\'';
Run Code Online (Sandbox Code Playgroud)
通过什么转换规则e变成了 a'而不是换行符\n?
顺便说一句,我在 Windows 11 上使用 Oracle JDK 19。
编辑:这个问题似乎与 Java 编译器未能按照 Java 语言规范工作有关。
编辑:当 Oracle JDK 19 在 JLS 18 模式下运行时,似乎会发生此问题。(我不知道如何正确地说这个)
Eclipse使用它自己的编译器(ECJ)来编译Java代码.调试使用Eclipse编译的程序更容易,因为可以立即应用简单的代码更改(通过热代码替换).
另一方面,Maven使用(默认情况下)oracle JDK,它生成不同的字节代码,防止在Eclipse调试会话中替换热代码.
因此,如果我计划调试程序,我想将Eclipse ECJ编译器与我的maven构建一起使用.对我来说一个方便的方式是"ecj"配置文件:
编译发布
$ mvn package
Run Code Online (Sandbox Code Playgroud)使用已启用的热代码替换编译快照
$ mvn -P ecj package
Run Code Online (Sandbox Code Playgroud)此外,可以在settings.xmlEclipse项目属性中指定配置文件激活.
我的问题是:
我的一个朋友注意到了
var<Integer> list = new ArrayList<Double>();
Run Code Online (Sandbox Code Playgroud)
在 Java 中有效。事实证明, 的类型list被评估为ArrayList<Double>。
使用时var<Integer> list = new ArrayList<>();,list就是ArrayList<Object>。
我们俩都无法弄清楚泛型类型的var作用,因为它似乎被忽略了。但如果是这样,为什么这首先在语法上是正确的?
下面的代码包含对Enum::name(通知无类型参数)的引用.
public static <T extends Enum<T>> ColumnType<T, String> enumColumn(Class<T> klazz) {
return simpleColumn((row, label) -> valueOf(klazz, row.getString(label)), Enum::name);
}
public static <T, R> ColumnType<T, R> simpleColumn(BiFunction<JsonObject, String, T> readFromJson,
Function<T, R> writeToDb) {
// ...
}
Run Code Online (Sandbox Code Playgroud)
Javac在编译期间报告警告:
[WARNING]发现原始类型:java.lang.Enum缺少泛型类java.lang.Enum的类型参数
更改表达式会Enum<T>::name导致警告消失.
但是,Idea会在Enum<T>::name版本上标记以下警告:
可以推断出显式类型参数
反过来,Eclipse(ECJ)没有报告任何一种配方的任何问题.
这三种方法中哪一种是正确的?
一方面原始类型相当令人讨厌.如果你试图放一些其他的类型参数,例如 Enum<Clause>::name会导致编译失败,所以这是一些额外的保护.
另一方面,上面的引用等同于e -> e.name()lambda,这个公式不需要类型参数.
Enviorment: