Sono C# stile gli inizializzatori di oggetti disponibili in Java

Come questo? http://weblogs.asp.net/dwahlin/archive/2007/09/09/c-3-0-features-object-initializers.aspx

Person p = new Person()
{
    FirstName = "John",
    LastName = "Doe",
    Address = new Address()
    {
        Street = "1234 St.",
        City = "Phoenix"
    }
};
InformationsquelleAutor Hao | 2012-02-02

 

6 Replies
  1. 64

    In realtà, non c’è!

    Person p = new Person()
    {{
        setFirstName("John");
        setLastName("Doe");
        setAddress(new Address()
        {{
            setStreet("1234 St.");
            setCity("Phoenix");
        }});
    }};

    o anche:

    Person p = new Person()
    {{
        firstName = "John";
        lastName = "Doe";
        address = new Address()
        {{
            street = "1234 St.";
            city = "Phoenix";
        }});
    }};

    Questo è chiamato doppia parentesi graffa di inizializzazione. Tuttavia vorrei evitare questo idioma, come ha fatto alcuni inaspettati effetti collaterali, ad esempio, la sintassi, in realtà crea un anonimo classe interna Person$1 e Address$.

    Vedere anche

    • Naturalmente, che richiede anche che i campi sono protetti solo. Mentre le due forme look simili in superficie, in realtà sono molto diversi.
    • a cosa ti riferisci?
    • Voglio dire che se i campi sono privati (come in genere la seconda forma certamente non funzionerà, come sta cercando di impostare i campi da una sottoclasse.
    • effetto collaterale? anonimo? è leggibile da sospensione? ho impostato il mio oggetto e pass è variabile, ma per altri collegamenti relazionali, ho passato una classe appena creata, che ha solo l’Id dell’oggetto… beh, io non sono sicuro che anche se di sospensione accettare come se generare un reale classe, non anonimo, ma che è quello che faccio in C# con EF(Entity Framework)
    • io non l’ho provato in tutti i modi, ma un po ‘ dove ho ottenuto l’errore di prima. ma io la uso con i metodi getter/setter è che ok? new Work(){{ setTime(work.getTime()); setPerson(new Person(){{ setId(work.getPersonId())}} ) }}
    • Beh, non vorrei fare personalmente, come stai creando una nuova classe di ogni codice posizione in cui si esegue questa operazione, e la doppia parentesi brutta, ma a me sì, funziona… Come se lavorerà con Hibernate ecc, non ho idea. Ma è necessario capire quanto è diverso questo è il codice C#.
    • beh, perché se io voglio dire che il nuovo lavoro(), e quindi impostare tutte le proprietà, e quindi prima che creo persona e fare lo stesso, e anche altre classi che i miei sono inoltre inclusi, è diventato molto massiccia codice che non è comprensibile a tutti. ma forse avete idea migliore. BTW, la comunità java che ammiro conosce un sacco di design pattern e può pensare a molte cose, che il nostro C# community non sono in grado, perché noi naturalmente non hai bisogno di molto, come dice il nome, per impostazione predefinita, è più nitida verso java.
    • sembrano non era :'( java.lang.IllegalArgumentException: Unknown entity: hassan.personnel.managment.rests.WorksController$1

  2. 28

    Altri hanno mostrato che il “doppio brace” gli inizializzatori, e credo che dovrebbero essere evitati in questo non è ciò che l’ereditarietà è, e sarà solo il lavoro, come mostrato quando i campi sono visibili direttamente alle sottoclassi, che avevo anche argomentare contro. Non è proprio la stessa cosa come C# inizializzatore di blocchi. Si tratta di un hack per sfruttare una caratteristica del linguaggio progettato per altri scopi.

    Se si hanno più valori che si desidera passare a un costruttore, si potrebbe desiderare di prendere in considerazione utilizzando il generatore di pattern:

    Person person = Person.newBuilder()
        .setFirstName("John")
        .setLastName("Doe")
        .setAddress(Address.newBuilder()
            .setStreet("...")
            .setCity("Phoenix")
            .build())
        .build();

    Questo permette anche di effettuare Person immutabile. D’altra parte, questa operazione richiede il Person classe per essere progettato per questo scopo. Che bello per generare automaticamente le classi (è il modello che Buffer Di Protocollo segue) ma è fastidioso caldaia-piastra per scritti manualmente il codice.

    • Questo suona strano, ma perché non solo la catena la set funzioni tornando this? Poi si potrebbe scrivere new Person().setFirstName("John").setLastName("Skeet").
    • Si potrebbe fare, ma sarebbe un po ‘ strano. (Inoltre, non funziona con l’immutabilità, naturalmente).
    • Che sarebbe qualcosa di simile a quello che C# chiama una “interfaccia fluida”, penso. Sono d’accordo sarebbe strano, e un generatore più senso. Grazie per il feedback.
    • C’è un altro inconveniente per il ritorno di questa’ tecnica – setter sulla base di classi di restituire un oggetto di tipo base, rendendo setter in sottoclassi inaccessibile senza fusione. È possibile ottenere intorno a questo impostando le proprietà di sottoclassi di prima, ma di tanto in tanto l’ordine è importante. Questo non dovrebbe importa con codice ben scritto, ma che ovviamente non è sempre il caso.
    • Curioso di sapere che cosa il vostro PersonBuilder sarebbe simile. Sono le proprietà di un’immagine speculare di Person? C’è qualche modo questo potrebbe essere fatto senza violare LAVAGGIO principio?
    • Sì, sarebbe guardare qualcosa come Persona, ma con setter così come getter. Non c’è una vera logica essere ripetuto se.
    • Mi consiglia di avere Person.newBuilder() restituire un oggetto di una classe interna Person.Builder che contiene un soggetto privato, oggetto e, essendo una classe interna, completo di accedere ai suoi campi e quindi si evita la necessità di ripetere il set di campi?

  3. 4

    Normalmente usiamo costruttori in java per tali casi

    utilizzando un costruttore della classe che si desidera creare un oggetto che è possibile utilizzare che per passare gli argomenti in oggetto la creazione di passaggio,
    ex- MyData obj1 = new MyData("name",24);

    per questo caso è necessario utilizzare costruttore con parametri corrispondenti agli argomenti si passa dal metodo main

    Ex-

    MyData(String name, int age){
        this.name=name;
        this.age=age;
        }

    Il codice completo come segue

    class MyData{
    public String name;
    public int age;
    
     MyData(String name, int age){
        this.name=name;
        this.age=age;
        }
         public static void main(String args[]){
            MyData obj1 = new MyData("name",24);
    
        }
    }
    • essi, in c# :)), anche usarli, ma supponiamo di avere 10+ campi… Ora confrontare la leggibilità del vecchio stile vs C#: nuovo MyData(new BigDecimal(24), nuova…, …); nuovo MyData{fiscale=new BigDecimal(24), importo=…, sconto=…)
  4. 4

    Dalla doppia parentesi graffe sono generalmente evitato, è possibile creare un semplice e generico sorta di “generatore” classe in grado di impostare le proprietà in un modo un po idiomatiche modo.

    Nota: ho chiamata la classe “a Fagiolo” o POJO a seguire il javabean standard: Che cosa è un JavaBean esattamente?. Vorrei utilizzare principalmente questa classe di init javabeans comunque.

    Bean.java

    public class Bean<T> {
        private T object;
        public Bean(Supplier<T> supplier) { object = supplier.get(); }
        public Bean(T object) { this.object = object; }
        public T set(Consumer<T> setter) {
            setter.accept(object);
            return object;
        }
    }

    Istanze di questa classe Bean può essere creato da un oggetto esistente o generate utilizzando un Fornitore. L’oggetto viene memorizzato nel campo object. Il set è un metodo di ordine superiore a funzione che prende in un’altra funzione–Consumer<T>. I consumatori a prendere in un argomento e restituisce void. Questo creerà il setter effetti collaterali in un nuovo ambito.

    Il Fagiolo .set(...) metodo restituisce object che può essere utilizzato direttamente in un incarico.

    Mi piace questo metodo, poiché l’oggetto dell’incarico sono contenute all’interno di chiuso blocchi e sente come sto impostando le proprietà prima che l’oggetto è stato creato, piuttosto che di creazione dell’oggetto e la mutazione è.

    Il risultato finale è già un buon modo per creare nuovi oggetti java, ma questo è ancora un po ‘ prolisso per il C# inizializzatore di oggetto sospiro.


    E qui è la classe in uso:

        //'{}' creates another scope so this function's scope is not "polluted"
        //'$' is used as the identifier simply because it's short
        Rectangle rectangle = new Bean<>(Rectangle::new).set($ -> {
            $.setLocation(0, 0);
            $.setBounds(0, 0, 0, 0);
            //set other properties
        });

    se si dispone di elementi nidificati, potrebbe essere meglio per nome le variabili di conseguenza. Java non consente di utilizzare il riutilizzo $ perché esiste in ambito esterno e non c’è ombra.

        //this time we pass in new Rectangle() instead of a Supplier
        Rectangle rectangle3 = new Bean<>(new Rectangle()).set(rect-> {
            rect.setLocation(-50, -20);
            //setBounds overloads to take in another Rectangle
            rect.setBounds(new Bean<>(Rectangle::new).set(innerRect -> {
                innerRect.setLocation(0, 0);
                innerRect.setSize(new Bean<>(Dimension::new).set(dim -> {
                    dim.setSize(640, 480);
                }));
            }));
        });

    ora confrontare il normale codice

        //innerRect and dimension are part of the outer block's scope (bad)
        Rectangle rectangle4 = new Rectangle();
        rectangle4.setLocation(-50, -20);
        Rectangle innerRect = new Rectangle();
        innerRect.setLocation(0, 0);
        Dimension dimension = new Dimension();
        dimension.setSize(640, 480);
        innerRect.setSize(dimension);
        rectangle4.setBounds(innerRect);

    In alternativa, si potrebbe avere una lambda che prende nel vuoto e restituisce l’oggetto e lanciarla come una Supplier<DesiredType> e invocare .get(). Questo non richiede una classe separata, ma è necessario creare bean te.

        Rectangle rectangle5 = ((Supplier<Rectangle>)() -> {
            Rectangle rect = new Rectangle();
            rect.setLocation(0, 0);
            return rect;
        }).get();

    Una nota sulla praticità: Perché non è possibile riutilizzare $ quando elementi di raggruppamento, tale metodo tende ad essere un po ‘ prolisso. I nomi delle variabili iniziare a lunghe e qualsiasi sintassi ricorso va via.

    Può anche essere facile da abuso il metodo set() per creare l’istanza di oggetti all’interno della chiusura. Per utilizzare correttamente, l’unico lato colpisce dovrebbe essere l’oggetto che si sta creando.

    Una nota di più: questo è davvero solo per divertimento. Non usare mai questo in produzione.

  5. 2

    Se le classi sono costruttori che assume valori per i soci, è possibile creare l’istanza di simile a questo:

    Person p = new Person("John", "Doe", new Address("1234 St.", "Phoenix"));

    Se non, è necessario utilizzare i metodi setter, dopo la creazione dell’oggetto.

    Person p = new Person();
    p.setFirstName("John");
    //and so on

    Dare un’occhiata al ufficiale Java tutorial.

  6. 1

    Si può fare qualcosa di simile in Java con una doppia parentesi graffa di blocco di inizializzazione:

    Person p = new Person() {{
        firstName = "John";
        lastName = "Doe";
        address = new Address() {{
            street = "1234 St.";
            city = "Phoenix";
        }};
    }};

    Tuttavia questo è solo utilizzo di un blocco di inizializzazione all’interno di un anonimo classe interna così sarebbe meno efficiente di costruire oggetti in modo normale.

Lascia un commento