Являются ли инициализаторы объектов стиля С# доступными в 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"
}
};
Ответы
Ответ 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";
}};
}};
Однако это просто использование блока инициализации внутри анонимного внутреннего класса, поэтому было бы менее эффективно, чем создание объектов обычным способом.