Java基本集合List-Set-Map介绍

1 篇文章 0 订阅
1 篇文章 0 订阅

 List

元素有序,且可重复

遍历方法:1-for循环通过下标遍历 2-foreach遍历 3-使用迭代器遍历 4-使用lambda遍历

扩容:初始容量10,负载因子0.5,扩容增量0.5被 新容量=旧容量+旧容量*0.5或者新容量=旧容量*1.5

实现

ArrayList

1  简单数据结构,超出容量会自动扩容。所以在我们看来ArrayList的空间是无线大的,动态数据 

2   内部实现是基于基础的对象数组       

3   随机访问块                            

4   不适合随机的增加或者删除(因为ArrayList是一个对象数据,数据一旦要修改整个数据位置都会改动)   

5  线程不安全(因为整个方法没有锁)


List<Student> ls=new ArrayList<Student>();
	
    /**
		 * student是我的一个实体类
		 */
		List<Student> ls=new ArrayList<>();
		
		// 输出方式1  使用遍历输出
		for (Student su : ls) {
			System.out.println(su);
		}
		
		
		
		// 输出方式2   使用for循环输出
		for (int i = 0; i < ls.size(); i++) {
			System.out.println(ls.get(i));
		}
		
		
		//输出方式3  使用迭代器输出
		Iterator<Student> lt= ls.iterator();
		
		//判断是否有下一位
		if(lt.hasNext()) {
			//得到它的下一位
			lt.next();
			System.out.println(lt);
		}
		
		//输出方式4 使用lambda表达式
		ls.forEach(l->System.out.println(l));
        


	//BeFore是在每个测试方法之前执行
	@Before
	public void stati() {
		ls.add(new Student("11",1));
		ls.add(new Student("22",2));
		ls.add(new Student("33",3));
		ls.add(new Student("44",4));
		ls.add(new Student("55",5));
		ls.add(new Student("66",6));
	}
	
	//test方法代表的是你在运行这个方法时,就只能运行你所选中的方法。其他的test方法是不能运行的,这样比较好测试
	@org.junit.Test
	public void text01() {
		//遍历  删除
		//当使用遍历删除集合时,要用break来终止循环,否则报错
		//因为你遍历的是原来的数组,你进行删除后。list这个集合里面的数据已经发生改变了,必须使用break来终止循环
		
		for (Student s : ls) {
			if(s.getSid()==1) {
				ls.remove(s);
				break;
			}
		}
		
		//输出
		ls.forEach(t->System.out.println(t));
		
	}
	
	@org.junit.Test
	public void text02() {
		
		//使用迭代器进行删除
		Integer a[]= {1,3,65,3,23,231,5,4,9};//定义一个数组
		List<Integer> ls=Arrays.asList(a);//把数组放到一个集合里面
		Iterator<Integer> it= ls.iterator();//使用 迭代器
		while(it.hasNext()) {//判断是否有下一个
			Integer s= it.next();//如果有下一个值
			if(s==1) {//判断值是否为1
				it.remove();//如果等于就删除
				//执行完毕后会报错,因为Arrays里面没有remove这个方法  可以看看源代码。但是我们为什么可是使用remove方法代码而不报错,因为Arrays里面继承了Arraylist接口。
				//所以我们必须使用下一种方法
			}
		}
		
	}
	
	
	@org.junit.Test
	public void text03() {
		//使用迭代器删除
		Integer a[]= {1,3,4,2,5,4};
		List<Integer> ls=new ArrayList<>(Arrays.asList(a));//这里我使用的是Arraylist,在ArrayList里面放了一个Arrays集合。这样我们就不会报错了
		Iterator<Integer> it= ls.iterator();
		while(it.hasNext()) {
			Integer s= it.next();
			if(s==1) {
				it.remove();
				break;
			}
		}
		ls.forEach(e->System.out.println(e));
		
		
	}
	
	@org.junit.Test
	public void text04() {
		//使用流的方式删除
		//从第一个开始,如果id不为1,则就保存到新的list集合中   filter过滤条件
		List<Student> a= ls.stream().filter(t-> t.getSid()!=1).collect(Collectors.toList());
		//输出
		a.forEach(e->System.out.println(e));
		
	}



    //java的引用传递
	@org.junit.Test
	public void text05() {
		//当我们需要对一个集合进行修改时,要保证之前的集合不会被修改就需要使用深度拷贝
		List<Student> lss=updata02(ls);
		lss.forEach(s->System.out.println(s));
		System.out.println("==========");
		ls.forEach(a->System.out.println(a));
	}
	
	//深度拷贝(克隆)
	//1使用json传递
	private List<Student> updata02(List<Student> o ){
		String json= JSON.toJSONString(o);//这里需要一个json工具包,我这里使用的是阿里的json工具包fastjson
		//复制一个新的集合
		List<Student> ls= JSON.parseArray(json,Student.class);
		//开始遍历
		for (Student s : ls) {
			s.setName("1111");
		}
		
		return ls;
	}
	

LinkedList

1  LinkedList额外提供了一些方法。比如addFirst 在集合最前面增加一组数据,addLast 在集合最后面增加一组数据,以及remove和insert方法等等       

2  LinkedList可用作堆栈(stack)包括了push和pop方法  队列queue  或双向队列deque 

3  以双向对象实现,所以能够很好的实现增加或者删除。链表无容量限制,允许元素为空 

4  适合最随机的增加或者删除               

 5  线程不安全(方法里面没有锁)


	java.util.LinkedList<Student> l=new java.util.LinkedList<>();
	
	@Test
	public void text01() {
		//Linkedlist的方法基本与ArrayList方法一致
		l.addFirst(new Student("1", 1));//在集合的最前面增加一组数据
		l.addLast(new Student("2", 2));//在集合的最后面增加一组数据
		
	}

 Vector

线程安全(说白了在每个方法里面都加了锁)并行效率慢,不建议使用。方法与ArrayList差不多

CopyOnwiterArrayList

1  写时复制             

2  线程安全                                                                                 

3  适合读多写少的场景(我查阅了很多数据,在数据很多的适合还是不适合写)   

4  写时复制一个新的数据,在这个新的数组里面完成增加或者修改删除,后将新数组赋值给旧数组。最终完成数据一致性         

5   比Vector性能高(虽然copyonwiterarraylist里面的方法也有所,但是它是写时赋值一个新的数组。在用户未完成新数组修改的方法后,其他用户还是访问的是旧数组。两边都不耽误) 

 6  最终一致性 

7 继承了List接口,使用方法与ArrayList基本一致(你只要会用ArrayList就会copyonwiterarraylist)

Set

特点:无序,不重复

遍历:foreach,迭代器,下标,lambda表达式。方法基本与list一致

扩容:初始容量为16,负载因子0.75。扩容增加一倍

实现

HashSet

1  它存储唯一元素并允许空值,依据对象的hashcode来判断该元素是否存在       

2  由HashMap支持     

3  不保存插入顺序                                                                         

4  非线程安全(方法也没有锁)


	private Set<Student> s=new HashSet<>();
	
	@Before
	public void set() {
		//增加
		s.add(new Student("1", 1));
		s.add(new Student("2", 2));
		s.add(new Student("3", 3));
		s.add(new Student("4", 4));
		s.add(new Student("5", 5));
	}
	
	@Test
	public void text01() {
		//注意,要在对象里面实现equals和hashCode方法。要不然还是会能增加重复的数据
		s.add(new Student("1", 1));//我这里已经实现了这两个方法,所以数据不会重复增加
		s.forEach(t->System.out.println(t));
	}
	
    

       //Set深度拷贝
		@Test
		public void text05() {
			String json= JSON.toJSONString(s);
			Set<Student> p= JSON.parseObject(json,new TypeReference<Set<Student>>() {});
			for (Student s : p) {
				if(s.getSid()==1) {
					p.remove(s);
					break;
				}
			}
			
			
			System.out.println("之前的数据");
			s.forEach(z->System.out.println(z));
			System.out.println("现在的数据");
			p.forEach(c->System.out.println(c));			
		}
		

TreeSet

1  是一个有序的,且不包含重复的额元素的集合     

2  作用是根据根据有序的Set集合,自然排序或者根据提供的Comparator进行排序       

3   TreeSet是基于TreeMap实现的

Map

特点:无序,键值对。键不可以重复,值可以重复。键如果重复则覆盖,没有继承Collection接口

扩容:初始容量16,负载因子0.75,扩容增量1倍

遍历:1-先获取所有键的Set集合,再遍历(通过键来获取值)2-取出保存好的Entry的Set,再遍历Set即可

实现

HashMap

线程不安全,但是速度最快,最常用

内部采用对象数组存放数据

流程图中绿色标出的部分为JDK8新增的处理逻辑,目的是在Table[i]中的Node节点数量大于8时,通过红黑树提升查找速度。

put执行过程

在使用put的方法时,Map中的table数组会使用hashcode方法来计算写入的Key值到底该数组存储table中什么位置。前提:在实体类中写入hashcode与equals方法

在我们使用get方法的时候也是类似,首先会通过hashcode计算我们需要得到的数据会保存在哪里。如果table[i]的存储的数组只有一个,直接会把该数据得到。如果里面的数据不止一只,那它就会通过遍历的方式,一个一个来遍历,最终得到想要的结果。因为table[i]中存储的是对象数组是链表结构。在jdk8之后就开始不同了,如果你的table[i]中的数组超过了8个,那它就会使用红黑树的方式来存储数据。这样的存储方式会让数据能够更好的遍历,因为不需要一个一个找了,所以速度会加快。前提:要在jdk8之后的版本才有这个功能,在jdk8版本之前都是数组的形式来存储数据的

Table数组中的的Node

链表结构示意图

红黑树示意图


	 java.util.Map<String, Object> p=new HashMap<>();
	 
	 @Before
	 public void befor() {
		 //增加
		 p.put("1", 1);
		 p.put("2", 2);
		 p.put("3", 3);
		 p.put("4", 4);
		 p.put("5", 5);
		 
	 }
	 
	 @Test
	 public void text01() {
		 //map键不能重复,值可以
		 p.put("1", 6);
		 //如果键重复则会覆盖
		System.out.println(p);
	 }
	 
	 
	 //使用迭代器遍历
	 @Test
	 public void text02() {
		 //得到键
		 Iterator<String> i= p.keySet().iterator();
		 while(i.hasNext()) {
			 String s= i.next();
			 //通过键输出对应的值
			 System.out.println(p.get(s));
		 }
		 
		 
	 }
	 
	 //使用EntrySet遍历
	 @Test
	 public void text03() {
		 Iterator<Entry<String, Object>> i= p.entrySet().iterator();
		 while(i.hasNext()) {
			 Entry<String, Object> e= i.next();
			 System.out.println(e.getKey()+e.getValue());
		 }		 
	 }
	 
	 //lambda表达式遍历
	 @Test
	 public void text04() {
		 p.forEach((k,v)->System.out.println(k+v));
	 }
	 
	 
	 //增加不存在的数据
	 @Test
	 public void text05() {
		 //如果Map集合里面没有5这个键,则增加
		 if(!p.containsKey("5")) {
			 p.put("5", 5);
		 }
		 
		 //第二种方法
		 //缺席,如果4这个键位有则不增加。如果没有则增加这个键位
		 p.putIfAbsent("4", 4);
		 
	 }

HashTable

线程安全,不太常用(用一把锁锁住所有,性能慢)方法与HashMap差不多

ConcurrentHashMap

线程安全,性能比HashTable高(因为是分段锁,而且还实现了cis接口)方法与HashMap差不多

TreeMap

1  Key值按一定的顺序排序         

2  添加或者获取元素比ConcurrentHashMap慢。因为需要维护内部的红黑树,用于保证Key值的顺序


	java.util.TreeMap<String, Object> t;
	
	//从小到大排序
		@Test
		public void text02() {
			//自己本身自带的排序
			t=new java.util.TreeMap<>();
			t.put("5", 5);
			t.put("4", 4);
			t.put("3", 3);
			t.put("2", 2);
			t.put("1", 1);
			t.forEach((k,v)->System.out.println(k+":"+v));
		}

	
	
	//按key值进行排序
	@Test
	public void text01() {
		t=new java.util.TreeMap<>(new Comparator<String>() {//Comparator比较器
            //当我们在方法时使用了匿名函数,同时在实体类是实现了Comparable。匿名函数的优先级别会更高
			@Override
			public int compare(String a, String b) {
				//比较  a>b返回正数  a=b 返回0  	a<b返回负数
				return b.compareTo(a);//如果是a.compareTo(b)则是从小到大排序,如果是b.compareTo(a)则是从大到小排序
			}
			
		});
		
		
		t.put("5", 5);
		t.put("4", 4);
		t.put("3", 3);
		t.put("2", 2);
		t.put("1", 1);
		
		
		//输出
		t.forEach((k,v)->System.out.println(k+v));
	}
	
	
	
	//排序
	@Test
	public void text04() {
		TreeSet<Student> t=new TreeSet<>(new Comparator<Student>() {

			@Override
			public int compare(Student a, Student b) {
				// TODO Auto-generated method stub
				return b.getSid()-a.getSid();//倒序
			}
			
		});
		
		t.add(new Student("1", 1));
		t.add(new Student("2", 2));
		t.add(new Student("3", 3));
		t.add(new Student("4", 4));
		t.add(new Student("5", 5));
		t.forEach(y->System.out.println(y));
		
	}
	
	//最后一种方法可以通过在实体类中写入Comparator
	@Test
	public void text05() {
		TreeSet<Student> s=new TreeSet<>();
		s.add(new Student("1", 1));
		s.add(new Student("2", 2));
		s.add(new Student("3", 3));
		s.add(new Student("4", 4));
		s.add(new Student("5", 5));
		s.forEach(i->System.out.println(i));
	}
	

LinkedHashMap

继承HashMap

LinkedHashMap是有序的,而且默认为插入顺序(与你怎么写就怎么输出)但我们需要有序的存储Key或者value是就使用LinkedHashMap

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值