2020/3/30学习笔记-day29【java高级特性(二)】

java-day29

java高级特性-第二部分

1、集合(Collection Framework)

Java中集合和相关的接口都在java.util包下。

集合的主要组成部分

1-1接口

整个集合架构的上层结构都是用接口进行组织的,接口中定义了将来集合中必须要有的基本方法。

通过接口还把集合划分成了几种不同的类型,每一种集合都有其对应的接口。

1-2实现类

对于上层接口划分好的集合类型,都会有对应的类型进行实现。每一种接口的实现类很可能有多个,每个的实现方法也会各有不同。

1-3实现的方法(算法)

每个实现类都实现了接口中所定义的最基本的方法,对数据的存储、检索、操作等这些方法,但是不同的实现类,他们的实现方法不同,也就是算法不同。

2、集合和数组的区别

集合对象是用来存放其他对象的,并且只能存放对象,不能存放基本数据类型。

数组对象可以存放对象也可以存放基本数据类型。

因为数组可以声明为引用类型和基本类型数组。

集合的长度是可以变化的,随着存储数据的增多,集合中的总长度也会随之变化。

数组的长度一旦确定,就无法改变。

集合是由javase-api中的java-util包里面所提供的接口和实现类组成的,这里面定义并实现了很多方法,我们可以使用集合对象直接调用,然后完成对集合中数据的操作。

数组是JVM中实现的,类型+[ ] 组合而成,除了一个length属性,还有从Object中继承过来的方法外,我们用数组对象就调用不到其他属性和方法。

3、集合框架的组成

集合中分为两个大的类型:Collection 和 Map

Iterable 接口

Collection 接口

Collection父接口

Iterable <E> 

Collection子接口

BeanContext
BeanContextServices
BlockingDeque <E>
BlockingQueue <E>
Deque <E>
List <E> 
NavigableSet <E> 
Queue <E>
Set <E>
SortedSet <E>
TransferQueue <E> 

Collection实现类

AbstractCollection , AbstractList ,
AbstractQueue , AbstractSequentialList ,
AbstractSet , ArrayBlockingQueue , ArrayDeque , 
【ArrayList】 , AttributeList , 
BeanContextServicesSupport , 
BeanContextSupport , 
ConcurrentHashMap.KeySetView , 
ConcurrentLinkedDeque , ConcurrentLinkedQueue , 
ConcurrentSkipListSet ,
CopyOnWriteArrayList ,
CopyOnWriteArraySet ,
DelayQueue , EnumSet , 
【HashSet】 , JobStateReasons ,
LinkedBlockingDeque ,
LinkedBlockingQueue ,
LinkedHashSet , 【LinkedList】 ,
LinkedTransferQueue , 
PriorityBlockingQueue ,
PriorityQueue , RoleList ,
RoleUnresolvedList , Stack , 
SynchronousQueue , 【TreeSet】 ,【Vector】 

在这里插入图片描述

注意:SortedMap是Map接口下面的子接口

4、每一种集合类型的特点

Iterable接口

这个接口不代表集合,但是很多集合实现了这个接口,集合实现这个接口后,就可以实现迭代功能。

Iterable接口中的抽象方法:

Iterator<T> iterator() 
返回类型为 T元素的迭代器

实现这个接口的集合中,都可以调用iterator()方法,该方法返回一个迭代器,使用这个迭代器就要可以迭代出集合的每一个元素。

该方法的返回类型是Iterator,这也是一个接口表示迭代器类型。

Collection接口

这个接口代表一种结合类型。这个接口继承了父接口Iterable,所以只要实现这个接口的集合都可以调用iterator() 方法来获取迭代器,从而迭代集合中的元素。

所有方法

boolean 	add(E e) 
			确保此集合包含指定的元素(可选操作)。  

boolean 	addAll(Collection<? extends E> c) 
			将指定集合中的所有元素添加到此集合(可选操作)。  

void 		clear() 
			从此集合中删除所有元素(可选操作)。  

boolean 	contains(Object o) 
			如果此集合包含指定的元素,则返回 true 。  

boolean 	containsAll(Collection<?> c) 
			如果此集合包含指定 集合中的所有元素,则返回true。  

boolean 	equals(Object o) 
			将指定的对象与此集合进行比较以获得相等性。  

int 		hashCode() 
			返回此集合的哈希码值。  

boolean 	isEmpty() 
			如果此集合不包含元素,则返回 true 。  

Iterator<E> iterator() 
			返回此集合中的元素的迭代器。  

boolean 	remove(Object o) 
			从该集合中删除指定元素的单个实例(如果存在)(可选操作)。  

boolean 	removeAll(Collection<?> c) 
			删除指定集合中包含的所有此集合的元素(可选操作)。  

boolean 	retainAll(Collection<?> c) 
			仅保留此集合中包含在指定集合中的元素(可选操作)。  

int 		size() 
			返回此集合中的元素数。  

Object[] 	toArray() 
			返回一个包含此集合中所有元素的数组。  

<T> T[] 	toArray(T[] a) 
			返回包含此集合中所有元素的数组;
			返回的数组的运行时类型是指定数组的运行时类型。
			
---------------默认方法------------------
					
default boolean 		removeIf(Predicate<? super E> filter) 
						删除满足给定谓词的此集合的所有元素
					
default Stream<E> 		parallelStream() 
						返回可能并行的 Stream与此集合作为其来源。  
                        
default Spliterator<E> 	spliterator() 
						创建一个Spliterator在这个集合中的元素。  

default Stream<E> 		stream() 
						返回以此集合作为源的顺序 Stream 。

List接口和Set接口

这两个接口都是Collection接口的子接口。

List接口的特点:

有序可重复

往List集合中所存储的数据是有序的(该顺序是存放的顺序)

可以将同一个数据重复存到List集合中

List新增加的方法:
boolean 	addAll(int index, Collection<? extends E> c) 
			将指定集合中的所有元素插入到此列表中的指定位置(可选操作)。
			
E 			get(int index) 
			返回此列表中指定位置的元素。
            
E 			remove(int index) 
			删除该列表中指定位置的元素(可选操作)。
            
E 			set(int index, E element) 
			用指定的元素(可选操作)替换此列表中指定位置的元素
			
int 		indexOf(Object o) 
			返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。            

void 		add(int index, E element) 
			将指定的元素插入此列表中的指定位置(可选操作)。
            
int 		lastIndexOf(Object o) 
			返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
            
List<E> 	subList(int fromIndex, int toIndex) 
			返回此列表中指定的 fromIndex (含)和 toIndex之间的视图。  

ListIterator<E> 	listIterator() 
					返回列表中的列表迭代器(按适当的顺序)。 
                    
ListIterator<E> 	listIterator(int index) 
					从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。  
Set接口的特点:

无序不可重复

往Set类型集合中存储的顺序默认是无序的

Set类型集合不能存放相同的数据(HashCode 和 equals来进行判断)

注意:Set接口的一个子接口SortedSet,是允许把存放到集合中的数据进行排序的。

Set新增加的方法:
default Spliterator<E> 	spliterator() 
						在此集合中的元素上创建一个 Spliterator 。  

Map接口

Map是和Collection不同的一种集合。

Map中存放数据的特点和Collection不同,Collection就是直接把数据存放进去就可以了,但是Map要求存放进去的数据都要有一个唯一的标识。

Map存放的数据都要以K-V的方式进行存放,V:存放的数据,K:这个数据在Map中的唯一标识,键值对(Key-Value)。

void 	clear() 
		从该Map中删除所有的映射(可选操作)。  
		
boolean containsKey(Object key) 
		如果此映射包含指定键的映射,则返回 true 。  
		
boolean containsValue(Object value) 
		如果此Map将一个或多个键映射到指定的值,则返回 true 。  
  
boolean equals(Object o) 
		将指定的对象与此映射进行比较以获得相等性。 
		
V 		get(Object key) 
		返回到指定键所映射的值,或 null如果此映射包含该键的映射。
		
int 	size() 
		返回此Map中键值映射的数量。  
		
int 	hashCode() 
		返回此Map的哈希码值。  
		
boolean isEmpty() 
		如果此Map不包含键值映射,则返回 true 。 
        
Set<K>	keySet() 
		返回此Map中包含的键的Set视图。
		
V 		put(K key, V value) 
		将指定的值与该映射中的指定键相关联(可选操作)。
		
Collection<V> 		values() 
					返回此Map中包含的值的Collection视图。
					
Set<Map.Entry<K,V>> entrySet() 
					返回此Map中包含的映射的Set视图。
					
void 				putAll(Map<? extends K,? extends V> m) 
					将指定Map的所有映射复制到此映射(可选操作)。
					
V 					remove(Object key) 
					如果存在(从可选的操作),从该Map中删除一个键的映射。  
...(default方法未放出来) 

5、集合中的实现类

List接口的实现类中常用的有ArrayList、LinkedList、Vector

ArrayList实现类的声明:(用数组实现)

public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable{
    //....
}
boolean 	add(E e) 
			将指定的元素追加到此列表的末尾。  
void 		add(int index, E element) 
			在此列表中的指定位置插入指定的元素。  
boolean 	addAll(Collection<? extends E> c) 
			按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。  
boolean 	addAll(int index, Collection<? extends E> c) 
			将指定集合中的所有元素插入到此列表中,从指定的位置开始。  
void 		clear() 
			从列表中删除所有元素。  
Object 		clone() 
			返回此 ArrayList实例的浅拷贝。  
boolean 	contains(Object o) 
			如果此列表包含指定的元素,则返回 truevoid 		ensureCapacity(int minCapacity) 
			如果需要,增加此 ArrayList实例的容量,以确保它可以至少保存最小容量参数指定的元素数。  
void 		forEach(Consumer<? super E> action) 
			对 Iterable的每个元素执行给定的操作,直到所有元素都被处理或动作引发异常。  
E 			get(int index) 
			返回此列表中指定位置的元素。  
int 		indexOf(Object o) 
			返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1boolean 	isEmpty() 
			如果此列表不包含元素,则返回 true 。  
Iterator<E> iterator() 
			以正确的顺序返回该列表中的元素的迭代器。  
int 		lastIndexOf(Object o) 
			返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。  
E 			remove(int index) 
			删除该列表中指定位置的元素。  
boolean 	remove(Object o) 
			从列表中删除指定元素的第一个出现(如果存在)。  
boolean 	removeAll(Collection<?> c) 
			从此列表中删除指定集合中包含的所有元素。  
boolean 	removeIf(Predicate<? super E> filter) 
			删除满足给定谓词的此集合的所有元素。  
void 		replaceAll(UnaryOperator<E> operator) 
			将该列表的每个元素替换为将该运算符应用于该元素的结果。  
boolean 	retainAll(Collection<?> c) 
			仅保留此列表中包含在指定集合中的元素。  
E 			set(int index, E element) 
			用指定的元素替换此列表中指定位置的元素。  
int 		size() 
			返回此列表中的元素数。  
void 		sort(Comparator<? super E> c) 
			使用提供的 Comparator对此列表进行排序以比较元素。   
List<E> 	subList(int fromIndex, int toIndex) 
			返回此列表中指定的 fromIndex (包括)和 toIndex之间的独占视图。  
Object[] 	toArray() 
			以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。  
<T> T[] 	toArray(T[] a) 
			以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 
			返回的数组的运行时类型是指定数组的运行时类型。  
void 		trimToSize() 
			修改这个 ArrayList实例的容量是列表的当前大小。  			
Spliterator<E> 	spliterator() 
				在此列表中的元素上创建late-binding和故障快速 Spliterator 。			
protected void 	removeRange(int fromIndex, int toIndex) 
				从这个列表中删除所有索引在 fromIndex (含)和 toIndex之间的元素。  
ListIterator<E> listIterator() 
				返回列表中的列表迭代器(按适当的顺序)。  
ListIterator<E> listIterator(int index) 
				从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。  

LinkedList实现类的声明:(用链表实现)

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
   		 //...
    }
boolean 	add(E e) 
			将指定的元素追加到此列表的末尾。  
void 		add(int index, E element) 
			在此列表中的指定位置插入指定的元素。  
boolean 	addAll(Collection<? extends E> c) 
			按照指定集合的迭代器返回的顺序将指定集合中的所有元素追加到此列表的末尾。  
boolean 	addAll(int index, Collection<? extends E> c) 
			将指定集合中的所有元素插入到此列表中,从指定的位置开始。  
void 		addFirst(E e) 
			在该列表开头插入指定的元素。  
void 		addLast(E e) 
			将指定的元素追加到此列表的末尾。  
void 		clear() 
			从列表中删除所有元素。  
Object 		clone() 
			返回此 LinkedList的浅版本。  
boolean 	contains(Object o) 
			如果此列表包含指定的元素,则返回 true 。  
Iterator<E> descendingIterator() 
			以相反的顺序返回此deque中的元素的迭代器。  
E 			element() 
			检索但不删除此列表的头(第一个元素)。  
E 			get(int index) 
			返回此列表中指定位置的元素。  
E 			getFirst() 
			返回此列表中的第一个元素。  
E 			getLast() 
			返回此列表中的最后一个元素。  
int 		indexOf(Object o) 
			返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1int 		lastIndexOf(Object o) 
			返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。  
ListIterator<E> listIterator(int index) 
				从列表中的指定位置开始,返回此列表中元素的列表迭代器(按适当的顺序)。  
boolean 	offer(E e) 
			将指定的元素添加为此列表的尾部(最后一个元素)。  
boolean 	offerFirst(E e) 
			在此列表的前面插入指定的元素。  
boolean		offerLast(E e) 
			在该列表的末尾插入指定的元素。  
E 			peek() 
			检索但不删除此列表的头(第一个元素)。  
E 			peekFirst() 
			检索但不删除此列表的第一个元素,如果此列表为空,则返回 null 。  
E 			peekLast() 
			检索但不删除此列表的最后一个元素,如果此列表为空,则返回 null 。  
E 			poll() 
			检索并删除此列表的头(第一个元素)。  
E 			pollFirst() 
			检索并删除此列表的第一个元素,如果此列表为空,则返回 null 。  
E 			pollLast() 
			检索并删除此列表的最后一个元素,如果此列表为空,则返回 null 。  
E			pop() 
			从此列表表示的堆栈中弹出一个元素。  
void 		push(E e) 
			将元素推送到由此列表表示的堆栈上。  
E 			remove() 
			检索并删除此列表的头(第一个元素)。  
E 			remove(int index) 
			删除该列表中指定位置的元素。  
boolean		remove(Object o) 
			从列表中删除指定元素的第一个出现(如果存在)。  
E 			removeFirst() 
			从此列表中删除并返回第一个元素。  
boolean 	removeFirstOccurrence(Object o) 
			删除此列表中指定元素的第一个出现(从头到尾遍历列表时)。  
E 			removeLast() 
			从此列表中删除并返回最后一个元素。  
boolean 	removeLastOccurrence(Object o) 
			删除此列表中指定元素的最后一次出现(从头到尾遍历列表时)。  
E 			set(int index, E element) 
			用指定的元素替换此列表中指定位置的元素。  
int 		size() 
			返回此列表中的元素数。  
Spliterator<E> 	spliterator() 
				在此列表中的元素上创建late-binding和故障快速 Spliterator 。  
Object[] 	toArray() 
			以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。  
<T> T[] 	toArray(T[] a) 
			以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 
			返回的数组的运行时类型是指定数组的运行时类型 

ArrayList和LinkedList的对比

ArrayList内部使用数组来实现List集合的特点,所以在使用访问元素的时候可以使用数组自带的下标来访问元素,效果比较高。但是在ArrayList中插入元素的话,其他元素就会要移动位置,这种操作效率就会低一些

LinkedList内部使用链表来实现List集合的特点,所以在LinkList中进行元素插入的时候,效率比较高。但是如果要使用下标来访问元素的话,LinkList的效率就会比较低,因为链表中本来没有下标,它的这个下标是模拟出来的。(ArrayList下标是数组自带的)

//一个个遍历
Node<E> node(int index) {
    // assert isElementIndex(index);
    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}
private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;

    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}
transient Node<E> first;
transient Node<E> last;
transient int size = 0;
//用transient关键字标记的成员变量不参与序列化过程。

时间戳

使用一个long类型数字来表示一个时间点。

public static long currentTimeMillis()

返回当前时间(以毫秒为单位)。请注意,虽然返回值的时间单位为毫秒,但该值的粒度取决于底层操作系统,并且可能较大。例如,许多操作系统以几十毫秒为单位测量时间。有关“计算机时间”和协调世界时间(UTC)之间可能出现的轻微差异的讨论,请参阅类别Date的说明。

结果 :在1970年1月1日UTC之间的当前时间和午夜之间的差异,以毫秒为单位。

插入和检索测试对比

package com.zzb.day30;
import java.util.*;
public class ListTest {
	
	public static void main(String[] args){
		ListTest lt = new ListTest();
		lt.test();
	}
	public void test(){
		List list1 = new ArrayList();
		List list2 = new LinkedList();
		this.insertData(list1);
		this.insertData(list2);
		this.retrieveData(list1);
		this.retrieveData(list2);
	}
	public void insertData(List list){
		long a1 = System.currentTimeMillis();
		for(int i=0;i<500000;i++){
			list.add(0,1);
		}
		long a2 = System.currentTimeMillis();
		System.out.println(list.getClass()+":"+"插入耗时"+(a2-a1)+"毫秒");
	}

	public void retrieveData(List list){
		long a3 = System.currentTimeMillis();
		for(int i=0;i<500000;i++){
			Object obj = list.get(i);
		}
		long a4 = System.currentTimeMillis();
		System.out.println(list.getClass()+":"+"检索耗时"+(a4-a3)+"毫秒");	
	}
}

在这里插入图片描述

Vector实现类的声明:

public class Vector<E>
    extends AbstractList<E> implements List<E>, 
    RandomAccess, Cloneable, java.io.Serializable{
	//...
}

Vector这个实现类主要是实现List集合中的操作,并且保证了这些操作再多线程环境下也是安全的。这个类中对元素操作的实现方法上,都加入了关键字synchronization,这个关键字是给方法中的代码进行加锁的,加锁后就能保证这个代码的线程安全。

ArrayList和LinkedList里面的方法都不是线程安全的,那么在多线程的操作情况下,这两个类来操作数据的话,可能会发生一些意想不到的情况(非线程安全)

例如:在一个线程中刚刚往ArrayList中存了一个数据,然后立刻在取出来,但是发现这个数据已经没有了,因为在我们往这个集合中存数据的时候,也有另外一个线程在操作这个集合,最后才导致了这么一个现象。

那如果使用Vector的话,就会避免这种情况的发生,因为Vector中进操作数据的方式都进行了加(synchronized),这样以来,这个线程在操作这个集合中的方法时候,其他线程是用不了这个集合中的方法的。保证了第一个线程操作期间,不会有其他线程调用中国集合的方法来干扰自己的操作。

注意,Vector是牺牲了方法的执行效率,换来了方法执行的安全性。

自己模仿写一个ArrayList

package com.zzb.day30;

public interface NewList {

	//在指定位置添加对象
	public void add(int index,Object obj);

	//在数据结构最后位置添加对象
	public void add(Object obj);
	
	//删除指定位置上的对象
	public Object remove(int index);

	//修改指定位置上的数据
	public void set(int index,Object obj);

	//获取指定位置上的数据
	public Object get(int index);

	//获取当前数据结构当前的长度
	public int size();

	//清空所有的数据
	public void clear();
}

class NewArrayList implements NewList{
	
	private Object[] o;//声明一个数组
	private int length = 3;//初始化数组长度
	private int size;//数组中数据的个数

	public NewArrayList(){
		o = new Object[length];
	}
	//在指定位置添加对象
	public void add(int index,Object obj){
		//System.out.print("调用  add(int index,Object obj)");
		if(index >size || index < 0){
			System.out.println("数组越界!!");
			return ;
		}
		if(size >= index){
			Object[] temp = new Object[length*2];
			System.arraycopy(o,0,temp,0,size);
			o = temp;
		}
		//方式一
		for(int i=size;i>index;i--){
			o[i] = o[i-1];
		}
		//方式二
		//System.arraycopy(o,index,o,index+1,size-index);

		o[index] = obj;
		size++;
	}

	//在数据结构最后位置添加对象
	public void add(Object obj){
		//System.out.print("调用  add(Object obj)");
		//数组满了进行扩容操作
		if(size >= length){
			Object[] temp = new Object[length*2];
			//方式二
			System.arraycopy(o,0,temp,0,size);
			o = temp;
		}
		//常规操作
		o[size] = obj;
		size++;
	}
	
	//删除指定位置上的对象
	public Object remove(int index){
		System.out.println("调用  remove(int index)");
		if(index>=size || index<0){
			return null;
		}
		for(int i=index;i<size-1;i++){
			o[i]=o[i+1];
		}
		o[--size] = null;
		return o[index];
	}

	//修改指定位置上的数据
	public void set(int index,Object obj){
		System.out.println("调用 set(int index,Object obj)");
		if( index<0||index>=size ){
			return ;
		}
		o[index] = obj;
	}

	//获取指定位置上的数据
	public Object get(int index){
		System.out.println("调用 get(int index)");
		if(index >= size || index < 0){
			System.out.println("数组越界!!");
			return null;
		}
		return o[index];
	}

	//获取当前数据结构当前的长度
	public int size(){
		System.out.println("调用size()");
		return size;
	}

	//清空所有的数据
	public void clear(){
		System.out.println("调用clear()");
		size = 0;
	}
}

class Test{
	public static void main(String[] args){
		Test t = new Test();
		
		NewList list = new NewArrayList();
		list.add("A");
		t.show(list);
		list.clear();
		t.show(list);
		list.add("B");
		list.add("C");
		list.add(0,"D");
		System.out.println(list.remove(0)+"被删除!");
		list.set(0,"first");
		t.show(list);
	}
	
	public void show(NewList list){
		System.out.println("--------begin-------------");		
		for(int i=0;i<list.size();i++){
			System.out.println("\t"+list.get(i));
		}
		System.out.println("--------end---------------");
	}
}

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章