Java AtomicReferenceFieldUpdater - 使用泛型时出现 ClassCastException
Java AtomicReferenceFieldUpdater - ClassCastException when using generic types
我收到以下错误:
Exception in thread "main" java.lang.ClassCastException
at java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl.<init>(AtomicReferenceFieldUpdater.java:336)
at java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater(AtomicReferenceFieldUpdater.java:109)
at org.telegram.bot.util.FieldTimer.<init>(FieldTimer.java:27)
at org.telegram.bot.util.FieldTimer.<init>(FieldTimer.java:19)
at org.telegram.bot.util.FieldTimer.main(FieldTimer.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
对泛型类型使用 AtomicReferenceFieldUpdater
时。
我很困惑,不知道为什么会出现这样的错误。
我使用的代码:
public final class FieldTimer<V> {
private volatile V value;
private final V defaultValue;
private final long resetTimeout;
private final AtomicLong lastSet;
private final AtomicReferenceFieldUpdater<FieldTimer, V> updater;
public FieldTimer(V value, Class<V> type, long resetTimeout, TimeUnit unit) {
this(value, value, type, resetTimeout, unit);
}
public FieldTimer(V value, V defaultValue, Class<V> type, long resetTimeout, TimeUnit unit) {
this.value = value;
this.defaultValue = defaultValue;
this.resetTimeout = unit.toMillis(resetTimeout);
lastSet = new AtomicLong(System.currentTimeMillis());
updater = AtomicReferenceFieldUpdater.newUpdater(FieldTimer.class, type, "value");
}
public V get() {
return System.currentTimeMillis() - lastSet.get() >= resetTimeout
? defaultValue
: value;
}
public void set(V value) {
updater.set(this, value);
lastSet.set(System.currentTimeMillis());
}
public boolean compareAndSet(V expect, V update) {
boolean set = updater.compareAndSet(this, expect, update);
if (set) {
lastSet.set(System.currentTimeMillis());
}
return set;
}
}
异常发生在这行代码:
updater = AtomicReferenceFieldUpdater.newUpdater(FieldTimer.class, type, "value");
但是,如果我把它改成这样:
public final class LongFieldTimer {
private volatile Long value;
...
public LongFieldTimer(Long value, Long defaultValue, long resetTimeout, TimeUnit unit) {
...
updater = AtomicReferenceFieldUpdater.newUpdater(LongFieldTimer.class, Long.class, "value");
}
}
那么就不会有错误了:| (但为什么???)
导致此问题的原因是什么?以及如何解决?
谢谢。
你的领域
private volatile V value;
属于 Object
类型,因为 type erasure. The javadoc of AtomicReferenceFieldUpdater#newUpdater
声明它抛出
ClassCastException
- if the field is of the wrong type
您可能已将 Long.class
或 long.class
作为参数传递给 type
参数。它期望 Object.class
.
在您的第二个示例中,该字段被明确定义为 Long
类型
private volatile Long value;
所以 Long.class
会起作用,因为这是预期的字段类型。
我收到以下错误:
Exception in thread "main" java.lang.ClassCastException
at java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl.<init>(AtomicReferenceFieldUpdater.java:336)
at java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater(AtomicReferenceFieldUpdater.java:109)
at org.telegram.bot.util.FieldTimer.<init>(FieldTimer.java:27)
at org.telegram.bot.util.FieldTimer.<init>(FieldTimer.java:19)
at org.telegram.bot.util.FieldTimer.main(FieldTimer.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
对泛型类型使用 AtomicReferenceFieldUpdater
时。
我很困惑,不知道为什么会出现这样的错误。
我使用的代码:
public final class FieldTimer<V> {
private volatile V value;
private final V defaultValue;
private final long resetTimeout;
private final AtomicLong lastSet;
private final AtomicReferenceFieldUpdater<FieldTimer, V> updater;
public FieldTimer(V value, Class<V> type, long resetTimeout, TimeUnit unit) {
this(value, value, type, resetTimeout, unit);
}
public FieldTimer(V value, V defaultValue, Class<V> type, long resetTimeout, TimeUnit unit) {
this.value = value;
this.defaultValue = defaultValue;
this.resetTimeout = unit.toMillis(resetTimeout);
lastSet = new AtomicLong(System.currentTimeMillis());
updater = AtomicReferenceFieldUpdater.newUpdater(FieldTimer.class, type, "value");
}
public V get() {
return System.currentTimeMillis() - lastSet.get() >= resetTimeout
? defaultValue
: value;
}
public void set(V value) {
updater.set(this, value);
lastSet.set(System.currentTimeMillis());
}
public boolean compareAndSet(V expect, V update) {
boolean set = updater.compareAndSet(this, expect, update);
if (set) {
lastSet.set(System.currentTimeMillis());
}
return set;
}
}
异常发生在这行代码:
updater = AtomicReferenceFieldUpdater.newUpdater(FieldTimer.class, type, "value");
但是,如果我把它改成这样:
public final class LongFieldTimer {
private volatile Long value;
...
public LongFieldTimer(Long value, Long defaultValue, long resetTimeout, TimeUnit unit) {
...
updater = AtomicReferenceFieldUpdater.newUpdater(LongFieldTimer.class, Long.class, "value");
}
}
那么就不会有错误了:| (但为什么???)
导致此问题的原因是什么?以及如何解决?
谢谢。
你的领域
private volatile V value;
属于 Object
类型,因为 type erasure. The javadoc of AtomicReferenceFieldUpdater#newUpdater
声明它抛出
ClassCastException
- if the field is of the wrong type
您可能已将 Long.class
或 long.class
作为参数传递给 type
参数。它期望 Object.class
.
在您的第二个示例中,该字段被明确定义为 Long
private volatile Long value;
所以 Long.class
会起作用,因为这是预期的字段类型。