[Thinking in Java] - No.8 容器学习初级

本文将介绍Java中的各类型容器、常用容器以及常用容器的一些基本的操作。在日后的文章中会进一步了解这些容器的内部实现、涉及容器线程安全方面的知识这里不再赘述。

一、各个类型容器之间的关系图


对这张图做一下简单的解释:

我们可以看出,在图中其实只有四种类型的容器,List,Set,Queue和Map(其实应该去掉Queue,因为Stack和Queue的功能均可以由LinkedList提供)。其中前三种容器实现了Collection接口。在这张图中,虚线加空心箭头表示实现,虚线和实心箭头表示产生。例如Map的对象,可以产生Collection类型的对象(例如keySet),每个Collection都可以产生Iterator类型对象。

二、List

实现List接口的有两个子类,ArrayList类和LinkedList类。两者的区别在于,当我们希望进行大量的随机访问的时候,我们使用ArrayList,当我们需要经常对列表从中间插入或者删除元素,那么我们使用LinkedList。可以理解为LinkedList像是一个双向链表,但是ArrayList只是数组。(其大小均可以扩展,ArrayList默认是10)

// 创建ArrayList
ArrayList<String>myList = new ArrayList<>();
//添加元素
myList.add("Irving");
myList.add("Jack");
myList.add("Kevin");
myList.add("Lily");
		
//排序-自定义排序Comparator和默认排序
myList.sort(new MyComparator());
Collections.sort(myList, new MyComparator());
Collections.sort(myList);
		
//判断是否包含某元素
System.out.println(myList.contains("Alice"));
		
//使用ListIterator遍历列表
ListIterator<String> iterator2 = myList.listIterator();
while(iterator2.hasNext())
{
        String str = iterator2.next();
        System.out.println(str);
	//更改元素
	if(str.equals("Lily"))
	{
	    iterator2.set("Lucy");
	}
}
//删除
myList.remove(2);


//创建LinkedList
LinkedList<String>myCollection = new LinkedList<>();
//添加元素
myCollection.add("Alice");
myCollection.add("Bob");

//在前后加入元素
myCollection.addFirst("Ada");
myCollection.addLast("Hellen");
		
//获取前后元素 不存在时peek返回null 其余抛出异常
System.out.println("列表第一个:" +myCollection.element()+" "+myCollection.getFirst()+" "+ myCollection.peek());
System.out.println("列表最后一个:" +myCollection.getLast()+" " +myCollection.peekLast());
LinkedList可以提供队列和栈的功能,可以从首部和尾部插入元素,同时获取首部或者尾部的元素。同时也可以使用相关的remove函数来删除元素

// 删除并返回首部元素,不存在即抛出异常
myCollection.removeFirst();
myCollection.pop();
// 删除并返回首部元素 不存在返回null
myCollection.poll();
// 同理还有删除尾部,主要的区别就是如果不存在是否抛出异常还是 返回null

由于Queue的使用和List差不多,同时Queue和Stack的功能LinkedList都可以实现,所以就不介绍Queue了。


三、Set

Set包含有TreeSet和HashSet两个子类。TreeSet主要是保持元素处于排序状态,HashSet用于快速的访问,不排序元素。同时,Set不接受重复的元素。

在set中,我们经常使用的是HashSet。

public static void main(String args[]) {
		HashSet<Person> mySet = new HashSet<>();
		HashSet<Person> mySet2 = new HashSet<>();
		Person Alice = new Person("Alice", 15);
		Person Alice1 =  new Person("Alice", 15);
		Person Bob =  new Person("Bob", 17);
		Person Cindy =  new Person("Cindy", 18);
		Person Dave = new Person("Dave", 15);
		//添加元素
		mySet.add(Alice);
		mySet.add(Bob);
		mySet.add(Cindy);
		mySet2.add(Alice1);
		mySet2.add(Dave);
		
		//删除元素
		mySet.remove(Bob);
		
		//直接增加一个集合所有的元素
		mySet.addAll(mySet2);
		//把集合转换成数组
		Object[] parry = mySet.toArray();
		for(int i = 0 ; i < parry.length;i++)
		{
			Person person = (Person)parry[i];
			System.out.println(person.name + "->" + person.age + " ");
		}
		
		//遍历
		Iterator<Person> iterator = mySet.iterator();
		while(iterator.hasNext()){
			System.out.println(iterator.next().name + "->"+iterator.next().age);
		}
	}
四、Map

Map主要使用的是HashMap和TreeMap两种Map。其中HashMap主要是基于哈希表,TreeMap的原理则和C++中的Map一样,是基于红黑树的。
HashMap主要是用于快速访问,TreeMap保持键始终在排序的状态。我们常使用HashMap

public static void main(String args []){
		// 创建HahMap
		HashMap<Integer, Integer>myMap = new HashMap<>();
		for(int i = 0 ; i <10;i++)
		{
			myMap.put(i, 1);
		}
		
		//更改 key:9 对应的value为15
		myMap.replace(9,15);
		//判断 key:9 对应的value是否为1,如果是1,更改为15 
		myMap.replace(9,1,15);
		
		//遍历方法1:获取所有的Entry,然后遍历Key和Value,可以很方便的更改键值对
		Set<Entry<Integer, Integer> > mySet = myMap.entrySet();
		for(Entry<Integer, Integer> entry:mySet)
		{
			System.out.println(entry.getKey() +" : " + entry.getValue());
			// 更改该entry的value为15
			entry.setValue(15);
		}
		Random random = new Random();
		for(int i = 10 ; i <20;i++)
		{
			int r = random.nextInt(10)+10;
			//判断是否包含该键值
			if(myMap.containsKey(r))
				//使用get方法获key对应的值,同时更改。相同的key的键值对插入会覆盖
				myMap.put(r, myMap.get(r)+1);
			else
				myMap.put(r, 1);
			
		}
		
		myMap.put(100, 100);
		//使用Function,如果存在key:100,更改其值为103,否则更改为100
		myMap.computeIfPresent(100, (k,v)-> true==false? 100:100+3);
		myMap.compute(1000, (k,v)-> 1003);

		//遍历方法2:首先获取所有的key的集合,然后根据key获得value,无法更改键值对
		Set<Integer> kset = myMap.keySet();
		Collection<Integer> myCollection = myMap.values();
		for(Integer k:kset)
		{
			System.out.println("key:"+k + "values:" + myMap.get(k));
		}
		
		//遍历方法3:获取所有的entry的集合,然后使用iterator遍历该set集合。和1原理相同
		//方便更改键值对
		Iterator<Entry<Integer, Integer>> it = myMap.entrySet().iterator();
		while(it.hasNext())
		{
			Entry<Integer, Integer> entry = it.next();
			System.out.println("key: "+entry.getKey()+"values: "+entry.getValue());
		}
		
 	}
五、Collections和Arrays工具类

在容器的使用时候,还有两个工具类,分别是Collections和Arrays。这两个类都只提供静态方法,而无法直接实例化。

Arrays常用方法:

String [] tmp = {"1","2","3"};
//使用asList方法,将对象数组转换为List对象
List<String>list = Arrays.asList(tmp);

//二分查找,查询目标数组中是否含有某个元素
Arrays.binarySearch(tmp, "5");
		
//拷贝某个数组,将其中从的0开始的length个元素作为新的数组。
//如果length大于数组长度,那么多出来的地方使用相应的数据类型默认的值填充
String tmp2[] = Arrays.copyOf(tmp, 5);
		
//判断两个数组是否相同
Arrays.equals(tmp, tmp2);
	
//使用替换值填充数组中所有元素
Arrays.fill(tmp, "替换值");
		
//使用归并排序把数组排成递增数组。自定义类型需要实现Comparable
Arrays.sort(tmp);
		
//打印数组 格式: [xxx,xxx,xxx]
System.out.println(Arrays.toString(tmp));


Collections常用方法:

String [] tmp = {"1","2","3"};
String [] tmp3 = {"7","8","9"};
//使用asList方法,将对象数组转换为List对象
//这里必须先把list转为list3,否则会抛出异常UnsupportedOperationException
List<String>list = Arrays.asList(tmp);
List<String>list3 = new ArrayList<>(list);
Collections.addAll(list3, tmp3);
		
//二分查找
Collections.binarySearch(list, "5");
		
//如果直接使用List<String>list2 = new ArrayList<>();会抛出数组越界异常。
//因为此时list2的size为0,无法进行copy。可是使用下面的方法或者赋初始值的方法
List<String>list2 = new ArrayList(Arrays.asList(new Object[3]));
Collections.copy(list2, list);
		
//判断两个集合是否相交
Collections.disjoint(list3,list2);

//返回一个空的List,但是无法进行直接增删操作。
//同类的还有Map,Set等相关函数
List<String> list4 = Collections.emptyList();

//使用替换值填充集合中所有元素
Collections.fill(list3, "你好");
		
//统计集合中某对象频率
int frequency = Collections.frequency(list3, "你好");
System.out.println(frequency);
		
//返回集合最大/小元素。自定义元素要实现Comparable
Collections.max(list3);
Collections.min(list3);
		
//对集合进行反序
Collections.reverse(list2);
		
//对集合进行打乱
Collections.shuffle(list);
		
//对集合进行排序,同时也可以提供Comparator
Collections.sort(list);
Collections.sort(list, new MyComparator());
		
//对集合进行旋转。意思就是集合循环右移distance位数。
//[h,e,l,l,o,] 右移三个变成 [l,l,o,h,e]
Collections.rotate(list, 3);
这里解释一个地方:

使用copyof()的地方:

如果直接使用下面的代码:

List<String>list = Arrays.asList(tmp);

Collections.addAll(list, tmp3);

Collections.addAll()内部的实现还是使用list.add()逐个增加元素。Arrays.asList() 返回java.util.Arrays$ArrayList, 而不是ArrayList。

Arrays$ArrayList和ArrayList都是继承AbstractList,remove,add等method在AbstractList中是默认throw UnsupportedOperationException而且不作任何操作。

但是ArrayList 覆盖了add等方法,来对list进行操作,所以我们使用ArrayList进行add不会产生异常。

本文仅仅列举了容器一些基本的操作,Collection中还有很多其他的函数,没有列举出。在使用的时候可以查询API文档。


P.S.文章不妥之处还望指正









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值