小编Arc*_*hie的帖子

Java:保证非最终引用字段的正确方法永远不会被读为null?

我正在尝试解决一个简单的问题,并陷入Java内存模型兔子洞.

什么是最简单和/或最有效(判断调用此处),但无竞争(根据JMM精确定义)编写包含非最终引用字段的Java类的方法,该字段初始化为非空值构造函数,后来从未改变过,这样任何其他线程的后续访问都不能看到非空值?

破碎的起始示例:

public class Holder {

  private Object value;

  public Holder(Object value) {
    if (value == null)
        throw NullPointerException();
    this.value = value;
  }

  public Object getValue() {    // this could return null!
    return this.value;
  }
}
Run Code Online (Sandbox Code Playgroud)

而根据这篇文章,标记该领域volatile甚至不起作用!

public class Holder {

  private volatile Object value;

  public Holder(Object value) {
    if (value == null)
        throw NullPointerException();
    this.value = value;
  }

  public Object getValue() {    // this STILL could return null!!
    return this.value;
  }
} …
Run Code Online (Sandbox Code Playgroud)

java java-memory-model

11
推荐指数
2
解决办法
541
查看次数

Java不区分大小写的正则表达式匹配不适用于字母Ñ

考虑这个程序:

import java.util.regex.Pattern;
public class xx {

    /*
     *  Ñ
     *  LATIN CAPITAL LETTER N WITH TILDE
     *  Unicode: U+00D1, UTF-8: C3 91
     */
    public static final String BIG_N = "\u00d1";

    /*
     *  ñ
     *  LATIN SMALL LETTER N WITH TILDE
     *  Unicode: U+00F1, UTF-8: C3 B1
     */
    public static final String LITTLE_N = "\u00f1";

    public static void main(String[] args) throws Exception {
        System.out.println(BIG_N.equalsIgnoreCase(LITTLE_N));
        System.out.println(Pattern.compile(BIG_N, Pattern.CASE_INSENSITIVE).matcher(LITTLE_N).matches());
    }
}
Run Code Online (Sandbox Code Playgroud)

由于Ñ是ñ的大写版本,你可以期望它打印:

true
true
Run Code Online (Sandbox Code Playgroud)

但它实际打印的内容(java 1.7.0_17-b02)是:

true
false
Run Code Online (Sandbox Code Playgroud)

为什么?

java regex

10
推荐指数
1
解决办法
1706
查看次数

java编译错误取决于静态变量名是否合格?

为什么这个java程序不能编译:

public class xx {
    public static final Object obj;
    static {
//        obj = null;       // this compiles
        xx.obj = null;      // this doesn't
    }
}
Run Code Online (Sandbox Code Playgroud)

有这个错误:

$ javac xx.java
xx.java:5: cannot assign a value to final variable obj
        xx.obj = null;      // this doesn't
          ^
1 error
$ javac -version
javac 1.6.0_33
Run Code Online (Sandbox Code Playgroud)

的时候,如果我取代xx.obj = nullobj = null(如评论提到),它编译.

我认为xx.类名前缀或多或少只是语法...这是编译器或语言规范中的错误吗?:)

java javac

9
推荐指数
1
解决办法
266
查看次数

Java不应该在变量声明中允许泛型类型声明的任何原因?

假设我们有一个这样的类:

public class xx {

    public interface Foo<T> {
        T getValue();
        void setValue(T value);
    }

    public void resetFoos(Iterable<Foo<?>> foos) {
        for (Foo<?> foo : foos)
            foo.setValue(foo.getValue());
    }
}
Run Code Online (Sandbox Code Playgroud)

它将无法编译,即使直观地看起来它应该"应该":

xx.java:10: setValue(capture#496 of ?) in xx.Foo<capture#496 of ?> cannot be applied to (java.lang.Object)
        foo.setValue(foo.getValue());
Run Code Online (Sandbox Code Playgroud)

原因是foo没有绑定泛型类型,因此编译器不"知道"输出foo.getValue()与输入兼容foo.setValue().

所以要解决这个问题,你必须创建一个新方法,只是为了在for()循环中绑定泛型类型参数:

public class xx {

    public interface Foo<T> {
        T getValue();
        void setValue(T value);
    }

    public void resetFoos(Iterable<Foo<?>> foos) {
        for (Foo<?> foo : foos)
            this.resetFoo(foo);
    }

    // …
Run Code Online (Sandbox Code Playgroud)

java generics language-design

8
推荐指数
1
解决办法
1980
查看次数

MySQL:为什么'FOO'没有被优化掉?

MySQL 5.5.28.我有两个表Person,Message后者有一个外键给前者.每个表都有id主键列,Person表中还有一个personId(唯一)索引的列.

下面的查询应该利用personId密钥索引,但是MySQL需要扫描整个Message表,原因如下:

mysql> EXPLAIN SELECT `m`.*
    -> FROM
    ->   `Message` AS `m`
    -> LEFT JOIN
    ->   `Person` AS `p` ON (`m`.`person` = `p`.`id`)
    -> WHERE
    ->   'M002649397' IS NULL OR
    ->   `p`.`personId` = 'M002649397';
+----+-------------+-------+--------+---------------+---------+---------+----------------+--------+-------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref            | rows   | Extra       |
+----+-------------+-------+--------+---------------+---------+---------+----------------+--------+-------------+
|  1 | SIMPLE      | m     | ALL …

mysql

6
推荐指数
1
解决办法
617
查看次数

如何判断java应用程序是否接近内存不足

我的简单目标:监视Java应用程序的内存使用情况,以便在应用程序危险地接近抛出时,可以收到警告OutOfMemoryError.

是的,简单说明,但提出正确的解决方案似乎非常复杂.一些复杂因素是:

  • 有不同的堆区域,每个区域都可以抛出OutOfMemoryError:
    • permgen空间,它有它自己的大小限制(通过设置-XX:MaxPermSize=)
    • 整个堆空间(设置为-Xmx)
  • 在烦扰垃圾收集之前,VM可能会分配几乎所有堆.如果应用程序使用了很多软引用,那么事实上肯定会发生这种情况.因此,只有高堆分配百分比并不意味着应用程序接近投掷OutOfMemoryError.
  • 如果System.gc()保证VM将回收所有可能可回收的对象(未引用和/或弱引用的对象),那将是很好的,但事实并非如此.所以调用System.gc()然后Runtime.freeMemory()不可靠.
  • 排队等待最终确定的对象占用内存,但(通常)在完成后将被释放.那么终结器线程是否已经到达它们会影响(明显的)内存使用量(在抛出OOM之前,VM是否将终结器作为最后一个绝对的行为运行?看起来不像它.)
  • 本机代码也会占用内存,过多使用它会导致OOM(在我的特定应用程序中这不是一个可能的情况,但确实会给整个图片增加另一个复杂性).

那么回答这个问题的好方法OutOfMemoryError什么呢?我的Java应用程序是否可以投入?

换句话说,假设应用程序版本X运行良好且没有内存泄漏,但版本X + 1具有缓慢的无法识别的内存泄漏.我希望在版本X + 1抛出之前通过此监视发出警报OutOfMemoryError,但我希望完全相同的监视不会给版本X带来误报.设置此监视可能需要一些调整 - 这没关系.

一个可能的答案可能是这样的结果:在GC运行之后,堆栈利用率在过去的N次"完整"GC运行中的最大值是多少?如果此值超过总分配内存的X%,则发出警报声.

这个想法是确定"应用程序内存使用"的简单数字,如百分比,甚至像LOW,MEDIUM或HIGH,然后监视此值.

jstat命令给出了大量的相关资料,问题就沸腾它归结为一个简单的答案,并避免由于上面列出的复杂因素误报(或否定).

java heap garbage-collection

6
推荐指数
1
解决办法
1354
查看次数

当名义类需要访问修改时,无法使用交集类型

接口:

interface PublicCloneable {
    Object clone();
}

interface HasPosition {
    // doesn't matter
}
Run Code Online (Sandbox Code Playgroud)

尝试使用交集类型:

@SuppressWarnings("unchecked")
<E extends PublicCloneable & HasPosition> E cloneAndIncrementPosition(E elem) {
    final E clone = (E)elem.clone();
    // rest omitted
}
Run Code Online (Sandbox Code Playgroud)

尝试编译javac 1.8.0_60:

$ javac xx.java
xx.java:13: error: clone() in Object cannot implement clone() in PublicCloneable
    <E extends PublicCloneable & HasPosition> E cloneAndIncrementPosition(E elem) {
     ^
  attempting to assign weaker access privileges; was public
xx.java:14: error: clone() has protected access in Object
        final E clone …
Run Code Online (Sandbox Code Playgroud)

java javac

6
推荐指数
1
解决办法
261
查看次数

如何使用MethodHandles.Lookup查找数组构造函数MethodHandle?

我如何得到MethodHandle像数组构造函数int[]::new

这不起作用:

public static void main(String[] args) throws Throwable {
    MethodHandles.Lookup lookup = MethodHandles.publicLookup();
    MethodHandle mh = lookup.findConstructor(int[].class, MethodType.methodType(void.class, int.class));
    System.out.println(mh);
    System.out.println(mh.invoke());
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

Exception in thread "main" java.lang.NoSuchMethodException: no such constructor: [I.<init>(int)void/newInvokeSpecial
    at java.lang.invoke.MemberName.makeAccessException(MemberName.java:871)
    at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:990)
    at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1382)
    at java.lang.invoke.MethodHandles$Lookup.findConstructor(MethodHandles.java:920)
    at xx.main(xx.java:11)
Caused by: java.lang.NoSuchMethodError: java.lang.Object.<init>(I)V
    at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
    at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:962)
    at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:987)
    ... 3 more
Run Code Online (Sandbox Code Playgroud)

这也不是:

public static void main(String[] args) throws Throwable {
    MethodHandles.Lookup lookup = MethodHandles.publicLookup();
    MethodHandle mh = lookup.findConstructor(int[].class, MethodType.methodType(void.class));
    System.out.println(mh); …
Run Code Online (Sandbox Code Playgroud)

java java-8 methodhandle

6
推荐指数
1
解决办法
764
查看次数

Collection.parallelStream()是否意味着发生在之前的关系?

考虑这个(完全人为的)Java代码:

final List<Integer> s = Arrays.asList(1, 2, 3);
final int[] a = new int[1];
a[0] = 100;
s.parallelStream().forEach(i -> {
    synchronized (a) {
        a[0] += i;
    }
});
System.out.println(a[0]);
Run Code Online (Sandbox Code Playgroud)

此代码是否保证输出"106"?

似乎不存在,除非有一个先发生过的关系建立起来parallelStream(),通过它我们可以肯定地知道a[0]lambda 中的第一次访问将看到100而不是零(根据我对Java内存模型的理解).

Collection.parallelStream()没有记录建立这种关系......

可以询问完成parallelStream()方法调用的相同问题.

所以我错过了一些东西,或者为了正确性,上述代码需要看起来像这样:

final List<Integer> s = Arrays.asList(1, 2, 3);
final int[] a = new int[1];
synchronized (a) {
    a[0] = 100;
}
s.parallelStream().forEach(i -> {
    synchronized (a) {
        a[0] += i;
    }
});
synchronized (a) …
Run Code Online (Sandbox Code Playgroud)

java java-memory-model java-stream

6
推荐指数
1
解决办法
160
查看次数

为什么这个程序用Java 7而不是Java 8编译?

考虑这个程序:

public class xx<T> {

    <T> Iterable<T> createIterable(Class<T> cls) {
        return null;
    }

    Iterable<? extends Number> createNumberIterable(boolean floatingPoint) {
        return this.createIterable(floatingPoint ? Integer.class : Float.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

在Java 7下,它编译:

$ java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
$ javac xx.java
$
Run Code Online (Sandbox Code Playgroud)

在Java 8下它没有:

$ java -version
java version "1.8.0_40"
Java(TM) SE Runtime Environment (build 1.8.0_40-b25)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
$ javac xx.java …
Run Code Online (Sandbox Code Playgroud)

java javac jls

5
推荐指数
1
解决办法
189
查看次数

Java JLS是否指定了原始包装类型的提升?

我对这个程序的输出感到有些神秘:

public class xx {
    public static void main(String[] args) throws Exception {
        Number x = false ? new Long(123) : new Integer(456);
        System.out.println(x + " isa " + x.getClass().getName());
    }
}
Run Code Online (Sandbox Code Playgroud)

这是它输出的内容:

456 isa java.lang.Long
Run Code Online (Sandbox Code Playgroud)

它出现在编译器"促进"类型的对象IntegerLong,就像它通常会促进原始值.我从来没有听说过对象推广,这种行为似乎非常令人惊讶.

我的问题:根据JLS,这是非常正确的行为吗?如果是这样,我希望尽可能看到参考.

或者这是一种autoboxing-gone-wild编译器错误?

我正在使用:

java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
Run Code Online (Sandbox Code Playgroud)

java jls

5
推荐指数
1
解决办法
99
查看次数

为什么SimpleDateFormat无法在日期字符串中解析工作日?

运行这个程序:

import java.text.*;
import java.util.*;
public class xx {
    public static void main(String[] args) throws Exception {
        final SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
        format.setLenient(false);
        format.parse("Tue, 16 Jan 2010 04:41:09 -0000");
    }
}
Run Code Online (Sandbox Code Playgroud)

给出这个结果(java version "1.7.0_17"):

Exception in thread "main" java.text.ParseException: Unparseable date: "Tue, 16 Jan 2010 04:41:09 -0000"
at java.text.DateFormat.parse(DateFormat.java:357)
at xx.main(xx.java:7)
Run Code Online (Sandbox Code Playgroud)

看来,当设置为非宽松模式时,Tue,前缀是无法解析的.

问题是,为什么EEE,不能匹配Tue,日期字符串的前缀?

java date

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

在堆上存储unique_ptr的最简单方法是什么?

Java很久,第一次使用C++.

我正在编写一个包装现有C++ API的Java类,看起来像这样:

public class Foo implements Closeable {

    private long handle;

    public Foo(File file) {
        this.handle = Foo.openFile(file.toString());
    }

    // other methods go here...

    public void close() {
        Foo.closeFile(this.handle);
        this.handle = 0;
    }

    private static native long openFile(String file);
    private static native void closeFile(long handle);
}
Run Code Online (Sandbox Code Playgroud)

我们将指向本机C++对象的指针填充到handle字段中.

问题是C++库没有给我一个指针,它给了我一个unique_ptr<Foo>.所以这必须被移到堆上openFile()(因此它不会超出范围),然后被销毁closeFile().

我无法让这个工作,我不确定我是否正确地做到了.在C++中正确执行此操作的最简单/最简洁的方法是什么?

这是我目前正在做的事情:

// This holds a unique_ptr<T>, typically on the heap, until no longer needed
template <class T>
class PointerHolder {
public:
    PointerHolder(unique_ptr<T> …
Run Code Online (Sandbox Code Playgroud)

c++ unique-ptr

0
推荐指数
1
解决办法
101
查看次数