[Thinking in Java]

来源:互联网 发布:淘宝怎么看行业类目 编辑:程序博客网 时间:2024/06/03 21:55

本文将介绍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)

// 创建ArrayListArrayList<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);


//创建LinkedListLinkedList<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();// 删除并返回首部元素 不存在返回nullmyCollection.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 []){// 创建HahMapHashMap<Integer, Integer>myMap = new HashMap<>();for(int i = 0 ; i <10;i++){myMap.put(i, 1);}//更改 key:9 对应的value为15myMap.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为15entry.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);elsemyMap.put(r, 1);}myMap.put(100, 100);//使用Function,如果存在key:100,更改其值为103,否则更改为100myMap.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, "替换值");//使用归并排序把数组排成递增数组。自定义类型需要实现ComparableArrays.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,否则会抛出异常UnsupportedOperationExceptionList<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);//返回集合最大/小元素。自定义元素要实现ComparableCollections.max(list3);Collections.min(list3);//对集合进行反序Collections.reverse(list2);//对集合进行打乱Collections.shuffle(list);//对集合进行排序,同时也可以提供ComparatorCollections.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.文章不妥之处还望指正









原创粉丝点击