Java集合

集合

集合体系

单列集合

在这里插入图片描述

双列集合

在这里插入图片描述

Collection 接口

Collection接口,作为单列集合中顶级接口,里面定义了单列集合共有的方法,方法以增,删,改,查,判断,转换为主

Collection, ArrayList后面是jdk5之后的语法—泛型

可以通过泛型语法,为集合设置一个类型,这样就只能存储设置的数据类型

集合中建议存储同一类型数据

集合是容器,可以存储不同的数据,严格上讲集合中是可以存储任何类型的(只能存储引用类型).

//collection接口中常用的方法(单列集合中所共有的方法)
public static void main(String[] args) {
		
		Collection<String> c = new ArrayList<>();
		c.add("a");
		c.add("b");
		c.add("c");
		c.add("d");
		Collection<String> c1 = new ArrayList<>();
		c1.add("a");
		c1.add("b");
		c1.add("c");
		c1.add("d");//向集合末尾添加元素
		
		//c1.addAll(c);//把一个集合添加到另一个集合
		//c.clear();//清空集合中的元素
		System.out.println(c.equals(c1));//比较两个集合中的内容是否相等
		System.out.println(c.isEmpty());//判断集合中元素的个数是否为空
		System.out.println(c.remove("h"));//删除指定元素,成功返回true,没有返回false
		
		//System.out.println(c.retainAll(c1));//在c中保留c1中交集的元素,发生变化返回true,没有变化返回false
		
		System.out.println(c.size());//数组长度length,字符串长度length(),集合长度size()
		
		System.out.println(c);
		System.out.println(c1);
		
		Object[] objs =   c.toArray();//将集合转为Object类型数组
		
		String[] sobject =  c.toArray(new String[c.size()]);//将集合转为指定类型数组
	}
	
}

List

ArrayList

ArrayList底层是数组实现 ,可重复存储元素

add();向集合中添加元素时,底层会默认创建一个长度为10的Object类型数组,当数组装满时,再次添加元素,会创建一个原来数组长度1.5倍的新数组,将原数组内容复制过来 最后将新数组地址赋给底层的数组

public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("a");
		list.add("b");
		list.add("c");
		list.add("d");
		list.add("d");
		list.add(0, "X");// 向指定下标位置上添加元素
		System.out.println(list.get(11));// elementData[index];
		System.out.println(list.remove(0));// 删除并返回指定位置的元素
		list.set(2, "K");// 替换指定位置的元素
		System.out.println(list.size());// 返回集合中实际存储的元素个数
		System.out.println(list);
	}

扩容机制:

(1)创建对象时创建一个指定容量的数组;

(2)添加前判断元素添加后,数组是否能容纳下,如果可以则直接添加,否则会创建一个新数组(扩容);

(3)扩容为原来的1.5倍

LinkedList

存储重复元素,按照添加顺序排放

public static void main(String[] args) {
		LinkedList<String> llist  = new LinkedList<>();
		llist.add("a");//向链表中添加元素 [0,1,2,3,4]
		llist.add("b");
		llist.add("c");
		llist.add("d");
		llist.add("e");
		System.out.println(llist.get(3));//要找的元素位置小于size/2,从头结点开始查找,否则从尾结点开始查找		
		llist.addFirst("X");
		llist.addLast("Y");
		System.out.println(llist.removeFirst());
		System.out.println(llist.removeLast());
		System.out.println(llist);
	}
Vector

底层也是数组实现,但是是线程安全的

public static void main(String[] args) {
		Vector<String> v = new Vector<>();
		v.add("a");
		v.add("b");
		v.add("c");
		v.add("d");
		v.add("a");
		v.get(1);
		System.out.println(v);
	}
List集合接口迭代

(1)for循环

for(int i=0;i<alist.size();i++){
    System.out.println(alist.get(i));
}

(2)增强for循环

for(String item:alist){
    System.out.println(item);
}

(3)迭代器

Iterator<String> it = alist.iterator();
  while(it.hasNext()){
      String item = it.next;
      if(item.equals("a")){
          it.remove();
      }
}

Set

无需且不重复的集合,元素没有索引

set集合只能用增强for循环和迭代器遍历

public HashSet() 
{
	 map = new HashMap<>(); 底层使用的是HashMap实现的.
}
HashSet

HashSet如何判断元素是否重复?

答:在add的底层方法中,每添加一个元素时,就会判断集合中是否已经包含了此元素.在底层使用hashCode()和equals()方法来判断内容是否重复。

hashCode()是Object类中的方法

public native int hashCode(); native修饰的方法称为本地方法,java没有实现,是调用的操作系统中的方法Object类中的 hashCode()获取的对象在内存中的地址

其他类中重写的hashCode(),都不是对象的地址,而是根据对象内容计算出来的哈希值.

aaaaa–>int 1234

abcd–>int 1234

equals(); 除了Object类中的equals是比较对象地址,其他类中都是比较内容是否相等,因为equls效率很低

hashCode(); 判断时,先调用hashCode()计算哈希值,用整数哈希值来比较是否相等,这样提高了比较效率,但是此种做法不安全,因为内容不同,可能计算的哈希值相同.

equals(); 当有哈希值相同时,再去调用equal()方法比较内容是否相等.

public class HashSetDemo2 {
    public static void main(String[] args) {
        //hash值相同,调用equals()进行比较
        HashSet<String> set = new HashSet<>();
        /*add添加时,先用内容调用hashCode()方法计算出一个hash值(int 类型),
        用hash值比较是否相同,效率高,但只用hash值比较不安全,
        这时调用equals()方法对每个字符进行比较
         */
        set.add("a");
        set.add("b");
        set.add("通话");
        set.add("c");
        set.add("重地");
        System.out.println(set);
    }
}

TreeSet

有序(可以根据元素自然顺序排序) 且不能存储重复元素,添加时要对元素进行排序和去重。

//TreeSet不重复可以对元素进行排序 
TreeSet<String> set = new TreeSet<>();
		                 set.add("c");
		                 set.add("b");
		                 set.add("z");
		                 set.add("a");
		                 set.add("x");
		                 set.add("x");
		      System.out.println(set);

存储对象时必须实现Comparable接口。

TreeSet底层数据结构是二叉树(红黑树是一种自平衡的二叉树)

public class Car implements Comparable<Car>{	
	 private int no;
    private String name;
	public Car(int no, String name) {
		super();
		this.no = no;
		this.name = name;
	}
	@Override
	public int compareTo(Car o) {
		return this.no-o.no;
	}
	@Override
	public String toString() {
		return "Car [no=" + no + ", name=" + name + "]";
	} 
}

public class TreeSetDemo {
	 public static void main(String[] args) {
		      Car car1 = new Car(1,"宝马1");
		      Car car2 = new Car(2,"宝马2");
		      Car car3 = new Car(3,"宝马3");
		      TreeSet<Car> carset = new TreeSet<>();
		      carset.add(car1);
		      carset.add(car3);
		      carset.add(car2);
		      System.out.println(carset);
	}
}

Map

HashMap

HashMap 键不能重复,值可以重复键是无序,可以存储一个为null的键

public static void main(String[] args) {
		HashMap<String,String> map = new HashMap<>();
		                   map.put("a", "aa");
		                   map.put("s", "ss");
		                   map.put("b", "bb");
		                   map.put("x", "xx");
		                   map.put("x", "aa");
		                   map.put(null, "cc");		         
		   //System.out.println(map.remove("a"));//删除key,返回其值
		     System.out.println(map.containsKey("a"));//true 是否包含指定的键
		     System.out.println(map.containsValue("aa"));//true 是否包含指定的值
		     System.out.println(map.isEmpty());//false 是否为空
		     System.out.println(map.size());//5 
    
		     Collection<String> c = map.values();//获取map中值的那一列,存放到一个c中
		     Set<String> set =   map.keySet();//获取map中键的那一列,存放到一个set中
		     System.out.println(map.get("b"));
		     map.replace("b", "XXXX");	     
		  System.out.println(map);
		  System.out.println(c);
		  System.out.println(set);
	}

HashMap的底层实现原理:

哈希函数根据内容的哈希值计算出在哈希表中的位置;

第一次添加元素时会创建哈希表,将元素插入到对应的位置,后面如果有位置相同的元素就放在链表中;

当链表长度大于等于7时,将链表转为红黑树;

当哈希表容量达到整数数组的0.75时,扩容为原来的2倍。

HashTable

键不能重复,值可以重复 键是无序

不可以存储一个为null的键和值,是线程安全的.

线程安全,锁住了整个put(),访问量较小时可以使用,访问量较高时,效率太低了。

TreeMap

键不能重复,值可以重复键可以排序,作为键类型的类必需实现排序接口

Collections类

Collections是集合类的工具类,与数组的工具类Arrays类似.

public class Collections {
	public static void main(String[] args) {
		/*ArrayList<String> list = new ArrayList<>();
	                    	list.add("a");
		   Collections.addAll(list, "a","b","c","d");
	          System.out.println(list);*/   
		ArrayList<Integer> list = new ArrayList<>();
    	          list.add(5);
    	          list.add(2);
    	          list.add(3);
    	          list.add(4);
    	          list.add(1);
    	 Collections.swap(list, 0, 2);//交换指定位置的元素
    	//Collections.sort(list); //排序
        /* Collections.sort(list,new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				return o2-o1;
			}
		  });   自定义倒序排序*/
    	          
        //System.out.println(Collections.binarySearch(list,4));//二分查找
    	          
    	    ArrayList<Integer> dlist = new ArrayList<>();
		    	      dlist.add(0);
			          dlist.add(0);
			          dlist.add(0);
			          dlist.add(0);
			          dlist.add(0);
			          dlist.add(0);
    	      Collections.copy(dlist, list);
    	      
    	      //Collections.fill(list,1);
    	      
    	      System.out.println(Collections.max(list));
    	       Collections.shuffle(list);
    	      
             System.out.println(list);    
             System.out.println(dlist);  
             
           // List<Integer> list1 = Collections.emptyList();//返回的是一个内部类EmptyList,此集合不能操作使用,用于逻辑判断
             
	         //test(10, 5,6,3,3,2);
	}
	/*
	   int...a 可变长度的参数  本质是数组
	           一个参数列表中,只能允许有一个可变长度参数
	          如果有,必须放在参数列表的末尾     
	 */
	public static void test(int b,int...a){
		System.out.println(b);
		System.out.println(Arrays.toString(a));
	}
}

泛型

泛型类

泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开

放相同的接口。

一个最普通的泛型类:
public class Demo<T>{ / /T可以为任意标识符,常见的如TEKV等形式的参数常用于表示泛型 
	private T key; / /key这个成员变量的类型为T,T的类型由外部指定 
	public Demo(T key) { / /泛型构造方法形参key的类型也为TT的类型由外部指定 
		this.key = key; 
	}
	public T getKey(){ / /泛型方法getKey的返回值类型为TT的类型由外部指定 
		return key; 
	} 
}
传入的实参类型需与泛型的类型参数类型相同,即为
Integer.Demo<Integer> demo = new Demo<Integer>(123456); 
1.泛型的类型参数只能是类类型 
2.泛型的类型参数可以有多个。
3.如果没有定义具体类型,默认为Object

从泛型类派生子类

子类也是泛型类,子类和父类的泛型类型要一致

class A<T> extends Demo<T> 

子类不是泛型类,父类要明确泛型的数据类型

class A extends Demo<String>

泛型通配符

类型通配符一般是使用"?"代替具体的类型实参。

? 表示实际传入的参数的泛型类型 ?表示可以是任意的 也称无界通配符

public void show(Demo<?> obj){
		 ?表示实际传入的参数类型可以是任意的
	}

● 类型通配符上限

/接口<extends 实参类型> 

要求该泛型的类型,只能是实参类型,或实参类型的子类类型。 

● 类型通配符下限

/接口<super 实参类型> 

要求该泛型的类型,只能是实参类型,或实参类型的父类类型。

类型擦除

泛型是Java 1.5版本才引进的概念,在这之前是没有泛型的,但是,泛型代码能够很

好地和之前版本的代码兼容。那是因为,泛到信息只存在于代码编译阶段,在进入JVM之

前,与泛型相关的信息会被擦除掉,我们称之为一类型擦除。

泛型类被类型擦除后,相应的类型就被替换成 Object 类型或者上限类型.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JIANG++

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值