标签: jls

"合格的"构造在java中意味着什么?

有效Java中 的项目"项目22:偏爱非静态的静态成员类"Josh Bloch说:

非静态成员类的每个实例都与其包含类的封闭实例隐式关联.在非静态成员类的实例方法中,您可以使用限定的此构造调用封闭实例上的方法或获取对封闭实例的引用.

合格的这个结构是什么意思?

java jls

26
推荐指数
2
解决办法
3433
查看次数

Java 8 Consumer/Function Lambda Ambiguity

我有一个重载方法,分别接受Consumer和Function对象,并返回一个匹配相应的Consumer/Function的泛型类型.我认为这样会好,但是当我尝试使用lambda表达式调用任一方法时,我得到一个错误,指示对该方法的引用是不明确的.

基于我对JLS§15.12.2.1的阅读.确定可能适用的方法:似乎编译器应该知道我的带有void块的lambda与Consumer方法匹配,而带有返回类型的lambda与Function方法匹配.

我把以下无法编译的示例代码放在一起:

import java.util.function.Consumer;
import java.util.function.Function;

public class AmbiguityBug {
  public static void main(String[] args) {
    doStuff(getPattern(x -> System.out.println(x)));
    doStuff(getPattern(x -> String.valueOf(x)));
  }

  static Pattern<String, String> getPattern(Function<String, String> function) {
    return new Pattern<>(function);
  }

  static ConsumablePattern<String> getPattern(Consumer<String> consumer) {
    return new ConsumablePattern<>(consumer);
  }

  static void doStuff(Pattern<String, String> pattern) {
    String result = pattern.apply("Hello World");
    System.out.println(result);
  }

  static void doStuff(ConsumablePattern<String> consumablePattern) {
    consumablePattern.consume("Hello World");
  }

  public static class Pattern<T, R> {
    private final Function<T, R> …
Run Code Online (Sandbox Code Playgroud)

java lambda overloading jls java-8

25
推荐指数
1
解决办法
3838
查看次数

Java编译器如何为具有多个边界的参数化类型选择运行时类型?

我想更好地理解当Java编译器遇到如下方法的调用时会发生什么.

<T extends AutoCloseable & Cloneable>
void printType(T... args) {
    System.out.println(args.getClass().getComponentType().getSimpleName());
}

// printType() prints "AutoCloseable"
Run Code Online (Sandbox Code Playgroud)

我很清楚,<T extends AutoCloseable & Cloneable>在运行时没有类型,因此编译器可以做出最少的错误,并创建一个类型为两个边界接口之一的数组,丢弃另一个.

无论如何,如果切换接口的顺序,结果仍然是相同的.

<T extends Cloneable & AutoCloseable>
void printType(T... args) {
    System.out.println(args.getClass().getComponentType().getSimpleName());
}

// printType() prints "AutoCloseable"
Run Code Online (Sandbox Code Playgroud)

这导致我做了一些调查,看看接口发生变化时会发生什么.在我看来,编译器使用某种严格的顺序规则来决定哪个接口是最重要的,并且接口在代码中出现的顺序不起作用.

<T extends AutoCloseable & Runnable>                             // "AutoCloseable"
Run Code Online (Sandbox Code Playgroud)
<T extends Runnable & AutoCloseable>                             // "AutoCloseable"
Run Code Online (Sandbox Code Playgroud)
<T extends AutoCloseable & Serializable>                         // "Serializable"
Run Code Online (Sandbox Code Playgroud)
<T extends Serializable & AutoCloseable>                         // "Serializable"
Run Code Online (Sandbox Code Playgroud)
<T extends SafeVarargs & Serializable>                           // "SafeVarargs"
Run Code Online (Sandbox Code Playgroud)
<T extends Serializable …
Run Code Online (Sandbox Code Playgroud)

java variadic-functions jls multiple-bounds

25
推荐指数
1
解决办法
464
查看次数

是在Java中写入易失性的内存屏障

我最近在一次演讲中听到,写入volatile会触发线程写入的每个变量的内存屏障.这是真的正确吗?从JLS看来,似乎只有相关的变量才被刷新,而其他变量则没有.有人知道什么是正确的吗?能指出我在JLS的具体位置吗?

java concurrency volatile jls

22
推荐指数
2
解决办法
5644
查看次数

明确指定通配符的上限时有区别吗?

假设我有一个通用的class Generic<A extends BaseType>.

就Java语言规范而言,在以下两种类型声明之间是否存在显着差异?

Generic<?>
Generic<? extends BaseType>
Run Code Online (Sandbox Code Playgroud)

嵌套通配符怎么样?

List<Generic<?>>
List<Generic<? extends BaseType>>
Run Code Online (Sandbox Code Playgroud)

考虑到这一点,我认为这些是等价的.Generic指定type参数A具有BaseType上限.

因此,BaseType无论是否明确指定,通配符都应始终"自动"或"隐式"限制.

下面,我尝试调和我的直觉与JLS.


我找不到有关"隐式"边界的信息,所以我从查看子类型规则开始.

阅读有关子类型$ 4.10.2的JLS部分,它说:

给定泛型类型声明C<F1,...,Fn>(n> 0),参数化类型的直接超类型C<T1,...,Tn>(其中Ti(1≤i≤n)是一个类型)是以下所有:

  • D<U1 ?,...,Uk ?>,其中D<U1,...,Uk>泛型类型是泛型类型的直接超类型C<T1,...,Tn>,θ是替换[F1:= T1,...,Fn:= Tn].

  • C<S1,...,Sn>,其中Si含有Ti(1≤i≤n)(§4.5.1).

(强调我的)

据我所知,"通配符"在JLS中不被视为"类型".所以这不适用于前两个,但它适用于这两个List例子.

相反,这应该适用:

给定泛型类型声明C<F1,...,Fn>(n> 0),参数化类型的直接超类型(C<R1,...,Rn> 其中Ri( 1≤i≤n)中的至少一个是通配符类型参数)是参数化类型的直接超类型C<X1,...,Xn>,这是结果将捕获转换应用于C<R1,...,Rn>(§5.1.10).

(强调我的)

捕获转换$ 5.1.10应用于Generic<?>Generic<? …

java generics wildcard jls language-lawyer

22
推荐指数
1
解决办法
404
查看次数

为什么带有varargs的Java方法被识别为瞬态?

我正在使用Java Reflection API,并观察到具有可变参数列表的方法变得短暂.为什么这个以及transient关键字在这种情况下意味着什么?

来自Java Glossary,transient:

Java编程语言中的关键字,指示字段不是对象的序列化形式的一部分.当对象被序列化时,其瞬态字段的值不包括在串行表示中,而其非瞬态字段的值包括在内.

然而,这个定义并未说明方法.有任何想法吗?

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Dummy {
    public static void main(String[] args) {
        for(Method m : Dummy.class.getDeclaredMethods()){
            System.out.println(m.getName() + " --> "+Modifier.toString(m.getModifiers()));
        }
    }

    public static void foo(int... args){}
}
Run Code Online (Sandbox Code Playgroud)

输出:

main --> public static
foo --> public static transient
Run Code Online (Sandbox Code Playgroud)

java reflection jls

21
推荐指数
2
解决办法
2098
查看次数

Java转换:是编译器错误,还是语言规范错误,还是我错了?

我一直在阅读Java语言规范第3版,并且发现了我认为规范和javac编译器实现之间的差异.Eclipse编译器中存在相同的差异.

15.16节讨论了强制转换表达式.如果参数类型无法通过强制转换转换为强制类型,那么它应该是编译时错误(第5.5节):

如果根据转换转换规则(第5.5节),操作数的编译时类型永远不会转换为强制转换运算符指定的类型,那么这是一个编译时错误.否则,在运行时,通过将转换转换为强制转换运算符指定的类型来转换操作数值(如果需要).

5.5节讨论了转换.它给出了允许的转换类型列表.列表中特别缺少的是"取消装箱转换,然后加宽/缩小原始转换".但是,javac编译器(以及Eclipse编译器)似乎确实允许确切的转换序列.例如:

long l = (long) Integer.valueOf(45);
Run Code Online (Sandbox Code Playgroud)

......编译得很好.(有问题的强制转换是强制转换long;参数是类型java.lang.Integer,因此转换需要拆箱int后跟扩展的原始转换).

同样地,根据JLS它不应该是可以从铸造bytechar,因为(根据5.1.4)需要加宽原语转换一个基本收缩转换-然而,该铸造也由编译器允许的.

任何人都可以开导我吗?

编辑:自从问这个以来,我已经向Oracle 提交了一份错误报告.他们的反应是,这是"JLS中的一个小故障".

java javac jls

20
推荐指数
1
解决办法
906
查看次数

何时可以使用Java语言规范第4版?

既然JDK 7开发人员预览已经完成,人们可能会认为现在是新JLS的时候了.毕竟,语言已经发生了变化,虽然很小.

我还没找到任何东西.何时可以使用新的JLS,从哪里可以获得它?

java jls java-7

19
推荐指数
2
解决办法
3060
查看次数

根据JLS,'T.super'是一个合法表达吗?

考虑以下一组表达式:

class T {{
/*1*/   Object o = T.super; // error: '.' expected
/*2*/   o.toString();
}}
Run Code Online (Sandbox Code Playgroud)

尝试编译这将失败的行/*1*/出现错误:

error: '.' expected
    o = T.super;
               ^
Run Code Online (Sandbox Code Playgroud)

使用OpenJDK 1.8.0(Ubuntu)Oracle JDK 1.8(Windows)时.

但是,Eclipse 4.5.0(Mars) 编译它没有任何错误,它导致:

class T {
    T();
     0  aload_0 [this]
     1  invokespecial java.lang.Object() [8] // super()
     4  aload_0 [this]
     5  astore_1 [o]  // o = T.super
     7  invokevirtual java.lang.Object.toString() : java.lang.String [10]
    10  pop           // ^-- o.toString()
    11  return
}
Run Code Online (Sandbox Code Playgroud)

从中您可以看到/*1*/ …

java eclipse super jls java-8

19
推荐指数
1
解决办法
232
查看次数

为什么在这种情况下为原始函数返回null?

这段丑陋的代码确实可以编译但是会抛出NPE s == null

public static boolean isNullOrEmpty(String s)
{
    return s != null ? s.isEmpty() : null;
}
Run Code Online (Sandbox Code Playgroud)

虽然这不(如预期):

public static boolean isNullOrEmpty(String s)
{
    if(s != null)
        return s.isEmpty();
    else
        return null;
}
Run Code Online (Sandbox Code Playgroud)

我知道它们都是明显错误的,但是当我在源代码中找到第一段代码时,我很惊讶它编译了.

编辑:这是Java 7中JLS的相关部分.我猜测第一个语句适用但粗体语句适用.

15.25条件运算符?:

[...]

条件表达式的类型确定如下:

[...]

  • 如果第二个和第三个操作数之一是原始类型T,而另一个操作数的类型是将装箱转换(第5.1.7节)应用于T的结果,那么条件表达式的类型是T.

[...]

  • 否则,第二和第三操作数分别是S1和S2类型.设T1是将拳击转换应用于S1所产生的类型,让T2为应用到S2的装箱转换所产生的类型.条件表达式的类型是将捕获转换(第5.1.10节)应用于lub(T1,T2)(第15.12.2.7节)的结果.

java jls

18
推荐指数
1
解决办法
1620
查看次数