Struct som objekter i Java

stemmer
178

Er det helt mot Java måten å skape struct som objekter?

class SomeData1 {
    public int x;
    public int y;
}

Jeg kan se en klasse med accessors og Mutators være mer Java lignende.

class SomeData2 {
    int getX();
    void setX(int x);

    int getY();
    void setY(int y);

    private int x;
    private int y;
}

Klassen fra det første eksempelet er notationally praktisk.

// a function in a class
public int f(SomeData1 d) {
    return (3 * d.x) / d.y;
}

Dette er ikke så praktisk.

// a function in a class
public int f(SomeData2 d) {
    return (3 * d.getX()) / d.getY();
}
Publisert på 31/08/2008 klokken 09:17
kilden bruker
På andre språk...                            


20 svar

stemmer
260

Det ser ut til at mange Java-folk ikke er kjent med Sun Java Coding retningslinjer som sier det er helt riktig å bruke offentlige instansvariabel når klassen er egentlig en "Struct", hvis Java støttet "struct" (når det ikke er atferd).

Folk har en tendens til å tenke kundeskaffere og settere er Java måte, som om de er i hjertet av Java. Dette er ikke slik. Hvis du følger Sun Java Coding retningslinjer, bruk av offentlige instansvariabler i aktuelle situasjoner, er du faktisk skriver bedre kode for å fylle det med unødvendig kundeskaffere og settere.

Java-kode konvensjonene fra 1999 og fortsatt uendret.

10.1 gi tilgang til forekomsten og Klassevariabler

Ikke gjør noen forekomst eller klassevariabel offentlig uten god grunn. Ofte gjør instansvariabler ikke trenger å være eksplisitt angi eller fått-ofte det skjer som en bivirkning av metodekall.

Et eksempel på egnede offentlig instans variabler er det tilfelle hvor den klassen er i hovedsak en datastruktur, uten oppførsel. Med andre ord, hvis du ville ha brukt en struct i stedet for en klasse (hvis Java støttes struct), så er det riktig å gjøre klassen instansvariabler offentlig .

http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177

http://en.wikipedia.org/wiki/Plain_old_data_structure

http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28

Svarte 19/12/2011 kl. 18:29
kilden bruker

stemmer
213

Bruk sunn fornuft egentlig. Hvis du har noe sånt som:

public class ScreenCoord2D{
    public int x;
    public int y;
}

Da er det liten vits i å pakke dem opp i kundeskaffere og settere. Du kommer aldri til å lagre en x, y koordinat i hele piksler annen måte. Kundeskaffere og settere vil bare sakte deg ned.

På den annen side, med:

public class BankAccount{
    public int balance;
}

Du vil kanskje endre måten en balanse er beregnet på et tidspunkt i fremtiden. Dette bør virkelig bruke kundeskaffere og settere.

Det er alltid best å vite hvorfor du søker god praksis, slik at du vet når det er ok å bøye reglene.

Svarte 31/08/2008 kl. 14:44
kilden bruker

stemmer
58

Dette er en vanlig diskutert tema. Ulempen med å skape offentlige felt i objekter er at du har ingen kontroll over verdiene som er satt til det. I gruppeprosjekter der det er mange programmerere som bruker den samme koden, er det viktig å unngå bivirkninger. Dessuten er det noen ganger bedre å returnere en kopi av feltets objekt eller forvandle det liksom etc. Du kan spotte slike metoder i testene. Hvis du oppretter en ny klasse du kanskje ikke ser alle mulige tiltak. Det er som defensiv programmering - Someday kundeskaffere og settere kan være nyttig, og det trenger ikke koste mye å lage / bruke dem. Så de er noen ganger nyttig.

I praksis de fleste felt har enkle kundeskaffere og settere. En mulig løsning ville se slik ut:

public property String foo;   
a->Foo = b->Foo;

Oppdatering: Det er svært lite sannsynlig at eiendommen støtte vil bli lagt i Java 7 eller kanskje noensinne. Andre JVM språk som Groovy, Scala, etc gjør støtter denne funksjonen nå. - Alex Miller

Svarte 31/08/2008 kl. 09:50
kilden bruker

stemmer
47

For å møte mutability bekymringer du kan erklære x og y som endelig. For eksempel:

class Data {
  public final int x;
  public final int y;
  public Data( int x, int y){
    this.x = x;
    this.y = y;
  }
}

Ringe kode som forsøker å skrive til disse feltene vil få en kompilering feil av "-feltet x er erklært endelig, kan ikke bli tildelt".

Klienten kode kan da ha 'short-hand' stor du beskrev i innlegget ditt

public class DataTest {
    public DataTest() {
        Data data1 = new Data(1, 5);
        Data data2 = new Data(2, 4);
        System.out.println(f(data1));
        System.out.println(f(data2));
    }

    public int f(Data d) {
        return (3 * d.x) / d.y;
    }

    public static void main(String[] args) {
        DataTest dataTest = new DataTest();
    }
}
Svarte 02/09/2008 kl. 01:51
kilden bruker

stemmer
9

Re: aku, izb, John Topley ...

Se opp for mutability problemer ...

Det kan virke fornuftig å utelate kundeskaffere / settere. Det kan faktisk være ok i noen tilfeller. Det virkelige problemet med den foreslåtte mønsteret som vises her er mutability.

Problemet er når du passerer et objekt referanse ut inneholder ikke-finalen, offentlige områder. Noe annet med at referansen er fritt til å endre disse feltene. Du trenger ikke lenger noen kontroll over staten som objekt. (Tenk hva som ville skje hvis Strings var foranderlig.)

Det blir dårlig når objektet er en viktig del av den interne tilstanden til en annen, du har bare utsatt intern gjennomføring. For å unngå dette, må en kopi av objektet returneres i stedet. Dette fungerer, men kan forårsake massive GC press fra tonnevis av engangs kopier opprettet.

Hvis du har offentlige områder, vurdere å gjøre klassen skrivebeskyttet. Legg feltene som parametre til konstruktøren, og merk feltene finalen. Ellers pass på at du ikke utsette indre tilstand, og hvis du trenger å konstruere nye instanser for en returverdi, sørg for at det ikke vil bli kalt overdrevet.

Se: " Effektiv Java " av Joshua Bloch - Varenummer 13: Favor Immutability.

PS: Husk også, alle JVM i disse dager vil optimalisere bort getMethod hvis mulig, noe som resulterer i bare ett enkelt felt lese instruksjon.

Svarte 31/08/2008 kl. 16:27
kilden bruker

stemmer
8

Ikke bruk publicfelt

Ikke bruk publicfelt når du virkelig ønsker å pakke den interne oppførselen til en klasse. Ta java.io.BufferedReaderfor eksempel. Den har følgende felt:

private boolean skipLF = false; // If the next character is a line feed, skip it

skipLFleses og skrives i alle lesemetoder. Hva om en ekstern klasse kjører i en egen tråd med onde hensikter staten skipLFi midten av en lese? BufferedReadervil definitivt gå floke.

Bruker publicfelt

Ta denne Pointklassen for eksempel:

class Point {
    private double x;
    private double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() {
        return this.x;
    }

    public double getY() {
        return this.y;
    }

    public void setX(double x) {
        this.x = x;
    }

    public void setY(double y) {
        this.y = y;
    }
}

Dette ville gjøre å beregne avstanden mellom to punkter svært smertefullt å skrive.

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.getX() - a.getX(), 2) + Math.pow(b.getY() - a.getY(), 2));

Klassen har ikke noe annet enn vanlig kundeskaffere og settere atferd. Det er akseptabelt å bruke offentlige felt når klassen representerer bare en datastruktur, og ikke har, og aldri vil ha atferd (tynne kundeskaffere og settere er ikke ansett oppførsel her). Det kan skrives bedre på denne måten:

class Point {
    public double x;
    public double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));

Ren!

Men husk: Ikke bare klassen må være fraværende av atferd, men det bør også ha noen grunn til å ha atferd i fremtiden også.

Svarte 25/09/2014 kl. 06:48
kilden bruker

stemmer
7

Jeg har prøvd dette i noen få prosjekter, på teorien om at kundeskaffere og settere fyller opp kode med semantisk meningsløst cruft, og at andre språk ser ut til å gjøre det bra med konvensjonen-baserte data-skjule eller oppdeling av ansvar (f.eks python).

Som andre har nevnt ovenfor, det er 2 problemer som du kjører inn i, og de er egentlig ikke an å fikse:

  • Bare om noen automatisert verktøy i java verden er avhengig av getter / setter konvensjonen. Ditto for, som nevnt av andre, JSP koder, våren konfigurasjon, Eclipse verktøy, etc. etc ... Kampen mot hva dine verktøy forvente å se er en oppskrift for lange økter trolling gjennom google prøver å finne at ikke-standard måte å initiere fjær bønner. Egentlig ikke verdt bryet.
  • Når du har din elegant kodet program med hundrevis av offentlige variabler vil du sannsynligvis finne minst en situasjon der de er insufficient- der du absolutt trenger uforanderlighet, eller du trenger å utløse en hendelse når variabelen blir satt, eller du ønsker å kaste et unntak på en variabel endringen fordi den setter et objekt tilstand til noe ubehagelig. Du er så fast med unenviable valg mellom å fylle opp koden din med noen spesiell metode overalt variabelen er direkte referert, å ha noen spesiell tilgang skjema for 3 av de 1000 variablene i programmet.

Og dette er i beste fall å jobbe helt i en selvstendig privat prosjekt. Når du eksporterer hele greia til en offentlig tilgjengelig bibliotek disse problemene vil bli enda større.

Java er veldig ordrik, og dette er en fristende ting å gjøre. Ikke gjør det.

Svarte 01/12/2008 kl. 20:50
kilden bruker

stemmer
7

Forresten, strukturen du gir som et eksempel eksisterer allerede i Java-basen klassebibliotek som java.awt.Point. Den har x og y som offentlige områder, sjekk den ut selv .

Hvis du vet hva du gjør, og andre i teamet vet om det, så er det greit å ha offentlige områder. Men du bør ikke stole på det fordi de kan forårsake hodepine som i bugs relatert til utviklere som bruker gjenstander som om de stakk tildelt structs (java objektene er alltid sendt til metoder som referanser og ikke som kopier).

Svarte 31/08/2008 kl. 14:24
kilden bruker

stemmer
4

Hvis Java måten er den OO måten, så ja, lage en klasse med offentlige felt bryter prinsippene rundt informasjon gjemme som sier at et objekt skal forvalte sin egen interne tilstand. (Så som jeg ikke bare sprutende sjargong på deg, er en fordel for informasjon skjul på at det interne arbeidet i en klasse er skjult bak et grensesnitt - si at du ønsket å endre den mekanismen som din struct klasse reddet en av sine felt, vil du sannsynligvis trenger å gå tilbake og endre noen klasser som bruker klassen ...)

Du kan heller ikke dra nytte av støtte for Javabean navngi kompatible klasser, noe som vil skade hvis du velger å si, bruke klassen i en Javaserver Page som er skrevet med Expression Language.

Den JavaWorld artikkel Hvorfor Getter og Setter Metoder er Evil artikkel også kan være av interesse for deg i å tenke på når man ikke skal gjennomføre aksessor og Mutator metoder.

Hvis du skriver en liten løsning og ønsker å minimere mengden av kode som er involvert, kan det hende at Java måten ikke være den riktige måten - jeg antar det alltid avhenger av deg og problemet du prøver å løse.

Svarte 31/08/2008 kl. 09:33
kilden bruker

stemmer
3

Det er ingenting galt med den type kode, forutsatt at forfatteren vet de er structs (eller datatransport) i stedet for gjenstander. Mange Java-utviklere kan ikke fortelle forskjellen mellom en velformet gjenstand (ikke bare en underklasse av java.lang.Object, men en ekte objekt i et bestemt domene) og en ananas. Ergo, de ender opp med å skrive structs når de trenger gjenstander og omvendt.

Svarte 15/04/2010 kl. 02:59
kilden bruker

stemmer
2

En veldig-veldig gamle spørsmålet, men la meg gjøre en kort bidrag. Java 8 introdusert lambda uttrykk og metode referanser. Lambda uttrykk kan være enkel metode referanser og ikke erklære en "ekte" kropp. Men du kan ikke "konvertere" et felt til en metode referanse. Og dermed

stream.mapToInt(SomeData1::x)

er ikke lovlig, men

stream.mapToInt(SomeData2::getX)

er.

Svarte 10/07/2014 kl. 15:03
kilden bruker

stemmer
2

Jeg bruker ofte dette mønsteret når du bygger private indre klasser for å forenkle koden min, men jeg vil ikke anbefale å utsette slike objekter i en offentlig API. Generelt, jo oftere kan du lage objekter i offentlige API uforanderlig jo bedre, og det er ikke mulig å konstruere din 'struct-aktig' objekt i en uforanderlig måte.

Som en side, selv om jeg skulle skrive dette objektet som et privat indre klasse Jeg vil likevel gi en konstruktør for å forenkle koden for å initialisere objektet. Måtte ha 3 linjer med kode for å få et brukbart objekt når en vil gjøre er bare rotete.

Svarte 15/10/2008 kl. 04:28
kilden bruker

stemmer
2

Problemet med å bruke offentlig felttilgang er det samme problemet som med ny i stedet for en fabrikk metode - hvis du ombestemmer deg senere, alle eksisterende innringere er brutt. Så, fra en API utvikling synspunkt, er det vanligvis en god idé å bite i kule og bruke kundeskaffere / settere.

Ett sted hvor jeg går den andre veien er når du sterkt styre tilgangen til klassen, for eksempel i en indre statisk klasse brukes som en intern datastruktur. I dette tilfellet, kan det være mye klarere å bruke felttilgang.

Forresten, på e-Bartek påstand, er det svært usannsynlig IMO at eiendom støtte vil bli lagt i Java 7.

Svarte 15/09/2008 kl. 16:21
kilden bruker

stemmer
1

Her lager jeg et program for å legge inn navn og alder på 5 forskjellige personer og utføre et utvalg sort (alder klok). I brukte en klasse som virker som en struktur (som programmeringsspråket C) og en hovedklasse for å utføre hele operasjonen. Herunder Jeg møblering koden ...

import java.io.*;

class NameList {
    String name;
    int age;
}

class StructNameAge {
    public static void main(String [] args) throws IOException {

        NameList nl[]=new NameList[5]; // Create new radix of the structure NameList into 'nl' object
        NameList temp=new NameList(); // Create a temporary object of the structure

        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

        /* Enter data into each radix of 'nl' object */

        for(int i=0; i<5; i++) {
            nl[i]=new NameList(); // Assign the structure into each radix

            System.out.print("Name: ");
            nl[i].name=br.readLine();

            System.out.print("Age: ");
            nl[i].age=Integer.parseInt(br.readLine());

            System.out.println();
        }

        /* Perform the sort (Selection Sort Method) */

        for(int i=0; i<4; i++) {
            for(int j=i+1; j<5; j++) {
                if(nl[i].age>nl[j].age) {
                    temp=nl[i];
                    nl[i]=nl[j];
                    nl[j]=temp;
                }
            }
        }

        /* Print each radix stored in 'nl' object */

        for(int i=0; i<5; i++)
            System.out.println(nl[i].name+" ("+nl[i].age+")");
    }
}

Koden ovenfor er feilfri og testet ... Bare kopier og lim den inn i IDE og ... Du vet og hva ??? :)

Svarte 19/02/2013 kl. 05:50
kilden bruker

stemmer
1

Dette er et spørsmål om objektorientert design, ikke Java språket. Det er generelt god praksis å skjule datatyper i klassen og avsløre bare metodene som er en del av klassen API. Hvis du utsetter interne datatyper, kan du aldri endre dem i fremtiden. Hvis du skjuler dem, din eneste forpliktelse til brukeren er metodens retur og argumenttypene.

Svarte 31/08/2008 kl. 10:13
kilden bruker

stemmer
1

Jeg ser ikke skade hvis du vet at det alltid kommer til å være en enkel struct og at du aldri kommer til å ønske å knytte atferd til det.

Svarte 31/08/2008 kl. 09:20
kilden bruker

stemmer
0

Aspect orientert programmering lar deg fange oppdrag eller henter og fest avskjærende logikken til dem, som jeg foreslår er den rette måten å løse problemet. (Spørsmålet om hvorvidt de skal være offentlige eller beskyttet eller pakke-beskyttede er ortogonale.)

Dermed du starter med unintercepted felt med riktig tilgang kvalifiseringen. Som program kravene øker du fester logikken til kanskje validere, lage en kopi av objektet som skal returneres etc.

Den getter / setter filosofi pålegger kostnader på et stort antall enkle tilfeller der de ikke trengs.

Enten aspekt-stil er renere eller ikke er noe kvalitativt. Jeg ville finne det lett å se bare variablene i en klasse og se logikken separat. Faktisk er raison d'être for apect orientert programmering er at mange bekymringer er kapp compartmentalizing dem i klassen kroppen selv er ikke ideelt (logging er et eksempel - hvis du vil logge alle får Java vil at du skal skrive en hel haug med getters og holde dem synkronisert men AspectJ gir deg en one-liner).

Spørsmålet om IDE er en rød-sild. Det er ikke så mye å skrive som det er lesing og visuell forurensning som oppstår fra get / sett.

Merknader synes ligner aspektet orientert programmering ved første øyekast, men de krever at du uttømmende nummerere pointcuts ved å feste merknader, i motsetning til en kortfattet wild-card-lignende pointcut spesifikasjon i AspectJ.

Jeg håper bevissthet AspectJ hindrer folk fra tidlig bosetting på dynamiske språk.

Svarte 19/12/2011 kl. 19:02
kilden bruker

stemmer
0

Som med de fleste ting, det er den generelle regelen, og da er det spesifikke omstendigheter. Hvis du gjør en lukket, fanget programmet slik at du vet hvordan et gitt objekt kommer til å bli brukt, så kan du trene mer frihet til å favorisere synlighet og / eller effektivitet. Hvis du utvikler en klasse som skal brukes offentlig av andre utenfor din kontroll, deretter helle mot getter / setter modell. Som med alle ting, bare bruk sunn fornuft. Det er ofte greit å gjøre en innledende runde med publikum og deretter endre dem til getter / settere senere.

Svarte 25/04/2010 kl. 04:13
kilden bruker

stemmer
0

En gang Jeg bruker en slik klasse, da jeg må returnere flere verdier fra en metode. Selvfølgelig er slikt objekt kortvarig og med svært begrenset sikt, så det burde være OK.

Svarte 23/11/2008 kl. 18:43
kilden bruker

stemmer
0

Du kan lage en enkel klasse med offentlige felt og ingen metoder i Java, men det er fortsatt en klasse og er fortsatt håndteres syntaktisk og i form av minnetildeling akkurat som en klasse. Det er ingen måte å virkelig reprodusere structs i Java.

Svarte 15/10/2008 kl. 04:35
kilden bruker

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