Java集合

---------------------- android培训java培训、期待与您交流! ---------------------- ----------------------


集合

集合是由数组过来的,数组不能随着元素的增加,长度增长。
数组中可以存储基本的数据类型,也可以装引用类型。
集合只能用于存储对象,集合的长度是可变的,集合可以存储不同类型的对象。
Collection接口的功能描述:
1.添加功能
2.删除功能
3.修改功能
4.获取功能
5.长度功能

Collection接口中方法 :
public class Collection {
				public static void main(String[] args) {
				//添加一个元素     返回值为boolean
				//只会返回true
				Collection c1 = new ArrayList();
				boolean flag1 =c1.add("hello");
				c1.add("world");
				System.out.println("c1:"+c1+"   "+flag1);
			
				//将指定集合元素 添加到当前集合中
				Collection c2 = new ArrayList();
				boolean flag2 = c2.addAll(c1);
				System.out.println("c2:"+c2+"   "+flag2);
				
				//移除此集合中的所有元素
				Collection c3 = new ArrayList();
				c3.add("hah");
				c3.add("heihei");
				c3.clear();
				System.out.println("c3:"+c3+"    ");
				
				//是否包含指定元素  有返回true
				System.out.println("c1是否包含hello        "+c1.contains("hello"));
				
				//是否包含指定集合中所有元素
				Collection c4 = new ArrayList();
				c4.addAll(c2);
				c4.add("me");
				System.out.println("c1是否包含c4所有元素           "+c1.containsAll(c4));
				
				//集合中没有元素  返回true
				System.out.println("c3中没有元素:                  "+c3.isEmpty());
				
				//移除元素
				Collection c5 = new ArrayList();
				c5.add("hh");
				c5.add("bb");
				c5.remove("hh");
				System.out.println("c5移除hh:                         "+c5);
				
				//移除此集合中那些也包含在指定集合中的所有元素
				//如果此集合内容发生改变  就返回true
				//换句话来说   就是 A和B中元素,不相同的在A中留下
				
				Collection c6 = new ArrayList();
				c6.add("hh");
				c6.add("bb");
				
				Collection c7 = new ArrayList();
				c7.add("hh");
				c7.add("bb");
				c7.add("cc");
				
				boolean flag3 =c6.removeAll(c7);
				System.out.println(c6+"  "+flag3);
				
				//移除此集合中未包含在指定集合中的所有元素
				//如果此集合改动 返回true
				//换句话说  就是在A和B中元素,相同的在A中留下 
				Collection c8 = new ArrayList();
				c8.add("hh");
				c8.add("bb");
				c8.add("d");
				
				Collection c9 = new ArrayList();
				c9.add("hh");
				c9.add("bb");
				c9.add("cc");
				
				boolean flag4 = c8.retainAll(c9);
				System.out.println("c8:"+c8+"   "+flag4);
			}


		}
		//输出结果:
				c1:[hello, world]   			true
				c2:[hello, world]   			true
				c3:[]    
				c1是否包含hello       			true
				c1是否包含c4所有元素           	false
				c3中没有元素:                  true
				c5移除hh:                      [bb]
				c6:[]  							true
				c8:[hh, bb]   					true


	
		/*
			
			创建集合存储5个学生对象,并把学生对象遍历
		
		*/
		public class student {
			private String name;
			private String sex;
			public String getName() {
				return name;
			}
			public void setName(String name) {
				this.name = name;
			}
			public String getSex() {
				return sex;
			}
			public void setSex(String sex) {
				this.sex = sex;
			}
			public student(String name, String sex) {
				this.name = name;
				this.sex = sex;
			}
			public student(){
				
			}
			@Override
			public String toString() {
				return "[姓名:"+name+"sex:"+sex+"]";
			}
		}
		//这个使用了泛型,如果不懂,去看我的泛型文章吧。。。
		public class Test{
			public static void main(String[] args){
				List<Student> list = new ArrayList<Student>();
				list.add(new Student("张三","man"));
				list.add(new Student("李四","man"));
				list.add(new Student("王五","man"));
				list.add(new Student("张飞","women"));
				list.add(new Student("二狗子","man"));
				for(Student i:list){
					System.out.println(i.toString());
				}
			}
		}
		//输出结果:	
				[姓名:张三sex:man]
				[姓名:李四sex:man]
				[姓名:王五sex:man]
				[姓名:张飞sex:women]
				[姓名:二狗子sex:man]



迭代器: 是遍历集合的一种方式。迭代器是依赖于集合存在的。
为什么设计为接口?
因为各个集合的存储结构不同,所以存储的方式和遍历的方式是不同的,
而每个集合都应该具备,而每个集合类都应该具备获取功能,并且最好有
辅助判断功能,在获取前判断,不容易出错.
原理:
查看源码得知
Collection接口继承了Interable接口 
Interable接口中有一个抽象的方法:Interator<T> iterator()  
又找到 Interator为接口。
我们去这个接口中看看都有什么方法?
大概是:hasNext()  next 方法
这样我们整理一下:
	public interface Interator{
			hasNext();
			next();
		}
		public interface   Interable {
			Interator iterator();
		}
		public interface Collection extends Interable{
		
		}
		public interface List extends Collection{
		
		}
		public class ArrayList implements List{
			//它不是抽象类  所以它要实现 Interator iterator()方法
			Interator<T> iterator(){
				//返回的是一个实现对象 
				return new Myiterator();
			}
			private class iterator implements Interator{
				hasNext(){
				
				}
				next(){
				
				}
			}
		}



public class Demo{
			public static void main(String[] args){
				List<Student> list = new ArrayList<Student>();
				list.add(new Student("张三","man"));
				list.add(new Student("李四","man"));
				list.add(new Student("王五","man"));
				Iterator<Student> it =  list.iterator();
				while(it.hasNext()){
					//这里它直接调用了内部类的next()方法
					System.out.println(it.next().toString());
				}
			}
		}
		//输出结果:
				[姓名:张三sex:man]
				[姓名:李四sex:man]
				[姓名:王五sex:man]



List集合是一个有序的Collection。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。
用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素
与Set不同,列表通常允许重复的元素。

List接口特有方法:
	public class list {
			public static void main(String[] args) {
				//在指定位置添加元素
				List list = new ArrayList<>();
				list.add("ha");
				list.add("heihei");
				list.add(2,"hehe");
				System.out.println(list);
				
				//获取指定位置元素
				System.out.println((String)list.get(1));
				
				//列表迭代器
				ListIterator lt = list.listIterator();
				while(lt.hasNext()){
					System.out.println((String)lt.next());
				}
				//逆向遍历
				while(lt.hasPrevious()){
					System.out.println(lt.previous());
				}
				//删除功能
				list.remove(1);
				System.out.println(list);
				
				//修改功能
				list.set(0, "heihei");
				System.out.println(list);
			}


		}
		//输出结果:
				[ha, heihei, hehe]
				heihei
				ha
				heihei
				hehe
				hehe
				heihei
				dd
				ha
				[ha, hehe]
				[heihei, hehe]



迭代器并发异常:

	public class listerr {


				public static void main(String[] args) {
					List list = new ArrayList();
					list.add("hello");
					list.add("world");
					//并发修改错误   
					//Iterator是依赖于集合的,而集合在修改时,it并不知道
					//Iterator it = list.iterator();
					//使用list特有迭代器解决
					ListIterator lt = list.listIterator();
					while(lt.hasNext()){
						if(lt.next().equals("world")){
							lt.add("b");
						}
					}
					System.out.println(list);
				}


			}



总结一下:
List 子类特点:
 实现类 底层数据结构 安全性 查询   增删    效率
ArrayList      数组  yes yes    no      yes
LinkedList     链表  yes  no yes     yes
Vector 数组   no        yes no no
 
ArrayList练习:


	/**
			 * 
			 * 将集合中字符串重复的移除
			 *
			 */
			public class Arraylist1 {
				public static void main(String[] args) {
					List list = new ArrayList();
					list.add("haha");
					list.add("world");
					list.add("world");
					list.add("hello");
					list.add("java");
					
					List newList = new ArrayList();
					Iterator it = list.iterator();
					while(it.hasNext()){
						String str = (String) it.next();
						//注意这个方法
						if(!newList.contains(str)){
							newList.add(str);
						}
					}
					System.out.println(newList);
				}
			}
		


	
			/**
			 * 
			 * 将集合对象属性相同的去掉
			 *
			 */
			public class Arraylist2 {
				public static void main(String[] args) {
					List<Student> list= new ArrayList<Student>();
					list.add(new Student("小明","男"));
					list.add(new Student("小红","女"));
					list.add(new Student("小明","男"));
					
					List<Student> list2= new ArrayList<Student>();
					Iterator it = list.iterator();
					while(it.hasNext()){
						Student stu = (Student) it.next();
						//其实它是判断用的对象的equals方法
						//源码  (o.equals(elementData[i]))
						//重写对象equals()方法就可以比较两个对象的内容了
						if(!list2.contains(stu)){
							list2.add(stu);
						}
					}
					System.out.println(list2);
				}
			}


	/**
			*从键盘读取数字  输入0结束  输出最大值
			*/
			public class ArrayListTest2 {
				public static void main(String[] args) {
					List<Integer> list = new ArrayList();
					while(true){
						System.out.println("请输入数字");
						Scanner sc = new Scanner(System.in);
						int i = sc.nextInt();
						if(!(i==0)){
							list.add(i);
						}else{
							break;
						}
					}
					Integer[] integer = new Integer[list.size()];
					list.toArray(integer);
					Arrays.sort(integer);
					System.out.println(integer[integer.length-1]);
					
				}


			}
			//输出结果:
					请输入数字
					20
					请输入数字
					30
					请输入数字
					0
					30




/**
			 * 
			 * 请用LinkedList模拟栈数据结构的集合,并测试
			 *
			 */
			 public class MyStack{
				private LinkedList link;
				public MyStack(){
					this.link = new LinkedList();
				}
				public boolean add(Object o){
					return link.add(o);
				}
				public Object get(){
					//返回 并弹栈
					return link.removeFirst();
					//它只是返回第一个  并没有弹栈  如果调用的话 一直返回的是第一个
					//		return link.getFirst();
				}
				public boolean  isEmpty(){
					return link.isEmpty();
				}
			}
			public class MyStackTest {
				public static void main(String[] args) {
					MyStack ms = new MyStack();
					ms.add("hah");
					ms.add("heihei");
					System.out.println(ms.get());
					//每次get都会弹栈
					System.out.println(ms.get());
					System.out.println("没有东西了?"+ms.isEmpty());
				}


			}



Set集合

HashSet:不保证set的迭代顺序,特别是它不保证该顺序不变。
底层数据结构是哈希表(元素是链表的数组)
哈希表依赖于哈希值的存储
底层依赖于两个方法:
int hashCode();
boolean equals(Object o);

源码分析得知新添加的元素要和前面所有元素比较hash值,如果hash值相同,再比较equals.
如果继承Object hash值肯定不相同,而String重写了hashcode方法,hash值相同。
我们为了减少它的排查,我们重写hashcode方法,用变量去影响它的hash值,这样只有变量的hash
值相等时,才有可能是一个元素。

分析: 如果我们的Person类继承于Object,那么它的hash值肯定都是不同的
public class HashSetDemo{
	public static void main(String[] args) {
				Set<Student> s  = new HashSet();
				s.add(new Student("zhangsan","nan"));
				s.add(new Student("zhangsan","nan"));
				s.add(new Student("lisi","nv"));
				s.add(new Student("zhangsan","nan"));
				s.add(new Student("zhangsan","nan"));
				
				for(Student d :s){
					System.out.println(d);
				}
			}
		//输出结果:
				[姓名:zhangsansex:nan]
				[姓名:lisisex:nv]
				[姓名:zhangsansex:nan]
				[姓名:zhangsansex:nan]
				[姓名:zhangsansex:nan]



HashSet是保证唯一性的,但从次看来并没有,也就是说明了,它走对象的hashcode时,判断了hash值
不同,所以直接添加。
如果我们传的String对象的话,会调用String重写hashcode方法,这时相等的字符串会出现相同的hash
值。所有HashSet的第一个条件就进去了,然后比较内容,如果相同,就不会添加。
从这个角度来想,如果我们想让自定义对象保证唯一性,必须重写hashcode方法。
那么我们可以将hash值与变量关联起来。
这样写: this.name.hashCode()+this.sex.hashCode();
如果两个String都相等说明可能是同一个元素
但是还会出现这样的情况: 15 20     20 15
我们可以看出它们根本不是相同元素,这时hash值还是相等,我们为了提高效率,在一个属性后面
*一个值。
这样优化后,只有它们的属性hash值相等时,才可能是同一个元素。
如果不相同,直接添加。


/**
		 * 存储自定义对象 保证元素唯一性
		 * 如果成员变量值 相同,则为同一个元素。
		 *
		 */
		public class Student {
				private String name;
				private String sex;
				public String getName() {
					return name;
				}
				public void setName(String name) {
					this.name = name;
				}
				public String getSex() {
					return sex;
				}
				public void setSex(String sex) {
					this.sex = sex;
				}
				public Student(String name, String sex) {
					this.name = name;
					this.sex = sex;
				}
				public Student(){
					
				}
				@Override
				public String toString() {
					return "[姓名:"+name+"sex:"+sex+"]";
				}
				@Override
				public int hashCode() {
					//这里修改了hash值  只有两个属性的hash值 加起来 相等时,才不会添加到集合中
					return this.name.hashCode()+this.sex.hashCode()*15;
				}
				@Override
				public boolean equals(Object obj) {
					if (this == obj)
						return true;
					if (obj == null)
						return false;
					if (getClass() != obj.getClass())
						return false;
					Student other = (Student) obj;
					if (name == null) {
						if (other.name != null)
							return false;
					} else if (!name.equals(other.name))
						return false;
					if (sex == null) {
						if (other.sex != null)
							return false;
					} else if (!sex.equals(other.sex))
						return false;
					return true;
				}
			}
			public class HashSetTest {


				public static void main(String[] args) {
					System.out.println(str.hashCode()+"  " +str2.hashCode());
					Set<Student> s  = new HashSet();
					s.add(new Student("zhangsan","nan"));
					s.add(new Student("zhangsan","nan"));
					s.add(new Student("lisi","nv"));
					s.add(new Student("zhangsan","nan"));
					s.add(new Student("zhangsan","nan"));
					//两个hash值相等时,才判断为同一个元素
					s.add(new Student("lisi","nan"));
					
					for(Student d :s){
						System.out.println(d);
					}
				}


			}
			//输出结果:
					[姓名:lisisex:nan]
					[姓名:lisisex:nv]
					[姓名:zhangsansex:nan]





LinkedHashSet:
元素有序唯一
由链表保证元素有序
由哈希表保证元素唯一
public class LinkedSetDemo {
				public static void main(String[] args) {
					Set<String> s = new LinkedHashSet<>();
					s.add("hello");
					s.add("java");
					s.add("world");
					for(String d: s){
						System.out.println(d);
					}
				}


			}
			//输出结果:
					hello
					java
					world


TreeSet:
使用元素的自然排序对元素进行排序
或者根据创建时提供的Conparator进行排序
具体取决于使用的构造方法

排序: 内部使用二叉树排序(红黑树属于一种自平衡二叉树)
源码: 首先创建根节点,如果第二个元素比根节点小 就放左边,大就放右边。相等不放。
  读取顺序 左中右    数据结构来说叫:中序遍历
实现排序有两种:
自然排序
比较器排序


	/**
			* 自然 排序  先按年龄从小到大   在按姓名排
		    */
			public class Student implements Comparator<Student>{
				private String name;
				private int age;


				public Student() {
					super();
				}


				public Student(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 int compareTo(Student o) { 
					//如果我们想从小到大排列的话 就用根减去比较值
					//如果从大到小的话  用比较值-根
					int num = this.age - o.age;
					int num2 = num==0?this.name.compareTo(o.name):num;
					return num2;	
				}
			}
			public class Test {


				public static void main(String[] args) {
					Set<Student> s = new TreeSet<>();
					s.add(new Student("dahjk","nan",5));
					s.add(new Student("dahk","nv",2));
					for(Student d:s){
						System.out.println(d);
					}
				}


			}
			//输出结果:	
					[dahksex:nvage:2]
					[dahjksex:nanage:5]
					



	/**
			 * 比较器排序
			 */
			public class MyComparator implements Comparator<Student> {
				@Override
				public int compare(Student o1, Student o2) {
					int num =  o1.getAge()-o2.getAge();
					int num2 = num==0?o1.getName().compareTo(o2.getName()):num;
					return num2;
				}
			}
			
			public class Test {


				public static void main(String[] args) {
					Set<Student> s = new TreeSet<>(new MyComparator());
					s.add(new Student("dahjk","nan",5));
					s.add(new Student("dahk","nv",2));
					for(Student d:s){
						System.out.println(d);
					}
				}


			}
			//输出结果:	
					[dahksex:nvage:2]
					[dahjksex:nanage:5]
			一种是类直接实现接口,另一种是自己写一个类继承比较器。
			


小练习:
/**
* 获取 10个  1-20的的随机数 ,不能重复
*
*/
public class Demo {
				public static void main(String[] args) {
					Set<Integer> s = new TreeSet<>();
					while (s.size()!=10) {
						int  num = (int) (Math.random()*20+1);
						s.add(num);
					}
					for(Integer a:s){
						System.out.println(a);
					}
				}


			}
			//输出结果:
					6
					7
					9
					11
					12
					16
					17
					18
					19
					20

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值