集合总结

在编程过程中,我们有很多时候都会遇到存储一组数据的问题,这个时候我们第一反应就是用数组,但是,数组的长度在声明的时候就已经给定,不可改变,我们面临着数组的扩容问题:数组的大小固定,不可直接扩容,我们只可以通过数组复制的方法变相的给数组扩容:

利用Arrays.copyOf(param1,param2);

第一个参数是要复制的数组,第二个参数新的长度,返回的是一个数组。

public static void main(String[] args) {
		int[] arr1 = {1,2,3,5,4};
		int[] arr2 = Arrays.copyOf(arr1, 4);
		//减少数组长度,默认从第一个开始
		for (int i = 0; i < arr2.length; i++) {
			System.out.println(arr2[i]);//1 2 3 5
		}
		System.out.println("增加长度");
		int[] arr3 = Arrays.copyOf(arr1, 6);
		arr3[arr3.length-1]= 520;
		for (int i = 0; i < arr3.length; i++) {
			System.out.println(arr3[i]);// 1 2 3 5 4 520
		}
		
		//截取指定范围的值到新数组中
		int[] arr4 = Arrays.copyOfRange(arr1, 1, 3);
		for (int i = 0; i < arr4.length; i++) {
			System.out.print(arr4[i]+" ");//2 3 含投不含尾
		}
	}

 

public static void main(String[] args) {
		int[] arr1 = {1,2,3,5,4};
		int[] arr2 = Arrays.copyOf(arr1, 4);
		//减少数组长度,默认从第一个开始
		for (int i = 0; i < arr2.length; i++) {
			System.out.println(arr2[i]);//1 2 3 5
		}
		System.out.println("增加长度");
		int[] arr3 = Arrays.copyOf(arr1, 6);
		arr3[arr3.length-1]= 520;
		for (int i = 0; i < arr3.length; i++) {
			System.out.println(arr3[i]);// 1 2 3 5 4 520
		}
		
		//截取指定范围的值到新数组中
		int[] arr4 = Arrays.copyOfRange(arr1, 1, 3);
		for (int i = 0; i < arr4.length; i++) {
			System.out.print(arr4[i]+" ");//2 3 含投不含尾
		}
	}

所以,如果我们清楚的知道,要保存的数据的数量的时候,选择数组是一个很好的选择。如果我们需要根据情况动态的添加数据,这个时候就需要用到集合了;

集合的特点:集合是可变长度的,只可以存储对象,集合可以存储不同类型的对象。

集合的框架如下:(大概的:)

集合只能存放引用类型元素,并且保存的是元素的引用(地址),所以,对象的值改变会引起集合对象里的值发生变化。
Iterator接口:提供了统一的遍历集合元素的方式,【遵循问,取,(删)的过程】提供了方法:
    boolean hasNext():判断集合是否还有元素可以遍历
    E next():返回迭代的下一个元素
    void remove():删除元素

Collection集合:collection是继承了Iterator接口的,所以可以用遍历器来遍历元素。
    boolean add(E e):将给定的元素添加到集合当中,当成功添加后返回true,否则为false。
    int size():获取集合的元素个数,集合没有长度,数组有长度 length
    void clear():清空集合
    boolean empty():判断集合是否为空集。当size等于0的时候,这个集合就是一个空集,空集并不是指null。
    boolean contains(Object o):判断当前集合是否包含给定元素,判定标准是看给定的对象是否与集合现有的元素存在
                                                equals比较为true,若有则包含,否则为不包含。
    boolean remove(Object o):从集合中删除一个元素,根据equals的判定结果删除,一次就删除一个元素,对于有重复的,就只                                                删除第一个元素
    boolean addAll(Collection<?> c): 将另一个集合的所有元素添加到另一个集合中
    boolean containsAll(Collection<?> c): 判断当前集合是否包含给定集合中的所有元素,若包含则返回true
    boolean removeAll(Collection<?> c):删除当前集合与给定集合的公有元素。
     Iterator iterator():返回一个用于遍历当前集合的迭代器的实现类。(不同的集合都实现了一个可以遍历自身的迭代器实现类,                                   无需记住这些类是什么,就把它当做Iterator来用即可)
    在用迭代器遍历集合的时候,不可以对集合进行操作元素(增,删,改),会报异常(ConcurrentModificationException)
    只可以用迭代器的删除方法删除通过next取出的元素。

    利用迭代器的原理,在jdk1.5之后,新推出了一个增强for循环,用来遍历数组或集合,但是不能取代传统的for循环,编译器认识这个for循环,然后还是会把它转换成传统的for循环交给虚拟机运行
    因为增强for循环实质上是一个迭代器,所以在用它进行遍历的过程中,不可以通过集合的方式操作元素。

    说到集合不免要提及泛型(也是在jdk1.5以后有的,也称为参数化类型):泛型在这提一点:

public class Fanxing {
	public static void main(String[] args) {
		Point<Integer> point1 = new Point<Integer>();
		point1.setX(1);
		point1.setY(2);
		
		int x1 = point1.getX();
		System.out.println("point1:"+point1.toString());
		
		Point point2 = point1;
		System.out.println("point2:"+point2.toString());
		point2.setX("三");
		System.out.println("point2:"+point2.toString());
		x1 = point1.getX();
		System.out.println("x1:"+x1);
		System.out.println("point1:"+point1);
	}

}

class Point<T>{
	private T x;
	private T y;
	public T getX() {
		return x;
	}
	public void setX(T x) {
		this.x = x;
	}
	public T getY() {
		return y;
	}
	public void setY(T y) {
		this.y = y;
	}
	public Point(T x, T y) {
		this.x = x;
		this.y = y;
	}
	public Point() {
		
	}
	@Override
	public String toString() {
		return "Point [x=" + x + ", y=" + y + "]";
	}
}


    如果使用了带有了泛型的类,就一定要写出使用的泛型类型,否则,默认为Object,极容易发生错误:
    point1刚开始一切正常,在赋值的时候经过了编译器的检查,是Integer类型,在调用get()方法取值的时候,编译器又给它加上了Integer类型(隐式转换),然后再返回回来。
    而point2在声明的时候,没有加泛型类型,而且和point1指向了同一个对象。赋值的时候由于没加泛型类型,是以Object类型放进去,但是用point1取值的时候,由于它的进
    和出都由编译器用Integer去检查,调用point1的get方法的时候,编译器会为他加上Integer,但是存进去是三,String类型,String不能直接转为Integer,所以会报一个类造型异常。

List接口:特点:可重复,并且有序,不仅可以用Iterator遍历,还可以用普通循环遍历。提供了一组通过下标操作元素的方法。
    void add(int index,E element):将给定的元素插入到指定位置,原位置及后续元素都顺序向后移动。
    E remove(int index):删除给定位置的元素,并将被删除的元素返回。
    E get(int index):获取集合中指定下标对应的元素,下标从0开始。
    E set(int index,E element):将给定的元素存入给定位置,并将原位置的元素返回。
    List<?>subList(int fromIndex,int toIndex):返回此列表中指定的fromIndex(含)和toIndex之间的元素
                                                              对通过subList得到的子集合,对子集进行的操作也是在对原集合进行操作,可利用这个                                                                  特性把子集合清除,从而也把原集合的该位置上的元素也被清除了。
    <T> T[] toArray(T[] a):这个是最常用的。
    所有集合都提供了一个参数为Collection类型的构造方法,在创建当前集合的同时包含给定集合中的所有元素。

public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		list.add("贺晓玲");
		list.add("好好学习");
		list.add("努力向上");
		System.out.println(list);//[贺晓玲, 好好学习, 努力向上]
		
		//把List集合转换为数组
		Object[] array = list.toArray();//就算这个本来规定了泛型类型的,所以并不常用
		
		/*
		 * 括号里,一般写size长度,如果大于size,则会报数组越界,如果小于size,会给我们自动添上,依然会装完所有的元素
		 */
		String[] array1 = list.toArray(new String[list.size()]);
		for (String string : array1) {
			System.out.print(string+" ");//贺晓玲 好好学习 努力向上 
		}
		
		//数组转换为List,Arrays提供了一个静态方法
		String[] array3 = {"one","two","three"};
		List<String> list2 = Arrays.asList(array3);
		System.out.println(list2);// [one, two, three]
		//对集合元素操作就是对原数组进行操作,故是不可以对集合进行增删操作的(会报UnsupportedOperationException异常)
		list2.set(1, "修改");
		for (String string : array3) {
			System.out.println(string+" ");//one 修改 three
		}
		
		/*
		 * 虽然说从数组转换过来的集合不可以进行增删操作,但是我们若是想修改,
		 * 可以new一个新的集合,来装上从数组返回回来的元素,再进行增删操作
		 */
		List<String> newList = new ArrayList<>(list2);
		System.out.println(newList);//[one, 修改, three]
		newList.remove(1);
		System.out.println(newList);//[one, three]
	}

 

对List进行排序:为什么不对Set排序呢?因为Set是无序的

 两种方式:

         第一种方式:Collections.sort();其中Collections是集合的工具类,提供了很多便于我们对集合操作的方法。
        void sort(List<T> list):对给定集合元素进行自然排序。(数字从小到大)
                该方法排序给定集合时对集合元素有一个要求,就是元素必须实现Comparable接口,否则编译不通过。
        那,Comparable接口又是什么?
            实现该接口必须实现抽象方法:int compareTo(T t);
            若当前对象大于给定对象,那么返回值应为>0的整数。
            若当前对象小于给定对象,那么返回值应为<0的整数
            若当前对象等于给定对象,那么返回值应为0

package colletion1;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

public class CollectionsSort {

	public static void main(String[] args) {
		/*
		 * java.util.Collections这个工具类提供了若干静态方法:如:
		 * Set<T> synchronizedSortedSet:返回支持该集合的线程同步集合(线程安全)
		 * List<T> synchronizedList(List<T> list:返回由指定列表支持的线程同步列表(线程安全)
		 */
		Random rm = new Random();
		List<Integer> list = new ArrayList<Integer>();
		for (int i = 0; i < 10; i++) {
			list.add(rm.nextInt(100));
		}
		/*
		 * sort方法对集合元素进行自然排序(从小到大)
		 */
		Collections.sort(list);
		for (Integer integer : list) {
			System.out.print(" "+integer);// 3 11 19 38 44 56 67 80 90 98
		}
		System.out.println("====排序自定义===");
		/*
		 * 如果要排序自定义类型元素,那么自定义类型要实现Comparable接口,重写compareTo()
		 */
		List<Point> list2 = new ArrayList<Point>();
		list2.add(new Point(3, 5));
		list2.add(new Point(2, 5));
		//排序前
		for (Point point : list2) {
			System.out.print(" "+point);
		}//Point [x=3, y=5] Point [x=2, y=5]
		
		Collections.sort(list2);
		
		//排序后
		for (Point point : list2) {
			System.out.print(" "+point);
		}//Point [x=2, y=5] Point [x=3, y=5]
	}
}
class Point implements Comparable<Point>{
	private int x;
	private int y;
	
	public Point(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}
	
	@Override
	public String toString() {
		return "Point [x=" + x + ", y=" + y + "]";
	}
	@Override
	public int compareTo(Point o) {
		/*
		 * 两个点比较大小的方式,点到原点的距离长的大
		 */
		int thisLen = this.x*this.x+this.y*this.y;
		int oLen = o.x*o.x+o.y*o.y;
		return thisLen-oLen;
	}
	
}

        但是这种方式,一旦实现了Comparable接口,比较逻辑就已经确定,如果希望在排序的操作
        中临时指定比较规则,则可以使用第二种方式。

        第二种方式:实现Comparator接口,重写 int compare(T o1,T o2);
            该方法的返回值要求:
                若o1>o2:返回值应>0;
                若o1<o2,返回值应<0;
                若o1=o2,返回值应为0;

public class CollectionsSort2 {
	public static void main(String[] args) {
		List<Cell> cells = new ArrayList<Cell>();
		cells.add(new Cell(3,2));
		cells.add(new Cell(5,1));
		cells.add(new Cell(2,3));
		
		//自定义排序规则,现在我要按col值的大小顺序要排序
		Collections.sort(cells, new Comparator<Cell>() {
			@Override
			public int compare(Cell o1, Cell o2) {
				return o1.getCol()-o2.getCol();
			}
		});
		System.out.println(cells);
		//[Cell [col=2, row=3], Cell [col=3, row=2], Cell [col=5, row=1]]
		//我们还可以用lambda表达式来实现,按照Cell的row从大到小排序
		Comparator<Cell> com = (o1,o2)->{return o2.getRow()-o1.getRow();};
		Collections.sort(cells, com);
		System.out.println(cells);//[Cell [col=2, row=3], Cell [col=3, row=2], Cell [col=5, row=1]]
	}

}
class Cell{
	private int col;
	private int row;
	public void setCol(int col) {
		this.col = col;
	}
	public void setRow(int row) {
		this.row = row;
	}
	public int getCol() {
		return col;
	}
	public int getRow() {
		return row;
	}
	@Override
	public String toString() {
		return "Cell [col=" + col + ", row=" + row + "]";
	}
	public Cell(int col, int row) {
		this.col = col;
		this.row = row;
	}
}

现在我们来Collection的另一个接口:Queue

Queue: 队列,Collection的另一个子接口,故也可以用迭代器遍历元素,可以将队列看成特殊的线性表,队列限制了对线性表的访问方式:只能从线性表的一端添加(offer)元素,从另一端取出(poll)元素
      
JDK提供了Queue接口,并同时使得LinkedList实现了该接口。因为Queue会经常进行添加和删除的操作,而LinkedList在这方面效率较高。
    主要方法:
    boolean offer(E e):将一个对象添加至队尾,添加成功返回true
    E poll();从队首删除并返回一个元素
    E peek():返回队首的元素(但并不删除)

Deque:双端队列,Queue的子接口,可从队列的两端分别入队(offer)和出队(poll),LinkedList也实现了该接口。
    如果将Deque限制为只能从一端入队和出队,则可实现("栈"Stack)的数据结构,对于栈而言,入栈称为push,出栈称为pop。栈遵循先进后出的原则
    主要方法:
    offerFirst():向队首添加
    offerLast():向队尾添加
    offer():默认向队尾添加
    pop():默认从首 取出元素

/**
 * 双端队列
 * @author tarena
 */
public class DequeTest {
	public static void main(String[] args) {
		Deque<String> deque = new LinkedList<String>();
		deque.offer("一");
		deque.offerFirst("二");
		deque.offerLast("三");
		deque.offer("四");
		deque.offer("五");
		System.out.println(deque);//[二, 一, 三, 四, 五]
		
		//取出元素 peek()取出队首元素,不在原队列中删除
		System.out.println("取出:"+deque.peek()+",以后变为"+deque);
		//poll()默认从队首取出元素,要在原队列中删除
		System.out.println("取出:"+deque.poll()+",以后变为"+deque);//取出:二,以后变为[一, 三, 四, 五]
		System.out.println("从队尾取出:"+deque.pollLast()+",以后变为:"+deque);//从队尾取出:五,以后变为:[一, 三, 四]
	}
}

Stack: 栈,如果双端队列只开放一端进行进出操作,那么就是栈的数据结构,比如:子弹上膛,最先上的那颗子弹最后一颗发射出来。LinkedList也实现了Stack
    又比如:电脑磁盘的后退功能,ctrl+z。先倒退的是你最后操作的那一步。
    主要方法:
    push():入栈操作
    pop():出栈操作

public class StackDemo {
	public static void main(String[] args) {
		LinkedList<String> stack = new LinkedList<String>();
		stack.push("一");
		stack.push("二");
		stack.push("三");
		System.out.println(stack);//[三, 二, 一]
		System.out.println("取出:"+stack.pop()+",原栈为:"+stack);//取出:三,原栈为:[二, 一]
	}
}

集合小结:

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值