java集合


title: java集合
date: 2018-12-16 15:54:20
updated: 2020-03-15 16:26:00
categories: java
tags:
- java


此文档为java集合的学习总结

集合框架

Collection接口:
	
	List接口:有序,可以重复
		ArrayList(主要实现类)
		LinkedList(频繁的插入、删除操作)
		Vector(古老的实现类,线程安全)
	
	Set接口:无序、不可重复
		HashSet(主要实现类)
		LinkedHashSet(使用链表维护了添加元素顺序,可以有序遍历,但底层存储元素还是hash无序的)
		TreeSet(可以按照添加进集合中的元素的指定顺序遍历)
	
Map接口:存储key-value对
		HashMap、LinkedHashMap、TreeMap、HashTable(-Properties)
		
两个排序接口:
	自然排序:实现Comparable接口重写compareTo()方法
	定制排序:创建TreeSet时传入Comparator对象
	

ArrayList

将Employee[]数组替换成ArrayList后:

不必指出数组的大小

使用add将任意多的元素添加到数组中

使用size()替代length计算元素的数目

使用a.get(i)替代a[i]访问元素

ArrayList<>尖括号中的类型参数不允许是基本类型。即不允许写成ArrayList,而只能用Integer对象包装器类ArrayList list = new ArrayList<>();

ArrayList<>与数组之间的转换

  • 1.数组转ArrayList–直接转
import java.util.ArrayList;
 
public class Test
{
	public static void main(String args[])
	{
		Employee[] staff = new Employee[2];
		staff[0] = new Employee("alice");
		staff[1] = new Employee("bob");
		
		ArrayList<Employee> list = new ArrayList<>();
		list.add(staff[0]);
		list.add(staff[1]);
	
		System.out.println(list.size());
		for(Employee e: list)
		{
			System.out.println(e.getName());
		}
	}
}
 
class Employee
{
	private String name;
	public Employee(String n)
	{
		name = n;
	}
	public String getName()
	{
		return name;
	}
}

output:

2
alice
bob

  • 2.ArrayList转数组–toArray
public class Test
{
	public static void main(String args[])
	{		
		ArrayList<Employee> list = new ArrayList<>();
		list.add(new Employee("alice"));
		list.add(new Employee("bob"));
		System.out.println(list.size());
		
		Employee[] staff = new Employee[list.size()];
		list.toArray(staff);//把list放进staff数组中
		
		for(Employee e: staff)
		{
			System.out.println(e.getName());
		}
	}
}

output:

2
alice
bob

ArrayList示例小程序

import java.util.*;
 
/**
 * This program demonstrates the ArrayList class.
 */
public class Test
{
	public static void main(String args[])
	{
		ArrayList<Employee> staff = new ArrayList<>();
		
		staff.add(new Employee("Alice", 75000, 1987, 12, 15));
		staff.add(new Employee("Bob", 50000, 1989, 10, 1));
		staff.add(new Employee("Carl", 40000, 1990, 3, 15));
		
		for(Employee e: staff)
		{
			e.raiseSalary(5);
		}
		
		for(Employee e: staff)
		{
			System.out.println("name="+e.getName()+", salary="+e.getSalary()
			+", hireDay="+e.getHireDay());
		}
	}
}
 
class Employee  
{  
    private String name;  
    private double salary;  
    private Date hireDay;  
      
    public Employee(String n, double s, int year, int month, int day)  
    {  
        name = n;  
        salary = s;  
        GregorianCalendar cal = new GregorianCalendar(year, month-1, day);  
        hireDay = cal.getTime();  
    }  
      
    public String getName()  
    {  
        return name;  
    }  
      
    public double getSalary()  
    {  
        return salary;  
    }  
      
    public Date getHireDay()  
    {  
        return hireDay;  
    }  
      
    public void raiseSalary(double percent)  
    {  
        salary *= (1 + percent/100);  
    }  
      
    public boolean equals(Object obj)  
    {  
        if(this == obj)  
            return true;  
        if(this == null)  
            return false;  
        if(this.getClass() != obj.getClass())  
            return false;  
          
        Employee tmp = (Employee)obj;  
        return Objects.equals(name, tmp.name) && this.salary==tmp.salary && hireDay.equals(tmp.hireDay);  
    }  
      
    public int hashCode()  
    {  
        return Objects.hash(name, salary, hireDay);  
    }  
      
    public String toString()  
    {  
        return getClass().getName()+"[name="+name+",salary="+salary+",hireDay="+hireDay+"]";  
    }  
}

output:

name=Alice, salary=78750.0, hireDay=Tue Dec 15 00:00:00 CST 1987
name=Bob, salary=52500.0, hireDay=Sun Oct 01 00:00:00 CST 1989
name=Carl, salary=42000.0, hireDay=Thu Mar 15 00:00:00 CST 1990

LinkedList

LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作队列(queue)或双向队列(deque),因为LinkedList类也实现了Queue、Deque接口。

import java.util.LinkedList; //这是实现了List、Queue、Deque等接口的实现类
import java.util.Queue; //这是队列的接口
 
public class Main {
    public static void main(String[] args) {
        //add()和remove()方法在失败的时候会抛出异常(不推荐)
        Queue<String> queue = new LinkedList<String>();
        //队尾添加元素
        queue.offer("a");
        queue.offer("b");
        queue.offer("c");
        queue.offer("d");
        queue.offer("e");
        for(String q : queue){
            System.out.println(q);
        }
        System.out.println("===");
        System.out.println("poll="+queue.poll()); //返回并删除队头元素
        for(String q : queue){
            System.out.println(q);
        }
        System.out.println("===");
        System.out.println("element="+queue.element()); //返回第一个元素 
        for(String q : queue){
            System.out.println(q);
        }
        System.out.println("===");
        System.out.println("peek="+queue.peek()); //返回第一个元素 
        for(String q : queue){
            System.out.println(q);
        }
    }
}

out:

a
b
c
d
e
===
poll=a
b
c
d
e
===
element=b
b
c
d
e
===
peek=b
b
c
d
e

注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:

List list = Collections.synchronizedList(new LinkedList(...));

Set

Set中的元素是用hash算法来存储的。

hash算法:当向Set中添加对象时,首先调用此对象所在类的hashCode()方法,计算此对象的hash值,此hash值决定了此对象在Set中的存储位置。若此位置没有对象存储,则存储该对象,若已有对象,再通过equals()方法比较两个对象是否相等,如果相等则不再存储,如果不相等,则hash冲突往后进行存储。

hash算法使Set有不可重复性,因此若要往Set中添加元素时,该元素所在的类需要同时重写equals()和hashCode()方法。

TreeSet

与其他Set不同,TreeSet中的元素必须是同一类的,且涉及排序(自然排序、定制排序),TreeSet底层按照红黑树进行排序。

自然排序:需要TreeSet中元素所在的类实现Comparable接口,重写相应的compareTo()方法。
compareTo()、equals()、hashCode()三者须一致。如果不一致,判断set重复元素时先按照compareTO()中定义的来,如compareTO()定义的name比较,那么相同名字的就算重复元素。

定制排序:创建TreeSet时传入Comparator对象

import org.junit.Test;
import java.util.*;
	
/**
 * TreeSet自然排序、定制排序的演示例子
 * 自然排序:需要TreeSet中元素所在的类实现Comparable接口,重写相应的compareTo()方法
 * 定制排序:创建TreeSet时传入Comparator对象
 */
public class TestTreeSet{
    //自然排序:需要Employee实现Comparable接口。这里按照name进行排序
    @Test
    public void test1(){
        Employee e1 = new Employee("名1", 25, new MyDate(1990,10,13));
        Employee e6 = new Employee("名1", 24, new MyDate(1990,10,13));
        Employee e2 = new Employee("名2", 21, new MyDate(1993,10,13));
        Employee e3 = new Employee("学1", 21, new MyDate(1993,6,13));
        Employee e4 = new Employee("张2", 21, new MyDate(1993,6,20));
        Employee e5 = new Employee("名5", 26, new MyDate(1997,3,13));
        TreeSet set = new TreeSet();
        set.add(e1);
        set.add(e2);
        set.add(e3);
        set.add(e4);
        set.add(e5);
        set.add(e6);
	
        Iterator it = set.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }
    
    //定制排序:创建TreeSet时传入Comparator对象。这里按照生日进行排序
    @Test
    public void test2(){
        Comparator com = new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if(o1 instanceof Employee && o2 instanceof Employee){
                    Employee e1 = (Employee)o1;
                    Employee e2 = (Employee)o2;
                    MyDate bir1 = e1.getBirthday();
                    MyDate bir2 = e2.getBirthday();
                    if(bir1.getYear() == bir2.getYear()){
                        if(bir1.getMonth() == bir2.getMonth()){
                            return bir1.getDay() - bir2.getDay();
                        }
                        return bir1.getMonth() - bir2.getMonth();
	
                    }
                    return bir1.getYear() - bir2.getYear();
                }
                return 0;
            }
        };
	
        Employee e1 = new Employee("名1", 25, new MyDate(1990,10,13));
        Employee e6 = new Employee("名1", 24, new MyDate(1990,10,13));
        Employee e2 = new Employee("名2", 21, new MyDate(1993,10,13));
        Employee e3 = new Employee("学1", 21, new MyDate(1993,6,13));
        Employee e4 = new Employee("张2", 21, new MyDate(1993,6,20));
        Employee e5 = new Employee("名5", 26, new MyDate(1997,3,13));
        TreeSet set = new TreeSet(com);
        set.add(e1);
        set.add(e2);
        set.add(e3);
        set.add(e4);
        set.add(e5);
        set.add(e6);
	
        Iterator it = set.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }
}
	
class Employee implements Comparable{
    private String name;
    private int age;
    private MyDate birthday;
	
    //自然排序:需要Employee实现Comparable接口。这里按照name进行排序
    public int compareTo(Object o){
        if(o instanceof Employee){
            Employee e = (Employee)o;
            return this.name.compareTo(e.getName());
        }
        return 0;
    }
	
    public Employee(String name, int age, MyDate birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }
	
    public String getName() {
        return name;
    }
	
    public void setName(String name) {
        this.name = name;
    }
	
    public int getAge() {
        return age;
    }
	
    public void setAge(int age) {
        this.age = age;
    }
	
    public MyDate getBirthday() {
        return birthday;
    }
	
    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }
	
    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }
	
    //同时需要重写equals方法,因为TreeSet中如contains等方法都需要equals判断
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age == employee.age &&
                Objects.equals(name, employee.name) &&
                Objects.equals(birthday, employee.birthday);
    }
	
    @Override
    public int hashCode() {
	
        return Objects.hash(name, age, birthday);
    }
}
	
class MyDate{
    private int month;
    private int day;
    private int year;
	
    public MyDate(int year, int month, int day) {
        this.month = month;
        this.day = day;
        this.year = year;
    }
	
    public int getMonth() {
        return month;
    }
	
    public void setMonth(int month) {
        this.month = month;
    }
	
    public int getDay() {
        return day;
    }
	
    public void setDay(int day) {
        this.day = day;
    }
	
    public int getYear() {
        return year;
    }
	
    public void setYear(int year) {
        this.year = year;
    }
	
    @Override
    public String toString() {
        return "MyDate{" +
                "month=" + month +
                ", day=" + day +
                ", year=" + year +
                '}';
    }
	
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyDate myDate = (MyDate) o;
        return month == myDate.month &&
                day == myDate.day &&
                year == myDate.year;
    }
	
    @Override
    public int hashCode() {
	
        return Objects.hash(month, day, year);
    }
}

Map接口

HashMap:主要实现类

LinkedHashMap:使用链表维护添加进Map中的顺序,故遍历Map时,是按添加顺序遍历的

TreeMap:按照添加进Map中元素的key的指定属性进行排序。故key必须是同一类的对象

Hashtable(子类Properties):Hashtable古老实现类,线程安全

Map与Collection并列存在,用于保存具有映射关系的数据:key-value

Map中的key和value都可以是任何引用类型的数据

Map中的key用Set来存放,不可重复,即同一个Map对象所对应的类,须重写hashCode()、equals()方法

各类Set其实就是Map的特例,Map中的key-value的value=null即为Set

常用String类作为Map的key

key和value之间存在单项一对一关系,即通过指定的key总能找到唯一的、确定的value

Java遍历Map对象的四种方式

Java遍历Map对象的四种方式

文中讲了四种遍历方法,最快捷常用的是:

Map<Integer, Integer> map = new HashMap<Integer, Integer>(); 
for (Map.Entry<Integer, Integer> entry : map.entrySet()) { 
  System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); 
}
	

HashMap

向HashMap中添加元素时,会调用key所在类的equals方法,判断两个key是否相同,若相同则只能添加后面添加的那个元素(覆盖前面元素)

HashMap遍历key集、value集。key是Set,value是Collection、key-value对是一个Set entrySet()

public void test1(){
    HashMap hm = new HashMap();
    hm.put(123, "asdad");
    hm.put("AA", 12532);
    hm.put(1234, new SimpleDateFormat("mm:ss").format(new Date()));
    System.out.println(hm);

    //遍历key集
    Set set = hm.keySet();
    Iterator it = set.iterator();
    while(it.hasNext()){//迭代器遍历
        System.out.println(it.next());
    }

    for(Object o: set){//增强for循环遍历
        System.out.println(o);
    }

    //遍历value集
    for(Object o: set){//通过key遍历来遍历value
        System.out.println(hm.get(o));
    }

    Collection coll = hm.values();
    for(Object o: coll){//通过value集的增强for循环遍历
        System.out.println(o);
    }

    //遍历key-value对
    //通过上述key遍历来遍历value可以得到,另一种方法是key-value对是一个Set entrySet()
    Set entry = hm.entrySet();
    for(Object obj: entry){
        Map.Entry ety = (Map.Entry)obj;
        System.out.println(ety.getKey() + "-->" + ety.getValue());
    }
}

TreeMap

TreeSet是特殊的TreeMap,按照添加进Map中元素的key的指定属性进行排序。因此TreeMap的key必须是同一类的对象,且有自然排序、定制排序。

自然排序:key元素所在类要实现Comparable接口重写compareTo()、equals()、hashCode()方法

定制排序:创建TreeMap时传入Comparator对象

Hashtable

Hashtable古老实现类,线程安全

与HashMap不同,Hashtable不允许使用null作为key和value

与HashMap一样,Hashtable也不能保证其中key-value对的顺序

Hashtable判断两个key相等、两个value相等的标准,与HashMap一致

Hashtable的子类Properties:常用来处理属性文件,key、value都为String类型

import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
	
public class TestHashMap{
    @Test
    public void test1() throws IOException{
        Properties pro = new Properties();
        pro.load(new FileInputStream(new File("abc.properties")));
        String user = pro.getProperty("user");
        String pass = pro.getProperty("password");
        System.out.println(user + ":" + pass);
    }
}
//abc.properties
//user=root
//pass=123456
//out:  root:123456

Collections:操作集合的工具类

Arrays是一个操作数组的工具类;Collections是一个操作Set、List、Map等集合的工具类

Collections提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制方法

1.排序操作:

Collections.reverse(list);//反转list中元素的顺序
Collections.shuffle(list);//对list集合元素进行随机排序
Collections.sort(list); //根据元素的自然顺序对list集合元素进行升序排序
Collections.sort(list, Comparator); //根据指定的Comparator产生的顺序对list集合元素进行排序
Collections.swap(list, int, int)//将list中i处、j处元素进行交换

2.查找、替换:

Collections.max(Collection) //根据自然顺序,返回集合中最大元素
Collections.max(Collection, Comparator) //根据指定顺序,返回集合中最大元素
Collections.frequency(Collection) //返回指定元素的出现次数
Collections.copy(List dest, List src) //将src的内容复制到dest中
Collections.replaceAll(List, Object oldVal, Object newVal) //替换

这里注意Collections.copy(dest list, src list)需要提前设置dest list大小:

public void test1(){
        List list = new ArrayList();
        list.add(123);
        list.add(13);
        list.add(12);
        list.add(12);
        list.add(4456);
        System.out.println(list);
        List list2 = Arrays.asList(new Object[list.size()]);//没有这句设置list2空间的话error
        Collections.copy(list2, list);
        System.out.println(list2);
}

3.同步控制:

Collections类中提供了多个synchronizedXxX()方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题(因为ArrayList、HashSet、HashMap等等全部都线程不安全,所以多线程时可使用Collections的同步控制来达到线程安全)

	public void test1(){
	        List list = new ArrayList(); //线程不安全
	        list.add(123);
	        list.add(13);
	        list.add(12);
	        list.add(12);
	        list.add(4456);
	
	        List list2 = Collections.synchronizedList(list);
	        System.out.println(list2); //list2是线程安全的
	}
	

HashMap与concurrentHashMap

1.HashMap:

1583508137

2.concurrentHashMap:

1583508181

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值