Javaの集合
集合
1. 集合概述
- Java 集合就像一种容器,可以把多个对象的引用放入容器中。
- Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组
- Java 集合可分为 Set、List 和 Map 三种体系
- Set:无序、不可重复的集合
- List:有序,可重复的集合
- Map:具有映射关系的集合
- 在 Java5 之前,Java 集合会丢失容器中所有对象的数据类型,把所有对象都当成 Object 类型处理;从 Java5 增加了泛型以后,Java 集合可以记住容器中对象的数据类型。
2. Collection接口
- Collection 接口是 List、Set 和 Queue 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合:
3. List接口
1. List接口简介
List接口为Collection直接接口。List所代表的是有序的Collection,即它用某种特定的插入顺序来维护元素顺序。用户可以对列表中每个元素的插入位置进行精确地控制,
同时可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。实现List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。
- ArrayList集合
ArrayList内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中。
当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高(ArrayList在内存不够时默认是扩展50% + 1个)。因此,它适合随机查找和遍历,不适合插入和删除。
public class Test3 {
public static void main(String[] args) {
List<String > list=new ArrayList<>();
list.add("456");//追加到末尾
list.add("hello");
list.add("12311");
list.add("12322");
//1.for
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
//2.foreach
for(String s:list){
System.out.println(s);
}
//3.迭代器
System.out.println("=============");
Iterator<String> it = list.iterator();
/*while (true){
boolean b = it.hasNext();
if(!b){
break;
}
System.out.println(it.next());
}*/
while (it.hasNext()){
System.out.println(it.next());
}
}
}
3. LinkedList集合
- LinkedList是用双向链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。
4. Vector集合
- Vector集合底层数据结构是数组实现的,其操作和ArrayList一致,查询快,增删慢,但是其内部是线程安全,效率低。
5. Itrator接口
Iterator 接口主要用于遍历 Collection 集合中的元素,Iterator 对象也被称为迭代器
Iterator 接口隐藏了各种 Collection 实现类的底层细节,向应用程序提供了遍历 Collection 集合元素的统一编程接口
Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。
6. ArrayList和LinkedList的区别如下:
ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
自己写一个集合类
public class MyArrayList<T> {
T[] arr;
int count = 0;
int size = 5;
public MyArrayList() {
arr = (T[])new Object[size];
}
public void add(T t){
if(count+1 == size){
size = size + size/2;
T[] newarr = (T[])new Object[size];
System.arraycopy(arr,0,newarr,0,count);
newarr[count] = t;
count++;
arr = newarr;
}
else{
arr[count] = t;
count++;
}
}
public void add(int index,T t) {
if (count + 1 == size) {
size = size + size / 2;
}
T[] newarr = (T[]) new Object[size];
System.arraycopy(arr,0,newarr,0,index);
newarr[index] = t;
System.arraycopy(arr,index,newarr,index+1,count - index);
arr = newarr;
count++;
}
public void clear(){
arr = null;
}
public T[] clone(){
T[] newArr = arr;
return newArr;
}
public boolean contains(T t){
boolean isContains = false;
for (int i = 0; i < count; i++) {
if(t.equals(arr[i])){
isContains = true;
}
else {
isContains = false;
}
}
return isContains;
}
public void ensureCapacity(int minCapacity){
size = minCapacity;
}
public T get(int index){
return arr[index];
}
public int size(){
return count;
}
public int indexOf(T t){
for (int i = 0; i < count; i++) {
if(t.equals(arr[i])){
return i;
}
}
return -1;
}
public boolean isEmpty(){
if(count==0){
return true;
}
else{
return false;
}
}
public T[] remove(int index){
if(index<0){
System.exit(0);
}
else{
T[] newarr = (T[])new Object[count];
System.arraycopy(arr,0,newarr,0,index);
System.arraycopy(arr,index+1,newarr,index,count-index);
// System.arraycopy(arr,index,newarr,index+1,count - index);
count--;
arr = newarr;
}
return arr;
}
public T[] remove(T t){
for (int i = 0; i < count; i++) {
if(t.equals(arr[i])){
return this.remove(i);
}
}
System.out.println("未找到元素,删除失败!");
return arr;
}
public void show(){
String s = "[";
if(count+1 == size){
size = size + size / 2;
T[] newarr = (T[])new Object[size];
System.arraycopy(arr,0,newarr,0,count);
arr = newarr;
}
for (int i = 0; i < count; i++) {
if(arr[i+1]!=null) {
s = s + arr[i] + ",";
}else{
s = s + arr[i];
}
}
s = s + "]";
System.out.println(s);
}
}
Set接口
1).Set接口介绍
Set是Collection子接口;
Set和Collection基本上一样,一点除外:Set无法记住添加的顺序,不允许包含重复的元素。
当试图添加两个相同元素进Set集合,添加操作失败,add()方法返回false。
Setr如何判断两个对象是否相等?HashSet 集合的add()方法底层依赖于双列集合HashMap, 它依赖于两个方法 equals()和hashCode(); 先比较元素equals(), 再比较hashCoede值.
也就是说两个对象equals比较返回true,Set集合是不会接受这个两个对象的。
常用子类:
HashSet:散列存放
TreeSet:有序存放
2).HashSet集合
HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。
HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。
HashSet 具有以下特点:
不能保证元素的排列顺序
HashSet 不是线程安全的
集合元素可以是 null
当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。
3).TreeSet集合
TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。
TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。
自然排序
TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序排列
如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable 接口。
实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过 compareTo(Object obj) 方法的返回值来比较大小。
Comparable 的典型实现:
BigDecimal、BigInteger 以及所有的数值型对应的包装类:按它们对应的数值大小进行比较
Character:按字符的 UNICODE 值来进行比较
Boolean:true 对应的包装类实例大于 false 对应的包装类实例
String:按字符串中字符的 UNICODE 值进行比较
Date、Time:后边的时间、日期比前面的时间、日期大
自然排序步骤:
1.让元素自身具备比较性,
2.实现Compareable接口,覆盖其CompareTo方法
public int compareTo(Object obj)
{
if(!(obj instanceof Student)) {
throw new RuntimeException("不是学生对象");}
Student s = (Student)obj;
System.out.println(this.name+"....compareto....."+s.name);
if(this.age>s.age)
return 1;
if(this.age==s.age)
{
return this.name.compareTo(s.name);
}
return -1;
}
定制排序
如果需要实现定制排序,则需要在创建 TreeSet 集合对象时,提供一个 Comparator 接口的实现类对象。由该 Comparator 对象负责集合元素的排序逻辑
定制排序步骤:
1)创建比较器,实现comparator接口
2)复写compare方法
3)在创建TreeSet集合对象时,提供一个一个Comparator对象
class MyComparator implements Comparator{//第一步:实现Comparator接口
public int compare(Object o1, Object o2) {//第二步:实现一个campare方法
if(o1 instanceof Student1 & o2instanceof Student1){
Student1 s1 =(Student1)o1;
Student1 s2 =(Student1)o2;
if(s1.getAge() > s2.getAge()){
return -1;
}else if(s1.getAge() < s2.getAge()){
return 1;
} }
return 0;
}}
Set<Student1> s= new TreeSet(new MyComparator());//第三步:创建TreeSet集合对象时,提供一个一个Comparator对象