java.util.Collection List与其子类 Set与其子类
package com.Collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class Study01 { public static void main(String[] args){ Collection<String> c=new ArrayList<String>(); Collection<String> c2=new ArrayList<String>(); c.add("I"); c.add("am"); c.add("guo"); c2.add("he"); c2.add("ha"); /*System.out.println(c);//增的结果 c.remove("I"); System.out.println(c);//删的结果 c.addAll(c2); System.out.println(c);//增一个集合所有元素 c.removeAll(c2); System.out.println(c);//删除另一个集合中存在的元素 c.clear(); System.out.println(c);//clear暴力删除所有 */ System.out.println(c); System.out.println(c.contains("am"));//包含? System.out.println(c2); System.out.println(c.containsAll(c2));//不包含c2中所有 /*System.out.println(c.retainAll(c2));//取交集,用交集替换原集合的元素。只要改变了集合返回true System.out.println(c);*/ /*c2.add("am"); System.out.println(c.retainAll(c2)); System.out.println(c);*/ //遍历集合 Object[] objs=c.toArray(); for(int i=0;i<objs.length;i++){ System.out.print(objs[i]+"\t"); } // System.out.println(); Iterator<String> it=c.iterator(); while(it.hasNext()){ String o=it.next(); System.out.print(o+"\t"); } } } /* * 引出集合: * java是面向对象的语言,对象使用的话需要一个容器装,我们前面有StringBuffer和数组两种容器,但都不太适合。因为StringBuffer存储的是字符串,而数组是不可变长的 * 数组和集合的比较: * 数组不可变长,一个数组只能存储一种类型,,集合只能存储引用数据类型 * Collection 集合 * 表示一组对象,这些对象也称为collection的元素 * 既然是操作一组对象,所以引出一些方法: * 增加: * boolean add(Object obj) * boolean addAll(Collection c) * 删除: * remove(Obj o); * removeAll(Collection c) 移除与c的交集,移除了一个就返回true * clear() 删除collection中所有元素 * boolean retainAll(Collection c) 此集合保留与c的交集 * 查找: * 通过遍历可以实现查找: * iterator() 返回在此collection上的迭代器 * Object[] toArray() 返回包含此collection中所有元素的数组 * <T> T[] toArray() 返回包含此collection中所有元素的数组,并且数组类型为指定的类型 * 判断集合中是否包含指定元素 * contains(Object o) 如果collection包含指定元素,则返回true * containsAll(Collection c) 如果包含c中所有的元素则返回true * 基本方法: * size() 返回集合大小 * isEmpty() 是否为空 * hashCode() * equals(Object o) * * 关于迭代器: * 迭代是依托于集合的,它的内部实现其实是在各种集合类中的内部类,个人感觉有点像是集合元素的一种特殊形式的复制或者其他 * 两个方法: * boolean hasNext()如果仍有元素可以迭代,则返回 true。 * Object next()返回迭代的下一个元素。 * * */
package com.List; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; public class Study01 { public static void main(String[] args) { List<String> l=new ArrayList<String>(); l.add("guo"); l.add("da"); l.add("xia"); System.out.println(l); l.add(0, "ni"); System.out.println(l); List<String> l2=new ArrayList<String>(); l2.add("hao"); l2.add("ma"); l.addAll(1,l2); System.out.println(l); System.out.println(l.get(2)); System.out.println(l.indexOf("guo")); System.out.println(""); l.set(5,"guo");//set是改变的方法。改变的下标必须拥有元素 System.out.println(l); System.out.println(l.lastIndexOf("guo")); List<String> l3=l.subList(2, 4); System.out.println(l3); for(int i=0;i<l.size();i++){ String s= l.get(i); System.out.print(s+"\t"); } ListIterator<String> it=l.listIterator(); System.out.println(); while(it.hasNext()){ String s= it.next(); System.out.print(s+"\t"); } System.out.println(); while(it.hasPrevious()){//逆序输出 String s= it.previous(); System.out.print(s+"\t"); } System.out.println(); //在遍历的中途中增加操作 while(it.hasNext()){ String s= it.next(); if(s.equals("ma")){ //ConcurrentModificationException 并发修改异常 //l.add("hi"); 不能在迭代的时候直接使用集合进行修改,但在这里可以使用迭代器的方法进行操作,在该下标的后一位增加。此次迭代器中不会出现 it.add("hi"); } System.out.print(s+"\t"); } System.out.println("\n"+l); for(int i=0;i<l.size();i++){ String s= l.get(i); if(s.equals("ma")){ l.add("haha");//for循环过程中增加,遍历出来所有元素 } System.out.print(s+"\t"); } System.out.println("\n"+l); } /* * * 对并发修改异常就是这两种方式处理: * 一是使用迭代器对象修改 * 二是使用get()和size()的结合操作 */ } /* * List 有序的collection,也称为序列。允许重复。 * 有序:指的是存进去和取出来的顺序一致 * 存取有序,所以就应该是有下标的说法 * * 新增方法: * add(int index Object obj) :将元素插入到集合指定下标的位置,之前的位置和后面的元素全部向后推移一位 * addAll(int index,Collection) * get(int index) 获取指定索引下的元素 * indexOf(Object obj) 返回指定元素在集合中的下标,不存在则返回-1 * lastIndexOf(Object obj) 返回指定元素在集合中最后一次出现的下标 * remove(int index) * set(int index,Object obj) 将集合中指定下标的元素更改为obj,返回集合中原有的元素 * subList(int formIndex,int toIndex)和String的substring类似,返回截取版的数组 * * 两个特有遍历方法: * listIterator() 返回此列表元素的迭代器,注意,是列表专用 * 这个迭代器的特点:可以实现逆向遍历。 * ListIterator * add(Object obj)将指定的元素插入列表,插入的位置是当前指针位置 * int nextIndex() 返回对next后续元素调用所返回元素的索引 * boolean hasPrevious() 判断将迭代器指针往前移一位是否存在元素 * previous() 迭代器指针前移一位,返回列表的前一个元素 * int previousIndex() * remove() 从列表中移除又next或者previous返回的最后一个元素 * set(Object obj) 用指定元素替换next或者previous返回的最后一个元素 * * ListIterator迭代和使用get()和size()结合迭代是List集合的两个特点遍历 * * * * */
package com.ArrayList_LinkedList_Vector; import java.util.ArrayList; import java.util.LinkedList; public class Study01 { public static void main(String[] args) { ArrayList<String> al=new ArrayList<String>(); al.add("ni"); al.add("hao"); al.add("wo"); al.add("men"); al.add("zai"); System.out.println(al); LinkedList<String> ll=new LinkedList<String>(); ll.add("c"); ll.addFirst("a"); ll.addLast("b"); System.out.println(ll); System.out.println(ll.peek()); System.out.println(ll.poll()); System.out.println(ll); } } /* * ArrayList * 底层数组,线程不同步,效率快,安全低 * * 构造方法: * ArrayList() 初始容量为10的空列表 * ArrayList(Collection c) 构造一个包含指定元素的集合的对象 * ArrayList(int initialCapacity) 构造一个具有指定初始化容量的空列表 * * 新增方法: * ensureCapacity(int minCapacity) 增加此ArrayList的容量 * //removeRange(int fromIndex,int toIndex) 删除指定索引区间的元素 这个方法在JDK1.6中是受保护的,不知道为什么用不了现在。 * trimToSize() 将此ArrayList实际的容量调整为列表的当前大小 * */ /* * LinkedList * List接口的链接列表实现。不是同步的 链接链表特点:增删快,查询慢 不同步特点:效率快 * 新增方法: * addFirst(Object obj) * addLast(Object obj) * descendingIterator() 返回以逆向顺序在此双端队列的元素上进行迭代的迭代器 * Object element()获取此列表第一个元素 * offer(Object obj)将指定元素添加到列表的末尾 * offerFirst(E e) * peek()获取第一个元素 * peekLast()获取最后一个元素 * pool()获取第一个元素同时移除第一个元素 * poolFirst() * poolLast() * set() * */ /* *Vector * 底层数组,查询快,增删慢 线程安全 * 和ArrayList几乎一样,不写太多 */ /* * 三个集合的选择: * 数组底层的:查询快,增删慢 ArrayList Vector * 线程安全的:速率慢,安全性高:Vector 反之,安全性较低,速率高:ArrayList * 链表结构:查询慢,增删快 LinkedList * */
package com.Set; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; /* * Set接口 * 实现Collection接口,无序,唯一 * 不是真的无序,是按照一种特殊的算法存储的,但不是11排列这种顺序 * * HashSet * 底层是哈希表,哈希表示元素为链表的数组结构 * hashSet唯一,所以添加不进重复元素,观察其源码,发现其底层是hashMap,其add方法和hashCode()和equals()方法有关 * 只有当两个元素的hash值相等,并且equals方法为true的时候才会直接跳过这个添加以保证hashSet集合的唯一性 * * 可以发现,前面好像是有唯一性,使用对象的时候就失效了,这是为什么呢? * 因为String对象自动重写了hashCode和equals方法,比较的是值。而你的Student对象的两个方法都没有重写,比较的就 * 是Object对象的hashCode方法得到的值,也就是地址值的特殊表示。所以,你只有将对象的equals和hashCode方法重写后才能 * 使得hashSet的唯一性生效 * 此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。 * LinkedHashSet * 具有可预知的迭代顺序,LinkedHashSet的子类 * 底层是哈希表和链表 * 哈希表保证元素唯一性 * 链表保证元素有序(存储一致) */ /* * 首先比较哈希值是否相同 * 相同: 继续执行equals * 返回true:元素重复了,不添加 * 返回false:可以添加 * 不同:也可以添加 */ public class HashSetAndLinkedHashSet { public static void main(String[] args) { LinkedHashSet<String> hs=new LinkedHashSet<String>(); hs.add("hello"); hs.add("java"); hs.add("world"); hs.add("java"); hs.add("world"); for(String s:hs){ System.out.println(s); } } public void test01(){ Set<String> s=new HashSet<String>(); s.add("java"); s.add("hello"); s.add("world"); s.add("java"); s.add("hello"); for(String ss:s){ System.out.println(ss); } Set<Student> s1=new HashSet<Student>(); s1.add(new Student("林青霞",27)); s1.add(new Student("范冰冰",30)); s1.add(new Student("林青霞",27)); s1.add(new Student("柳岩",25)); s1.add(new Student("林青霞",27)); for(Student ss:s1){ System.out.println(ss); } } } package com.Set; public class Student implements Comparable<Student>{ private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Student(String name, int age) { super(); this.name = name; this.age = age; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } public Student() { super(); } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } @Override public int compareTo(Student o) { //两个Student对象的比较方法 //我这里定义它先根据年龄比较,然后根据姓名比较 if(this.equals(o)){ return 0; }else if(this.getAge()==o.getAge()){ return this.getName().compareTo(o.getName()); }else{ return this.getAge()-o.getAge(); } } } package com.Set; import java.util.Comparator; import java.util.TreeSet; /* * TreeSet:能够对元素按照某种规律排序 * TreeSet的排序方式和它的比较方式有关 * * 底层是红黑树结构! * * 排序有两种: * A:自然排序 * B:比较器排序 * * 构造方法: * TreeSet() 构造新的空set,根据自然顺序进行排序 * TreeSet(Comparator<? extends E> o) 构建一个空的TreeSet,它根据比较器进行排序 * TreeSet集合的特点: * 排序和唯一 * 唯一:根据比较的值是否为0 * 排序:数的存储方式和取出方式 * * 自然排序接口:Comparable 在基本数据类型和常用类型都有它的实现,它表现在类型的compareTo方法上: * Number型比较的是数值的大小,String比较的是内容的哈希吗,boolean类型真比假为正,假比真为负,其他为0,char类型比较的是Ascill码 * 如果你使用的是自定义对象类型,就必须实现Comparable接口,才能使用自然排序。 * 自然排序,就是依据对象的compareTo方法进行排序 * * 比较器排序 * 什么是比较器? * 比较器是一个用来比较两个同类型对象的对象,比较器实现了Comparator接口,在compare方法中确定如何比较或者说是比较结果。 * * 使用比较器就是在构造方法中加入比较器。 * * 使用比较器与自然排序相比: * 自然排序的比较方式是定义在对象里的,所以每一个同类型的对象的比较方法都是确定的。而比较器是独立的一个对象,在需要这样比较的时候调用特定的比较器就好。 */ public class TreeSetStudy { public static void main(String[] args) { //我们前面使用了自然排序,那么怎么使用比较器排序呢? TreeSet<Student> ts=new TreeSet<Student>(new comparator02()); ts.add(new Student("林青霞",27)); ts.add(new Student("刘亦菲",18)); ts.add(new Student("苏有朋",30)); ts.add(new Student("刘诗诗",18)); for(Student i:ts){ System.out.println(i); } } public void test01(){ TreeSet<Integer> ts=new TreeSet<Integer>(); ts.add(18); ts.add(28); ts.add(22); ts.add(18); ts.add(19); for(int i:ts){ System.out.println(i); } } public void test02(){ //自然排序 TreeSet<String> ts=new TreeSet<String>(); ts.add("hi"); ts.add("nice"); ts.add("to"); ts.add("meet"); ts.add("you"); for(String s:ts){ System.out.println(s); } } public void test03(){ //这样报错:com.Set.Student cannot be cast to java.lang.Comparable //因为这样默认使用的是自然排序,但是Student并没有实现Comparable接口,没有自然比较方法,接下来我们让Student实现Comparable接口试试 TreeSet<Student> ts=new TreeSet<Student>(); ts.add(new Student("林青霞",27)); ts.add(new Student("刘亦菲",18)); ts.add(new Student("苏有朋",30)); ts.add(new Student("刘诗诗",18)); for(Student i:ts){ System.out.println(i); } } public void test04(){ TreeSet<Integer> ts=new TreeSet<Integer>(new comparator01()); ts.add(18); ts.add(28); ts.add(22); ts.add(18); ts.add(19); for(int i:ts){ System.out.println(i); } } } class comparator01 implements Comparator<Integer>{ @Override public int compare(Integer o1, Integer o2) { int i=o2-o1; return i; } } class comparator02 implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { if(o1.getAge()!=o2.getAge()){ return o2.getAge()-o1.getAge();//年龄从大到小排序 }else{ return o1.getName().compareTo(o2.getName()); } } } package com.Set; import java.util.Comparator; import java.util.Scanner; import java.util.TreeSet; /* * ctrl+ shift+ o 自动导包 * alt+ shift +s+o 有参构造 * alt+ shift +s+c 无参构造 * alt+ shift +s+r 封装 */ public class TreeSetDemo { public static void main(String[] args) { Scanner sc=new Scanner(System.in); //内部类实现比较 TreeSet<Student01> ts=new TreeSet<Student01>(new Comparator<Student01>(){ @Override public int compare(Student01 o1, Student01 o2) { //总分从高到低 int num=o2.getSum()-o1.getSum(); //总分相同的语文不一定相同 int num2=num==0?o1.getChinese()-o2.getChinese():num; //数学不一定相同 int num3=num2==0?o1.getMath()-o2.getMath():num2; //英语不一定相同 int num4=num3==0?o1.getEnglish()-o2.getEnglish():num3; //姓名不一定相同 int num5=num4==0?o1.getName().compareTo(o2.getName()):num4; return num5; } }); for(int x=1;x<=5;x++){ System.out.println("请输入第"+x+"个学生的姓名:"); String name=sc.nextLine(); System.out.println("请输入第"+x+"个学生的语文成绩:"); String chineseString=sc.nextLine(); System.out.println("请输入第"+x+"个学生的数学成绩:"); String mathString=sc.nextLine(); System.out.println("请输入第"+x+"个学生的英语成绩:"); String englishString=sc.nextLine(); Student01 s=new Student01(); s.setName(name); s.setChinese(Integer.parseInt(chineseString)); s.setMath(Integer.parseInt(mathString)); s.setEnglish(Integer.parseInt(englishString)); ts.add(s); } System.out.println("学生信息录入完毕"); System.out.println("学生信息从高到低顺序如下:"); System.out.println("姓名\t语文成绩\t数学成绩\t英语成绩"); for(Student01 s:ts){ System.out.println(s.getName()+"\t"+s.getChinese()+"\t"+s.getMath()+"\t"+s.getEnglish()); } } } class Student01{ private String name; private int chinese; private int math; private int english; public Student01(String name, int chinese, int math, int english) { super(); this.name = name; this.chinese = chinese; this.math = math; this.english = english; } public Student01() { super(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getChinese() { return chinese; } public void setChinese(int chinese) { this.chinese = chinese; } public int getMath() { return math; } public void setMath(int math) { this.math = math; } public int getEnglish() { return english; } public void setEnglish(int english) { this.english = english; } public int getSum(){ return getChinese()+getMath()+getEnglish(); } }