学习内容:
1.List接口:
List接口的实现类有如下特点:
有顺序(存取顺序相同),值可以重复,有索引。
常用方法:
a. add()方法,返回布尔值
b. set(),返回被修改的值(注意,是修改前而不是修改后的值!)
c.remove()方法,返回被删除的值
d.addAll()方法,将另外一个集合的所有元素添加到当前集合,返回布尔值
public class Test { public static void add() { List<String> list = new ArrayList<String>(); //有顺序,值可以重复,有索引 list.add("one"); list.add("two"); list.add("three"); list.add(3,"four");可以顺序添加 list.add(4, "four"); System.out.println(list); String s = list.remove(0);//删除时返回被删除的值 System.out.println(s); String e = list.set(0, "who");//修改时返回被修改的值(注意,是修改前而不是修改后的值!) System.out.println(e); System.out.println(list); } }
并发修改异常、无此元素异常:
public class Test { public static void add() { List<String> list = new ArrayList<String>(); list.add("one"); list.add("two"); list.add("three"); Iterator<String> it = list.iterator(); while(it.hasNext()) { String str = it.next(); if(str.equals("one")) { int i = list.indexOf("one"); list.add(i, "who"); } //System.out.println(str); /*java.util.ConcurrentModificationException*/ //并发修改异常 } } }
public class Test{ public static void main(String[] args){ List<String> list2 = new ArrayList<String>(); list2.add("nihao"); list2.add("wohao"); list2.add("dajiahao"); list2.add("nihao"); list2.add(1, "tahao"); for(Iterator<String> it = list2.iterator();it.hasNext();) { String str = it.next(); if(str.equals("nihao")) { int i = list2.indexOf(str); list2.set(i,"nibuhao"); } //System.out.println(it.next()); //无此元素异常,NoSuchElementException } } }
e.contains(),是否包含某个元素,返回布尔值,配合迭代可以实现去重,例:
ArrayList<Student> list = (ArrayList<Student>)ois.readObject(); ArrayList<Student> filterlist = new ArrayList<Student>(); Iterator<Student> it = list.iterator(); while(it.hasNext()){ Student stu = it.next(); if(!filterlist.contains(stu)){ filterlist.add(stu); } }
2.数据存储的常用结构有:堆栈、队列、数组、链表。
(1)堆栈:数据先进后出。
(2)队列:数据先进先出。
(3)数组:查找快,增删慢,因为每次增删都要创建一个新数组。
(4)链表:增删快,查询慢,各个元素之间通过地址指向互相连接。
3.LinkedList
链表结构,数据先进先出,可以很方便的向集合首尾添加、删除数据
常用方法:addFirst,addLast,removFirst,removeLast
public Test{ public static void main(String[] args){ LinkedList<String> list = new LinkedList<String>(); list.add("123"); list.addFirst("123"); list.addLast("456"); list.removeFirst(); list.removeLast(); } }
4.Set接口
特点:无序(存取顺序不同),数据不重复,无索引
因为Set的实现类没有下标,所以只能通过迭代器或者增强型for循环来遍历
public Test{ public static void main(String[] args){ Set<String> set = new HashSet<String>(); set.add("Cross"); set.add("bingo"); set.add("where"); set.add("are"); set.add("you"); for(Iterator it = set.iterator();it.hasNext();) { System.out.println(it.next()); } for(String str:set) { System.out.println(str); } } }
实现类:
HashSet:
注意add方法:默认会调用父类的hashcode、equals方法,先比较hashcode,如果相同,直接返回false,不存入,
如果不同,用equals比较,如果相同,返回false,不存入,如果不同,返回true,存入。
HashSet 如何add机制
假如我们有一个数据(散列码76268),而此时的HashSet有128个散列单元,那么这个数据将有可能插入到数组的第108个链表中(76268%128=108)。
但这只是有可能,如果在第108号链表中发现有一个老数据与新数据equals()=true的话,这个新数据将被视为已经加入,而不再重复丢入链表。
HashSet的散列单元大小如何指定?
Java默认的散列单元大小全部都是2的幂,初始值为16(2的4次幂)。假如16条链表中的75%链接有数据的时候,则认为加载因子达到默认的0.75。
HahSet开始重新散列,也就是将原来的散列结构全部抛弃,重新开辟一个散列单元大小为32(2的5次幂)的散列结果,并重新计算各个数据的存储位置。
以此类推下去.....
如果HashSet的泛型是字符串或者基本数据类型的的封装类,这样不会有问题,但是如果存入的是实例化的对象,因为每个实例化的对象其hashcode不同,即使其成员变量相同(即本质上是相同的对象),也会存入HashSet,所以必须重写继承自父类的hashcode、equals方法!
public Test { public static void main(String[] args){ HashSet<String> hs = new HashSet<String>(); hs.add("one"); hs.add("one");//重复的值只会保留一个,hashcode相同 hs.add("two"); System.out.println(hs); HashSet<Person> hp = new HashSet<Person>(); hp.add(new Person("a","nan",20));//哈希值不同,导致全部存入,需要重写Person类内的hashcode、equals方法 hp.add(new Person("a","nan",20));//默认调用父类的hashcode与equals方法 hp.add(new Person("a","nan",20)); System.out.println(hp); Person p1 = new Person("1","a",20); Person p2 = new Person("1","a",20); System.out.println(p1.hashCode());// System.out.println(p2.hashCode());//这两个对象hashcode不同,但本质上是一个对象 } }
public class Person { String name; String sex; int age; public Person() {}; public Person(String name,String sex,int age) { this.name = name; this.sex = sex; this.age = age; } public String toString() { return name+' '+sex+' '+age; } public int hashCode() {//重写父类方法 return name.hashCode()*55; } public boolean equals(Object obj) {//方法重写,根据对象属性判断是否为同一对象 if(obj==null) { return false; } if(this==obj) { return true; } if(obj instanceof Person) { Person person = (Person)obj; return ((Person)obj).age==this.age&&((Person)obj).name==this.name&&((Person)obj).sex==this.sex; } return super.equals(obj); } }
LinkedHashSet:
可以实现元素的顺序存取
public Test{ public static void main(String[] args){ LinkedHashSet<String> lhs = new LinkedHashSet<String>();//按顺序存取 lhs.add("123"); lhs.add("456"); lhs.add("7889"); lhs.add("412"); lhs.add("017"); System.out.println(lhs); } }