JavaSE基础语法--集合与容器使用
第七章:集合/容器
集合:能动态增长长度,并且可以实现各种数据结构的容器,就是集合。
Java的集合框架是由很多接口、抽象类、具体类组成的,都位于java.util包中
1.Collection接口
数组的缺点: 长度一旦定义就不可变 , 结构单一 ,只存储类型相同的元素
Collection(集合接口):不能实例化 集合可以存储引用类型(默认是Object类型),可以添加任何元素,它会先用valueOf()自动装箱,最好还是向集合中添加同一类型的元素
1.基本方法
public static void main(String[] args) {
// 通过子类创建父类对象
Collection c = new ArrayList();
// 向末尾添加元素
c.add(2);
c.add("3");
c.add(4);
c.add(3);
c.add("6");
c.add(true);// 它会先用valueOf()自动装箱
System.out.println(c);
// 删除指定元素,并且删除时需要与输入时的数据类型相同
c.remove("3");
System.out.println(c);
// size()方法 得到集合的长度
// length属性 得到数组的长度
// length()方法 得到字符串的长度
System.out.println(c.size());
// isEmpty 是否为空
System.out.println(c.isEmpty());
// contains 是否包含
System.out.println(c.contains(3));
// clear 清空
// c.clear();
// System.out.println(c);
// addAll 将一个集合添加到另一个集合中
Collection c1 = new ArrayList();
c1.add(7);
c1.add(8);
c1.add(9);
c1.addAll(c);
System.out.println(c1);
// containsAll 集合 c1 是否包含集合 c
System.out.println(c1.containsAll(c));
// removeAll 删除集合c1中与c相同的元素
// c1.removeAll(c);
// System.out.println(c1);
// retainAll c1中只保留c1与c的交集,有改变时返回true
System.out.println(c1.retainAll(c));
System.out.println(c1);
// removeIf有选择地删除指定元素 匿名内部类过滤
System.out.println(c1.removeIf(new Predicate() {
@Override
public boolean test(Object o) {
return o.equals("6");
}
}));
}
2.集合转数组 toArray( )
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("1");
c.add("2");
c.add("3");
c.add("4");
// 第一种方式
Object obj = c.toArray();
System.out.println(obj.toString());
// 第二种方式
Collection<String> c1 = new ArrayList<String>();// JDK8以后如果前面写了,后面就不用写了。
c1.add("5");
c1.add("6");
c1.add("7");
c1.add("8");
String[] s = c1.toArray(new String[c1.size()]);
System.out.println(Arrays.toString(s));
3.数组转集合 asList(T… a)
public static void main(String[] args) {
// asList(T...a)数组转换列表
Integer[] i = new Integer[]{1,2,4};
List<Integer> list = Arrays.asList(i);
System.out.println(list);
// 可变长度参数,可同时传入多个参数
// 本质是一个数组,一个参数列表只能有一个
// 必须方法参数列表末尾,可以直接传一个数组。
test(1,2,3,4);
}
public static void test(int...a){
System.out.println("");
}
4.特殊方法 sort( ),subList( ),removeRange( )
public static void main(String[] args) {
ArrayList a = new ArrayList();
a.add("s");
a.add("d");
a.add("f");
a.add("a");
a.add("t");
a.add("k");
// 不能直接使用sort函数,需要创建一个比较类
a.sort(new StringC());
System.out.println(a);
// 从集合中截取元素,包括开始,不包括结束
System.out.println(a.subList(2,5));
// 删除指定区间元素 包含开始,不包含结束
CollectionDemo3 list = new CollectionDemo3();
list.add("s");
list.add("d");
list.add("f");
list.add("a");
list.add("t");
list.add("k");
list.removeRange(0,3);
System.out.println(list);
}
排序所需要的比较类
public class StringC implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
}
2.List接口
List:数据对象 有顺序 且 可以重复。
List继承了Collection接口,有三个实现的类,分别是下面的三个:
LinkedList:采用双向链表存储方式。插入、删除元素时效率比较高
Vector: 数组列表,同步锁,线程安全的,两倍扩容
ArrayList: 数组列表,数据采用数组方式存储,实现了长度可变的数组,一点五倍扩容。遍历元素与随机访问元素效率高。
1.ArrayList
ArrayList: 数组列表,数据采用数组方式存储,实现了长度可变的数组,一点五倍扩容。
在内存中分配连续的空间。遍历元素和随机访问元素的效率比较高。(是我们最常用的)
public static void main(String[] args) {
// ArrayList的默认空间初始值是10,如果需要更大的空间,建议在一开始初始化的时候就设置新的空间大小。
// ArrayList的常用方法
ArrayList a1 = new ArrayList(100);
a1.add(0,1);
a1.add(1,3);
a1.add(0,2);
a1.add(1,4);
a1.add(3,4);
a1.add(3,2);
a1.add(9);// 不加索引就是向末尾插入
System.out.println(a1);// [2, 4, 1, 3]
// 测试之前add()方法是赋值的意思,结果出来之后知道了,是以插入的方法进行赋值
// get()方法是通过指定index索引得到数组元素
System.out.println(a1.get(0));// 4
// indexOf方法是 从头遍历寻找指定元素的索引值
// 如果搜索的是数组中没有的值,那么会返回 -1
// 如果有重复的元素,会返回距离头部最近的元素的索引
System.out.println(a1.indexOf(4));
// lastIndexOf 从尾遍历寻找指定元素的索引值
// 如果搜索的是数组中没有的值,那么会返回 -1
// 如果有重复的元素,会返回距离尾部最近的元素的索引
System.out.println(a1.lastIndexOf(2));
// remove 删除并返回指定位置的元素
// 如果超过索引范围,就会抛出异常java.lang.IndexOutOfBoundsException
System.out.println(a1.remove(2));
System.out.println(a1);// [2, 4, 2, 4, 3]
// set 修改指定索引的元素值
// 如果超过索引范围,就会抛出异常java.lang.IndexOutOfBoundsException
a1.set(3,9);
System.out.println(a1);// [2, 4, 2, 9, 3]
}
2.LinkedList
LinkedList:采用双向链表存储方式。插入、删除元素时效率比较高
public static void main(String[] args) {
LinkedList a = new LinkedList();
// add 向指定索引处插入元素
a.add(0,1);
a.add(1,2);
a.add(2,3);
a.add(1,4);
a.add(4,5);
System.out.println(a);// [1, 4, 2, 3, 5]
// addFirst 向头部插入指定元素
a.addFirst(3);
a.addFirst(0);
System.out.println(a);// [0, 3, 1, 4, 2, 3, 5]
// addLast 向尾部插入指定元素
a.addLast(9);
a.addLast(10);
System.out.println(a);// [0, 3, 1, 4, 2, 3, 5, 9, 10]
// remove 删除指定索引的元素
// 超出索引位置会报错java.lang.IndexOutOfBoundsException
a.remove(7);
System.out.println(a);// [0, 3, 1, 4, 2, 3, 5, 10]
// removeFirt 删除头部首个元素
a.removeFirst();
System.out.println(a);// [3, 1, 4, 2, 3, 5, 10]
// removeLast 删除尾部首个元素
a.removeLast();
System.out.println(a);// [3, 1, 4, 2, 3, 5]
// getFirst 获得头部的首个元素
System.out.println(a.getFirst());// 3
// getLast 获得尾部的首个元素
System.out.println(a.getLast());// 5
// 因为LinkedList 和 ArrayList实现了同一个接口List所以能调用的方法基本是一样的
System.out.println(a.get(2));// 4
}
3.Vector
vector: 底层也是数组实现的,可扩容,,多线程安全。(方法基本与ArrayList一样)
Vector<String> v = new Vector<>();
v.add("1");
v.add("3");
v.add("2");
v.add("2");
v.add("4");
System.out.println(v);//[1, 3, 2, 2, 4]
4.集合遍历
集合遍历:
- for循环
- foreach循环
- iterator迭代器
public static void main(String[] args) {
Vector<String> v = new Vector<>();
v.add("1");
v.add("3");
v.add("2");
v.add("2");
v.add("4");
System.out.println(v);//[1, 3, 2, 2, 4]
// 集合迭代与遍历
// for循环遍历
for (int i = 0; i < v.size(); i++) {
System.out.print(v.get(i));// 1324
if(v.get(i).equals("2")){
v.remove(i);
/*
* 删除元素后,长度减一,元素向前移动一位。
* 想解决这个问题,可以在执行完删除操作后,i--
* */
i--;
}
}
System.out.println();
System.out.println(v);// [1, 3, 4]
// foreach 遍历
for(String vector : v){
System.out.print(vector);// 遍历
if(vector.equals("3")){
v.remove(vector);
break;
/*
* 如果删除元素就会抛出异常,即不允许在遍历过程中进行操作。
* ConcurrentModificationException 表明不能修改
* 如果必要进行删除,可以在删除元素后立即退出循环,这样就不会抛出异常。
* */
}
}
System.out.println();
System.out.println(v);// [1, 4]
// 迭代器 Iterator ——> 接口
Iterator<String> iterator = v.iterator();
while(iterator.hasNext()){// 是否还有元素
String s = iterator.next();
System.out.println(s);// 遍历
iterator.remove();// 拿一个删除一个
// 必须使用Iterator专用删除方法,无需参数,不然也会抛出异常
// 删除指定元素
// if(iterator.equals("1")){
// iterator.remove();
// }
}
}
3.泛型
泛型:早期的Object类可以表示接收任何类型,但是在类型转换时,存在一定的隐患,因此出现了泛型
泛型类型可以添加任何元素,但只能是引用类型,例:Integer
泛型类型默认是 Object类型
泛型可以有多个,例如 在类声明时
/*
* 泛型:早期的Object类可以表示接收任何类型,但是在类型转换时,存在一定的隐患,因此出现了泛型
* 泛型类型可以添加任何元素,但只能是引用类型,例:Integer
* 泛型类型默认是 Object类型
* 泛型可以有多个,例如 在类声明时
* */
public class GenericDemo<T> {
// 泛型在类声明中使用,可以是多个,例:<T,V,K>
Object obj;
public static void main(String[] args) {
// 向上转型,没问题,但是向下转型可能会有问题
GenericDemo generic = new GenericDemo();
generic.obj = 1;
generic.obj = "1";
generic.obj = true;
ArrayList arr = new ArrayList();
arr.add(1);
arr.add("2");
arr.add(true);
for (int i = 0; i < arr.size(); i++) {
Object obj = arr.get(i);// 这样是没问题的
System.out.print(obj);// 1, 2, true
}
System.out.println();
for (int i = 0; i < arr.size(); i++) {
// String s = arr.get(i);
/*
* 这样会直接编译报错,
* 因为String类与Integer类和Boolean类都是Object类的子类,
* 但是他们之间没有关联,是"平级的"
* 因此会编译失败
* */
// 这种时候还想要遍历的话就需要加一个判断
// 但是当一个集合中的数据类型过多的时候,这就会很麻烦
Object obj = arr.get(i);
if (obj instanceof String) {
String s1 = (String) obj;
System.out.println(s1);
}
}
// 如果使用泛型的话就会直接确定集合元素的类型
ArrayList<String> alist = new ArrayList<String>();
// JDK-8 以后可以不用再写后面的类型
// 类型不对的话,会在添加元素编译的时候直接报错
// alist.add(1);
// alist.add(true);
alist.add("1");
alist.add("2");
alist.add("3");
for (int i = 0; i < alist.size(); i++) {
System.out.print(alist.get(i));
}
}
// 泛型在方法中使用
public T test(T t1) {
return t1;
}
}
4.Set接口
Set:接口,不允许重复元素
HashSet:无序(不是按照添加顺序排序,而是按照哈希值排序),不可重复
TreeSet:有序(按照元素的自然顺序存储,例如2,1,3——> 1,2,3)不可重复。数据类型必须 实现comparable接口 , 重写compareTo()
1.HashSet
hashSet:无序(不是按照添加顺序排序,而是按照哈希值排序),不可重复
哈希表加链表存储,同一位置可以存储不同内容的元素
底层为hashMap
public native hashcode(),native 意为调用本地系统方法
public static void main(String[] args) {
Student s1 = new Student(1,"jim1");
Student s2 = new Student(2,"jim1");
Student s3 = new Student(3,"jim1");
Student s4 = new Student(4,"jim4");
// 添加时根据内容的hash值,再经过hash函数计算得到元素在hash表中存储的位置
HashSet hashSet = new HashSet();
hashSet.add(s1);
hashSet.add(s2);
hashSet.add(s3);
hashSet.add(s4);
// 如果不在student类中重写hashcode(),那么就会调用Object中hashcode()方法算出对象(对象不同,哈希值就不同)的哈希值
// 重写Object类中hashCode(),来自己根据对象中包含的内容计算hash值。
// 向hashSet中添加元素是如何判断重复元素?
// 底层是双保险,既要提高判断效率,又要安全可靠。
/*
* ① 首先通过hashcode()算出添加内容的哈希值,判断hash值在集合中是否存在,
* 但是有时哈希值可能相同,但内容不同,因此并不安全
* 效率高,但是可能会出现重复
* ② 当哈希值相同时,就需要通过equals()足逐个判断元素内容是否相同。
* 效率底,安全
* */
System.out.println(hashSet);
}
Student类
public class Student {
private int num;
private String name;
public Student(int num, String name) {
this.num = num;
this.name = name;
}
public Student() {
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Student student = (Student) o;
return num == student.num &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(num,name);
}
@Override
public String toString() {
return "Student{" +
"num=" + num +
", name='" + name + '\'' +
'}';
}
}
2.TreeSet
TreeSet:有序(按照元素的自然顺序存储,例如2,1,3——> 1,2,3)不可重复
数据类型必须 实现comparable接口 , 重写compareTo( )
底层为红黑树
public static void main(String[] args) {
TreeSet<String> tset = new TreeSet<String>();
tset.add("c");
tset.add("d");
tset.add("b");
tset.add("a");
System.out.println(tset);//[a, b, c, d] 有序,按照内容的自然顺序排序
// 自定义对象
Student s1 = new Student(1,"stu1");
Student s2 = new Student(2,"stu2");
Student s3 = new Student(3,"stu3");
Student s4 = new Student(4,"stu1");
TreeSet<Student> ts = new TreeSet<Student>();
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
// 自己定义的数据类型如果不实现comparable接口,并重写compareTo(),就会报错
// java.lang.ClassCastException
System.out.println(ts);
}
Student类
public class Student implements Comparable<Student>{
private int num;
private String name;
public Student(int num, String name) {
this.num = num;
this.name = name;
}
public Student() {
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(Student o) {
return this.name.compareTo(o.name);
}
}
5.Map接口
Map:双列存储 ,键 – 值
键不能重复,而值可以重复
键相同时,后面的会将前面的键包括值覆盖掉
键值去重复 :hashcode (), equals( )
允许有一个为空的键, map.put(null,“q”)
分为三类:
- HashMap
- TreeMap
- Hashtable
1.HashMap
hashMap:无序(通过hashcode(),和equals() 去重复,添加元素)
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("a", "a");
map.put("a", "b");
map.put("c", "c");
map.put("s", "s");
map.put("q", "q");
// 为空的键
//map.put(null, "q");
// 清空所有键值对
//map.clear();
// 删除指定元素
//map.remove("a");
// 得到键为 a的键值对的值
//System.out.println(map.get("a"));
// 是否包含指定键
//System.out.println(map.containsKey("f"));
// 是否包含指定值
//System.out.println(map.containsValue("s"));
// 是否为空
System.out.println(map.isEmpty());
// 获取长度,即键值对个数
System.out.println(map.size());
}
2.TreeMap
treeMap:按照键的自然顺序排序,键的类型所属类必须实现comparable接口,TreeMap根据compareTo( )的逻辑对key进行排序。底层为红黑树。
public static void main(String[] args) {
TreeMap<String,String> tree = new TreeMap<>();
tree.put("b","b");
tree.put("b","c");
tree.put("a","x");
tree.put("s","l");
// 不允许重复,按照键的自然顺序排序
System.out.println(tree);//{a=x, b=c, s=l}
}
3.Hashtable
Hashtable: 线程安全的,按照添加顺序排序,底层也是哈希表加单链表
哈希碰撞:哈希值一样,内容不一样。
public static void main(String[] args) {
Hashtable<String,String> able = new Hashtable<>();
able.put("b","b");
able.put("b","c");
able.put("a","b");
able.put("c","d");
// 按照添加顺序排序
System.out.println(able);// {b=c, a=b, c=d}
}
4.Map集合遍历
1.keySet( )
获取键的集合;遍历键的集合,获取每一个键;根据键找值
// map遍历一 keySet
Set<String> keySet = map.keySet();
for (String key : keySet) {
System.out.println(key + "==" + map.get(key));
}
2.entrySet( )
获取所有键值对对象的集合;遍历键值对对象的集合,获取到每一个键对对象;根据键值对对象找键和值
// map遍历二 entrySet常用
Set<Map.Entry<String, String>> entrySet1 = map.entrySet();
for (Map.Entry<String, String> entrySet : entrySet1) {
System.out.println(entrySet.getKey() + "==" + entrySet.getValue());
}
6.Collections
Collections:对集合进行常规操作的类(工具类)
定义的静态方法分为两类:①同步集合对象的方法;②对List排序的方法
public static void main(String[] args) {
ArrayList<String> arr = new ArrayList<>();
arr.add("b");
arr.add("v");
arr.add("d");
arr.add("s");
ArrayList<String> list = new ArrayList<>();
list.add("i");
list.add("p");
list.add("o");
// 排序
Collections.sort(arr);
System.out.println(arr);//[b, d, s, v]
// 二分搜索,前提是有序有序列表,搜索不到返回负数。
System.out.println(Collections.binarySearch(arr,"v"));
// 添加多个元素
Collections.addAll(arr,"x","k","l");
System.out.println(arr);//[b, d, s, v, x, k, l]
// 复制一个列表到另一个列表。目的列表的长度应大于源列表
Collections.copy(arr,list);
// 目的 源列表
System.out.println(arr);//[i, p, o, v, x, k, l]
// 全部变为A
// Collections.fill(arr,"A");
// System.out.println(arr);//[A, A, A, A, A, A, A]
// 回文
Collections.reverse(list);
System.out.println(list);//[o, p, i]
// 交换两个位置的元素
Collections.swap(arr,3,4);
System.out.println(arr);//[i, p, o, x, v, k, l]
}
若有错误,欢迎私信指正。
本文地址:https://blog.csdn.net/weixin_44734518/article/details/110147554