Java基础2——集合框架

Collection和Map是集合的顶层接口

先看Collection,这个接口定义了以下方法:

添加功能:

  boolean add(Object obj):添加一个元素

  boolean addAll(Collection c):添加一个集合的元素

删除功能

  void clear():移除所有元素

  boolean remove(Object o):移除一个元素

  boolean removeAll(Collection c):移除一个集合的元素(是一个还是所有)

判断功能

  boolean contains(Object o):判断集合中是否包含指定的元素

  boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(是一个还是所有)

  boolean isEmpty():判断集合是否为空

获取功能

  Iterator<E> iterator()(重点)

长度功能

  int size():元素的个数

  面试题:数组有没有length()方法呢?字符串有没有length()方法呢?集合有没有length()方法呢?

交集功能

  boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?

把集合转换为数组

  Object[] toArray()

List和Set是Collection集合的两个子接口

  List是一个有序的队列,每一个元素都有它的索引,第一个元素的索引值是0

  ArrayList、Vector、LinkedList、Stack是List的四个实现类,其中比较常用的是ArrayList(线性表)、LinkedList(链表)

  Set是一个不允许有重复元素的集合

  Set的实现类有HastSet和TreeSet,其中比较常用的是HashSet

Collection通用方法举例

        Collection c=new ArrayList();
        Student s1=new Student("aaa",15);
        Student s2=new Student("bbb",16);
        Student s3=new Student("ccc",17);
        Student s4=new Student("ddd",18);
        Student s5=new Student("eee",19);
        Student s6=new Student("fff",20);
        //添加一个或多个元素
        c.add(s1);
        c.add(s2);
        //========
        Collection c1=new ArrayList();
        c1.add(s3);
        c1.add(s4);
        c.addAll(c1);
        //========
        Collection c2=new ArrayList();
        c2.add(s5);
        c2.add(s6);
        c.addAll(c2);
        //========
        
        //移除一个或多个元素
        c.remove(s1);
        c.removeAll(c1);
        
        //查看某个元素是否存在于集合中
        System.out.println(c.contains(s2));
        System.out.println(c.containsAll(c2));
        
        //判断集合是否为空
        System.out.println(c.isEmpty());
        
        //判断集合中有几个元素
        System.out.println(c.size());
        
        //集合转数组 此处不可以用Student[]类型来接收,存入集合的元素都将变成Object类型的
        Object[] objs=c.toArray();
        
        //清空集合
        c.clear();
        
        //迭代遍历
        Iterator it=c.iterator();
        while(it.hasNext()){
            Student s=(Student)it.next();
            System.out.println(s.name+" "+s.age);
        }

List集合特有的功能

/*
         * List集合的特有功能:
         * A:添加功能
         *         void add(int index,Object element):在指定位置添加元素
         * B:获取功能
         *         Object get(int index):获取指定位置的元素
         * C:列表迭代器
         *         ListIterator listIterator():List集合特有的迭代器
         * D:删除功能
         *         Object remove(int index):根据索引删除元素,返回被删除的元素
         * E:修改功能
         *         Object set(int index,Object element):根据索引修改元素,返回被修饰的元素
         */
        Student s1=new Student("aaa",15);
        Student s2=new Student("bbb",16);
        Student s3=new Student("ccc",17);
        Student s4=new Student("ddd",18);
        Student s5=new Student("eee",19);
        Student s6=new Student("fff",20);
        List list=new ArrayList();
        list.add(s1);
        list.add(s2);
        
        //在指定位置添加元素,位置可以是0 1 2,否则会报IndexOutOfBoundsException越界异常
        list.add(0,s3);
        list.add(3,s4);
        
        //获取到指定位置的元素
        Student s=(Student)list.get(2);
        System.out.println(s.name+" "+s.age);
        
        //删除指定索引的元素
        list.remove(0);
        
        //设置指定位置的元素
        list.set(0, s5);
        
        System.out.println("-----------------");
        //其实这里可以通过ListIterator实现遍历
        //而且ListIterator可以实现逆向遍历,但是必须先正向遍历,才能逆向遍历,所以一般无意义,不使用
        Iterator it=list.iterator();
        while(it.hasNext()){
            Student ss=(Student)it.next();
            System.out.println(ss.name+" "+ss.age);
        }
        /*
         * 问题?
         *         我有一个集合,如下,请问,我想判断里面有没有"world"这个元素,如果有,我就添加一个"javaee"元素,请写代码实现。
         * 
         * ConcurrentModificationException:当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。 
         * 产生的原因:
         *         迭代器是依赖于集合而存在的,在判断成功后,集合的中新添加了元素,而迭代器却不知道,所以就报错了,这个错叫并发修改异常。
         *         其实这个问题描述的是:迭代器遍历元素的时候,通过集合是不能修改元素的。
         * 如何解决呢?
         *         A:迭代器迭代元素,迭代器修改元素
         *             元素是跟在刚才迭代的元素后面的。
         *         B:集合遍历元素,集合修改元素(普通for)
         *             元素在最后添加的。
         */
        List list=new ArrayList();
        list.add("hello");
        list.add("world");
        list.add("java");
        for (int x = 0; x < list.size(); x++) {
            String s = (String) list.get(x);
            if ("world".equals(s)) {
                list.add("javaee");
            }
        }
        System.out.println("list:" + list);

ArrayList里面没有什么特有的功能

LinkedList特有的功能

  A:添加功能
    public void addFirst(Object e)
    public void addLast(Object e)
  B:获取功能
    public Object getFirst()
    public Obejct getLast()
  C:删除功能
    public Object removeFirst()
    public Object removeLast()

数组中必须存放同种类型的元素,那想要约束一个集合必须存储同种类型的元素就要用到泛型,集合中的泛型只能是引用类型

泛型可以把运行时的错误提前到编译期,同时避免了强制从Object到特定类型的类型转换,同时在Eclipse中也没有黄色的警告线了

ArrayList<String> array = new ArrayList<String>();
array.add("hello");
array.add("world");
array.add("java");
Iterator<String> it = array.iterator();
while (it.hasNext()) {
    String s = it.next();//不必强转
    System.out.println(s);
}

泛型类

如下代码:早期的时候,我们使用Object来代表任意的类型。向上转型是没有任何问题的,但是在向下转型的时候其实隐含了类型转换的问题。也就是说这样的程序其实并不是安全的。

public class ObjectTool {
    private Object obj;

    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) { // Object obj = new Integer(30);
        this.obj = obj;
    }
}
public class ObjectToolDemo {
    public static void main(String[] args) {
        ObjectTool ot = new ObjectTool();

        // 正常使用
        ot.setObj(new Integer(27));
        Integer i = (Integer) ot.getObj();
        System.out.println("年龄是:" + i);

        ot.setObj(new String("林青霞"));
        String s = (String) ot.getObj();
        System.out.println("姓名是:" + s);

        System.out.println("---------");
        ot.setObj(new Integer(30));
        // ClassCastException 出异常了
        String ss = (String) ot.getObj();
        System.out.println("姓名是:" + ss);
    }
}

所以Java在JDK5后引入了泛型,提高程序的安全性:

public class ObjectTool<T> {
    private T obj;

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}
public class ObjectToolDemo {
    public static void main(String[] args) {
        ObjectTool<String> ot = new ObjectTool<String>();
        // ot.setObj(new Integer(27)); //这个时候编译期间就过不去
        ot.setObj(new String("林青霞"));
        String s = ot.getObj();
        System.out.println("姓名是:" + s);

        ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
        // ot2.setObj(new String("风清扬"));//这个时候编译期间就过不去
        ot2.setObj(new Integer(27));
        Integer i = ot2.getObj();
        System.out.println("年龄是:" + i);
    }
}

泛型还可以用于方法和接口

泛型方法

上面的泛型类有一个很不好的地方就是setObj的参数的类型只能是和ObjectTool里面的泛型类一样的类的类型,这样就很不灵活,所以产生了泛型方法

public class ObjectTool {
    public <T> void show(T t) {
        System.out.println(t);
    }
}
public class ObjectToolDemo {
    public static void main(String[] args) {
        // 定义泛型方法后
        ObjectTool ot = new ObjectTool();
        ot.show("hello");
        ot.show(100);
        ot.show(true);
    }
}

ObjectTool类本身还可以有泛型,例如ObjectTool<Boolean>,ObjectTool本身的泛型类型和它里面的成员方法的泛型类型没有任何关系

泛型接口

public interface Inter<T> {
    public abstract void show(T t);
}
//第一种情况:已经知道该是什么类型的了,用的很少
public class InterImpl implements Inter<String> {
    public void show(String t) {
        System.out.println(t);
    }
}
//第二种情况:还不知道是什么类型的,用的很多
public class InterImpl<T> implements Inter<T> {
    public void show(T t) {
        System.out.println(t);
    }
}
public class InterDemo {
    public static void main(String[] args) {
        // 第一种情况的测试
        Inter<String> i = new InterImpl();
        i.show("hello");
    
        // 第二种情况的测试
        Inter<Integer> ii = new InterImpl<Integer>();
        ii.show(100);

        Inter<String> iii = new InterImpl<String>();
        iii.show("hello");
    }
}

泛型通配符

/*
 * 泛型高级(通配符)
 * ?:任意类型,如果没有明确,那么就是Object以及任意的Java类了
 * ? extends E:向下限定,E及其子类
 * ? super E:向上限定,E极其父类
 */
public class GenericDemo {
    public static void main(String[] args) {
        // 泛型如果明确的写的时候,前后必须一致
        Collection<Object> c1 = new ArrayList<Object>();
        // Collection<Object> c2 = new ArrayList<Animal>();
        // Collection<Object> c3 = new ArrayList<Dog>();
        // Collection<Object> c4 = new ArrayList<Cat>();

        // ?表示任意的类型都是可以的
        Collection<?> c5 = new ArrayList<Object>();
        Collection<?> c6 = new ArrayList<Animal>();
        Collection<?> c7 = new ArrayList<Dog>();
        Collection<?> c8 = new ArrayList<Cat>();

        // ? extends E:向下限定,E及其子类
        // Collection<? extends Animal> c9 = new ArrayList<Object>();
        Collection<? extends Animal> c10 = new ArrayList<Animal>();
        Collection<? extends Animal> c11 = new ArrayList<Dog>();
        Collection<? extends Animal> c12 = new ArrayList<Cat>();

        // ? super E:向上限定,E极其父类
        Collection<? super Animal> c13 = new ArrayList<Object>();
        Collection<? super Animal> c14 = new ArrayList<Animal>();
        // Collection<? super Animal> c15 = new ArrayList<Dog>();
        // Collection<? super Animal> c16 = new ArrayList<Cat>();
    }
}

class Animal {
}

class Dog extends Animal {
}

class Cat extends Animal {
}

JDK1.5新特性——可变参

/*
 * 可变参数:定义方法的时候不知道该定义多少个参数
 * 格式:
 *         修饰符 返回值类型 方法名(数据类型…  变量名){
 * 
 *         }
 * 
 *         注意:
 *             这里的变量其实是一个数组
 *             如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个
 */
public ArgsTest{
    public static void main(String args[]){
        int r=sum(10,20,30);
        System.out.println(r);
    }
    public static int sum(int... a){
        int sum=0;
        for(int i:a){
            sum+=a[i];
        }
        return sum;
    }
}

Arrays.asList传入可变参作为参数

/*
 * public static <T> List<T> asList(T... a):把数组转成集合
 * 
 * 注意事项:
 *         虽然可以把数组转成集合,但是集合的长度不能改变。
 */
public class ArraysDemo {
    public static void main(String[] args) {
        // 定义一个数组
        // String[] strArray = { "hello", "world", "java" };
        // List<String> list = Arrays.asList(strArray);

        List<String> list = Arrays.asList("hello", "world", "java");
        // UnsupportedOperationException
        // list.add("javaee");
        // UnsupportedOperationException
        // list.remove(1);
        list.set(1, "javaee");

        for (String s : list) {
            System.out.println(s);
        }
    }
}

以上是List集合的相关类及其方法的总结,List集合是有序的,即存和取的顺序是一致的,List集合里面的元素可以重复

Set集合是无序的,存和取的顺序不一致,而且取的时候不保证顺序永久不变,但是作为集合来说,它肯定有自己的存储顺序,Set集合里面的元素是唯一的

Set的一个很重要的实现类是HashSet

此外还有LinkedHashSet,该类的底层数据结构由哈希表和链表组成,哈希表保证元素的唯一性,链表保证元素有顺序,即存进去和取出来的元素顺序相同

Collection和Collections的区别

Collection:是单列集合的顶层接口,有子接口List和Set。
Collections:是针对集合操作的工具类,有对集合进行排序和二分查找的方法

要知道的方法
public static <T> void sort(List<T> list):排序 默认情况下是自然顺序。
public static <T> int binarySearch(List<?> list,T key):二分查找
public static <T> T max(Collection<?> coll):最大值
public static void reverse(List<?> list):反转
public static void shuffle(List<?> list):随机置换

同Collection并列的还有另外一个顶层集合接口——Map

Map中存储的是键值对,类似js里面的json

Map<String,String> hm = new HashMap<String,String>();

hm.put("it002","hello");
hm.put("it003","world");
hm.put("it001","java");

//方式1 键找值 set是键的集合
Set<String> set = hm.keySet();
for(String key : set) {
    String value = hm.get(key);
    System.out.println(key+"---"+value);
}

//方式2 键值对对象找键和值 set2是键值对的集合
Set<Map.Entry<String,String>> set2 = hm.entrySet();
for(Map.Entry<String,String> me : set2) {
    String key = me.getKey();
    String value = me.getValue();
    System.out.println(key+"---"+value);
}
原文地址:https://www.cnblogs.com/zhaohuiziwo901/p/5010876.html