为了账号安全,请及时绑定邮箱和手机立即绑定

JAVASE之JAVA集合篇

标签:
Java 面试

一 集合概述

        一方面, 面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就要对对象进行存储。另一方面,使用Array存储对象方面具有一些弊端,而Java 集合就像一种容器,可以动态地把多个对象的引用放入容器中。Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组。

JAVA集合可分为Collection和Map两中体系:

        Collection接口:

                  Set: 元素无序,不可重复的集合.

                  List:元素有序,可重复的集合.

        Map接口:

                  具有映射关系“key-value对”的集合.

如下图:

https://img1.sycdn.imooc.com//5b5c08250001516008520411.jpg


https://img1.sycdn.imooc.com//5b5c08450001bcc607750423.jpg

具体信息请查看API.

二 常用集合类型

下面介绍下JAVA中常用的集合类型

List实现类:

1) ArrayList

       ArrayList 是 List 接口的典型实现类,本质上,ArrayList是对象引用的一个变长数组,ArrayList 是线程不安全的,而 Vector 是线程安全的,即使为保证 List 集合线程安全,也不推荐使用Vector,Arrays.asList(…) 方法返回的 List 集合既不是 ArrayList 实例,也不是 Vector 实例。 Arrays.asList(…)  返回值是一个固定长度的 List 集合.

@Test
	public void testArrayList() {
		List<Student> lists = new ArrayList<Student>();
		lists.add(new Student(1,"张三"));
		lists.add(new Student(2,"李四"));
		lists.add(new Student(3,"王五"));
		for (Student student : lists) {
			System.out.println(student);
		}
		lists = Arrays.asList(new Student(4,"赵六"),new Student(5,"田七"));
		for (Student student : lists) {
			System.out.println(student);
		}
	}	

运行结果:

Student [id=1, name=张三]
Student [id=2, name=李四]
Student [id=3, name=王五]
Student [id=4, name=赵六]
Student [id=5, name=田七]

2) LinkedList

    对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高,操作与ArrayList差不多。

3) Vector

Vector 是一个古老的集合,JDK1.0就有了。大多数操作与ArrayList相同,区别之处在于Vector是线程安全的。

在各种list中,最好把ArrayList作为缺省选择。当插入、删除频繁时,使用LinkedList;Vector总是比ArrayList慢,所以尽量避免使用。

    /**
     * Sets the size of this vector. If the new size is greater than the
     * current size, new {@code null} items are added to the end of
     * the vector. If the new size is less than the current size, all
     * components at index {@code newSize} and greater are discarded.
     *
     * @param  newSize   the new size of this vector
     * @throws ArrayIndexOutOfBoundsException if the new size is negative
     */
    public synchronized void setSize(int newSize) {
        modCount++;
        if (newSize > elementCount) {
            ensureCapacityHelper(newSize);
        } else {
            for (int i = newSize ; i < elementCount ; i++) {
                elementData[i] = null;
            }
        }
        elementCount = newSize;
    }

Set实现类:

Set接口是Collection的子接口,set接口没有提供额外的方法

Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。

Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals 方法

1) HashSet

HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。

HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。

HashSet 具有以下特点:

    Ø不能保证元素的排列顺序

    ØHashSet 不是线程安全的

    Ø集合元素可以是 null

当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。

HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。

	@Test
	public void testHashSet() {
		Set<Student> set = new HashSet<Student>();  
        //Student需要重写hashCode()和equals()方法
		set.add(new Student(1,"张三"));
		set.add(new Student(2,"李四"));
		set.add(new Student(3,"王五"));
		set.add(new Student(3,"王五"));
		for (Student student : set) {
			System.out.println(student);
		}
	}

运行结果:

Student [id=2, name=李四]
Student [id=1, name=张三]
Student [id=3, name=王五]

2) LinkedHashSet

LinkedHashSet 是 HashSet 的子类

LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。

LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。

LinkedHashSet 不允许集合元素重复。

3) TreeSet

TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。

TreeSet 两种排序方法:自然排序定制排序。默认情况下,TreeSet 采用自然排序。

①自然排序   TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序排列

向 TreeSet 中添加元素时,只有第一个元素无须比较compareTo()方法,后面添加的所有元素都会调用compareTo()方法进行比较。

因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同一个类的对象

对于 TreeSet 集合而言,它判断两个对象是否相等的唯一标准是:两个对象通过 compareTo(Object obj) 方法比较返回值

当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 方法时,应保证该方法与 compareTo(Object obj) 方法有一致的结果:如果两个对象通过 equals() 方法比较返回 true,则通过 compareTo(Object obj) 方法比较应返回 0

	@Test
	public void testTreeSet() {
		Set<Student> set = new TreeSet<>();
		set.add(new Student(1,"张三"));
		set.add(new Student(2,"李四"));
		set.add(new Student(3,"王五"));
		set.add(new Student(1,"王五"));
		for (Student student : set) {
			System.out.println(student);
		}
	}

package com.lxj.collection;

public class Student implements Comparable {

	private Integer id;
	private String name;

	public Student(Integer id,String name) {
		this.id = id;
		this.name = name;
	}
	
	public Student() {
		
	}
	
	public Integer getId() {
		return id;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result + ((name == null) ? 0 : name.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;
		Student other = (Student) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

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

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

	@Override
	public int compareTo(Object o) { 
    //如果id相同就按照name排序 
		if(o instanceof Student) {
			Student s = (Student)o;
			int i = this.id.compareTo(s.getId());
			if(i == 0) {
				return this.name.compareTo(s.getName());
			}else {
				return i;
			}
		}
		return 0;
	}
}

结果:

Student [id=1, name=张三]
Student [id=1, name=王五]
Student [id=2, name=李四]
Student [id=3, name=王五]

②定制排序

TreeSet的自然排序是根据集合元素的大小,进行元素升序排列。如果需要定制排序,比如降序排列,可通过Comparator接口的帮助。需要重写compare(T o1,T o2)方法。利用int compare(T o1,T o2)方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。要实现定制排序,需要将实现Comparator接口的实例作为形参传递给TreeSet的构造器。

此时,仍然只能向TreeSet中添加类型相同的对象。否则发生ClassCastException异常。

使用定制排序判断两个元素相等的标准是:通过Comparator比较两个元素返回了0。

     @Test
	public void testTreeSet2() {
		//定制排序
		Set<Student2> treeSet = new TreeSet<>(new Comparator<Object>() {
			@Override
			public int compare(Object o1, Object o2) {
				if(o1 instanceof Student2 && o2 instanceof Student2) {
					Student2 s1 = (Student2)o1;
					Student2 s2 = (Student2)o2;
				    int i = s1.getId().compareTo(s2.getId());
				    if(i == 0) {
				    	return s1.getName().compareTo(s2.getName());
				    }
				    return i;
				}
				return 0;
			}
		});
		treeSet.add(new Student2(1,"张三"));
		treeSet.add(new Student2(2,"李四"));
		treeSet.add(new Student2(3,"王五"));
		treeSet.add(new Student2(1,"王五"));
		for (Student2 student : treeSet) {
			System.out.println(student);
		}
	}

运行结果:

Student [id=1, name=张三]
Student [id=1, name=王五]
Student [id=2, name=李四]
Student [id=3, name=王五]

Map实现类:

Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value

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

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

常用String类作为Map的“键”。

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

1) hashMap

	@Test
	public void testHashMap() {
		Map<Object,Student> stus = new HashMap<>();
		stus.put("aa", new Student(1,"aa"));
		stus.put("c", new Student(1,"aa"));
		stus.put("bb", new Student(2,"bb"));
		stus.put("cc", new Student(3,"cc"));
		stus.put(null, new Student(3,"cc"));
		for (Entry<Object, Student>  student : stus.entrySet()) {
			System.out.println(student.getKey()+" : " + student.getValue());
		}
	}

运行结果:

aa : Student [id=1, name=aa]
bb : Student [id=2, name=bb]
cc : Student [id=3, name=cc]
null : Student [id=3, name=cc]
c : Student [id=1, name=aa]

2) LinkedHashMap

LinkedHashMap 是 HashMap 的子类

与LinkedHashSet类似,LinkedHashMap 可以维护 Map 的迭代顺序:迭代顺序与 Key-Value 对的插入顺序一致

3)TreeMap

TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。TreeMap 可以保证所有的 Key-Value 对处于有序状态。

TreeMap 的 Key 的排序:

Ø自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException

Ø定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口

@Test
	public void testTreeMap() {
		Map<Object,Object> stus = new TreeMap<>(new Comparator<Object>() {
			@Override
			public int compare(Object o1, Object o2) {
				if(o1 instanceof Student2 && o2 instanceof Student2) {
					Student2 s1 = (Student2)o1;
					Student2 s2 = (Student2)o2;
				    int i = s1.getId().compareTo(s2.getId());
				    if(i == 0) {
				    	return s1.getName().compareTo(s2.getName());
				    }
				    return i;
				}
				return 0;
			}
		});
		stus.put( new Student2(1,"aa"),"aa");
		stus.put( new Student2(1,"aa"),"bb");
		stus.put( new Student2(2,"bb"),"cc");
		stus.put( new Student2(3,"cc"),"dd");
		stus.put( new Student2(3,"dd"),"ee");
		for (Entry<Object, Object>  student : stus.entrySet()) {
			System.out.println(student.getKey()+" : " + student.getValue());
		}
	}

 运行结果:

Student [id=1, name=aa] : bb
Student [id=2, name=bb] : cc
Student [id=3, name=cc] : dd
Student [id=3, name=dd] : ee

4) Hashtable

Hashtable是个古老的 Map 实现类,线程安全。

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

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

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

5) Properties

Properties 类是 Hashtable 的子类,该对象用于处理属性文件

由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型

存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法

	@Test
	public void testProperty() throws FileNotFoundException, IOException {
		Properties properties = new Properties();
		properties.load(new FileInputStream("jdbc.properties"));
		String name = properties.getProperty("name");
		String password = properties.getProperty("password");
		System.out.println(name);
		System.out.println(password);
	}

运行结果:

root
123456


Collections 操作集合的工具类

Collections 是一个操作 Set、List 和 Map 等集合的工具类

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

Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题

相关的信息请查阅API。

















点击查看更多内容
5人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
7796
获赞与收藏
665

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消