您好我正在尝试整理一些代码,我偶然发现了一些双括号。我意识到这是一种罪,我应该解决这个问题。但是,我不知道从哪里开始。有人可以帮忙吗?
private SelectItem notifyTypeItem = new SelectItem();
notifyTypeItem.setTitle("Default Notification");
notifyTypeItem.setWidth("100%");
notifyTypeItem.setValueMap(new LinkedHashMap<String, String>() {{
put("0", "None");
put("1", "Subtle");
put("2", "Intrusive");
}}
);
答案 0 :(得分:2)
要了解如何修复它,您应该首先了解它正在做什么。为此,您需要了解两件事:
TL;如何修复它的DR只是将那些put
调用和初始化从setter中分离出来:
Map<String, String> valueMap = new LinkedHashMap<String, String>();
valueMap.put("0", "None");
valueMap.put("1", "Subtle");
valueMap.put("2", "Intrusive");
notifyTypeItem.setValueMap(valueMap);
继续阅读,了解发生了什么以及为什么它可能是一种不好的方法。
匿名类通常只是一个没有名称的类。例如,您可以创建类似Runnable
的接口的匿名实例:
Runnable r = new Runnable() {
@Override
public void run() {
// Do something
}
};
r.run(); // Does that something
同样,您也可以创建抽象类和具体类的匿名实例。例如,创建ThreadLocal
:
private static ThreadLocal<SimpleDateFormat> localIsoDateFormat = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
}
当您不需要一个完整的专用类来覆盖一个或两个方法时,这非常有用,类似于只使用一个方法创建接口的匿名实例。
实例初始化程序块允许您在构造函数之外执行初始化程序。例如:
public class MyClass {
private final String s;
{
s = "My Class String";
}
public String getS() { return s; }
}
它本质上是构造函数的替身,而且它通常是不必要的,所以你很少看到它。它几乎总是可以移动到构造函数。
你的例子结合了它们。它创建了LinkedHashMap
的匿名子类,然后它也使用了初始化块。格式更正确,您的代码是:
Map<String, String> map = new LinkedHashMap<>() {
{
put("0", "None");
put("1", "Subtle");
put("2", "Intrusive");
}
};
它是LinkedHashMap
的匿名实例,其中包含执行put
调用的实例初始化程序块。
出于同样的原因,您需要be careful creating anonymous classes:对封闭类实例的引用。
匿名类因应用程序中的内存泄漏源而臭名昭着。您的代码似乎位于非static
上下文中。这意味着您创建的匿名LinkedHashMap
子类将隐含引用您的方法所在的类。例如,如果您的方法位于MyClass
:
public class MyClass {
private SelectItem notifyTypeItem = new SelectItem();
public void foo() {
notifyTypeItem.setTitle("Default Notification");
notifyTypeItem.setWidth("100%");
notifyTypeItem.setValueMap(new LinkedHashMap<String, String>() {{
put("0", "None");
put("1", "Subtle");
put("2", "Intrusive");
}}
);
}
}
新创建的LinkedHashMap
子类(MyClass$1
将是&#34;类名&#34;,如果你可以调用它这样的东西)将引用封闭的{{1实例。在某些情况下,这可能没问题。但是,如果您要创建MyClass
并将其传递给其他内容并丢弃notifyTypeItem
实例,那么您将在应用程序中创建内存泄漏。 MyClass
实例将引用MyClass
实例,MyClass$1
将引用SelectItem
实例,因此MyClass$1
实例永远不会被垃圾回收不再引用MyClass
实例。如果SelectItem
除了MyClass
之外还有其他几个引用,那么这只会增加单个SelectItem
实例消耗的总内存,并导致更多的内存泄漏问题。
以下是一些相关链接: