黑马程序员—JAVA基础—集合类

来源:互联网 发布:软件测试人员保密协议 编辑:程序博客网 时间:2024/06/04 19:54
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
1、概念:集合类是一个容器,只用于存储对象。
2、与数组相比,集合用于存储对象,且长度可变。数组用于存储基本数据类型,长度不可变。
3、为什么出现集合类,java语言的编程思想是面向对象,对象就会很多,集合就是为了更好的管理对象。
4、集合框架:





List:元素是有序的,元素可以重复
         ArrayList:底层为数组结构,带有脚标。特点:查询快,增删慢,线程不同步。
         LinkedList:底层为链表数据结构,没有脚标。特点:查询慢,增删快,线程不同步。
         Vector:底层为数组结构,带有脚标。特点:查询、增删都慢,线程同步,因为效率低,jdk升级后被ArrayList代替。

Set:元素是无序的,元素不可以重复。

       Collection接口中定义了集合框架中共性的功能:
        添加:
               add(E):添加一个元素
               addAll(Conllection):添加一个集合中所有元素
        删除:
               remove(Object):移除一个元素
               removeAll(Conllection):移除本集合中与传入集合相同的元素
               clear():清空集合
        判断:
               contains(Object):是否包含某个元素
               containsAll(Conllection):是否包含一个集合中的所有元素
               isEmpty():判断集合是否为空
        获取:
               iterator():迭代器
               size():获取集合的长度
        取交集:
retainAll(Conllection):保留本集合与传入集合相同的元素
       转成数组:
               toArray()

         List接口中的特有方法:
         添加:
add(int index, E element):根据脚标添加
                add(int index,Conllection)
         删除
                remove(int index):根据脚标移除元素
         修改:
                set(int index,E):替换指定脚标的元素
         查询:
                get(int index):获取指定脚标的元素
                listIterator():特有迭代器,在迭代过程中可以对数据进行添加、修改操作
                indexOf(Object):获取元素的脚标
                subList(int fromIndex, int toIndex):获取集合中某一段

LinkedList中特有的方法:
添加:
addFirst()
addLast()
获取:
getFirst()
getLast()
删除:
removeFirst()
removeLast()
上述两个方法同样可以获取元素,但是跟获取中两个方法比较,此方法会删除元素


在jdk1.6版本后
添加:
offerFirst()
offerLast()
获取:
peekFirst()
peekLast()
删除:
pollFirst()
pollLast()

           Vector中特有方法:
            枚举:相当于迭代器
代码示例:
import java.util.*;class VectorDemo {public static void main(String[] args) {Vector v = new Vector();v.add("person01");v.add("person02");v.add("person03");v.add("person04");//Vector枚举方法相当于迭代器Enumeration e = v.elements();while (e.hasMoreElements()){sop(e.nextElement());}}public static void sop(Object o){System.out.println(o);}}

练习1:模拟队列结构和堆栈结构
队列结构:先进先出,就像水管
堆栈结构:先进后出,就像水杯
import java.util.*;class DuiLie{private LinkedList link;DuiLie(){link = new LinkedList();}public void myAdd(Object o){link.addFirst(o);}public Object myGet(){//return link.removeLast();return link.removeFirst();//要改为堆栈结构,只需修改取数据的动作,同时//也可以修改存储的动作}public boolean isNull(){return link.isEmpty();}}
练习2:去除ArrayList中的重复元素
public static ArrayList removeSame(ArrayList al){/*定义一个新的容器,将要去除重复元素的容器进行迭代,新的容器对迭代出来的元素进行是否包含判断,如果包含就存储进新的容器*/ArrayList newAl = new ArrayList();Iterator it = al.iterator();while (it.hasNext()){Object o = it.next();if (!newAl.contains(o)){newAl.add(o);}}return newAl;}
当要存储自定义对象时,在自定义对象类中呀重写Object类中的equals方法,因为集合的contains方法会调用对象的equals方法
比如要在集合中存储人对象,当人的姓名和年龄相同时,就视为同一个人,那么,人这个类中就可以这样描述
class Person{private String name;private int age;Person(String name,int age){this.name = name;this.age = age;}public String getName(){return name;}public int getAge(){return age;}//复写Object类中的equals方法public boolean equals(Object o){if (!(o instanceof Person))return false;Person p = (Person)o;return this.name.equals(p.name) && this.age == p.age;}}

HashSet:底层是哈希表结构,元素是无序的,在存储元素的时候,先判断元素的哈希值,再判断元素是否相同
练习3:往HashSet存储自定义对象的时候,要复写Object类中的hashCode和equals方法:
那么在定义对象的时候就可以这样定义
class Person{private String name;private int age;Person(String name,int age){this.name = name;this.age = age;}public String getName(){return name;}public int getAge(){return age;}public int hashCode(){//System.out.println(this.name+"----hashCode......");/*return 60;直接返回数值也可以,但是为了减少判断对象是否相同,也就是减少equals方法,要自定义返回值,而且要不一样*/return this.name.hashCode()+age*39;//乘39是为了避免返回的哈希值一样}//复写Object类中的equals方法public boolean equals(Object o){if (!(o instanceof Person))return false;Person p = (Person)o;//System.out.println(this.name+"----equals....."+p.name);return this.name.equals(p.name) && this.age == p.age;}}

TreeSet:底层为二叉树结构

以34位基准,比34小的往左边放,比34大的往右边放,,在插入过程中,会找一个中间数作为比较,永远都遵循小的在左边
大的在右边

用TreeSet存储自定义对象时,在运行时会发生java.lang.ClassCastException(类型转换异常)
解决办法:
第一:可以让自定义对象具有比较性,实现Comparable接口,覆盖compareTo方法,
在compareTo方法里面自定义比较内容
第二:可以自定义一个比较器,实现comparator接口,覆盖compare方法,里面自定义比较内容,
将比较器作为参数传给TreeSet对象
注意:当两者都存在时,以比较器为主
代码示例:当用TreeSet集合存储自定义人对象时,按年龄升序排序,但是遇到姓名不同,年龄相同时,不能存储,所以当年龄相同时,要比较姓名
第一:让对象具有比较性
class Person implements Comparable//让对象具有比较性{private String name;private int age;Person(String name,int age){this.name = name;this.age = age;}public String getName(){return name;}public int getAge(){return age;}public int compareTo(Object o){if (!(o instanceof Person)){throw new RuntimeException("参数不匹配");}Person p = (Person)o;/*if (this.age>p.age){return 1;}if (this.age==p.age){return this.name.compareTo(p.name);}return -1; *///同样是先比较年龄,主要条件,再比较姓名这个次要条件int a = new Integer(this.age).compareTo(new Integer(p.age));//Integer自身具有默认的比较方法if (a==0){return this.name.compareTo(p.name);}return a;}}
第二:自定义比较器方法:
class MyComparator implements Comparator//定义比较器,实现Comparator接口{public int compare(Object o1,Object o2){Person p1 = (Person)o1;Person p2 = (Person)o2;//比较主要条件,当年龄相同时,再比较次要条件,姓名int a = new Integer(p1.getAge()).compareTo(new Integer(p2.getAge()));if (a==0){//次要条件return p1.getName().compareTo(p2.getName());}return a;}}

练习1:按字符串的长度进行排序
/*自定义比较器,用于比较字符串长度,但是当用户存储的字符串长度一样,但是内容不一样时,没有存储进去,所以当长度一样时,要进行字符串的比较*/class MyComparator implements Comparator{public int compare(Object o1,Object o2){String s1 = (String)o1;String s2 = (String)o2;int a = new Integer(s1.length()).compareTo(new Integer(s2.length()));if (a==0){return s1.compareTo(s2);}return a;}}
练习2:"90 -7 0 18 2 45 4" 将字符串中的数值进行排序。使用TreeSet完成
/*分析:将字符串进行切割,将切割后的字符转成Integer存储进TreeSet集合,TreeSet本身具备比较功能*/import java.util.*;class TreeSetTest2 {public static void main(String[] args) {String s= "90 -7 0 18 2 45 4";String[] str = s.split(" ");//按空格对字符串进行切割TreeSet t = new TreeSet();for (int x=0; x<str.length; x++){t.add(Integer.parseInt(str[x]));//转成Integer依次存储进TreeSet集合中} System.out.println(t);//打印集合}}
5、泛型:是一个安全机制,提高代码安全性
在编写代码时用<>指定类型,在编译时,如果传入不是指定类型,就会编译失败
避免强转
泛型可以定义在类上
//泛型定义在类上,在整个类中有效class Test<T>{public void show(T t){System.out.println("show----"+t);}//将泛型定义在接口上,不受类上泛型的影响public <W> void print(W w){System.out.println("print----"+w);}//静态方法不能直接访问类上的泛型//如果静态方法操作的数据类型不确定,可以将泛型定义在方法上/*public static void print_2(T t){System.out.println("show----"+t);}*/}
泛型定义在接口上:
//泛型定义在接口中interface Inter<E>{public void show(E e);}//在实现接口时,指定类型,在使用的时候,只能操作指定的类型class InterImpl implements Inter<String>{public void show(String s){System.out.println("show---"+s);}}//如果操作的类型不确定,也可以不指定类型,在类中继续使用泛型class InterImpl_2<E> implements Inter<E>{public void show(E e){System.out.println("show---"+e);}}
泛型限定
?通配符或者占位符
? extends E 可以接收E类型或者E的子类型  向上限定
? super E 可以接收E类型或者E的父类型   向下限定
代码示例:
class GenericTest4 {public static void main(String[] args) {TreeSet<Student> t = new TreeSet<Student>(new MyComparator());t.add(new Student("Student01",21));t.add(new Student("Student02",19));t.add(new Student("Student03",25));t.add(new Student("Student04",22));t.add(new Student("Student05",19));printColl(t);}//定义一个打印集合的方法,限定泛型为Person或者Person的子类public static void printColl(Collection<? extends Person> al){Iterator<? extends Person> it = al.iterator();while (it.hasNext()){Person p = it.next();System.out.println("name:"+p.getName()+"-----age:"+p.getAge());}}}//定义一个比较器接收Person或者Person的子类class MyComparator implements Comparator<Person>{public int compare(Person p1,Person p2){int a = new Integer(p1.getAge()).compareTo(new Integer(p2.getAge()));if (a==0){return p1.getName().compareTo(p2.getName());}return a;}}class Person{private String name;private int age;Person(String name,int age){this.name = name;this.age = age;}public String getName(){return name;}public int getAge(){return age;}}class Student extends Person{Student(String name,int age){super(name,age);}}class Worker extends Person{Worker(String name,int age){super(name,age);}}

Map集合:接口 Map<K,V>  该集合存储的是键值对,一个key对应一个value
|--Hashtable:底层是哈希表结构,key和value都不能为null,线程是同步的,效率低
|--HashMap:底层是哈希表结构,key和value可以为null,线程是不同步的,效率高
|--TreeMap:底层是二叉树结构,key和value不可以为空,线程是不同步的,可以给key进行排序

添加:
put(K key, V value)
putAll(Map<? extends K,? extends V> m)
删除:
remove(Object key):在移除元素的时候,可以获取value的值
clear():清空
判断:
contains(Object key)
contains(Object value)
isEmpty()
获取:
get(Object key)
size()
values()
ketSet:
将map中的key存储到Set集合中,通过迭代器,根据key的用get(Object key)方法获取值

entrySet:
将map集合中的映射关系存储到Set集合中,这种映射关系的类型是Map.Entry
entrySet是map中一个静态内部接口,因为先存在键值对,才有映射关系,并且要直接访问map的映射关系,所以定义在内部
练习1、往HashMap中存储学生对象和地址,学生类中有姓名和年龄,姓名和年龄一样视为同一个学生,保证学生唯一性
class MapTest {public static void main(String[] args) {Map<Student,String> m = new HashMap<Student,String>();Student s1 = new Student("张三",18);Student s2 = new Student("李四",22);Student s3 = new Student("王五",25);Student s4 = new Student("赵六",20);Student s5 = new Student("赵六",20);m.put(s1,"广东省");m.put(s2,"湖南省");m.put(s3,"福建省");m.put(s4,"黑龙江省");m.put(s5,"北京市");//keySet方式取出数据Set<Student> keySet = m.keySet();Iterator<Student> it = keySet.iterator();while (it.hasNext()){Student s = it.next();System.out.println("姓名:"+s.getName()+"-年龄:"+s.getAge()+"-地址:"+m.get(s));}//entrySet方式取出数据Set<Map.Entry<Student,String>> entrySet = m.entrySet();Iterator<Map.Entry<Student,String>> it2 = entrySet.iterator();while (it2.hasNext()){Map.Entry<Student,String> me = it2.next();Student s = me.getKey();String address = me.getValue();System.out.println("姓名:"+s.getName()+"-年龄:"+s.getAge()+"-地址:"+address);}}}class Student implements Comparable<Student>{private String name;private int age;Student(String name,int age){this.name = name;this.age = age;}public void setName(String name){this.name = name;}public String getName(){return name;}public void setAge(int age){this.age = age;}public int getAge(){return age;}//因为HashMap底层为哈希表结构,要保证唯一性,//就要复写Object类中的hashCode方法public int hashCode(){return name.hashCode()+age*39;}//并且要覆盖equals方法public boolean equals(Object obj){if (!(obj instanceof Student)){throw new ClassCastException("类型不匹配");}Student s = (Student)obj;return this.name.equals(s.name) && this.age==s.age;}//因为可能需要往TreeSet集合里面存储学生//所以实现Comparable接口覆盖compareTo方法public int compareTo(Student s){int a = new Integer(this.age).compareTo(new Integer(s.age));if (a==0){return this.name.compareTo(s.name);}return a;}}

练习2:获取一段字符串中每个字母出现的次数,并以a(次数)b(次数)这样的形式打印
/*分析:先将字符串转换成字符数组将字符作为键,次数作为值存入TreeSet集合中,因为TreeSet集合自身具有排序功能遍历字符数组,将每一个元素作为键去查找集合中是否有值如果没值,就将(字符,1)存入集合,如果有值,就将(字符,原来的次数加1)存入集合因为在map集合中,如果key一样,新的value会覆盖旧的value*/class MapTest2 {public static void main(String[] args) {String s = "abcabce2fgh}oll.eabb";s = getCharCount(s);System.out.println(s);}//定义一个获取出现次数的方法public static String getCharCount(String s){char[] arr = s.toCharArray();//将字符串转换成字符数组TreeMap<Character,Integer> hm = new TreeMap<Character,Integer>();int count = 0;//定义计数器,记录次数for (int x=0; x<arr.length; x++){//判断数组中的元素是否为字母if(!(arr[x]>'a' && arr[x]<'z' || arr[x]>'A' && arr[x]<'Z'))continue;Integer value = hm.get(arr[x]);//根据字符获取valueif(value!=null)count = value;count ++;hm.put(arr[x],count);count = 0;//要循环获取每个字符,计数器要清零}Set<Map.Entry<Character,Integer>> entrySet = hm.entrySet();Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator();StringBuilder sb = new StringBuilder();//定义字符缓冲区对象while (it.hasNext()){Map.Entry<Character,Integer> me = it.next();Character ch = me.getKey();Integer i = me.getValue();sb.append(ch+"("+i+")");//将迭代出来的字符按照如下形式依次存入}return sb.toString();//将字符缓冲区转换为字符串,并返回}}
Map集合拓展:Map集合中嵌套集合
代码示例:
class MapTest3 {/*集合中嵌套集合一个公司中有多个部门,一个部门有多个员工将部门中的员工存储在List集合中,然后再将部门名称作为key,员工作为value存储Map集合中*/public static void main(String[] args) {List<Employee> personnel = new ArrayList<Employee>();//人事部List<Employee> technology = new ArrayList<Employee>();//技术部HashMap<String,List<Employee>> compary = new HashMap<String,List<Employee>>();//公司compary.put("人事部",personnel);compary.put("技术部",technology);personnel.add(new Employee(01,"zhangsan"));personnel.add(new Employee(02,"lisi"));personnel.add(new Employee(03,"wangwu"));technology.add(new Employee(01,"张三"));technology.add(new Employee(02,"王五"));technology.add(new Employee(03,"李四"));//通过entrySet方法取出元素Set<Map.Entry<String,List<Employee>>> entrySet = compary.entrySet();Iterator<Map.Entry<String,List<Employee>>> it = entrySet.iterator();while (it.hasNext()){Map.Entry<String,List<Employee>> me = it.next();String department = me.getKey();List<Employee> al = me.getValue();System.out.println(department);printList(al);}}public static void printList(List<Employee> l)//打印list集合中的元素{Iterator<Employee> it = l.iterator();while (it.hasNext()){Employee e = it.next();System.out.println("id:"+e.getId()+"----name:"+e.getName());}}}class Employee//员工类{private int id;private String name;Employee(int id,String name){this.id = id;this.name = name;}public String getName(){return name;}public int getId(){return id;}}
Collections:集合框架工具类,定义都是静态方法
          Collection和Collections的区别?
          Collection是集合框架中一个顶层接口,定义了集合中共性的方法。常用子类口有List和Set
          Collections是集合框架工具类,提供了各种操作集合的静态方法,比如二分法查找、排序、同步方法

常用方法:
        sort(List<T> list):对list集合进行自然排序
        sort(List<T> list, Comparator<? super T> c):用自定义比较器进行排序
        static void swap(List<?> list, int i, int j):交换元素
        reverse(List<?> list):反转指定list集合中的元素
        replaceAll(List<T> list,T oldVal,T newVal):替换list集合中某个值
        reverseOrder():逆转现有比较器的排序方式
        reverseOrder(Comparator<T> com):逆转自定义比较器的排序方式
        shuffle(List<?> list):对list集合中的元素随机产生不同的顺序

       注意:Collection中toArray方法:当需要限定对集合中的元素进行操作时,就把集合转成数组
                  定义转换后数组长度时,如果定义小于原集合的长度,该方法内部会新建一个数组,长度为原集合的长度
                  如果定义大于原集合长度,则不会新建一个数组,直接使用传递进来的集合,但是多余的部分将会是null值

Arrays:用于操作数组的工具类,定义的都是静态方法
        asList:将数组变为list集合
        注意:如果原数组存储的是对象,转换成集合时,数组中的元素就是集合中的元素
                   如果原数组存储的是基本数据类型,转换成集合时,那么会将数组对象作为集合中的元素。
                   将数组转换成集合后,不可以使用集合中增删方法,因为数组的长度是固定的。

可变参数:一定要将可变参数定义在参数列表的最后
代码示例:
class  ParamMethodDemo{public static void main(String[] args) {show("haha",2,3,4,5,6);}public static void show(String str,int... arr){System.out.println(arr.length);}}

静态导入:在导入包时,加上static关键字,导入的是类中静态方法,在调用时,可以省略类名.
       注意:当类重名时,要指定包名。
                  当方法重名时,要指定类名或者对象。
                  




0 0
原创粉丝点击