java集合框架

3 集合框架

3.1 ArrayList

使用数组的局限性

如果要存放多个对象,可以使用数组,但是数组有局限性
比如 声明长度是10的数组
不用的数组就浪费了
超过10的个数,又放不下

ArrayList存放对象

为了解决数组的局限性,引入容器类的概念。 最常见的容器类就是 
ArrayList 
容器的容量"capacity"会随着对象的增加,自动增长 

3.1.1常用方法

增加

public class IOTest {

public static void main(String[] args){

    ArrayList al=new ArrayList();

    al.add(5);

    System.out.println(al);  // [5]

}

}

判断是否存在

通过方法contains 判断一个对象是否在容器中
判断标准: 是否是同一个对象,而不是name是否相同

获取指定位置的对象

通过get获取指定位置的对象,如果输入的下标越界,一样会报错

获取对象所处的位置

indexOf用于判断一个对象在ArrayList中所处的位置
contains一样,判断标准是对象是否相同,而非对象的name值是否相等

删除

remove用于把对象从ArrayList中删除
remove可以根据下标删除ArrayList的元素

替换

set用于替换指定位置的元素

获取大小

public class IOTest {

public static void main(String[] args){

    ArrayList al=new ArrayList();

    System.out.println(al.size()); // 0

    al.add(5);

    System.out.println(al);  // [5]

    System.out.println(al.size());  // 1

}

}

转换为数组

toArray可以把一个ArrayList对象转换为数组

把另一个容器所有对象都加进来

addAll 把另一个容器所有对象都加进来

清空

public class IOTest {

public static void main(String[] args){

    ArrayList al=new ArrayList();

    al.add(5);

    System.out.println(al);  // [5]

    al.clear();

    System.out.println(al.size()); // 0

}

}

3.1.2 List接口

ArrayList实现了接口List
常见的写法会把引用声明为接口List类型
注意:是java.util.List,不是java.awt.List

List al=new ArrayList();

3.1.3泛型 Generic

泛型 Generic

不指定泛型的容器,可以存放任何类型的元素
指定了泛型的容器,只能存放指定类型的元素以及其子类

List<Object> list=new ArrayList<Object>();

// 不过JDK7提供了一个可以略微减少代码量的泛型简写方式

       List<Object> list=new ArrayList<>();

3.1.4 遍历

用for循环遍历

迭代器遍历

public class Test {

    public static void main(String[] args) {

       // 不过JDK7提供了一个可以略微减少代码量的泛型简写方式

       List<Object> list=new ArrayList<>();

       list.add(10);

       list.add(20);

       list.add(30);

       System.out.println(list);  // [10,20,30]

       // 通过迭代器遍历

        Iterator<Object> it=list.iterator();

       while(it.hasNext()){

           Object l=it.next();

           System.out.println(l); // 10 20 30

       }

    }

}

用增强型for循环 foreach遍历

public class Test {

    public static void main(String[] args) {

       // 不过JDK7提供了一个可以略微减少代码量的泛型简写方式

       List<Object> list=new ArrayList<>();

       list.add(10);

       list.add(20);

       list.add(30);

       System.out.println(list);  // [10,20,30]

       // 通过foreach遍历

       for (Object object : list) {

           System.out.println(object); // 10 20 30

       }

    }

}

3.2 LinkedList

序列分先进先出FIFO,先进后出FILO 
FIFO在Java中又叫Queue 队列 
FILO在Java中又叫Stack 栈

3.2.1 LinkedList 与 List接口

ArrayList一样,LinkedList也实现了List接口,诸如add,remove,contains等等方法。

双向链表 – Deque

除了实现了List接口外,LinkedList还实现了双向链表结构Deque,可以很方便的在头尾插入删除数据

队列 – Queue

LinkedList 除了实现了List和Deque外,还实现了Queue接口(队列)。
Queue是先进先出队列 FIFO,常用方法:
offer 在最后添加元素
poll 取出第一个元素
peek 查看第一个元素

3.3 二叉树

二叉树概念

二叉树由各种节点组成
二叉树特点:
每个节点都可以有左子节点,右子节点
每一个节点都有一个

二叉树排序-插入数据

假设通过二叉树对如下10个随机数进行排序
67,7,30,73,10,0,78,81,10,74
排序的第一个步骤是把数据插入到该二叉树中
插入基本逻辑是,小、相同的放左边大的放右边

public class Node {

    // 左子节点

    public Node leftNode;

    // 右子节点

    public Node rightNode;

    //

    public Object value;

    // 插入 数据

    public void add(Object v) {

        // 如果当前节点没有值,就把数据放在当前节点上

        if (null == value)

            value = v;

     // 如果当前节点有值,就进行判断,新增的值与当前值的大小关系

        else {

            // 新增的值,比当前值小或者相同

            if ((Integer) v -((Integer)value) <= 0) {

                if (null == leftNode)

                    leftNode = new Node();

                leftNode.add(v);

            }

            // 新增的值,比当前值大

            else {

                if (null == rightNode)

                    rightNode = new Node();

                rightNode.add(v);

            }

        }

    }

    public static void main(String[] args) {

        int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };

        Node roots = new Node();

        for (int number : randoms) {

            roots.add(number);

        }

    }

}

二叉树排序-遍历

通过上一个步骤的插入行为,实际上,数据就已经排好序了。 接下来要做的是看,把这些已经排好序的数据,遍历成我们常用的List或者数组的形式
二叉树的遍历分左序,中序,右序
左序即: 中间的数遍历后放在左边
中序即: 中间的数遍历后放在中间
右序即: 中间的数遍历后放在右边
如图所见,我们希望遍历后的结果是从小到大的,所以应该采用中序遍历

public class Node {

    // 左子节点

    public Node leftNode;

    // 右子节点

    public Node rightNode;

    //

    public Object value;

    // 插入 数据

    public void add(Object v) {

        // 如果当前节点没有值,就把数据放在当前节点上

        if (null == value)

            value = v;

     // 如果当前节点有值,就进行判断,新增的值与当前值的大小关系

        else {

            // 新增的值,比当前值小或者相同

            if ((Integer) v -((Integer)value) <= 0) {

                if (null == leftNode)

                    leftNode = new Node();

                leftNode.add(v);

            }

            // 新增的值,比当前值大

            else {

                if (null == rightNode)

                    rightNode = new Node();

                rightNode.add(v);

            }

        }

    }

 // 中序遍历所有的节点

    public List<Object> values() {

        List<Object> values = new ArrayList<>();

        // 左节点的遍历结果

        if (null != leftNode)

            values.addAll(leftNode.values());

        // 当前节点

        values.add(value);

        // 右节点的遍历结果

        if (null != rightNode)

            values.addAll(rightNode.values());

        return values;

    }

    public static void main(String[] args) {

        int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };

        Node roots = new Node();

        for (int number : randoms) {

            roots.add(number);

        }

        System.out.println(roots.values());

    }

}

3.4 HashMap

HashMap的键值对

HashMap储存数据的方式是—— 键值对

public class Test {

    public static void main(String[] args){

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

       hm.put("name","Tom");

       hm.put("age","18");

       System.out.println(hm.get("name")); //Tom

       System.out.println(hm.get("age"));  // 18

    }

}

键不能重复,值可以重复

对于HashMap而言,key是唯一的,不可以重复的。 
所以,以相同的key 把不同的value插入到 Map中会导致旧元素被覆盖,只留下最后插入的元素。 
不过,同一个对象可以作为值插入到map中,只要对应的key不一样

3.5 HashSet

Set中的元素,不能重复

Set中的元素,没有顺序。 
严格的说,是没有按照元素的插入顺序排列
HashSet的具体顺序,既不是按照插入顺序,也不是按照hashcode的顺序。

public class Test {

    public static void main(String[] args){

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

       hs.add(10);

       System.out.println(hs); // [10]

    }

}

Set不提供get()来获取指定位置的元素 
所以遍历需要用到迭代器,或者增强型for循环

HashSet和HashMap的关系

可以发现HashSet自身并没有独立的实现,而是在里面封装了一个Map.
HashSet是作为Map的key而存在的
而value是一个命名为PRESENT的static的Object对象,因为是一个类属性,所以只会有一个。

3.6 Collection

Collection是 Set List Queue和 Deque的接口
Queue: 先进先出队列
Deque: 双向链表
注:Collection和Map之间没有关系,Collection是放一个一个对象的,Map 是放键值对的
注:Deque 继承 Queue,间接得继承了 Collection

3.7 Collections

Collections是一个类,容器的工具类,就如同Arrays是数组的工具类

反转

reverse 使List中的数据发生翻转

Collections.reverse();

混淆

shuffle 混淆List中数据的顺序

Collections.shuffle();

排序

sort 对List中的数据进行排序

 Collections.sort(numbers);

交换

swap 交换两个数据的位置

Collections.swap(numbers,0,5);

滚动

rotate 把List中的数据,向右滚动指定单位的长度

Collections.rotate(numbers,2);

线程安全化

synchronizedList 把非线程安全的List转换为线程安全的List

Collections.synchronizedList(numbers);

3.8 ArrayList与HashSet

ArrayList: 有顺序
HashSet: 无顺序

List中的数据可以重复
Set中的数据不能够重复
重复判断标准是:
首先看hashcode是否相同
如果hashcode不同,则认为是不同数据
如果hashcode相同,再比较equals,如果equals相同,则是相同数据,否则是不同数据

3.9 ArrayList和LinkedList

ArrayList 插入,删除数据慢
LinkedList, 插入,删除数据快
ArrayList是顺序结构,所以定位很快,指哪找哪。 就像电影院位置一样,有了电影票,一下就找到位置了。
LinkedList 是链表结构,就像手里的一串佛珠,要找出第99个佛珠,必须得一个一个的数过去,所以定位慢

public class TestCollection {

    public static void main(String[] args) {

        List<Integer> l;

        l = new ArrayList<>();

        insertFirst(l, "ArrayList");

        l = new LinkedList<>();

        insertFirst(l, "LinkedList");

    }

    private static void insertFirst(List<Integer> l, String type) {

        int total = 1000 * 100;

        final int number = 5;

        long start = System.currentTimeMillis();

        for (int i = 0; i < total; i++) {

            l.add(0, number);

        }

        long end = System.currentTimeMillis();

        System.out.printf("在%s 最前面插入%d条数据,总共耗时 %d 毫秒 %n", type, total, end - start);

    }

}

定位数据

public class TestCollection {

    public static void main(String[] args) {

        List<Integer> l;

        l = new ArrayList<>();

        modify(l, "ArrayList");

        l = new LinkedList<>();

        modify(l, "LinkedList");

    }

    private static void modify(List<Integer> l, String type) {

        int total = 100 * 1000;

        int index = total/2;

        final int number = 5;

        //初始化

        for (int i = 0; i < total; i++) {

            l.add(number);

        }

        long start = System.currentTimeMillis();

        for (int i = 0; i < total; i++) {

             int n = l.get(index);

             n++;

             l.set(index, n);

        }

        long end = System.currentTimeMillis();

        System.out.printf("%s总长度是%d,定位到第%d个数据,取出来,加1,再放回去%n 重复%d遍,总共耗时 %d 毫秒 %n", type,total, index,total, end - start);

        System.out.println();

    }

}

3.10 HashMap和Hashtable的区别

HashMap和Hashtable的区别

HashMap和Hashtable都实现了Map接口,都是键值对保存数据的方式
区别1: 
HashMap可以存放 null
Hashtable不能存放null
区别2:
HashMap不是
线程安全的类
Hashtable是线程安全的类

3.11 HashSet LinkedHashSet TreeSet

HashSet: 无序
LinkedHashSet: 按照插入顺序
TreeSet: 从小到大排序

public class TestCollection {

    public static void main(String[] args) {

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

        //HashSet中的数据不是按照插入顺序存放

        numberSet1.add(88);

        numberSet1.add(8);

        numberSet1.add(888);

        System.out.println(numberSet1);

        LinkedHashSet<Integer> numberSet2 =new LinkedHashSet<Integer>();

        //LinkedHashSet中的数据是按照插入顺序存放

        numberSet2.add(88);

        numberSet2.add(8);

        numberSet2.add(888);

        System.out.println(numberSet2);

        TreeSet<Integer> numberSet3 =new TreeSet<Integer>();

        //TreeSet 中的数据是进行了排序的

        numberSet3.add(88);

        numberSet3.add(8);

        numberSet3.add(888);

        System.out.println(numberSet3);

    }

}

3.12 hashcode原理

hashcode概念
所有的对象,都有一个对应的hashcode(散列值)

List查找的低效率

HashMap的性能表现快

这是一种用空间换时间的思维方式

HashSet判断是否重复

HashSet判断是否重复

HashSet的数据是不能重复的,相同数据不能保存在一起,到底如何判断是否是重复的呢?
根据HashSet和HashMap的关系,我们了解到因为HashSet没有自身的实现,而是里面封装了一个HashMap,所以本质上就是判断HashMap的key是否重复。
再通过上一步的学习,key是否重复,是由两个步骤判断的:
hashcode是否一样
如果hashcode不一样,就是在不同的坑里,一定是不重复的
如果hashcode一样,就是在同一个坑里,还需要进行equals比较
如果equals一样,则是重复数据
如果equals不一样,则是不同数据

3.13 Comparator比较器

假设Hero有三个属性 name,hp,damage
一个集合中放存放10个Hero,通过Collections.sort对这10个进行排序
那么到底是hp小的放前面?还是damage小的放前面?Collections.sort也无法确定
所以要指定到底按照哪种属性进行排序
这里就需要提供一个Comparator给定如何进行两个对象之间的大小比较

Comparable

使Hero类实现Comparable接口
在类里面提供比较算法
Collections.sort就有足够的信息进行排序了,也无需额外提供比较器Comparator

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值