文章目录
集合类
1 为什么要使用集合类?
集合类就是用于存储多个数据的类
在Java基础中我们学习了数组,而数据时可以存储多个数据的,为什么还要使用集合?
1.2数组的特点
- 用于存放多个数据
- 数组中的数据的数据类型是相同的
- 数组的长度固定
- 数组的操作需要开发人员自己定义相关操作算法
1.3 集合类的特点
- 集合类中可以存放多个数据
- 集合类中存放的数据的类型的任意类型(内部类型为Object类型,所以可以存放任意类型)
- 集合类的长度都是可变的
- 集合类中提供了关于这类集合的常用操作方法,开发人员可以通过这些方法实现对集合的常见操作
集合类不是一个类,而是一套接口和类的统称
2 Java中集合类的类结构
Java中的集合类根据存储方式不同分为两大类集合
-
基于Collection接口的
线性
集合Collection接口下有两个子接口,分别对应不同的线性集合
-
List接口的特点
(1).有序的集合(进入到集合中顺序和取出顺序一致)
(2).可以存放重复数据的集合- List接口的的实现类:
①.ArrayList
②.LinkedList
③.Vector
- List接口的的实现类:
-
Set接口
(1).无序的集合(不保证集合中元素的顺序)
(2).不允许存放重复数据的集合- Set接口的实现类:
①.HashSet
②.TreeSet
- Set接口的实现类:
-
-
基于Map接口的
key-value
映射对集合
3 基于List接口的ArrayList类的使用
ArrayList底层是基于动态数组实现的
3.1 ArrayList的特点
ArrayList在使用时,查找其中的元素效率是比较高的,数组有下标,可以通过下标直接锁定到一个元素
ArrayList在插入或移除元素时效率低(内存中要移位)
3.2 ArrayList常用API
-
创建ArrayList对象
//创建ArrayList集合类对象 ArrayList arrayList = new ArrayList();
-
add(element):向ArrayList的尾部追加一个元素
//向ArrayList的尾部追加元素 arrayList.add("aaa"); arrayList.add(20); arrayList.add('a'); arrayList.add(true); arrayList.add(20.5);
-
add(index,element):向集合中的某个位置插入一个元素
//向ArrayList某个位置插入元素 arrayList.add(2,"str")
-
set(index,element) :替换集合中的某个元素
//更改ArrayList替换位置的元素 arrayList.set(2,"set")
-
contains(element):检查集合是否有指定元素
//检查ArrayList中是否含有指定元素 arrayList.contains("set")
-
isEmpty():检查容器是否为空
arrayList.isEmpty()
-
get(index):根据下标获得该下标对应的元素,默认返回Object类型(根据自己的需要转换具体类型)
//根据下标获得一个元素 String str= (String) arrayList.get(0); System.out.println(str);
-
remove(element|index):
如果参数为对象类型,则根据内容移除,如果参数为int类型的基本类型则根据下标移除
//移除元素 arrayList.remove("aaa"); System.out.println(arrayList); //如果参数为int类型,则根据下标移除,如果要移除的内容为整数则需要使用Integer类型删除 arrayList.remove(new Integer(3)); System.out.println(arrayList);
-
addAll():集合并集操作
ArrayList<String> arrayList=new ArrayList<>(); arrayList.add("1"); arrayList.add("2"); ArrayList<String> arrayList1=new ArrayList<>(); arrayList1.add("我是一"); arrayList1.add("我是二"); arrayList.addAll(arrayList1);
-
retainAll():集合交集操作
ArrayList<String> arrayList2=new ArrayList<>();
arrayList2.add("1");
arrayList2.add("我是二");
arrayList2.add("我是一");
ArrayList<String> arrayList3=new ArrayList<>();
arrayList3.add("我是一");
arrayList3.add("我是二");
boolean flag= arrayList2.retainAll(arrayList3);//判断是否交集成功
-
removeAll():集合中差集操作
ArrayList<String> arrayList4=new ArrayList<>(); arrayList4.add("1"); arrayList4.add("我是二"); arrayList4.add("我是一"); ArrayList<String> arrayList5=new ArrayList<>(); arrayList5.add("我是一"); arrayList5.add("我是二"); boolean flag1=arrayList4.removeAll(arrayList5);
-
遍历ArrayList集合中的所有元素
//遍历List集合中的所有元素 //使用传统for循环遍历 for(int i=0;i<arrayList.size();i++){ Object obj = arrayList.get(i); System.out.println(obj); } System.out.println("---------------"); //使用for循环加强版遍历 for(Object obj : arrayList){ System.out.println(obj); } System.out.println("---------------"); //用迭代器遍历 Iterator iterator=arrayList.iterator(); while(iterator.hasNext() System.out.println(iterator.next()) } //使用list集合中的foreach方法进行遍历 arrayList.forEach(System.out::println);
4 基于List接口的实现类Vector
4.1 Vector的特点
1.Vector的底层也是基于动态数组实现
2.Vector中提供的操作和ArrayList基本相同
4.2 ArrayList和Vector的区别
- 相同点:ArrayList和Vector底层都是基于动态数组实现,而且提供了相近的API
- 不同点:
(1) ArrayList默认创建长度为0的数组,而Vector创建的长度为10的数组
(2) Vector是线程安全的,而ArrayList是非线程安全的,在并发情况下建议使用Vector
我们可以通过外部手段让ArrayList也是线程安全的
5 Vector的子类Stark
Stark栈容器,是Vector的一个子类,它实现了后进先出的栈
5.1 Stark的特点
后进先出
5.2 Stark常用api
-
创建Stark对象
//实例化栈容器 Stack<String> stack=new Stack<>();
-
push() 入栈,压栈
//入栈 stack.push("one"); stack.push("two"); stack.push("three");
-
pop() 出栈,弹栈(删除栈顶部对象,并返回他的值)
//出栈 //获取栈容器元素 System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack.pop());
-
empty() 检查栈容器是否为空
//检查栈容器是否为空 System.out.println(stack.empty());
-
peek() 读取栈顶元素
//查看栈顶元素 System.out.println(stack.peek());
-
search() 返回栈元素在容器所在位置
System.out.println(stack.search("one"));
5.3 Stark使用案例
-
判断元素对称性
String str=“… {…[…(…)…]…}…(…)…[…]…” ;
public class Test01 { public static void main(String[] args) { String str="... {.....[....(....)...]....}..(....)..[...]..." ; Stack<String> stack=new Stack<>(); //假设修正法 boolean flag=true;//假设是匹配的 //拆分字符串获取字符 for (int i=0;i<str.length();i++){ char chars=str.charAt(i); if (chars == '['){ stack.push("]"); } if (chars =='{'){ stack.push("}"); } if (chars =='('){ stack.push(")"); } //判断符号是否匹配 if (chars =='}'||chars==']'||chars==')'){ if (stack.empty()){ flag=false; break; } String str1= stack.pop(); if (str1.charAt(0)!=chars){ flag=false; break; } } } if (!stack.empty()){ flag=false; } System.out.println(flag); } }
6 基于List接口的实现类LinkedList
LinkedList底层是基于链表实现
6.1 LinkedList的特点
1.插入或删除元素时效率高
2.查询及遍历元素时效率低
6.2 LinkedList常用API
- add(element):尾部添加
- addFirst(element):首部插入
- addLast(element):尾部插入
- add(index,element):指定下标位置插入元素
- push(element):入栈
- pop():出栈
- toArray():将列表转换为数组
7 基于Set接口的实现类HashSet
7.1 HashSet的特点
- 底层基于Map集合的实现
- 不能存放重复数据
- 集合中的元素不保证顺序
- Set集合无法从集合中直接获取某一个元素
- Set集合没有下标
7.2 HashSet常用API
1.add(element):向集合中添加一个元素
2.iterator():遍历集合中的所有元素
//遍历集合中元素
Iterator<String> iterator = hashSet.iterator();
//循环遍历集合中的每个元素
while(iterator.hasNext()){
//检测集合中是否存在要迭代的数据,true表示存在
String str = iterator.next();//获取一个元素
System.out.println(str);
}
3.通过foreach循环遍历集合中所有元素
//使用foreach遍历集合中的所有元素
for(String str : hashSet){
System.out.println(str);
}
4.使用foreach方法遍历集合中的元素
//通过foreach方法遍历集合中的所有元素
hashSet.forEach(System.out::println);
8 基于Set接口的TreeSet实现
TreeSet是基于树状结构的Set集合,该集合可以排序,被称为可排序的Set集合
8.1 TreeSet集合的特点
1.TreeSet是一个有序的Set集合
2.TreeSet中不能存放重复数据
3.在TreeSet中存储的元素必须为可排序的元素(实现了比较器接口的对象),如果存储的元素为不可排序的元素则会报异常(ClassCastException)
9 基于key-value(键值对)的Map集合
Map集合中存储的元素为一个key对应一个value
9.1 Map集合的特点
1.key不允许重复,默认情况下key是Object类型,可以存放任意类型的数据
2.value是允许重复,默认情况下value是Object类型,可以存放任意类型的数据
3.Map中允许存在null的key(只能出现一次)和null的value
9.2 基于Map接口的实现类HashMap
HashMap中不允许存放重复key,如果新添加的key已存在,则使用新的value替换原有的value值
9.3 HashMap的常用API
1.put(key,val):向Map集合中添加一对key-value
2.get(key):根据key获得对应的value
3.remove(key):根据key移除Map集合中的一个元素
4.size():获得集合中元素的数量
5.keySet():获得Map集合中所有的key,返回一个包含所有key的set集合
//获取hashmap中所有元素
System.out.println(hashMap.keySet());
for (String map :hashMap.keySet()){
System.out.println(map+"<--------->"+hashMap.get(map));
}
}
}
6.values():获得Map集合中所有的value,返回一个Collection集合
7.entrySet():获得Map集合中每个元素的Entry集合对象,返回Set集合
for (Map.Entry<String,String> entry : map.entrySet()){
System.out.println(entry.getKey()+"<--->"+entry.getValue());
}
Map集合中的key不能重复,如果想Map添加一个新元素,Map集合如何判定该元素在集合中是否存在?
10 基于Map接口的TreeMap实现类
TreeMap和TreeSet一样都是一个可排序的集合
TreeMap中根据key进行排序的
进入到TreeMap中的元素(key)必须为可排序的元素(key)
11 附加知识点
-
Collections工具类
- Collections常用api
void sort(List) 对容器内元素进行排序
void shuffle(List)对List中元素进行随机排序
void reverse(List)对List中元素进行逆序排序
void fill(List,Object)用一个特定的对象重写整个容器
int binarySerach(List,Object)二分查找
addAll(Collection,element…):一次性向集合添加多个元素
- Collections常用api
-
equals方法
==也是用于判断两个对象是否相等:用于判断两个对象是否为同一个对象的
equals方法用于判断两个对象的值是否相等
String s1 = "abc";
String s2 = "abc";
//s1和s2两个变量都指向“abc”字符串对象,他们两个是同一个对象
System.out.println(s1 == s2);
/**
* Java中每次使用new关键字创建对象时,在JVM的堆区都会自动创建一个新对象
* 只不过两个对象的值都是"abc"字符串
* 这两个对象不是同一个对象,但他们的值是相等
* 所以“==”的结果为false,他们两个不是同一个对象
* 如果要判断两个对象的值是否相等使用equals方法
*/
String str = new String("abc");
String str1 = new String("abc");
System.out.println(str == str1);//false
System.out.println(str.equals(str1));
equals方法在任意对象中都存在,该方法在Object类中定义的,他们默认定位为
public boolean equals(Object obj) {
return this == obj;
}
从Object类中的源码可以看出,equals方法默认的定义为判断两个对象是否为同一个对象的
所以为了能够判断两个对象的值是否相等,我们在自己定义的实体类中都会重写该方法
String重写equals方法,JDK中大多数类都重写了该方法…
- hashCode方法
hashCode方法在任意类中都存在,该方法也是在Object类中定义的
hashCode方法用于获得当前对象所对应的内存地址的hash码
如果两个对象的hash相等,则表示当前的两个对象肯定为同一个对象(默认情况)
开发人员可以根据实际需要重写hashCode,重写后不同对象的hashCode就有可能相等
在开发中一般会重写equals方法和hashCode方法以改变他们的默认行为
- Map集合如何判断新添加的元素的key在集合中是否存在
1.先判断hashCode是否相等,如果hashCode不相等则认为没有相同的对象,直接将新元素添加到map集合中
2.如果hashCode的值存在相等的,则无法确定是否存在相同对象,进而继续判断equals方法,如果equals返回值为true,则认为存在相等元素
使用新元素替换原有的元素,如果equals判断是不相等,则认为不存在相同对象直接将新元素添加到map集合中
- 比较器接口
比较器是用于定义比较规则,有了比较规则后,就可以对这些数据按照比较规则进行排序
Java中定义比较规则的方式有两种:
(1) 实现Comparable接口:Comparable在java.lang包下
- Comparable用于实现对象的默认比较规则,默认比较规则只有一种
- Comparable中存在一个compareTo方法,该方法用于定义比较规则
- 方法的返回值为正整数表示当前对象大于比较对象
- 方法的返回值等于0两个对象相等
- 方法的返回值为负整数表示当前对象小于比较对象
@Override
public int compareTo(User user) {
return this.userId - user.getUserId();
}
(2) 实现Comparator接口:Comparator在java.util包下
- Comparator用于定义对象的扩展比较规则的,可以定义多个
- Comparator接口中有一个定义比较规则的方法compare(obj1,obj2)
- 方法的返回值为正整数表示obj1大于obj2
- 方法的返回值等于0两个对象相等
- 方法的返回值为负整数表示obj1小于obj2
/**
* 使用内部类定义扩展规则
* 1.根据积分升序排序
*/
static class sortByScoreASC implements Comparator<User>{
@Override
public int compare(User user1, User user2) {
return user1.getUserScore() - user2.getUserScore();
}
}
/**
* 2.根据积分降序排序
*/
static class sortByScoreDESC implements Comparator<User>{
@Override
public int compare(User user1, User user2) {
return user2.getUserScore() - user1.getUserScore();
}
}
/**
* 2.根据学号降序排序
*/
static class sortByUserIdDESC implements Comparator<User>{
@Override
public int compare(User user1, User user2) {
return user2.getUserId() - user1.getUserId();
}
}
//调用
// TreeSet<User> users = new TreeSet<>();//使用user对象中的默认排序规则进行排序
//使用User内定义的内部类指定排序规则
// TreeSet<User> users = new TreeSet<>(new User.sortByUserIdDESC());
//使用匿名内部类定义排序规则
TreeSet<User> users = new TreeSet<>(new Comparator<User>() {
//使用匿名内部类实现比较器接口
@Override
public int compare(User user1, User user2) {
return user1.getRegDate().compareTo(user2.getRegDate());
}
});
- transient关键字
将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会被序列化。
1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
3)被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。
- native关键字
Java不能直接访问操作系统及硬件底层,需要通过native关键字来实现对底层的控制,这就需要更底层的语言的支持了,这个就是native的作用
- 学习来自于西安加中实训