2010-03-06 5 views
27

come faccio a rendere la mia funzione di scambio in java se non esiste un metodo con cui possiamo passare per riferimento? Qualcuno potrebbe darmi un codice?come faccio a rendere la mia funzione di scambio in java?

swap(int a, int b) 
{ 
    int temp = a; 
    a = b; 
    b = temp; 
} 

ma il cambiamento solito essere riflessa dal java passa dal valore

+3

Dovrai specificare più specificatamente cosa stai cercando di ottenere se vuoi ottenere aiuto con questo. –

+1

Dai un'occhiata a questo articolo: http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html –

+1

Tutti i parametri in Java vengono passati per valore. –

risposta

14

Non è possibile creare un metodo swap, in modo che dopo aver chiamato swap(x,y) il i valori di x e y saranno scambiati. Potresti creare un tale metodo per le classi mutabili scambiando il loro contenuto¹, ma questo non cambierebbe la loro identità dell'oggetto e non potresti definire un metodo generale per questo.

È tuttavia possibile scrivere un metodo che scambia due elementi in un array o in un elenco, se questo è ciò che si desidera.

¹ Ad esempio, è possibile creare un metodo di scambio che richiede due elenchi e dopo aver eseguito il metodo, l'elenco x avrà il contenuto precedente della lista y e l'elenco y avrà il contenuto precedente della lista x.

+4

È possibile creare un [metodo] (http://stackoverflow.com/questions/2393906/how-do-i-make-my-swap-function-in-java/20600020#20600020) chiamato come 'y = swap (x, x = y) 'per scambiare x e y. – dansalmo

14

Dipende da cosa si vuole fare. Questo codice scambia due elementi di un array.

void swap(int i, int j, int[] arr) { 
    int t = arr[i]; 
    arr[i] = arr[j]; 
    arr[j] = t; 
} 

Qualcosa di simile scambia il contenuto di due int[] di uguale lunghezza.

void swap(int[] arr1, int[] arr2) { 
    int[] t = arr1.clone(); 
    System.arraycopy(arr2, 0, arr1, 0, t.length); 
    System.arraycopy(t, 0, arr2, 0, t.length); 
} 

Qualcosa di simile scambia il contenuto di due BitSet (utilizzando il XOR swap algorithm):

void swap(BitSet s1, BitSet s2) { 
    s1.xor(s2); 
    s2.xor(s1); 
    s1.xor(s2); 
} 

Qualcosa di simile scambia i x e y campi di alcune Point classe:

void swapXY(Point p) { 
    int t = p.x; 
    p.x = p.y; 
    p.y = t; 
} 
+0

sono gli array passati per riferimento? – higherDefender

+0

No. Tutto in Java viene passato in base al valore, comprese le _referenze agli array in Java. Gli array non sono diversi da altri oggetti in questo caso. – polygenelubricants

+2

@ D.J .: Le matrici (come tutti gli oggetti) sono tipi di riferimento. Ciò significa che qualsiasi modifica apportata all'oggetto all'interno di un metodo sarà visibile all'esterno (significa anche che il passaggio di un oggetto a un metodo non copia il contenuto dell'oggetto, quindi il passaggio di un array di elementi 1M non copia gli oggetti 1M). Tuttavia la riassegnazione della variabile che si riferisce alla matrice non sarà visibile all'esterno (nel senso che se si esegue qualcosa come "arr1 = arr2' all'interno del metodo, questo non avrà alcun effetto visibile all'esterno). – sepp2k

1

Potrei fare qualcosa di simile al seguente. Naturalmente, con la ricchezza delle classi Collection, non riesco a immaginare di aver mai bisogno di usarlo in qualsiasi codice pratico.

public class Shift { 
    public static <T> T[] left (final T... i) { 
    if (1 >= i.length) { 
     return i; 
    } 
    final T t = i[0]; 
    int x = 0; 
    for (; x < i.length - 1; x++) { 
     i[x] = i[x + 1]; 
    } 
    i[x] = t; 
    return i; 
    } 
} 

Chiamato con due argomenti, è uno scambio.

Può essere utilizzato come segue:

int x = 1; 
int y = 2; 
Integer[] yx = Shift.left(x,y); 

alternativa:

Integer[] yx = {x,y}; 
Shift.left(yx); 

Poi

x = yx[0]; 
y = yx[1]; 

Nota: auto-scatole primitive.

+0

Tentativo di downvotare, dato che (a) non aiuta molto: il risultato è un array; le x originali, y non sono ancora state scambiate.(b) lo swap è un'operazione così comune, che si dovrebbe scrivere una funzione personalizzata da scambiare, non usare questa funzione di shift più generale. – ToolmakerSteve

+1

@ToolmakerSteve Avete notato che è già stato fornito uno swap standard e una risposta adeguata, che non è possibile in un modo standard? Quindi, piuttosto che clonare la risposta già fornita, la mia risposta è un "tipo" diverso di swap. Il punto di risposta è fornire opzioni, non solo per tutti, per rigurgitare ripetutamente la stessa risposta. Quindi usare uno shift per uno swap è un tipo di swap valido e non era una risposta già fornita, quindi l'ho inviato. – nicerobot

+0

Non sono ancora d'accordo: non è utile nel contesto della domanda. Forse in una domanda diversa. E le osservazioni che ho fatto sostengono. Tuttavia, come ho detto, il mio disaccordo non è abbastanza forte da svalutare la tua risposta. – ToolmakerSteve

53

penso che questo è il più vicino si può arrivare a un semplice scambio, ma non ha un modello di utilizzo semplice:

int swap(int a, int b) { // usage: y = swap(x, x=y); 
    return a; 
} 

y = swap(x, x=y); 

Essa si basa sul fatto che x passerà in swap prima y viene assegnato a x, quindi x viene restituito e assegnato a .

Si può rendere generico e scambiare qualsiasi numero di oggetti dello stesso tipo:

<T> T swap(T... args) { // usage: z = swap(a, a=b, b=c, ... y=z); 
    return args[0]; 
} 

c = swap(a, a=b, b=c) 
+2

Questa è davvero una bella idea. – Sunspawn

+3

Sono d'accordo, una buona idea, ma anche pericolosa ... Poiché si basa sull'assegnazione dei parametri sull'invocazione, qualsiasi progetto con questo metodo prima o poi finirà in un bug a causa di esso. Non lo permetterei nel codice di produzione se fossi in testa. –

+2

Intelligente. TROPPO intelligente. Si basa su qualcuno che scrive questo modello esattamente correttamente. Estremamente non ovvio da leggere più tardi. Avrei anche posto il veto su un pezzo di codice in produzione. Ma sono d'accordo che è molto intrigante. Così vicino ... – ToolmakerSteve

-5
public class Swap1 { 
    public static void main(String[] args){ 
     int x =7; 
     int y = 3; 

     swap(x,y); 

     System.out.println("x = " + x); 
     System.out.println("y = " + y); 
    } 

    public static void swap(int x, int y) { 
     int temp = x; 
     x = y; 
     y = temp; 
    } 
} 
+0

Non funziona, i parametri vengono passati per valore, non per riferimento, x e y non vengono scambiati. – gulchrider

+2

sul serio, hai letto anche la domanda originale? L'OP aveva già esattamente questa funzione e chiedeva perché non funzionava. E tu stampi con attenzione i valori, ma ovviamente non hai effettivamente eseguito il tuo codice, per vedere quali sono i valori. – ToolmakerSteve

+0

Java utilizza uno schema di valori pass-value che significa che quando si compila il programma fino allo scambio (x, y), viene assegnata una nuova x, y in memoria e quindi si fa riferimento alla variabile appena creata. Dopo che il passaggio è terminato, poiché NON appare più tardi, sarà raccolto e scomparso. Pertanto non vengono apportate modifiche dopo lo scambio (x, y). Prova a utilizzare un array per farlo funzionare. – CHANist

4

A quanto pare non ho punti reputazione abbastanza per commentare su Dansalmo's answer, ma è un buono, anche se errato. La sua risposta è in realtà un K-combinator.

int K(int a, int b) { 
    return a; 
} 

JLS is specific about argument evaluation when passing to methods/ctors/etc. (Non era così nelle specifiche più vecchie?)

Concesso, questo è un idioma funzionale, ma è abbastanza chiaro per coloro che lo riconoscono. (Se non si capisce il codice a trovare, non lo fanno scimmia in su!)

y = K(x, x=y); // swap x and y 

Il K-Combinator è progettato appositamente per questo genere di cose. AFAIK non c'è motivo per cui non dovrebbe passare una revisione del codice.

Mio $ 0,02.

+2

Ora che hai abbastanza reputazione, per favore sposta questo in un commento. Grazie! –

+0

Sono d'accordo, per favore aggiungi il tuo commento sopra. In effetti, ero molto impegnato nell'apprendimento delle tecniche funzionali al momento e potevo applicarle inconsapevolmente senza riconoscere il modello. Potresti anche trovarlo interessante. http://pure-fn.appspot.com/about – dansalmo

2

AFAIS, nessuno cita atomic reference.

Integer

public void swap(AtomicInteger a, AtomicInteger b){ 
    a.set(b.getAndSet(a.get())); 
} 

String

public void swap(AtomicReference<String> a, AtomicReference<String> b){ 
    a.set(b.getAndSet(a.get())); 
} 
+0

Non è necessario un tipo atomico per eseguire questa operazione. Qualunque detentore della classe mutevole farà. Anche matrici a un elemento di primitivi o riferimenti. –

0

Prova questa magia

public static <T> void swap(T a, T b) { 
    try { 
     Field[] fields = a.getClass().getDeclaredFields(); 
     for (Field field : fields) { 
      field.setAccessible(true); 
      Object temp = field.get(a); 
      field.set(a, field.get(b)); 
      field.set(b, temp); 
     } 
    } catch (IllegalAccessException e) { 
     e.printStackTrace(); 
    } 
} 

e provarlo!

System.out.println("a:" + a); 
    System.out.println("b:" + b); 
    swap(a,b); 
    System.out.println("a:" + a); 
    System.out.println("b:" + b); 
Problemi correlati