Are C# style object initializers available in Java
like this one?http:/ / / / / weblogs.asp.net dwahlin馆2007年09 / / / c-3-0-features-object-initializers.aspx 09P></
1 2 3 4 5 6 7 8 9 10 | Person p = new Person() { FirstName ="John", LastName ="Doe", Address = new Address() { Street ="1234 St.", City ="Phoenix" } }; |
事实上,有!
1 2 3 4 5 6 7 8 9 10 | Person p = new Person() {{ setFirstName("John"); setLastName("Doe"); setAddress(new Address() {{ setStreet("1234 St."); setCity("Phoenix"); }}); }}; |
甚至:
1 2 3 4 5 6 7 8 9 10 | Person p = new Person() {{ firstName ="John"; lastName ="Doe"; address = new Address() {{ street ="1234 St."; city ="Phoenix"; }}); }}; |
这称为双括号初始化。但是,我会避免使用这个成语,因为它有一些意想不到的副作用,例如,这个语法实际上创建了一个匿名的内部类
- Java中双括号初始化是什么?
- 双括号初始化
其他人展示了"双大括号"初始值设定项,我认为应该避免这一点——这不是继承的目的,它只会在字段对子类直接可见时才能工作,我也反对这一点。它与C初始值设定项块实际上不同。利用为其他目的设计的语言特性是一种黑客行为。
如果您的值超过了要传递给构造函数的数量,那么您可能需要考虑使用构建器模式:
1 2 3 4 5 6 7 8 | Person person = Person.newBuilder() .setFirstName("John") .setLastName("Doe") .setAddress(Address.newBuilder() .setStreet("...") .setCity("Phoenix") .build()) .build(); |
这还允许您使
由于通常避免使用双大括号,因此可以创建一个非常简单和通用的"builder"类,该类可以以某种惯用方式设置属性。
注意:我调用类"bean"或pojo来遵循JavaBean标准:JavaBean到底是什么?.I主要使用这个类初始化JavaBeans。
爪哇
1 2 3 4 5 6 7 8 9 | 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; } } |
这个be an类的实例可以从现有对象创建,也可以使用供应商生成。对象存储在字段
be an
我喜欢这个方法,因为对象的赋值包含在封闭的块中,感觉就像是在创建对象之前设置属性,而不是创建对象并改变它。
最终的结果是创建新Java对象的一种体面的方法,但从C对象初始化器的叹息来看,这仍然有点冗长。
下面是正在使用的类:
1 2 3 4 5 6 7 |
如果您有嵌套项,那么最好对变量进行相应的命名。Java不允许使用重用EDCOX1(4),因为它存在于外部范围内并且没有阴影。
1 2 3 4 5 6 7 8 9 10 11 | // 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); })); })); }); |
现在比较正常代码
1 2 3 4 5 6 7 8 9 | // 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); |
或者,您可以有一个lambda,它接收空的并返回对象,并将其转换为
1 2 3 4 5 |
关于实用性的一个注意事项:因为嵌套元素时不能重用
也很容易滥用set()方法在闭包中创建对象的实例。要正确使用,唯一的副作用应该是创建的对象。
另一个注意事项:这真的只是为了好玩。不要在生产中使用这个。
通常我们使用Java中的构造函数来处理这种情况。
通过在要创建对象的类中使用构造函数,可以使用该构造函数在对象创建步骤传递参数,除
对于这种情况,必须使用与从主方法传递的参数匹配的参数化构造函数。
前-
1 2 3 4 |
完整代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 |
如果类具有为成员获取值的构造函数,则可以这样创建实例:
1 | Person p = new Person("John","Doe", new Address("1234 St.","Phoenix")); |
如果不是,则必须在创建对象后使用setter方法。
1 2 3 | Person p = new Person(); p.setFirstName("John"); // and so on |
看看官方的Java教程。
您可以在Java中用双括号初始化块进行类似的操作:
1 2 3 4 5 6 7 8 | Person p = new Person() {{ firstName ="John"; lastName ="Doe"; address = new Address() {{ street ="1234 St."; city ="Phoenix"; }}; }}; |
但是,这只是在匿名内部类中使用初始化块,因此比以正常方式构造对象的效率要低。