Java集合框架

什么是集合框架?

集合可以看作是一种容器,用来存储对象信息。所有集合类都位于java.util包下,但支持多线程的集合类位于java.util.concurrent包下。

在这里插入图片描述

在这里插入图片描述
Java集合类主要由两个根接口Collection和Map派生出来的,Collection派生出了三个子接口:List、Set、Queue(Java5新增的队列),因此Java集合大致也可分成List、Set、Queue、Map四种接口体系,(注意:Map不是Collection的子接口)。

  • 其中List代表了有序可重复集合,可直接根据元素的索引来访问;Set代表无序不可重复集合,只能根据元素本身来访问;Queue是队列集合;Map代表的是存储key-value对的集合,可根据元素的key来访问value。
  • 上图中淡绿色背景覆盖的是集合体系中常用的实现类,分别是ArrayList、LinkedList、ArrayQueue、HashSet、TreeSet、HashMap、TreeMap等实现类。

List集合

List集合代表一个有序、可重复集合,集合中每个元素都有其对应的顺序索引。List集合默认按照元素的添加顺序设置元素的索引,可以通过索引(类似数组的下标)来访问指定位置的集合元素。

ArrayList

ArrayList是一个动态数组,也是我们最常用的集合,是List类的典型实现。它允许任何符合规则的元素插入甚至包括null。每一个ArrayList都有一个初始容量(10),该容量代表了数组的大小。随着容器中的元素不断增加,容器的大小也会随着增加。在每次向容器中增加元素的同时都会进行容量检查,当快溢出时,就会进行扩容操作。所以如果我们明确所插入元素的多少,最好指定一个初始容量值,避免过多的进行扩容操作而浪费时间、效率。

如下演示ArrayList的用法:

import java.util.ArrayList;

public class ArrayListDemo {
	public static void main(String[] args) {
		//1.生成ArrayList对象
		ArrayList list = new ArrayList();
		//2.向集合中添加元素
		list.add("aabb");
		list.add("abc");
		list.add(1,"aaa");    //在下标为1的位置插入元素aaa,元素abc向后移一位
		list.add("abc");
		System.out.println(list.get(0));
		System.out.println(list.get(1));
		System.out.println(list.get(2));
		//遍历
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}
		//增强for循环遍历
		for(Object obj:list){
			System.out.println(obj);
		}
		int index = list.indexOf("abc"); //indexOf()查找元素的下标
		System.out.println(index); //2
		int lastIndex = list.lastIndexOf("abc");   //lastIndex()元素最后一个下标
		System.out.println(lastIndex);  //3 
		
		list.remove(0);   //移除下标为0的元素,后面的元素依次向前移动
		
		for(Object obj : list ){
			System.out.println(obj);
		}
		
		System.out.println(list.contains("aaa"));  //集合中是否包含aaa
		
		list.set(0,"zhangsan"); //把下标为0的元素改成zhangsan
		
		for(Object obj : list ){
			System.out.println(obj);
		}
	}
}

LinkedList

LinkedList是List接口的另一个实现,除了可以根据索引访问集合元素外,LinkedList还实现了Deque接口,可以当作双端队列来使用,也就是说,既可以当作“栈”使用,又可以当作队列使用。

LinkedList的实现机制与ArrayList的实现机制完全不同,ArrayLiat内部以数组的形式保存集合的元素,所以随机访问集合元素有较好的性能;LinkedList内部以链表的形式保存集合中的元素,所以随机访问集合中的元素性能较差,但在插入删除元素时有较好的性能。

Map集合

Map接口采用键值对Map<K,V>的存储方式,保存具有映射关系的数据,因此,Map集合里保存两组值,一组值用于保存Map里的key,另外一组值用于保存Map里的value,key和value可以是任意引用类型的数据。key值不允许重复,可以为null。如果添加key-value对时Map中已经有重复的key,则新添加的value会覆盖该key原来对应的value。常用实现类有HashMap、LinkedHashMap、TreeMap等。

HashMap与Hashtable

HashMap与Hashtable是Map接口的两个典型实现,它们之间的关系完全类似于ArrayList与Vertor。HashTable是一个古老的Map实现类,它提供的方法比较繁琐,目前基本不用了,HashMap与Hashtable主要存在以下两个典型区别:

  • HashMap是线程不安全,HashTable是线程安全的。

  • HashMap可以使用null值最为key或value;Hashtable不允许使用null值作为key和value,如果把null放进HashTable中,将会发生空指针异常。

为了成功的在HashMap和Hashtable中存储和获取对象,用作key的对象必须实现hashCode()方法和equals()方法。

public class HashMapDemo {

	public static void main(String[] args) {
		HashMap map= new HashMap();
		map.put("zhangsna","1345485454564545");
		map.put("lisi","454545455445");
		map.put("fanchenda", "7898956567");
		String str=(String) map.get("fanchenda");
		System.out.println(str);
		//遍历所有的键
		for (Object key:map.keySet()) {
			System.out.println(key);
		}
		//遍历所有的值
		for (Object vaule:map.values()) {
			System.out.println(vaule);
		}
		//集合的大小
		System.out.println(map.size()); //大小 输出3
		System.out.println(map.containsKey("lisi"));  //containsKey 包含
		for (Object obj:map.entrySet()) {  //键值对形式
			System.out.println(obj);
		}

迭代器Iterator

所有集合接口和类都没有提供相应的遍历方法,而是把遍历交给迭代器Iterator完成。Iterator为集合而生,专门实现集合的遍历。它隐藏了各种集合实现类的内部细节,提供了遍历集合的一编程接口。

Collection接口的iterator()方法返回一个Iterator,然后通过Iterator接口的两个方法即可方便地实现遍历。

  • boolean hasNext():判断是否存在另一个可访问的元素
  • Object next():返回要访问的下一个元素

在使用迭代器的时候,一定不能改变集合的长度(增加或者删除),每次迭代器都会判断底层的记忆长度是否与实际长度相等,如果不相等,则会出现一个并发修改异常,ConcarrentModifiCationException,可以在集合中修改元素,但不能改变长度。

import java.util.HashMap;
import java.util.Iterator;

public class HashMapDemo {

	public static void main(String[] args) {
		HashMap map= new HashMap();
		map.put("zhangsna","1345485454564545");
		map.put("lisi","454545455445");
		map.put("fanchenda", "7898956567");
		//迭代方式
		Iterator it=map.keySet().iterator();  //迭代器
		while (it.hasNext()) {
			System.out.println(it.next());
		}
		System.out.println();
		Iterator ut=map.values().iterator();
		while (ut.hasNext()) {
			System.out.println(ut.next());
		}
	}		
	}

泛型集合

所谓泛型就是允许在定义类、接口时指定类型形参,这个类型形参将在声明变量、创建对象时确定。增加了泛型支持后的集合,完全可以记住集合

中元素的类型,并可以在编译时检查集合中元素的类型。即解决一些安全问题,同时还可以让代码变得更加简洁。

创建一个只存放字符串的对象,代码如下:

import java.util.ArrayList;
import java.util.List;

public class GenericDemo {
public static void main(String[] args) {
    //创建一个只能保存字符串的ArrayList集合
    List<String> strList=new ArrayList<String>();
    //如果存放其他类型的对象时会出现编译错误
    strList.add("chaofn");
    System.out.println(strList);
}
}

使用泛型的好处:

1、将运行时期出现的ClassCastExcpetion , 转移到了编译时期。方便于程序员解决问题,让运行时期问题减少。

2、避免了强制转换的麻烦。

如下代码可以解释这一点:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

 class StringDemo {
    
    String name;
    public StringDemo(String name){
        this.name=name;
    
}
    
}
	public class GenericDemo {    
public static void main(String[] args) {
    //创建一个只能保存字符串的ArrayList集合
     List<String> ls=new ArrayList<String>();
    //如果存放其他类型的对象时会出现编译错误
    ls.add(new StringDemo("chaofn01"));
    ls.add(new StringDemo("chaofn02"));
    ls.add(new StringDemo("chaofn03"));
    ls.add(new StringDemo("chaofn04"));
    ls.add(1000);
    MyIterator(ls);   
}

public static void MyIterator(List ls){
    Iterator it=ls.iterator();
    while(it.hasNext()){
        StringDemo s=(StringDemo) it.next();
        System.out.println(s.name);
    }
}
}

运行结果:

chaofn01
chaofn02
Exception in thread"main"java.lang.ClassCastException:java.lang.Integercannot be cast tocom.csu.test1.StringDemo at com.csu.test1.GenericDemo.MyIterator(GenericDemo.java:34)at com.csu.test1.GenericDemo.main(GenericDemo.java:27) chaofn03 chaofn04

在调用MyIterator(List ls) 方法时会发生ClassCastException 异常。而且在编译时是不会有任何提示,只有运行时会出现,所以使的程序存在安全隐患。

如果使用泛型则会在编译时提示错误,而且在遍历时不需要强制转换。如:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

 class StringDemo {
    
    String name;
    public StringDemo(String name){
        this.name=name;
    
}
    
}
public class GenericDemo {
    
public static void main(String[] args) {
    //创建一个只能保存字符串的ArrayList集合
     List<StringDemo> ls=new ArrayList<StringDemo>();
    //如果存放其他类型的对象时会出现编译错误
    ls.add(new StringDemo("chaofn01"));
    ls.add(new StringDemo("chaofn02"));
    ls.add(new StringDemo("chaofn03"));
    ls.add(new StringDemo("chaofn04"));
    //下面一行代码在编译时会出错
    //ls.add(1000);
    MyIterator(ls);
    
    
}
public static void MyIterator(List<StringDemo> ls){
    Iterator<StringDemo> it=ls.iterator();
    while(it.hasNext()){
        //不需要强制转化成StringDemo
        StringDemo s= it.next();
        System.out.println(s.name);
    }
}
}

泛型方法

你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

下面是定义泛型方法的规则:

  1. 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的)。

  2. 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。

  3. 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。

  4. 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。

实例:

public class GenericMethodTest
{
   // 泛型方法 printArray                         
   public static < E > void printArray( E[] inputArray )
   {
      // 输出数组元素            
         for ( E element : inputArray ){        
            System.out.printf( "%s ", element );
         }
         System.out.println();
    }
 
    public static void main( String args[] )
    {
        // 创建不同类型数组: Integer, Double 和 Character
        Integer[] intArray = { 1, 2, 3, 4, 5 };
        Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
        Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
 
        System.out.println( "整型数组元素为:" );
        printArray( intArray  ); // 传递一个整型数组
 
        System.out.println( "\n双精度型数组元素为:" );
        printArray( doubleArray ); // 传递一个双精度型数组
 
        System.out.println( "\n字符型数组元素为:" );
        printArray( charArray ); // 传递一个字符型数组
    } 
}

运行结果:

整型数组元素为:
1 2 3 4 5
双精度型数组元素为:
1.1 2.2 3.3 4.4
字符型数组元素为:
H E L L O

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值