和Java集合谈谈(一)
来源:互联网 发布:淘宝日系女生店铺推荐 编辑:程序博客网 时间:2024/06/06 01:32
Collection(I) List(I) Set(I)ArrayList LinkedList Vector HashSet TreeSet
一,List
上面的每一种容器的数据结构都是不同的,而Collection接口就是它们不断抽取出的共性的内容。
List下的集合,它们的共同点就是,集合中的元素都是有索引。
也因为有索引,所以就有了和Collection下稍稍不同的地方。
List另有个特点,有序,可以存储重复元素。
1.1 和Collection的不同之处
①比如就有因为有角标index而有的一些特有的方法(相较于Collection):
//添加集合元素到指定的位置 void add(int index,E element) //添加集合到指定的位置 void addAll(int index, Collection<? extends E> c) //根据角标获取集合元素 get(int index) //根据角标删除集合元素 remove(int index)//根据角标替换集合元素 set(int index, E element)//根据角标返回子集合 List<E> subList(int fromIndex,int toIndex)
②迭代器加强
Collection下的iterator方法,它返回的是Iterator接口。
Iterator迭代器为什么会是一个接口呢?
上面说过,每一种容器的数据结构是不同的,而”存”和”取”的动作却是相同的。但是”存”和”取”这些动作(可能还有其他的动作)并不可以用一个方法或多个方法就能搞掂。
所以需要使用一个类来表示,”存”和”取”虽然都有,但实际”存”和”取”的每一种容器的处理过程却不同,于是一层一层的抽出了一个接口Iterator。
该接口有三个方法,hasNext(),next(),remove()。
ArrayList的iterator():
public Iterator<E> iterator() { return new Itr();}private class Itr implements Iterator<E> {//实现了Iterator接口}Itr是ArrayList的内部类,这样做的好处就是可以很方便的访问类中的成员。我们不必关心Itr中怎么去重写那三个方法。因为已经封装好了,拿过来用就ok。
而List下的获取迭代器除了iterator方法,还有一个加强的listIterator方法。返回的是ListIterator列表迭代器。不同于迭代器而言,它可以自由的遍历,Iteraotr只可以正序,而列表迭代器还可以逆序。不仅如此,还可以在遍历时,修改和添加集合中的元素。这些只有加强的迭代器可以做到。
ArrayList al=new ArrayList(); al.add("000"); al.add("001"); al.add("002"); ListIterator it=al.listIterator(); while(it.hasNext()){ Object obj=it.next(); if(obj.equals("001")){ it.remove();//删除 it.add("003");//添加(独有) } }
1.2 List下的每个容器的特点
ArrayList
数据结构——>数组结构
便于查询,增删比较麻烦。ArrayList查询某个元素,遍历一遍就可以得知。而增删某个元素,都会导致集合中的元素移动。
LinkedList
数据结构——>链表结构
不便于查询,增删很方便。LinkedList中的元素是后面的元素记录前面的元素,如果查询的话,遍历时,就要不断的判断后面的元素是否记录着前一个。较低效。而增删的改变却微乎其微,只需要增删元素的前后元素的引用改变就可以完成增删。
Vector
数据结构——>数组结构
不同于ArrayList的是,它的线程是同步的。效率较低。已经ArrayList被替代。
那么如果多线程操作集合怎么办?由于同步效率很低,所以即使线程不安全我们也要用ArrayList。同时,我们也可以自己加锁解决安全问题。
1.3 ArrayList去除重复元素
去除普通元素的思路,新定义一个新的ArrayList集合,然后通过迭代器迭代需要去除重复元素的集合,在迭代中判断,如果新的集合中不包含迭代出的元素,就把该元素添加到新集合,最后返回新集合。
对于普通类型的元素,比如String,int等。是可以去除的。原因就是在判断时会调用contains方法,而contains底层调用的就是equals。而基本类型的equals方法是复写了Object的equals的。
对于String,它比较的是对象之间的内容是否相同,对于int,比较的是值是否相同。
而如果ArrayList添加的是自定义的对象,而自定义对象的equals毫无疑问是参照Object的equals。它比较的是对象之间的内存地址是不是相同。
而对于自定义的不同对象,它们的内存地址肯定是不同的,所以有必要复写equals,定义我们自己的规则。
class Person{ private String name; private int age; Person(String name,int age){ this.name=name; this.age=age; } public int getAge(){ return age; } public String getName(){ return name; } @Override public boolean equals(Object obj) { if(!(obj instanceof Person)){ //不相同的对象,肯定不重复返回false return false; } Person p=(Person)obj; //下面的情况我们才认为是重复的元素 return this.name.equals(p.getName())&& this.age==p.getAge(); }}
二,Set
Set集合,是一种简单的集合。无序,而且不可以存储重复元素。
分为HashSet,TreeSet。前者是哈希表的结构,后者是树结构。
3.1 HashSet去除重复元素
private static void method_0() { HashSet hs=new HashSet(); hs.add("java01"); hs.add("java02"); hs.add("java02"); System.out.println ("java02".hashCode()=="java02".hashCode()); //返回的HashCode值是相同的 hs.add("java03"); hs.add("java03"); hs.add("java04"); Iterator it=hs.iterator(); while(it.hasNext()){ System.out.println(it.next()); } }
打印的结果,去除了重复元素。那么它是怎么做到的呢?
那就不得不提Object的hashCode方法。它返回的是对象的哈希值。这里的哈希值并不是对象的内存地址值。但是有一点可以确定,那就是同一个对象的哈希值一定相同。
而hashCode和equals方法之间还有千丝万缕的联系。
如果对象的hashCode的返回值不一样,JVM就会认为它们是不同的对象,于是会偷懒,也就不会再调用equals去比较。
而如果返回的哈希值相同,一定会调用equals去比较。
对于上面的例子,不同的值它们的hashcode值肯定是不一样的,而相同的值它们的hashCode的值必定一样,所以这时会在add的时候,调用equals。String的equals判断它们之间的对象的值是否相同。当相同时,add就会返回false,表示添加失败。
HashSet就通过这样去除了重复的元素。
而HashSet存储自定义的对象是否可以去除重复呢?
private static void method_1() { HashSet hs=new HashSet(); hs.add(new Student("ronaldo",24)); hs.add(new Student("ronaldo",24)); Iterator iterator=hs.iterator(); while(iterator.hasNext()){ Student stu=(Student) iterator.next(); Syso(stu.getName()+"......"+stu.getAge()); }}
class Student{ private String name; private int age; Student(String name,int age){ this.name=name; this.age=age; } public int getAge(){ return age; } public String getName(){ return name; } @Override public int hashCode() { Syso( "hashCode值"+ Integer.toHexString(super.hashCode())); return super.hashCode(); } @Override public boolean equals(Object obj) { System.out.println("equals执行"); return super.equals(obj); }}
执行后的结果:
哈希值为:15db9742哈希值为:6d06d69cronaldo......24ronaldo......24
结论:自定义对象的hashCode值是不一样的,系统就认为它们是不重复,也就不会调用equals去继续比较。
所以为了在equals中定义我们自己的去除规则,hashCode的返回值要保持一致。
于是就有:
@Override public int hashCode() { //尽量保证hashCode的一致性 return name.hashCode()+age*39; }
@Overridepublic boolean equals(Object obj) { if(!(obj instanceof Student)){ return false; } Student stu=(Student)obj; return this.name.equals(stu.getName()) &&this.age==stu.getAge();}
3.2 TreeSet排序
TreeSet兼容Set集合的特性,由于它树形的结构的特点,我们可以对集合中的元素进行排序。
TreeSet的默认排序规则,是按照首字母在ASCII码表的前后位置来进行排序,也称为自然排序法。
要进行自然排序,前提是需要实现Compareable接口,复写compareTo方法。该接口会强行为每个对象进行自然排序。
对于基本类型,它们都已经实现了Compareable接口。
private static void method_0() { TreeSet ts=new TreeSet(); ts.add("cba"); ts.add("aaa"); ts.add("bca"); ts.add("Dbcd"); Iterator it=ts.iterator(); while(it.hasNext()){ System.out.println(it.next()); } }
而对于自定义的对象,必须要实现Compareable接口,否则在TreeSet进行排序时,会抛出ClassCaetException异常。原因很简单,TreeSet必须要知道根据什么来排序,实现Compareable接口,在compareTo中定义我们排序的规则。
int compareTo(T o)当前对象和此对象比较,如果大于此对象,返回正数,小于,返回负数。相等,返回0。返回0表示是重复元素,就会将其pass掉。
改写为:
private static void method_1() { TreeSet ts=new TreeSet(); ts.add(new StudentTree("wcx02",22)); ts.add(new StudentTree("wcx007",20)); ts.add(new StudentTree("wcx09",19)); ts.add(new StudentTree("wcx09",19)); ts.add(new StudentTree("wcx08",19)); Iterator it=ts.iterator(); while(it.hasNext()){ Object obj=it.next(); StudentTree stu=(StudentTree)obj; Syso(stu.getName()+" "+stu.getAge()); } }
class StudentTree implements Comparable<StudentTree>{ private String name; private int age; StudentTree(String name,int age){ this.name=name; this.age=age; } public int getAge(){ return age; } public String getName(){ return name; } @Override public int compareTo(StudentTree o) { if(this.age>o.getAge()){ return 1; } if(this.age==o.getAge()){ return this.name.compareTo(o.getName()); } if(this.age<o.getAge()){ return -1; } return 0; }}
这时,有一种情况我需要考虑。String,Integer这些已经实现了自然排序的类,如果我不想自然排序,想换另一种。难道我们要去修改compareTo中的代码么?
还有就是其他人已经写好的类已经实现Compareable,它的排序规需要修改,去更改别人写好的排序规则,这也是不妥的。
public TreeSet(Comparator<? super E> comparator)
TreeSet的构建器中接收一个比较器,在Comparator中的compare中规定我们的规则。
int compare(T o1,T o2)o1大于,小于,等于o2会分别返回正数,负数,0。
Compareable和Comparator:
虽然它们都可以实现排序,但一个在对象内部实现,一个在对象外部。
Comparator比较器它可以不改变对象的本身来达到排序的效果。
- 和Java集合谈谈(一)
- 谈谈java 集合框架
- 简单谈谈Collection集合和Map集合
- java基础之谈谈集合类(关于集合类的总结和比较)
- JAVA【集合一】集合类
- 和Java泛型谈谈
- Java集合框架 (一)
- Java集合框架 (一)
- Java集合框架 (一)
- java集合总结(一)
- Java集合(一)
- java集合类 一
- java集合总结一
- JAVA 集合类一
- JAVA集合框架(一)
- Java集合(一)
- Java集合框架(一)
- java集合学习一
- JAVA设计模式之------简单工厂模式
- Qualification Round 2016(A. Counting Sheep,B. Revenge of the Pancakes,C. Coin Jam,D. Fractiles(构造))
- unity3d面试2
- 西电网络赛 - G
- 有jQuery背景如何用AngularJS思考
- 和Java集合谈谈(一)
- tomcat 处理请求过程
- 顺序容器和关联容器的比较
- Swift:Float
- 阿里巴巴2016前端实习笔试不会的题
- java多线程的公平锁和非公平锁
- 用对象数组操作长方柱类
- Hadoop在虚拟机简单的集群
- 【程序人生】:看到商汤集团的招聘简章,感觉自己弱爆了