Java-metoden argument puslespill

stemmer
1

Jeg snublet over en veldig rart funksjon (?) Av Java.

Det virker som å bruke en ny søkeord for å erstatte en metode argument slags skift som objekt til et annet omfang:

import java.util.ArrayList;

public class Puzzle {
    public static void main(String[] args) {
        ArrayList<Integer> outer = new ArrayList<Integer>();
        outer.add(17);
        Puzzle.change(outer);
        outer.add(6);
        System.out.println(outer);

        // excpected output:
        // [23]
        // [23, 6]
        //
        // actual output:
        // [23]
        // [17, 7, 6]
    }

    public static void change(ArrayList<Integer> inner) {
        inner.add(7);
        inner = new ArrayList<Integer>();
        inner.add(23);
        System.out.println(inner);
    }
}

Kan noen forklare dette særhet? Jeg la merke til det samme type atferd med oppdraget.

Publisert på 24/09/2009 klokken 14:03
kilden bruker
På andre språk...                            


9 svar

stemmer
6

Dette er et av de klassiske java spørsmålet for nybegynnere.

Den indre para passeres av verdi (for en ikke-primitiv objekt, er det referansen). Hvis du handle på det, det påvirker det samme objektet som i det ytre kode, slik at du ser effekten i den ytre metoden.

Hvis du bytter objekt med et nytt objekt, er det ikke det samme. Når du arbeider på den nye, endrer du ikke den forrige, og du trenger ikke se virkningen i ytre metoden.


Oppdatering: sorry for vokabular feil som forårsaket mange kommentarer. Jeg rettet svaret mitt nå. Jeg tror poenget ble gjort, men det er mye klarere nå.

Svarte 24/09/2009 kl. 14:08
kilden bruker

stemmer
2

Den outerreferansen fremdeles forholder seg til den opprinnelige Arraylist som ble opprettet i hovedmetode. Bare den innerreferansen stadig peker til den nye Arraylist opprettet inne i changemetoden, og dette Arraylist er aldri referert utenfor change.

Dette er forventet atferd. Du må returnere referansen til den indre Arraylist for å få tilgang til det fra kallet omfang.

Svarte 24/09/2009 kl. 14:08
kilden bruker

stemmer
1

Du "faktiske produksjonen" gir mening. Du har re-tildelt indre til en ny verdi i endring () -metoden og ytre er ikke lenger påvirket. Prøv sporing gjennom utførelse med en debugger, og du vil forstå hva som skjer.

Svarte 24/09/2009 kl. 14:08
kilden bruker

stemmer
1

Du ikke skifte omfang, du bare tildelt den nye Arraylist til innerparameter. Prøv å lage inneret finalparameter for å forhindre dette.

Svarte 24/09/2009 kl. 14:08
kilden bruker

stemmer
0

'Indre' er en referanse til den samme gjenstanden som 'ytre' referanser initielt (som Java benytter pasning med referanse for objekt parametere angående fremgangsmåter, slik at indre og ytre både punkt til det samme objekt), og deretter inne i metode deg å gjøre 'indre' refererer til en ny gjenstand.

De viktige ting med Java er at dette ikke endrer hva ytre "henviser i den viktigste metoden. Når metodekallet er ferdig, 'indre' slutter å være i omfang, og vil bli avfall samles til slutt. Objektet som 'ytre' poeng til fortsatt er i omfang (som ytre fremdeles er aktiv).

Svarte 24/09/2009 kl. 14:08
kilden bruker

stemmer
1

Så vidt jeg forsto dette ikke er et puslespill, Java støtter bare pasning fra verdi, mener jeg alltid kopier argumenter. Mer her .

Svarte 24/09/2009 kl. 14:08
kilden bruker

stemmer
6

I java kan du tenke på alle variablene som pekere til de virkelige stedene.

Hva skjer er dette:

  1. Du oppretter en liste.
  2. legge 17 til det.
  3. sende listen til en annen funksjon som har sin egen pekeren til listen.
  4. legge 7 til den første listen.
  5. opprette en ny liste og peker den "indre" -pekeren til at en.
  6. legge 23 til den nye listen.
  7. skrive den nye listen og tilbake.
  8. i den opprinnelige funksjonen du har fortsatt pekeren peker til det samme objektet som før.
  9. du legger seks til den første listen.
  10. og skrive ut den første listen.
Svarte 24/09/2009 kl. 14:13
kilden bruker

stemmer
1

Ved å bygge metoden din får følgende tilsvarende kode:

import java.util.ArrayList;

public class Puzzle {
    public static void main(String[] args) {
        ArrayList<Integer> outer = new ArrayList<Integer>();
        outer.add(17);

        ArrayList<Integer> inner = outer;
        inner.add(7);  // inner refers to same array list as outer

        inner = new ArrayList<Integer>();  // inner refers to new array list
        inner.add(23);
        System.out.println(inner);  // new list is printed

        outer.add(6);
        System.out.println(outer);  // outer list is printed
}

}

Svarte 24/09/2009 kl. 14:37
kilden bruker

stemmer
8

Dette er en klassisk tur-up for Java nybegynnere. En del av problemet er at vi mangler et felles språk for å identifisere dette. Er parametere vedtatt av verdi? Objekter er vedtatt av referanse? Avhengig av hvem du snakker med vil det være ulike reaksjoner på ordene passerer verdi og passerer referanse, selv om alle ønsker å si det samme.

Den måten å visualisere dette på er å forstå at java variable kan være en av to ting. Den kan enten inneholde en primitiv eller en referanse til et objekt. Tenk på at referansen som et tall som peker til et sted i minnet. Det er ikke en peker i C ++ mening i at det ikke peke på en bestemt sted i minnet, er det mer av et håndtak, ved at den lar JVM slå opp et bestemt minneområde hvor objektet kan bli funnet. Men du kan visualisere det på denne måten:

   ArrayList<Integer> outer = @1234; //The first reference where the ArrayList was created.

Du kan deretter ringe indre med parameterne:

  Puzzle.change(@1234);

Merk at du ikke passerer den ytre variabel, passerer du verdien av @ 1234. ytre kan ikke endres på noen måte ved å være en parameter på en metode. Dette er hva vi mener når vi sier passerer verdi. Verdien er passert, men det er koblet fra den ytre variable.

Inne puslespill:

public static void change(ArrayList<Integer> inner) { // a new reference inner is created.
    //inner starts out as @1234
    inner.add(7);
    //now inner becomes @5678
    inner = new ArrayList<Integer>();
    //The object @5678 is changed.
    inner.add(23);
    //And printed.
    System.out.println(inner);
}

Men ytre peker fremdeles til @ 1234 som metode ikke kunne endre det, det hadde aldri den ytre variabel, det hadde bare innholdet. Imidlertid, siden endringen metode startet med en henvisning til @ 1234, objektet ved at plasseringen kan faktisk bli endret på samme måte og resultatene er synlige for en hvilken som helst annen referanse til @ 1,234.

Etter endringen metoden er fullført, ingenting refererer objektet @ 5678, så det blir kvalifisert for søppelrydding.

Svarte 24/09/2009 kl. 14:53
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more