1、集合回顾
ArrayList 类
void add(int index, E element) 在此列表中的指定位置插入指定元素
boolean add(E e) 将指定的元素附加到此列表的末尾。
E get(int index) 返回此列表中指定位置的元素。
E remove(int index) 移除此列表中指定位置的元素。
boolean remove(Object o) 从此列表中删除第一次出现的指定元素(如果存在)。
E set(int index, E element) 用指定的元素替换此列表中指定位置的元素。
int size() 返回此列表中的元素数。
2、集合进阶
2.1、Collection是单例集合的顶层接口,它表示一组对象,这些对象被称为Collection元素,JDK不提供此接口的任何直接实现,它提供更加具体的子接口Set和List实现。创建Collection集合的对象采用多态的方式、具体实现类ArrayList。
2.2、Collection集合常用的方法:
boolean add(E e) 确保此集合包含指定的元素(可选操作)。
void clear() 从此集合中删除所有元素(可选操作)。
boolean contains(Object o) 返回true此集合是否包含指定的元素。
boolean isEmpty() true如果此集合不包含元素,则返回。
int size() 返回此集合中的元素数。
Iterator iterator() 返回此集合中元素的迭代器。
iterator常用的方法:
E next() 返回迭代中的下一个元素。
boolean hasNext() true如果迭代有更多元素,则返回。
public static void main(String[] args) {
Collection<String> ct = new ArrayList<String>();
ct.add("hello");
ct.add("java");
ct.add("javase");
ct.add("javaee");
System.out.println(ct.contains("hello"));//判断集合中是否有这个元素
//Iterator<E> iterator() 返回此集合中元素的迭代器。
Iterator<String> it = ct.iterator();//Iterator<E> iterator() 返回此集合中元素的迭代器。
while (it.hasNext()){//boolean hasNext() true如果迭代有更多元素,则返回
String s = it.next();//E next() 返回迭代中的下一个元素。
System.out.println(s);
}
}
2.3 List集合
什么是List集合?
是有序集合(也被称为序列) 用户可以精确控制每个元素在列表中的插入位置。用户可以通过它们的整数索引(在列表中的位置)访问元素,并在列表中搜索元素。与set集合不同,列表通常允许重复元素。
List集合特点:可重复,有序
List集合特有的方法:
void add(int index, E element) 在此列表中的指定位置插入指定元素(可选操作)。
E set(int index, E element) 用指定的元素替换此列表中指定位置的元素(可选操作)。
E remove(int index) 移除此列表中指定位置的元素(可选操作)。返回被删除元素
public static void main(String[] args) {
List<String> list=new ArrayList<>();
//void add(int index, E element) 在此列表中的指定位置插入指定元素(可选操作)。
list.add("Java");
list.add("JavaEE");
list.add("JavaSE");
//E set(int index, E element) 用指定的元素替换此列表中指定位置的元素(可选操作)。
list.set(1,"I");
//E remove(int index) 移除此列表中指定位置的元素(可选操作)。返回被删除元素
list.remove(0);
//迭代器遍历
Iterator<String> it = list.iterator();
while (it.hasNext()){
String s=it.next();
System.out.println(s);
}
}
并发修改异常:ConcurrentModificationException
出现原因:当不允许此类修改时,检测到对象的并发修改的方法可能会抛出此异常。在使用next方法时会检测集合实际修改次数和预期修改次数ArrayList.this.modCount != this.expectedModCount。调用add方法时会使得modCount++导致两者不相等抛出ConcurrentModificationException异常。
while (it.hasNext()){
String s=it.next();
if(s.equals("Java")){
list.add("java");
}
}
修改方法:遍历方式改为for循环,使用get方法获取集合元素。
for (int i=0;i<list.size();i++){
String s = list.get(i);
if(s.equals("Java")){
list.add("java");
}
}
列表迭代器:List.listIterator()创建一个列表迭代器。
void add(E e)将指定的元素插入列表(可选操作)。不会发生并发异常
while (lit.hasNext()){
String s=lit.next();
if(s.equals("Java")){
lit.add("java");//void add(E e)将指定的元素插入列表(可选操作)。不会发生并发异常
}
}
System.out.println(list);
增强for循环
目的:简化数组和Collection集合的遍历
增强的格式
for(元素数据类型 变量名:数组或Collection集合){
元素就是变量名
}
LinkedList集合:
LinkedList同时实现了List接口和Deque接口,也就是收它既可以看作一个顺序容器,又可以看作一个队列(Queue),同时又可以看作一个栈(stack)
LinkedList特有的方法:
void addFirst(E e) 在此列表的开头插入指定的元素。
void addLast(E e) 将指定的元素附加到此列表的末尾。
E getFirst() 返回此列表中的第一个元素。
E getLast() 返回此列表中的最后一个元素。
E removeFirst() 移除并返回此列表中的第一个元素。
E removeLast() 从此列表中删除并返回最后一个元素。
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<String>();
list.add("hello");
list.add("java");
//void addFirst(E e) 在此列表的开头插入指定的元素。
list.addFirst("JavaSE");
// void addLast(E e) 将指定的元素附加到此列表的末尾。
list.addLast("JavaEE");
// E getFirst() 返回此列表中的第一个元素。
String lf = list.getFirst();
System.out.println("列表中第一个元素是:"+lf);
// E getLast() 返回此列表中的最后一个元素。
String ll = list.getLast();
System.out.println("列表中最后一个元素是:"+ll);
System.out.println(list);
System.out.println("--------");
// E removeFirst() 移除并返回此列表中的第一个元素。
String lrm = list.removeFirst();
System.out.println("列表中被删除的第一个元素是:"+lrm);
// E removeLast() 从此列表中删除并返回最后一个元素。
String llm = list.removeLast();
System.out.println("列表中被删除的最后一个元素是:"+llm);
System.out.println(list);
}
3、Set集合
3.1、Set集合的特点:不包含重复元素的集合、没有带索引的方法所以不能使用普通遍历
3.1、哈希值:是JDK根据地址或字符串或数值计算出来的int类型的数值
public static void main(String[] args) {
//int hashCode()
//Returns a hash code value for the object.
Student student = new Student();
Student student1 = new Student();
//默认情况下不同对象的哈希值是不同的
//通过方法重写,可以实现不同对象的哈希值相同
System.out.println(student.hashCode());//764977973
System.out.println(student.hashCode());//764977973
System.out.println(student1.hashCode());//381259350
System.out.println("hello".hashCode());//99162322
System.out.println("word".hashCode());//3655434
System.out.println("天才".hashCode());//732740
System.out.println("神仙".hashCode());//983355
}
3.3、HashSet集合
底层数据结构是哈希表、对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的顺序一致、没有带索引的方法,所以不能使用普通for循环遍历、由于是Set集合,所以不包含重复元素的集合
public static void main(String[] args) {
HashSet<String> hash = new HashSet<>();
hash.add("Java");
hash.add("wrold");
hash.add("JavaSE");
for (String hashSet:hash){
System.out.println(hashSet);//不保证存储和取出的数据一致
}
}
HashSet练习:要求集合添加学生对象,统一名称视为同一个对象
public static void main(String[] args) {
HashSet<Student> hash = new HashSet<>();
Student s1 = new Student("张三", 20);
Student s2 = new Student("李四", 20);
Student s3 = new Student("王五", 20);
Student s4 = new Student("王五", 20);
hash.add(s1);
hash.add(s2);
hash.add(s3);
hash.add(s4);
for (Student hashs:hash){
System.out.println(hashs);
}
}
这里我们需要在student类中重写hashCode()和equals()方法
3.4、LinkedHashSet集合
1、哈希表和链表实现Set接口具有可预测的迭代性
2、链表保证元素的有序
3、哈希表保证元素的唯一
public static void main(String[] args) {
LinkedHashSet<String> hash = new LinkedHashSet<>();
hash.add("Java");
hash.add("JavaSE");
hash.add("JavaEE");
for (String hashs:hash){
System.out.println(hashs);
}
}
3.5、TreeSet集合
1、元素不重复
2、排序根据构造方法来:无参构造函数进行自然排序,带参构造函数根据参数排序接口
3、没有索引,不能使用普通for循环遍历
//TreeSet()
//构造一个新的空树集,根据其元素的自然顺序排序。
TreeSet<Integer> ts = new TreeSet<>();
ts.add(10);
ts.add(12);
ts.add(13);
ts.add(20);
ts.add(23);
ts.add(33);
for (Integer i:ts){
System.out.print(i);//101213202333
}
//TreeSet(Comparator<? super E> comparator)
//构造一个新的空树集,根据指定的比较器进行排序。
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num=s1.getAge()-s2.getAge();
int num2= num==0?s1.getName().compareTo(s2.getName()):num;
return num2;
}
});
Student s1 = new Student("zhangsan",20);
Student s2 = new Student("lisi",30);
Student s3 = new Student("wangwu",23);
Student s4 = new Student("erniu",20);
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
for (Student i:ts){
System.out.println(i);
}
练习:存储学生对象并遍历,创建TreeSet集合使用无参构造方法;要求:按照年龄大小进行排序,年龄相同则按照姓名的字母数序排序。
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<>();
Student s1 = new Student("zhangsan",20);
Student s2 = new Student("lisi",30);
Student s3 = new Student("wangwu",23);
Student s4 = new Student("erniu",20);
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
for (Student i:ts){
System.out.println(i);
}
}
需要Student类实现Comparable 接口,重写public int compareTo(Student s)方法。方法内容为排序规则
@Override
public int compareTo(Student s) {
// return 0;//只会添加一个进集合
// return 1;//按存储顺序添加进集合
// return -1;//按存储顺序倒序添加进集合
int num=this.age-s.age;//按照年龄大小升序排列
// int num=s.age-this.age;//按照年龄大小降序排列
int num2= num==0?this.name.compareTo(s.name):num;
return num2;
}
练习:
public static void main(String[] args) {
/*
* 练习:创建一个set集合
* 创建一个随机数
* 随机数在0-20
* 存入set集合
* 遍历,随机数不重复
* */
// HashSet<Integer> s = new HashSet<>();
TreeSet<Integer> s = new TreeSet<>();
Random r = new Random();
while (s.size()<10){
int number = r.nextInt(20)+1;
s.add(number);
}
for (Integer i:s){
System.out.println(i);
}
}
4、泛型
泛型定义:泛型是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型。它的本质是参数化类型
泛型好处:把运行时期的问题提前到了编译期间、避免了强制类型转换
泛型类:
泛型类的定义格式:
修饰符 class 类名<类型>{}
泛型方法:
泛型方法的定义格式:
修饰符<类型>返回值类型方法名(类型 变量名){}
泛型接口:
泛型接口的定义格式:
修饰符 interface 接口名<类型>{}
public class test10 {
public static void main(String[] args) {
/*
* 泛型类测试
* */
// A<String> a1 = new A<>();
// a1.setT("张三");
// System.out.println(a1.getT());
// A<Integer> a2 = new A<>();
// a2.setT(123);
// System.out.println(a2.getT());
/*
* 泛型方法测试
* */
// B b = new B();
// b.show(123);
// b.show("zsls");
// b.show(true);
/*
* 泛型接口测试
* */
// A<String> s1 = new A<>();
// s1.show("张三");
// A<Integer> s2 = new A<>();
// s2.show(123);
}
}
class A<T> implements c<T>{
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
@Override
public void show(T t) {
System.out.println(t);
}
}
class B{
public <T> void show(T t){
System.out.println(t);
}
}
interface c<T>{
void show(T t);
}
类型通配符:<?>可以任何一种类型;<?extends 类型> 类型上限;<? super 类型>类型下限
可变参数
格式: 修饰符 返回值类型 方法名(类型…变量名){}
注意事项:可变参数应当放在后面例如 public static int sum(int b,int…a){},可变参数其实是一个数组
可变参数的使用:Arrays类、List接口、Set接口
public static void main(String[] args) {
//Arrays中有一个静态的方法 static <T> List<T> asList(T... a)返回由指定数组支持的固定大小列表。
// List<String> list = Arrays.asList("hello","java");
// list.add("javaSE");//UnsupportedOperationException
//List接口中有一个静态的方法 static <E> List<E> of(E... elements)返回包含任意数量元素的不可修改列表。
// List<String> list = List.of("1", "Java", "world");
// list.add("javaSE");//UnsupportedOperationException
//Set接口中有一个静态的方法 static <E> Set<E> of(E... elements)返回包含任意数量元素的不可修改集合。
// Set<String> list = Set.of("1", "Java", "world");
// list.add("javaSE");//UnsupportedOperationException
// System.out.println(list);
}
5 、Map集合
Map集合类似与Python的字典,存储的是键值对对象。Map不能包含重复的键;每个键最多可以映射到一个值。
Map基本功能如代码所示:
public static void main(String[] args) {
/*
* Map集合的基本功能
* */
Map<String, String> map = new HashMap<>();
//V put(K key, V value) 将指定值与此映射中的指定键相关联(可选操作)。
map.put("1802076","软件工程6班");
map.put("1802075","软件工程5班");
map.put("1802074","软件工程4班");
map.put("1802073","软件工程3班");
// System.out.println(map);
//V remove(Object key) 如果存在,则从此映射中删除键的映射(可选操作)。返回值为值
// System.out.println(map.remove("1802076"));
//int size()返回此映射中键值映射的数量。
// System.out.println(map.size());
//boolean containsKey(Object key)返回true此映射是否包含指定键的映射。
//boolean containsValue(Object value)返回true此映射是否将一个或多个键映射到指定值。
// System.out.println(map.containsKey("1802076"));//true
// System.out.println(map.containsKey("1802071"));//false
//void clear()从此映射中删除所有映射(可选操作)。
// map.clear();
//boolean isEmpty()返回true如果此映射不包含键-值映射关系。
// System.out.println(map.isEmpty());//false
/*
*Map的获取功能
* */
//V get(Object key)返回指定键映射到的值,或者null如果此映射不包含键的映射。
// System.out.println(map.get("1802076"));
// System.out.println(map.get("1802071"));
//Set<K> keySet() 返回Set此映射中包含的键的视图。
// System.out.println(map.keySet());
//Collection<V> values()返回Collection此映射中包含的值的视图。
// System.out.println(map.values());
/*
* Map集合的遍历方式1
* 1、通过键获取值
* 2、通过增强for循环来遍历
* */
Set<String> keySets = map.keySet();
for (String key:keySets){
System.out.println(key+"="+map.get(key));
}
/*
* Map集合的遍历方式2
* 1、直接获取键值对对象
* 2、通过增强for循环遍历
* */
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String,String> entry:entries){
System.out.println(entry);
}
练习:
键存储student类,值为String类,如果键里面对象内容一样则判断是同一个键,将值修改为最新的值
需要在student类中重写hasCode()和equals()方法。
HashMap<Student, String> hm = new HashMap<>();
Student s1 = new Student("刘备", 30,"蜀国");
Student s2 = new Student("黄盖", 40,"东吴");
Student s3 = new Student("周瑜", 27,"东吴");
Student s4 = new Student("小乔", 24,"东吴");
Student s5 = new Student("小乔", 24,"东吴");
hm.put(s1,"蜀国");
hm.put(s2,"东吴");
hm.put(s3,"东吴");
hm.put(s4,"东吴");
hm.put(s5,"大汉");
Set<Map.Entry<Student, String>> entries = hm.entrySet();
for (Map.Entry<Student, String> entry:entries){
String value = entry.getValue();
System.out.println(entry.getKey().name+"来自"+value);
}
/*
* 练习:
* 统计字符串中每个字符出现的次数
* 需求:键盘录入一串字符,要求统计字符串中字符出现的次数
* 例:aaabbbbccc 输出a(3)b(4)c(3)
* */
Scanner scanner = new Scanner(System.in);
HashMap<Character, Integer> hm = new HashMap<>();
String line = scanner.nextLine();
for (int i = 0; i < line.length(); i++) {
char key = line.charAt(i);
Integer value = 1;
if (hm.get(key) == null) {
hm.put(key, value);
} else {
value=hm.get(key)+1;
hm.put(key, value);
}
}
Set<Character> keySet = hm.keySet();
for (Character keyset:keySet){
System.out.println(keyset+"("+hm.get(keyset)+")");
}
6、Collections
是针对集合的操作类
有以下几种常用的方法
public static void main(String[] args) {
// List list = new ArrayList();
// list.add(10);
// list.add(30);
// list.add(40);
// list.add(50);
// list.add(60);
// list.add(40);
//static void shuffle(List<?> list)
//使用默认的随机源随机排列指定的列表。
// Collections.shuffle(list);
//static <T extends Comparable<? super T>>
//void sort(List<T> list)
//根据其元素的自然顺序,将指定列表按升序 排序。
// Collections.sort(list);
//static void reverse(List<?> list)
//反转指定列表中元素的顺序。
// Collections.reverse(list);
// System.out.println(list);
- 练习:
* 使用ArrayList存储学生对象,使用Collections对ArrayList排序
* 要求:年龄从小到大排序,年龄相同,按照姓名字母排序
/*
* 练习:
* 使用ArrayList存储学生对象,使用Collections对ArrayList排序
* 要求:年龄从小到大排序,年龄相同,按照姓名字母排序
* */
Student s1 = new Student("zhangsan", 20);
Student s2 = new Student("zhangsan", 30);
Student s4 = new Student("zhangsan", 230);
Student s3 = new Student("lisi", 20);
ArrayList<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num=s1.age-s2.age;
int num2=s1.getName().compareTo(s2.getName());
return num2;
}
});
for (Student s:list){
System.out.println(s.getName()+":"+s.age);
}
}