java从零开始系统性学习完整超全资源+笔记(下)
java从零开始系统性学习完整超全资源+笔记(上)
文章目录
- java从零开始系统性学习完整超全资源+笔记(下)
- 第十七章 泛型与常见数据结构
- ArrayList
- Collection接口的实现
- 泛型 generics
- 迭代器Iterator
- foreach
- 常见的数据结构
- 数组
- 链表
- 栈和队列
- List
- LinkedList
- 案例 查找元素索引及判断元素是否存在案例
- 练习
- 第十八章 Set与Map集合
- Set
- 增强for循环
- hashSet
- 方法重载与重写
- hashCode方法和equals方法的优化
- Collection
- 定义
- Collection和Collections有什么区别?
- collection方法
- Collection练习 模拟斗地主
- Map
- Map和Collection有什么区别?
- map常用功能
- map的两种遍历方式
- Map的第二种遍历方式
- 使用HashMap存储数据并遍历(字符串作为key)
- 使用HashMap存储数据并遍历(自定义对象作为key)
- 异常的处理
- 异常的概述和体系结构.
- JVM处理异常的方式
- 如何处理多个异常
- Throwable的常用方法
- finally概述和应用场景
- 异常的分类
- 自定义异常
- 递归概述和例题
第十七章 泛型与常见数据结构
ArrayList
集合的体系结构:
由于不同的数据结构(数据的组织,存储方式),所以Java为我们提供了不同的集合,
但是不同的集合他们的功能都是相似,不断的向上提取,将共性抽取出来,这就是集合体系结构形成的原因
体系结构:
怎么学习?最顶层开始学习,因为最顶层包含了所有的共性
怎么使用?使用最底层,因为最底层就是具体的实现
Collection
List
ArrayList
package com.demo01;
import java.util.ArrayList;
/*
* ArrayList
* 集合的体系结构:
* 由于不同的数据结构(数据的组织,存储方式),所以Java为我们提供了不同的集合,
* 但是不同的集合他们的功能都是相似,不断的向上提取,将共性抽取出来,这就是集合体系结构形成的原因
*
* 体系结构:
* 怎么学习?最顶层开始学习,因为最顶层包含了所有的共性
* 怎么使用?使用最底层,因为最底层就是具体的实现
*
* Collection
* List
* ArrayList
*/
public class CollectionDemo {
public static void main(String[] args) {
//创建集合对象
ArrayList al = new ArrayList();
//添加元素
al.add("hello");
al.add("world");
al.add("java");
//遍历集合
for(int x = 0;x < al.size();x++) {
System.out.println(al.get(x));
}
}
}
Collection接口的实现
Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接 实现:**它提供更具体的子接口(如 Set 和 List)**实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。
/*
* Collection接口的实现
* boolean add(E e) 确保此 collection 包含指定的元素(可选操作)。
* void clear() 移除此 collection 中的所有元素(可选操作)。
* boolean contains(Object o) 如果此 collection 包含指定的元素,则返回 true。
* boolean isEmpty() 如果此 collection 不包含元素,则返回 true。
* boolean remove(Object o) 从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。
* int size() 返回此 collection 中的元素数。
* Object[] toArray() 返回包含此 collection 中所有元素的数组。
* 如果此 collection 包含指定的元素,则返回 true。更确切地讲,当且仅当此 collection 至少包含一个满足 (o==null ? e==null : o.equals(e)) 的元素 e 时,返回 true。
*/
package CollectionDemo;
import java.util.ArrayList;
import java.util.Objects;
public class ArrayListDemo2 {
public static void main(String[] args) {
ArrayList a = new ArrayList();
// 1.boolean add(E e)
a.add("hello1"); //add的时候运行没有东西,必须打印出来才有
a.add("hello2");
// 2.void clear()
// a.clear();
for(int i = 0;i<a.size();i++){
System.out.println(a.get(i));
}
// 3.boolean contains(Object o)
boolean flag = a.contains("hello1"); //包含就返回true
System.out.println(flag);
System.out.println(a);
// boolean isEmpty()
boolean flag1 = false;
if(a!=null&&a.isEmpty()){
flag1 = true;
System.out.println(flag);
}
// boolean remove(Object o)
boolean f = a.remove("hello1");
System.out.println(f);
System.out.println(a);
int size = a.size();
System.out.println(size);
// Object[] toArray()
Object[] objects = a.toArray();
for(int i = 0;i< objects.length;i++){
System.out.println(objects[i]);
}
}
}
泛型 generics
使用集合存储自定义对象并遍历
* 由于集合可以存储任意类型的对象,当我们存储了不同类型的对象,就有可能在转换的时候出现类型转换异常,
* 所以java为了解决这个问题,给我们提供了一种机制,叫做泛型
*
* 泛型:是一种广泛的类型,把明确数据类型的工作提前到了编译时期,借鉴了数组的特点
* 泛型好处:
* 避免了类型转换的问题
* 可以减少黄色警告线
* 可以简化我们代码的书写 不用强制类型转换
*
* 什么时候可以使用泛型?
* 问API,当我们看到<E>,就可以使用泛型了
List ArrayList Collection 等都可以用泛型
使用泛型的缺点
虽然泛型在很多情况下能够提供强类型检查和代码重用的好处,但它们也有一些缺点,包括以下几点:
**增加代码复杂性**:泛型代码通常比非泛型代码更复杂,因为它需要在类型安全的同时支持多种数据类型。这可能导致代码更难理解和维护。
**增加编译时间**:泛型代码通常需要更多的编译时间,因为编译器必须在编译时生成并检查泛型类型的代码。这可能会导致较长的编译时间,特别是在使用大量泛型的大型项目中。
受限于类型擦除:在 Java 中,泛型类型信息在编译时被擦除,这意味着在运行时无法访问泛型类型的信息。这可以导致一些类型转换和类型安全问题,尤其是在处理复杂的泛型类型时。
需要额外的学习和使用成本:泛型是一种相对较新的编程技术,因此需要额外的学习成本。此外,对于一些简单的应用程序,使用泛型可能是过度设计,这可能会增加使用成本和复杂性。
综上所述,泛型的使用虽然有很多好处,但也需要仔细考虑其使用场景和实际需求,以平衡其优点和缺点。
例如
package CollectionDemo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*泛型概述
使用集合可以存储任意类型的对象,由于存储了不同类型的对象,有可能在转换的时候
出现类型转换异常。所以java为了解决这个问题,提供了一种机制generic泛型
泛型:是一种广泛的类型,把明确数据类型的工作提前到了编译时期,借鉴了数组的特点
泛型的好处:
避免类型转换的问题
可以减少黄色警告线
简化代码书写 不用强制类型转换
什么时候用泛型?
问API,当我们看到<E>就可以使用泛型
List ArrayList Collection等都可以用泛型
*/
public class GenericDemo {
public static void main(String[] args) {
/*
// 不知道集合里面的类型是什么,所以用泛型解决这个问题
// Iterator 是一个接口,用于遍历集合(如 List、Set、Map 等)中的元素
Collection c = new ArrayList();
c.add("hello");
Iterator iterator = c.iterator();
int i = (int) iterator.next();
System.out.println(i);
//出现异常 java.lang.String cannot be cast to java.lang.Integer
*/
// 创建集合对象
Collection<Student> c = new ArrayList<Student>();
// 创建元素对象
Student s1 = new Student("zhangsan1",13);
Student s2 = new Student("zhangsan2",16);
// 添加元素对象
c.add(s1);
c.add(s2);
// 遍历元素对象
Iterator<Student> it = c.iterator();
while (it.hasNext()){
Student stu = it.next();
System.out.println(stu.name);
}
}
static class Student{
String name;
int age;
public Student(String name,int age){
this.name = name;
this.age = age;
}
}
}
package com.demo03;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*
* 使用集合存储自定义对象并遍历
* 由于集合可以存储任意类型的对象,当我们存储了不同类型的对象,就有可能在转换的时候出现类型转换异常,
* 所以java为了解决这个问题,给我们提供了一种机制,叫做泛型
*
* 泛型:是一种广泛的类型,把明确数据类型的工作提前到了编译时期,借鉴了数组的特点
* 泛型好处:
* 避免了类型转换的问题
* 可以减少黄色警告线
* 可以简化我们代码的书写 不用强制类型转换
*
* 什么时候可以使用泛型?
* 问API,当我们看到<E>,就可以使用泛型了
List ArrayList都可以用泛型
*
*/
public class GenericDemo {
public static void main(String[] args) {
/* Collection<String> c = new ArrayList<String>();
c.add("Hello");
Iterator iterator = c.iterator();
int i = (int) iterator.next();
System.out.println(i);
*/
//String[] s =new String[3];
//创建集合对象
Collection<Student> c = new ArrayList<Student>();
//创建元素对象
Student s = new Student("zhangsan",18);
Student s2 = new Student("lisi",19);
//添加元素对象
c.add(s);
c.add(s2);
//遍历集合对象
Iterator<Student> it = c.iterator();
while(it.hasNext()) {
Student stu = it.next();
System.out.println(stu.name);
}
}
}
class Student {
String name;
int age;
public Student(String name,int age) {
this.name = name;
this.age = age;
}
}
迭代器Iterator
chatGPT回答
在 Java 中,Iterator 是一个接口,用于**遍历集合(如 List、Set、Map 等)中的元素**。Iterator 接口定义了访问和移除集合中元素的方法,可以帮助开发者逐个访问集合中的元素,而不需要暴露底层数据结构的实现细节。
Iterator 接口包含以下几个方法:
hasNext():返回集合中是否还有下一个元素。
next():返回下一个元素。
remove():从集合中移除上一次返回的元素(可选操作)。
使用 Iterator 遍历集合的基本流程是:首先通过集合对象的 iterator() 方法获得 Iterator 实例,然后通过调用 hasNext() 和 next() 方法逐个访问集合中的元素,最后使用 remove() 方法删除元素(如果需要)。
Iterator 接口的出现使得遍历集合变得更加方便和灵活,同时也提高了代码的可读性和可维护性。
在使用迭代器进行遍历的时候使用迭代器来进行修改
iterator() 可以返回一个迭代器对象,我们可以通过迭代器对象来迭代集合
- Iterator:可用于遍历集合
- E next()返回下一个元素
- boolean hasNext():判断元素是否可以获取
package CollectionDemo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
/*
* 集合的遍历方式
* 1.toArray() 可以将集合转化成数组,然后遍历数组即可
* 2.iterator() 可以返回一个迭代器对象,我们可以通过迭代器对象来迭代集合
* Iterator:可用于遍历集合
* E next()返回下一个元素
* boolean hasNext():判断元素是否可以获取
* 注意:Exception in thread "main" java.util.NoSuchElementException
* 使用next方法获取下一个元素,如果没有元素可以获取,则出现NoSuchElementException
* */
public class IteratorDemo1 {
public static void main(String[] args) {
// 创建集合对象
Collection c = new ArrayList();
// 添加元素
c.add("hello1");
c.add("hello2");
// 获取数组
Object[] objs = c.toArray();
// 遍历数组
for (int i = 0; i < objs.length; i++) {
System.out.println(objs[i]);
}
}
}
/*运行结果
hello1
hello2
*/
package CollectionDemo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo2 {
public static void main(String[] args) {
//创建集合对象
Collection c = new ArrayList();
//添加元素
c.add("hello1");
c.add("hello2");
// 获取迭代器对象
Iterator it = c.iterator();
// Object next():返回下一个元素
/* System.out.println(it.next());
System.out.println(it.next());
// 输出hello1,hello2
*/
// boolean hasNext():判断是否有元素可以获取
/* if(it.hasNext()){
System.out.println(it.next());
} //输出hello1*/
while (it.hasNext()){
System.out.println(it.next());
} //输出 hello1 hello2
}
}
package CollectionDemo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/*需求:判断集合中是否包含元素java,如果有则添加元素android
Exception in thread "main" java.util.ConcurrentModificationException:并发修改异常
迭代器是依赖集合的,相当于集合的一个副本,当迭代器在操作的时候如果发现和迭代器不一样就抛出异常
解决方案:
别使用迭代器
在使用迭代器进行遍历的时候使用迭代器来进行修改
* */
public class IteratorDemo3 {
public static void main(S,,,,,,,,,,,,,,,tring[] args) {
// 创建集合对象
List c = new ArrayList();
// 添加元素
c.add("hello1");
c.add("hello2");
c.add("java");
System.out.println(c);
// 通过遍历集合中的每一个元素来比较判断是否包含java
/* Iterator it = c.iterator();
while (it.hasNext()){
String s = (String) it.next();
if(s.equals("java")){
c.add("android");
}
}
System.out.println(c);
Exception in thread "main" java.util.ConcurrentModificationException:并发修改异常
迭代器是依赖集合的,相当于集合的一个副本,当迭代器在操作的时候如果发现和迭代器不一样就抛出异常
*/
ListIterator lit = c.listIterator();
while (lit.hasNext()){
String s =(String)lit.next();
if(s.equals("java")){
lit.add("android"); // 在使用迭代器进行遍历的时候使用迭代器来进行修改
}
}
System.out.println(c);
}
}
foreach
foreach:增强for循环,一般用于遍历集合或者数组
格式:
for(元素的类型 变量 : 集合或者数组对象) {
可以直接使用变量;
}
注意:在增强for循环中不能修改集合,否则会出现并发修改异常,不能进行增减。
public interface Iterable<T>
实现这个接口允许对象成为 "foreach" 语句的目标。
package com.demo04;
import java.util.ArrayList;
import java.util.Collection;
/*
* foreach:增强for循环,一般用于遍历集合或者数组
* 格式:
* for(元素的类型 变量 : 集合或者数组对象) {
* 可以直接使用变量;
* }
注意:在增强for循环中不能修改集合,否则会出现并发修改异常,不能进行增减。
public interface Iterable<T>
实现这个接口允许对象成为 "foreach" 语句的目标。
*/
public class ForEachDemo {
public static void main(String[] args) {
/* //创建集合对象
Collection<String> c = new ArrayList<String>();
//添加元素
c.add("hello");
c.add("world");
c.add("java");
//增强for循环遍历集合
for(Object obj : c) {
System.out.println(obj);
}
for(String s : c) {
s = s.toUpperCase()+"其他的内容";
System.out.println(s);
}
for(String s : c) {
System.out.println(s);
}*/
/*for (String string : c) {
c.add("android");
System.out.println(string);
}*/
Collection<Student> c = new ArrayList<Student>();
c.add(new Student("张三",20));
c.add(new Student("李四",18));
for(Student student:c) {
System.out.println("name:"+student.name+" age:"+student.age);
}
/* for(Student student:c) { 用foreach对集合修改就出现异常 ConcurrentModificationException:并发修改异常
System.out.println("name:"+student.name+" age:"+student.age);
student.name = student.name+"xx";
c.add(new Student("王五",22));
}*/
}
}
class Student {
String name;
int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
结果name:张三 age:20
name:李四 age:18
常见的数据结构
数组
数据结构图
特点:1.长度一旦定义就不能被改变;2.数组中的元素都有整数索引;3.数组只能存储同一数据类型的元素;4.数组既可以存储基本数据类型,也可以存储引用数据类型。
优点:检索快,因为可以通过索引获取数组元素
缺点:增加和删除数据慢,因为需要创建新的数据,效率低。
如何插入新的元素?如[1,2,3,4]3后面插入8。
首先创建一个新的数组,长度是原来的数组长度+1;接着遍历原来的数组并存储到新的数组中,遇到3的时候在它后面添加8,最后将剩下的元素添加到8后面即可。
链表
获取结点:
添加结点:
特点:由链子链接起来的一堆结点,有头结点和尾结点
优点:增加和删除元素快
缺点:查询慢,只能遍历列表一个个看
栈和队列
特点:栈:先进后出(子弹出夹);队列:先进先出。(买火车票进站)
优点:
缺点:
List
定义:List 组件为用户提供了一个可滚动的文本项列表。可设置此 list,使其允许用户进行单项或多项选择。
* List:
* 有序的(存储和读取的顺序是一致的)
* 有整数索引
* 允许重复的
*
* List的特有功能:
* void add(int index, E element) 在列表的指定位置插入指定元素
* E get(int index) 根据索引返回元素
* E remove(int index) 删除指定元素并返回
* E set(int index, E element) 将指定索引位置的元素替换为指定元素,并将原先的元素返回
package CollectionDemo;
import java.util.ArrayList;
import java.util.List;
/*
* List:
* 有序的(存储和读取的顺序是一致的)
* 有整数索引
* 允许重复的
*
* List的特有功能:
* void add(int index, E element)
* E get(int index)
* E remove(int index) 删除指定元素并返回
* E set(int index, E element)
*
* 增删改查
*/
public class ListDemo {
public static void main(String[] args) {
List list =new ArrayList();
// //void add(int index, E element) : 在列表的指定位置插入指定元素
list.add(0,"hello");
list.add(0,"c++");
list.add(1,"java");
System.out.println(list);
// E get(int index) :根据索引返回元素
/*System.out.println(list.get(0));
System.out.println(list.get(1));
System.out.println(list.get(2));
*/
for (int i= 0;i<list.size();i++){
System.out.println(list.get(i));
}
// E remove(int index) : 删除指定元素并返回
System.out.println(list.remove(1));
System.out.println(list);
// 输出 [c++, hello]
// E set(int index, E element) : 将指定索引位置的元素替换为指定元素,并将原先的元素返回
System.out.println(list.set(0,"and"));
System.out.println(list);
// 输出 [and, hello]
}
}
LinkedList
List的常用子类
ArrayList 底层是数组 增删慢,查询快
LinkedList 底层是链表 增删快,查询慢
如何选择使用不同的集合?
如果查询多,增删少,则使用ArrayList
如果查询少,增删多,则使用LinkedList
如果你不知道使用什么,则使用ArrayList
LinkedList的特有功能:
void addFirst(E e)
void addLast(E e)
E getFirst()
E getLast()
E removeFirst()
E removeLast()
package com.demo06;
import java.util.LinkedList;
*/
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<String>();
list.add("hello");
list.add("world");
//void addFirst(E e) :将元素添加到索引为0的位置
//void addLast(E e) :将元素添加到索引为size()-1的位置
//list.addFirst("java");
//list.addLast("android");
//E getFirst() :获取索引为0的元素
//E getLast() :获取索引为size()-1的元素
//System.out.println(list.getFirst());
//System.out.println(list.getLast());
System.out.println(list);
//E removeFirst() :删除索引为0的元素并返回
//E removeLast() :删除索引为size()-1的元素并返回
//System.out.println(list.removeFirst());
System.out.println(list.removeLast());
System.out.println(list);
}
}
package CollectionDemo;
import java.util.LinkedList;
/*
List的常用子类
ArrayList 底层是数组 增删慢,查询快
LinkedList 底层是链表 增删快,查询慢
如何选择使用不同的集合?
如果查询多,增删少,则使用ArrayList
如果查询少,增删多,则使用LinkedList
如果你不知道使用什么,则使用ArrayList
LinkedList的特有功能:
void addFirst(E e)
void addLast(E e)
E getFirst()
E getLast()
E removeFirst()
E removeLast()
*/
public class ListedListDemo {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<String>();
list.add("hello");
list.add("ho");
list.addFirst("h");
list.addLast("yy");
System.out.println(list);
// 运行结果 [h, hello, ho, yy]
System.out.println(list.getFirst()); //h
System.out.println(list.getLast()); //yy
System.out.println(list.removeFirst()); // h删除索引为0的元素并返回
System.out.println(list.removeLast()); //yy
System.out.println(list); //输出[hello, ho]
}
}
案例 查找元素索引及判断元素是否存在案例
package com.demo07;
import java.util.ArrayList;
import java.util.List;
/*
* 需求:定义一个方法,返回指定列表中指定元素的索引位置
*
* 判断元素是否存在
*
*/
public class ListTest {
public static void main(String[] args) {
List list = new ArrayList();
list.add("hello");
list.add("world");
list.add("java");
int index = index(list,"python");
System.out.println(index);
boolean flag = contains(list, "world");
System.out.println(flag); //输出 1
boolean flag1 = list.contains("java");
System.out.println(flag1); // 输出true
}
public static int index(List list,Object other) {
for(int x = 0;x < list.size();x++) {
//获取列表中的元素
Object obj = list.get(x);
//使用列表中的元素和指定的元素进行比较
if(obj.equals(other)) {
return x;
}
}
//查找不到指定的元素
return -1;
}
public static boolean contains(List list,Object other) {
//获取指定元素在指定列表中的索引位置
int index = index(list,other);
//如果索引位置大于等于0,则认为元素存在,否则不存在
if(index >= 0) {
return true;
} else {
return false;
}
}
}
练习
1、
分析以下需求,并用代码实现
(1)生成10个1至100之间的随机整数(不能重复),存入一个List集合
(2)然后利用迭代器和增强for循环分别遍历集合元素并输出
(3)如:15 18 20 40 46 60 65 70 75 91
需求分析:
随机生成10个1至100之间的不重复整数,可以通过使用Java的Random类,生成随机数,再判断是否已经存在于集合中,如果存在则重新生成。
存储生成的随机数可以使用Java的List集合,因为它能够按照插入顺序存储元素。
遍历集合元素可以使用Java的迭代器和增强for循环。迭代器是遍历集合的标准方法,它能够对集合中的元素进行读取、删除和修改操作。增强for循环是一种简化版的迭代器,它可以遍历集合中的元素,但不能进行修改和删除操作。
输出集合元素可以使用Java的System.out.println方法,将每个元素输出到控制台。
import java.util.*;
public class RandomNumbers {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
Random rand = new Random();
// 生成10个1至100之间的不重复整数
while (numbers.size() < 10) {
int n = rand.nextInt(100) + 1;
if (!numbers.contains(n)) {
numbers.add(n);
}
}
// 使用迭代器遍历集合并输出
System.out.print("使用迭代器遍历集合:");
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
int n = iterator.next();
System.out.print(n + " ");
}
System.out.println();
// 使用增强for循环遍历集合并输出
System.out.print("使用增强for循环遍历集合:");
for (int n : numbers) {
System.out.print(n + " ");
}
System.out.println();
}
}
利用迭代器遍历集合并输出
63 82 15 69 9 87 52 92 93 40
利用for增强遍历集合并输出
63 82 15 69 9 87 52 92 93 40
2、
分析以下需求,并用代码实现
(1)定义List集合,存入多个字符串
(2)删除集合元素字符串中包含0-9数字的字符串(只要字符串中包含0-9中的任意一个数字就需要删除此整个字符串)
(3)然后利用迭代器遍历集合元素并输出
package CollectionDemo.Test;
import java.util.*;
import java.util.List;
/*分析以下需求,并用代码实现
(1)定义List集合,存入多个字符串
(2)删除集合元素字符串中包含0-9数字的字符串(只要字符串中包含0-9中的任意一个数字就需要删除此整个字符串)
(3)然后利用迭代器遍历集合元素并输出*/
public class Test2 {
public static void main(String[] args) {
// 定义List集合,存入多个字符串
List<String> list = new ArrayList<>();
list.add("abc");
list.add("efg");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String s = iterator.next();
// (2)删除集合元素字符串中包含0-9数字的字符串(只要字符串中包含0-9中的任意一个数字就需要删除此整个字符串)
if (s.matches(".*[0-9].*")){
iterator.remove();
}
}
// (3)然后利用迭代器遍历集合元素并输出
for (String s:list
) {
System.out.println(s);
}
}
}
abc
efg
分析以下需求,并用代码实现
(1)定义Person类包含姓名:String name、年龄:int age、成绩:int score,生成空参、有参构造、set和get方法、toString方法
(2)定义Student类继承Person,属性与Person类相同
(3)查看API中ArrayList集合中的以下方法:
(a)boolean add(E e) 方法
(b) T[] toArray(T[] a)方法
(c)boolean addAll(Collection<? extends E> c)方法
(4)通过查看API对以上方法的学习,完成以下功能
a. ArrayList集合中存入5个Student对象,将ArrayList集合转成对应的数组Studentp[],并遍历打印数组中的元素
b. 定义一个存储Person对象的ArrayList集合对象list1,并出入2个Person对象,定义一个存储Student对象的ArrayList集合对象list2,并出入2个Student对象,
调用addAll方法将list2的全部内容添加到list1中,遍历打印list1中的内容
package CollectionDemo.Test;
import java.util.ArrayList;
/*分析以下需求,并用代码实现
(1)定义Person类包含姓名:String name、年龄:int age、成绩:int score,生成空参、有参构造、set和get方法、toString方法
(2)定义Student类继承Person,属性与Person类相同
(3)查看API中ArrayList集合中的以下方法:
(a)boolean add(E e) 方法
(b)<T> T[] toArray(T[] a)方法
(c)boolean addAll(Collection<? extends E> c)方法
(4)通过查看API对以上方法的学习,完成以下功能
a. ArrayList集合中存入5个Student对象,将ArrayList集合转成对应的数组Studentp[],并遍历打印数组中的元素
b. 定义一个存储Person对象的ArrayList集合对象list1,并出入2个Person对象,定义一个存储Student对象的ArrayList集合对象list2,并出入2个Student对象,
调用addAll方法将list2的全部内容添加到list1中,遍历打印list1中的内容*/
public class Test3 {
public static void main(String[] args) {
// a. ArrayList集合中存入5个Student对象,将ArrayList集合转成对应的数组Studentp[],并遍历打印数组中的元素
ArrayList<Person.Student> arrayList = new ArrayList<Person.Student>();
arrayList.add(new Person.Student("小结",16,79));
arrayList.add(new Person.Student("小结2",13,45));
//b. 定义一个存储Person对象的ArrayList集合对象list1,并出入2个Person对象,定义一个存储Student对象的ArrayList集合对象
Person.Student[] stu = arrayList.toArray(new Person.Student[arrayList.size()]);
for (Person.Student st:stu
) {
System.out.println(st);
}
}
}
//(1)定义Person类包含姓名:String name、年龄:int age、成绩:int score,生成空参、有参构造、set和get方法、toString方法
class Person{
String name;
int age;
int score;
// 空参构造
public Person() {
}
// 有参构造
public Person(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
//set和get方法
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;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public String toString(){
return "Person{"+"name="+name+'\''+",age="+age+
",score="+score+"}";
}
// (2)定义Student类继承Person,属性与Person类相同
static class Student extends Person{
public Student(String name, int age, int score) {
super(name, age, score);
}
}
}
4.现在已知Cloth ,衣物都有颜色,价格,牌子;
已知裤子是衣物的一种,裤子有裤袋;
已知袜子也是一种,袜子有个洞;
已知衬衣也是衣服的一种,衬衣有扣子;
已知鞋子也是衣物,鞋子有鞋带
已知人这个类, 人类有姓名,性别, 可以穿衣服;
要求: 定义一个衣柜(衣柜不用创建对象, 里面放置一套衣服);
创建人对象,然后实现穿一套衣服的过程;
package CollectionDemo.Test;
/*现在已知Cloth ,衣物都有颜色,价格,牌子;
已知裤子是衣物的一种,裤子有裤袋;
已知袜子也是一种,袜子有个洞;
已知衬衣也是衣服的一种,衬衣有扣子;
已知鞋子也是衣物,鞋子有鞋带
已知人这个类, 人类有姓名,性别, 可以穿衣服;
要求: 定义一个衣柜(衣柜不用创建对象, 里面放置一套衣服);
创建人对象,然后实现穿一套衣服的过程;*/
public class Test4 {
public static void main(String[] args) {
Person1 person1 = new Person1();
person1.name="Mary";
person1.gender = "female";
Wardrobe wardrobe = new Wardrobe();
person1.wear(wardrobe.pants);
person1.wear(wardrobe.socks);
person1.wear(wardrobe.shirt);
person1.wear(wardrobe.shoes);
}
}
class Cloth{
String color;
double price;
String brand;
}
class Pants extends Cloth{
boolean hasPocket; //有口袋
}
class Socks extends Cloth{
boolean hasHole;
}
class Shirt extends Cloth{
boolean hasButton;
}
class Shoes extends Cloth{
boolean hasLaces;
}
class Person1 {
String name;
String gender;
void wear(Cloth cloth) {
System.out.println(name + " is wearing " + cloth.brand + " " + cloth.getClass().getSimpleName() + ".");
}
}
class Wardrobe{
Pants pants = new Pants();
Socks socks = new Socks();
Shirt shirt =new Shirt();
Shoes shoes = new Shoes();
Wardrobe(){
pants.color="blue";
pants.price=36.88;
pants.brand="LOV";
pants.hasPocket=true;
socks.color = "white";
socks.price = 4.99;
socks.brand = "Hanes";
socks.hasHole = true;
shirt.color = "pink";
shirt.price = 39.99;
shirt.brand = "Ralph Lauren";
shirt.hasButton = true;
shoes.color = "black";
shoes.price = 79.99;
shoes.brand = "Nike";
shoes.hasLaces = true;
}
}
Mary is wearing LOV Pants.
Mary is wearing Hanes Socks.
Mary is wearing Ralph Lauren Shirt.
Mary is wearing Nike Shoes.
键盘录入若干个字符串,将字符串存入泛型为String的集合当中, 知道输入quit的时候不用输入;
1.集合中含有字符a的元素有多少个
2.将集合中第三个元素中"a"全部替换成"b";
3.删掉长度为3的元素;
4.遍历集合;
package CollectionDemo.Test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;
/*键盘录入若干个字符串,将字符串存入泛型为String的集合当中, 直到输入quit的时候不用输入;
1.集合中含有字符a的元素有多少个
2.将集合中第三个元素中"a"全部替换成"b";
3.删掉长度为3的元素;
4.遍历集合;*/
public class Test5 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
ArrayList<String> stringList = new ArrayList<>(); // 创建泛型为String的ArrayList
System.out.println("请输入字符串(输入quit结束输入):");
// 用循环读取用户输入的字符串并存入ArrayList,直到输入"quit"为止
while (true) {
String input = scanner.nextLine();
if (input.equals("quit")) {
break;
} else {
stringList.add(input);
}
}
// 打印集合中含有字符a的元素数量
int count = 0;
for (String str : stringList) {
if (str.contains("a")) {
count++;
}
}
System.out.println("集合中含有字符a的元素数量为:" + count);
// 将集合中第三个元素中"a"全部替换成"b"
if (stringList.size() >= 3) { // 确保集合中至少有3个元素
String thirdElement = stringList.get(2);
stringList.set(2, thirdElement.replace("a", "b"));
}
// 删除长度为3的元素
stringList.removeIf(str -> str.length() == 3);
// 遍历集合并打印每个元素
System.out.println("遍历集合:");
for (String str : stringList) {
System.out.println(str);
}
}
}
请输入字符串(输入quit结束输入):
sdha
jkhg
ghsa
quit
集合中含有字符a的元素数量为:2
遍历集合:
sdha
jkhg
ghsb
第十八章 Set与Map集合
Set
- 定义
在Java中,Set是一种集合类型,它继承自Collection接口,用于存储不重复的元素。Set接口的定义如下:
public interface Set<E> extends Collection<E> {
// 声明Set特有的方法
}
常用的Set实现类有HashSet、TreeSet和LinkedHashSet。
需要注意的是,Set接口是一个抽象接口,不能直接实例化。需要使用Set接口的实现类来创建Set对象。
- 特点
- 无序
- 不重复
- 没有整数索引
- 方法
add() toArray()
增强for循环
增强for循环语法(也称为for-each循环)是Java中用于遍历数组或集合的简化循环语法。其语法形式如下:
for (elementType element : collection) {
// 循环体
}
其中:
elementType 是集合中元素的类型,也可以是数组的元素类型。
element 是循环变量,用于在每次循环迭代中代表集合中的一个元素。
collection 是要遍历的集合或数组。
增强for循环的工作原理是自动迭代集合或数组,并将每个元素依次赋值给循环变量,然后执行循环体中的代码。循环将在集合或数组中的每个元素上执行一次,直到所有元素都被遍历完为止。
需要注意的是,增强for循环只能用于遍历集合或数组,无法用于遍历其他数据结构或自定义对象。
使用HashSet存储字符串并遍历
package mySet;
import java.util.HashSet;
import java.util.Set;
/*使用HashSet存储字符串并遍历
*
* Set的特点:
* 无序(存储和读取的顺序可能不一样)
* 不允许重复
* 没有整数索引*/
public class hashSetDemo1 {
public static void main(String[] args) {
// 创建集合
Set<String> set = new HashSet<>(); //必须要是泛型的
// 添加元素
set.add("hello");
set.add("world");
set.add(null);
System.out.println(set.add("java"));
System.out.println(set.add("java")); //不允许有重复的元素,所以值输出一个java
// 遍历元素
for(String s : set){
System.out.println(s);
}
}
}
输出
true
false
null
world
java
hello
为啥输出了true和false?
这段代码输出了"true"和"false",以及集合中的元素。
首先,让我们逐行分析代码的执行:
创建HashSet对象并将其赋值给set变量:Set set = new HashSet<>();
创建一个名为set的HashSet集合,其中存储的元素类型为String。
添加元素到集合中:
set.add(“hello”);:向集合中添加字符串"hello"。
set.add(“world”);:向集合中添加字符串"world"。
set.add(null);:向集合中添加一个null元素。
System.out.println(set.add(“java”));:向集合中添加字符串"java",并输出add方法的返回值。因为集合中原本没有"java"这个元素,所以添加成功,返回true,因此输出为"true"。
System.out.println(set.add(“java”));:再次向集合中添加字符串"java",并输出add方法的返回值。因为集合中已经存在"java"这个元素,添加失败,返回false,因此输出为"false"。
遍历集合中的元素:
使用增强for循环遍历集合中的元素。
for(String s : set){…}:对于集合中的每个元素,将其赋值给变量s,并执行循环体中的代码。
循环体中的代码System.out.println(s);将每个元素打印到控制台。
hashSet
-
定义
HashSet实现了Set接口,并且还继承了AbstractSet类,同时也实现了Cloneable接口和Serializable接口。它使用哈希表来存储元素,并且允许存储null元素(只能存储一个)。
-
特点
- 不允许重复元素:HashSet中不会包含重复的元素。当向HashSet中添加元素时,会先通过元素的hashCode()方法计算哈希值,然后根据哈希值确定元素在内部存储结构中的位置。如果发现该位置已经存在元素,则进行比较,如果元素已经存在,则不会添加;如果元素不存在,则将其添加到该位置。
- 无序性:HashSet中的元素没有特定的顺序。HashSet不会保持元素的插入顺序,也不会按照元素的排序顺序存储。
- 高效的查找和插入操作:HashSet基于哈希表实现,因此查找和插入操作的性能非常高效,具有常数时间复杂度O(1)。
可以存储null元素:HashSet可以存储一个null元素,但不能存储多个null元素,因为HashSet要求元素唯一。 - 不是线程安全的:HashSet不是线程安全的,如果多个线程同时访问一个HashSet并且至少有一个线程修改了集合,则必须进行外部同步。
遍历性能较好:由于HashSet使用哈希表实现,遍历HashSet的性能较好。
注意:由于HashSet使用哈希表实现,元素的顺序是根据哈希值决定的,因此无法保证HashSet的元素顺序是固定的。如果需要有序的集合,可以使用LinkedHashSet类,它在HashSet的基础上使用了链表来维护元素的插入顺序。
-
add()
HashSet的add()方法,首先会使用当前集合中的每一个元素和新添加的元素进行hash值比较,
如果hash值不一样,则直接添加新的元素
如果hash值一样,比较地址值或者使用equals方法进行比较
比较结果一样,则认为是重复不添加
所有的比较结果都不一样则添加 -
方法
方法重载与重写
方法重写与方法重载区别
方法重写@override 在子类当中,子类和父类的方法完全一样,子类覆盖了父类的方法,重写之后,使用子类对象调用的就是子类的方法。
方法重载@overload 在一个类中有多个重名方法,但是方法参数不同(参数类型、数目,顺序),和返回值无关。
使用HashSet存储自定义对象并遍历
package mySet;
import java.util.HashSet;
/*
* 使用HashSet存储自定义对象并遍历
*
* HashSet的add()方法,首先会使用当前集合中的每一个元素和新添加的元素进行hash值比较,
* 如果hash值不一样,则直接添加新的元素
* 如果hash值一样,比较地址值或者使用equals方法进行比较
* 比较结果一样,则认为是重复不添加
* 所有的比较结果都不一样则添加
*/
public class hashSetDemo2 {
public static void main(String[] args) {
// 创建集合对象
HashSet<Student> hashSet = new HashSet<Student>();
// 创建元素对象
Student s = new Student("张三",18);
Student s2 = new Student("lisi",18);
Student s3 = new Student("lisi",18);
// 添加元素
hashSet.add(s);
hashSet.add(s2);
hashSet.add(s3);
// 遍历集合对象 自定义的类
for (Student student:hashSet
) {
System.out.println(student);
}
}
}
class Student {
String name;
int age;
public Student(String name,int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public boolean equals(Object obj) {
System.out.println("-------------------");
Student s = (Student)obj;//向下转型,可以获取子类特有成员
//比较年龄是否相等,如果不等则返回false
if(this.age != s.age) {
return false;
}
//比较姓名是否相等,如果不等则返回false
if(!this.name.equals(s.name)) {
return false;
}
//默认返回true,说明两个学生是相等的
return true;
}
@Override
public int hashCode() {
return 1;
}
}
hashCode方法和equals方法的优化
我们发现当hashCode方法永远返回整数1时,所有对象的hash值都是一样的, 有一些对象的成员变量完全不同,但是它们还需要进行hash和equals方法的比较,如果我们可以让成员变量不同的对象,它们的hash值也不同,这就可以减少一部分equals方法的比较从而可以提高我们程序的效率
可以尝试着让hashCode方法的返回值和对象的成员变量有关
可以让hashCode方法返回所有成员变量之和,
让基本数据类型直接相加,然后引用数据类型获取hashCode方法返回值后再相加(boolean不可以参与运算)
package mySet;
import java.util.HashSet;
public class HashSetDemo3 {
public static void main(String[] args) {
//创建集合对象
HashSet<Person> hs = new HashSet<Person>();
//创建元素对象
Person p = new Person("zhangsan",18);
Person p2 = new Person("lisi",21);
Person p3 = new Person("lisi",20);
//添加元素对象
hs.add(p);
hs.add(p2);
hs.add(p3);
//遍历集合对象
for (Person person : hs) {
System.out.println(person);
}
}
}
Person.java
package com.demo02;
public class Person {
String name;
int age;
public Person(String name,int age) {
this.name = name;
this.age = age;
}
//自动生成的方法重写
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) 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 int hashCode() {
//return age;
return age + name.hashCode();
}
@Override
public boolean equals(Object obj) {
System.out.println("-------------");
//提高效率
if(this == obj) {
return true;
}
//提高健壮性
if(this.getClass() != obj.getClass()) {
return false;
}
//向下转型
Person p = (Person)obj;
if(!this.name.equals(p.name)) {
return false;
}
if(this.age != p.age) {
return false;
}
return true;
}
*/
}
Collection
定义
Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。
Collections:
Collection和Collections有什么区别?
面试题:Collection和Collections有什么区别?
Collection是集合体系的最顶层,包含了集合体系的共性
Collections是一个工具类,方法都是用于操作Collection
- Collection
collection方法
- static void swap(List list, int i, int j) :将指定列表中的两个索引进行位置互换
- static int binarySearch(List list, Object key) 使用二分查找法查找指定元素在指定列表的索引位置 1 2 3 4 5 6 7
- static void copy(List dest, List src) :是把源列表中的数据覆盖到目标列表
注意:目标列表的长度至少等于源列表的长度 - static void fill(List list, Object obj) :使用指定的对象填充指定列表的所有元素
- static void reverse(List list) :反转
- static void sort(List list) :按照列表中元素的自然顺序进行排序
public class CollectionsDemo {
public static void main(String[] args) {
method7();
}
private static void method7() {
//static void swap(List list, int i, int j) :将指定列表中的两个索引进行位置互换
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(7);
list.add(0);
list.add(-1);
System.out.println(list);
Collections.swap(list, 2, 5);
System.out.println(list);
}
private static void method() {
//static int binarySearch(List list, Object key) 使用二分查找法查找指定元素在指定列表的索引位置 1 2 3 4 5 6 7
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
int index = Collections.binarySearch(list, 4);
System.out.println(index);
}
private static void method2() {
//static void copy(List dest, List src) :是把源列表中的数据覆盖到目标列表
//注意:目标列表的长度至少等于源列表的长度
//创建源列表
List<String> src = new ArrayList<String>();
src.add("hello");
src.add("world");
src.add("java");
//创建目标列表
List<String> dest = new ArrayList<String>();
dest.add("java");
dest.add("java");
//dest.add("java");
//dest.add("java");
Collections.copy(dest, src);
System.out.println(dest);
}
private static void method3() {
//static void fill(List list, Object obj) :使用指定的对象填充指定列表的所有元素
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
System.out.println(list);
Collections.fill(list, "android");
System.out.println(list);
}
private static void method4() {
//static void reverse(List list) :反转
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println(list);
Collections.reverse(list);
System.out.println(list);
}
private static void method5() {
//static void shuffle(List list):傻否,随机置换
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println(list);
Collections.shuffle(list);
System.out.println(list);
}
private static void method6() {
//static void sort(List<T> list) :按照列表中元素的自然顺序进行排序
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(4);
list.add(3);
list.add(2);
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}
}
输出:
[1, 2, 3, 4, 7, 0, -1]
[1, 2, 0, 4, 7, 3, -1]
Collection练习 模拟斗地主
package com.demo03;
import java.util.ArrayList;
import java.util.Collections;
/*
* 模拟斗地主发牌
买牌
洗牌
发牌
*/
public class CollectionsTest {
public static void main(String[] args) {
//String[] box0 = {"黑桃A","黑桃2"...}
//买牌
String[] arr = { "黑桃", "红桃", "方片", "梅花" };
String[] arr2 = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" };
ArrayList<String> box = new ArrayList<String>();
//添加每张牌
for (int i = 0; i < arr.length; i++) {
//获取每一个花色
for (int j = 0; j < arr2.length; j++) {
//获取每一个数
box.add(arr[i] + arr2[j]);
}
}
box.add("大王");
box.add("小王");
System.out.println(box.size());
System.out.println(box);
//洗牌
Collections.shuffle(box);
System.out.println(box);
//发牌
ArrayList<String> 林志玲 = new ArrayList<String>();
ArrayList<String> 林心如 = new ArrayList<String>();
ArrayList<String> 舒淇 = new ArrayList<String>();
//留三张底牌给地主
for (int i = 0; i < box.size() - 3; i++) {
/* i = 0;i % 3 = 0;
i = 1;i % 3 = 1;
i = 2;i % 3 = 2;
i = 3;i % 3 = 0;
i = 4;i % 4 = 1;
i = 5;i % 5 = 2;*/
if(i % 3 == 0) {
林志玲.add(box.get(i));
}else if(i % 3 == 1) {
林心如.add(box.get(i));
}else if(i % 3 == 2) {
舒淇.add(box.get(i));
}
}
System.out.println("林志玲:" + 林志玲);
System.out.println("林心如:" + 林心如);
System.out.println("舒淇:" + 舒淇);
System.out.println("底牌:");
/*System.out.println(box.get(box.size() - 1));
System.out.println(box.get(box.size() - 2));
System.out.println(box.get(box.size() - 3));*/
for (int i = box.size() - 3; i < box.size(); i++) {
System.out.println(box.get(i));
}
}
}
54
[黑桃A, 黑桃2, 黑桃3, 黑桃4, 黑桃5, 黑桃6, 黑桃7, 黑桃8, 黑桃9, 黑桃10, 黑桃J, 黑桃Q, 黑桃K, 方块A, 方块2, 方块3, 方块4, 方块5, 方块6, 方块7, 方块8, 方块9, 方块10, 方块J, 方块Q, 方块K, 红桃A, 红桃2, 红桃3, 红桃4, 红桃5, 红桃6, 红桃7, 红桃8, 红桃9, 红桃10, 红桃J, 红桃Q, 红桃K, 梅花A, 梅花2, 梅花3, 梅花4, 梅花5, 梅花6, 梅花7, 梅花8, 梅花9, 梅花10, 梅花J, 梅花Q, 梅花K, 大王, 小王]
[红桃7, 梅花J, 梅花4, 黑桃4, 大王, 方块2, 梅花2, 黑桃6, 方块7, 方块3, 方块Q, 黑桃A, 黑桃3, 梅花8, 红桃8, 红桃10, 梅花10, 黑桃10, 红桃A, 红桃K, 黑桃9, 方块A, 梅花Q, 梅花5, 红桃6, 黑桃7, 梅花A, 红桃5, 红桃4, 红桃2, 方块4, 方块10, 方块8, 方块K, 黑桃5, 方块6, 方块J, 红桃Q, 梅花6, 红桃J, 黑桃J, 红桃3, 方块9, 梅花7, 方块5, 黑桃K, 梅花K, 红桃9, 小王, 黑桃Q, 黑桃8, 黑桃2, 梅花9, 梅花3]
林志玲[红桃7, 黑桃4, 梅花2, 方块3, 黑桃3, 红桃10, 红桃A, 方块A, 红桃6, 红桃5, 方块4, 方块K, 方块J, 红桃J, 方块9, 黑桃K, 小王]
林心如[梅花J, 大王, 黑桃6, 方块Q, 梅花8, 梅花10, 红桃K, 梅花Q, 黑桃7, 红桃4, 方块10, 黑桃5, 红桃Q, 黑桃J, 梅花7, 梅花K, 黑桃Q]
舒淇[梅花4, 方块2, 方块7, 黑桃A, 红桃8, 黑桃10, 黑桃9, 梅花5, 梅花A, 红桃2, 方块8, 方块6, 梅花6, 红桃3, 方块5, 红桃9, 黑桃8]
底牌:
黑桃2
梅花9
梅花3
Map
需求:实现学号和姓名这样有对应关系的数据存储
- 为了体现这种有对应关系的数据,我们使用以前所学的内容是可以实现的,但是略有不便,所以java又给我们提供了一种专门用于存储对应关系的集合。
Map:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值
Map和Collection有什么区别?
Map:是一个双列集合,常用语处理有对应关系的数据,key是不可以重复的,我们也称之为是夫妻对集合
Collection:是单列集合,Collection有不同的子体系,有的允许重复有索引有序,有的不允许重复而且无序,那么我们也称之为单身汉集合
一对一:一个学号对应一个姓名。
定义:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
map常用功能
映射功能:
V put(K key, V value)
获取功能:
V get(Object key)
int size()
判断功能:
boolean containsKey(Object key)
boolean containsValue(Object value)
boolean isEmpty()
删除功能:
void clear()
V remove(Object key)
遍历功能:
Set<Map.Entry<K,V>> entrySet()
-
Set<K> keySet()
-
Collection<V> values()
public class MapDemo2 {
public static void main(String[] args) {
//创建Map对象
Map<String,String> map = new HashMap<String,String>();
//V put(K key, V value) :就是将key映射到value,如果key存在,则覆盖value,并将原来的value返回
System.out.println(map);
System.out.println(map.put("s001", "张三"));
System.out.println(map.put("s002", "李四"));
System.out.println(map.put("s001", "王五"));
//System.out.println(map.put("s001", null));
System.out.println(map);
//V get(Object key) : 根据指定的key返回对应的value
//System.out.println(map.get("s002"));
//System.out.println(map.get("s002sdf"));
//int size() : 返回对应关系的个数
//System.out.println(map.size());
//boolean containsKey(Object key) : 判断指定key是否存在
//System.out.println(map.containsKey("s003"));
//System.out.println(map.containsKey("s002"));
//boolean containsValue(Object value):判断指定的value是否存在
//System.out.println(map.containsValue("王五"));
//System.out.println(map.containsValue("王"));
//void clear() : 清空所有的对应关系
//map.clear();
//System.out.println(map);
//V remove(Object key) :根据指定的key删除对应关系,并返回key所对应的值,如果没有删除成功则返回null
System.out.println(map.remove("s005"));
System.out.println(map.remove("s002"));
System.out.println(map);
//boolean isEmpty() : 判断是否有对应关系
System.out.println(map.isEmpty());
map.clear();
System.out.println(map);
System.out.println(map.isEmpty());
}
}
Set keySet() 获取map的键,Collection values() 获取map的值
/*
* Set<K> keySet()
* Collection<V> values()
*/
public class MapDemo3 {
public static void main(String[] args) {
//创建Map对象
Map<String,String> map = new HashMap<String,String>();
//添加映射关系
map.put("s001", "张三");
map.put("s002", "李四");
map.put("s005", "李四");
//Set<K> keySet() : 以Set的形式获返回所有的key
Set<String> keys = map.keySet();
for (String key : keys) {
System.out.println(key);
}
System.out.println("-----------");
//Collection<V> values() :
Collection<String> values = map.values();
for (String value : values) {
System.out.println(value);
}
}
}
s005
s002
s001
-----------
李四
李四
张三
map的两种遍历方式
- map的第一种遍历方式
首先召集所有的键(丈夫):
Set<String> keys = map.keySet();
遍历所有的键(丈夫):
for (String key : keys) {
//让每个丈夫去找他自己的媳妇就可以了
String value = map.get(key);
System.out.println("丈夫:" + key + "---" + "媳妇:" + value);
}
获取每一个键(丈夫)
让每一个键(丈夫)去找他自己的值(媳妇)
/*
* Map的第一种遍历方式:
* 首先召集所有的丈夫
* 遍历所有的丈夫
* 获取每一个丈夫
* 让每一个丈夫去找他自己的媳妇
*/
public class MapDemo4 {
public static void main(String[] args) {
//创建Map对象
Map<String,String> map = new HashMap<String,String>();
//添加映射关系
map.put("谢婷疯", "张箔纸");
map.put("陈关西", "钟欣桶");
map.put("李亚碰", "王飞");
//遍历Map对象
//首先召集所有的丈夫
Set<String> keys = map.keySet();
//遍历所有的丈夫
for (String key : keys) {
//让每个丈夫去找他自己的媳妇就可以了
String value = map.get(key);
System.out.println("丈夫:" + key + "---" + "媳妇:" + value);
}
}
}
Map的第二种遍历方式
通过结婚证对象来获取丈夫和媳妇
for (Map.Entry<String, String> entry : entrys) {
//获取每个单独的结婚证对象
//通过结婚证对象获取丈夫和媳妇
String key = entry.getKey();
String value = entry.getValue();
System.out.println("丈夫:" + key + "---" + "媳妇:" + value);
}
Set<Map.Entry<K,V>> entrySet()
/*
* Map的第二种遍历方式:
* 通过结婚证对象来获取丈夫和媳妇
* Set<Map.Entry<K,V>> entrySet()
*
*/
public class MapDemo5 {
public static void main(String[] args) {
//创建Map对象
Map<String,String> map = new HashMap<String,String>();
//添加映射关系
map.put("尹志平", "小龙女");
map.put("令狐冲", "东方姑娘");
map.put("玄慈", "叶二娘");
//获取所有的结婚证对象
Set<Map.Entry<String,String>> entrys = map.entrySet();
//遍历包含了结婚证对象的集合
for (Map.Entry<String, String> entry : entrys) {
//获取每个单独的结婚证对象
//通过结婚证对象获取丈夫和媳妇
String key = entry.getKey();
String value = entry.getValue();
System.out.println("丈夫:" + key + "---" + "媳妇:" + value);
}
}
}
使用HashMap存储数据并遍历(字符串作为key)
package com.demo02;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
*
* 使用HashMap存储数据并遍历(字符串作为key)
*
*/
public class HashMapDemo {
public static void main(String[] args) {
//创建Map对象
HashMap<String,String> hm = new HashMap<String,String>();
//添加映射关系
hm.put("s001", "张三");
hm.put("s002", "李四");
hm.put("s003", "王五");
hm.put("s003", "赵六");
//遍历Map对象
//方式1 获取所有的key,通过key来获取value
Set<String> keys = hm.keySet();
for (String key : keys) {
String value = hm.get(key);
System.out.println(key + "=" + value);
}
System.out.println("------------------");
//方式2:获取所有的结婚证对象,然后通过结婚证对象获取丈夫和媳妇
Set<Map.Entry<String, String>> entrys = hm.entrySet();
for (Map.Entry<String, String> entry : entrys) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
}
}
使用HashMap存储数据并遍历(自定义对象作为key)
package com.demo02;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/*
*
* 使用HashMap存储数据并遍历(自定义对象作为key)
*
*/
public class HashMapDemo2 {
public static void main(String[] args) {
//创建Map对象
HashMap<Student,String> hm = new HashMap<Student,String>();
//创建key对象
Student s = new Student("zhangsan",18);
Student s2 = new Student("lisi",20);
Student s3 = new Student("lisi",20);
//添加映射关系
hm.put(s, "s001");
hm.put(s2, "s002");
hm.put(s3, "s002");
//遍历Map对象
//方式1: 获取所有的key,通过key来获取value
Set<Student> keys = hm.keySet();
for (Student key : keys) {
String value = hm.get(key);
System.out.println(key + "=" + value);
}
System.out.println("-----");
//方式2:获取所有结婚证对象,通过结婚证对象获取丈夫和媳妇
Set<Map.Entry<Student, String>> entrys = hm.entrySet();
for (Entry<Student, String> entry : entrys) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
}
}
Student类
package com.demo02;
public class Student {
String name;
int age;
public Student(String name,int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@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;
}
}
异常的处理
异常的概述和体系结构.
-
Exception in thread “main” java.lang.ArithmeticException: / by zero
at com.demo01.ExceptionDemo.main(ExceptionDemo.java:5)
我们在写代码的时候,经常的出现一些小问题,那么为了方便我们处理这些问题,java为我们提供了异常机制
异常包含了错误的类型、原因以及位置异常:不正常,我们在代码的时候出现的编译或者运行时的错误
异常的体系结构:</ font>
Throwable(最顶层)
Error:出现的不能够处理的严重问题
Exception:可以处理的问题电脑坏了:
系统中毒:重装系统就可以了 这是Exception
主板坏了:买一台新的 这是Error
什么是异常?举例子:
public class exceptionDemo {
public static void main(String[] args) {
int a = 10 / 0;
System.out.println(a);
}
}
输出:出现异常
Exception in thread “main” java.lang.ArithmeticException: / by zero
at ExceptionDemo.exceptionDemo.main(exceptionDemo.java:5)
Throwable
JVM处理异常的方式
1.捕获处理
try…catch语句
try…catch的执行顺序:
首先执行try语句如果发现异常,异常下面的代码不再执行,直接跳入catch语句中,catch语句结束后,整个try…catch结束
如果没有发现异常,try语句执行结束后,try…catch直接结束, 不再执行catch语句
try{
有可能出现问题的代码;
}catch(ArithmeticException ae){
处理异常;
}
2.抛出去
当我们不想处理异常,或者没有能力处理的时候,我们可以选择抛出异常,谁调用方法谁处理异常
使用关键字throws在方法的声明出抛出异常
jvm处理异常的方式:
如果出现异常我们没有处理,jvm会帮我们进行处理,它会把异常的类型,原因还有位置显示在命令行,并且还终止了程序,异常后面的代码将不在执行。
public class ExceptionDemo2 {
public static void main(String[] args) throws Exception {
/*try {
System.out.println("执行前");
int a = 10 / 2;
System.out.println("执行后");
System.out.println(a);
}catch(ArithmeticException e) {
System.out.println("不能除0");
}
System.out.println("执行完问题语句后");
*/
try {
readFile();
}catch(FileNotFoundException e) {
System.out.println("没有发现文件");
}
}
public static void readFile() throws FileNotFoundException {
FileReader fr = new FileReader("d:\\a.txt");
}
}
如何处理多个异常
可以使用多个try…catch语句
使用一个try和多个catch
多个catch之间的顺序:
多个catch之间可以有子父类
平级之间没有顺序关系
如果有子父类,父类异常必须放在后面
public class ExceptionDemo3 {
public static void main(String[] args) {
try {
String s = "1";
System.out.println(s.length());
int[] arr = new int[5];
System.out.println(arr[4]);
int i = 10;
System.out.println(i/0);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界异常");
} catch (NullPointerException e) {
System.out.println("空指针异常");
} catch (Exception e) {
System.out.println("异常");
}
}
}
Throwable的常用方法
Throwable的常用方法:
- String getMessage() 原因
- String toString() 类型和原因
- void printStackTrace() 类型原因和位置
public class exceptionDemo2 {
public static void main(String[] args) {
try{
System.out.println(2 / 0);
}catch (ArithmeticException e){
// String getMessage():原因
System.out.println(e.getMessage());
// String toString()类型和原因
System.out.println(e.toString());
// void printStackTrace():类型原因和位置
e.printStackTrace();
}
}
}
finally概述和应用场景
finally:组合try…catch使用,用于释放资源等收尾工作,无论try…catch语句如何执行,finally的代码一定会执行。
try{
有可能出现问题的代码;
}catch(异常对象){
处理异常;
}finally{
释放资源;
清理垃圾;
}
package ExceptionDemo;
import java.io.FileWriter;
import java.io.IOException;
public class finallyDemo {
public static void main(String[] args) {
FileWriter fileWriter = null;
try{
fileWriter = new FileWriter("a.txt");
fileWriter.write("你好");
System.out.println(2/0);
fileWriter.write("我在学java");
} catch (IOException e) {
e.printStackTrace();
}finally {
try{
fileWriter.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
输出:Exception in thread “main” java.lang.ArithmeticException: / by zero
at ExceptionDemo.finallyDemo.main(finallyDemo.java:12)
异常的分类
异常的分类:
运行时期异常:RuntimeException的子类就是运行时期异常,在编译时期可以自由选择处理或者不处理。RuntimeException 是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。例如:ArithmeticException(当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。 )
编译时期异常:是Exception的子类,非RuntimeExcpetion的子类,在编译时期必须处理
举例子:
public class exceptionClassification {
public static void main(String[] args) throws IOException {
/* System.out.println(2 / 0);
String s = null;
System.out.println(s.length());
运行时异常 输出 ArithmeticException
*/
FileWriter fw = new FileWriter("a.txt");
//编译异常,在编译的时候必须处理,处理方式就是抛出异常
}
}
自定义异常
自定义异常的方法:写一个类去继承Exception或者RuntimeException,然后实现多个构造即可
1.先自定义异常:写一个类去继承Exception或者RuntimeException
package ExceptionDemo;
public class MyException extends RuntimeException{
private static final long serialVersionUID = 1L;
public MyException(){
super();
}
public MyException(String s){
super(s);
System.out.println("自定义异常");
}
}
2.实现多个构造
package ExceptionDemo;
public class exceptionDemo3 {
public static void main(String[] args) {
checkScore(110);
}
public static void checkScore(int score) throws MyException{
if(score < 0 || score > 0){
throw new MyException("考试不符合要求");
}
System.out.println("符合要求");
}
}
输出:
自定义异常
Exception in thread “main” ExceptionDemo.MyException: 考试不符合要求
at ExceptionDemo.exceptionDemo3.checkScore(exceptionDemo3.java:9)
at ExceptionDemo.exceptionDemo3.main(exceptionDemo3.java:5)
递归概述和例题
递归:把大问题拆成很多小问题,然后再把小问题拆成更多的小问题,
当我们把更多小问题解决了,小问题也解决了
随着小问题的解决,大问题也随之解决了
在方法本身不断的调用方法自己
递归注意事项:
==递归一定要有出口,内存溢出==
==递归次数不宜过多,内存溢出==
package Recurrence;
/*
* 需求:求5的阶乘
* 5! = 5 * 4 * 3 * 2 * 1; //120
* 5! = 5 * 4!; //120
* 4! = 4 * 3!; //24
* 3! = 3 * 2!; //6
* 2! = 2 * 1!; //2
* 1! = 1; //1
n! = n * (n - 1)!
*/
public class recurrenceDemo1 {
public static void main(String[] args) {
int n = method(5);
System.out.println(n);
}
public static int method(int n){
if(n == 0){ //出口
return 1;
}else{
return n * method(n-1);
}
}
}
斐波那契数列:
package Recurrence;
/*
* 古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,
* 小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,
* 问第二十个月的兔子对数为多少?
* 1
* 1
* 2
* 3
* 5
* 8
* 13
* 规律:除了第一个月和第二月以外,其余每个月都是前两个月之和
* 斐波那契列数
*
*/
public class recurrentDemo2 {
public static void main(String[] args) {
int m = method(20);
System.out.println(m);
}
public static int method(int n){
if(n == 1){
return 1;
}else if(n==2){
return 1;
}else{
return method(n-1)+method(n-2);
}
}
}
练习:手动实现FileWriter的try catch异常处理形式的完整模式
package ExceptionDemo;
import java.io.FileWriter;
import java.io.IOException;
/*手动实现FileWriter的try catch异常处理形式的完整模式*/
public class exceptionTest {
public static void main(String[] args) throws IOException {
demo();
}
private static void demo(){
FileWriter fileWriter = null;
try{
fileWriter = new FileWriter("E://a.txt");
fileWriter.write("小猫");
fileWriter.write("小狗");
}catch(Exception e){
System.out.println("出现异常");
e.printStackTrace();
}finally {
try {
if(fileWriter!=null){
fileWriter.close();
}
}catch(IOException el){
el.printStackTrace();
}
}
}
public static int get(){
try{
return 520;
}finally {
System.out.println("发生异常");
}
}
}