我是靠谱客的博主 高高悟空,最近开发中收集的这篇文章主要介绍JavaSE-集合(List)Collection,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

JavaSE-集合(List)

  • Collection
    • List接口
      • ArrayList 实现类
      • Vector 实现类
      • 泛型
        • 扩展
        • 返回泛型类型的值
      • LinkedList 实现类

在这里插入图片描述

Collection

集合与数组的区别

  1. 数组只能放一种数据类型,可以是基本数据类型也可以是引用数据类型。
  2. 集合可以放多种数据类型,但是一般使用泛型,让他只能放置一种数据类型就是【引用数据类型】或者叫【包装类】。
  3. 所以集合是能放基本数据类型的,但是需要对数据进行自动装箱。

为什么要使用集合

传统使用数组对数据进行储存,但是一旦添加或者删除元素就会引起大量元素的移动后果是低效的,所以集合就是来解决这一问题的。

ArrayList 实现类

package src.com.study.oop;

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

public class Demo {
    public static void main(String[] args) {
        // 实例化实现类
        Collection col = new ArrayList();

        /**
         * Api
         * 增加:add(Object e)  addAll(Collection e)
         * 删除:remove(Object e)  clear()
         * 修改:
         * 查询:iterator()  size()
         * 比较:equals(Collection e)比较值  ==比较地址
         * 判断:isEmpty() contains(Object o)
         */
        col.add("123");
        Collection col2 = new ArrayList();
        col2.add(123);
        col2.add("1");
        col2.add("abc");
        col.addAll(col2);

        col2.remove(123);
        col2.clear();

        System.out.println(col.toString());
        System.out.println(col.size());
        System.out.println(col2.isEmpty());
        System.out.println(col.contains("1"));

        /**
         * 遍历集合
         * 1. 增强型for循环
         * 2. iterator() 迭代器
         */

        for (Object o : col) {
            System.out.print(o + "t");
        }
        System.out.println("-------------------------");

        Iterator iterator = col.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

List接口

扩展了跟索引相关的方法。

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

public class Demo1 {
    public static void main(String[] args) {
        List list = new ArrayList();

        /**
         * Api
         * 增加:add(int index, Object e)
         * 删除:remove(int index)
         * 修改:set(int index, Object e)
         * 查询:get(int index)
         */

        list.add("123");
        list.add("321");
        list.add("abc");
        list.add(1, "efg");
        list.remove(1);
        list.set(0, "hello");
        System.out.println(list.toString());
        System.out.println(list.size());
        System.out.println(list.get(0));

        /**
         * 对List 集合的遍历
         * 1. for 循环(增强型或者普通)
         * 2. iterator() 迭代器
         */
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i) + "t");
        }
        for (Object o :
                list) {
            System.out.print(o + "t");
        }

        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

ArrayList 实现类

ArrayList 底层就是一个数组,那些方法其实就是对数组的增删改查操作。

import java.util.ArrayList;

public class Demo2 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList(); // 底层创建数组,且为{}长度为0
        arrayList.add("123");// 执行这一步底层生成长度为10 的数组,并且装入数据,size++
        arrayList.add("123");
        arrayList.add("123");
        arrayList.add("123");
        arrayList.add("123");
        arrayList.add("123");
        arrayList.add("123");
        arrayList.add("123");
        arrayList.add("123");
        arrayList.add("123");// 执行到这一步直接放满长度为10 的数组,在此之前的元素添加均未调用grow方法

        arrayList.add("123");// 执行到这一步底层数组不够用时,将老数组扩容1.5 倍。原因:(源码)int newCapacity = 10 + (10 >> 1);结果就是int newCapacity = 15;elementData = Arrays.copyOf(elementData, 15); 并且对老数组进行了拷贝。
        arrayList.add("123");
        arrayList.add("123");
        arrayList.add("123");
        arrayList.add("123");
	
        arrayList.add("123");// 执行到第16个是同样存在数组不够用的情况,所以还是需要进行数组的扩容,扩容后长度变为15*1.5
        
        arrayList.isEmpty();  //底层直接使用size和0 进行比较返回一个布尔值。
        arrayList.clear();  //底层进行集合元素个数遍历,将所有集合元素赋值为null,清空集合元素计数。
        arrayList.remove("123");  //底层通过遍历就近删除集合元素,注意不是直接使用== 进行比较,而是使用equals 进行值得比较。然后进行集合拷贝移动。
        arrayList.get(0);  // 底层进行错误的捕获,后直接返回集合元素。
    }
}

源码分析:

public class ArrayList{
	// 空数组
	private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

	// Object类型的数组,所以ArrayList 底层就是一个Object类型的数组
	transient Object[] elementData;

	// 集合元素计数
	private int size;

	// 默认创建长度
	private static final int DEFAULT_CAPACITY = 10;

	// 空参构造器
	public ArrayList() {
        		this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;// 一旦调用,赋予数组{}
    	}

	// 增加操作
	private void grow(int minCapacity) {
        		// overflow-conscious code
        		int oldCapacity = elementData.length;
        		int newCapacity = oldCapacity + (oldCapacity >> 1);
        		if (newCapacity - minCapacity < 0)
            			newCapacity = minCapacity;
        		if (newCapacity - MAX_ARRAY_SIZE > 0)
            			newCapacity = hugeCapacity(minCapacity);
        			// minCapacity is usually close to size, so this is a win:
        		elementData = Arrays.copyOf(elementData, newCapacity);  

		// 执行结果:elementData = Arrays.copyOf({}, 10);  数组的扩容
    	}

	private void ensureExplicitCapacity(int minCapacity) {
       		modCount++;
        		if (minCapacity - elementData.length > 0)  // 数组长度不够用时此处为true
            		grow(minCapacity);  

		//=> 执行结果:grow(10)
    	}

	private static int calculateCapacity(Object[] elementData, int minCapacity) {
        		if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            			return Math.max(DEFAULT_CAPACITY, minCapacity);  
 
			//=> 执行结果:return 10
        		}
        		return minCapacity;
		// 底层数组不为空时直接返回
    	}

	private void ensureCapacityInternal(int minCapacity) {
        		ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    	}

	public boolean add(E e) {
        		ensureCapacityInternal(size + 1);  //=> 执行完这一步后顶层的数组已经扩容为10 了
        		elementData[size++] = e;  //=> 执行结果:elementData[0] = "123" size+1操作
        		return true;
    	}

	public boolean isEmpty() {
       		return size == 0;
    	}
	
	public void clear() {
       		modCount++;

        		// clear to let GC do its work
        		for (int i = 0; i < size; i++)
            			elementData[i] = null;

        			size = 0;
    	}
	
	public boolean remove(Object o) {
        		if (o == null) {
            			for (int index = 0; index < size; index++)
                			if (elementData[index] == null) {
                    			fastRemove(index);
                    			return true;
                			}
        		} else {
           			for (int index = 0; index < size; index++)
                			if (o.equals(elementData[index])) {
                    			fastRemove(index);
                    			return true;
                			}
        		}
        		return false;
    	}

	private void fastRemove(int index) {
        		modCount++;
        		int numMoved = size - index - 1;
        		if (numMoved > 0)
            			System.arraycopy(elementData, index+1, elementData, index, numMoved);
			// 此处执行的意思是将原集合某个位置的后一位赋值到当前集合的某个位置上且长度为几
        			elementData[--size] = null; // clear to let GC do its work
			// 最后将集合的最后位置赋值为null,并且size-1
    	}
	
	private void rangeCheck(int index) {
        		if (index >= size)
           			throw new IndexOutOfBoundsException(outOfBoundsMsg(index));  // 集合下标越界异常
    	}	
	
	public E get(int index) {
        		rangeCheck(index); // 异常的捕获

        		return elementData(index);
    	}
}

Vector 实现类

将之前的ArrayList全部替换为Vector,执行结果完全相同。

1. 区别在于底层的数组扩容倍数不一样。

Vector:

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

ArrayList:

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

2. ArrayList JDK1.2版本效率高线程不安全,Vector JDK1.0版本效率低线程安全(同步方法)。

3. 数组查询效率高,增加删除效率低。

泛型

泛型的作用

泛型的作用就是限制放入集合元素的类型,并且将类型限制为同一种类型。(JDK1.5)

import java.util.ArrayList;


public class Demo {
    private String name;
    private int age;

    public Demo(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

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

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Demo{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }

    public static void main(String[] args) {
        // 加入泛型,在编写代码的过程中开始生效,在编译期间就不允许添加其它类型了。
        ArrayList<Demo> list = new ArrayList<Demo>();
        Demo stu = new Demo("小明", 20);
        list.add(stu);
        // list.add("123")

        // 加了泛型之后,遍历更加简单了,直接可以中泛型类,在没加泛型之前只能遍历出父类(Object)
        for (Object d : list) {
            System.out.println(d);
        }
        for (Demo d : list) {
            System.out.println(d);
        }
    }

}

扩展

泛型类

// 这就是一个泛型类
public class Demo<AA>{
	
}

< > 中的字母可以是什么?如果是类一般随意,实际上就是一个占位符,这个类型还暂时不能确定所以只能随意取。但是在api 中一般使用 < E >。

确定类的泛型?创建对象时确定泛型。

public class Demo<AA>{
	
}

class AA{
	public static void main(String[] args){
		// 创建一个普通类对象
		Demo demo1 = new Demo();
		// 创建一个泛型类对象 
		Demo<Integer> demo2 = new Demo<Integer>();
		Demo<String> demo3 = new Demo<String>();
	}
}

泛型方法

参数是不确定泛型时,与创建泛型类的概念类似,也是创建对象时确定泛型,确定泛型后的对象调用方法时确定泛型方法所以不能使用static 修饰。
方法是不确定泛型时,参数不确定可以传入任何类型的参数。这可以有效地解决不同数据类型做参数的重载问题,可以使用static 进行修饰。

public class Demo01<AA> {

    public void a(AA data){
        System.out.println(data);
    }
    public <BB> void b(BB data){
        System.out.println(data);
    }
    // 此处会报错,原因就是static先于对象存在所以不知道AA 代表的是什么,因为AA 需要进行实例化对象后才能确定。
	/*public static void c(AA data){
		System.out.println(data)
	}*/
    // 此处不会报错,原因BB 无论有没有对象都是不确定的所以加不加static 效果也是一样。
    public static <BB> void d(BB data){
        System.out.println(data);
    }
    public void e(AA[] data){
        System.out.println(data);
    }
    // 类似与ArrayList 中的toArray 方法
    public <BB> BB[] f(BB...q){
        for (BB b:
             q) {
            System.out.println(q);
        }
        return q;
    }
}

class AA{
    public static void main(String[] args){
        Demo01<Integer> demo = new Demo01<Integer>();
        // 对象调用a 方法时传入泛型,所以AA 就是Integer 类型
        demo.a(12);
        // 泛型不确定
        demo.b("123");
        demo.b(123);
        demo.e(new Integer[]{1,2,3});
        demo.f(1,2,3);
        System.out.println(demo.f("1","2","3").toString());;
    }
}

泛型接口

// 定义一个泛型接口
public interface MyInterface<AA>{
	
}

// 定义一个实现类
class impl implements MyInterface<String>{

}

class impl<BB> implements MyInterface<BB>{
	public void a(BB data){}
}

泛型限制

泛型的上限:? extends A: 表示A或者A的子类都可以传入数据

import java.util.ArrayList;

public class Person {
    public int age;

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

    public Person() {
    }
    public Person(int age) {
        this.age = age;
    }
}

class Student extends Person{
    public String name;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                '}';
    }

    public Student(int age, String name) {
        super(age);
        this.name = name;
    }

    public Student(String name) {
        this.name = name;
    }
}
class  Test{
    public static void main(String[] args) {
        ArrayList<Person> arrayList = new ArrayList<Person>();
        arrayList.add(new Person(12));
        arrayList.add(new Person(14));
        arrayList.add(new Person(16));
        show(arrayList);

        ArrayList<Student> arrayList2 = new ArrayList<Student>();
        arrayList2.add(new Student("小明"));
        arrayList2.add(new Student("小红"));
        arrayList2.add(new Student("小华"));
        show(arrayList2);  // 使用重载方法会报错,原因就是参数不受泛型控制,进行泛型上限处理(只要是Person 或者Person 的子类都可以传入)
    }

    private static void show(ArrayList<? extends Person> arrayList) {
        for (Person p:
                arrayList) {
            System.out.println(p);
        }
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h5gLQtlG-1653568537671)(imgclip.png "imgclip.png")]

泛型的下限:? super A: 表示A或者A的父类都可以传入数据

import java.util.ArrayList;

public class Person {
    public int age;

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

    public Person() {
    }

    public Person(int age) {
        this.age = age;
    }
}

class Student extends Person {
    public String name;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                '}';
    }

    public Student(int age, String name) {
        super(age);
        this.name = name;
    }

    public Student(String name) {
        this.name = name;
    }
}

class Test {
    public static void main(String[] args) {
        ArrayList<Person> arrayList = new ArrayList<Person>();
        arrayList.add(new Person(12));
        arrayList.add(new Person(14));
        arrayList.add(new Person(16));
        show(arrayList);

        ArrayList<Student> arrayList2 = new ArrayList<Student>();
        arrayList2.add(new Student("小明"));
        arrayList2.add(new Student("小红"));
        arrayList2.add(new Student("小华"));
        show(arrayList2);  // 使用泛型下限处理
    }

    private static void show(ArrayList<? super Student> arrayList) {
        for (Object p :
                arrayList) {
            System.out.println(p);
        }
    }
}

返回泛型类型的值

    public static <T> T parse(String str, Class<T> valueType) throws JsonProcessingException {
        return objectMapper.readValue(str, valueType);
    }

LinkedList 实现类

增设集合开头 / 末尾元素操作

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

class LinkedListTest{
    public int age;
    public String name;

    public LinkedListTest(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "LinkedListTest{" +
                "age=" + age +
                ", name='" + name + ''' +
                '}';
    }
}

public class Demo2{
    public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<String>();
        /**
         * API
         * 增加:add[First][Last]() push() offer[Left][Last]()
         * 删除:pop()  remove[First][Last]Occurrence()
         * 修改:set()
         * 查询:get[First][Last]() peek[First][Last]()检索不删除 poll[First][Last]()检索并删除 [last]indexOf()
         * 判断:isEmpty()
         */
        list.addFirst("1");// 开头添加
        list.add("2"); // 添加
        list.addLast("3");
        list.addLast("3");// 末尾追加
        list.push("4");// 推入栈中,后进先出(开头)
        list.pop();// 弹出栈中的第一个
        list.offer("5");// 末尾追加
        list.offerFirst("6");// 开头追加
        System.out.println("检索第一个集合元素:" + list.peek());
        System.out.println("检索第一个集合元素:" + list.peekFirst());
        System.out.println("检索最后一个集合元素:" + list.peekLast());
        System.out.println("检索第一个元素并删除:" + list.poll());
        System.out.println("检索第一次出现‘3’的索引位置:" + list.indexOf("3"));
        System.out.println("检索最后一个出现‘3’的索引位置:" + list.lastIndexOf("3"));
        // 增强for 循环遍历
        for (Object o :
                list) {
            System.out.print(o + ", ");
        }
        System.out.println("-------------------");
        // 指定位置迭代遍历
        ListIterator<String> listIterator = list.listIterator(1);
        while (listIterator.hasNext()) {
            System.out.print(listIterator.next() + ", ");
        }
        // 倒叙
        while(listIterator.hasPrevious()){
            System.out.print(listIterator.previous() + ", ");
        }
        System.out.println("-------------------");
        // 倒叙迭代遍历
        Iterator<String> iterator = list.descendingIterator();
        while (iterator.hasNext()) {
            System.out.print(iterator.next() + ", ");
        }
        System.out.println("-------------------");
        // for 循环 + 迭代器
        // 语法:for (条件初始化;比较判断;迭代){}
        for (Iterator<String> iterator2 = list.descendingIterator();iterator2.hasNext();){
            System.out.print(iterator2.next() + ", ");
        }

        List<Object> list2 = new LinkedList<Object>();
        list2.add(new LinkedListTest(12,"xiaoming"));
        list2.add(new LinkedListTest(12,"xiaoming"));
        list2.add(new LinkedListTest(15,"xiaohong"));
        list2.add(new LinkedListTest(1,"xiaohua"));
        System.out.println(list2);  //=> [LinkedListTest{age=12, name='xiaoming'}, LinkedListTest{age=12, name='xiaoming'}, LinkedListTest{age=15, name='xiaohong'}, LinkedListTest{age=1, name='xiaohua'}]
    }
}

源码分析:

底层就是一个双向链表

  1. 实例化对象,初始化参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FvGnJaZw-1653568564271)(imgclip.png "imgclip.png")]

  1. 调用addFirst 传入参数 “1”

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g63f2yZN-1653568564272)(imgclip_1.png "imgclip_1.png")]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q9KX2xZ3-1653568564274)(imgclip_2.png "imgclip_2.png")]

  1. 调用add 传入参数 “2”

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eguX0rLv-1653568564277)(imgclip_4.png "imgclip_4.png")]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y7O3HCY7-1653568564280)(imgclip_5.png "imgclip_5.png")]

  1. 调用push 传入参数 “4”

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0NPkyelB-1653568564281)(imgclip_6.png "imgclip_6.png")]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ctRKUJXP-1653568564282)(imgclip_7.png "imgclip_7.png")]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6D7aROpX-1653568564284)(imgclip_8.png "imgclip_8.png")]

  1. 调用pop

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z8a81kh8-1653568564285)(imgclip_9.png "imgclip_9.png")]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AzrCzPXn-1653568564287)(imgclip_10.png "imgclip_10.png")]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ippRMRKS-1653568564288)(imgclip_11.png "imgclip_11.png")]

  1. 调用offer 传入参数 “5”

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6pPsElgo-1653568564290)(imgclip_12.png "imgclip_12.png")]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5GRreuYa-1653568564292)(imgclip_13.png "imgclip_13.png")]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4MUZCai3-1653568564293)(imgclip_14.png "imgclip_14.png")]

最后

以上就是高高悟空为你收集整理的JavaSE-集合(List)Collection的全部内容,希望文章能够帮你解决JavaSE-集合(List)Collection所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部