2015-08-06 1 views
0

je reçois l'erreur suivante:Java AtomicReferenceFieldUpdater - ClassCastException lors de l'utilisation des types génériques

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) 

lors de l'utilisation AtomicReferenceFieldUpdater pour les types génériques.

Je suis totalement confus et je ne sais pas pourquoi je reçois une telle erreur.

le code J'utilise:

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; 
    } 

} 

l'exception se produit dans cette ligne de code:

updater = AtomicReferenceFieldUpdater.newUpdater(FieldTimer.class, type, "value"); 

mais, si je change à quelque chose comme ceci:

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"); 
    } 

} 

alors il n'y aurait pas d'erreurs: | (mais pourquoi ???)

Qu'est-ce qui cause ce problème? et comment le résoudre?

Merci.

Répondre

1

Votre champ

private volatile V value; 

est de type Object à cause de type erasure. Le javadoc AtomicReferenceFieldUpdater#newUpdater déclare qu'il jette

ClassCastException - si le champ est du mauvais type

Vous avez probablement passé Long.class ou long.class comme argument pour le paramètre type. Il s'attend à Object.class.

Dans votre deuxième exemple, le champ est explicitement défini comme étant de type Long

private volatile Long value; 

donc Long.class fonctionnera, puisque c'est le type du champ prévu.