容器

本文深入探讨了Java中的容器类,重点介绍了Collection接口及其子接口List和Set,包括ArrayList、LinkedList、HashSet和TreeSet的特性和使用场景。此外,还详细讲解了Map接口以及HashMap和TreeMap的实现原理,强调了自定义类型在集合中的去重和排序策略。
摘要由CSDN通过智能技术生成

容器|集合:

如果对象的数量与生命周期都是固定的,自然我们也就不需要很复杂的数据结构。
我们可以通过创建引用来持有对象,如
Class clazz;
也可以通过数组来持有多个对象,如
Class[] clazs = new Class[10];

然而,一般情况下,我们并不知道要创建多少对象,或者以何种方式创建对象。数组显然只能创建固定长度的对象,为了使程序变得更加灵活与高效,Java类库提供了一套完整的容器类,具备完善的方法来解决上述问题。

数组: 存储多个数据
特点:
1) 定长
2) 所有数据的类型保持一致
3) 有序

容器特点: 可变长,可有存储任意类型的数据,必须是引用数据类型
只能存储字符串类型的数据

 public class Demo01 {
	public static void main(String[] args) {
		MyContainer my=new MyContainer();
		my.add("nihao");
		my.add("lisi");
		System.out.println(my.size);
		System.out.println(my.get(0));
		System.out.println(my.get(1));
		my.remove(0);
		System.out.println(my.size);
		System.out.println(my.get(0));
	}
}
//自定义的容器类  
class MyContainer{
	//存储数据的字符串数组
	private String[] arr;
	//容器中存储数据的个数
	int size;
	
	public MyContainer() {
		arr=new String[0];
	}
	/*
	 * 添加 ,追加在原数据的最后
	 */
	public void add(String value) {
		//备份原数组 
		String[] temp=arr;
		//新数组
		arr=new String[size+1];
		if(size!=0){
			for(int i=0;i<size;i++){
				arr[i]=temp[i];
			}
		}
		arr[size]=value;  //添加的数据赋值
		size++; //长度+1
	}
	/*
	 * 获取方法 根据索引获取 参数是索引
	 */
	public String get(int index){
		if(index<0  || index>=size){
			throw new ArrayIndexOutOfBoundsException("索引越界");
		}
		return arr[index];
	}
	//修改方法  修改指定索引位置的数据
	//删除方法  删除指定索引位置的数据
	public void remove(int index){
		//备份原数组
		String[] temp=arr;
		//创建新数组
		arr=new String[size-1];
		//遍历原数组
		for(int i=0;i<size;i++){
			if(i<index){
				arr[i]=temp[i];
			}else if(i==index){
				continue;
			}else{
				arr[i-1] = temp[i];
			}
			size--;
		}
	}
}

在这里插入图片描述
通过上图,可以把握两个基本主体,即Collection和Map。

  1. Collection是一个接口,是高度抽象出来的集合,它包含了集合的基本操作和属性。Collection包含了List和Set两大分支。
  2. List是一个有序的队列,每一个元素都有它的索引。第一个元素的索引值是0。List的实现类有LinkedList, ArrayList, Vector, Stack。 Set是一个不允许有重复元素的集合。
    Set的实现类有HastSet和TreeSet。HashSet依赖于HashMap,它实际上是通过HashMap实现的;TreeSet依赖于TreeMap,它实际上是通过TreeMap实现的。
  3. Map是一个映射接口,即key-value键值对。Map中的每一个元素包含“一个key”和“key对应的value”。
  4. AbstractMap是个抽象类,它实现了Map接口中的大部分API。而HashMap,TreeMap,WeakHashMap都是继承于AbstractMap。
    Hashtable虽然继承于Dictionary,但它实现了Map接口。
  5. Iterator是遍历集合的工具,即我们通常通过Iterator迭代器来遍历集合。我们说Collection依赖于Iterator,是因为Collection的实现类都要实现iterator()函数,返回一个Iterator对象。ListIterator是专门为遍历List而存在的。
  6. Enumeration是JDK 1.0引入的抽象类。作用和Iterator一样,也是遍历集合;但是Enumeration的功能要比Iterator少。在上面的框图中,Enumeration只能在Hashtable,
    Vector, Stack中使用。
  7. Arrays和Collections是操作数组、集合的两个工具类。

Collection 接口

	1.for each
	2.迭代器

public class CollectionDemo01 {
	public static void main(String[] args) {
		Collection  col=new ArrayList();
		
		//添加
		col.add("haha");
		col.add(1);
		col.add(false);
		col.add(null);
		
		//删除
		col.remove("haha");
		//包含
		System.out.println(col.contains("haha"));
		System.out.println(col.size());
		//for each
		for(Object o:col){
			System.out.println(o);
		}
		//迭代器
		//1)获取迭代器对象
		Iterator it=col.iterator();  //it用来遍历col容器
		//2)判断是否存在下一个元素boolean hasNext() 如果仍有元素可以迭代,则返回 true。 
		while(it.hasNext()){
			//3)获取E next() 返回迭代的下一个元素。 
			System.out.println(it.next());
		}
	}
}

List 有序可重

新增:一些与索引相关的方法

遍历:
1.普通for
2.增强for
3.迭代器iterator
4.列表迭代器 listIterator

public class ListDemo01 {
	public static void main(String[] args) {
		//泛型可以规范容器中存放的所有数据的类型
		List<Integer> list=new ArrayList<Integer>();
		list.add(11);
		list.add(22);
		list.add(33);
		list.add(44);
		
		//void add(int index, E element) 
		list.add(0,2);
		
		System.out.println(list);
		
		//E get(int index)  
		System.out.println(list.get(2));
		
		//remove(index|obj)   如果内容和索引有相同情况,以索引为主
		System.out.println(list.remove(2));
		System.out.println(list);
		// E set(int index, E element) 用指定元素替换列表中指定位置的元素(可选操作)。 
		list.set(3, 333);
		System.out.println(list);
		
		//普通for
		for(int i=0;i<list.size();i++){
			System.out.println(list.get(i));
		}
		
		//for each
		for(Integer i: list){
			System.out.println(i);
		}
		
		//iterator
		//1) 获取一个迭代器对象
		for(Iterator<Integer> it=list.iterator();it.hasNext();){
			System.out.println(it.next());
		}
	}
}

list的遍历方式:

public class ListDemo02 {
	public static void main(String[] args) {
		List<String> list=new ArrayList();
		list.add("蜘蛛侠");
		list.add("钢铁侠");
		list.add("美国队长");
		list.add("灭霸");
		list.add("火箭浣熊");
		
		//判断  1.contains(obj)
		/*if(list.contains("灭霸")){
			list.add("惊奇队长");
		}*/
		//遍历  for
		/*for(int i=0;i<list.size();i++){
			if("灭霸".equals(list.get(i))){
				list.add("惊奇队长");
			}
		}*/
		//for.each
		//当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。 
		/*for(String str:list){
			if("灭霸".equals(str)){
				list.add("惊奇队长");
			}
		}*/
		//iterator 迭代器
		当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。 
		/*Iterator it=list.iterator();
		while(it.hasNext()){
			if("灭霸".equals(it.next())){
				list.add("惊奇队长");
			}
		}*/
		
		/*
		 * 列表迭代器:ListIterator<E> listIterator() 返回此列表元素的列表迭代器(按适当顺序)。 
		 */
		ListIterator<String> ls=list.listIterator();
		while(ls.hasNext()){
			if("灭霸".equals(ls.next())){
				ls.add("惊奇队长");
			}
		}
		System.out.println(list);
	}
}

list的实现类

  1. ArrayList

    底层实现: 是由可变数组实现的,通过数组的拷贝实现
    优点: 查询效率高
    缺点: 添加,删除效率低,需要大量的使用数组的拷贝,效率较低
    使用: 大量做查询的时候使用
    扩容机制: int newCapacity = oldCapacity + (oldCapacity >> 1); 新容量每次扩容原来的1.5倍,使用copyOf方法进行动态扩容

    存储自定义的引用数据类型的数据,使用任何比较数据是否相等的方法,需要手动重写equals方法

  2. Vector 向量

    区别:
    1.ArrayList线程不安全的 Vector同步的线程安全的
    2.ArrayList扩容原容量的1.5倍 Vector扩容原容量的2倍

  3. LinkedList

    底层: 使用双向链表结构实现
    优点: 做增删效率高
    缺点: 查询效率低
    使用: 大量做增删的时候使用
    新增: 新增了一些操作于链表头尾的方法

    public class ArrayListDemo03 {
    	public static void main(String[] args) {
    		ArrayList<Person> list=new ArrayList();
    		
    		list.add(new Person("张三",18));
    		list.add(new Person("李四",19));
    		//默认比较对象的地址,因为多个new多个对象,重写equals方法
    		System.out.println(list.indexOf(new Person("张三",18)));  //0
    	}
    }
    
    //Person类
    
    public class Person {
    	private String name;
    	int age;
    	
    	public Person() {
    		// TODO Auto-generated constructor stub
    	}
    
    	public Person(String name, int age) {
    		super();
    		this.name = name;
    		this.age = age;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    	@Override
    	public String toString() {
    		return "Person [name=" + name + ", age=" + age + "]";
    	}
    
    
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (getClass() != obj.getClass())
    			return false;
    		Person other = (Person) obj;
    		if (age != other.age)
    			return false;
    		if (name == null) {
    			if (other.name != null)
    				return false;
    		} else if (!name.equals(other.name))
    			return false;
    		return true;
    	}
    }
    

简单使用单向链表实现LinkedList

public class LinkedListDemo04 {
	public static void main(String[] args) {
		MyLinkedList my=new MyLinkedList();
		my.add("haha1");
		my.add("haha2");
		my.add("haha3");
		my.add("haha4s");
		System.out.println(my.getSize());
		System.out.println(my.get(0));
		System.out.println(my.get(1));
		System.out.println(my.get(2));
		System.out.println(my.get(3));
		System.out.println(my.get(4));
	}
}

//自定义MyLinkedList 类 只能存储字符串数据
class MyLinkedList{
	private Node head;
	private int size;
	
	public MyLinkedList() {
		// TODO Auto-generated constructor stub
	}
	public int getSize(){
		return this.size;
	}
	/*
	 * 添加方法
	 */
	public void add(String value) {
		//新节点
		Node temp=new Node(value,null);
		//把新节点挂在原链表节点的最后
		//判断当前的新节点是否为链表头
		if(null==head){
			head=temp;
			size++;
			return;
		}
		Node node=head;
		while(node.getNext()!=null){
			node=node.getNext();
		}
		node.setNext(temp);
		size++;
	}
	
	//根据索引获取
	public String get(int index){
		//i作为链表结构的索引  模拟
		Node temp=head;
		for(int i=0;i<size;i++){
			if(i!=index){
				temp=temp.getNext();
			}else{
				return temp.getData();
			}
		}
		return null;
	}
}

/*
 * 节点类:
 */
class Node{
	private String data;  //数据
	private  Node next; //下一个节点的地址
	
	public Node() {
		// TODO Auto-generated constructor stub
	}

	public Node(String data, Node next) {
		super();
		this.data = data;
		this.next = next;
	}

	public String getData() {
		return data;
	}

	public void setData(String data) {
		this.data = data;
	}

	public Node getNext() {
		return next;
	}

	public void setNext(Node next) {
		this.next = next;
	}

	@Override
	public String toString() {
		return "Node [data=" + data + ", next=" + next + "]";
	}
}

Set 无序 不可重复

新增方法: 无
遍历方式: 1)for each 2)迭代器

HashSet:*** -->HashMap维护的
底层结构:底层是由哈希表存储的 (数组+链表+红黑树组成)
优点:添加,查询,删除效率高
缺点:无序
HashSet存储自定义引用数据类型去重问题:我们认为内容相同就是一个对象
需要重写这个类型的hashcode和equals方法,如果hashcode不相同,不会比较两个对象的equals,hashcode相等才会比较equals方法进一步比价内容

	public class SetDemo01 {
		public static void main(String[] args) {
			HashSet<String> set=new HashSet();
			set.add("胡歌");
			set.add("杨洋");
			set.add("宋承宪");  //字符串的内容相同,hashcode值肯定相同
			set.add("宋承宪");
			set.add("苏志燮");
			//无序: 存放的顺序与真实存储的顺序不一致,顺序一旦确定不会改变
			System.out.println(set);
			System.out.println(set);
			System.out.println(set);
			System.out.println(set);
			
			/*String str1=new String("nihao");
			String str2=new String("nihao");
			System.out.println(str1.hashCode());
			System.out.println(str2.hashCode());*/
			
		}
	}

TreeSet: -->–>TreeMap维护的
底层结构: 红黑树
优点:查询效率快,有序(默认升序,自定义排序方式)
缺点:但是ArrayList,HashSet快

存储自定义引用数据类型的去重+排序:存储person类型的对象数据的排序和去重问题
去重排序都是按照比较器的比较规则定义
比较器可以是内部或者外部

比较器
内部比较器|自然比较器:默认的比较方式
类实现java.lang.Comparable接口,重写compareTo(T o) 方法,在方法中定义比较规则

  • 内部比较器,每次修改都要修改源码,其他类不能使用

  • 外部比较器|自定义比较器
    对Comparator接口的方法compare方法进行重写,定义比较规则
    以外部比较规则优先,没有外部比较规则默认使用自然排序

    查看api,看数组的Arrays.sort方法,对对象类型进行按照身高降序排序,遍历

    TreeSet|TreeMap|Arrays.sort(数组) | Collections.sort(容器,外部比较器对象)

    public class Test2 {
    public static void main(String[] args) {
    // Comparator com=new Comparator(){
    //
    // @Override
    // public int compare(Object o1, Object o2) { //外部比较器
    // // TODO Auto-generated method stub
    // return ((Person)o2).getAge() - ((Person)o1).getAge();
    // }
    //
    // };
    Set tree = new TreeSet((Object o1, Object o2)-> { //外部比较器简写
    return ((Person)o2).getAge() - ((Person)o1).getAge();
    });
    Person p1=new Person(“zhangsan”,18);
    Person p2=new Person(“lisi”,17);
    Person p3=new Person(“wangwu”,19);
    Person p4=new Person(“lisi”,17);
    Person p5=new Person(“zhaoliu”,17);
    tree.add(p1);
    tree.add(p2);
    tree.add(p3);
    tree.add(p4);
    tree.add(p5);

     	System.out.println(tree);
     }
    

    }
    //自定义类
    public class Person implements Comparable{ //内部比较器
    //public class Person {
    private String name;
    int age;

     	public Person() {
     		// TODO Auto-generated constructor stub
     	}
     
     	public Person(String name, int age) {
     		super();
     		this.name = name;
     		this.age = age;
     	}
     
     	public String getName() {
     		return name;
     	}
     
     	public void setName(String name) {
     		this.name = name;
     	}
     
     	public int getAge() {
     		return age;
     	}
     
     	public void setAge(int age) {
     		this.age = age;
     	}
     
     	@Override
     	public String toString() {
     		return "Person [name=" + name + ", age=" + age + "]";
     	}
     
     	@Override
     	public int hashCode() {
     		final int prime = 31;
     		int result = 1;
     		result = prime * result + age;
     		result = prime * result + ((name == null) ? 0 : name.hashCode());
     		return result;
     	}
     
     	@Override
     	public boolean equals(Object obj) {
     		if (this == obj)
     			return true;
     		if (obj == null)
     			return false;
     		if (getClass() != obj.getClass())
     			return false;
     		Person other = (Person) obj;
     		if (age != other.age)
     			return false;
     		if (name == null) {
     			if (other.name != null)
     				return false;
     		} else if (!name.equals(other.name))
     			return false;
     		return true;
     	}
     
     	/*
     	 * 按照年龄的大小做升序排序
     	 */
     	@Override
     	public int compareTo(Person o) {
     		
     		return this.getAge() - o.getAge();
     	}
     }
    

Map

每一个数据都是一个键值对形式的数据 k—v
key是唯一的,不可重复 —所有的key,set集合
value可以是任意类型的数据,value不唯一,可重复 ----所有的value,Collection集合
只按照key值计算位置|去重|排序
一个key只能对应一个value(一对多可以对应value是一个集合)
如果key相同的数据,value会覆盖

	public class MapDemo01 {
		public static void main(String[] args) {
			Map<String,Boolean> map=new HashMap();
			//存放值  put()
			map.put("赵", null);
			map.put("钱", false);
			map.put("孙", true);
			System.out.println(map.put("李", false));
			System.out.println(map);
			//相同key,value会覆盖
			System.out.println(map.put("孙", null));
			System.out.println(map);
			
			/*
			 * boolean containsKey(Object key) 
			          如果此映射包含指定键的映射关系,则返回 true。 
			   boolean containsValue(Object value) 
			          如果此映射将一个或多个键映射到指定值,则返回 true。 
			 */
			System.out.println(map.containsKey("孙"));
			System.out.println(map.containsValue(null));
			
			//V get(Object key) 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。 
			System.out.println(map.get("吴"));
			
			//V put(K key, V value)  
			System.out.println(map.put("王", false));
			// V remove(Object key) 	
			System.out.println(map.remove("吴"));
		}
	}

Map 的遍历
1.keySet() 根据key获取value
2.values() 直接获取所有的value值
3.Set<Map.Entry<K,V>> entrySet()

	public class MapDemo02 {
		public static void main(String[] args) {
			Map<String,Boolean> map=new HashMap();
			//存放值  put()
			map.put("赵", false);
			map.put("钱", false);
			map.put("孙", true);
			map.put("李", true);
			map.put("周", true);
			
			System.out.println(map);
			
			System.out.println("-------keySet()------");
			/*Set<String> keys=map.keySet();
			for(String s: keys){
				System.out.println(s+"-->"+map.get(s));
			}*/
			
			System.out.println("------- values()--------");
			Collection col=map.values();
			/*Iterator it=col.iterator();
			while(it.hasNext()){
				System.out.println(it.next());
			}*/
			
			System.out.println("-----entrySet()--------");
			Set<Map.Entry<String, Boolean>> set=map.entrySet();
			for(Map.Entry<String, Boolean> entry : set){
				System.out.println(entry.getKey()+"==>"+entry.getValue());
			}
		}
	}

HashMap 存储自定义引用数据类型的数据
key为自定义的引用数据类型的时候,去重,需要对key数据的类型重写hashcode和equals方法
初始容量 (16) 和默认加载因子 (0.75) 每次扩容原容量的2倍

TreeMap
key为自定义的引用数据类型的时候,去重,排序,需要key数据的类型实现内部|外部比较器

HashMap存储的value值为自定义应用数据类型对象时,达到去重,如果value相同,放不进入,怎么做?
遍历value|判断value是否存在,比较如果不相同,再存放,如果相同就不放

	public class HashMapDemo03 {
		public static void main(String[] args) {
			Person p1=new Person("zhangsan",18);
			Person p2=new Person("lisi",17);
			Person p3=new Person("haha",8);
			Person p4=new Person("lisi",17);
			
			TreeMap<Person,Integer> map=new TreeMap((o1,o2)->((Person)o2).getAge() -((Person)o1).getAge());
			map.put(p1, 2000);
			map.put(p2, 30000);
			map.put(p3, 10000);
			map.put(p4, 15000);
			
			System.out.println(map);
		}
	}

Properties 属性列表中每个键及其对应值都是一个字符串。
经常被作为配置文件使用:

	public class PropertiesDemo05{
		public static void main(String[] args) throws IOException {
			Properties pro=new Properties();
			pro.put("小熊历险记","李四");
			pro.put("小白历险记","李白");
			pro.setProperty("haha", "123");
			//现加载
			System.out.println(pro);
			pro.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
			//读入
			System.out.println(pro.getProperty("name"));
			System.out.println(pro.getProperty("age"));
		}
	}

Hashtable 线程安全的hashmap
问如何控制HashMap的线程安全问题:
1.Hashtable
2.Collections工具类中synchronizedMap(Map<K,V> m)
3.juc包下ConcurrentHashMap --效率高

static <T extends Comparable<? super T>> void sort(List list) 根据元素的自然顺序 对指定列表按升序进行排序。
static void sort(List list, Comparator<? super T> c)
根据指定比较器产生的顺序对指定列表进行排序。

	public class Demo04 {
		public static void main(String[] args) {
			ArrayList<Person> list=new ArrayList();
			
			list.add(new Person("张三",18));
			list.add(new Person("李四",19));
			list.add(new Person("王五",17));
			list.add(new Person("赵六",20));
			System.out.println(list);
			Collections.sort(list);
			System.out.println(list);
			
			Collections.sort(list,(o1,o2)->((Person)o2).getAge() -((Person)o1).getAge());
			System.out.println(list);
			
			//static void reverse(List<?> list) 反转指定列表中元素的顺序。 
			Collections.reverse(list);
			System.out.println(list);
			
			//static void shuffle(List<?> list) 使用默认随机源对指定列表进行置换。 
			Collections.shuffle(list);
			System.out.println(list);
			
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值