黑马程序员-----笔记整理(java基础十----集合)

---------------------- android培训java培训、期待与您交流! ----------------------  

       抓紧整理完睡觉吧,脑瓜子有点发蒙的感觉。

集合 

 1.0 集合特点: 
 1.1 Object 
 1.2 集合框架的工具类 
 1.3 泛型 
 1.4 集合使用技巧 
 1.5 foreach 
 集合练习 

    下边的挨个介绍一下吧:

集合 

集合类的由来:对象用于封装特有数据,对象多了就需要存储,如果对象的个数不确定,就使用集合容器进行存储。

 1.0 集合特点: 

存储对象,长度可变.可进行增删改查

 1.1 Object  

|----- Collection接口

1.方法: 

添加

boolean    add(Object obj);

boolean    addAll(Collection coll)

删除

boolean    remove(Object obj);  集合的remove会改变集合的长度。

boolean    removeAll(Collection coll); 将两个集合中的相同元素从调用removeAll的集合中删除。

void  clear();

判断

boolean     contains(Object obj);

boolwan    containsAll(Collection coll); 是否包含另外一个集合里面所有的元素。

boolean isEmpty();判断集合中是否有元素。

获取

int   size();

 Iterator iterator();取出元素的方式:迭代器

迭代器: 对象必须依赖于具体的容器,因为每个容器的数据结构都不同。所以该迭代器对象是在容器中进行内部实现的。

对于使用容器者而言,具体的实现不重要,只要通过容器获取到该实现的迭代器的对象即可,也就是iterator方法。

Iterator接口就是对所有的Collection容器进行元素去除的公共接口。

使用Collcetion中的iterator()方法。调用集合中的迭代器方法,是为了获取集合中的迭代器对象。

其他

boolean     retainAll(Collection coll); 取交集。与removeAll相反,保留和指定集合相同的元素,而删除不同的元素

Object [ ] toArray(); 将集合转成数组。

|-----------List 

有序(存入和取出的顺序一致),元素都有索引(角标),元素可以重复。具有增删改查 

特有常见方法:有一个共性特点就是都可以操作角标。

添加

void     add( index,element)

void   add(index,collection);

删除

Object      remove(index);

修改

Object      set(index,element);

获取:

Object        get(index) //List特有的取出方式之一。

int      indexOf(object)

int      laseIndexOf(object)

List    subList(from,to)//包含头,不包含尾

List特有的取出方式代码:

      for(int x = 0;x<list.size();x++){

           System.out.println(list.get(x));

    }

 

List集合是可以完成对元素的增删改查。

|----------------Arraylist

内部是数据数据结构,是不同步的。替代了Vector。查找元素的速度很快

练习:

练习:用ArrayList删除里面重复的元素。

importjava.util.ArrayList;

importjava.util.Iterator;

 

public class ArrayListTest2 {

    public static void main(String[] args) {

       ArrayList a1 = newArrayList();

       a1.add("abc1");

       a1.add("abc2");

       a1.add("abc3");

       a1.add("abc4");

       a1.add("abc5");

       a1.add("abc2");

       a1.add("abc3");

       a1 = getSingleElement(a1);

       Iterator it = a1.iterator();

       while(it.hasNext()){

           System.out.println(it.next());

       }

    }

 

    public static ArrayList getSingleElement(ArrayList a1) {

       ArrayList temp = newArrayList();

       Iterator it = a1.iterator();

       while(it.hasNext()){

           Object obj = it.next();

           if(!temp.contains(obj)){

              temp.add(obj);

           }

       }

       return temp;

    }

}

 

 

练习二:需求:同姓名同年龄视为同一个人,视为重复元素。去除同一元素。

Person类中的equals方法继承Object,判断相同的依据是Person对象的地址值。

为了按照指定的条件来判断Person对象是否相同,必须覆盖equals方法。

 

public class Person {

    private Stringname;

    private int age;

    public Person() {

       super();

    }

    public Person(String name,int age) {

       super();

       this.name = name;

       this.age = age;

    }

    public String getName() {

       returnname;

    }

    @Override

    public boolean equals(Object obj) {//因为所有的类都继承了Objectequals方法,所以要进行向下转型

       //记住要加健壮性的判断,如果传的不是Person直接让程序挂掉

       if(!(objinstanceof Person))

           throw new ClassCastException("类型错误");

       Person p = (Person)obj;

       return this.name.equals(p.name) &&this.age==p.age;

    }

    public void setName(String name) {

       this.name = name;

    }

    public int getAge() {

       returnage;

    }

    public void setAge(int age) {

       this.age = age;

    }

    @Override

    public String toString() {//覆盖toString方法是为了让集合迭代器打印的不是对象的哈希值(地址值)。

       return"Person :"+name+" "+age;

    }   

 

importjava.util.ArrayList;

importjava.util.Iterator;

 

importbeen.Person;

 

public class ArrayListTest {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       ArrayList a = newArrayList();

       a.add(new Person("lisi1",21));

       a.add(new Person("lisi2",22));

       a.add(new Person("lisi3",23));

       a.add(new Person("lisi4",24));

       a.add(new Person("lisi3",23));

       a.add(new Person("lisi4",24));

       

       a = getSingleElement(a);

       

       Iterator it = a.iterator();

       while(it.hasNext()){

           System.out.println(it.next());

       }

    }

 

    public static ArrayList getSingleElement(ArrayList a) {

       //定义一个临时的集合容器

       ArrayList temp = newArrayList();

       Iterator it = a.iterator();

       while(it.hasNext()){

           //取出的元素都是对象

           Object obj = it.next();

           //进行判断,如果临时的集合容器有这个元素对象,就不进行存储

           //没有的话就进行存储。

           if(!temp.contains(obj))

              temp.add(obj);

       }

       //返回这个临时集合容器

       return temp;

    }

}

注意:

ArrayList:当自定义对象进行取出时,一定要先进行向下转型。

ArrayList:判断里面元素是否相同,用的是对象所属的equals方法来判断是否包含。

removecontains方法其实都是依赖于对象的equals方法来判断是否相同,相同即包含。


|----------------Linkedlist

内部是链表数据结构,是不同步的。增删元素的速度很快。

常见方法:


addFirst();

addLast();

JDK1.6

offerFirst();

offetLast();

 

getFirst();获取但不移除,如果链表为空,抛出NoSuchElementException.

getLast();

JDK1.6

peekFirst();获取但不移除,如果链表为空,返回null

peekLastt();

 

removeFirst();//获取并移除,如果链表为空,抛出NoSuchElementException

removeLast();

JDK1.6

pollFirst();//获取并移除,如果链表为空,返回null。

pollLast();

面试题:

请使用用LinkedList,来模拟一个对战或者队列数据结构。

 

堆栈:先进后出。 First In Last out FIFO

 

队列:先进先出。 First In First Out FIFO

 

应该描述这样一个容器,给使用提供一个容器对象完成者两种结构中的一种。

堆栈表现形式:

packageit.cast_01;

 

importjava.util.LinkedList;

 

public class DuiLie {

    private LinkedList link;

    public DuiLie(){

       link = newLinkedList();

    }

    public void myAdd(Object obj){

       link.add(obj);

    }

    public Object myGet(){

       returnlink.removeLast();//如果要改成队列,link.removeFirst()

    }

    public boolean isNull(){

       returnlink.isEmpty();

    }

}

 

 

 

packageit.cast_01;

 

public class DuiLieZhanDemo {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       DuiLie d = new DuiLie();

       d.myAdd("haha");

       d.myAdd("hehe");

       d.myAdd("xixi");

       d.myAdd("hiahia");

       while(!d.isNull()){

           System.out.println(d.myGet());

       }

    }

}


|----------------Vector

内部是数组数据结构,是同步的。增删,查询都很慢! 

Enumeration接口

此接口的功能与Iterator接口的功能是重复的,Iterator接口添加了一个可选的移除操作,并使用较短的方法名。

扩展:Arraylists和linkedlist区别:

因为Arraylist是数组结构可以通过角标操作集合里面的元素,但是linkedlist是链表结构只能操作头和尾上的元素。但是有人会问?List集合不是有序的吗?此时的有序是想相对于存入

和取出是一致的。怎样放就怎样取,ArrayList是连续的空间,而linkedlist是不连续的空间。

依角标查询是依然一个一个的向下询问。



|-----------Set

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

set集合的底层就是map集合

|----------------TreeSet

TreeSet:是二叉树结构其实就是二分查找,对已有的有序元素进行折半,再确定新元素的位置。二叉树其实就是看的返回值,对象比较的大小。

二叉树结构示意图:


如果要按照怎么存入就怎么取出元素,上图可以看出,比顶层大的元素都在右边,只要在比较器里面的compare里面返回1就行。二叉树具体是看对象比较的返回值。

 

示例代码:

importjava.util.Comparator;

 

public class ComparatorByName implementsComparator {

    /**

     * 创建了一个根据Person类的name进行排序的比较器

     */

    @Override

    public int compare(Object o1, Object o2) {

       Person p1 = (Person)o1;

       Person p2 = (Person)o2;

    /*  int temp = p1.getName().compareTo(p2.getName());

       return temp==0?p1.getAge()-p2.getAge():temp;*/

       return 1;

    }


|----------------hashSet

 


 

  |-----Map集合

Map:一次添加一对元素。Collection一次添加一个元素。

Map也称为双列集合,Collection集合称为单列集合。

其实Map集合中存储的就是键值对。

Map集合中必须保证键的唯一性。

Map常用方法:

添加

value put(key,value); 返回前一个和key关联的值,如果没有返回null

删除

void  clear(); 清空map集合

value remove(key); 根据指定的key删除这个键值对

判断

boolean    containsKey(key);

boolean    containsVaule(value);

         boolean isEmpty();

获取

value   get(key); 通过键获取值,如果没有该键返回null。

                               当然可以通过返回null,来判断是否包含指定键。

         int    size(); 获取键值对的个数。

|---------Hashmap

底层数据结构是哈希表,线程不同步,可以存入null键值。要保证键的唯一性,需要覆盖hashCode()方法和equals()方法

|----------LinkedHashMap

该子类基于哈希表又融入链表,可以使map集合增删时提高效率,

怎么存入就怎么取出元素


|---------Hashtable

底层结构是哈希表数据结构,线程是同步,不可以存入null键值对。效率较低,被hashmap锁替代

|-----------Properties

用来存储键值对型的配置文件的信息,可以和IO技术相结合

|---------Treemap

底层是二叉树结构,可以对map集合中的键进行排序。需要使用comparable或者comparator进行排序。

思考:

如果有映射关系应该最先想到数组,然后在思考这个映射关系是否是有序的,如果没有序的话就应该考虑到Map集合,因为Map集合存储的是键值对,映射关系是不需要有序的

 1.2 集合框架的工具类 

该类中的方法都是静态的。

|-------Arrays

List asList(数组)将数组转成集合

如果数组中的元素是对象,那么转成集合时,直接将数组中的元素作为集合中的元素进行集合存储。

如果数组中的元素是基本类型数值,那么会将该数组作为集合中的元素进行存储。

 

 

将数组转成集合!

            好处:可以使用集合中非方法操作数组中的元素

            注意:数组的长度是固定的,所以对于集合的增删方法是不可以使用的

            否则会发生UnsupportedOperationException    

 

            如果数组中的元素是对象,那么转成集合时,直接将数组中的元素作为集合中的元素进行集合存储

 

            如果数组中的元素是基本数据类型数值,那么就会将该数组作为集合中的元素进行存储


|-------Collections

reverseOrder()  获取一个比较器,用于反转集合中的内容  

reverse(List<?> list)  反转

fill(List,T obj)  将集合中的元素一次性全部替换

shuffle(list);   随机把这些元素安放在任意位置上

 

给非同步的集合加锁  synchronizedList(List list)

 

 

使用的就是Collection借口中的toArray方法。

集合转成数组:可以对集合中的元素操作的方法进行限定。不允许对其进行增删。

toArray方法需要传入一个指定类型的数组。

长度该如何定义呢?

如果长度小于集合的size,那么该方法会创建一个同类型并和集合相同的size的数组。

如果长度大于集合的size,那么该方法就会使用指定的数组,存储集合中的元素,其他位置默认为null。

所以建议,最后长度就指定为集合的长度size()





 1.3 泛型 


 泛型<>什么时候用:


当操作的引用数据类型不确定的时候,就使用<>泛型,将要操作的引用数据类型传入即可。其实<>就是一个用于接收具体引用数据类型的参数范围。

在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型。

将泛型定义在方法上:public <W> void show(W str)

当方法静态时,不能访问类上定义的泛型,如果静态方法使用泛型,只能将泛型定义在方法上。如:public static<Y> void show(Y obj);

注意:泛型必须放在修饰符后面返回值的前面。

 

泛型接口,将泛型定义在接口上。

示例代码:

public class GenericDemo2 {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       Imple1 in1 = new Imple1();

       in1.show("haha");

       Imple2<Integer> in2 = new Imple2<Integer>();

       in2.show(new Integer(5));

    }

 

}

interfaceInter<T>{

    public void show(T t);

}

 

class Imple1 implements Inter<String>{

    public void show(String str){

       System.out.println("show  "+str);

    }

}

//如果实现接口也不知道传什么类型的话就自定义

classImple2<Q> implements Inter<Q>{

    public void show(Q q){

       System.out.println("show  "+q);

    }

}

泛型的擦除于补偿:(作为了解)

注意细节:

泛型技术是给编译器使用的技术,用于编译时期,确保了类型的安全。

运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除。

为什么擦除呢?因为为了兼容运行的类的加载器。

 

泛型的补偿:在运行时,通过获取元素的类型进行转换动作。不用使用者再强制转换了。


泛型的通配符:

泛型的通配符:未知类型。

 

 

示例代码:

importjava.util.ArrayList;

importjava.util.Collection;

importjava.util.HashSet;

importjava.util.Iterator;

 

public class GenericDemo3 {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       ArrayList<String> al1 = new ArrayList<String>();

       al1.add("haha");

       al1.add("xixi");

       HashSet<Integer> hs = new HashSet<Integer>();

       hs.add(new Integer(5));

       hs.add(new Integer(6));

       

       printCollection(al1);

       printCollection(hs);

    }

    public static void printCollection(Collection<?> al1) {

       //如果打印的集合多,直接用父类的接口大集合作为参数类型

       //如果打印的多个集合的类型不同,可以用通配符?的形式来表示

       Iterator<?> it = al1.iterator();

       while(it.hasNext()){

           System.out.println(it.next());

       }

    }

}


泛型类型限定:

可以对类型进行限定:? extends E :接收E类型或者E的子类型对象。叫上限。

                                               ? super E: 接收E类型或者E的父类型。 叫下限。

上限示例代码:

importjava.util.ArrayList;

importjava.util.Collection;

importjava.util.Iterator;

 

import bean.Person;

importbean.Student;

importbean.Worker;

 

public class GenericDemo4 {

    public static void main(String[] args) {

       ArrayList<Worker> al1 = new ArrayList<Worker>();

       al1.add(new Worker("工人2",20));

       al1.add(new Worker("工人4",40));

       ArrayList<Student> al2 = new ArrayList<Student>();

       al2.add(new Student("小明1",20));

       al2.add(new Student("小四4",24));

       printCollection(al1);

       printCollection(al2);

    }

 

    public static void printCollection(Collection<? extends Person> al1) {

       Iterator<? extends Person> it = al1.iterator();

       while(it.hasNext()){

           System.out.println(it.next());

       }

    }

}

 

什么时候使用上限呢?

一般在存储元素的时候都使用上限,因为这样取出都是按照上限类型来运算的,不会出现类型安全隐患。

 

注意:迭代器的泛型百分之百和获取迭代器对象集合的泛型一致。

 

什么时候使用下限?

通常对集合中的元素进行取出操作时,可以使用下限。

 

下限代码示例

importjava.util.ArrayList;

importjava.util.Collection;

import java.util.Iterator;

 

importbean.Person;

importbean.Student;

importbean.Worker;

 

public class GenericDemo5 {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       ArrayList<Worker> al1 = new ArrayList<Worker>();

       al1.add(new Worker("工人1",10));

       al1.add(new Worker("工人3",30));

       ArrayList<Student> al2 = new ArrayList<Student>();

       al2.add(new Student("小明1",20));

       al2.add(new Student("小明4",30));

       ArrayList<Person> p2 = new ArrayList<Person>();

       p2.add(new Person("人民1",40));

       p2.add(new Person("人民2",59));

       printCollection(al1);

       printCollection(p2);

//     printCollection(al2);

    }

    public static void printCollection(Collection<? super Worker> al1) {

       Iterator<? super Worker> it = al1.iterator();

       while(it.hasNext()){

           System.out.println(it.next());

       }

    }

}


 

 1.4 集合使用技巧

集合查阅的一些技巧:

需要唯一吗?

需要:Set

         需要制定顺序:

                            需要:TreeSet

                            不需要:HashSet

                            但是想要一个和存储一致的顺序(有序):LinkedHashSet

 

不需要:List

         需要频繁增删吗?

                   需要:LinkedList

                   不需要:ArrayList

 

如何记录每一个容器的结构和所属体系呢?

看名字!

List

         |----ArrayList

         |----LinkedList

Set

         |----HashSet

         |----TreeSet

后缀名就是该集合的所属的体系。

前缀名就是该集合的数据结构。

看到array:就要想到数组,就要想到查询快,有角标。

看到link:就要想到链表,就要像到增删快,就要想到 add  get remove+first last 的方法

看到hash:就要想到哈希表,就要想到唯一性,就要想到元素需要覆盖hashcode方法和equals方法。

看到tree:就要想到二叉树,就要想到排序,就要想到两个接口Comparable,Comparator。

 

而且通常这些常用的集合容器都是不同步的。

 

 1.5 foreach 

foreach语句:

格式: for(类型 变量:Collection集合|数组)

          {

 

          }

传统for和高级for的区别?

传统for可以完成对语句执行很多次,因为可以定义控制循环的增量和条件。

高级for是一种简化形式。

它必须有被便利的目标。该目标要么是数组,要么是Collection单列集合。

对于数组的遍历如果仅仅是获取数组中的元素,可以使用高级for。

如果要对数组的角标进行操作,建议使用传统for。

 

可以使用高级for遍历Map集合吗?

不能直接用,但是可以将Map转成单列的Set集合,就可以用了。

 

函数的可变参数。

其实就是一个数组,但是收的是数组的元素。

自动将这些元素封装成数组。简化了调用者的书写。

注意:可变参数类型,必须定义在参数列表的结尾


 集合练习 

练习需求:

 * "fdgavcbsacdfs" 获取该字符串中,每一个字母出现的次数。

 * 要求打印结果是:a(2)b(1)...;

 

 

importjava.util.Iterator;

importjava.util.Map;

importjava.util.TreeMap;

 

/*

 * 练习

 * "fdgavcbsacdfs" 获取该字符串中,每一个字母出现的次数。

 * 要求打印结果是:a(2)b(1)...;

 * 思路:

 * 对于结果的分析发现,字母和次数之间存在着映射关系。而且这种关系很多。

 * 很多就需要存储,能存储映射关系的容器有数组和Map集合。

 * 关系一方式中是有序编号吗?有就使用数组,没有!那就是使用Map集合。

 * 又发现可以保证唯一性的一方具备着顺序如a b c.....

 * 所以可以使用TreeMap集合。

 * 

 * 这个集合中应该存储的是字母和次数的对应关系。

 * 

 * 1,因为操作的是字符串中的字母,所以先将字符串变成一个字符数组。

 * 2,遍历字符数组,用每一个字母作为键去查Map集合这个表。

 * 如果该字母键不存在,就将该字母作为键1作为值存储到Map集合中,代表出现一次。

 * 如果该字母键存在,就将该字母键对应值取出并自增,再将该字母和自增后的值存储到Map集合中,

 * 键相同值会覆盖,这样就记录住了该字母的次数。

 * 3,遍历结束,Map集合就记录所有字母的出现的次数。

 */

public class MapTest1 {

 

 

    /**

     * @param args

     */

    

    public static void main(String[] args) {

       String s = "fdgavcbsacdfs";

       String str = getCharCount(s);

       System.out.println(str);

    }

 

    public static String getCharCount(String s) {

       //将字符串变成数组

       char []  ch = s.toCharArray();

       //建立Map集合,通过循环来记录住出现的字符和次数来对Map集合查表,没有出现的字符就存储,出现的字符就继续自增value值

       //看输出的结果是有序的打印,因此可以用TreeMap来完成

       Map<Character,Integer> map = new TreeMap<Character,Integer>();

       for (int i = 0; i < ch.length; i++) {

           Integer value = map.get(ch[i]);

           if(value==null){

              map.put(ch[i], 1);

           }

           else

              map.put(ch[i], value+1);

           

       }

       return mapToString(map);

    }

 

    private static String mapToString(Map<Character, Integer> map) {

       StringBuilder sb = new StringBuilder();

       Iterator<Character> it = map.keySet().iterator();

       while(it.hasNext()){

           Character key = it.next();

           Integer value = map.get(key);

           sb.append(key+"("+value+")");

       }

       return sb.toString();

    }

}

 

 

 

练习:

将"asjd+    5568a sd SAAA Aas77dfffwe"字母出现的次数打印出来

要求打印结果是:a(2)b(1)...;

 

 

importjava.util.Iterator;

importjava.util.Map;

importjava.util.TreeMap;

 

public class MapTest3 {

 

    /*

     * 需求:

     * "asjd    5568a sd SAAA Aas77dfffwe"获取该字符串中,每一个字母出现的次数

     * 要求打印结果是:a(2)b(1)...;

     */

    /**

     * @param args

     */

    public static void main(String[] args) {

       String str = "asjd+    5568a sd SAAA Aas77dfffwe";

       String s = getCharCount(str);

       System.out.println(s);

    }

 

    public static String getCharCount(String str) {

       //将字符串变成数组

       char [] chs = str.toCharArray();

       //建立以个Map集合,通过循环来查询Map集合表。

       Map<Character,Integer> map = new TreeMap<Character,Integer>();

       for (int i = 0; i < chs.length; i++) {

           //判断一下,如果不大于或等于里面里面的字符就不打印,排除了里面的符号和空格

           if(!(chs[i]>='a' && chs[i]<='z' || chs[i]>='A' && chs[i]<='Z'))

              continue;

           Integer value = map.get(chs[i]);

           if(value==null){

              map.put(chs[i],1);

           }else{

              map.put(chs[i], value+1);

           }

           

       }

       return mapToString(map);

    }

 

    private static String mapToString(Map<Character, Integer> map) {

       StringBuilder sb = new StringBuilder();

       Iterator<Character> it = map.keySet().iterator();

       while(it.hasNext()){

           Character key = it.next();

           Integer value = map.get(key);

           sb.append(key+"("+value+")");

       }

       return sb.toString();

    }

 

}


---------------------- android培训java培训、期待与您交流! ----------------------  

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值