Java类集

集合

普通的对象数组的最大问题在于数组中的元素个数是固定的,不能动态的扩充大小,所以最 早的时候可以通过链表实现一个动态对象数组。但是这样做毕竟太复杂了,所以在 Java 中为了方便用户操作各个数据结构, 所以引入了类集的概念,有时候就可以把类集称为 java 对数据结构的实现。

在整个类集中的,这个概念是从 JDK1.2(Java 2)之后才正式引入的,最早也提供了很多的操作类,但是并没有完 整的提出类集的完整概念。 类集中最大的几个操作接口:Collection、Map、Iterator,这三个接口为以后要使用的最重点的接口。
所有的类集操作的接口或类都在 java.util 包中。

在这里插入图片描述

1. Collection接口

Collection 接口是在整个 Java 类集中保存单值的最大操作父接口,里面每次操作的时候都只能保存一个对象的数据。 此接口定义在 java.util 包中。
此接口定义如下:

public interface Collection<E> extends Iterable<E>

此接口的常用方法如下所示:
在这里插入图片描述
但是,在开发中不会直接使用 Collection 接口。而使用其操作的两个子接口:List、Set
在这里插入图片描述

1.1 List 接口

在整个集合中 List 是 Collection 的子接口,里面的所有内容都是允许重复的。

List 子接口的定义:

public interface List<E> extends Collection<E> 

此接口上依然使用了泛型技术。此接口对于 Collection 接口来讲有如下的扩充方法:
在这里插入图片描述
了解了 List 接口之后,那么该如何使用该接口呢?需要找到此接口的实现类,常用的实现类有如下几个: · ArrayList(95%)、Vector(4%)、LinkedList(1%)

1.1.1 ArrayList

ArrayList 是 List 接口的子类,此类的定义如下:
public class ArrayList extendsAbstractList implementsList , RandomAccess, Cloneable, Serializable

此类继承了 AbstractList 类。AbstractList 是 List 接口的子类。AbstractList 是个抽象类,适配器设计模式。
例子ArrayList增加和取得元素

package org.listdemo.arraylistdemo; 
import java.util.ArrayList; 
import java.util.List; 
public class ArrayListDemo01 { 
	public static void main(String[] args) {
		List<String> all = new ArrayList<String>(); // 实例化List对象,并指定泛型类型 
		all.add("hello "); // 增加内容,此方法从Collection接口继承而来 
		all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的 
		all.add("world"); // 增加内容,此方法从Collection接口继承而来 
		System.out.println(all); // 打印all对象调用toString()方法 
		}
}

以上的操作向集合中增加了三个元素,其中在指定位置增加的操作是 List 接口单独定义的。随后进行输出的时候, 实际上调用的是 toString()方法完成输出的。 可以发现,此时的对象数组并没有长度的限制,长度可以任意长,只要是内存够大就行。
例:删除元素,并且使用循环的方式输出。

package org.listdemo.arraylistdemo; 
import java.util.ArrayList; 
import java.util.List;
public class ArrayListDemo02 { 
	public static void main(String[] args) {
		List<String> all = new ArrayList<String>(); // 实例化List对象,并指定泛型类型 
		all.add("hello "); // 增加内容,此方法从Collection接口继承而来 
		all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的 
		all.add("world"); // 增加内容,此方法从Collection接口继承而来 
		all.remove(1); // 根据索引删除内容,此方法是List接口单独定义的 
		all.remove("world");// 删除指定的对象 
		System.out.print("集合中的内容是:"); 
		for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来 
			System.out.print(all.get(x) + "、"); // 此方法是List接口单独定义的 
		}
	}
}

1.1.2 Vector

Vector类实现了可增长的对象数组。 像数组一样,它包含可以使用整数索引访问的组件。 但是, Vector的大小可以根据需要增大或缩小,以便在创建Vector后添加和删除元素。

从Java 2平台v1.2开始,该类被改进以实现List接口,使其成为Java Collections Framework的成员。 与新的集合实现不同, Vector是同步的。 如果不需要线程安全实现,建议使用ArrayList代替Vector 。

与 ArrayList 一样,Vector 本身也属于 List 接口的子类,此类的定义如下:
public class Vector extends AbstractList implementsList,RandomAccess,Cloneable,Serializable
此类与 ArrayList 类一样,都是 AbstractList 的子类。所以,此时的操作只要是 List 接口的子类就都按照 List 进行操作。

package org.listdemo.vectordemo; 
import java.util.List; 
import java.util.Vector; 
public class VectorDemo01 { 
	public static void main(String[] args) {
		List<String> all = new Vector<String>(); // 实例化List对象,并指定泛型类型 
		all.add("hello "); // 增加内容,此方法从Collection接口继承而来 
		all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的 
		all.add("world"); // 增加内容,此方法从Collection接口继承而来 
		all.remove(1); // 根据索引删除内容,此方法是List接口单独定义的 
		all.remove("world");// 删除指定的对象 
		System.out.print("集合中的内容是:"); 
		for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来 
			System.out.print(all.get(x) + "、"); // 此方法是List接口单独定义的 
		} 
	} 
} 

1.1.3 Vector和ArrayList的区别

在这里插入图片描述
同步处理和异步处理会在多线程中涉及到。

1.1.4 LinkedList

集合数据存储的结构是链表结构。方便元素添加、删除的集合。

实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方 法。这些方法我们作为了解即可:
在这里插入图片描述
例:验证 LinkedList 子类

import java.util.LinkedList; 
import java.util.Queue; 
public class TestDemo { 
	public static void main(String[] args) { 
		Queue<String> queue = new LinkedList<String>(); 
		queue.add("A"); 
		queue.add("B"); 
		queue.add("C"); 
		int len=queue.size();//把queue的大小先取出来,否则每循环一次,移除一个元素,就少 一个元素,那么queue.size()在变小,就不能循环queue.size()次了。 
		for (int x = 0; x <len; x++) { 
			System.out.println(queue.poll()); 
		} 
		System.out.println(queue); 
	} 
}

1.2 Set接口

Set 接口也是 Collection 的子接口,与 List 接口最大的不同在于, Set 接口中元素无序并且接口里面的内容是不允许重复的。 它与 Collection 接口中的方法基本一致,并没有对 Collection 接口进行功能上的扩充,只是比 Collection 接口更加严格了。

1.2.1 散列存放HashSet

HashSet 是 Set 接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的 (即存取顺序不一致)

HashSet 是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证 元素唯一性的方式依赖于: hashCode 与 equals 方法。

例:

public class HashSetDemo {    
	public static void main(String[] args) {        
		//创建 Set集合        
		HashSet<String>  set = new HashSet<String>();  // 实例化Set接口对象
        //添加元素        
        set.add(new String("123"));        
        set.add("123");        
        set.add("123");         
        set.add("321");          
        // 用迭代器或者forEach遍历        
        for (String name : set) {            
        	System.out.println(name);       
        }

		// 或者将Set转化为数组进行遍历
		String[] str = set.toArray();
		for (int x = 0; x < obj.length; x++) { 
			System.out.print(obj[x] + "、"); 
		}
   
    }
}

输出结果如下,说明SET集合中不能存储重复元素:

123
321

1.2.2 排序子类TreeSet

与 HashSet 不同的是,TreeSet 本身属于排序的子类,此类的定义如下:
public class TreeSet extends AbstractSet implements NavigableSet, Cloneable, Serializable

例:展现排序

public class Demo1 {
    public static void main(String[] args) {
        TreeSet<String> data = new TreeSet<>();
        data.add("B");
        data.add("A");
        data.add("C");
        data.add("D");
        for (String s: data) {
            System.out.println(s);
        }
    }
}

输出结果是:

A
B
C
D

但是如果对自定义类排序会怎么样呢?
例:定义一个Person类

public class Demo1 {
    public static void main(String[] args) {
        TreeSet<Person> data = new TreeSet<>();
        Person p1 = new Person("张三", 18);
        Person p2 = new Person("李四", 19);
        data.add(p1);
        data.add(p2);
        for (Person p : data) {
            System.out.println(p);
        }
    }

    static class Person {
        String name;
        int age;
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
        public Person() {
        }
        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 String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Person person = (Person) o;
            return age == person.age &&
                    Objects.equals(name, person.name);
        }
        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
    }
}

执行以上的操作代码之后,发现出现了如下的错误提示:

Exception in thread "main" java.lang.ClassCastException: class Java集合.Demo1$Person cannot be cast to class java.lang.Comparable (Java集合.Demo1$Person is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')
	at java.base/java.util.TreeMap.compare(TreeMap.java:1291)
	at java.base/java.util.TreeMap.put(TreeMap.java:536)
	at java.base/java.util.TreeSet.add(TreeSet.java:255)
	at Java集合.Demo1.main(Demo1.java:19)

此时的提示是:Person类不能向 Comparable 接口转型的问题。通俗来说就是Java不知道怎么给Person进行排序。

所以,证明,如果现在要是想进行排序的话,则必须在 Person类中实现 Comparable 接口。

public class Demo1 {
    public static void main(String[] args) {
        TreeSet<Person> data = new TreeSet<>();
        Person p1 = new Person("张三", 18);
        Person p2 = new Person("李四", 19);
        Person p3 = new Person("王二麻子", 19);
        data.add(p1);
        data.add(p2);
        data.add(p3);
        for (Person p : data) {
            System.out.println(p);
        }
    }

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

        @Override
        public int compareTo(Person o) {
            // 拿this与o比较
            // 返回数据是:负数this小 / 0一样大 / 正数this大
            if (this.age > o.age) {
                return 1;
            } else if (this.age == o.age) {
                return 0; // 如果一样大说明有重复对象, 不存这个对象
            }
            return -1;
        }


        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
        public Person() {
        }
        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 String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) 
            return false;
            Person person = (Person) o;
            return age == person.age &&
                    Objects.equals(name, person.name);
        }
        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
    }
}
Person{name='张三', age=18}
Person{name='李四', age=19}

从以上的结果中可以发现,李四没有了。因为李四的年龄和张三的年龄是一样的,所以会被认为是同一个对象, 所以无法继续加入。

2. Map

Collection 中,每次操作的都是一个对象(单值存储),如果现在假设要操作一对对象(双值存储),则就必须使用 Map 了。

Map 接口。里面的所有内容都按照 key(不可重复) -> value 的形式保存,也称为二元偶对象。

此接口定义如下:
public interface Map<K,V>

此接口与 Collection 接口没有任何的关系,是第二大的集合操作接口。此接口常用方法如下:
在这里插入图片描述
Map 本身是一个接口,所以一般会使用以下的几个子类:HashMap、TreeMap、Hashtable

2.1 Map子类HashMap

HashMap 是 Map 的子类,此类的定义如下:
在这里插入图片描述
此类继承了 AbstractMap 类,同时可以被克隆,可以被序列化下来。

例:向集合中增加内容

package org.listdemo.hashmapdemo; 
import java.util.HashMap; 
import java.util.Map; 
public class HashMapDemo01 { 
	public static void main(String[] args) { 
		Map<Integer, String> map = new HashMap<Integer, String>(); 
		map.put(1, "张三A"); 
		map.put(1, "张三B"); // 新的内容替换掉旧的内容 
		map.put(2, "李四"); 
		map.put(3, "王五"); 
		String val = map.get(6); 
		System.out.println(val); 
	} 
}

以上的操作是 Map 接口在开发中最基本的操作过程,根据指定的 key 找到内容,如果没有找到,则返回 null,找到 了则返回具体的内容。

例: 遍历输出所有的key和value

package org.listdemo.hashmapdemo; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.Map; 
import java.util.Set; 
public class HashMapDemo03 { 
	public static void main(String[] args) { 
		Map<String, String> map = new HashMap<String, String>(); 
		map.put("ZS", "张三"); 
		map.put("LS", "李四"); 
		map.put("WW", "王五"); 
		map.put("ZL", "赵六"); 
		map.put("SQ", "孙七"); 
		Set<String> set = map.keySet(); // 得到全部的key 
		for (String key:set) {
			System.out.println(key + " --:> " + map.get(key)); 
		}
	} 
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值