gpt4 book ai didi

Java怎样创建集合才能避免造成内存泄漏你了解吗

转载 作者:qq735679552 更新时间:2022-09-28 22:32:09 31 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章Java怎样创建集合才能避免造成内存泄漏你了解吗由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

由于Java语言的集合框架中(collections, 如list, map, set等)没有提供任何简便的语法结构,这使得在建立常量集合时的工作非常繁索。每次建立时我们都要做:

1、定义一个空的集合类变量 。

2、向这个结合类中逐一添加元素 。

3、将集合做为参数传递给方法 。

例如,要将一个Set变量传给一个方法:

?
1
2
3
4
5
6
Set users = new HashSet();
users.add( "Hollis" );
users.add( "hollis" );
users.add( "HollisChuang" );
users.add( "hollis666" );
transferUsers(users);

这样的写法稍微有些复杂,有没有简洁的方式呢?

双括号语法初始化集合

其实有一个比较简洁的方式,那就是双括号语法(double-brace syntax)建立并初始化一个新的集合:

?
1
2
3
4
5
6
7
8
9
10
public class DoubleBraceTest {
     public static void main(String[] args) {
         Set users = new HashSet() {{
             add( "Hollis" );
             add( "hollis" );
             add( "HollisChuang" );
             add( "hollis666" );
         }};
     }
}

同理,创建并初始化一个HashMap的语法如下:

?
1
2
3
4
5
Map<String,String> users = new HashMap<>() {{
     put( "Hollis" , "Hollis" );
     put( "hollis" , "hollis" );
     put( "HollisChuang" , "HollisChuang" );
}};

不只是Set、Map,jdk中的集合类都可以用这种方式创建并初始化.

当我们使用这种双括号语法初始化集合类的时候,在对Java文件进行编译时,可以发现一个奇怪的现象,使用javac对DoubleBraceTest进行编译:

?
1
javac DoubleBraceTest.java

我们会发现,得到两个class文件:

?
1
2
DoubleBraceTest. class
DoubleBraceTest$ 1 . class

有经验的朋友可能一看到这两个文件就会知道,这里面一定用到了匿名内部类.

没错,使用这个双括号初始化的效果是创建匿名内部类。创建的类有一个隐式的this指针指向外部类.

不建议使用这种形式

首先,使用这种形式创建并初始化集合会导致很多内部类被创建。因为每次使用双大括号初始化时,都会生成一个新类。如这个例子

?
1
2
3
4
5
6
7
8
9
10
11
12
Map hollis = new HashMap(){{
     put( "firstName" , "Hollis" );
     put( "lastName" , "Chuang" );
     put( "contacts" , new HashMap(){{
         put( "0" , new HashMap(){{
             put( "blogs" , "http://www.hollischuang.com" );
         }});
         put( "1" , new HashMap(){{
             put( "wechat" , "hollischuang" );
         }});
     }});
}};

这会使得很多内部类被创建出来:

?
1
2
3
4
5
DoubleBraceTest$ 1 $ 1 $ 1 . class
DoubleBraceTest$ 1 $ 1 $ 2 . class
DoubleBraceTest$ 1 $ 1 . class
DoubleBraceTest$ 1 . class
DoubleBraceTest. class

这些内部类被创建出来,是需要被类加载器加载的,这就带来了一些额外的开销.

如果您使用上面的代码在一个方法中创建并初始化一个map,并从方法返回该map,那么该方法的调用者可能会毫不知情地持有一个无法进行垃圾收集的资源.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public Map getMap() {
     Map hollis = new HashMap(){{
         put( "firstName" , "Hollis" );
         put( "lastName" , "Chuang" );
         put( "contacts" , new HashMap(){{
             put( "0" , new HashMap(){{
                 put( "blogs" , "http://www.hollischuang.com" );
             }});
             put( "1" , new HashMap(){{
                 put( "wechat" , "hollischuang" );
             }});
         }});
     }};
 
     return hollis;
}

我们尝试通过调用getMap得到这样一个通过双括号初始化出来的map 。

?
1
2
3
4
5
6
public class DoubleBraceTest {
     public static void main(String[] args) {
         DoubleBraceTest doubleBraceTest = new DoubleBraceTest();
         Map map = doubleBraceTest.getMap();
     }
}

返回的Map现在将包含一个对DoubleBraceTest的实例的引用。读者可以尝试这通过debug或者以下方式确认这一事实.

?
1
2
3
Field field = map.getClass().getDeclaredField( "this$0" );
field.setAccessible( true );
System.out.println(field.get(map).getClass());

替代方案

很多人使用双括号初始化集合,主要是因为他比较方便,可以在定义集合的同时对他进行初始化.

但其实,目前已经有很多方案可以做这个事情了,不需要再使用这种存在风险的方案.

使用Arrays工具类

当我们想要初始化一个List的时候,可以借助Arrays类,Arrays中提供了asList可以把一个数组转换成List:

?
1
List<String> list2 = Arrays.asList( "hollis " , "Hollis" , "HollisChuang" );

但是需要注意的是,asList 得到的只是一个 Arrays 的内部类,是一个原来数组的视图 List,因此如果对它进行增删操作会报错.

使用Stream

Stream是Java中提供的新特性,他可以对传入流内部的元素进行筛选、排序、聚合等中间操作(intermediate operate),最后由最终操作(terminal operation)得到前面处理的结果.

我们可以借助Stream来初始化集合:

?
1
List<String> list1 = Stream.of( "hollis" , "Hollis" , "HollisChuang" ).collect(Collectors.toList());

使用第三方工具类

很多第三方的集合工具类可以实现这个功能,如Guava等:

?
1
2
ImmutableMap.of( "k1" , "v1" , "k2" , "v2" );
ImmutableList.of( "a" , "b" , "c" , "d" );

关于Guava和其中定义的不可变集合,我们在后面会详细介绍 。

Java 9内置方法

其实在Java 9 中,在List、Map等集合类中已经内置了初始化的方法,如List中包含了12个重载的of方法,就是来做这个事情的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
  * Returns an unmodifiable list containing zero elements.
  *
  * See <a href="#unmodifiable" rel="external nofollow" >Unmodifiable Lists</a> for details.
  *
  * @param <E> the {@code List}'s element type
  * @return an empty {@code List}
  *
  * @since 9
  */
static <E> List<E> of() {
     return ImmutableCollections.emptyList();
}
 
static <E> List<E> of(E e1) {
     return new ImmutableCollections.List12<>(e1);
}
 
static <E> List<E> of(E... elements) {
     switch (elements.length) { // implicit null check of elements
         case 0 :
             return ImmutableCollections.emptyList();
         case 1 :
             return new ImmutableCollections.List12<>(elements[ 0 ]);
         case 2 :
             return new ImmutableCollections.List12<>(elements[ 0 ], elements[ 1 ]);
         default :
             return new ImmutableCollections.ListN<>(elements);
     }
}

到此这篇关于Java怎样创建集合才能避免造成内存泄漏你了解吗的文章就介绍到这了,更多相关Java 集合内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。

原文链接:https://blog.csdn.net/hollis_chuang/article/details/120506216 。

最后此篇关于Java怎样创建集合才能避免造成内存泄漏你了解吗的文章就讲到这里了,如果你想了解更多关于Java怎样创建集合才能避免造成内存泄漏你了解吗的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com