欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java 类集初探

程序员文章站 2022-06-21 09:32:08
类集 类集:主要功能就是Java数据结构的实现(java.util) 类集就是动态对象数组(链表也是动态数组) Collection 接口 Collection是整个类集之中单值保存的最大 父接口 。即:每一次仅可以向集合中保存一个对象 在Collection定义的常用操作方法 常用操作方法 向集合 ......

类集

  • 类集:主要功能就是java数据结构的实现(java.util)
  • 类集就是动态对象数组(链表也是动态数组)

collection 接口*

  • collection是整个类集之中单值保存的最大 父接口 。即:每一次仅可以向集合中保存一个对象
public interface collection<e>
extends iterable<e>
  • 在collection定义的常用操作方法

常用操作方法

  • 向集合中保存数据
public  boolean add(e e);
  • 追加一个集合
public boolean addall(collection<? extends e>c);
  • 清空集合(根元素为null)
public void clear();
  • 判断是否有指定的内容
public boolean contains(object o);
  • 判断是否为空集合
public boolean isempty();
  • 删除对象
public boolean remove(object o);
  • 取得元素个数
public int size();
  • 以对象数组保存集合
public object [] toarray();
  • 为iterator接口实例化
public iterator<e> iterator();

contains() 和 remove() 一定要依靠 equals() 的支持;

list子接口

  • list子接口是collection接口中最常用的子接口;
  • list对collection接口进行了功能的扩充;

常用操作

  • 取得索引编号的内容
public e get(int index);
  • 修改索引的内容
public e set(int index , e element);
  • 为lisiterator接口实例化对象
public listiterator<e> listiterator();

list属于接口,如果想使用接口进行操作,就必须存在子类;使用 arraylist 子类实现(和vector子类)

arraylist子类

    public static void main(string [] args) throws ioexception {
        list<string> all = new arraylist<string>();
        system.out.println("size:" + all.size() + "null:" + all.isempty());
        all.add("hello");
        all.add("hello");
        all.add("world");
        system.out.println("size:" + all.size() + "null:" + all.isempty());
        // collection接口定义了size()方法取得集合长度
        // list子接口增加了 get() 方法,可取取得所有的数据
        for (int x = 0 ; x < all.size() ; x++) {
            string str = all.get(x);
            system.out.println(str);
        }
    }
}

通过对arraylist()子类的使用分析在:list集合中所保存的数据是按照保存的顺序存放的,而且允许重复数据;list子接口有get()方法,可以获得集合中指定序列的内容

  • 为collection接口实例化
public class testdemo {
    public static void main(string [] args) throws ioexception {
        collection<string> all = new arraylist<string>();
        system.out.println("size:" + all.size() + "null:" + all.isempty());
        all.add("hello");
        all.add("hello");
        all.add("world");
        system.out.println("size:" + all.size() + "null:" + all.isempty());
        object[] obj = all.toarray();//变为对象数组读取数据
        for (int x = 0 ; x < obj.length ; x ++) {
            system.out.println(obj[x].tostring());
        }
        /*for (int x = 0 ; x < all.size() ; x++) {
            string str = all.get(x);// 由于collection类中没有get()方法所以无法使用
            system.out.println(str);
        }*/
    }
}
  • list保存对象
class book {
    private string title ; 
    private double price ;
    public book(string title , double price) {
        this.price = price;
        this.title = title;
    }
    @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 + "\t" + this.price + "\n";
    }
}

public class testdemo {
    public static void main(string [] args) {
        list<book> all = new arraylist<book>();
        all.add(new book("java",11.1));
        all.add(new book("python",22.2));
        all.add(new book("c/c++",33.3));
        all.add(new book("php",44.4));
        // 切记:remove和contains方法需要在类中覆写equls()类
        all.remove(new book("php",44.4));
        system.out.println(all);
    }
}

vector子类(旧)

  • 区别:

    vector子类采用同步处理,线程安全;而arraylist子类则采用非线程安全的异步处理机制。arraylist支持iterator、listiterator、foreach输出,而vector还支持enumeration。

总结:

  • list中的数据保存顺序就是数据的添加顺序
  • list集合中允许保存有重复的元素
  • list子接口比collection扩充了get()、set()方法
  • list大多使用arraylist子类进行操作

set 子接口

set子接口只是简单点额继承了collection接口,并没有效仿list接口对原接口的功能方法进行扩充。

  • 常见子类:hashset、treeset

  • 观察 hashset 子类:

public class testdemo {
    public static void main(string [] args) {
        set<string> all = new hashset<string>();
        all.add("hello");
        all.add("hello");//不保存重复的数据
        all.add("world");
        all.add("huawei");
        system.out.println(all + ">>>" + all.size());
    }
}

通过观察发现:set集合下没有重复的数据元素(set 子接口的特征)即:hashset 子类特征属于 无序排列

  • 观察 treeset子类:
public class testdemo {
    public static void main(string [] args) {
        set<string> all = new treeset<string>();
        all.add("hello");
        all.add("hello");//不保存重复的数据
        all.add("world");
        all.add("array");
        system.out.println(all + ">>>" + all.size());
    }
}

分析得出:treeset子类没有重复数据,以及所保存的内容默认自动升序排序。

数据排序问题

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 string tostring() {
        return this.title + "\t" + this.price;
    }
    /*
     * 集合本质上就是动态对象数组,而动态的对象数组排序使用的是比较器
     * 所以我们使用comparable比较器
     * 
     * 由于存在重复的元素,compareto会认为是同一个对象,(set子接口的特性)
     * 所以 set子接口的重复判读就是依靠comparable
     * 为此我们可以使用string的compareto方法进行同对象的比较
     */
    @override
    public int compareto(book o) {
        if (this.price > o.price) {
            return 1;   
        } else if(this.price < o.price) {
            return -1;
        } else {
            // 我们调用string类的compareto方法来比较
            return this.title.compareto(o.title);
        }
    }
}

public class testdemo {
    public static void main(string [] args) {
        set<book> all = new treeset<book>();
        all.add(new book("java",11.1));
        all.add(new book("java",11.1));     //信息完全重复
        all.add(new book("php",11.1));      //信息部分重复
        all.add(new book("python",33.3));   //信息完全不重复
        system.out.println(all);
    }
}

通过观察发现,comparable接口支持了treeset类的重复数据的判断,并不支持对hashset类的重复数据的判读

重复元素问题

通过上述的各段代码发现:comparable接口(比较器)只负责对treeset子类的重复元素的判断;(依靠comparto()方法,如若发现数据相同则判断为是同样的对象元素,则 return 0;)

如果要判断数据元素的重复,只能依靠object中的方法:

  • 取得哈希码
public int hashcode();
  • 对象比较
public boolean equals(object obj);

代码:

    @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;
    }
  • 总结:

    在不考虑排序问题情况下,判断元素是否重复,依靠object方法中的 hashcode() 和 equals()

总结:

  • 在开发中,set子接口不建议首选,如果使用也是首选建议hashset类;
  • comparable 比较器普遍应用于java理论中

集合输出

collection、list、set三个接口,list接口是最有利于输出操作的(arraylist子类),故此集合的输出:

iterator*:迭代输出

public interface iterator<e> {
    public boolean hasnext();
    public e next<e>();
} 

iterator是一个接口,如若取得接口的实例化需要依靠collection接口iterator()方法

public iterator<e> iterator();// java.util.collection
public class testdemo {
    public static void main(string [] args) {
        set<string> all = new hashset<string>();//set子接口
        all.add("mirror");
        all.add("wangyuyang");
        all.add("wangyuyang");
        iterator<string> iter = all.iterator();// 实例化接口
        while (iter.hasnext()) { //判断是否为空
            string str = iter.next();// 获取元素数据
            system.out.println(str);
        }
    }
}

set的特性会自动不保留重复数据,并无序输出

public class testdemo {
    public static void main(string [] args) {
        list<string> all = new arraylist<string>();//list子接口
        all.add("mirror");
        all.add("wangyuyang");
        all.add("wangyuyang");
        iterator<string> iter = all.iterator();// 实例化接口
        while (iter.hasnext()) { //判断是否为空
            string str = iter.next();// 获取元素数据
            system.out.println(str);
        }
    }
}

显示添加的所有元素并原样添加的顺序输出

  • 集合的输出问题:

    在遇到集合的输出问题是,完全可以直接使用iterator接口进行输出

listiterator:双向迭代

  • iterator本身只具备”由前向后“的输出,而 listlterator 子接口则支持双向迭代。

  • 判断是否有前一个元素:(逆向)

public boolean haspreviout();
  • 取得前一个元素:(逆向)
public e previous();
  • 实例listiterator接口的list方法:
public listiterator<e> listiterator();
public class testdemo {
    public static void main(string [] args) {
        list<string> all = new arraylist<string>();//set子接口
        all.add("a");
        all.add("b");
        all.add("c");
        system.out.println("正向迭代输出");
        listiterator<string> iter = all.listiterator();
        while (iter.hasnext()) { //判断是否为空
            string str = iter.next();// 获取元素数据
            system.out.println(str);
        }
        system.out.println("***********");
        system.out.println("逆向迭代输出");
        while(iter.hasprevious()) {
            system.out.println(iter.previous());
        }
    }
}

上例程序实现了双向迭代的功能;利用hasnet()方法判断是否为空,next()方法输出元素内容,实现正向迭代输出;利用listiterator接口中的hasprevious()和previous()方法来实现逆向迭代输出。

  • 注意:

如果利用listiterator接口实现逆向迭代输出,就需要先进行正向迭代输出;也就是说在实现逆向迭代输出前必须实现正向迭代输出。

enumeration:枚举输出

enumeration 和 vector类同时发布的输出接口;早期的vector类定义的集合就需要enumeration 来输出。

  • 接口定义
public interface enumberation<e>{
    public boolean hasmoreelements(); //判断是否有下一个元素
    public e nextelement(); // 获取当前元素内容
}
  • 实例化 enumeration接口对象,只能依靠 vector子类
public enumeration<e> elements() // 取得enumeration接口对象
public class testdemo {
    public static void main(string [] args) {
        vector<string> all = new vector<string>();//set子接口
        all.add("a");
        all.add("b");
        all.add("c");
        enumeration<string> enu = all.elements();
        while(enu.hasmoreelements()) {
            system.out.println(new string(enu.nextelement()));
        }
    }
}

foreach 输出

public class testdemo {
    public static void main(string [] args) {
        list<string> all = new arraylist<string>();//set子接口
        all.add("a");
        all.add("b");
        all.add("c");
        for (string str : all) {
            system.out.println(str);
        }
    }
}

map接口

collection每次都会保存一个对象,而map接口主要负责一对对象的信息。

主要操作方法

  • 向集合中保存数据
public v put(k key , v value);
  • 根据key查找value
public v get(object key);
  • 将map结合转化为set集合
public set<map entry<k,v>> entryset();
  • 取出所有key值
public set<k> keyset();
  • 常用子类:
    • hashmap
    • hashtable

观察hashmap

public class testdemo {
    public static void main(string [] args) {
        map<string,integer> map = new hashmap<string,integer>();
        map.put("壹", 1);
        map.put("贰", 2);
        map.put("叁", 3);
        map.put("叁", 33);
        system.out.println(map);
    }
}

通过代码分析可以发现:hashmap实现的输出是无序的;发现的重复的key会进行覆盖,使用新的内容key的value覆盖原来的value

  • get方法的应用
public class testdemo {
    public static void main(string [] args) {
        map<string,integer> map = new hashmap<string,integer>();
        map.put("壹", 1);
        map.put("贰", 2);
        map.put(null, 3);
        system.out.println(map.get("壹")); //返回 1
        system.out.println(map.get("陸"));//key不存在返回 null
        system.out.println(map.get(null));// 返回 3
    }
}

通过hashmap和get()方法的代码观察发现,map主要的目的是实现数据的信息的查找,collection主要的目的是实现信息数据的输出。

  • 取得所有的key值:
public class testdemo {
    public static void main(string [] args) {
        map<string,integer> map = new hashmap<string,integer>();
        map.put("壹", 1);
        map.put("贰", 2);
        map.put("叁", 3);
        set<string> set = map.keyset();// 取得key
        iterator<string> iter = set.iterator();
        while(iter.hasnext()) {
            system.out.println(iter.next());//输出全部的key
        }
    }
}

观察hashtable

public class testdemo {
    public static void main(string [] args) {
        map<string,integer> map = new hashtable<string, integer>();
        map.put("壹", 1);
        map.put("贰", 2);
        map.put("叁", 3);
        system.out.println(map);
    }
}

通过设置key或value为null值来比较hashtable和hashmap两个子类之间区别:hashtable子类不允许存在null值,而hashmap允许key或value中为null值。*

iterator输出的问题(重点)

  • 涉及到集合的输出,一定要使用iterator进行输出;而map接口中未定义返回iterator接口对象的方法,故此map数据使用iterator输出就需要将map集合转换为set集合。

  • 在collection接口中,iterator得到的是一个collection完整的对象;而map则不同了,但是map.put()向集合中存一对数据的时候,会自动的封装为map.entry接口对象

public static interface map.entry<k,v>;//(等同于一个外部接口)
  • map.entry接口操作方法
    • getkey():获取key值
    • getvalue():获取value值

在map中保存的实际上是被map.entry接口包装的一个对象,map.entry接口的对象包装的是:key和value值对数据元素。

  • 如上述,iterator如取出输出的数据实取得是一个对象(collection接口中就是实质上取得collection的对象),而在map接口中,则是取出一个map.entry接口对象,然后在得出key和value。
  • 在map定义了一种将map集合转为set的方法:
public set<map.entry<k,v>> entryset();
  • 转为set集合后,就可以调用iterator输出。

  • 利用map接口entryset()方法将map结合变为set集合 ——> 利用set结合中的iterator()方法将set进行iterator输出 ——> 每一次取出的set元素都是map.entrty接口对象,利用此对象进行key与value的取出

利用iterator实现map接口的输出 *

public class testdemo {
    public static void main(string [] args) {
        map<string,integer> map = new hashtable<string, integer>();
        map.put("壹", 1);
        map.put("贰", 2);
        map.put("叁", 3);
        // 将map集合变为set结合
        set<map.entry<string, integer>> set = map.entryset();
        // 将set集合实例化iterator接口对象
        iterator<map.entry<string, integer>> iter = set.iterator();
        while(iter.hasnext()) {
            // 因为iter内容保存的是map.entry接口的对象,所以利用map.entry对象将key和value取出
            map.entry<string, integer> men = iter.next();
            system.out.println(men.getkey() + "==" + men.getvalue());
        }
    }
}

map集合中的key

使用的map集合,key的类型可以自定义;那么这个自定义的类型必须覆写object类之中的hashcode() 和 equals()方法,因为只有依靠这两个方法,才可以判断是否元素重复。【首先的key类型是string,尽量不要使用自定义的对象类型去定义key;因为string类中默认了hashcode() 和 equals()】

class book{
    private string title ; 
    public book(string title) {
        this.title = title;
    }
    @override
    public string tostring() {
        return this.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;
    }
    
}

public class testdemo {
    public static void main(string [] args) {
        map<book,string> map = new hashmap<book, string>();
        map.put(new book("java"),new string ("开发"));
        system.out.println(map.get(new book("java")));
    }
}

或者:

public class testdemo {
    public static void main(string [] args) {
        map<string,book> map = new hashmap<string, book>();
        map.put(new string ("开发"),new book("java"));
        system.out.println(map.get(new string("开发")));
    }
}
public class testdemo {
    public static void main(string [] args) {
        map<string,book> map = new hashmap<string, book>();
        map.put("开发",new book("java"));
        system.out.println(map.get("开发"));
    }
}

总结

  • map集合保存数据更有利与查找,而collection保存数据是为了输出
  • map使用iterator接口输出步骤:……
  • hashmap可以保存null,hashtable不可以保存null。
  • 可以不可以重复,一旦出现重复会覆盖原有内容(更新key的value值)

stack子类

stack 表示:栈操作;栈是一种先进后出的数据结构;而stack是vector的子类。

public class stack<e>
extends vector<e>

需要注意:stack虽是vector子类,可是不会使用vector方法。

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("a");
        all.push("b");
        all.push("c");
        all.push("d");
        system.out.println(all.pop());
        system.out.println(all.pop());
        system.out.println(all.pop());
        system.out.println(all.pop());
    }
}

如果栈中数据已经全部执行出栈而依旧继续执行出栈pop操作,则报错:空栈异常(栈中无数据则无法出栈执行操作)

properties子类

collections工具类

  • 向集合中追加一组数据
public static <t> boolean addall(collection<e> c,……);
public class testdemo {
    public static void main(string [] args) {
        list<string> all = new arraylist<string>();
        collections.addall(all, "a","b","c","d");
        system.out.println(all);
    }
}

collections工具类是负责给集合操作接口collection提供辅助的操作方法