Java集合类二集合类详解及使用

一、常见集合详解与使用

1、ArrayList

ArrayList:实现原理:

数组实现,查找快,增删慢

数组为什么是查询快?因为数组的内存空间地址是连续的.

    ArrayList底层维护了一个Object[]用于存储对象,默认数组的长度是10。可以通过 new ArrayList(20)显式的指定用于存储对象的数组的长度。

    当默认的或者指定的容量不够存储对象的时候,容量自动增长为原来的容量的1.5倍。

由于ArrayList是数组实现,在增和删的时候会牵扯到数组增容,以及拷贝元素.所以慢。数组是可以直接按索引查找,所以查找时较快

可以考虑,假设向数组的0角标未知添加元素,那么原来的角标位置的元素需要整体往后移,并且数组可能还要增容,一旦增容,就需要要将老数组的内容拷贝到新数组中.

所以数组的增删的效率是很低的.


ArrayList使用:

去除ArrayList中重复元素:

public class Demo6 {
  public static void main(String[] args) {
    ArrayList arr = new ArrayList();
    Person p1 = new Person("jack", 20);
    Person p2 = new Person("rose", 18);
    Person p3 = new Person("rose", 18);
    arr.add(p1);
    arr.add(p2);
    arr.add(p3);
    System.out.println(arr);
    ArrayList arr2 = new ArrayList();
    for (int i = 0; i < arr.size(); i++) {
      Object obj = arr.get(i);
      Person p = (Person) obj;
      if (!(arr2.contains(p))) {
        arr2.add(p);
      }
    }
    System.out.println(arr2);
  }
}

class Person {
  private String name;
  private int age;

  public Person() {

  }

  public Person(String name, int age) {

    this.name = name;
    this.age = age;
  }

  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;
  }

  @Override
  public int hashCode() {
    return this.name.hashCode() + age * 37;
  }

  @Override
  public boolean equals(Object obj) {
    if (!(obj instanceof Person)) {
      return false;
    }
    Person p = (Person) obj;

    return this.name.equals(p.name) && this.age == p.age;
  }

  @Override
  public String toString() {
    return "Person@name:" + this.name + " age:" + this.age;
  }

}

2、LinkedList

LinkedList:链表实现, 增删快, 查找慢

由于LinkedList:在内存中的地址不连续,需要让上一个元素记住下一个元素.所以每个元素中保存的有下一个元素的位置.虽然也有角标,但是查找的时候,需要从头往下找,显然是没有数组查找快的.但是,链表在插入新元素的时候,只需要让前一个元素记住新元素,让新元素记住下一个元素就可以了.所以插入很快.

由于链表实现, 增加时只要让前一个元素记住自己就可以, 删除时让前一个元素记住后一个元素, 后一个元素记住前一个元素. 这样的增删效率较高。

但查询时需要一个一个的遍历,所以效率较低。

LinkedList使用:

基本方法:

import java.util.Iterator;
import java.util.LinkedList;

public class Demo3 {
  public static void main(String[] args) {
    LinkedList list = new LinkedList();
    list.add("西游记");
    list.add("三国演义");
    list.add("石头记");
    list.add("水浒传");
    list.add("全球通史");
    list.addFirst("史记");
    list.addLast("呐喊");
    // list.addFirst(null);
    // list.addLast(null);
    System.out.println(list);
    // 获取指定位置处的元素。
    String str = (String) list.get(0);
    // 返回此列表的第一个元素。
    String str2 = (String) list.getFirst();
    System.out.println(str.equals(str2));

    // 获取指定位置处的元素。
    String str3 = (String) list.get(list.size() - 1);
    // 返回此列表的最后一个元素。
    String str4 = (String) list.getLast();
    System.out.println(str3.equals(str4));

    // 获取但不移除此列表的头(第一个元素)。
    Object element = list.element();
    System.out.println(element);

    int size = list.size();
    System.out.println(size);
}
LinkedList的迭代:

mport java.util.Iterator;
import java.util.LinkedList;

public class Demo3 {
	public static void main(String[] args) {
		LinkedList list = new LinkedList();
		list.add("西游记");
		list.add("三国演义");
		list.add("石头记");
		list.add("水浒传");
		list.add("全球通史");
		Iterator it = list.iterator();
		while (it.hasNext()) {
			String next = (String) it.next();
			System.out.println(next);
		}
	}
}

ArrayList和 LinkedList的存储查找的优缺点:

(1)ArrayList 是采用动态数组来存储元素的,它允许直接用下标号来直接查找对应的元素。但是,但是插入元素要涉及数组元素移动及内存的操作。总结:查找速度快,插入操作慢。

(2)LinkedList 是采用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快

3、Vector

Vector: 描述的是一个线程安全的ArrayList。

使用:

public static void main(String[] args) 
	{
		Vector v = new Vector();
		v.addElement("aaa");
		v.addElement("bbb");
		v.addElement("ccc");
		System.out.println( v );
		System.out.println( v.elementAt(2) );   // ccc
		// 遍历Vector遍历
		Enumeration ens = v.elements();
		while ( ens.hasMoreElements() )
		{
			System.out.println( ens.nextElement() );
		}
	}

Set

Set所包含集合用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。

4、HashSet

哈希表边存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同)是按照哈希值来存的所以取数据也是按照哈希值取得。

HashSet会通过元素的hashcode()和equals方法进行判断元素师否重复。

向hashSet中添加自定义对象,并判断是否是重复对象的代码如下:

import java.util.HashSet;
import java.util.Iterator;

public class Demo4 {
	public static void main(String[] args) {
		HashSet hs = new HashSet();
		hs.add(new Person("jack", 20));
		hs.add(new Person("rose", 20));
		hs.add(new Person("hmm", 20));
		hs.add(new Person("lilei", 20));
		hs.add(new Person("jack", 20));

		Iterator it = hs.iterator();
		while (it.hasNext()) {
			Object next = it.next();
			System.out.println(next);
		}
	}
}

class Person {
	private String name;
	private int age;

	Person() {

	}

	public Person(String name, int age) {

		this.name = name;
		this.age = age;
	}

	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;
	}

	@Override
	public int hashCode() {
		System.out.println("hashCode:" + this.name);
		return this.name.hashCode() + age * 37;
	}

	@Override
	public boolean equals(Object obj) {
		System.out.println(this + "---equals---" + obj);
		if (obj instanceof Person) {
			Person p = (Person) obj;
			return this.name.equals(p.name) && this.age == p.age;
		} else {
			return false;
		}
	}

	@Override
	public String toString() {

		return "Person@name:" + this.name + " age:" + this.age;
	}

}


5、TreeSet

TreeSet会对元素进行自然排序,所以插入的元素要具备比较性或给其指定比较规则。

给TreeSet指定排序规则的方法:

方式一:元素自身具备比较性

元素自身具备比较性,需要元素实现Comparable接口,重写compareTo方法,也就是让元素自身具备比较性,这种方式叫做元素的自然排序也叫做默认排序。

示例代码:

public class Demo4 {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet();
		ts.add(new Person("aa", 20, "男"));
		ts.add(new Person("bb", 18, "女"));
		ts.add(new Person("cc", 17, "男"));
		ts.add(new Person("dd", 17, "女"));
		ts.add(new Person("dd", 15, "女"));
		ts.add(new Person("dd", 15, "女"));


		System.out.println(ts);
		System.out.println(ts.size()); // 5

	}
}

class Person implements Comparable {
	private String name;
	private int age;
	private String gender;

	public Person() {

	}

	public Person(String name, int age, String gender) {

		this.name = name;
		this.age = age;
		this.gender = gender;
	}

	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 String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	@Override
	public int hashCode() {
		return name.hashCode() + age * 37;
	}

	public boolean equals(Object obj) {
		System.err.println(this + "equals :" + obj);
		if (!(obj instanceof Person)) {
			return false;
		}
		Person p = (Person) obj;
		return this.name.equals(p.name) && this.age == p.age;

	}

	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", gender=" + gender
				+ "]";
	}

	@Override
	public int compareTo(Object obj) {
		
		Person p = (Person) obj;
		System.out.println(this+" compareTo:"+p);
		if (this.age > p.age) {
			return 1;
		}
		if (this.age < p.age) {
			return -1;
		}
		return this.name.compareTo(p.name);
	}

}

方式二:容器具备比较性

当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。

示例代码:

public class Demo5 {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet(new MyComparator());
		ts.add(new Book("think in java", 100));
		ts.add(new Book("java 核心技术", 75));
		ts.add(new Book("现代操作系统", 50));
		ts.add(new Book("java就业教程", 35));
		ts.add(new Book("think in java", 100));
		ts.add(new Book("ccc in java", 100));

		System.out.println(ts); 
	}
}

class MyComparator implements Comparator {

	public int compare(Object o1, Object o2) {
		Book b1 = (Book) o1;
		Book b2 = (Book) o2;
		System.out.println(b1+" comparator "+b2);
		if (b1.getPrice() > b2.getPrice()) {
			return 1;
		}
		if (b1.getPrice() < b2.getPrice()) {
			return -1;
		}
		return b1.getName().compareTo(b2.getName());
	}

}

class Book {
	private String name;
	private double price;

	public Book() {

	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public Book(String name, double price) {

		this.name = name;
		this.price = price;
	}

	@Override
	public String toString() {
		return "Book [name=" + name + ", price=" + price + "]";
	}

}


6、LinkedHashSet

会保存插入的顺序

Map

Map中的元素是两个对象,一个对象作为键,一个对象作为值。键不可以重复,但是值可以重复。

7、HashMap

底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。要保证键的唯一性,需要覆盖hashCode方法,和equals方法。

示例代码:

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;

public class Demo3 {
	public static void main(String[] args) {
		HashMap<Person, String> hm = new HashMap<Person, String>();
		hm.put(new Person("jack", 20), "1001");
		hm.put(new Person("rose", 18), "1002");
		hm.put(new Person("lucy", 19), "1003");
		hm.put(new Person("hmm", 17), "1004");
		hm.put(new Person("ll", 25), "1005");
		System.out.println(hm);
		System.out.println(hm.put(new Person("rose", 18), "1006"));

		Set<Entry<Person, String>> entrySet = hm.entrySet();
		Iterator<Entry<Person, String>> it = entrySet.iterator();
		while (it.hasNext()) {
			Entry<Person, String> next = it.next();
			Person key = next.getKey();
			String value = next.getValue();
			System.out.println(key + " = " + value);
		}
	}
}

class Person {
	private String name;
	private int age;

	Person() {

	}

	public Person(String name, int age) {

		this.name = name;
		this.age = age;
	}

	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;
	}

	@Override
	public int hashCode() {

		return this.name.hashCode() + age * 37;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Person) {
			Person p = (Person) obj;
			return this.name.equals(p.name) && this.age == p.age;
		} else {
			return false;
		}
	}

	@Override
	public String toString() {

		return "Person@name:" + this.name + " age:" + this.age;
	}

}
}


8、TreeMap

TreeMap可以对集合中的键进行排序。如何实现键的排序?

方式一:元素自身具备比较性

和TreeSet一样原理,需要让存储在键位置的对象实现Comparable接口,重写compareTo方法,也就是让元素自身具备比较性,这种方式叫做元素的自然排序也叫做默认排序。

方式二:容器具备比较性

当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。

自定义元素排序代码:

import java.util.Comparator;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

public class Demo3 {
	public static void main(String[] args) {
		TreeMap<Person, String> hm = new TreeMap<Person, String>(
				new MyComparator());
		hm.put(new Person("jack", 20), "1001");
		hm.put(new Person("rose", 18), "1002");
		hm.put(new Person("lucy", 19), "1003");
		hm.put(new Person("hmm", 17), "1004");
		hm.put(new Person("ll", 25), "1005");
		System.out.println(hm);
		System.out.println(hm.put(new Person("rose", 18), "1006"));

		Set<Entry<Person, String>> entrySet = hm.entrySet();
		Iterator<Entry<Person, String>> it = entrySet.iterator();
		while (it.hasNext()) {
			Entry<Person, String> next = it.next();
			Person key = next.getKey();
			String value = next.getValue();
			System.out.println(key + " = " + value);
		}
	}
}

class MyComparator implements Comparator<Person> {

	@Override
	public int compare(Person p1, Person p2) {
		if (p1.getAge() > p2.getAge()) {
			return -1;
		} else if (p1.getAge() < p2.getAge()) {
			return 1;
		}
		return p1.getName().compareTo(p2.getName());
	}

}

class Person implements Comparable<Person> {
	private String name;
	private int age;

	Person() {

	}

	public Person(String name, int age) {

		this.name = name;
		this.age = age;
	}

	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;
	}

	@Override
	public int hashCode() {

		return this.name.hashCode() + age * 37;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Person) {
			Person p = (Person) obj;
			return this.name.equals(p.name) && this.age == p.age;
		} else {
			return false;
		}
	}

	@Override
	public String toString() {

		return "Person@name:" + this.name + " age:" + this.age;
	}

	@Override
	public int compareTo(Person p) {

		if (this.age > p.age) {
			return 1;
		} else if (this.age < p.age) {
			return -1;
		}
		return this.name.compareTo(p.name);
	}

}


二、迭代器

     为了方便的处理集合中的元素,Java中出现了一个对象,该对象提供了一些方法专门处理集合中的元素.例如删除和获取集合中的元素.该对象就叫做迭代器(Iterator).

1.Iterator

Iterator接口定义的方法

Itreator   该接口是集合的迭代器接口类,定义了常见的迭代方法

    1:boolean hasNext()

                     判断集合中是否有元素,如果有元素可以迭代,就返回true。

    2: E next() 

                     返回迭代的下一个元素,注意: 如果没有下一个元素时,调用next元素会抛出NoSuchElementException

    3: void remove()

                     从迭代器指向的集合中移除迭代器返回的最后一个元素(可选操作)。

使用迭代器遍历

for循环遍历:

import java.util.ArrayList;
import java.util.Iterator;

public class Demo2 {
	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		// 增加:add() 将指定对象存储到容器中
		list.add("计算机网络");
		list.add("现代操作系统");
		list.add("java编程思想");
		list.add("java核心技术");
		list.add("java语言程序设计");
		System.out.println(list);

		for (Iterator it = list.iterator(); it.hasNext();) {
             //迭代器的next方法返回值类型是Object,所以要记得类型转换。
			String next = (String) it.next();
			System.out.println(next);
		}
	}
}
while循环遍历:

public static void main(String[] args) {
		ArrayList list = new ArrayList();
		// 增加:add() 将指定对象存储到容器中
		list.add("计算机网络");
		list.add("现代操作系统");
		list.add("java编程思想");
		list.add("java核心技术");
		list.add("java语言程序设计");
		System.out.println(list);
		Iterator it = list.iterator();
		while (it.hasNext()) {
			String next = (String) it.next();
			System.out.println(next);
		}
	}
2.  List特有的迭代器ListIterator

方法:

---|Iterator

       hasNext()

       next()

       remove()

      ------| ListIterator Iterator子接口 List专属的迭代器

                  add(E e)    将指定的元素插入列表(可选操作)。该元素直接插入到next返回的下一个元素的前面(如果有)

                  void set(E o)  用指定元素替换 nextprevious 返回的最后一个元素

                  hasPrevious()    逆向遍历列表,列表迭代器有多个元素,则返回true

                 previous()       返回列表中的前一个元素。

倒序遍历:

import java.util.ArrayList;
import java.util.ListIterator;

public class Demo2 {
	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		// 增加:add() 将指定对象存储到容器中
		list.add("计算机网络");
		list.add("现代操作系统");
		list.add("java编程思想");
		list.add("java核心技术");
		list.add("java语言程序设计");
		System.out.println(list);
        // 获取List专属的迭代器
		ListIterator lit = list.listIterator();
		while (lit.hasNext()) {
			String next = (String) lit.next();
			System.out.println(next);
		}
		System.out.println("***************");
		while (lit.hasPrevious()) {
			String next = (String) lit.previous();
			System.out.println(next);
		}

	}
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值