java入门基础九(集合)

13. 集合

13.1 集合的概念

  1. 集合是由java提供的一系列类,可用于动态的存放多个对象。(集合只能够存放对象)

  2. 集合和数组之间的不同在于:集合大小可变,且元素类型不受限定,只要是引用类型即可。(集合中不能存放基本数据类型,但可以存放基本数据类型的包装类。)

  3. 集合类全部支持泛型,是一种数据安全的用法。

13.2 集合的框架图

在这里插入图片描述

详细描述:

整体上,集合分为两大家族:Collection 和 Map

  1. Collection:单列集合(存放单个对象地址)。

  2. Map:双列集合(存放键值对—[key,value])。

在框架中,还有另外的三个分支:Iterator、Comparator、Collections

  1. Iterator:迭代器,为服务Collection及其子类而设计。
  2. Comparator:比较器,在集合中储存对象时,用于对象之间的比较。
  3. Collections:工具类,提供静态方法,用来对Collection集合进行操作。

13.3 Collection

13.3.1 接口概述

Collection接口定义了存取对象的方法,有两个非常重要的子接口List和Set。

List接口:存放的元素有序且允许有重复的集合接口。

Set接口:存放的元素无序不允许有包含重复的集合接口。

注:

无序并不是随机,而是通过哈希值+散列算法得出的存放地址,在遍历输出时,有特定的顺序。

13.3.2 接口中的常用方法

  1. int size(); 返回此collection中的元素个数
  2. boolean isEmpty(); 判断此collection中是否包含有元素。(有:false;无:true)
  3. boolean contains(Object obj); 判断此collection是否包含指定的元素。
  4. boolean contains(Collection c); 判断此collection是否包含指定collection中的所有元素。
  5. boolean add(Object element); 向此collection中添加元素。
  6. boolean addAll(Collection c);将指定collection中的所有元素添加到此collection中
  7. boolean remove(Object element); 从此collection中移除指定的元素。
  8. boolean removeAll(Collection c); 移除此collection中那些也包含在指定collection中的所有元素。
  9. void clear(); 移除些collection中所有的元素。
  10. boolean retainAll(Collection c); 仅保留此collection中那些也包含在指定collection的元素。
  11. Iterator iterator(); 返回在此collection的元素上进行迭代的迭代器。
  12. Object[] toArray(); 把此collection转成数组。

13.3.3 List—ArrayList

底层:一维数组。

在Collection定义的方法基础上,List接口还增加定义了许多对下标的操作方法。

对Collection基础方法的实现示例:

ArrayList<String> list = new ArrayList<>();
//添加元素
list.add("aaa");
list.add("bbb");
list.add("ccc");

//获取元素的个数
System.out.println("当前集合元素的个数为:"+list.size());

ArrayList<String> list2 = new ArrayList<>();
//使用Collections工具对集合实现多添加。
Collections.addAll(list2, "111","222","333");

//在集合末尾插入新集合的所有元素
list.addAll(list2);


//判断集合中是否包含某个元素
System.out.println("当前集合是否有元素eee:"+list.contains("eee"));

//判断当前集合是否含有某个集合的所有元素
System.out.println("当前集合是否含有新集合的所有元素:"+list.containsAll(list2));
//清空集合
//list.clear();

System.out.println("当前集合元素的个数为:"+list.size());

list.remove("222");
//删除-去交集
LinkedList<Object> newList2 = new LinkedList<>();
Collections.addAll(newList2, "333","555");
list.removeAll(newList2);

//保留交集
LinkedList<Object> newList3 = new LinkedList<>();
Collections.addAll(newList3, "111","aaa");
list.retainAll(newList3);

对List新增方法的实现示例:

ArrayList<String> list = new ArrayList<>();
//添加元素
list.add("aaa");
list.add("bbb");
list.add("ccc");

//设置指定下标上的元素
list.set(1, "ddd");

//在指定下标上插入元素
list.add(1, "eee");

ArrayList<String> list2 = new ArrayList<>();
//使用Collections工具对集合实现多添加。
Collections.addAll(list2, "111","222","333");
//在集合指定下标处插入新集合的所有元素
list.addAll(2, list2);

//获取元素在集合中的下标
System.out.println("元素111在当前集合的下标为:"+list.indexOf("111"));

//根据元素下标/内容删除
list.remove(4);

//获取指定下标之间的元素,生成新的集合
List<String> list3 = list.subList(2, 4);

遍历方法:

System.out.println("---------------");
//迭代器遍历
Iterator<String> iterator = list3.iterator();
while(iterator.hasNext()){//判断当前迭代指向的下一个元素是否存在。
    System.out.println(iterator.next()); //返回迭代中的下一个元素,并迭代指针下移。
}

System.out.println("---------------");
//foreach遍历
for (String string : list) {
    System.out.println(string);
}

System.out.println("---------------");
//for循环遍历
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

Iterator迭代器:

常用方法:

hasNext(); 判断当前迭代指向的下一个位置是否存在元素。

next(); 返回迭代中的下一个元素,并迭代指针下移。

(这两个方法常用作遍历,示例见上13.3.3.)

remove();删除当前迭代对应的元素。(能够在遍历时,删除集合元素)

示例:

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "aa","bb","cc","dd");
Iterator<String> it = list.iterator();
while(it.hasNext()){
    String str=it.next();
    if(str=="bb"){
        it.remove();
    }
}
for (String string : list) {
    System.out.println(string);
}
/*
aa
cc
dd
*/

注:

如果在迭代过程中使用list.remove(str); 进行删除,运行将会报错。

原因:在进行迭代时,Iterator会获取到当前集合的操作数,将这个操作数赋值给内部操作数。且每次迭代时会进行比较,如果进行list.remove()方法,则集合的操作数会加1,导致与内部操作数不一致,报出异常。

而在使用Iterator中的方法remove删除(实质上还是调用的集合的remove方法),集合的操作数依旧会加1,但内部操作数也会及时更新。这样能够保证数据的一致性,不会有脏数据的出现。

ListIterator迭代器:

ListIterator迭代器:专门服务于List接口及其实现类的接口类,实现自Iterator。

常用方法:

Iterator常用方法:见上

hasPrevious(); 判断前面是否有可迭代的元素。

previous(); 返回迭代指向的上一个元素,并上移。

set(); 用该元素替换当前迭代指向的元素

add(); 在迭代位置添加该元素

listIterator(int index); 从下标处开始迭代

示例(倒叙输出List集合中的内容):

LinkedList<String> list = new LinkedList<>();
list.add("111");
list.add("222");
list.add("333");
list.add("444");
ListIterator<String> it1 = list.listIterator(list.size());
while(it1.hasPrevious()){
    System.out.println(it1.previous());
}
/*
444
333
222
111
*/

示例(使用add和set方法)

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

Collections.addAll(list, "aa","bb","cc","dd");

ListIterator<String> it = list.listIterator();
while(it.hasNext()){
    String str=it.next();
    if(str=="bb"){
        it.add("11");
    }
    if(str=="cc"){
        it.set("CC");
    }
}
for (String string : list) {
    System.out.println(string);
}
/*
aa
bb
11
CC
dd
*/

拓展1:泛型

数据安全的作法,规定集合应该存储什么样的数据类型

泛型在集合中的使用:

如上的例子,ArrayList list = new ArrayList<>(); 规定了list集合中只能装String类型对象,如果装入的对象类型不兼容,将会报错。

泛型限定的简单使用:(创建A父类,B子类:继承A类)

//?:任何类型
public ArrayList<?> method01(){
    ArrayList<String> list = new ArrayList<>();
    return list;
}

//? extends A
//?:表示A的子类或者A类
public ArrayList<? extends A> method02(){
    //ArrayList<B> list = new ArrayList<>();
    ArrayList<A> list = new ArrayList<>();
    return list;
}

//? super A
//?:表示A的父类或A类
public ArrayList<? super A> method03(){
    //ArrayList<Object> list = new ArrayList<>();
    ArrayList<A> list = new ArrayList<>();
    return list;
}

拓展2:foreach遍历

foreach遍历的底层由迭代器实现

String e;
for(Iterator<String> it = list.iterator();it.hasNext();System.out.println(e)){
    e = it.next();
}

13.3.4 List—LinkedList

底层:双向链表

LinkedList在方法的使用上和ArrayList完全兼容(原因:同时实现List接口),唯一的不同为:由于底层的链表结构,LinkedList多出两种模式。

  1. 队列模式:先进先出,(removeFirst();方法)

    LinkedList<String> list = new LinkedList<>();
    list.add("111");
    list.add("222");
    list.add("333");
    list.add("444");
    Iterator<String> it = list.iterator();
    while(it.hasNext()){
        System.out.println(list.removeFirst());
    }
    /*
    111
    222
    333
    444
    */
    
  2. 栈模式:先进后出,(removeLast();方法)

    LinkedList<String> list = new LinkedList<>();
    list.add("111");
    list.add("222");
    list.add("333");
    list.add("444");
    Iterator<String> it = list.iterator();
    while(it.hasNext()){
        System.out.println(list.removeLast());
    }
    /*
    444
    333
    222
    111
    */
    

注:由于ArrayList和LinkedList底层结构的不同,在使用时如果需要多次查询,使用ArrayList,如果需要多次删除和添加,则使用LinkedList效率更高。

13.3.5 List—Vector(已弃用)

13.3.5.1 Vector(弃)

了解:Vector是元老级别的集合类,在JDK1.0开始就投入使用,后在JDK1.2才开始推出集合框架。

在方法使用上,Vector实现了List接口,能够实现List的所有方法,但也还有一些老的方法被保留下来。

如:

addElement()//添加元素
removeElement(); //删除元素
v.removeElementAt();//依据下标删除元素
//遍历
Enumeration<String> elements = v.elements();
while(elements.hasMoreElements()){
    String nextElement = elements.nextElement();
    System.out.println(nextElement);
}
13.2.5.2 Stack(弃)

继承Vector,多出栈模式(先进后出)

使用示例:

Stack<String> stack = new Stack<>();
		
//添加元素 - 将元素压入栈顶
stack.push("aa");
stack.push("bb");
stack.push("cc");
stack.push("dd");
stack.push("ee");

System.out.println("距离栈顶的位置(从1开始):" + stack.search("bb"));
//4
while(!stack.empty()){
    //获取栈顶第一个元素,并返回
    //String element = stack.peek();

    //删除栈顶第一个元素,并返回
    String element = stack.pop();
    System.out.println(element);
}
/*
ee
dd
cc
bb
aa
*/

13.3.6 Set—HashSet

底层:一维数组(哈希表)

HashSet在装入元素时,将元素的hash值+自身的散列算法,得出在哈希表中存放的地址,所以,当装入的元素相同时,计算得出的地址也相同,此时,HashSet认为这是同一个对象,将不再添加。

也正因为如此,HashSet添加的元素在数组中存放的位置不固定(对人来说),输出又是依次按照数组输出,所以其顺序也就等于无序。

使用方法(所有Collection接口中的方法):

常用示例:

HashSet<String> set = new HashSet<>();
//添加元素
set.add("aaa");
set.add("bbb");
set.add("ccc");

//获取元素的个数
System.out.println("当前集合元素的个数为:"+set.size());

HashSet<String> set2 = new HashSet<>();
//使用Collections工具对集合实现多添加。
Collections.addAll(set2, "111","222","333");

//在集合末尾插入新集合的所有元素
set.addAll(set2);

//在集合指定下标处插入新集合的所有元素

//判断集合中是否包含某个元素
System.out.println("当前集合是否有元素eee:"+set.contains("eee"));

//判断当前集合是否含有某个集合的所有元素
System.out.println("当前集合是否含有新集合的所有元素:"+set.containsAll(set2));

System.out.println("当前集合元素的个数为:"+set.size());
//根据元素下标/内容删除
set.remove(4);
set.remove("222");

System.out.println("---------------");
//遍历集合
for (String string : set) {
    System.out.println(string);
}	

13.3.7 Set—LinkedHashSet

底层:双向链表(除了元素内容还存储有前后节点地址,Node节点类)

特点:去重+有序

在LinkedHashSet中,元素的储存方式依旧是和HashSet相同,采用哈希值+散列算法计算出存储的位置地址,但LinkedHashSet中不仅仅是储存元素,还会将元素的首尾节点一同储存到LinkedHashSet中,在进行遍历时,会从根节点出发,按照装入元素的顺序遍历出,所以为有序的。

常用方法与HashSet相同

13.3.8 Set—SorteSet—TreeSet

底层:自平衡的排序二叉树(红黑树)

注:使用TreeSet集合装入的元素,必须实现有比较方法。

常见的使用方法有两种:内置比较器和外置比较器

  1. 内置比较器(在需要装入TreeSet集合的类中实现接口Comparable< >,重写compareTo方法):

简单示例(学生类):

public class Student implements Comparable<Student>{
	private String name;
	private int age;
	
	//构造方法
	public Student() {
		
	}
	public Student(String name, int age) {
		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 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 (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 String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
    
    //重写的compareTo方法,按照年龄排序
	@Override
	public int compareTo(Student o) {
		
		return this.age-o.age;
	}
}

注:此处重写的compareTo方法,当年龄相同时,会被TreeSet集合认为相同元素,从而不再加入,所以我们测试时使用不同的年龄看效果。

方法测试:

TreeSet<Student> set = new TreeSet<>();
set.add(new Student("小明",20));
set.add(new Student("小红",18));
set.add(new Student("小刚",27));
set.add(new Student("小南",19));
set.add(new Student("小慧",21)); 
for (Student student : set) {
    System.out.println(student);
}
/*
Student [name=小红, age=18]
Student [name=小南, age=19]
Student [name=小明, age=20]
Student [name=小慧, age=21]
Student [name=小刚, age=27]
*/
  1. 外置比较器(在使用TreeSet集合时,在外部创建匿名内部类重写compare方法):

    简单示例:

    //创建集合对象
    TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {
    
    @Override
    public int compare(Student o1, Student o2) {
        //此处按照年龄倒序排序
        return o2.getAge()-o1.getAge();
        }
    });
    set.add(new Student("小明",20));
    set.add(new Student("小红",18));
    set.add(new Student("小刚",27));
    set.add(new Student("小南",19));
    set.add(new Student("小慧",21));
    set.add(new Student("小章",21));  //认为的“相同元素”,集合不再添加
    for (Student student : set) {
    	System.out.println(student);
    }
    /*
    Student [name=小刚, age=27]
    Student [name=小慧, age=21]
    Student [name=小明, age=20]
    Student [name=小南, age=19]
    Student [name=小红, age=18]
    */
    

    说明:外置比较器的优先级是要大于内置比较器!!

资源拓展(理解二叉树的网站):https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

13.4 Map

13.4.1 HashMap

底层:一维数组

特点:存入键值对(key—value),去重+无序(添加元素时,同样是利用哈希值和散列算法求出存放地址,所有在数组中依次遍历的时候,是无序的。)

注:

  1. 计算地址只通过Key计算,与value无关,所有value值能够重复,而Key不能重复。

  2. Map没有迭代器,需要遍历时:

    1.可以通过keySet();方法,将所有的key抽取到Set集合中,再通过迭代器获取value值。

    2.可以使用entrySet()方法返回Set<Entry<String, Integer>>对象再遍历。

常用使用方法示例:

HashMap<String ,Integer> map = new HashMap<>();
//添加元素
map.put("aa", 21);
map.put("bb", 22);
map.put("cc", 23);
map.put("dd", 21);
map.put("ee", 20);
map.put("ff", 21);

//将新集合添加到集合中
HashMap<String, Integer> map2 = new HashMap<>();
map2.put("gg", 10);
map2.put("hh", 10);
map2.put("ii", 10);
map2.put("jj", 10);
map.putAll(map2);

//添加元素:如果有该key就不添加,返回集合中的value
System.out.println(map.putIfAbsent("aa", 20));  //21
System.out.println(map.putIfAbsent("adc", 20));  //null


//清空集合
//		map.clear();

//通过key获取对应的value
Integer integer2 = map.get("aa"); 
System.out.println(integer2); //21

System.out.println(""+map.getOrDefault("sf", 404));//如果没有key则返回默认设置的value

//判断集合中是否存在元素

System.out.println(map.isEmpty());//存在元素:false ;不存在:true

//删除元素
map.remove("abc");//通过key值
map.remove("bb", 22);  //通过key+value判断
map.remove("cc", 22);  //通过key+value判断

//替换
//替换成功就返回替换前的value值
System.out.println("替换1:"+map.replace("aa", 100));
//替换不成功就返回null
System.out.println("替换2:"+map.replace("ggb", 100));
//put替换:如果有相同key,就替换value,并返回原来的value。
System.out.println("替换3:"+map.put("ff", 100));
/*
替换1:21
替换2:null
替换3:21
*/
//获取集合的元素个数
System.out.println("集合元素个数:"+map.size());

//获取所有的value值
Collection<Integer> values = map.values();
System.out.println(values);
//遍历1——keySet()
//将所有的key抽取到Set集合中,在通过迭代器获取value值
System.out.println("-------------------");
Set<String> set = map.keySet();
for (String key : set) {
    Integer integer = map.get(key);
    System.out.println(key+"----"+integer);
}
System.out.println("-------------------");

//遍历2 -entrySet()
Set<Entry<String, Integer>> entrySet = map.entrySet();
for (Entry<String, Integer> entry : entrySet) {
    System.out.println(entry);
}
/*
dd=21
ff=100
hh=10
jj=10
aa=100
cc=23
ee=20
gg=10
ii=10
adc=20
*/

13.4.2 LinkedHashMap

底层:双向链表

特点:存入键值对(key—value),去重+有序

(对照ArrayList和LinkedList)

13.4.3 ConcurrentHashMap

底层:一维数组

特点:存入键值对(key—value),去重+无序+线程安全(效率高—局部加锁)

使用方法和HashMap相同,但具有线程安全的特性。

13.4.4 Hastable(已弃用)

底层:一维数组

特点:存入键值对(key—value),去重+无序+线程安全(效率低—方法加锁)

使用方法和HashMap相同,虽然具有线程安全的特性,但效率低,已经被遗弃。

13.4.5 Properties

作用:配置文件

使用示例:

  1. 创建后缀为.properties的文件,放入src文件夹下。文件中可以编辑用户名和密码。
username=root
password=123456

注:字符串也不需要加" "。

  1. 在类中的使用:
public static void main(String[] args) throws IOException {
    //创建配置文件的对象
    Properties p = new Properties();
    //将配置文件加载到对象中
    p.load(Test_2.class.getClassLoader().getResourceAsStream("DBconfig.properties"));
    String username=p.getProperty("username");
    String password=p.getProperty("password");
    System.out.println(username+"----"+password);
}
/*
root----123456
*/

13.4.6 TreeMap

使用示例(Student类见上13.3.8):

调用内部比较器

//内部比较器见Student类中,排序方法使用年龄排序
TreeMap<Student, Integer> map = new TreeMap<>(new Comparator<Student>() {

    @Override
    public int compare(Student o1, Student o2) {

        return o2.getAge()-o1.getAge();
    }
});
map.put(new Student("小明",20),20);
map.put(new Student("小红",18),20);
map.put(new Student("小刚",27),20);
map.put(new Student("小南",19),20);
map.put(new Student("小慧",21),20);
Set<Entry<Student,Integer>> entrySet = map.entrySet();
for (Entry<Student, Integer> entry : entrySet) {
    System.out.println(entry);
}
/*
Student [name=小红, age=18]=20
Student [name=小南, age=19]=20
Student [name=小明, age=20]=20
Student [name=小慧, age=21]=20
Student [name=小刚, age=27]=20
*/

调用外部比较器

//调用外部比较器(比较器采用年龄倒序排序)
TreeMap<Student, Integer> map = new TreeMap<>(new Comparator<Student>() {

    @Override
    public int compare(Student o1, Student o2) {

        return o2.getAge()-o1.getAge();
    }
});
map.put(new Student("小明",20),20);
map.put(new Student("小红",18),20);
map.put(new Student("小刚",27),20);
map.put(new Student("小南",19),20);
map.put(new Student("小慧",21),20);
Set<Entry<Student,Integer>> entrySet = map.entrySet();
for (Entry<Student, Integer> entry : entrySet) {
    System.out.println(entry);
}
/*
Student [name=小刚, age=27]=20
Student [name=小慧, age=21]=20
Student [name=小明, age=20]=20
Student [name=小南, age=19]=20
Student [name=小红, age=18]=20
*/

Map集合之间的综合比较:

HashMap:存储键值对,无序,允许存null键,线程不安全

LinkedHashMap:存储键值对,有序,允许存null键,线程不安全

Hashtable:存储键值对,无序,不允许存null键,线程安全(直接在方法中上锁,效率低),已弃用

ConcurrentHashMap:存储键值对,无序,不允许存null键,线程安全(局部加锁,效率高)

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java入门基础知识是学习和理解Java编程语言的基础概念和语法规则。下面是一些常见的基础知识点: 1. Java环境安装:首先需要安装Java开发工具包(JDK),它包含了Java编译器和运行时环境。 2. Java语言特点:Java是一种面向对象的编程语言,具有简单、可移植、面向对象、安全、高性能等特点。 3. Java程序结构:一个Java程序由一个或多个类组成,每个类包含方法和属性。Java程序从main()方法开始执行。 4. 数据类型:Java提供了基本数据类型(如整数、浮点数、字符、布尔等)和引用数据类型(如类、数组、接口等)。 5. 变量和常量:变量是用于存储数据的内存位置,常量是固定不变的值。在Java中,使用关键字来声明变量和常量。 6. 运算符:Java提供了各种运算符,例如算术运算符、赋值运算符、比较运算符、逻辑运算符等。 7. 控制流程:Java提供了条件语句(如if-else、switch-case)、循环语句(如for、while、do-while)和跳转语句(如break、continue)来控制程序的执行流程。 8. 数组:数组是一种存储相同类型数据的集合,可以通过索引访问数组中的元素。 9. 方法:方法是一段可重用的代码块,用于执行特定的任务。Java中可以定义自己的方法,也可以使用已经存在的方法。 10. 异常处理:Java提供了异常处理机制来处理程序运行过程中发生的异常情况,可以使用try-catch语句块来捕获和处理异常。 以上是Java入门基础知识的一些主要内容,希望对你有所帮助。如果有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值