第十三章 Java类集框架

第十三章 Java类集框架

13.1 类集概念

类集在整个Java中最为核心的用处就在于其实现了动态对象数组的操作,并且定义了大量的操作标准。

在整个类集框架中,其核心接口为:Collection、List、Set、Map、Iterator、Enumeration。

13.2 单对象保存父接口:Collection

即每次利用Collection接口都只能保存一个对象信息。

核心方法

NO.方法名称类型描述
1public boolean add(E e)普通向集合里面保存数据
2public boolean add.All(Collection<?extends E>c)普通追加一个集合
3public void clear()普通清空集合,根元素为null
4public boolean contains(Object o)普通判断是否包含指定的内容,需要equals()支持
5public boolean isEmpty()普通判断是否是空集合(不是null)
6public boolean remove(Object o)普通删除对象,需要equals()支持
7public int size()普通取得集合中保存的元素个数
8public Object[] toArray()普通将集合变为对象数组保存
9public Iteratoriterator()普通为Iterator接口实例化

在所以方法中最重要的就是add()和iterator()两个方法,同时在使用contains()与remove()两个方法的操作时,必须保证类中已经成功地覆写了Object类中的equals()方法。

13.3 List子接口

里面所保存的数据可以存在重复内容

扩充的方法

public E get(int index):取得索引编号的内容

public E set(int index,E element):修改指定索引编号的内容

public ListIteratorlistIterator():为ListIterator接口实例化

13.3.1 新的子类:ArrayList

List基本操作

public class TestDemo {
    public static void main(String[] args) throws Exception {
        List<String>all=new ArrayList<String>();
        System.out.println("长度:"+all.size()+",是否为空:"+all.isEmpty());
        all.add("Hello");
        all.add("Hello");
        all.add("World");
        System.out.println("长度:"+all.size()+",是否为空:"+all.isEmpty());
        for (int x=0;x<all.size();x++){
            String str=all.get(x);
            System.out.println(str);
        }
    }
}

常见面试题

数组(Array)与数组列表(ArrayList)有什么区别?什么时候应该使用Array而不使用ArrayList?

数组Array中保存的内容是固定的,而数组列表(ArrayList)中保存的内容是可变的。在很多时候(ArrayList)进行数据保存与取得时需要一系列的判断,而如果是数组Array只需要操作索引即可。

如果在已经确定好长度的前提下,完全可以使用数组(Array)来替代数组列表,但是如果集合框架保存的数据内容长度是不固定的,那么就使用ArrayList。

在集合里面保存对象

import java.io.Serializable;
public class Book implements Serializable {
    private String title;
    private double price;
    public Book(String title,double price){
        this.title=title;
        this.price=price;
    }
    @Override
    public boolean equals(Object obj){
        if (this==obj){
            return true;
        }
        if (obj==null){
            return false;
        }
        if (!(obj instanceof Book)){
            return false;
        }
        Book book=(Book) obj;
        if (this.title.equals(book.title)&&this.price==book.price){
            return true;
        }
        return false;
    }
    @Override
    public String toString(){
        return "书名:"+this.title+"价格:"+this.price;
    }
}
public class TestDemo {
    public static void main(String[] args) {
        List<Book>all=new ArrayList<Book>();
        all.add(new Book("Java实战项目",19.9));
        all.add(new Book("Jav实战项目",29.9));
        all.add(new Book("Ja实战项目",39.9));
        all.remove(new Book("朱小东自传",89.5));
        System.out.println(all);
    }
}

instanceof

instanceof是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。

这里说明下:

类的实例包含本身的实例,以及所有直接或间接子类的实例

instanceof左边显式声明的类型与右边操作元必须是同种类或存在继承关系,也就是说需要位于同一个继承树,否则会编译错误

请解释ArrayList和LinkedList的区别

  • ArrayLis中采用顺序式的结果进行数据的保存,并且可以自动生成相应的索引信息。
  • LinkedList集合保存的是前后元素,也就是说像链表一样的结构。

13.3.2 旧的子类:Vector

public class TestDemo {
    public static void main(String[] args) {
        List<String>all=new Vector<String>();
        System.out.println("长度:"+all.size()+",是否为空:"+all.isEmpty());
        all.add("Hello");
        all.add("Hello");
        all.add("World");
        System.out.println("长度:"+all.size()+",是否为空:"+all.isEmpty());
        for (int x=0;x<all.size();x++){
            String str=all.get(x);
            System.out.println(str);
        }
    }
}

13.4 Set子接口

Set子接口只是简单地继承了Collection接口,在Set子接口里面无法使用get()方法根据索引取得保存数据的操作。

两个子类

  • HashSet:散列存放数据
  • TreeSet:有序存放数据

13.4.1 关于数据排序的说明

TreeSet子类保存的内容可以进行排序,但是其排序是依靠比较器接口(Comparable)实现的。

利用TreeSet保存自定义类对象

public class Book implements Comparable<Book> {
    private String title;
    private double price;
    public Book(String title,double price){
        this.title=title;
        this.price=price;
    }
    @Override
    public int compareTo(Book o){
        if (this.price>o.price){
            return 1;
        }else if (this.price<o.price){
            return -1;
        }else {
            return this.title.compareTo(o.title);
        }
    }
    @Override
    public String toString(){
        return "书名:"+this.title+"价格:"+this.price+"\n";
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Set<Book> all=new TreeSet<Book>();
        all.add(new Book("java实战项目",79.8));
        all.add(new Book("Jsp实战项目",55.5));
        all.add(new Book("java实战项目",79.8));
        all.add(new Book("朱小东自传",55.5));
        System.out.println(all);
    }
}

13.4.2 关于重复元素说明

如果HashSet要消除重复元素,则必须依靠Object类中提供的两个方法。

  • 取得哈希码:public int hashCode();(先判断对象的哈希码是否相同,依靠哈希码取得一个对象的内容)
  • 对象比较:public boolean equals(Object obi)(再将对象的属性进行依次的比较)

利用Has和Set子类保存自定义类对象

public class Book {
    private String title;
    private double price;
    public Book(String title,double price){
        this.title=title;
        this.price=price;
    }
    @Override
    public int hashCode(){
        final int prime=31;
        int result=1;
        long temp;
        temp=Double.doubleToLongBits(price);
        result=prime*result+(int)(temp^(temp>>>32));
        result=prime*result+((title==null)?0:title.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;
        }
        Book other = (Book) obj;
        if (Double.doubleToLongBits(price) != Double.doubleToLongBits(other.price))
            return false;
        if (title == null) {
            if (other.title != null)
                return false;
        } else if (!title.equals(other.title))
            return false;
        return true;
    }
    @Override
    public String toString(){
        return "书名:"+this.title+"价格:"+this.price+"\n";
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Set<Book> all=new HashSet<Book>();
        all.add(new Book("java实战项目",79.8));
        all.add(new Book("Jsp实战项目",55.5));
        all.add(new Book("java实战项目",79.8));
        all.add(new Book("朱小东自传",55.5));
        System.out.println(all);
    }
}

在进行非排序集合操作时,只要是判断重复元素依靠的永远都是hashCode()与equals().

13.5 集合输出

集合的输出操作有4种形式:Iterator输出、ListIterator输出、foreach输出、Enumeration输出。

13.5.1 迭代输出:Iterator

hasNext():判断是否还有内容

next():取出当前内容

使用Iterator输出集合

public class TestDemo {
    public static void main(String[] args) {
        List<String>all=new ArrayList<String>();
        all.add("Hello");
        all.add("Hello");
        all.add("World");
        Iterator<String>iter=all.iterator();
        while (iter.hasNext()){
            String str=iter.next();
            System.out.println(str);
        }
    }
}

13.5.2 双向迭代:Listlterator

hasPrevious():判断是否有前一个元素

previous:取出前一个元素

add(E e):向集合追加数据

set(E e):修改集合数据

在实际开发中一般使用Iterator接口

ListIterator是专门为List子接口定义的输出接口,所以ListIterator接口对象的实例化可以依靠List接口提供方法。

public class TestDemo {
    public static void main(String[] args) {
        List<String>all=new ArrayList<String>();
        all.add("Hello");
        all.add("You");
        all.add("World");
        System.out.println("有前向后输出:");
        ListIterator<String>iter=all.listIterator();
        while (iter.hasNext()){
            String str=iter.next();
            System.out.println(str+"、");
        }
        System.out.println("\n由后向前输出:");
        while (iter.hasPrevious()){
            String str=iter.previous();
            System.out.println(str+"、");
        }
    }
}

13.5.3 foreach输出

public class TestDemo {
    public static void main(String[] args) {
        List<String>all=new ArrayList<String>();
        all.add("Hello");
        all.add("You");
        all.add("World");
        for(String str:all){
            System.out.println(str);
        }
    }
}

13.5.4 Enumeration输出

如何要利用集合类为Enuemration接口实例化,就必须依靠Vector子类完成。

public class TestDemo {
    public static void main(String[] args) {
        Vector<String>all=new Vector<String>();
        all.add("Hello");
        all.add("You");
        all.add("World");
        Enumeration<String>enu=all.elements();
        while (enu.hasMoreElements()){
            String str=enu.nextElement();
            System.out.println(str);
        }
    }
}

13.6 偶对象保存:Map接口

Map的特点

  • 使用HashMap定义的Map集合是无序存放的;
  • 如果发现了重复的key会进行覆盖,使用新的内容替换旧的内容。
  • 使用HashMap子类保存数据时key或value可以保存为null。
  • Map保存数据的目的并不是进行输出操作,而是为了进行查找,即利用get()方法通过key找到对应的value数据。

Map接口的常用方法

public V put(K key,V vaule):向集合中保存数据

public V get(Object key):根据key查找对应的value数据

public Set<Map.Entry<K,V>>entrySet():将Map集合转化为Set集合。

public SetkeySet:取出全部的key

HashMap的使用

public class TestDemo {
    public static void main(String[] args) {
        Map<String,Integer>map=new HashMap<String,Integer>();
        map.put("哈",1);
        map.put("哈",1);
        map.put("哈哈",null);
        map.put("null",1);
        map.put("哈哈哈",5);
        map.put("哈哈哈哈",null);
        System.out.println(map.keySet());
        System.out.println(map);
        System.out.println(map.get("哈"));
    }
}

Collection接口数据是为了输出,Map接口数据是为了查询。

使用Hashtable

public class TestDemo {
    public static void main(String[] args) {
        Map<String,Integer>map=new Hashtable<String,Integer>();
        map.put("哈",1);
        map.put("哈哈",null);
        map.put(null,1);
        map.put("哈哈哈",5);
        map.put("哈哈哈哈",null);
        System.out.println(map.get("哈"));
    }
}

常见面试题分析

区别点HashMapHashtable
推出时间JDK1.2推出,属于新类JDK1.0时推出,属于旧的类
性能采用异步处理采用同步处理
数据安全非线程安全线程安全
设置null允许key或value为空不允许设置null

13.6.1 利用Iterator输出Map集合

用Map集合保存数据时,所保存的key与value会自动包装为Map.Entry接口对象,也就是说如果利用Iterator进行迭代,那么每当使用next()方法读取数据时返回的都是一个Map.Entry接口对象。

常用方法

getKey():取得数据中的key

getValue():取得数据中的value

setValue(V value):修改数据中的value

public class TestDemo {
    public static void main(String[] args) {
        Map<String,Integer>map=new Hashtable<String,Integer>();
        map.put("哈",1);
        map.put("哈哈",null);
        map.put(null,1);
        map.put("哈哈哈",5);
        map.put("哈哈哈哈",null);
        Set<Map.Entry<String,Integer>>set=map.entrySet();
        Iterator<Map.Entry<String,Integer>>iter=set.iterator();
        while (iter.hasNext()){
            Map.Entry<String,Integer>me=iter.next();
            System.out.println(me.getKey()+"="+me.getValue());
        }
    }
}

13.6.2 自定义Map集合的key类型

使用自己定义的类作为Map集合的key

public class Book {
    private String title;
    public Book(String title){
        this.title=title;
    }
    @Override
    public int hashCode(){
        final int prime=31;
        int result=1;
        result=prime*result+((title==null)?0:title.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;
        }
        Book other = (Book) obj;
        if (title == null) {
            if (other.title != null)
                return false;
        } else if (!title.equals(other.title))
            return false;
        return true;
    }
    @Override
    public String toString(){
        return "书名:"+this.title;
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Map<Book,String >map=new HashMap<Book,String>();
        map.put(new Book("java开发"),new String("java"));
        System.out.println(map.get(new Book("java开发")));
    }
}

13.7 Stack子类

Stack属于一种栈的操作

public E push(E item):数据入栈

public E pop():数据出栈,如果栈中没有数据,则调用此方法会抛出空栈异常。

观察栈的操作

public class TestDemo {
    public static void main(String[] args) {
        Stack<String>all=new Stack<String>();
        all.push("www.baidu.com");
        all.push("www.jiangli.com");
        all.push("www.douban.com");
        System.out.println(all.pop());
        System.out.println(all.pop());
        System.out.println(all.pop());
        System.out.println(all.pop());
    }
}

如果栈中没有任何数据时,进行出栈将会抛出异常,EmptyStackException。

13.8 Properties子类

此子类只能保存字符串类型的数据

public Object setProperty(String key,String value):设置属性

public String getProperty(String key):取得属性,如果key不存在则返回null。

public String getProperty(String key,String defaultValue):取得属性,如果key不存在则返回默认值

public void store(OutputStream out,String comments)throws IOException:通过输出流保存属性内容,输出的同时可以设置注释信息。

public void load(InputStream inStream)throws IOException:通过输入流读取属性内容

属性的基本操作

public class TestDemo {
    public static void main(String[] args) {
        Properties pro=new Properties();
        pro.setProperty("BJ","北京");
        pro.setProperty("TJ","天津");
        System.out.println(pro.getProperty("BJ"));
        System.out.println(pro.getProperty("GZ"));
        System.out.println(pro.getProperty("GZ","没有此记录"));
    }
}

将属性信息保存在文件里

public class TestDemo {
    public static void main(String[] args) throws Exception {
        Properties pro=new Properties();
        pro.setProperty("BJ","北京");
        pro.setProperty("TJ","天津");
        System.out.println(pro.getProperty("BJ"));
        System.out.println(pro.getProperty("GZ"));
        System.out.println(pro.getProperty("GZ","没有此记录"));
        pro.store(new FileOutputStream(new File("d:"+File.separator+"hhh.properties")),"Area Info");
    }
}

通过文件流读取属性内容

public class TestDemo {
    public static void main(String[] args) throws Exception {
        Properties pro=new Properties();
        pro.load(new FileInputStream(new File("d:"+File.separator+"hhh.properties")));
        System.out.println(pro.getProperty("BJ"));
    }
}

Properties类与ResourceBundle类使用那个更好?

Properties可以读取任意输入流,ResourceBundle类要结合国际化读取*.prperties文件。

如果是国际文件用ResourceBundle,配置信息则用Properties。

13.9 Collections工具类

常用方法

public static < T >boolean addAll(Collection<?super T>c,T…elements):实现集合数据追加

public static < T >int binarySearch(List<?extends Comparable<? super T>>list,T key):使用二分查找法查找集合数据

public static < T >void copy(LIst <?super T>dest,List <?extends T>src):集合复制

public static void reverse(List <?>list):集合反转

public static <T extends Comparable<? super T>>void sort (List list):集合排序

public class TestDemo {
    public static void main(String[] args) throws Exception {
        List<String>all=new ArrayList<String>();
        //利用Collections类的方法向集合保存多个数据
        Collections.addAll(all,"jijij","dfaf","dfafdsa","dfafasd");
        Collections.reverse(all);       //反转
        System.out.println(all);
    }
}

Collection与Collections的区别

  • Collection是集合操作的接口

  • Collections:是集合操作的工具类

13.10 数据流

13.10.1 数据流基础操作

Stream接口常用方法

NO.方法类型描述
1public long count()普通返回元素个数
2public Streamdistinct()普通消除重复元素
3public <R,A>R collect(Collector<? super T,A,R>collector)普通利用收集器接收处理后的数据
4public Stream< T>filter(Predicate<?super T>predicate)普通数据过滤(设置断言型函数式接口)
5public < R >Stream < R >map(Function<? super T,? extends R>mapper)普通数据处理操作(设置功能型函数接口)
6public Stream < T >skip (long n)普通设置跳过的数据行树
7public Stream < T >limit (long maxSize)普通设置取出的数据个数
8public boolean allMatch(Preadicate <? super T>predicate)普通数据查询,要求全部匹配
9public boolean anyMatch(Predicate <? super T>predicate)普通数据查询,匹配任意一个
10default Predicate < T > or(Predicate<? super T>other)普通或操作
11default Predicate < T > and(Predicate<? super T>other)普通与操作

利用forEach()方法输出

public class TestDemo {
    public static void main(String[] args) throws Exception {
       List<String>all=new ArrayList<String>();
       all.add("www.baidu.com");
       all.add("www.xiaomi.com");
       all.add("www.bilibili.com");
       all.forEach(System.out::println);
    }
}

取得Stream对象

首先利用stream()方法将集合转化为数据流的形式,然后利用Stream类中的count()方法取得了数据流中所保存的元素个数。

public class TestDemo {
    public static void main(String[] args) throws Exception {
       List<String>all=new ArrayList<String>();
       all.add("www.baidu.com");
       all.add("www.xiaomi.com");
       all.add("www.bilibili.com");
       Stream<String> stream=all.stream();
       System.out.println(stream.count());
    }
}

取消集合中的重复数据

public class TestDemo {
    public static void main(String[] args) throws Exception {
       List<String>all=new ArrayList<String>();
       all.add("www.baidu.com");
        all.add("www.baidu.com");
        all.add("www.xiaomi.com");
       all.add("www.bilibili.com");
       Stream<String> stream=all.stream();
       //去掉重复数据后形成新的List集合数据,里面不包含重复内容的集合
        List<String>newAll=stream.distinct().collect(Collectors.toList());
        newAll.forEach(System.out::println);
    }
}

利用filter()方法针对数据流中的数据进行数据过滤的操作,在执行过滤时需要设置一个断言型函数式接口的方法引用。

数据过滤

如何集合中包含“t”则满足过滤条件

public class TestDemo {
    public static void main(String[] args) throws Exception {
       List<String>all=new ArrayList<String>();
       all.add("www.baidu.com");
       all.add("www.AHJHH.com");
        all.add("www.baidu.com");
        all.add("www.xiaomi.com");
       all.add("www.bilibili.com");
       Stream<String> stream=all.stream();
       //去掉重复数据后形成新的List集合数据,里面不包含重复内容的集合,对每条数据统一转为小写
        List<String>newAll=stream.distinct().map((x)->x.toLowerCase())
                .filter((x)->x.contains("b")).collect(Collectors.toList());
        newAll.forEach(System.out::println);
    }
}

实现数据流数据的分页操作

此时只需要使用skip()与limit()两个方法控制即可

public class TestDemo {
    public static void main(String[] args) throws Exception {
       List<String>all=new ArrayList<String>();
       all.add("www.JIXIANIT.com");
       all.add("www.yootk.com");
        all.add("www.yootk.com");
        all.add("www.mldn.com");
        all.add("www.mldn.com");
       Stream<String> stream=all.stream();
       //去掉重复数据后形成新的List集合数据,里面不包含重复内容的集合,对每条数据统一转为小写
        List<String> newAll=stream.distinct().map((x)->x.toLowerCase())
                .filter((x)->x.contains("t")).skip(1).limit(1).collect(Collectors.toList());
        newAll.forEach(System.out::println);
    }
}

实现数据的匹配查询

public class TestDemo {
    public static void main(String[] args) throws Exception {
       List<String>all=new ArrayList<String>();
       all.add("www.JIXIANIT.com");
       all.add("www.yootk.com");
        all.add("www.yootk.com");
        all.add("www.mldn.com");
        all.add("www.mldn.com");
       Stream<String> stream=all.stream();
       if (stream.anyMatch((x)->x.contains("yootk"))){
           System.out.println("数据存在!");
       }
    }
}

不管使用allMatch()或anyMatch()方法,都只能接收一种数据验证条件,如果要同时匹配多个条件,则可以利用or()或and()方法实现逻辑操作。

设置多个条件

public class TestDemo {
    public static void main(String[] args) throws Exception {
       List<String>all=new ArrayList<String>();
        all.add("www.baidu.com");
        all.add("www.AHJHH.com");
        all.add("www.baidu.com");
        all.add("www.xiaomi.com");
        all.add("www.bilibili.com");
        Predicate<String> p1=(x)->x.contains("baidu");
        Predicate<String> p2=(x)->x.contains("bilibili");
       Stream<String> stream=all.stream();
       if (stream.anyMatch(p1.or(p2))){
           System.out.println("数据存在!");
       }
    }
}

13.10.2 MapReduce

  • public < R > Stream < R > map(Function<? super T,?extends R>mapper):数据处理方法
  • public Optional< T > reduce(BinaryOperator< T >accumulator):数据分析方法。

实现一个MapReduce

public class TestDemo {
    public static void main(String[] args) throws Exception {
       List<Orders>all=new ArrayList<Orders>();
       //添加购买记录
        all.add(new Orders("java开发",22.33,300));
        all.add(new Orders("web开发",32.33,200));
        all.add(new Orders("毛泽东自传",222.33,150));
        all.add(new Orders("数据结构",42.33,160));
        //输出每一个商品的总价
        all.stream().map((x)->x.getAmount()*x.getPrice()).forEach(System.out::println);
    }
}
  • getCount():求和
  • getAverage():求平均值
  • getCount():求数量
  • getMax():求最大值
  • getMain():求最小值
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值