「java集合类应用」java常用的集合类有哪些

博主:adminadmin 2023-01-12 07:54:07 804

本篇文章给大家谈谈java集合类应用,以及java常用的集合类有哪些对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

多线程中使用Java集合类

Java集合类中 某个线程在 Collection 上进行迭代时 通常不允许另一个线性修改该 Collection 通常在这些情况下 迭代的结果是不确定的 如果检测到这种行为 一些迭代器实现(包括 JRE 提供的所有通用 collection 实现)可能选择抛出此异常 执行该操作的迭代器称为快速失败 迭代器 因为迭代器很快就完全失败 而不会冒着在将来某个时间任意发生不确定行为的风险

因此 当一个线程试图ArrayList的数据的时候 另一个线程对ArrayList在进行迭代的 会出错 抛出ConcurrentModificationException

比如下面的代码

final ListString tickets = new ArrayListString();

for (int i = ; i ; i++) {

   tickets add( ticket NO + i);

}

System out println( start );

for (int i = ; i ; i++) {

   Thread salethread = new Thread() {

       public void run() {

           while (tickets size() ) {

               tickets remove( );

               System out println(Thread currentThread() getId()+ Remove );

           }

       }

   };

   salethread start();

}

System out println( start );

new Thread() {

   public void run() {

       for (String s : tickets) {

System out println(s);

       }

   }

} start();

上述程序运行后 会在某处抛出异常

java util ConcurrentModificationException

at java util ArrayList$Itr checkForComodification(Unknown Source)

at java util ArrayList$Itr next(Unknown Source)

at mytest mytestpkg Tj$ run(Tj java: )

Vector是线程同步的 那么把ArrayList改成Vector是不是就对了呢?

答案是否定的 事实上 无论是ArrayList还是Vector 只要是实现Collection接口的 都要遵循fail fast的检测机制 即在迭代是时候 不能修改集合的元素 一旦发现违法这个规定就会抛出异常

事实上 Vector相对于ArrayList的线程同步 体现在对集合元素是否脏读上 即ArrayList允许脏读 而Vector特殊的机制 不会出现脏读 但是效率会很差

举个例子 一个集合 有 个线程从该集合中删除元素 那么每个元素只可能由一个线程删除掉 不可能会出现一个元素被多个线程删除的情况

比如下面的代码

final ListString tickets = new ArrayListString();

for (int i = ; i ; i++) {

   tickets add( ticket NO + i);

}

System out println( start );

for (int i = ; i ; i++) {

   Thread salethread = new Thread() {

       public void run() {

           while (true) {

if(tickets size() )

System out println(Thread currentThread() getId()+ tickets remove( ));

else

break;

           }

       }

   };

   salethread start();

}

for循环构造 个线程删除同一个集合中的数据 理论上只能删除 次 但是运行完发现 输出的删除次数 次 其中很多数据都是被多个线程删除 比如下面的输出片段

ticket NO

ticket NO

ticket NO

ticket NO

ticket NO

ticket NO

ticket NO

ticket NO

ticket NO

ticket NO

ticket NO

可以看到 都被多个线程删除 这事实上就是出现了脏读 解决的办法就是加锁 使得同一时刻只有 个线程对ArrayList做操作

修改代码 synchronized关键字 让得到锁对象的线程才能运行 这样确保同一时刻只有一个线程操作集合

final ListString tickets = new ArrayListString();

for (int i = ; i ; i++) {

   tickets add( ticket NO + i);

}

System out println( start );

final Object lock=new Object();

for (int i = ; i ; i++) {

   Thread salethread = new Thread() {

       public void run() {

           while (true) {

               synchronized(lock)

               {

                 if(tickets size() )

                   System out println(Thread currentThread() getId()+ tickets remove( ));

                 else

                    break;

               }

           }

       }

   };

   salethread start();

}

这样得到的结果就是准确的了

当然 不使用synchronized关键字 而直接使用vector或者Collections synchronizedList 也是同样效果

final ListString tickets =java util Collections synchronizedList(new ArrayListString());

final ListString tickets =new VectorString();

lishixinzhi/Article/program/Java/gj/201311/27405

Java集合有什么用?

当你事先不知道要存放数据的个数,或者你需要一种比数组下标存取机制更灵活的方法时,你就需要用到集合类。

理解集合类

集合类存放于java.util包中。

集合类存放的都是对象的引用,而非对象本身,出于表达上的便利,我们称集合中的对象就是指集合中对象的引用(reference)。

集合类型主要有3种:set(集)、list(列表)和map(映射)。

Java泛型集合的应用和方法

泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。

可以在集合框架(Collection framework)中看到泛型的动机。例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象。

因为 Map.get() 被定义为返回 Object,所以一般必须将 Map.get() 的结果强制类型转换为期望的类型,如下面的代码所示:

Map m = new HashMap();

m.put("key", "blarg");

String s = (String) m.get("key");

要让程序通过编译,必须将 get() 的结果强制类型转换为 String,并且希望结果真的是一个 String。但是有可能某人已经在该映射中保存了不是 String 的东西,这样的话,上面的代码将会抛出 ClassCastException。

理想情况下,您可能会得出这样一个观点,即 m 是一个 Map,它将 String 键映射到 String 值。这可以让您消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。

泛型的好处

Java 语言中引入泛型是一个较大的功能增强。不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了。这带来了很多好处:

类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。

Java 程序中的一种流行技术是定义这样的集合,即它的元素或键是公共类型的,比如“String 列表”或者“String 到 String 的映射”。通过在变量声明中捕获这一附加的类型信息,泛型允许编译器实施这些附加的类型约束。类型错误现在就可以在编译时被捕获了,而不是在运行时当作 ClassCastException 展示出来。将类型检查从运行时挪到编译时有助于您更容易找到错误,并可提高程序的可靠性。

消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。

尽管减少强制类型转换可以降低使用泛型类的代码的罗嗦程度,但是声明泛型变量会带来相应的罗嗦。比较下面两个代码例子。

该代码不使用泛型:

List li = new ArrayList();

li.put(new Integer(3));

Integer i = (Integer) li.get(0);

该代码使用泛型:

ListInteger li = new ArrayListInteger();

li.put(new Integer(3));

Integer i = li.get(0);

在简单的程序中使用一次泛型变量不会降低罗嗦程度。但是对于多次使用泛型变量的大型程序来说,则可以累积起来降低罗嗦程度。

潜在的性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。

由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。

泛型用法的例子

泛型的许多最佳例子都来自集合框架,因为泛型让您在保存在集合中的元素上指定类型约束。考虑这个使用 Map 类的例子,其中涉及一定程度的优化,即 Map.get() 返回的结果将确实是一个 String:

Map m = new HashMap();

m.put("key", "blarg");

String s = (String) m.get("key");

如果有人已经在映射中放置了不是 String 的其他东西,上面的代码将会抛出 ClassCastException。泛型允许您表达这样的类型约束,即 m 是一个将 String 键映射到 String 值的 Map。这可以消除代码中的强制类型转换,同时获得一个附加的类型检查层,这个检查层可以防止有人将错误类型的键或值保存在集合中。

下面的代码示例展示了 JDK 5.0 中集合框架中的 Map 接口的定义的一部分:

public interface MapK, V {

public void put(K key, V value);

public V get(K key);

}

注意该接口的两个附加物:

类型参数 K 和 V 在类级别的规格说明,表示在声明一个 Map 类型的变量时指定的类型的占位符。

在 get()、put() 和其他方法的方法签名中使用的 K 和 V。

为了赢得使用泛型的好处,必须在定义或实例化 Map 类型的变量时为 K 和 V 提供具体的值。以一种相对直观的方式做这件事:

MapString, String m = new HashMapString, String();

m.put("key", "blarg");

String s = m.get("key");

当使用 Map 的泛型化版本时,您不再需要将 Map.get() 的结果强制类型转换为 String,因为编译器知道 get() 将返回一个 String。

在使用泛型的版本中并没有减少键盘录入;实际上,比使用强制类型转换的版本需要做更多键入。使用泛型只是带来了附加的类型安全。因为编译器知道关于您将放进 Map 中的键和值的类型的更多信息,所以类型检查从执行时挪到了编译时,这会提高可靠性并加快开发速度。

向后兼容

在 Java 语言中引入泛型的一个重要目标就是维护向后兼容。尽管 JDK 5.0 的标准类库中的许多类,比如集合框架,都已经泛型化了,但是使用集合类(比如 HashMap 和 ArrayList)的现有代码将继续不加修改地在 JDK 5.0 中工作。当然,没有利用泛型的现有代码将不会赢得泛型的类型安全好处。

二 泛型基础

类型参数

在定义泛型类或声明泛型类的变量时,使用尖括号来指定形式类型参数。形式类型参数与实际类型参数之间的关系类似于形式方法参数与实际方法参数之间的关系,只是类型参数表示类型,而不是表示值。

泛型类中的类型参数几乎可以用于任何可以使用类名的地方。例如,下面是 java.util.Map 接口的定义的摘录:

public interface MapK, V {

public void put(K key, V value);

public V get(K key);

}

Map 接口是由两个类型参数化的,这两个类型是键类型 K 和值类型 V。(不使用泛型)将会接受或返回 Object 的方法现在在它们的方法签名中使用 K 或 V,指示附加的类型约束位于 Map 的规格说明之下。

当声明或者实例化一个泛型的对象时,必须指定类型参数的值:

MapString, String map = new HashMapString, String();

注意,在本例中,必须指定两次类型参数。一次是在声明变量 map 的类型时,另一次是在选择 HashMap 类的参数化以便可以实例化正确类型的一个实例时。

编译器在遇到一个 MapString, String 类型的变量时,知道 K 和 V 现在被绑定为 String,因此它知道在这样的变量上调用 Map.get() 将会得到 String 类型。

除了异常类型、枚举或匿名内部类以外,任何类都可以具有类型参数。

命名类型参数

推荐的命名约定是使用大写的单个字母名称作为类型参数。这与 C++ 约定有所不同(参阅 附录 A:与 C++ 模板的比较),并反映了大多数泛型类将具有少量类型参数的假定。对于常见的泛型模式,推荐的名称是:

K —— 键,比如映射的键。

V —— 值,比如 List 和 Set 的内容,或者 Map 中的值。

E —— 异常类。

T —— 泛型。

泛型不是协变的

关于泛型的混淆,一个常见的来源就是假设它们像数组一样是协变的。其实它们不是协变的。ListObject 不是 ListString 的父类型。

如果 A 扩展 B,那么 A 的数组也是 B 的数组,并且完全可以在需要 B[] 的地方使用 A[]:

Integer[] intArray = new Integer[10];

Number[] numberArray = intArray;

上面的代码是有效的,因为一个 Integer 是 一个 Number,因而一个 In。

java中,集合类有什么作用??

存储对象用的,例如 你要 打印出 今天 10点 访问你服务器所有人的 ip 用户名 密码 等信息 那么 用户 肯定是一个对象 你就要定义一个集合 每当有一个访问你就把 这个对象放在你的集合里面 当过了10点之后遍历这个集合取出来就行了 集合的数据放在内存中 。说白了他就是用来存储临时数据的。

关于java集合类应用和java常用的集合类有哪些的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。