【第12天】Java集合(一)

版权声明:©2018 本文為博主來秋原創,轉載請註明出處,博主保留追責權利。 https://blog.csdn.net/qq_30257081/article/details/84308373

1 什么是集合?有哪些分类

       集合是用来装类型不同元素的,没有个数限制;而数组装类型相同元素,有个数限制。

1.1 JCF(Java Collections FrameWork)

       意为Java集合框架。

在这里插入图片描述

上图中蓝色箭头的意为接口继承(如public interface List extends Collection 子接口为List,父接口为Collection),里面出现的均为接口。接口不允许创建对象,只允许实现类,其中接口List的实现类有ArrayList、LinkedList、Vector、Stack等(如public class ArrayList implements List),其他的接口均有具体实现。

  • List、Set、Map是不是属于同一个等级?
    List Set属于Collection的子接口,Collection和Map属于同一个等级。

  • 注意:

    • 使用这些集合需要导入java.util包,如果不导包Java会自动去java.lang下面搜索,找不到。
    • 所以在为类命名时,不要再使用这些已经被官方用过的名字了,这样会使Java直接导入你自己写的类,找不到官方类中的方法而报错。
    • 在赋值引用的名字时这些官方定义的类、接口的标识符是可以用的,但是可读性太差,要避免。
    • List x = new ArrayList<>();这样定义是对的,相当于父类 引用 = new 子类();

2 ArrayList ★

       ArrayList集合的特点为有序,元素不唯一。底层基于数组(Object[]) 实现。

2.1 包装类

  • 由于ArrayList底层基于Object[]实现,这导致所有的引用数据类型都可以存放在集合里,但是基本数据类型不可以存放其中。为了保证基本数据类型也可以放在集合里,Java定义了包装类。

  • 作用1 将基本数据类型打包为包装类,然后再传入集合中。(2.1.1)

  • 作用2 将String类型转为包装类型。(2.1.2)

2.1.1 对应转换关系

  • 对应的类型
基本数据类型 boolean char byte short int long float double
对应包装类 Boolean Character Byte Short Integer Long Float Double
  • 转换(其他类型可类比)
		//打包(基本数据类型-->包装类)
		int x = 45;
		//JDK5.0之前
		Integer y = Integer.valueOf(x);
		//JDK5.0开始,支持自动解包
		Integer y = x;

		//解包(包装类-->基本数据类型)
		Integer x = new Integer(45);
		//JDK5.0之前
		int y = x.intValue();
		//JDK5.0之后,支持自动打包			
		int y = x;

也就是说JDK5.0之后,包装类和其对应的基本数据类型可以直接赋值(自动打包/解包),当看到在集合的方法参数列表中传入的数据类型为基本数据类型时需知道并非支持基本数据类型了,而是基本数据类型的自动打包。

另外,整数类型的包装类会自动缓存-128到127之间所有的数字,当直接给引用赋值为数字(自动打包)时,使用自动缓存机制,并不是在堆内存中创建对象,而是直接在缓存区创建值。比如:

	Long x = 120L;
	Long y = 120L;
	System.out.println(x == y);//--->true

2.1.2 将String类型转为包装类型

       除Character类(无法把一个字符串转成一个字符),其他包装类还可以将String类型转换成对应的基本数据类型。举一例,其余类型类推:
	String x = "120";
	int y = Integer.parseInt(x);

字符串转类型的时,如果字符串中有除本类型之外的其他值,会报NumberFormatException错误。

转类型boolean字符串时,传入true会转换为true;传入其他都报false。

  • 例:
//打印三年后张三的年龄
public class Example{
	public static void main(String[] args){

		String str = "张三:17";

		String age = str.substring(str.indexOf(":") + 1);

		int age1 = Integer.parseInt(age);
		System.out.println(age1 + 3);//--->20
		
		//或:
		//data[0]:姓名	data[1]:年龄
		//String[] data = str.split(":");
		//int age = Integer.parseInt(data[1]);
		//System.out.println("张三三年后:" + (age + 3));
	}
}

2.2 基本用法与特点

  • 如何创建ArrayList对象

    • JDK5.0之前,默认往集合里面存放的都是Object类型的对象,取元素后类型需强转。
      ArrayList list = new ArrayList();

    • JDK5.0及以后,可以加泛型(不加泛型默认传入元素为Object类型)
      ArrayList<泛型> list = new ArrayList<泛型>();

    • JDK7.0及以后,后面的泛型会自动推断(不加泛型默认传入元素为Object类型)
      ArrayList<泛型> list = new ArrayList<>();

  • 如何添加元素

    • 一次添加一个元素:
      list.add(元素);

    • 一次添加多个元素:
      Collections.addAll(集合对象, 元素, 元素, 元素)

      	面试题:
      	Collection和Collections之间的区别?
      		Collection是所有单值类型集合统一的父接口,
      		Collections是集合的工具类。
      
    • 如何得到集合的大小
      list.size();

    • 如何得到集合里面的某一个元素
      list.get(int 下标)

    • 如何判断集合里面是否出现指定的元素
      list.contains(元素)

    • 如何遍历集合对象

      	    //方法1 for + 下标(执行按下标查找时使用)
      		for(int x = 0;x < list.size();x++){
      			//x -> 下标
      			//list.get(x) -> 元素
      		}
    
      		//方法2 foreach
      		//底层使用迭代器实现
      		//执行与下标无关、不对集合进行增删的一些操作使用这个比较简单
      		for(泛型 x : list){
      			//x -> 元素
      		}
    
    
      		//方法3 迭代器 ★
      		//如果集合是无序的,无法使用下标依次删除,使用迭代器
      		for(得到迭代器对象; 迭代器是否还有下一个元素; ){
      			//取出下一个元素
      		}
      		
      		//Java命名惯例,当getter/setter只存在一个时,可以不写前三个字母(iterator方法命名由来)
      		for(Iterator<泛型> car = list.iterator(); car.hasNext(); ){
      			//car.next() -> 元素
      		}
    
  • 迭代器:可类比为word文档中的光标,开始时迭代器在首元素的左边。遍历时使用这个功能可取出集合中的元素,for和while中均可以使用,foreach的底层实现方式是迭代器。

    • hasNext():判断迭代器当前所在位置的下一个是否还有元素。
    • next():取出下一个元素。
    • remove():移除当前元素。
  • 需要注意的是,在同一方法内使用同一个迭代器进行第二次遍历时会因为第一次已迭代到集合末尾使得.hasNext()方法为false,第二次不能使用。

    • 当使用for循环时要注意将iterator方法定义于条件的首位(上面迭代器的第二个例子),定义局部变量。
    • 使用while时每次循环都要定义新的iterator。
  • 例:

import java.util.*;
public class Example{
	public static void main(String[] args){

		ArrayList<String> list = new ArrayList<>();

		list.add("张三");
		Collections.addAll(list,"李四","张三","王五","王五");

		System.out.println(list);
		
		ArrayList<String> temp = new ArrayList<>();
		for(String name : list){
			if(!temp.contains(name)){
				temp.add(name);
			}
		}

		System.out.println(temp);
	}
}

2.3 删除元素

       一个remove方法只能删除一个元素。

2.3.1 指定下标删除

       list.remove(int 下标)需注意:当传入Integer类型时可能存在歧义,在这里传入int、char、short、byte类型不会自动打包,一定识别为下标;其他基本数据类型可自动打包为包装类。

模拟实现:

public class Test{

	public static void main(String[] args){
		Integer x = 10;
		remove(x);--->元素

		Integer x1 = new Integer(10);
		remove(x1);--->元素
		
		remove(10);--->下标
	}

	public static void remove(int x){
			System.out.println("下标");
	}

	public static void remove(Object obj){
		System.out.println("元素");
	}
}

2.3.2 指定元素删除与equals()

       list.remove(Object obj),底层遵循equals()比较机制。

       此处传入的obj仅仅作为一个参照,并不是这个集合的元素。用这个参照删除集合中“参照.equals()”为true的元素。

       如果这个调用remove(Object)的集合泛型重写了equals()方法,remove(Object)会使用这个新的equals()方法判断哪些值可以被删除。

       可以定制(重写)equals()自定义remove(Object)的删除规则。

import java.util.*;
public class Test1{
	public static void main(String[] args){
		ArrayList<Teacher> list = new ArrayList<>();

		Teacher t1 = new Teacher();
		Teacher t2 = new Teacher();

		list.add(t1);
		System.out.println(list.size());//--->1
		list.remove(t2);
		//t2.equals(t1) ---> 无论什么情况下都是true
		//此时无论remove中传入什么,只要传入的是Teacher类的引用,都会将t1删除
		System.out.println(list.size());//--->0
	}
}

class Teacher{

	@Override
	public boolean equals(Object obj){
		return true;
	}
}
import java.util.*;
public class Test2{
	public static void main(String[] args){
		ArrayList<Teacher> list = new ArrayList<>();

		Teacher t1 = new Teacher();
		Student s1 = new Student();

		list.add(t1);
		System.out.println(list.size());//--->1
		list.remove(s1);
		//s1.equals(t1) ---> Student中的equals()方法未被重写,两个对象地址不同,返回必为false
		System.out.println(list.size());//--->1
	}
}

class Teacher{

	@Override
	public boolean equals(Object obj){
		return true;
	}
}

class Student{
}
import java.util.*;
public class Test3{
	public static void main(String[] args){
		ArrayList<Teacher> list = new ArrayList<>();

		Teacher t1 = new Teacher();
		Student s1 = new Student();

		list.add(t1);
		System.out.println(list.size());//--->1
		list.remove(s1);
		//s1.equals(t1) ---> Student中的equals()方法被重写,且返回必为true
		//此时无论remove中传入什么,只要传入的是Teacher或Student类的引用,都会将t1删除
		System.out.println(list.size());//--->0
	}
}

class Teacher{

	@Override
	public boolean equals(Object obj){
		return true;
	}
}

class Student{

	@Override
	public boolean equals(Object obj){
		return true;
	}
}

2.3.3 清空当前数组内全部元素

       list.clear()

  • 使用集合给出的方法进行清空的其他办法:
		ArrayList<Integer> list = new ArrayList<>();

		Collections.addAll(list,1,2,3,4,5);

		//for循环时为什么要倒序遍历?
		//这种执行结果是[2,4],因为当1被删除后,2成为第0个元素,第二个被删除的是3,同理第三个被删除的是5
		//因数组的长度小于当前下标数而停止删除,结果出错
		//删除元素后,后面的元素向前移动,但下标不断增长造成漏删
		for(int x = 0; x < list.size(); x++){
				list.remove(x);
		}

		//倒序删除
		for(int x = list.size() - 1; x >= 0; x--){
			list.remove(x);
		}
		//或
		while(list.size() != 0){
			list.remove(0);
		}

		System.out.println(list);

2.3.4 按元素内容遍历删除指定元素

       因为后面用到的集合不仅仅是有序集合,所以使用for + 下标遍历删除指定元素不一定可行。
       需要使用到迭代器进行对指定内容元素的删除。但当使用迭代器遍历集合的过程中,如果需要一边遍历,一边添加/删除,直接使用对象引用调用方法进行添加/删除操作,会触发ConcurrentModificationException(CME,并发修改异常)。 此时需要使用迭代器的.remove()方法对光标下一个指向的元素进行删除。

  • 例题:
import java.util.*;
public class Example{
	public static void main(String[] args){

		ArrayList<Integer> list = new ArrayList<>();

		Collections.addAll(list,45,38,77,62,59,83);

		//删除所有不及格的学生成绩

		//方法1 for + 下标 不可行
		//删除元素后,后面的元素向前移动,但下标不断增长造成漏删
		for(int x = 0; x < list.size(); x++){
			//x -> 下标
			Integer score = list.get(x);
			if(score < 60){
				list.remove(x);
			}
		}
		
		//方法2 for + 下标(倒序)不提倡使用
		//后面会遇到很多无序的集合
		for(int x = list.size() - 1; x >= 0; x--){
			//x -> 下标
			Integer score = list.get(x);
			if(score < 60){
				list.remove(x);
			}
		}

		//方法3 foreach 不可行
		//底层使用迭代器实现
		//遍历并使用集合方法增删(add/remove),会报ConcurrentModificationException(CME)异常
		for(Integer score : list){
			if(score < 60){
				list.remove(score);//remove(Object 元素)
			}
		}
		
		//方法4
		//当需要遍历并在其中集合执行add/remove时,使用这种方法
		for(Iterator<Integer> car = list.iterator(); car.hasNext(); ){
			Integer score = car.next();

			if(score < 60){
				//如果使用“list.remove(score);”不可行,出异常
				car.remove();
			}
		}

		System.out.println(list);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_30257081/article/details/84308373
今日推荐