Подтвердить что ты не робот

Являются ли инициализаторы объектов стиля С# доступными в Java

Как этот? 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"
    }
};
4b9b3361

Ответ 1

Собственно, есть!

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

или даже:

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

Это называется инициализацией двойной скобки. Однако я бы избегал этой идиомы, поскольку она имеет некоторые неожиданные побочные эффекты, например. этот синтаксис фактически создает анонимный внутренний класс Person$1 и Address$.

См. также

Ответ 2

Другие указали инициализаторы "двойной скобки", которые, как мне кажется, следует избегать - это не то, наследование, и оно будет работать только так, как показано, когда поля будут непосредственно видны для подклассов, что я также спорить. На самом деле это не то же самое, что блоки инициализатора С#. Это взломать возможность использования языковой функции, предназначенной для других целей.

Если у вас больше значений, чем вы хотите передать конструктору, вам может потребоваться использовать шаблон построителя:

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

Это также позволяет сделать Person неизменяемым. С другой стороны, для этого требуется класс Person, предназначенный для этой цели. Это хорошо для автогенерированных классов (это шаблон, который Протокол Buffers следует), но раздражает котельную-панель для написанного вручную кода.

Ответ 3

Так как двойные фигурные скобки обычно избегают, вы можете создать очень простой и общий тип класса "строитель", который может задавать свойства несколько идиоматическим способом.

Примечание. Я вызываю класс "Bean" или POJO, чтобы следовать стандарту javabean: Что такое JavaBean именно?. Я бы в первую очередь использовал этот класс для инициализации javabeans.

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;
    }
}

Экземпляры этого класса Bean могут быть созданы из существующего объекта или сгенерированы с использованием Поставщика. Объект хранится в поле object. Метод set - это функция более высокого порядка, которая принимает другую функцию - Consumer<T>. Потребители принимают один аргумент и возвращаются в пустоту. Это создаст побочные эффекты сеттера в новой области.

Метод Bean .set(...) возвращает object, который может использоваться непосредственно в назначении.

Мне нравится этот метод, потому что назначение объекта содержится в закрытых блоках, и мне кажется, что я устанавливаю свойства до создания объекта, а не создавая объект и мутируя его.

Конечный результат - это достойный способ создания новых java-объектов, но это все еще малословно из взлома инициализатора объекта С#.


И вот этот класс:

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

если у вас есть вложенные элементы, возможно, лучше назвать переменные соответственно. Java не позволяет использовать повторное использование $, потому что оно существует во внешней области видимости и нет тени.

    // 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);
            }));
        }));
    });

теперь сравните нормальный код

    // innerRect and dimension are part of the outer block 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);

В качестве альтернативы, вы можете иметь лямбда, которая принимает пустоту и возвращает ваш объект, и отбрасывает его как Supplier<DesiredType> и сразу вызывает .get(). Это не требует отдельного класса, но вам нужно создать Bean самостоятельно.

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

Замечание о практичности: поскольку вы не можете повторно использовать $ при вложенности элементов, этот метод все еще имеет тенденцию быть немногословным. Имена переменных начинают становиться длинными, и любая синтаксическая реклама уходит.

Также можно легко использовать метод set() для создания экземпляра объектов в закрытии. Чтобы правильно использовать, единственная сторона влияет на объект, который вы создаете.

Еще одно замечание: это действительно просто для удовольствия. Никогда не используйте это в производстве.

Ответ 4

Обычно мы используем конструкторы в java для таких случаев

с помощью конструктора в классе, который вы хотите создать объект, который вы можете использовать для передачи аргументов на этапе создания объекта, ex MyData obj1 = new MyData("name",24);

для этого случая вам нужно использовать параметризованный конструктор, соответствующий аргументам, которые вы передаете из основного метода

Ex -

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

Полный код выглядит следующим образом

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);

    }
}

Ответ 5

Если у ваших классов есть конструкторы, которые принимают значения для членов, вы можете создать экземпляр следующим образом:

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

Если нет, вы должны использовать методы setter после создания объекта.

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

Взгляните на официальный официальный учебник по Java.

Ответ 6

Вы можете сделать что-то подобное на Java с блоком инициализации двойной привязки:

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

Однако это просто использование блока инициализации внутри анонимного внутреннего класса, поэтому было бы менее эффективно, чем создание объектов обычным способом.