2013-01-16 11 views
45

Secondo the tutorial:sulle parole chiave finali statici in Java

Il static modificatore, in combinazione con il modificatore final, viene utilizzato anche per definire le costanti. Il modificatore final indica che il valore di questo campo non può essere modificato.

Concordo con questo solo se i tipi coinvolti erano primitivi. Con i tipi di riferimento, ad es. un'istanza di una classe Point2D dove i suoi attributi di posizione non erano final (cioè, potremmo cambiare la sua posizione), gli attributi di questo tipo di variabili come public static final Point2D A = new Point2D(x,y); potrebbero ancora essere modificati. È vero?

+0

Sì, questa parte "definire costanti" è fuorviante. –

+2

Hmm. Potremmo fare un paio di risposte in più per renderlo veramente chiaro. –

+1

Non dimenticare che Point2D è astratto, quindi non puoi fare Point2D (x, y); – david99world

risposta

66

Sì, può essere modificato. Solo i riferimenti non possono essere modificati, ma i suoi campi interni possono essere. Il codice seguente lo mostra:

public class Final { 
    static final Point p = new Point(); 
    public static void main(String[] args) { 
     p = new Point(); // Fails 
     p.b = 10; // OK 
     p.a = 20; // Fails 
    } 
} 

class Point { 
    static final int a = 10; 
    static int b = 20; 
} 

Groovy (un JVM lingua alternativa) presenta un'annotazione chiamato @Immutable, che blocca il passaggio ad uno stato interno di un oggetto dopo che è costruito.

+18

+1 per il suggerimento Groovy. – Fildor

+0

E riguardo l'oggetto const in C++? – rpat

2

Il riferimento al punto (A nel tuo caso) non può essere modificato. Solo lo stato dell'oggetto può cambiare. Pertanto non è possibile creare un nuovo Point2D e assegnarlo alla variabile.

6

finale statico pubblico Point2D A = new Point2D (x, y); potrebbe ancora essere cambiato. È vero?

riferimento di un non poteva essere cambiato, ma valore la sua vera associato di oggetto può essere modificato se gli attributi non sono definitive.

class Point2D{ 
    private int x; 
    private int y; 
    <getter & setter> 
} 
class Constant{ 
    Public static final Point2D A = new Point2D(1,2); 
    public static void main(String[] args){ 
    A.setX(10); // this will work 
    A = new Point2D(10,20);// this will not work 
    } 
} 

In caso Point2D's attributi sono finali poi Point2Dclass sarebbe immutable.

oppure è possibile inviare l'oggetto clone-able.

Come -

private static final Point2D A = new Point2D(x,y); 
public static getA(){ 
    return A.clone(); 
} 
16

corretta, può ancora essere modificato. Il "finale statico", in questo caso, si riferisce al riferimento stesso, che non può essere modificato. Tuttavia, se l'oggetto di riferimento è modificabile, l'oggetto a cui fa riferimento può essere modificato.

Un oggetto immutabile, ad esempio una stringa, sarà una costante.

10
public static final Point2D A = new Point2D(x,y); 

Qui il riferimento A è finale e non i valori all'interno della classe Point2D.

Non si può fare questo dopo la definizione di una statica finale:

//somewhere else in code 
A = new Point2D(x1,y1); 
6

E 'vero. Il modificatore final non è transitabile in alcun modo possibile.

Significa solo che il riferimento non cambierà. Il contenuto del riferimento (i campi dell'oggetto) può cambiare nel tempo.

2

Solo il riferimento è definitivo, l'oggetto a cui si fa riferimento può essere modificato (a meno che non si tratti di un oggetto immutabile, come Integer o simile). Quindi sì, è costante solo per un dato valore di "costante".

0

È ancora vero.

Esiste un modo in cui l'affermazione citata è vera. static final descrive una variabile ed è vero che quella variabile non può essere modificata e quindi è una costante. La variabile è un puntatore a un oggetto e quell'oggetto può cambiare. Ma ciò non impedisce alla variabile di essere una costante.

Questo è un modo meno efficace di essere vero che è possibile ottenere con const in C++, ma è qualcosa.

0

Sì, hai ragione. Il riferimento non può essere modificato, ma l'oggetto a cui si fa riferimento può essere. Qualcosa di simile è perfettamente legale:

public static final List<Object> someList = new ArrayList<Object>(); 

// ... 

someList.add(someThing); // <-- this would be illegal if the referenced object was also constant 
0

È possibile modificare le proprietà di Point2D, ma non creare una nuova istanza di esso.

Vorrei anche menzionare che Point2D è astratto quindi è necessario creare un'istanza di una classe figlio che estenda questo.

0

Come già menzionato, è il riferimento all'oggetto Point2D che è statico finale, non gli attributi x e y. Se vuoi essere sicuro di non poter cambiare la posizione di un oggetto Point2D, devi impostare gli attributi x e y statici e finali (inizializzati) nella classe Point2D.

1

Sì.

Naturalmente, è anche possibile modificare il valore del campo finale in seguito as described elsewhere.

1

potete trovare una domanda molto simile qui con abbastanza buona spiegazione:

QUI: Why can final object be modified?

Tra l'altro ho iniziato a pensare a meccanismi di riflessione ....

in teoria .. .Credo che tu possa ottenere l'istanza di classe proprietaria .. quindi ottenere membri della classe, trovare istanza corrente e controllare che sia definitiva ....

Non l'ho controllato e non ho nemmeno kwnow se è possi BLE - è solo un'idea (? forse)

in

public class Final { 
    static final Point p = new Point(); 

    public static void main(String[] args) throws MyImmutableException { 
     p = new Point(); // Fails 
     p.setB(10); // OK 
     p.setA(20); // Fails - throws MyImmutableException 
    } 
}  

public class Point() { 
    int a = 10; 
    int b = 20; 

    public setA(int a) { 
     this.a = a; 
    } 
    public setB(int b) throws MyImmutableException { 
     detectIsFinal() 
     this.b = b; 
    } 

    private void detectIsFinal() throws MyImmutableException { 
     int mod = this.getClass().getModifiers() 
     if (Modifier.isFinal(mod)) { 
      throw new MyImmutableException(); 
     } 
    } 
} 

public class MyImmutableException extends Exception { 
    public MyImmutableException() {super(); } 
} 

pensavo che altro si può fare ... ancora una volta è solo un !!!!!!!!! PSEUDOCODE !!! Non sono sicuro che funzionerà anche: P

Forse qualcuno con conoscenza delle annotazioni sarà ispirato e farlo funzionare. Purtroppo non ho più tempo questa settimana. Forse più tardi cercherò di creare un POC.

public class Final { 
    @Immutable 
    static final Point p = new Point(); 

    public static void main(String[] args) { 
     p = new Point(); // Fails 
     p.setB(10); // Fails 
     p.setA(20); // OK 
    } 
}  

public class Point() { 
    int a = 10; 
    @ImmutableOnThisInstance 
    int b = 20; 

    @DetectIsImmutable 
    public setA(int a) {    
     this.a = a; 
    } 

    @DetectIsImmutable 
    public setB(int b) { 
     this.b = b; 
    }  
} 


class Immutable { 
    ????????????????? 
} 

class DetectIsImmutable { 
    /** 
    * Just a pseudocode - I don't know how to work with ANNOTATIONS :) :) :) 
    * SORRY :) 
    * @throws MyImmutableException 
    */ 
    private void detectMethod() throws MyImmutableException { 
     Immutable instance = CLASS_THAT_IS_ANNOTATED.getClass().getAnnotation(Immutable.class) 
     if (instance != null) { 
      // get parent Method invocation name (from stacktrace list) 
      String methodName = .............; 
      if (methodName.startsWith("set")) { 
       // check id we have variable with this settername 
       String fieldName = ...; // cut "set" get rest of it, make first letterSmall 
       // find this field in object fields 
       Field f = this.getClass().getDeclaredField(fieldName); 
       if (f.getAnnotation(ImmutableOnThisInstance.class) != null) { 
        throw MyImmutableException(); 
       } 
      } 
     } 
    }   

} 
0
static final Point2D A = new Point2D(x,y); 

Tutto ciò che dice è di riferimento della classe Point2D non può essere modificata.

  _____________ 
      |    | 
A----------|--->(x,Y) | 
      |    | 
      |_____________|Heap 

Così non si può cambiare una puntando a un oggetto diverso, ma naturalmente è possibile modificare il valore di (x, y) oppure il contenuto del punto oggetto

Se si desidera rendere il tuo oggetto altrettanto costante dovrai rendere l'oggetto Point immutabile.

0

Quando una variabile di riferimento è dichiarata come finale, non è possibile riassegnare un nuovo oggetto ad esso una volta che si riferisce a un oggetto. Ma puoi cambiare lo stato di un oggetto a cui punta la variabile di riferimento finale. Guardate l'esempio seguente ..

class A 
{ 
    int i = 10; 
} 

public class UseOfFinalKeyword 
{ 
    public static void main(String[] args) 
    { 
     final A a = new A(); //final reference variable 

     a.i = 50; 
     //you can change the state of an object to which final reference variable is pointing 

     a = new A(); //compile time error 

     //you can't re-assign a new object to final reference variable 
    } 
} 

Per maggiori informazioni, seguire il link: final keyword in java