[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MkstKd0f-1654725363432)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]MyBatis
搭建
思路流程:搭建环境(添加依赖) -> 导入Mybtais -> 编写代码 -> 测试
搭建环境:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
编写核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-////DTD Config 3.0//EN"
"/dtd/">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value=""/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
//对应的寻找找到你们sql映射文件
<mappers>
<mapper resource="com/kuang/dao/"/>
</mappers>
</configuration>
Mybatis工具类
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession连接
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
资源过滤问题:
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
在.xml中有个属性名为namespace
用来指定mapper接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EEvB9FFz-1654725363436)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
配置文件中namespace中的名称为对应Mapper接口或者Dao接口的完整包名,必须一致!
select
接口中搜索需写在select
里面
mapper接口:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b8za5kR9-1654725363437)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xMLr6Zor-1654725363438)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
思路一:直接在方法中传递参数
在接口的方法中可以通过@Param("参数名")
来给该参数命名,然后再.xml文件中使用,这样就不要设置参数类型。
没有使用@Param
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T7EjZqWs-1654725363438)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
使用了@Param
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q7WtQkmB-1654725363439)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
中:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aAAZXS5M-1654725363440)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
没有使用的需要给参数定义一个参数类型,使用了就不要在定义参数类型可以直接使用!
思路二:使用Map接收
如果传递的参数过多,可以使用Map来接收
mapper接口中:
Emp selectByIdEbYmap(Map<String,Object>);
中:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g7FQGLQD-1654725363441)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
接着在调用的时候直接传递一个HashMap
Map<String, Object> map = new HashMap<String, Object>();
("sndasdasame","小明");
("asadsage","123456");
User user = mapper.selectUserByNP2(map);
比较推荐第二种,第一种能处理少量的参数,如果多的话可以使用map
insert
故名思议用来完成增加操作的
mapper接口中:
int addemp(Emp emp);
中:
<insert id="addemp" parameterType="emp">
insert into `emp`(`sname`,`ssex`,`age`,`salary`) values (#{sname},#{ssex},#{age},#{salary})
</insert>
这样调用即可
update
故名思议用来完成更新操作的
mapper接口
int updateById(Emp emp);
中:
<update id="updateById" parameterType="emp">
update `emp` set `sname`=#{sname},`ssex`=#{ssex},`age`=#{age},`salary`=#{salary} where id=#{id}
</update>
这样调用即可
delete
故名思议用来完成删除的
mapper接口:
int deletById(@Param("userid") int id);
中:
<delete id="deletById" parameterType="int">
delete from `emp` where id=#{userid}
</delete>
总结:
1.在传递参数的时候,需要添加参数的类型
2.使用@Param("参数名")
可以直接在xml中使用该参数名对应的该表示后面的参数,使用的时候不用添加参数类型
特别是在有多个参数的时候尽量使用@Param()
来给参数命名,在参数多的时候必须写上
3.在参数很多的情况下也可以使用map来接收
4.为了规范,在编写.xml中尽量把Parameter(参数类型)和resultType(返回值类型)都写上。
模糊语句Like
string wildcardname = “%smi%”;
list<name> names = mapper.selectlike(wildcardname);
<select id=”selectlike”>
select * from foo where bar like #{value}
</select>
分析:
在实际中可以先获取参数然后拼接两个百分号上去凑成一个字符串。
核心配置文件
:系统核心配置文件
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
environments元素
<environments default="development">
<environment >
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
多表查询(一对多)
在mybaits
中多表查询:
数据库:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZhhNxhyv-1654725363441)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
创建两个实体类
注意:实体类的类名要与数据库的类型一致才能匹配到,如果名称不一样在后面springboot中可以使用@TableName(数据库表名)
来进行匹配,否则无法匹配,属性名也要与数据库中的列名相等才能匹配
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P3pVCpEK-1654725363442)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
创建接口:
public interface StuMapper {
List<Stu> selectStuAndLession();
}
中:
在resultMap
中创建一个标签association标签
property
:为stu
表中的引用类型lesson
column:为多的一方的列名
javaType:为property的数据类型
select:通过说明为搜索语句
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w7i53iV8-1654725363442)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Q0sAzcp-1654725363443)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4THpfnHZ-1654725363443)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
多对一思路:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UrT3siC9-1654725363444)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
这样相当于下面的语句:
select * from `student` inner join `lesson` on(student.lesson_id=lesson.lesson_id)
resultMap
就相当于主sql后面的inner join
lesson on(student.lesson_id=lesson.lesson_id)
准备的数据库表:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ffJQQ1Yp-1654725363444)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
按搜索嵌套处理:
实体类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kv4oBPJ4-1654725363445)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
目的:通过stu
的lesson_id
来完成与lesson
表的链接
接口:
public interface StuMapper {
List<Stu> selectBylESSON();
}
xml中:
//这里我们的stu中有引用类型所以使用resultMap
<select id="selectBylESSON" resultMap="getLesson">
select * from `student`
</select>
//根据上面的id来匹配 这里的type为多的一方的类型
<resultMap id="getLesson" type="Stu">
//association:用来给引用类型做一个连接
//property:指属性的名称
//column:为数据库中student的lesson_id拿来和lesson中的lesson_id匹配
//javaType:指属性名的类型
//select:链表的查询语句的id,下面的getLessona要与这个匹配才能获得lesson表中`lesson_id`=stu表中的`lesson_id`
//相互匹配的值
<association property="lesson" column="lesson_id" javaType="lesson" select="getLessona"/>
</resultMap>
<select id="getLessona" resultType="lesson">
select * from `lesson` where `lesson_id`=#{gsga}
</select>
结果:
@Test
public void tsata(){
SqlSession sqlSession = Mybatisuntils.getSqlSession();
StuMapper mapper = sqlSession.getMapper(StuMapper.class);
List<Stu> stus = mapper.selectBylESSON();
for (Stu stu : stus) {
System.out.println("学生名:"+stu.getStudent_name()+"课名"+stu.getLesson().getLesson_name());
}
}
调用结果:
学生名:Andy课名Java
学生名:Jack课名Java
学生名:Jim课名Python
学生名:Tom课名C++
学生名:Pete课名C++
学生名:Citr课名PHP
思路:
这个搜索嵌套处理有两个sql
第一个sql为搜索stu中的所有信息
第二个sql为搜索lesson
中的根据相同点给出对应的数据
中间的resultmap用来衔接两个sql的,是为了衔接lesson表在stu实体类中的属性名、类型、和衔接链表的共同点数据库中的列名,然后通过该列名给第二段sql来进行匹配查询
按结果嵌套处理:
接口:
public interface StuMapper {
List<Stu> selectLesonTWO();
}
xml中:
//在这段sql语句中将所有想要查询的信息进行链表查询
<select id="selectLesonTWO" resultMap="fontLesson">
select s.student_id ssid,s.lesson_id sid,s.student_name sname,l.lesson_name lname from student s,lesson l where s.lesson_id = l.lesson_id
</select>
<resultMap id="fontLesson" type="Stu">
//然后通过键值对将上面别名是数据库表名对应给类中的属性名
//这里的property是stu的成员属性名, column是上面sql中的别名
<id property="id" column="ssid"/>
<result property="lesson_id" column="sid"/>
<result property="student_name" column="sname"/>
//因为lesson属性为引用类型,所以这里使用了association ,因此有引用类型就使用association
<association property="lesson" javaType="lesson">
//给引用类型中的属性名赋值
<result property="lesson_name" column="lname"/>
</association>
</resultMap>
结果:
@Test
public void saerawr(){
SqlSession sqlSession = Mybatisuntils.getSqlSession();
StuMapper mapper = sqlSession.getMapper(StuMapper.class);
List<Stu> stus = mapper.selectLesonTWO();
for (Stu stu : stus) {
System.out.println("学生名:"+stu.getStudent_name()+"课名:"+stu.getLesson().getLesson_name());
}
}
调用结果:
学生名:Andy课名:Java
学生名:Jack课名:Java
学生名:Jim课名:Python
学生名:Tom课名:C++
学生名:Pete课名:C++
学生名:Citr课名:PHP
两种方法区别:
搜索嵌套的是:
在搜索语句中途去配置相对应的属性以及匹配的表名(有两段sql语句)
结果嵌套的是:
现在整体输入完所有的语句然后通过resultmap来给属性统一赋值(只需要一段sql语句)
springboot
创建原生组件注解模式创建
1.原生组件之servlet
思路流程:创建类a继承httpServlet
实现里面的doget
与dopost
,然后创建一个类为servler
的配置类,并在该类设置为配置类,在该类内将类a注册进容器中,然后通过servletRestionBean
将servlet
进容器容器中相当于注册一个servlet
a类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XgTTj6ov-1654725363445)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
然后定义一个配置类b,将a放进容器,并通过ServletRestionBean
进行注册。
注意在注册servlet
中需要给servlet
定义一个路径为该a类的访问路径
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3V2LvHAl-1654725363446)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
@Configuration
public class MyServletTestConfig {
@Bean
public MyServlet myServlet(){
return new MyServlet();
}
@Bean
public ServletRegistrationBean servletRegistrationBean(){
ServletRegistrationBean<MyServlet> myServletServletRegistrationBean = new ServletRegistrationBean<>(new MyServlet(),"/testa");
return myServletServletRegistrationBean;
}
}
这样就可以将servlet
注册进了springboot中了
2.原生组件之filter(过滤器)
手动配置:
流程: 创建类a实现Filter
这个类,并加上注解@WebFilter(拦截的路径)
,然后编写内部的逻辑,然后到主配置文件中添加注解扫描a类所在的包
在a类中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NeGfWImH-1654725363446)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
在主配置文件中,加入fliter
所在的包路径即可。 注意:这里使用@ServletComponentScan
来扫描因为这个注解在servlet
包下所以可以用该注解扫码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KcXXfT0v-1654725363447)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
自动配置:
流程:创建a类实现filter
,然后创建一个类为配置类,然后将a类放进容器中,在将a类进行注册
就创建过滤器,然后注册该过滤器,再放入到容器中
a类中:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WWv8Tj5W-1654725363447)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
filter
配置类中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xet0IimG-1654725363448)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
这样就可以在springboot中将原生的spring组件注册到springboot中了
配置处理和字符编码
方法一手动配置:
在servlet配置类中进行注册字符编码过滤器,前提是需要到yaml
中 将springboot
默认的字符编码关闭
思路流程:
字符集编码是需要和过滤器来进行统一的一个搭配的原因是,过滤器拦截到的请求可以在到后台之前全部设置为例如utf-8
等字符集,这样就可以不需要我们去每个控制器中手动设置字符集!
需要创建一个字符集过滤器,设置字符编码,接着放进filterFilterRegistration
过滤器中,通过过滤器来给字符集过滤器加上路径,最后加上需要修改字符的路径(意为只要是这些路径都会将字符集编程设置的)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aakcK62X-1654725363448)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
@Bean
public FilterRegistrationBean characet(){
//创建过滤器
FilterRegistrationBean<Filter> = new FilterRegistrationBean<>();
// 创建字符集过滤器
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
//然后开启设置强制编码
characterEncodingFilter.setForceEncoding(true);
//设置字符集为utf-8
characterEncodingFilter.setEncoding("utf-8");
//将字符集放入到过滤器中
filterFilterRegistrationBean.setFilter(characterEncodingFilter);
//过滤路径为/*也就是所有路径都将字符集调整的utf-8
filterFilterRegistrationBean.addUrlPatterns("/*");
return filterFilterRegistrationBean;
}
方法二使用springboot自动配置(推荐):
在springboot中自动配置的话,直接去主配置文件上面进行设置就可以了
//将字符编码调整为utf-8
server.servlet.encoding.charset=UTF-8
//启用springboot提供的配置字符集
server.compression.enabled=true
//开启强制字符集为utf-8
server.servlet.encoding.force=true
打包WAR
1.如果是创建项目之初是WAR包的,在配置类中设置端口号以及上下文,然后右边选这项目,然后点Package
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lo9xvUdt-1654725363449)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NexfzKS4-1654725363449)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
然后就可以在test中可以找到该WAR包在部署到linux;
JAR打包
与WAR包打包方式同理;
Thymleaf
在使用Thymeleaf
时,要到主配置文件将Thymeleaf
默认的缓存关闭,不然没办法看到实时页面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g6m2RDqk-1654725363450)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Java基础
循环:
break :
用于退出当前循环的循环体,若有多个循环则默认退出最近的循环体
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cPU23jXl-1654725363450)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
在结果处可以得知一当j
为2只退出第二层,第一层不影响
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AlaW7JWp-1654725363450)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
continue:
用于返回,当循环中出现该代码,直接进入下一个循环,continue
后面的代码不执行直接进入下一个循环,若有多个循环也是默认退出最近的循环体
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hMgKv4fX-1654725363451)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DiZB28Z5-1654725363451)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Return:
表示跳出当前方法7
Random
生成随机数,创建实例接着调用内部的方法(传入数值)
获取到的随机数为0到该数值之间的范围,不包括该该数值
Random r = new Random();
int i = r.nextInt(10);//获取到的数值为[0,10)之间的随机数
sout(i);
//创建一个1到10直接的数
int u = r.nextint(10)+1;
注意:该随机数是由0开始到目标数的,如果需要创建的数值为1开始的在末尾加1即可
Scanner
用于获取键盘输入的内容,创建实例接着调用内部的方法就可以获取键盘输入的内容
Scanner sc = new Scanner(System.in);//这里的是获取键盘输入的内容的
//scanner内部有很多方法,可以同来判断接字符类型返回的boolean,也可以接收字符串数字类型等等
int ie = sc.nextInt();//这就为接收的类型为数据类型
//如果输入的数据不为int类型就会报错,否则会是输出我们输入的Int
sout(ie)
sc.next();//是接收字符串
数组:
数组的声明
//第一种 数据类型[] 变量名;
int[] arr;
//第二种 数据类型 变量名[];
int arr[];
数组的动态初始化:
就是在声明数组的同时给了数组一个指定的长度,有系统为数组分配初始值
//格式: 数据类型[] 变量名 = new 数据类型[数组长度]
int[] arr = new int[5];//这里给数组指定了长度,没赋值之前默认为0
//这里输出的是地址值
sout(arr)
//打印的结果
[I@12a3a380
//小分析 [:说明的数组 I:说明的int类型的
//动态初始化赋值通过下标赋值(没赋值都为0)
arr[0] = 11;
arr[1] = 22;
arr[2] = 33;
arr[3] = 44;
arr[4] = 55;
数组的静态初始化:
//格式 数据类型[] 变量名= {数值}
int[] arr = {11,22,33,44,55}
sout(arr[0])
sout(arr[1])
sout(arr[2])
sout(arr[3])
sout(arr[4])
内存分配:
注意:new出来的实例都是在堆中
int arr[] = {11,22};
int[] arr2=arr;
arr2[0] = 33;
System.out.println(arr[0]);
结果:
33
说明了在arr2=arr 相当于arr2的地址也指向了arr所对应的地址,arr2改变其中的内容arr也随着改变
内存图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AavtqIOc-1654725363452)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
应用场景:
在知道参数的个数,但是不知道值的时候使用动态初始化:例如有5个学生,但是分数不知道,就可以用动态初始化
在知道参数的实际数值和个数的时候,直接使用静态初始化
方法:
方法重载:
在同一个类中,同名不同参数的为方法重载**(若参数相同但是位置顺序不同也为方法重载如 methor(int a,double b ) 与 methor(double b ,int a)这算重载)**
重载的好处:
不需要记住太多的方法名称传递对应的数据就可以返回理想值
如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tejpQyVB-1654725363452)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
面向对象基础
类和对象:
面向对象和面向过:
面向对象直接将执行者转换为了指挥者
面向过程就是每一步都需要自己去创作
例子:
洗衣服:
面向过程的洗衣服自己去洗,放水,加洗衣液然后手动去搓去洗
面向对象直接使用洗衣机来完成洗衣服个需要自己来动手的部分
类与对象的关系:
类:类是实现生活中一类具有共同属性和行为的事情的抽象
对象:是能够看得到摸得着的真实存在的实体
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ob3Dan0-1654725363453)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
对象的内存图:
单个对象:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8bDO4QaF-1654725363453)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
类中有成员方法的话,在运行中该对象会在堆中创建成员属性,而成员方法则是储存的方法区中的地址
多个对象:
多个对象的话字节码文件不会重复加载,而new出来的对象是新的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rO1Wl3hq-1654725363454)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
这里的两个对象都是同一个对象,但是new出来的在内存中是重新创建的,但成员方法是指向的地址是一样的
两个引用指向同一个对象:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oEN6NqQm-1654725363454)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
这里stu1在堆内存中指向地址为001的对象,然后stu2=stu1就是stu2=stu1=001指向同一个地址,所以不管是一还是二修改地址001中的成员属性,另一个也会受到影响
stu2=null,stu1=null 说明是将两个变量的地址指向为空,则无法找到对应的对象,所有后面就无法得到对应内容
成员变量与局部变量:
成员变量:类中方法外的变量(类中的所有方法都可以调用)
局部变量:方法内的变量(仅在方法中可用,方法外无法调用)
public class tesar{
private String name;//类中方法外成员变量
public void teast(){
int i ;//方法内。局部变量
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zzVvCT49-1654725363454)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
封装:
面向对象的三大特征之一
隐藏实现细节,仅对外公布公共的访问方法
封装的常见体现:
1.私有的成员变量,提供getxxx和setxxx方法
2.将代码抽取到方法中,这是对代码的一种封装
3.将属性抽取到类当中,这是对数据的一种封装
封装的好处:
1.提高代码的安全性
2.提高了代码的复用性
private关键字
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WtCMIVb9-1654725363455)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cS4oZRjB-1654725363455)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
this关键字
作用可以用来解决成员变量和局部变量同名的问题,如当成员变量与局部变量同名,方法内的调用就是调用的就近原则
public class TestThis {
private String name;
public String setName(String age){
//这里成员变量和局部变量同名就进来指向的是局部变量,这里相当于自己给自己赋值
age= age;
//如果想要调用成员变量这时候就可以加个this指向当前类中的成员变量
this.age = age;
}
}
this:
代表所在类的对象引用(方法被那个对象调用,this就指向哪个对象的地址)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xwDKIZ6W-1654725363456)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:相当于加了this的话就说明了这个name是在当前这个地址中的名为name的属性
可以看他们两个地址值的相同的,所以可以得出 就相当于当前对象中的name
this内存原理图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-45TAn2Rx-1654725363456)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
构造方法:
构架,创建对象的时候,所调用的方法
格式:
1.方法名与类名相同,大小要一致
2.没有返回值,连void都没有
3.没有具体的返回(不能由return带回的结果数据)
执行实际:
1.创建对象的时候使用,每创建一个对象,就会执行一次构造方法
2.不能手动调用
//类
public class student{
//构造方法:不能有返回值,void,方法名要与类名相同区分大小写的,不能带return
public student(){
sout("执行了一次构造方法")
}
}
//在测试中
//***************
//这创建了对象就调用了一次无参构造了
Studen su= new Student();
su.student();//这一步不能成功!,因为不能手动调用
构造方法的作用:
可以在创建对象的时候就给变量赋值
public class student{
private String name;
private Integer age;
public student(String name){
this.name = name;
}
}
//测试中
TestThis safasf = new TestThis("safasf", 18);
System.out.println(safasf);
//结果
TestThis{name='safasf', age=18}
构造方法注意事项:
1.构造方法的创建
如果没有定义构造方法,系统会默认调用无参构造
如果定义了构造方法,系统不再提供默认的构造方法
2.构造方法的重载
如果定义了带参构造方法,还要使用无参的构造方法,就必须在写一个
3.推荐的使用方式:
不管用不用都全部创建出来
API基础
Scanner:
用于获取键盘的输入对象
()
与()
t的区别
nextLine()
可以将数据全部获取过来
**结束标记:**回车
next()
一旦数据中有空格就直接输出空格前的数据,后面的不出
**结束标记:**空格 和 table键
Scanner sc = new Scanner(System.in);
//这里输入内容为:AA BB CC
String ae = sc.nextLine();
sout(ae)
//输出结果是
AA BB CC
//这里使用next
String ac = sc.next();
//输入同样的内容AA BB CC
sout(ac)
//输出结果是
AA
图:
nextLine
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6tTHVaZ8-1654725363457)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1DnKSZtE-1654725363457)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
next
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bKu8omFS-1654725363457)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8oM6JASt-1654725363458)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
注意:nextInt()
和nextLine()
联合使用的时候nextLine()
不能获取到参数,因为nextInt输出完输入了回车,那么nextLine获取到了回车会默认为结果所以就不会接受直接输出
因此:录入键盘数据的时候如果需要使用整数和字符串,建议使用next
String:
String创建的字符串是唯一的不可变的
String常见的构造方法:
public String():创建一个空的字符串对象
public String(char[]):传入char数组返回值是字符串
public String(String Or):传入字符串内容,创建字符串对象
String ace=“字符串”:直接赋值的方式创建字符串对象,内容是abc
String s = new String();
System.out.println(s);//这里掉用构造方法 public String()
char[] arr ={'a','b','c'};
String s1 = new String(arr);
System.out.println(s1);// public String(char[])
String s2 = new String("123");
System.out.println(s2);//public String(original:)
String abc = "abc"
System.out.println(abc);//String 变量名 = "";
//结果:
//这里调用构造方法 public String()
abc// public String(char[])
123//public String(original:)
abc//String 变量名 = "";
创建字符串对象的区别对比:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zknYmpMN-1654725363458)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:通过双引号创建的字符串是在方法区中存储的,通过构造方法创建字符串是在堆内存中存储的
String常见面试题:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MjjGKVc6-1654725363459)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:s1和s2直接是在字符串常量池中创建出来的,而s3=s2+“c”,它底层默认在堆内存中创建一个stringbuilder然后通过append来拼接"c"在用tostring在堆内存中构成的"abc"所以与字符串常量池中的"abc"不是同一个地址。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XIcoirxE-1654725363459)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析: s2是由字符串由一个个字符串拼接的所以这里生成的"abc"会指向s1所指向的"abc"是同一个地址
理解:在字符串拼接中出现了变量拼接字符串是在堆内存中创建的,字符串之间的拼接是在字符串常量池中创建(如果常量池中了该字符串则会指向该字符串,没有则创建)
String练习:
判断字符中的小写字符和大写字符以及数字字符的个数
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String next = scanner.next();
char[] chars = next.toCharArray();//char[] tochar//将字符串转换成字符数组类型
int small = 0;
int big = 0;
int num = 0;
for (int i = 0; i < chars.length; i++) {
//这里是通过ASCII表来判断的
if(chars[i]>='a'&&chars[i]<='z'){
small++;
}else if(chars[i]>='A'&&chars[i]<='Z'){
big++;
}else {
num++;
}
}
System.out.println("小写字符有:"+small+"个");
System.out.println("大写字符有:"+big+"个");
System.out.println("数字字符:"+num+"个");
}
输出值:
输入值查看其中的数值:
abdABC123
输入值为:abdABC123
小写字符有:3个
大写字符有:3个
数字字符:3个
屏蔽电话号码:
Scanner scanner = new Scanner(System.in);
System.out.println("输入电话号码");
// 接收键盘输入的号码
String next = scanner.next();
// 换成char数组
char[] chars = next.toCharArray();
//然后循环获取每一个号码
for (int i = 0; i < chars.length; i++) {
//这里根据号输入的字符串的下标来给对应的位置号码改为*
if (i>2&&i<7){
chars[i] ='*';
}
}
System.out.println(chars);
输出值:
输入电话号码
123456789
输出电话号码:
123****89
第二种方法:
Scanner scanner = new Scanner(System.in);
System.out.println("输入电话号码");
String next = scanner.next();
//string substring(int s,int e);用于截取字符创中从s到e的之间的数值不包括e
String substring = next.substring(0, 2);
//substring(int e);用于截取第七个数值后面的字符,
String substring1 = next.substring(7);
System.out.println(substring+"****"+substring1);
输出:
输入电话号码
asd123456
as****56
分析:
substring(): 是截取后重新创建一个字符串,原来的字符串不变
敏感词替换
Scanner scanner = new Scanner(System.in);
System.out.println("和谐前:");
String next = scanner.next();
String tmd = next.replace("TMD", "***");
System.out.println("和谐后:");
System.out.println(tmd);
结果:
和谐前:
TMDhaha
和谐后:
***haha
分析:
replace(“想换”,“换成”):用于将字符创中的想换的字符内容换成想换的内容。
切割字符串
Scanner scanner = new Scanner(System.in);
System.out.println("输入姓名和年龄中间用逗号隔开");
String next = scanner.next();
String[] split = next.split(",");
System.out.println("学生姓名:"+split[0]);
System.out.println("年龄:"+split[1]);
结果:
输入姓名和年龄中间用逗号隔开
张三,23
学生姓名:张三
年龄:23
分析:
split(“字符串中分割的标记”):这里是看到逗号就分割,分割后,前后两个内容会用数组存储起来通过下标就可以调用了
String小结:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ZzHKvAF-1654725363459)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KFQBQGVp-1654725363460)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
StringBuilder :
StringBuilder是一个可变的字符创类,我们可以把它看成一个容器
**作用:**提高字符串的操作效率
比较:
//使用String 的拼接
long s = System.currentTimeMillis();//currentTimeMillis()这个方法可以获取1970年计算机发明时到现在的时间返回的是秒值
String se = "";
for (int i = 1; i < 50000; i++) {
se+=i;
}
System.out.println(se);
long e = System.currentTimeMillis();
System.out.println("执行时间:"+(e-s));
输出结果:
执行时间:7562 //方法执行用了7秒的时间
//使用StringBuilder的拼接
long s = System.currentTimeMillis();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 1; i < 50000; i++) {
stringBuilder.append(i);//拼接字符串
}
System.out.println(stringBuilder);
long e = System.currentTimeMillis();
System.out.println("执行时间:"+(e-s));
输出结果:
执行时间:9
输出的结果可以说明StringBuilder的拼接效率比String的拼接效率快
分析:
currentTimeMillis
:可以获取到计算机1970至今的时间,返回值的按秒回的
StringBuilder构造方法
public StringBuilder()
:创建一个空的字符串对象,不含任何的内容
public StringBuilder(String str)
:根据字符串的内容,来创建可变字符串对象
//public stringBuilder();
StringBuilder sb = new StringBuilder();
sout(sb);//输出结果为 空 "";
StringBuilder sb2 = new StringBuilder("abc");
sout(sb2);//输出结果为 "abc"
StringBuilder的常用方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2nEKqqKY-1654725363460)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//public StringBuilder append(任意类) 添加数据,并返回本身
StringBuffer sb = new StringBuffer();
StringBuffer f = sb.append("红色");
System.out.println(f);
StringBuffer s = f.append("蓝色");
System.out.println(s);
//判断两个是否都是本身
System.out.println(f==s);//这里返回值为true,说明两次的返回都是本身
//优化
StringBuffer sb = new StringBuffer();
sb.append("绿色").append("蓝色");//因为返回的都是本身,那么上面的("蓝色")相当于在("绿色").append("蓝色")
sout(sb);// 结果:绿色蓝色
分析:publice StringBuilder append(任意类型)
添加并返回的是本身
StringBuffer sb = new StringBuffer("abc");
StringBuffer reverse = sb.reverse();
System.out.println(sb);
System.out.println(reverse);
结果:
cba
cba
//由于StringBuilder就是一个容器,在调用这个方法都是在本身上面进行修改的
分析:Pubilc StringBuilder reverse()
反转字符顺序(在本身上面反转的,所以反转后的字符就是本身自己)
StringBuffer sb = new StringBuffer("abc");
int i = sb.length();
sout(i);
结果:
3
分析:public int length()
返回的字符串长度
Public String toString()
通过toString将StringBuilder
转换为String
类型
StringBuilder内存分析图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7TomOF2Q-1654725363461)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
原理图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LwXzfpuy-1654725363461)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:为什么说String比StringBuilder更加高效率呢上面图可以看出,string的拼接是,一拼接就需要创建new StringBuilder来通过append()来进行拼接,那么堆内存中每次拼接都要创建一个,而StringBuilder直接在本身上面进行的拼接,不需要创建任何东西,需要String类型的时候调用toString就可以了,所以StringBuilder更加的高效率
通过这就可以知道上面调用50000次的例子的原因了,每次都在堆内存中创建一个stringBuilder,五万次创建五万个所以就时间需要7秒的时间,而StringBuilder直接在本身上面添家不需要创建任何东西,所以StringBuilder更加高效率
String 和 StringBuilder的区别
String: 内容不可变
StringBuilder: 内容可变
StringBuilder练习:
判断是否是对称字符:
//对称字符 abccba 那么反转过来的话值是不变的那么就可以使用StringBuilder的reverse()来获取反转的内容并且对比
System.out.println("输入字符判断是否对称");
Scanner scanner = new Scanner(System.in);
String next = scanner.next();//这里获取到键盘输入的字符串
StringBuilder stringBuilder = new StringBuilder(next);//将她转换成stringBuilder类型,调用里面的reverse()来反转
stringBuilder.reverse();
String s1 = stringBuilder.toString();//这里就可以获得反转后
if(next.equals(s1)){//这里判断传入的字符串反转前和反转后是否一致,一致就是对称字符
System.out.println("这个是对称字符");
}else {
System.out.println("这个不是对称字符");
}
那数组的格式返回字符串
int arr[] = {1,2,3};
//这里是需要返回字符串我们先创建stringbuilder方便拼接
StringBuilder sb = new StringBuilder();
//先加个[ : 这时候sb:[
sb.append("[");
//这里根据数组中的个数添加进去
for (int i = 0; i < arr.length; i++) {
sb.append(arr[i]);//这里第一个就获数组中的1,sb:[1
if(i == arr.length-1){//到这判断是否是最后一个,是话加个]
sb.append("]");
break;
}
sb.append(",");//这里不是最后一个后面加个逗号 sb:[1,
}
System.out.println(sb);//这里是stringBuilder类型的
String se = sb.tostring();
sout(se)
}
//返回值:
[1,2,3]
[1,2,3]
StringBuilder和String之间的转换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-85zRkANl-1654725363461)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
集合基础
ArrayList:
集合和数组容器的区别:
集合容器的特点:提供一种存储空间的存储模型,存储的数据容量可以发生改变
集合和数组的区别:
共同点:都是存储数据的容器
不同点:数组容量是固定的,集合容量是可变的
如果存储的数据,长度经常发生改变,推荐使用集合
例子:
//如果使用数组这里我们不管动态数组还是静态数组都需要给它
//设定一个存储个数,不能随意添加
//比如这里学生数组我们设定存储3个学生
Student[] stu = new Student[3];
//创建三个学生对象
Student s1 = new Student("kk",23);
Student s2 = new Student("ee",24);
Student s3 = new Student("ll",25);
//赋值进去
stu[0] = s1;
stu[1] = s2;
stu[2] = s3;
//循环获取学生数组里面的对象名称和年龄
for(int i = 0;i<stu.length -1 ;i++){
sout(stu[i].getName());
sout(stu[i].getAge());
}
//这里如果我们突然要加多一个学生,那只能重新创建一个学生数组设置值为4才能存储
//这样就很麻烦了,所以来了ArrayList()数组的长度是任意的
//随时可以加
ArrayList构造方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sbFqbwu0-1654725363462)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
ArrayList()
:构造一个初始容量为10 的空列表
成员方法:
添加: boolean add(E e) 将指定元素添加到此列表的尾部(这个E是代表可以放入任何类型)
void add(int index,E element): 将制定的元素插入此列表中的指定位置
ArrayList list = new ArrayList();
list.add("abc");
list.add(123);
list.add(true);
sout(list);
输出:
[abc, 123, true]
//上面这种可以在集合中存入任何的数据类型
//但我们想要完成集合内的数字添加和,那如果什么类型都可以添加就无法得到准确是数据
//所以集合中有个泛型是拿来指定该集合可以添加入的数据类型做限制的
//尖括号内只能写入引用数据类型
ArrayList<Integer>atts= new ArrayList<Integer>();//这里设置只能添加Integer类型
//("sad");//报错无法添加int类型之外的
ints.add(123);//boolean add(E e);
ints.add(0,456);//在下标为0的地方加456,先前的值往后退;
sout(ints);
结果:
[456,123]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9BqdRAa3-1654725363462)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
案例:
ArrayList<String> ss = new ArrayList<>();
ss.add("hahaha");
ss.add("eeee");
ss.add("sss");
//在集合中,集合的长度是size()来表示的,获取集合中的某元素用get(元素下标)
for (int i = 0; i < ss.size(); i++) {
System.out.println(ss.get(i));
}
分析:集合的长度使用size()
来表示的
获取集合中某个下标的元素通过get(int i )
加上下标来获取的;
集合存储对象时: 存储的是对象的地址
删除元素:
ArrayList<String> ase= new ArrayList<>();
ase.add("test");
ase.add("haha");
ase.add("test");
ase.add("test");
for (int i = 0; i < ase.size(); i++) {
String se= ase.get(i);
if("test".equals(se)){
ase.remove(i);
i--;//这一步很关键
}
}
System.out.println(ase);
}
结果:
[haha]
面向对象进阶
static
static关键字是静态的意思,是java中的一个修饰符,可以修饰成员方法,成员变量
被修饰的成员变量叫静态变量
被修饰的成员方法叫静态方法
static的作用:
static修饰成员属性:
1.被static修饰的成员,会被该类的所有对象所共享
2.被static修饰的成员,会随着类的加载而加载,优先于对象存在
3.多了一种调用
//被static的成员变量会被该类的所有对象共享
//实体类
public class School {
String name;
static String schoole;
public void show(){
System.out.println(name+"****"+"\t"+schoole);
}
}
//测试:
public static void main(String[] args) {
School school = new School();
school.name = "张武";
school.schoole = "huohouhuo";//这里给实体类中的静态方法赋值
school.show();//输出内容是 张武**** huohouhuo
School s2 = new School();//这里也创建了一个school对象
s2.name = "孙七";//但是只对其中的name进行赋值,没有对静态属性赋值
s2.show();//输出得到了之前对象一所赋值的内容 结果: 孙七**** huohouhuo
//所以说明被static声明的静态变量是共享所有对象的
}
结果:
张武**** huohouhuo
孙七**** huohouhuo
分析:上例子中,只在对象一中对静态变量进行赋值,对象二没有赋值,输出却有对象一所赋值的内容,所以说明被static修饰的静态变量是可以被所有属性共享的。
//被static修饰的成员是优先于对象加载的
//这里在对象创建之前就赋值内容了,所以可以说明一切
School.schoole = "haha";//这里是静态属性的多一种调用方法,因为类一被加载他就被加载了所以就可以通过类来调用它
School school = new School();
school.name = "张武";
school.show();//输出得到了结果
结果:
张武**** haha
分析:static修饰的成员属性是优先于对象加载的,因为他与类同时产生。所以可以在对象创建实例之前就可以提前调用
static修饰成员方法:
静态随着类的加载而加载,优先于对象存在;
非静态需要在创建对象之后,才可以进行使用
1.静态方法中,只能访问静态成员(成员变量,成员方法)
2.非静态方法中,可以访问静态成员,也可以访问非静态成员
3.静态方法中没有this关键字
分析:
1.静态方法是对象没有创建就已经创建了,而这时候调用非静态的成员属性和方法,他们是需要有对象创建才能创建出来的,所以如果使用了静态方法找不到非静态的成员属性所以无法访问,只能访问静态属性和静态方法。
2.非静态方法可以访问静态成员和非静态成员,这个很好理解,因为静态比非静态先创建,那么当非静态创建可以使用的时候静态早已存在所以可以调用
是指向的一个对象的内存地址,对象都没有创建因此没有地址,那么this在静态方法中就无法获取你想访问的内容
static内存分析图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QRIn6Nwr-1654725363463)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
继承:
继承:让类与类之间产生关系(子父类关系),子类可以直接使用父类中非私有的成员
格式:
public class zi extends fu
这其中的zi是子类fu是父类
继承的有点和弊端:
优点:
可以解决代码的重复性问题
调高代码的维护性
让类与类之间产生了关系,是多态的前提
弊端:
继承的侵入性的
减低了代码的灵活性
继承关系,导致子类必须拥有父类非私有属性和方法,让子类*的世界中多了些约束
增强了耦合性:
代码与代码之间存在关联都可以将其称之为”耦合“
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ilij4CwL-1654725363463)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
继承特点:
java只支持单根继承,不支持多继承,但支持多层继承
publice class a {
public void tes(){
sout("aaa");
}
}
publice class b extends a{
public void test(){
sout("bbb");
}
}
publice class c extends b{
}
//测试:
//这里连环继承c可以调用a与b中的非私有的方法
C c = new C();
c.tes();
c.test();
结果:
aaa
bbb
为什么java不支持多根继承看图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B6Zvzvc8-1654725363463)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Super:
当子类中有成员属性名与父类中成员属性同名,而有刚好需要父类中同名的那个成员属性的话,就可以通过super来指定父类中那个同名的属性。
public class a {
int a = 10;
}
public class B extends a{
int b = 20;
public void mehod(){
int c = 30;
sout(c);//输出30
sout(b);//输出20
sout(super.a);//输出10 因为调用了super指向了父类中的int a 所以等于10
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WSogFZ2l-1654725363464)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
继承的成员变量和访问特点:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZiEMhVBu-1654725363464)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
继承中成员方法的访问特点:
通过子类访问一个方法
- 现在子类中查找是否有这个方法
- 子类中没有择到父类汇总寻找
都没有就显示报错
方法重写
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yC1jmJ3O-1654725363465)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
注意:
重载:在同一个类中,方法名相同,参数列表和返回值不同
重写:在继承的关系中,子类出现与父类一模一样的方法声明(方法名,参数列表,返回值类型)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I7ydtzbX-1654725363465)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
继承中构造方法的访问特点:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9SXcpXRg-1654725363465)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
public class fu{
int a = 10;
public fu(){
sout("fu");
}
public fu(int e){
sout("父类有参构造")
}
}
public class Zi extends fu{
int e = 30;
public Zi(){
sout("zi")
}
public Zi(int es){
sout("子类有参构造")
}
}
//test
Zi z = new Zi();
Zi z = new Zi(3);
//输出:
fu
zi
fu
子类有参构造
分析:为什么会输出到父类的构造方法呢?
在继承中,程序不知道我们是否需要调用父类的成员属性或者成员方法,所以在每一个构造方法中都会加上一个父类的无参构造,要有实例才能调用父类中的属性和方法,所以是默认加上的super()
来实例父类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-snUpG1aw-1654725363466)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:当父类中没有无参构造,则子类的构造方法都会报错,结果方法是手动在无参构造加通过super调用父类的有参构造
//父类
public class fu{
int a ;
public a(int e ){
sout("有参构造")
}
}
//子类
public class Zi{
int e = 30;
public Zi(){ //这里就会报错,因为他默认的添加的父类的无参构造,但是此时父类没有无参够着所以需要用super来调用父类的有参构造
super(3);//手动添加就可以不报错了
sout("子类无参狗仔")
}
}
抽象类:
抽象方法:将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体明确,该方法就可以定义为抽象方法
抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LoXqifTS-1654725363466)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:在一个父类中如果对方法的描述不明确时就需要加入abstract
变成抽象类让子类来重写其中的内容
//这里有个动物的父类
public abstract class Animal{
//在这个动物类中,它的子类动物,它们吃的东西不一样我们不能描述清楚所以需要让他的子类的重写描述这个方法
//因为需要变成抽象类来让它的子类来描述吃东西
public abstract void eat();//抽象方法一定要放在抽象类中
public void drink(){
sout("喝水");
}
}
//猫
public class Cat extends Animal{//一继承抽象类就会出现波浪线要求重写其中的抽象方法
@Overdel
public void eat(){
sout("吃鱼");
}
}
public class Dog extends Animal{
public void eat(){
sout("吃肉");
}
}
//测试
Cat c = new Cat();
c.eat();
Dog d = new Dog();
d.eat();
结果:
吃鱼
吃肉
分析:在上面的案例就可以知道了,抽象方法就是父类中描述不清的方法也就是继承他的自己子类有各自不同的描述,就需要加上抽象方法来让子类自己重写对应的描述,然后要在类中也变成抽象类,这样当引用的时候才会告知子类去重写该方法。
抽象类的注意事项:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ayn4qKxB-1654725363466)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析理解:
1.抽象类不能实例化:因为如果可以实例化说明就可以访问类中没有实例方法的方法体没有意义(如:因为抽象方法没有方法体,如果可以实例抽象类那么就可以访问到没有方法的抽象方法这样没有意义所以不能被实例化)
2.首先抽象方法中没有方法体如果放在不是抽象类中,那么别人访问这个类中的抽象方法发现里面没有方法体这就没意义,所以抽象方法一定要放在抽象类,其次抽象方法无方法体需要继承这个类的子类去完成其中的方法内容,所以父类也要变成抽象类,让他的子类知道去重写该抽象方法,因此抽象类不一定有抽象方法,但是抽象方法一定要在抽象类中。
3.抽象类是由构造方法的,因为他的继承他的子类方法中都默认调用了super()
模板设计模式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VJ0yG8Ek-1654725363467)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//模板设计模式
public abstract class zuowen{
public void write(){
sout("《梦想》");
body();
sout("这就是我的梦想");
}
public abstract void body();
}
public class Tom extends zuowen{
@Overidel
public void body(){
sout("内容!!!!!!!");
}
}
//测试:
Tom t = new Tom();
t.write();
//结果
《梦想》
内容!!!!!!
这就是我的梦想
分析:以上代码,就是一个模板设计模式的典型,子类继承了父类完成其中的要求重写的方法,类似小学生写作文标题和结尾都需要一致但是中间的内容需要自己去编写的,这种就是模板设计模式有一个模板在那里只需要加入自己不同的内容。在代码是如此抽象类就是一个模板我们则需要去编写其中的抽象方法就得到一个通过模板完成。
Final关键字:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-24rkUZul-1654725363467)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Final修饰变量:
1.基本数据类型变量:其值不能被更改
2.引用数据类型变量:地址值不能被更改,但是可以修改对象的属性值
//基本数据类型不能更改值
final int a = 10;
a=20;//报错 因为a被Final修饰是定为一个最终值,所以不能给他重新赋值
//引用数据类型:
final Student stu = new Student();
stu.setName("haha");
stu.setName("qiqi");
stu = new Student();//报错! stu被final修饰后,指向的地址不能改变,但是他的属性可以修改
Final修饰成员变量:
1.在创建时直接赋值(推荐)
2.在调用构造方法时赋值
//1.在创建时直接赋值(推荐)
public class Student{
final int a = 10;
}
//2.在调用构造方法时赋值
public class Student{
final int a;
public Stundet{
a = 10;
}
}
代码块:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-23GcMQ6y-1654725363468)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//局部代码块
public class student{
public void esa(){
{
int a = 10;
sout(a);
}
sout(a);//这里就访问不到a因为他在局部代码块内执行完会就消失代码块外的无法访问
}
}
//构造代码块
public class Tom{
private int a ;
{
sout("hahaha");
}
public Tom(int e){
a = e;
}
public Tom(){
}
}
//测试:
Tom t = new Tom();
Tom s = new Tom(3);
sout(s)
//结果:
hahaha
hahaha
3
//分析:根据结果可以看出,构造代码块构造方法每执行一次他都会执行一次
//静态代码块
public class Tom{
private int a ;
static{
sout("hahaha");
}
public Tom(int e){
a = e;
}
public Tom(){
sout("11");
}
}
//测试
Tom e = new Tom();
Tom s = new Tom(2);
sout(s)
//结果:
hahaha
11
2
//分析:静态代码块只执行一次因为他是和类字节码文件一起创建的,字节码文件只创建一次不会在创建所以他只能执行一次
接口:
当类中的所有方法都是抽象方法时改类就可以定义为一个接口!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IaKsG7IF-1654725363468)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H2CKW78M-1654725363468)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
JDK8版本中成员的特点:
例子:
假设有一个版本已经上线,接口中与一个抽象方法,但是更新版本后需要加入两个抽象方法,如果按照之前的方法添加,其他方法实现该接口的类就会全部报错然后需要实现新添加的方法。
这样在JDK8中提供了一个解决方法,就是给新添加的抽象方法添加上一个default
默认方法,这样就不会变会出现报错的情况,且也可以使用**注意:**该类如果实现了多个接口,且名称一样,那么就会出现报错
public interface StudentMapper{
int add(Stu stu);//这个是第一个版本中的方法
default int delete(int id){
sout("删除了:"+id+"信息")
};//这是后面添加的
}
class StudentMapperImpl Implment StudentMapper{//上面加了default这里就不会报错显示添加更新后的抽象方法
int add(Stu stu);
@Overidel //如果需要修改添加的新功能也可以这样在实现类中进行一个修改
int delete(int ie){
sout("准备删除:"+ie)
}
}
//test
StudentImpl stu = new StudentImpl();
stu.delete(1);//这就可以直接调用
分析:这个特性就有利于版本更新后我们在原先的接口中添加新方法后,之前实现该接口的类不会出现报错(这里的报错是要求重写抽象方法),方便调用在需要的位置,不会导致前一个版本的混乱问题。如果出现了过个接口,方法名一样的但是答应的逻辑不一样,这样就会报错。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j3Lj7tVF-1654725363469)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
第二点:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J6xiBreE-1654725363469)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
public interface stumapper{
public static void tt(){
sout("haha");
}
}
public class stuee implments stumapper{
}
//测试
Stuee sut = new Stuee();
sut.tt();//这里报错,因为静态的方法在接口中就算是实现类去实现了其中的方法也无法调用接口中的静态方法的
stumapper.tt();//这样才能够调用 接口名调用
分析:接口中允许定义静态方法,如果在实现类中实现了该类,当实现类被实例化也无法调用接口中的静态方法的,接口中的静态方法只能被接口名来调用如上
JDK9版本中成员特点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kemIbTZQ-1654725363470)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
jdk9中接口可以定义私有的成员方法
//如接口中有两个重复的内容
public default void j(){
loe();
System.out.println("start执行了!");
}
default void k(){
loe();
System.out.println("end执行了");
}
private void loe(){//重复的内容可以使用private将重复的抽取出来然后上面引用
System.out.println("日志");
}
public static void stat(){//静态方法也一样的
log();
System.out.println("starat开启");
}
public static void end(){
log();
System.out.println("end开启");
}
private static void log(){
System.out.println("ha");
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OK0Bn54m-1654725363470)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
在jdk9中,如果接口中的方法有共同点的可以抽取出来
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ItXgp1w7-1654725363471)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
类和接口的关系
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dPnXkHNM-1654725363471)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
如果直接父类出现了与实现接口的相同的方法声明,但代码逻辑不一样,那么首先调用的父类逻辑,其次是接口实现的
接口与接口直接可以多继承,但当继承的接口中出现了相同的方法声明,那么就会报错,因为不知道要执行哪一个,说一需要在子接口中重写这个同名的方法就可以解决了
多态
同一个对象,在不同时刻表现出来的不同形态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eawyO1YO-1654725363471)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//父类
class Animal{
public void eat(){
System.out.println("动物吃饭");
}
}
//子类
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
//测试
Cat cat = new Cat();
cat.eat();
Animal animal = new Cat();//父类指向子类对象
animal.eat();
//结果:
猫吃鱼
猫吃鱼
分析:多态的前提是需要子类继承父类且子类重写了父类方法,父类的指向子类实例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sS7rXpcs-1654725363472)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//父类
class Animal{
int num = 10;
public void eat(){
System.out.println("动物吃饭");
}
}
//子类
class Cat extends Animal{
int num = 20;
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
//测试
Animal a = new Cat();
//这里输出了父类中的num,说明父类引用指向子类对象时,当两个类中有相同的成员变量会调用的父类的
sout(a.num);//输出为10
//*************************************
Animal a = new Cat();
//这里输出了子类中的eat,说明父类引用指向子类对象时,当两个类中有相同的成员方法会调用的子父类的
a.eat();//这里执行的是猫吃鱼
分析:在父类引用指向子类的时候,两类若有相同的成员变量,调用出来的是父类中的成员变量,因此编译时候看父类****,执行也是看父类
若两类中有相同的成员方法,使用的时候则是调用的子类的成员方法因为父类与子类的方法直接存在重写所以,编译的时候看父类,执行的时候看子类。
多态的好处与弊端
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RqkMiGG1-1654725363472)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
public class Animal{
abstract void eat;
}
public class Cat extends Animal{
void eat(){
sout("猫吃鱼")
}
}
public class Dog extends Animal{
void eat(){
sout("狗吃肉");
}
void drink(){//这个方法无法执行,这就是多态的弊端,在父类引用指向子类对象的时候会先看父类有无该方法有才能执行子类中的方法无法被查看到所以就算Animal 指向了Dog也无法执行到drink方法
sout("喝水")
}
}
//测试
showAnimal(new Cat());//这里使用了多态后我们只需要传一个子类进去就可以访问cat中的eat方法,若不用多态就需要创建出两这样的方法 才能完成同样的操作
public static void showAnimal(Animal a){//这里相当于 Animal a = new Cat();
a.eat();
}
分析:
优点:当有一个方法需要动物类中每个动物的吃的东西,就需要创建一个方法每次都传近对应的动物才能获得他的eat方法,如果直接将对应的动物变成它们的父类,这样就可以不管创建什么样的动物都可以执行到它的eat方法不要多于创建一个方法。
弊端:当子类自己写方法父类中没有时,子类的该方法就无法被调用到。因为编译看的父类,执行才看的子类,说明会先看父类的所有方法,如果发现子类有重写就输出子类的方法,如果发现没有被重写那么就输出的父类的方法。
多态中的转型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OW5app3h-1654725363473)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
class Animal{
public abstract void eat();
}
class Cat extends Animal{
void eat(){
sout("吃鱼")
}
void drink(){
sout("喝水")
}
}
//测试
Animal a = new Cat()//向上转型
//那么什么时候使用向下转型呢?
//当想调用子类中特有的方法时候就可以使用向下转型
Cat c = (Cat)a;
c.drink();//结果: 喝水
分析:父类引用指向子类对象为向上转型,但是不能调用子类中的方法,因为编译的时候先看父类有什么方法然后看看子类有没有重写再去执行,所以子类的方法无法使用。
向下转型:当想使用子类中的方法时可以使用父类引用转向子类对象就可以使用子类中的方法了。
多态中转型存在的风险:
public static void test(Animal a){
//这里是直接将猫对象转为狗对象则出现了报错,那么如何来避免呢?
//instanceof 来判断类型在进行向下转型
if(a instanceof Dog){//这样就会判断变量是否与类型相符相符才执行向下转型
Dog d = (Dog)a;
a.drink();
}
}
//测试
test(new Cat());//这里传入一个猫对象
//解决
//方法
static void shouanimak(Animal a){
a.eat();
if(a instanceof Dog){
Dog d = (Dog) a;
d.play();
}
if(a instanceof Cat){
Cat c = (Cat) a;
c.drink();
}
}
//输出:
shouanimak(new Cat());//结果: 吃鱼 喝水
shouanimak(new Dog());//结果: 吃肉 玩
分析:像上例子,可以通过instanceof来判断变量是否与指定类型相同。
内部类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F8fp5xSc-1654725363473)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
内部类:就是在一个类中定义一个类,举例:在A类中定义一个B类,B类就被称为内部类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ybpo3Llu-1654725363474)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
class lisi{
private int es = 30;
class wangwu{
int ee = 20;
void show(){
System.out.println(ee);
System.out.println(es);
}
}
//测试:
//调用成员内部类
lisi.wangwu es = new lisi().new wangwu();
es.show();
//结果:
20
30
分析:当使用成员内部类的时候创建方法为 类名.成员内部类名 变量名 = new 类实例.new 成员内部类实例,这样才可以调用成员内部类中的方法。
成员内部类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cjCweZTr-1654725363474)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//私有成员内部类的访问
class Yo{
private class Ke{
int a = 10;
}
public void method(){//创建该方法来访问私有化的成员内部类
Ke k = new Ke();
System.out.println(k.a);
}
}
//测试:
Yo.Ke e = new Yo().new Ke();//无法获取到
Yo y = new Yo();
y.method();
//结果:
10
分析:当成员内部类加了private
私有化后,就想上面例子的e无法读取到被私有的内部类,只能通过创建一个方法来内部读取该私有类才能读取到。
//静态成员内部类
class Stu{
static class Xe{
void ee(){
System.out.println("esa");
}
static void method(){
System.out.println("哈哈");
}
}
}
//调用静态成员内部类
//类名.静态内部类名 变量名 = new 类名.静态类名();
Stu.Xe xe = new Stu.Xe();
xe.ee();
//类名.静态类名.方法名
Stu.Xe.method();
分析:当内部类是静态内部类的时候调用方法就改变了上面使用的,
局部内部类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rZ6relR9-1654725363474)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
class Stu{
int a = 10;
void method(){
int b = 20;
class He{//这就是局部内部类
void show(){
System.out.println("这是一个局部内部类");
System.out.println(a);
System.out.println(b);
}
}
He e = new He();
e.show();
}
}
//测试
Stu stu = new Stu();
stu.method();
//结果
这是一个局部内部类
10
20
分析:在上面例子,He是局部内部类,因为它在类中的方法内的一个类,外面是无法调用到的,只能通过方法内部调用,该局部内部类可以访问方法中的变量也可以访问Stu中的变量。
匿名内部类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9kmVpzCO-1654725363475)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//接口
interface Stu{
void show();
}
//实现类
class Ste implements Stu{
@Override
public void show() {
System.out.println("普通方法!");
}
}
//测试中:
Ste ste = new Ste();//这是通过普通方法创建的需要创建实现类来实现接口编写接口中的方法然后再调用
ste.show();//普通的方法需要编写实现类重写方法然后调用创建对象实例来调用
new Stu(){//匿名内部类将实现接口重写方法和创建对象一步完成
@Override
public void show() {
System.out.println("这是匿名内部类");
}
}.show();
//结果:
普通方法!
这是匿名内部类
分析:匿名内部类可以更加的方便,是直接将接口中的抽象方法重写然后自动创建一个对象一步到位,之前的方法则需要到实现类中实现****接口中的方法然后再能调用,这里的匿名内部类就一步到位,实现接口、重写方法、创建对象一步完成。
匿名内部类的应用场景:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-giBbYD0C-1654725363475)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
当发现方法中所需要的参数是一个实现类就可以使用这个方式
//匿名内部类的方法
//接口
interface Swim{
void GOto();
}
//方法
//这里需要传入的是Swim的一个实现类,如果使用普通的方法就需要创建一个实现类去实现接口然后重写方法在测试中实例该实现类,在放入该方法中这样才能完成,但是如果使用了匿名内部类,直接在传入的参数中编写完成一步到位。
public static void WantTo(Swim swim){
swim.GOto();
}
WantTo(new Swim() {
@Override
public void GOto() {
System.out.println("去有用吧");
}
});
//结果:
去有用吧
分析:当方法中需要传入的参数是接口实现类的时候就可以使用匿名内部类的方法,直接在传参数位置编写匿名内部类即可,也可以使用实现类的方法去编写实现类然后实例化话实现类,放入也可行,只不过匿名内部类更加的方便。
Lambda表达式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-852C8FpA-1654725363476)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//Lambda表达式
interface Stu{
void method();
}
//
static void gow(Stu stu){//这里相当于 Stu stu = new Stu();
stu.method();
}
// 测试
//下面使用了Lambda
gow(()->{
sout("hahaha")
})
//结果
hahaha
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KYaPRjXU-1654725363476)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Lambda表达式的标准格式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9TgFsUh6-1654725363476)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
练习:
//Lambda操作带参数无返回值的方法
interface StringHandler{
void method(int a );
}
public static void useHandler(StringHandler hd){
hd.method(3)
}
//测试
//省略前
userHandler((int k ) -> {//这是使用了Lambda来实现的带有参无返回值的
sout("输入了"+k);
})
//省略后
userHandler(k -> sout("输出了"+k))
//下面的匿名内部类来完成的
usetHandler(new StringHandler(){
@Overdiel
public void method(int a){
a = 3;
sout("这是匿名内部类:"+a)
}
})
//结果
3
3
//Lambda无参带有返回值的方法
interface Randen{
int method();
}
//测试
useStringHandler(() -> {
Random random = new Random();
int i = random.nextInt(10) + 1;
return i;
});
}
static void useStringHandler(Randen e){
int method = e.method();
System.out.println(method);
}
//结果:
6
分析:上面案例当是无参有放回值的方法时,注意有返回值一定要加return
不然会报错.
//Lambda有参有放回值
interface Calcutor{
int calc(int a,int b);
}
//测试
public static void useCacu(Calcutor calcutor){
int calc = calcutor.calc(3, 4);
System.out.println(calc);
}
//***********************************************
//省略前
useCacu((int e ,int k) ->{
int i = e + k;
return i;
});
//省略后
useCacu((e,k) -> e+k)
//结果:
7
//Lambda表达式
interface Calcutor{
double mehod(double a,double b);
}
//测试
//省略前
useCal(( k, j) -> {
return k+j;
});
}
//省略后
//首先带有两个参数,括号不能去掉,其次里面只有一行代码大括号可以去掉剩下下面的
useCal((k,j) -> k+j);
static void useCal(Calcutor calcutor){
double mehod = calcutor.mehod(2.5, 3.7);
System.out.println(mehod);
}
//结果:
6.2
Lambda省略模式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Tg1fNZ4-1654725363477)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
回顾:看上面案例!可以知道,当使用Lambda表达式的时候,若参数只有一个可以省去参数的类型,代码只有一条可以去掉大括号还偶有return。
Lambda表达式和匿名内部类的区别:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BqakXDLd-1654725363477)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
常用API&异常
API基本使用
什么是API:应用程序接口
简单来说:就是JAVA帮我们已经写好的一些方法,我们直接拿过来用就可以了
Math 类概述
Math包含执行基本数字运算的方法
//public static int abs(int a) 返回参数的绝对值
int i = Math.abs(-10);
sout(i);//输出 为10
//public static double ceil(double e) 向上取整
double ceil = Math.ceil(9.1);//这个方法多0.1都会向上取整
System.out.println(ceil); //结果 10
//public static double floor(double e)向下取整
double floor = Math.floor(9.1);
System.out.println(floor);//结果 9
//public static int round(float a ) 四舍五入
long round = Math.round(3.4);
System.out.println(round);//结果 3
//public static int max(int a,int b ) 返回两个数中的最大值
int max = Math.max(1, 3);
System.out.println(max);//结果 3
//public static int min(int a,int b ) 返回两数的最小值
int max = Math.max(1, 3);
System.out.println(max);//结果 1
//public static double pow(doubl a,double b) 返回a的b次幂值
double pow = Math.pow(2, 3);
System.out.println(pow);//结果 8
//public static double random() 返回值为double的正值,[0.0,1.0)
double random = Math.random();
System.out.println(random);//结果 0.7057794534635693
System类概述:
System不能被实例化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hhrg04RS-1654725363478)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//public static void exit(int status) 终止当前虚拟机
System.out.println("11111");
System.exit(0);//这一步就终止了虚拟机的运行,后面的2222就无法输出了
System.out.println("22222");
//结果
111111 //程序中已使用了()就会停止虚拟机
//public static long currentTimeMillis() 返回当前时间(以毫秒为单位)
long l = System.currentTimeMillis();//这个方法之前说过,可以获得当前的时间以秒为单位的
System.out.println(l);
//arraycopy(数据源数组,起始索引,目的地数组,起始索引,拷贝个数) 数组copy
int arr[] = {1,2,3,4,5,6};
int arr1[] = new int[10];
System.arraycopy(arr, 0, arr1, 0, arr.length);//这里就是将arr数组中下标为0的数组拷贝到arr1中下标为0开始,最后是拷贝的个数
for (int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);
}
//结果:
1
2
3
4
5
6
0
0
0
0
分析:如果需要停止虚拟机可以使用(0)
,想获得当前的时间的话可以()
来获取当前的时间以秒为单位,arraycopy()
用于拷贝数组
Object类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LnftzZ84-1654725363478)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Student stu = new Student();
sout(stu);
//结果
com.bjpowernode.test2.SS@330bedb4
//若想要输出的不是地址值可以在类中重写toString方法就可以输出实际值
//从写tostring;
@Override
public String toString() {
return "SS{" +
"token operator">+ id +
", name='" + name + '\'' +
'}';
}
//测试
Student s1 = new Student(1,"xiao");
sout(s1);
//结果:
1 xiao
分析:因为我们的stu实体类如果没有继承父类的话,系统默认是继承了*父类object,当在类中重写toString 方法就可以获得的是类中的值而不是地址值了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XG6rON0l-1654725363479)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F9FkIFqu-1654725363479)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
objcet常用的方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wg2utPKv-1654725363479)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
public class Student{
private int id;
private String name;
}
//测试
Student stu = new Student(1,"小");
Student stu2 = new Student(1,"小");
sout(stu == stu2);//这里要知道 等号比较引用类型时是比较的地址
sout(stu.eqauls(stu2));//这里的值为:false 为什么呢?因为在object中equals也是通过==来比较的地址值的;
//---------------------------------------------------------------
//当我们在Student类中重写Object中的equals时就是对比的类中中的值
//在类中重写了equals方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SS ss = (SS) o;
if (id != ss.id) return false;
return name != null ? name.equals(ss.name) : ss.name == null;
}
//测试
Student s1 = new Student(1,"xxx");
Student s2 = new Student(1."xxx");
sout(s1.equals(s2));//这里返回true;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rEsfOKZw-1654725363480)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:在这里可以知道,当类中没有重写equals时,调用的object的equals对比的时候其内部就是通过==来对比的,也是对比的地址值。
当在类中重写了equals时就可以通过对象中的值进行对比了而不是地址值。
object面试题:
String s1 = "abc";
StringBuilder s2 = new StringBuilder("abc");
sout(s1.equals(s2));//false
sout(s2.equals(s1));//false
分析:第一个false 因为String
中重写了objcet
中的equals
方法,是将对比的参数先判断是否为String类型,若不是String类型返回false,这里的s2是StringBuilder所以为false;
第二个false 因为stringbuilder
中没有重写object
中的equals
所以他对比的是地址值,s1的地址值是在字符串常量池中储存的,而s2的值是在堆内存中的两个的地址指向不同所以为false
objects类
objects常用方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DcifxC4E-1654725363480)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//public static String toString(对象) 返回参数中对象的字符串表示形式
SS xiao = new SS(1, "xiao");
String string = Objects.toString(xiao);//注意这里:若对象中重写了tostring则返回的对象中的tostring方法,无就返回的地址值
System.out.println(string);//有从写tostring 则为1 xiao 无就是地址值 包名+类名@ 内存地址
//public static String toString(对象,默认字符串) 返回对象的字符串形式
String s = null;
String string = Objects.toString(s, "我是一个字符串");
System.out.println(string);//这里返回 我是一个字符串
//这个方法通过底层可以看到,它是先判断对象是否为Null 为Null的话就返回的默认值,上面的默认值是我是一个字符串因为s为null
//public static Boolean isNull(对象) 判断对象是否为空
String s = null;
boolean aNull = Objects.isNull(s);//该方法用来判断对象是否为空,若为空就返回true,不为空就是false
System.out.println(aNull);//结果 为 true
//public static Boolean nonNull(对象) 判断对象是否不为空
String s = null;
boolean b = Objects.nonNull(s);
System.out.println(b);//结果 为 false
分析:以上的Objects
方法,第一个toString
默认是返回的地址值,若重写了toString
则返回修改后的值,第二个toString(object o ,默认值)
这个当前的对象为空时则返回的默认值,第三个isNull
字面意思来看就可以,判断传入的类是否为空的,第四个nonNUll
判断****对象是否不为空!。
BigDecimal
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-66So2JjE-1654725363481)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OxlfKIgZ-1654725363481)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//注意在进行精确计算的时候使用字符串的构造方法才能精确
//public BigDecimal add(传入参数需要的一个BigDecimal对象) 加法
BigDecimal s1 = new BigDecimal("1.2");
BigDecimal s2 = new BigDecimal("2.2");
sout(si.add(s2));//这里结果为 3.4
//public BigDeciaml subtract(传入参数为一个BigDecimal对象) 减法
BigDecimal s1 = new BigDecimal("1.2");
BigDecimal s2 = new BigDecimal("2.2");
sout(s1.subtract(s2));//结果 -1
//public BigDecimal multiply(传入参数为一个BigDecimal对象) 乘法
BigDecimal s1 = new BigDecimal("1.2");
BigDecimal s2 = new BigDecimal("2.2");
sout(s1.multiply(s2));//结果 0.03
//public BigDecimal divide(传入参数为一个BigDecimal对象) 除法
BigDecimal s1 = new BigDecimal("1");
BigDecimal s2 = new BigDecimal("2");
sout(s1.divide(s2));//结果 0.5
分析:在进行精确计算的时候,使用BigDecimal(String str)
这个构造方法才能精确,所以要完成精确的数可以使用该方法
BigDecimal特殊方法
//使用BigDecimal的divide方法时,如果出现除不尽就会报错刚刚我们也看到了
//解决方法
BigDecimal bigDecimal = new BigDecimal("1");
BigDecimal bigDecimal1 = new BigDecimal("2");
//进一法,若两数想除出来了 3.267则为3.28进以为,因为这里设置了保留两位小数
sout(bigDecimal.divial(bigDecimal,2,BigDecimal.ROUND_UP));//进一法
//去尾法:两数相除,3.267则为3.26 直接去掉了0.007;
sout(bigDecimal.divide(bigDecimal1,2,BigDecimal.ROUND_FLOOR));//去尾法
//四舍五入:在保留两位小数以外第三位小数按四舍五路进一: 3.267 为3.27 3.264 为3.26
sout(bigDecimal.divide(bigDecimal1,2,BigDecimal.ROUND_HALF_UP));//四舍五入
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1cjqW4L6-1654725363482)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:进一发 是保留的小数,若存在第三个小数则进一(例如这里 保留两位 3.267 进一就是 3.27);
去尾法 是保留的小数以外,若存在其余的小数则去掉
舍入模式 是保留的小数以外,若存在第三为小数,则按四舍五入
包装类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mrsEfzS8-1654725363482)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Integer类的概述和使用:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gljw9fRc-1654725363483)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UpQpdF1C-1654725363483)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ApA0A3Xa-1654725363483)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//测试 将String类型的"91 46 58 37 84"装换成Integer类型
String se = "91 46 58 37 84";
//这一步将空额为标识切开
String[] split = se.split(" ");
//这里创建int类型的数组
int[] arr = new int[5];
//循环获取里面的字符串
for (int i = 0; i < split.length; i++) {
//放入数组中即可
int i1 = Integer.parseInt(split[i]);//这里将获得的每个字符串装换为Int类型
arr[i] = i1;
}
数组高级操作
二分查找
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OFseRTHh-1654725363484)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:二分查找的前提是数组内的大小顺序是已经排好了,然后开始二分查询,就是去除数组中的中间值然后对比,该数比中间值大就舍去左边部分在右边寻同样的方法,定义下标最小和最大开始找中间值直到找到为止,如果查找的数大于max最大值就会返回-1
例子:找3这个值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ifLRmZYT-1654725363484)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
这里发现中间值5大于三,接着舍去右边,将max该为3,然后中间值就会变为1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZOfIW7EK-1654725363485)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
发现1所对应的值不是小于3所以舍去左边留下右边来查找直到找到为止
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vUUhfyN8-1654725363485)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
这就是二分查找的步骤流程
//实例二分数组
//首先定义一个int数组
//定义方法完成二分查找
public static int select(int[] a ,int num){
int max = a.length-1;
int min = 0;
while(true){
int mid = (max+min)>>1;
if(a[mid]>num){
max = min-1;
}elseif(a[mid]<num){
min = mid+1;
}else{
return mid;
}
}
}
//测试
int[] arr = {1,2,3,4,5,6,7,8,9};
sout(select(3,arr));//返回下标 2
冒泡排序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OD0HQbUh-1654725363486)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-93ZclrW3-1654725363486)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//方法
//外层循环是循环的次数
for (int i = 0; i < arr.length -1; i++) {
//内层循环的对比
for (int j = 0; j < arr.length -1-i; j++) {
if (arr[j]>arr[j+1]){
int temp = 0;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
//测试
int[] arr={5,8,1,7,3,4,9,6,2};
preSelet(arr);
//上面分析冒泡排序,不使用冒泡
int[] a = {10,9,8,7};
//这里我们就需要循环对比四个数要对比3次就得到一个最大数
for(int i = 0;i<a.length-1 ;i++){//这里的减一是不超出数组最大下标
if(a[i] > a[i+1]){
int temp = 0;
tep = a[i];
a[i] = a[i+1];
a[i+1]= temp;
}
}
//这里执行一次结果为
{9,8,7,10}//这里排序好了最大的数,但是并没有完全排完,还需要继续排序
//第二次
for(int i = 0;i<a.length-1-1 ;i++){
if(a[i] > a[i+1]){
int temp = 0;
tep = a[i];
a[i] = a[i+1];
a[i+1]= temp;
}
}
//结果
{8,7,9,10}
//第三次
for(int i = 0;i<a.length-1-2 ;i++){
if(a[i] > a[i+1]){
int temp = 0;
tep = a[i];
a[i] = a[i+1];
a[i+1]= temp;
}
}
//结果
{7,8,9,10}
//在上面就可以总结出每次都会找到一个最大值,但数组内数据有四个每次只能找到1个最大的第二次循环需要找到第二个打以此类推,每次循环都减去1,因为后面大小的不在需要进行对比
递归:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vAMMyN5H-1654725363487)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
private static int Dig(int i) {
if(i == 1){
return 1;
}else {
return i + Dig(i-1);
}
}
//测试
sout(Dig(100))
5050
//递归求阶层
int result = Jiec(5);
sout(result)
//方法
private static int JiEc(int i) {
//i ==1 就是出口
if(i == 1){
return 1;
}else {
//这就是递归的规则
return i * JiEc(i-1);
}
}
//分析:若传递过来的数据不为1就该数减一后继续调用该方法,知道数值为1才有的得数
//就 i*(i-1) 这里传递为5就是 5*(5-1)//判断不为1就继续调用 5*(4*(4-1))//直到i等于一为止
分析:内部先判断传入数据是否为1不为1就继续执行本身直到返回值为1
递归内存图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uiSoXutQ-1654725363488)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
快速排序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g4RrWywk-1654725363488)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XmkOJp6Y-1654725363488)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:快排就是拿数组的第一个数来做基数,从后往前和从前往后同时找比基础小的,先从后往前,若发现比基数小的就停下,前往后找比基数大的找到就前与后换位置,在进行问第一个数的查找能得到基数在数组中的位置以及知道基数左边的是比他小的,右边的是比它大的
//快排练习
private static void FastPai(int[] arr,int left,int right) {
int left0 = left;
int riht0 = right;
int baseNuberi = arr[left0];
while (left != right){//如果这里相等说明最右边的到最左边的值一样这就是说明了根据基数排序完毕
//从右往左找比基数小的值
while (arr[right]>= baseNuberi && right > left){//如果比基数大就减找比基数小的
right--;
}
//从左往右找比基数大的值
while(arr[left]<=baseNuberi && right>left){//比基数小的话就加加找比基数大的
left++;
}
int temp = arr[right];//到这里将比基数小的和比基数大的换位
arr[right] = arr[left];
arr[left] = temp;
}
//基数归位
int temp = arr[left];//换完就将基数放到 left与right相同的下标点
arr[left] = arr[left0];
arr[left0] = temp;
}
//测试
int[] arr = {6,1,2,7,9,3,4,5,10,8};
FastPai(arr,0,arr.length-1);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+",");
}
//结果
3,1,2,5,4,6,9,7,10,8,
//********************************************************************
//通过递归
private static void FastPai(int[] arr,int left,int right) {
if(right<left){
return;
}
int left0 = left;
int riht0 = right;
int baseNuberi = arr[left0];
while (left != right){
//从右往左找比基数小的值
while (arr[right]>= baseNuberi && right > left){
right--;
}
//从左往右找比基数大的值
while(arr[left]<=baseNuberi && right>left){
left++;
}
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
//基数归位
int temp = arr[left];
arr[left] = arr[left0];
arr[left0] = temp;
FastPai(arr, left0, left-1);
FastPai(arr, left+1,riht0);
}
//测试
int[] arr = {6,1,2,7,9,3,4,5,10,8};
FastPai(arr,0,arr.length-1);
for (int i = 0; i < arr.length; i++) {
System.out.print
(arr[i]);
}
//结果
1,2,3,4,5,6,7,8,9,10,
Arrays类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gA38eQBD-1654725363489)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//public static String toString(int []a) 返回指定数组的内容的字符串表示形式
int[] arr ={1,2,3,45,6,78,6};
System.out.println(Arrays.toString(arr));//可以将数组改成字符串形式输出
//结果
[1, 2, 3, 45, 6, 78, 6]
//public static void sort(int[] a)//按照数字顺序排列指定的数组
Arrays.sort(arr)//传入数组,可以根据数值的大小进行排序
sout(Arrays.toString(arr));//这里将排序好的数组输出为string形式
//结果
[1, 2, 3, 6, 6, 45, 78]
//public static int binarySearch(int[] a,int key) 利用二分查找返回指定的元素的索引,key为需要在数组中寻找的数值
//这个方法是要建立在数组顺序的排好的前提下,否则会出现负数
Arrays.sort(arr);//这里先给数组排序
Arrays.binarySearch(arr,45);//
//结果:
5
时间日期类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N6WxJ9tg-1654725363489)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Date类概述和构造方法
Date代表了一个特定的时间,精确到毫秒
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xJrqnQQ6-1654725363490)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//public Date() 创建一个Date对象,表示默认时间
Date date = new Date();//调用这个无参构造,它返回的是当前计算机中的时间
System.out.println(date);
//public Date(Long DATE) 创建一个Date对象,表示指定时间
Date date = new Date(3600 * 1000);
System.out.println(date);//这个返回的是计算机开始时间加上你输入毫秒的时间,这里输出的是1970年的世界
分析:使用Date无参构造的时候,需要注意返回的是计算机当前的时间,若计算机的时间调了2048年则返回的也是2048年的世界
使用Date(Long date)这个方法需要注意,参数是毫秒数,意味1970年计算机开始时间的毫秒加上你输入的毫秒所得的时间,注意:该时间在世界时间上加了8小时表示是中国的时间
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hiHusXtz-1654725363490)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Date 常用的成员方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r25Msxv3-1654725363491)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//public long getTime() 获取时间对象的毫秒值
//将当前的时间封装成一个date对象
Date date = new Date();
//将date对象读取其毫秒数 --------也就是将存入的时间按毫秒来计算
long time = date.getTime();
System.out.println(time);//结果 1653849120432
//public void setTime(long Time) 设置时间,传递毫秒值
//把当前计算机的时间封装成一个Date对象
Date date = new Date();
//修改时间,将原先存入的时间修改成0毫秒
date.setTime(0L);
//这里返回的是计算机1970年开始的世界
sout(date);
SimpleDateFormat概述:
这个类可以对Date对象,进行解析和格式化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lGxoV5ug-1654725363491)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:格式化就是将当前计算机的时间由英文转换你想要的格式输出,解析就是将时间转化成Date对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K1QIWs0g-1654725363492)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WBS6S8Ro-1654725363492)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//没有格式化前
Date date = new Date();
System.out.println(date);//结果: Mon May 30 04:46:16 CST 2022
//格式化后
//创建一个simpleDateFormat对象 英文意思简单的日期格式
SimpleDateFormat sdf = new SimpleDateFormat();//这里是默认的格式
//然后调用里面的方法
sout(sdf.format(sdf));//结果:22-5-30 上午4:48
//当想要改成自定义格式的时候
SimpleDateFormat sdt = new SimpleDateFormat(yyyy-MM-dd HH:mm:ss);//这里定义格式
//然后将Date对象放入
sout(sdt.format(date));//2022-05-30 04:55:07 然后输出就为定义好的格式
//**************************************************************************************
//解析
String sdw="2021-4-5";
SimpleDateFormat sdt = new SimpleDateFormat("yyyy-M-d");//注意 这里的格式要与需要解析的字符串格式一样
sout(sdt.parse(sdw));//结果 Mon Apr 05 00:00:00 CST 2021
分析:当格式化日期时,若没有定义格式,将采取默认的默认的格式,若想修改默认的格式可以在创建simpleDateFormat("格式")
写入格式,调用其中的方法format
传入日期输出后就为定义好的格式,当解析时,注意:simpleDateFormat
的格式要与字符串的格式一样才能进行一个解析,调用parse
传入字符串就可以完成对日期的解析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qT8iy5CA-1654725363492)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//练习秒杀
//先获取小贾与小皮的下单时间和秒杀开始以及结束时间创建成字符串类型
//小贾
String XJ = "2020年11月11日 0:03:47";
//小皮
String XP = "2020年11月11日 0:10:11";
//秒杀时间
String KS = "2020年11月11日 0:00:00";
//秒杀结束
String JS = "2020年11月11日 0:10:0";
//通过simpleDateFormat格式化后调用parse方法转换成计算机中的时间再调用getTime()获取毫秒值
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
//获取秒杀开始的时间
long KSS = simpleDateFormat.parse(KS).getTime();
//获取秒杀结束的时间
long JSS = simpleDateFormat.parse(JS).getTime();
//小贾秒杀时间
long XJM = simpleDateFormat.parse(XJ).getTime();
//小皮秒杀时间
long XPM = simpleDateFormat.parse(XP).getTime();
//判断小皮与小贾是否在该时间内,在就抢购成功否则就失败
if(KSS=<XJM && JSS>=XJM){
System.out.println("小贾抢购成功!");
}else {
System.out.println("小贾抢购失败!");
}
//结果
小贾购买成功!
小皮购买失败!
分析:如果涉及到时间的计算的时候,可以 先使用simpleDateFormat设定格式,然后通过parse来解析成计算机的那种格式再调用getTime来获取毫秒值。
JDK8新增的时间日期类
//下面是使用原来的Date类完成的添加时间
//秒杀开始时间
String KS= "2020年11月11日 0:00:00";
//若秒杀开始时间我们修改了11月10日开始则要在原来的时间上面修改日期
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
Date parse = simpleDateFormat.parse(KS);
System.out.println(parse);
//将时间换成毫秒
long time = parse.getTime();
//添加一天的时间 一秒等于一千毫秒,一分钟60秒,一天24小时这样加一天时间
long l = time + (1000 * 60 * 60 * 24);
//这里将添加完的时间放入Date中输出
Date date = new Date(l);
//得到修改后的世界
System.out.println(date);
//**************************************************************************
//JDK8新添加的特性
//秒杀开始时间
String KS= "2020年11月11日 00:00:00";
//用()解析字符创中日期的格式
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
//然后调用LocalDateTime这个类通过parse来解析传入字符串和解析的格式
LocalDateTime parse = LocalDateTime.parse(KS, dtf);//在这一步就获得了时间按格式获取并获得了毫秒
//这里输入要修改的时间 这里为添加一天的时间
LocalDateTime localDateTime = parse.plusDays(1);//这里他Local这个类中内部有个添加时间也就是上面的只不过他封装起来了
//
String format = localDateTime.format(dtf);//将添加完时间的类格式化输出
System.out.println(format);//结果 2020年11月12日 00:00:00
分析:新特新的添加时间,与原本的优化了代码和实现步骤,创建字符创的接收格式,然后和调用(字符串,格式)传入对应的字符串和需要的格式传入进去,然后调用它内部的plusDays来添加时间该类中也有月、分、秒等,最后再调用();这样就是将原先的时间传入在此基础上加一输出值就是一天后。
JDK8新的时间类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jDKLfeoT-1654725363493)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:JDK8中Date分为了三种,有可以只输出年月日的、时分秒的以及全部输出的,在原先的版本只能获取默认的时间也就是年月日时分秒全部输出。在这里它讲时间拆分的更加细致。
LocalDateTime
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IqKWZk5T-1654725363494)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//获取具体的年月日时分秒的日期
LocalDateTime now = LocalDateTime.now();
System.out.println(now);//这里为计算机当前的时间为 2022-05-30T20:02:43.960
//这里的获取时间以年、月、日、时、分、秒输入进去就可以自定义时间
LocalDateTime of = LocalDateTime.of(2021, 11, 11, 11, 01, 01);
System.out.println(of);//这里为刚输入的日期 2021-11-11T11:01:01
//旧版本的创建全部时间 这个还可以使用
Date date = new Date();//这里他默认的就是本地时间
sout(date);//结果是 Mon May 30 20:05:14 CST 2022
//旧版本的自定义时间 (现在不建议使用)
Date date = new Date(2020, 11, 11, 00, 00, 00);
System.out.println(date);//结果 Sat Dec 11 00:00:00 CST 3920
LocalDateTime成员方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bq6fbpd9-1654725363494)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//设置时间
LoalDateTime ldt = LocalDateTime.of(2020,11,12,15,15);
//public int getYear() 获取年
int year = ldt.getYear();
sout(year);//获取当前时间的年份
//public int getMonthValue() 获取月份(1-12)
int Month = ldt.getMonthValue();
sout(Month);//获取当前时间的月份
//public int getDayOfMonth() 获取月份中的第几天(1-31)
int DayofMonth = ldt.getDayOfMonth();
sout(DayogMonth);// 获取当天在该月的第几天
//public int getDayOfYear() 获取一年中的第几个月
int dayoFMONTH= ldt.DayOfMonth();
sout(dayoFMONTH);//获取当前月份在当年的第几个月
//public DayOfWeek getDayOfWeek() 获取星期
DayOfWeek dayofweek= ldt.getDayOfWeek();
sout(dayofWeeK);//获取当天是星期几
//public int getMinute() 获取分钟
int minute = ldt.getMinute();
sout(minute);//获取当前时间的分钟
//public int getHour 获取小时
int hour = ldt.getHour();
sout(hour);//获取当前时间小时
分析:LocalDateTime
可以获取将获取的时间分成年、月、日,星期都可以获取出来
LocalDateTime转换方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t0pmtmC2-1654725363495)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
LocalDateTime sdt = LocalDateTime.of(2020,11,11,1,30,45);
//public LocalDate toLocalDate() 装换成一个LocalDate对象
LocalDate date= sdt.toLocalDate();
sout(date);//获取该对象中的日期
//public LocalTime toLocalTime() 转换成一个LocalTime对象
LocalTime lat = sdt.toLocalTime();
sout(lat);//获取到该对象中的时间
//结果:
2020-11-11
01:30:45
分析:上面的两个方法就相当于把传入的时间对象可以分开,分别获得其中的时间和其中的日期
LocalDateTime解析和格式化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-INCwIdGY-1654725363495)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//JDK8 格式化
LocalDateTime of = LocalDateTime.of(2020, 11, 11, 12, 30, 45);
//设定格式
DateTimeFormatter sdt = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
//将需要格式化的时间放进format中
String format = sdt.format(of);
//输出
System.out.println(format);
//结果:
2020年11月11日 12:30:45
//*****************************************************************************************************
//解析
String se = "2020年11月 20日 12:30:45";
//定义解析的数据类型
DateTimeFormatter date = DateTimeFormatter.ofpatter("yyyy年MM月dd日 HH:mm:ss");
//调用LocalDateTime中的parse来解析 第一个参数为需要解析的字符串 第二个参数为字符串的格式
LocalDateTime dat = LocalDateTime.parse(se,date);
//输出
sout(dat);//结果:2020-11-20T12:30:45
分析:在格式化和解析的时候都需要调用日期时间格式化程序也就是DateTimeFormatter
然后调用他的OfPattern()
输入自己的格式,再将格式化的对象引用format
将需要格式化的类型放入就可以格式化了。
解析也是一样,创建一个日期时间格式化程序调用根据字符串的格式定义,接着调用LocalDateTime
中的parse
再将需要解析的字符串和他的格式的放入,就可以解析一个字符串了。
LocalDateTime增加时间和减少时间
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nSlqQDXo-1654725363495)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//先获取LocalDateTime对象
LocalDateTime ast = LocalDateTime.of(2020,11,11,12,34,56);
//修改后的时间在原来的技术上面加了一年
LocalDatrTime asg = ast.plusYeats(1);//这个方法可以添加正数也可以添加负数
sout(asg);//结果:2021-11-11T12:34:56
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9kAmqeve-1654725363496)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7wPnD21V-1654725363496)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:在获取的时间中可以修改年份时间等,加号就是在原来的年份或则月份中加一年或一个月,减号就是减去一年或则一个月,这就比较好理解了,就是可以拿修改时间
LocalDateTime第二种方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aQhXdstH-1654725363497)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:这与上面的PLUS
一样可以增加减少时间,不过这里是反过来的,传入正数的减去时间,负数的增加时间,两者会一种就可以了。推荐plus比较好理解
LocalDateTime修改时间
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BTWYsWnU-1654725363499)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//LocalDateTime withYeat(int year)
LocalDateTime dateTime = LocalDateTime.of(2020, 11, 11, 12, 30, 45);
LocalDateTime localDateTime = dateTime.withYear(2048);//将年份改为2048年
System.out.println(localDateTime);//输出: 2048-11-11T12:30:45
分析:在LocalDateTime中带有with的都是直接修改的内容,注意:需要传入正确值,否则报错
Period类
该类翻译为时期,也就是拿来获取两个时期直接的间隔
下面的方法可以获得两个时间间隔的对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GKMu4qEz-1654725363499)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:这个类是用来计算两个时间的年月日之间的间隔如2022.11.11到2023.11.11这其中的间隔是多久,就可以用Period
中的between来传入两个LocalDate
就可以计算出来。
//使用Period来计算两个时间的间隔 时间是年月日的
//创建来个时间日期
//开始时间
LocalDate date = LocalDate.of(2020, 11, 12);
//结束时间
LocalDate date1 = LocalDate.of(2022, 1, 10);
Period between = Period.between(date,date1);
sout(between);//这里获得结果:P1Y1M29D 这结果中的Y前面的数表示间几年年M表示几个月份D表示几天 也就是间隔几年另几个月与几天
System.out.println(between.getYears());//结果: 1年
System.out.println(between.getMonths());//结果: 1个月
System.out.println(between.getDays());//结果: 29天
//也就表示两个时间间隔为 1年1月29天
分析:这个类是可以拿来算出两个日期之间的间隔的。
Duration类
该类翻译为期间,也就是拿来获取两个时间之间的一个间隔
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bwXHWYVj-1654725363499)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//Duration 用来获取时间的间隔计算的是天、小时、分钟、秒
LocalDateTime time = LocalDateTime.of(2020, 11, 12,10,30,20);
LocalDateTime time1 = LocalDateTime.of(2020, 11, 12, 12, 35, 20);
Duration betwee = Duration.between(time, time1);//这里输出 PT2H5M
System.out.println(betwee.toDays());//0 间隔0天
System.out.println(betwee.toHours());//2 间隔两个小时
System.out.println(betwee.toMillis());//7500000 两个时间断间隔7500000毫秒
System.out.println(betwee.toMinutes());//125 说明两个时间段的间隔为125分钟
分析:Duration可以用来计算两个时间之间的小时差,分钟差和毫秒差等。
小结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ADIaoCku-1654725363500)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PFJcElqg-1654725363500)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
异常类
异常类的概述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6tbLZhef-1654725363501)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:也就是代码在运行期间出现报错,jvm就会把异常的信息输出在控制台,并且异常后面的代码无法执行。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gop9PgOt-1654725363501)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:上面也就紧接着说明了这一结论
异常类处理方式
throws
用来声明异常,告诉调用者该方法可能出现的异常
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TVlT5Bjn-1654725363501)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//throw异常
//方法一
//throws相当于告诉调用者该方法会出现异常后面加的是异常类型
//如果方法中没有异常就正常执行
//如果方法中有异常就会抛出去给调用者处理
public static void method() throws NullPointerException{
int[] arr = null;
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
//方法二
public static void method1() throws ParseException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
simpleDateFormat.parse("2020-11月20日");
}
//测试
method();//这里调用者没有处理这个异常,就是交给了虚拟机jvm来处理,jvm就会输出异常信息和段落位置并且停止后面的代码运行
method1();
//分析:两个方法都会出现报错,在方法的类名后面添加上了throws 就是代表这告诉调用者该方法可能会出现异常如上面的空指针和解析异常
分析:在看了throws
就说明该方法可能出现异常后面加的是异常的类型,使用了throws相当于把异常抛出去给调用者处理,如果调用者没有处理就默认的是给JVM虚拟机来处理,虚拟机就会答应异常的内容以及异常的段落,并且暂停异常后面代码的执行。
声明异常的注意事项:
如果声明时期的异常是运行时期的一次忽略不写,但如果是编译时期的异常就必须声明异常!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aWZDNXQB-1654725363502)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:代码是先编译在运行的,在编译时期就会去检查异常并且处理,运行期间是代码在运行时才会发生的所以可以不写
//在看源码中可以看到NullPointerException 继承的是 RuntimeException运行时期异常 方法中可以忽略不声明异常
public static void method(){
int[] arr = null;
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
//但是如果是编译时期的异常就必须要声明
//这里看源码看到ParseException解析异常 继承的是 Exception编译时期异常 方法中就必须声明异常
public static void method1() throws ParseException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
simpleDateFormat.parse("2020-11月20日");
}
验证图:
运行时期的异常不声明异常
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FA19IxU4-1654725363502)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
编译时期不声明异常
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7LqQ9CAP-1654725363503)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
总结:通过两个对比可以知道,异常分为运行时期异常和编译时期的异常,运行时期的异常可以忽略不声明,但是编译时期的异常就必须声明异常。
throw
自己创建一个异常处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rq93Lf15-1654725363503)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
System.out.println("HHH");
System.out.println("KKK");
System.out.println("EEE");
throw new RuntimeException();//在这里创建了一个运行时期的异常对象
//该异常创建之后暂时没有手动处理,而是抛出给调用者处理
//下面代码不会执行
System.out.println("ggg");
throws与throw的区别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vpbjT9jP-1654725363504)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
抛出异常的意义
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VUzgFDH7-1654725363504)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//抛出异常的意义
private static void PrintArr(int[] arr) {
if(Objects.isNull(arr)){
// ("数组不能为空~");//在这里 判断该数组是否为空为空在控制台输出了数组不能为空,但是调用者不知 道出现异常所以这里就需要创建一个异常对象告诉调用者
thorw new RunTimeException(); //这里手动创建一个异常对象,抛给调用者
}else {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
//测试
int[] arr = null;
PrintArr(arr);//这里调用者就会收到一个异常 ,我们还需要自己处理异常
分析:上面的案例就说明在判断为空的时候输出的语句在控制台,调用者是不知道发生异常的,所以就需要手动创建一个异常对象抛出去给调用者处理。
try…catch
用来捕捉异常并且自行处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BbETSAD6-1654725363504)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
private static void PrintArr(int[] arr) {
if(Objects.isNull(arr)){
throw new RuntimeException();//创建异常对象,抛出给调用者处理
}else {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
//测试
int[] arr = null;
try{ //这里是将可能出现异常的代码放入来捕捉异常
PrintArr(arr);
}catch(RunTimeException e){//捕捉异常的类型
sout("数组不能为空!");//出现捕捉到对应类型的异常就手动输出异常原因 这里就不会调用JVM的默认处理了
}
//使用了try...catch..来捕捉异常不影响后面代码的执行
sout("我还能运行");
//结果:
数组不能为空!
捕捉后我还能运行
分析:在调用时出现异常可以使用try…catch(异常类型)… 将可能出现异常的代码放入try中catch就会来捕捉可能出现的异常,一捕捉到就或输出catch中的内容,这个过程并不会影响后面代码的执行,这样就是手动的处理异常并且不会调用JVM默认处理。
try…catch…常见问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vrKesK78-1654725363505)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//如果try中没有遇到问题,怎么执行? ---- try正常执行catch中的代码不会执行看下面例子
try {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入字符");
String s = scanner.nextLine();
int i = Integer.parseInt(s);
System.out.println(i);
System.out.println("测试123");
} catch (NumberFormatException e) {
sout("我能被调用到吗?")
}
System.out.println("测试456");
//结果:
请输入字符
23
23
测试123
测试456
//说明在try中没遇到问题方法正常执行,catch中的代码不被调用到
//*******************************************************************************
//如果try中出现了问题,那么try下面的代码还会执行吗?
try {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入字符");
String s = scanner.nextLine();
int i = Integer.parseInt(s);
System.out.println(i);
System.out.println("测试123");
} catch (NumberFormatException e) {
System.out.println("我能被执行到吗?");
}
System.out.println("测试456");
//测试
请输入字符
abc
我能被执行到吗?
测试456
//说明在try中间出现问题,try问题后面的代码不执行,直接跳到catch中去执行错误语句,然后接着执行后面的测试456
//**********************************************************************************
//如果出现问题没有被捕捉,那么程序如何运行?
try {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入字符");
String s = scanner.nextLine();
int i = Integer.parseInt(s);
System.out.println(i);
System.out.println("测试123");
} catch (NullPtiontException e) {//这里将捕捉的异常改为空指针异常
System.out.println("我能被执行到吗?");
}
//结果
请输入字符
abc
Exception in thread "main" java.lang.NumberFormatException: For input string: "abc"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at com.bjpowernode.test2.MM.main(MM.java:22)
//分析:try中出现的解析格式异常,而设置的捕捉异常类型的空指针,所以没有捕捉到,因此报错就会调用JVM的默认处理方法,那么这个trycatch相当于没有写
//说明 如果try中出现的异常类型与捕捉的不同类型,这个try...catch...相当于没写,系统就会调用JVM来处理
//同时出现多个异常怎么处理?
try {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入字符");
String s = scanner.nextLine();
int i = Integer.parseInt(s);
System.out.println(i);
System.out.println(2 / 0);//数学异常
System.out.println("测试123");
} catch (NumberFormatException e) {
System.out.println("我能被执行到吗?");
}catch (ArithmeticException e){
System.out.println("数学逻辑出现异常");
}
System.out.println("测试456");
//多个语句异常如数学异常前出现了一次其他异常那么数学异常就不会被读取到,异常出现直接被捕捉后面的代码不执行
请输入字符
abc
我能被执行到吗?
测试456
//这里如果传入是正确的类型,后面的数学异常被读取到就会去和catch中的异常类型匹配,匹配到相同的就执行其内容
请输入字符
123
123
数学逻辑出现异常
测试456
//如果代码中有多个异常第一个异常被捕捉到后面的异常就不会被捕捉到了,因为异常一出来就直接走catch,捕捉多种类型的异常需要在后面加多个catch加入想要捕捉的异常类型,出现异常就会去catch的类型中匹配,如果catch有对应的异常类型就执行该catch内部的代码,无就调用的JVM的默认来执行。
//注意:如果出现子父类异常,那么子类一定要放在父类前面,因为父类的exception是异常的*类可以解决所以的异常,那么此时如果子类放在后面子类就无法执行了,每个类型的异常都被父类捕捉。
//那么为什么不直接使用父类异常来捕捉所有的异常呢?
//因为后面每个异常都有自己不同的处理方式,所有不会直接使用父类异常,因为捕捉到的不知道是什么类型的异常,就无法做出对应的处理方式
总结:
1.也就是try内执行的语句不出异常,那么就不会走catch,然后顺序后面的代码
内执行的语句出现异常,在异常出现的位置后面的代码不执行,直接去catch中匹配对应的异常类型执行出现异常的内容,然后继续执行try…catch…后的代码
3.如果try中出现的异常与catch中捕捉的不一样,那么就是调用jvm中的异常处理方式,打印异常的信息和位置,结束虚拟机的运行后面的代码全部不执行
4.多个异常就第一个异常出现,后面如果有异常也不会被捕捉到因为异常出现后面的异常不会被执行,直接去catch中执行对应的代码
异常的成员方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yJiUxiV6-1654725363505)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
try {
int[] arr = {1,2,3,4,5};
System.out.println(arr[10]);//在这里虚拟机就创建了异常对象 new ArrayIndexOutOfBoundException 对象
} catch (ArrayIndexOutOfBoundsException e) {
//public String getMessage()
System.out.println(e.getMessage());//返回次throwable的详细消息字符串
//public void printStackTrace()
System.out.println(e.toString);//返回此可
//public void printStackTrace()
e.printStackTrace//把异常的错误信息输出在控制台
}
//结果:
10
[Ljava.lang.StackTraceElement;@330bedb4
java.lang.ArrayIndexOutOfBoundsException: 10
at com.bjpowernode.test2.MM.main(MM.java:20)
分析:这三个方法是用来获取抛出异常时,可以通过这三方法来获取对应的错误信息,分别是详细的消息字符串、简短的描述以及把异常信息输出在控制台(红色字体)
异常小结:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1fNXzlMv-1654725363506)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:也就是throw 和 throws是用来抛出异常告诉调用者这里出现了异常不会去处理异常,而try…catch…就是捕捉异常并且自己手动处理异常。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r7HrqKX4-1654725363506)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//异常小练习
//student对象
public void setAge(Integer age) { //为什么在类中来判断setAge,因为需求中要求学生的年龄要求,如果不在类中写那么每写一个学 生对象附上对应的年龄都需要用if来判断所以直接在类里面来调用
if(age>= 18 && age<=23){//符合要求直接赋值
this.age = age;
}else {//不符合要求高数调用者出现异常
throw new RuntimeException("请输入正确的范围");//创建一个运行时异常告诉调用者这里出现异常
}
}
//测试中
Student student = new Student();//创建student来赋值
Scanner scanner = new Scanner(System.in);
System.out.println("输入用户姓名");
String s = scanner.nextLine();
student.setName(s);
while (true){//让调用者输入正确为止
System.out.println("输入用户年龄");
try {
String s1 = scanner.nextLine();
int i = Integer.parseInt(s1);//在这里会出现一个异常也就是调用传入的是abc不为Int类型就会出数字类型格式异常
student.setAge(i);//在这里接收到类中的异常后捕捉进行处理
break;
} catch (NumberFormatException e) {//如果传入的是abc则调用次异常
System.out.println("请输入正确的数字");
} catch (RuntimeException e ){//如果传入的年龄不对则调用该异常
System.out.println("请输入正确的年龄范围");
}
}
思路:在上面的联系中,判断年龄直接在类中判断就可以省去每有一个student输入年龄都需要来创建if来判断的问题,直接在类中来判断传入直接判断,超出的在类中通过throw来创建异常告诉调用者,接着通过try…catch…来出来会出现的异常,第一个异常是输入的内容不为int类型则会出现数字格式异常这个需要捕捉,还有一个是在类中抛出来的异常运行时期异常,都用catch来捕捉,如输入 正确就break退出循环,**注意:**如果没有处理异常会默认调用虚拟机中的处理,会暂停后面的代码执行,所以使用try…catch…能保证抛出异常并且继续执行try…catch…后面的代码还能够正常执行。
自定义异常
用来抛出异常的时候更加的见面知意
//上面的练习中,在类中创建掏出了一个RunTimeException 这个运行时期的异常,但是这个异常里面有很多子异常调用者不知道是哪一个所以要这时候就需要我们来创建一个异常更加的见名知意
//在看其他异常可以发现都是继承了一个异常类 这里继承RunTimeException这个异常类
public class AgeOutOfIIndexException extends RuntimeException{
//然后创建一个有参构造和一个无参构造就可以了
public AgeOutOfIIndexException() {
}
public AgeOutOfIIndexException(String message) {
super(message);
}
}
//引用上面的
public void setAge(Integer age) {
if(age>= 18 && age<=23){
this.age = age;
}else { //下面的括号内就是对异常的简短概述
throw new AgeOutOfIIndexException("数字不符合大小");//这里抛出的异常就写我们创建的异常对象就可以了别人就可以更加的清楚是出了什 么异常
}
}
//在测试时页就可以把捕捉异常改成我们写的
while (true){
System.out.println("输入用户年龄");
try {
String s1 = scanner.nextLine();
int i = Integer.parseInt(s1);
student.setAge(i);
break;
} catch (NumberFormatException e) {
System.out.println("请输入正确的数字");
continue;
} catch (AgeOutOfIIndexException e ){//改成这样调用者就知道这个异常是出现在年龄相关大小的异常了
sout(e.toString);//打印的是类中的出错简短概述
System.out.println("请输入正确的年龄范围");
continue;
}
}
理解:自定义异常比java中提供的异常可以更加的见名知意,因为java中的异常包含看很多子异常,调用者不知道哪个子异常会出现错误,那么就需要创建一个异常来继承这个异常类,然后类名简单名了的让人一看就知道哪里出错的,类中一个有参构造,一个无参构造就可以调用了,**注意:**创建的这个异常类名一定要加上Exception
集合
集合的特点就是长度可变,而数组是固定的长度如果多出长度的就会报错
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ltYbAvFs-1654725363507)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//数组
int[] arr = {1,2,3};
String[] arre = {"a","b","c"};
System.out.println(Arrays.toString(arr));
System.out.println(Arrays.deepToString(arre));
//运行时无措 说明数组可以存储基本数据类型也可以存储引用数据类型
//********************************
//ArrayList<int> arr = new ArrayList<int>();//报错,说明集合只能存储引用数据类型
ArrayList<Integer> arr = new ArrayList<Integer>();//这样就可以储存数据了
理解:
数组是规定的存储的个数的,多出存储个数会报错,数组可以存储基本数据类型和引用数据类型
集合存储的数据个数不限定,多出初始的10个会添加控件存储,集合只可以存储引用数据类型,且规定了类型不能传入其他类型数据
集合类体系结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mcSI1oMR-1654725363507)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8DDszl9N-1654725363507)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:Collection是list和set的父类,List内的存储元素可以重复,Set中的元素不可重复 **重点:**List集合和Set集合就是一个接口,平时我们创建的如 ArrayList就是List 的一个实现类,所以平时所说的list集合和set集合就是一个接口,我们调用的是它的实现类。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pdMyDtJf-1654725363508)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
以上是集合的体系结构 (浅颜色为接口,深颜色的是父类)
单列集合
Collection集合
它是所有单列集合的*接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JFn1ZqAV-1654725363508)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Collection常用方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ytM1Xje-1654725363508)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
**注意:**这也是List
集合和Set
集合共有的方法因为都是继承他就可以调用里面父类里面的方法
//boolean add(E e) 添加元素
Collection<String> e = new ArrayList<>();
e.add("haha");//用来添加元素的 返回值是boolean值添加成功是true
boolean s = e.add("hehe");
e.add("gege");
sout(s);//true
sout(e);//结果:[haha,hehe,gege]
//boolean remove(Object o )从集合中移除指定的元素
e.remove("haha");//用来删除集合中的元素 返回值是boolean值说明删除成功为true删除失败为false 说明集合中没有匹配的删除元素
sout(e);//[hehe,gege];
//boolean removeif(Objcet o) 根据条件进行删除 括号内传入的是Lambda表达式
//boolean test(T t);底层方法
ec.removeIf(
(String s)->{
return s.length() == 3;//删除长度为3的元素
}
);
sout(ec);//[haha, haha, hehe]
//理解: removeif的底层会遍历集合,获取到集合中的元素
//s依次表示集合中的元素
//就会把每一个元素都到Lambda表达式中判断一下
//返回true就删除成功
//放回false就删除失败
//********************************************************************
e.clear();//就是将集合中的所有元素删除
sout(e);//结果 []
//void contains 用来判断集合中是否包含指定的元素 包含返回的true 不包含返回false
sout(e.contains("haha"));//true
//boolean isEmpty() 判断集合是否为空 为空返回的true 不为空返回false
sout(e.isEmpty());//true 上面调用了clear()把集合清空了,所以这里检测到是空的返回的true
//int size() 用来表示集合的长度
sout(e.size());//结果 3
分析:在Collection
中的方法均可以见名知意,
1.添加元素用add
2.删除指定元素用remove
3.根据条件删除使用removeIf()
**注意:(这个方法括号内是Lambda表达式)**这个方法是先遍历的集合中的元素,然后根据赋值给了底层的boolean test<T t>
中的t,然后根据自己输入的逻辑来进行判断为true就删除,为false就保留。
4.清空集合用clear()
5.判断集合是否为空isEmpty()
如果集合不为空则返回false
6.集合中的长度(也就是结合中的元素个数)size()
Collection集合的遍历
Iterator:
迭代器,集合的专用遍历方式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-22ZfSYkz-1654725363509)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//iterator常用方法
Collection<String> se = new ArrayList<>();//创建一个List集合
se.add("a");
se.add("a");
se.add("a");
se.add("a");
se.add("a");
se.add("a");
se.add("a");
Iterator<String> e = se.iterator();//迭代器 变量名.迭代器对象
//boolean hasNext() 用来判断集合中是否有元素可以被取出来
boolean see= e.hasNext();//返回的是布尔值,判断集合中是否有元素 有则true否则就false
sout(see);//也是就判断集合中是否有元素
//E next() 获取当前位置的元素 初始的位置为0 将迭代器对象移向下一个索引位置
String next = e.next();//在获取完该位置的对象时,迭代的位置会移动向下一个位置的元素 也就是1位置的元素
System.out.println(next);
//循环获得集合中的元素
while (e.hasNext()){//先通过haxNext判断是否有元素可以读取
System.out.println(e.next());//读取元素
}
//上面为什么用while循环来获取元素呢,因为next方法每次获取元素下标都会加一,下次在调用就是下一个元素,当超出了集合的元素个数就会报错,因此先用hastNext来判断是否存在元素,存在再来读取这些就不会报错。
理解:Iterator迭代器,判断集合中是否有元素可以获取可以使用boolean hasNext()
也是看集合中是不是存在元素,E next()
将集合中的元素读取出来,从下标为0处开始获取元素**(Iterator翻译为迭代器,hastNext翻译为有下一个,next意为下一个)**
迭代器 原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HoFIqE2L-1654725363509)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
先创建一个集合的迭代器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S0COdhN1-1654725363510)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
接着hastNext去判断集合为0的索引是否存在元素(默认从0开始判断);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YznMzEit-1654725363510)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
next方法操作两步,想获取元素,然后下标指向下一个元素
迭代器小结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JusdyE0r-1654725363510)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
迭代器练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sx0JN4pp-1654725363511)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//注意如果使用for循环
ArrayList<String> arr = new ArrayList<>();
arr.add("a");
arr.add("b");
arr.add("b");
arr.add("c");
arr.add("d");
for (int i = 0; i < arr.size(); i++) {
String s = arr.get(i);
if(s.equals("b")){
arr.remove(s);
i--;//加上i--第二个b就可以被删除了
}
}
System.out.println(arr);//结果为[a, b, c, d] 发现相邻的两个b只删除了一个
//原因: 因为list集合可以不限大小的存储可以添加和删除,一删除了第一个b,next指向下一个下标存储的值,那理应的下一个b但是前面的b被删除出现空位,第二个b就会前进以为,因为他判断的是c而第二个b被错过了,所以当输出的时候让i--就可以判断到第二个b了,--到++相当于没动判断上移的元素是否为b。
//第二种方法调用iterator中的remove方法
Iterator<String> iterator = arr.iterator();
while (iterator.hasNext()){
if("b".equals(iterator.next())){
iterator.remove();
}
}
System.out.println(arr);//结果 [a,c,d]
增强for循环
用来简化数组和Collection集合的遍历
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y0NpvEZc-1654725363511)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
结论:通过看底层collection实现了接口说明说有的当例集合都可以使用增强for,Map集合没有实现说明不能直接使用增强for
格式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pIPOxtdv-1654725363512)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
ArrayList<String> arr = new ArrayList<>();
arr.add("a");
arr.add("b");
arr.add("b");
arr.add("c");
arr.add("d");
//1.数据类型要和集合中元素的类型要一样
//是一个变量,在循环的过程中,依次代表每一个元素
//是要循环的集合或则素组
for (String s : arr) {
System.out.println(s);
}
//结果
a
b
b
c
d
增强for注意点
//如果修改for循环中的一个变量名不会影响循环的结果
for (String s : arr) {
s = "q";//这并不会影响循环的结果,因为s只是一个变量并没有去修改集合中的元素所以不会影响
System.out.println(s);
}
目前所学的三种循环:for循环、iterator、增强for
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fJ3GJiZn-1654725363512)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:当通过下边索引操作的时候用for循环,当想要判断删除集合中元素的时候使用迭代器,如果只是想遍历就使用增强for
Collection练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QSmGStdT-1654725363512)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Collection<Student> aee = new ArrayList<>();
Student kk = new Student("KK", 20);
Student kg = new Student("Ke", 21);
Student ke = new Student("Ko", 22);
aee.add(kk);
aee.add(kg);
aee.add(ke);
for (Student student : aee) {
System.out.println(student);
}
//结果
Student{name='KK', age=20}
Student{name='Ke', age=21}
Student{name='Ko', age=22}
List集合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uCZ2BIjp-1654725363513)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3hcaO2tw-1654725363513)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
List<String> e = new ArrayList<>();
e.add("aaa");
e.add("bbbb");
e.add("ccc");
//使用迭代器遍历
Iterator<String> iterator = e.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//使用增强for
for (String s : e) {
System.out.println(s);
}
注意:list集合的有序是说按放入的顺序并不打大小顺序
List集合特有方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PA41O41f-1654725363513)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
List<String> e = new ArrayList<>();
e.add("aaa");
e.add("bbbb");
e.add("ccc");
//void add(int index,E element) 在此集合中的指定位置插入指定的元素
e.add(0,"qqq");
sout(e);//结果:[qqq,aaa,bbbb,ccc]
//理解:之前collection中的add都是添加在最后面叠加上去,这个add可以根据索引插入添加,先前索引的元素往后退一
//*************************************************************************************************
//E remove(int index) 删除指定位置索引处的元素,返回被删除的元素
e.remove(1);//这里删除索引为1的上面添加了qqq在0索引 aaa就退到1索引处所以就是删除aaa
System.out.println(e);//结果 [qqq,bbbb,ccc]
//理解:之前collection中的remove是删除集合中的元素返回的是boolean这个是返回的是该元素
//也可以这么理解collection是通过判断集合是通过元素名来删除,list则是通过下标,一个返回的boolean一个返回元素名
//*************************************************************************************************
//E set(int index,E element) 修改指定索引处的元素
e.set(0,'eeeee');//修改改位置的元素,之前该位置的元素就被替换
sout(e);//结果 [eeeee,bbbb,ccc];
//理解:用来修改指定下标的元素
//*************************************************************************************************
//E get(int index) 获取集合中指定索引的元素
String s = e.get(1);
sout(s);//结果: bbbb
数据结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RwxnJzM3-1654725363514)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
栈
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eq3a3hSY-1654725363514)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AAk9jY8M-1654725363514)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LjNdrZLC-1654725363515)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
队列模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GzRtDe0o-1654725363515)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lOSV62Rt-1654725363516)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
栈模型和队列模型的小笑话加深记忆
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1IS1SNBT-1654725363516)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
数组结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rEAwIZtZ-1654725363516)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YLH2IGZK-1654725363517)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PVBpxKIm-1654725363517)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
链表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f3P8FKIz-1654725363518)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
链表存储数据的过程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U8pm4Ngl-1654725363518)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
链表添加数据过程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w50aEAr5-1654725363518)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
链表删除
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2WZZx08F-1654725363519)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
这里删除c,B所记的地址就改为D的地址然后C删除
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yoLg1xBs-1654725363519)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fhnr9ZHn-1654725363519)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
链表的查询
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sZLWXXhT-1654725363520)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Ij7nd4C-1654725363520)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
ArrayList底层源码分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YC2kAiMb-1654725363521)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rGsR6qP0-1654725363521)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:Arraylist就是一添加元素,底层调用了add方法分别获得要传入的值,数组名,本次添加的值的下标,然后就会在add方法中进行判断数组长度是不是与本次想要添加信息的索引一致,一致就说明该数组的位置满了,需要添加存储地址,接着底层调用grow方法来扩容数组,然后就会创建一个新的数组将旧的数组元素传入,在新数组内会看旧容量,然后新容量就是就容量的1.5倍然后返回出去,这样底层就会自动扩容。例如:Arraylist初始默认是可以存放10个元素,但当储存第10个元素时,他就会判断第十个元素的下标和默认的长度一样,那么它就会自动扩容,创建一个新是数组是旧数组的1.5被储存完旧数组的元素后又可以储存后面添加的元素。
LinkList
该集合与ArrayList一样都是list
集合的一个实现类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fzNuiqZu-1654725363521)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
LinkedList<String> strings = new LinkedList<>();
strings.add("aaa");
strings.add("bbb");
strings.add("ccc");
//public void getFrist(E e )//获取数组开头的元素
String first = strings.getFirst();
System.out.println(first);
//public void getLast(E e) //获取数组结束的元素
String last = strings.getLast();
System.out.println(last);
//public E addFrist(E e) 在集合开头添加元素
strings.addFirst("111");
System.out.println(strings);//结果 [111, aaa, bbb, ccc]
//public E addLast(E e) 在集合结尾添加元素
string.addLast("lll");
sout(strings);//结果 [111, aaa, bbb, ccc,lll]
//public E removeFrist() 删除集合中第一个元素
strings.removeFrist();
sout(strings);//结果 [aaa,bbb,ccc,lll]
//public E removeLast() 删除集合末尾的元素
strings.removeLast();
sout(strings);//结果 [aaa,bbb,ccc]
Linklist 底层源码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uCqT5QxO-1654725363522)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JHk82HAJ-1654725363522)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
**分析:**在创建new Linkedlist的时候会创建一个头结点和一个尾节点,使用集合中的add,底层就会创建一个新的节点保存上一个节点的地址,本身值,和下一个节点的地址,在创建完节点后,尾节点就会指向该新创建的节点的地址,头节点判断是否为空,这里传入的是第一个元素,所以为空,头结点就储存新节点的位置,后面再添加的元素也会创建一个节点,它们上一个节点就尾节点记录的地址,然后上一会节点的尾节点就会记录这个新添加进来元素的地址
理解:也就是新的元素进去就创建了要记录三个东西一个的前一个节点的地址,一个是储存的值,一个是下一个节点的地址,每个元素进去都会创建节点,第一个元素进去后,头结点就会指向这个第一个元素创建的节点地址最后一个节点也会记录这个地址,然后,当后面又元素进来也是先创建节点储存自己,这个后面的节点的前一个节点的地址值就是最后一个节点的地址值也就是上一个节点的地址值,最后一个节点指向这个后来的,第一个节点就将他的下一个节点的值改为这个新创建的节点地址值。
为什么说LinkList的查询效率比Arraylist慢?
因为LinkList他搜索是从开头搜索到结尾,不能像Arraylist一样可以通过下标来搜索,它的底层是链表,每个元素保存上一个元素的地址和一个下一个元素的地址,所以要从头开始搜索地址,来一个一个,因此LinkList的增加效率高,搜索效率低
List集合总结
list集合的特点是可以重复,下面有两个实现类一个是ArrayList和LinkedList
ArrayList:底层是一个数组结构,在增加元素的时候比较慢,以为数组中增加元素后面的的元素全部要退一位,所以比较慢,而搜索比较快,因为它是一个连续的空间所以查找的比较快,还有下标直接可以查询到
LinkedList: 底层是一个链表结构, 查找的话就会判断该元素离头节点与尾节点两个距离,对比完,就从头往后去寻找,因此比较慢,增加和删除快,因为他是一个节点储存两个地址一个是上一个节点的地址,一个是下一个节点的地址,如果删除,C节点的地址直接将上一个节点的地址由B改成A,那么A的下一个节点就是C了,所以比数组要快
Set类型
TreeSet
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BpBZKheG-1654725363523)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Set集合的主要特点,元素不可重复。
例如:王者荣耀的ID不可重复就可以使用的Set集合来储存,如果要像赛尔号一样不管ID的重复可以使用List集合来存放。
set的是不按存取顺序的,它底层是一个Hash,会看每一个元素的哈希值来排列谁是第一个位置,所以这里是不按顺序的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R0OIJHvi-1654725363523)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Set<String> e = new TreeSet<>();
e.add("ccc");
e.add("aaa");
e.add("aaa");
e.add("bbb");
// for (int i = 0; i < (); i++) {
// ();//这里报错,无法通过下标来获取因为set集合没有索引的方法
//}
//所以使用迭代或则增强for来遍历
Iterator<String> iterator = e.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//输出结果:
aaa
bbb
ccc
//分析结果: 在集合中输入了两个相同的aaa只能输出一个说明set集合不能存放重复值,其次ccc的存入比aaa前当是获取时aaa在前面说明set的存储顺序不一样,底层是一个hash,通过判断哪个元素的hash靠前哪个元素先出来。
TreeSet集合特点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wnwnmf5x-1654725363523)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-82zp2yZG-1654725363524)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//创建TreeSet集合存放数据
TreeSet<Integer> te = new TreeSet<>();
te.add(5);
te.add(4);
te.add(3);
te.add(2);
te.add(1);
System.out.println(te);
//结果:[1, 2, 3, 4, 5]
//分析: 看结果可以分析出TreeSet在底层我们进行了一个大小的排序 这里是按照int大小进行的排序 如果是字符串类型会看hash表大小
//字符串类型
TreeSet<String> te = new TreeSet<>();
te.add("d");
te.add("b");
te.add("c");
te.add("a");
System.out.println(te);
//这里它就会按每个元素的hash表来进行排序
//引用类型
private String name;
private Integer age;
//此处省略类中的有参构造和toString方法
//测试类
TreeSet<Stt> es = new TreeSet<>();
Stt e = new Stt("小狗", 23);
Stt e1 = new Stt("中狗", 20);
Stt e2 = new Stt("大狗", 32);
es.add(e);
es.add(e1);
es.add(e2);
System.out.println(es);
//结果
报错出现异常
//分析:TreeSet在上面的分析我们都知道,它内部会进行一个排序,数字类型就是比较数值的大小,字符串类型就是对比的hash值,都有一个对比的东西,而这个Stt类中只有name和age没有设定一个对比的值,所以TreeSet报错,不知道怎么排序。
分析:TreeSet底层后自动排序,需要有排序规则,如Int类型则按数字的大小,String类型就按哈希值来排序,如果需要传入的泛型是一个引用类型,就需要在该类中设置一个排序规则有对比的东西。
TreeSet自然排序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wsEE8iRr-1654725363524)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//当泛型是一个对象类的时候如何排序
//在对象类中去实现Comparable中的泛型为集合中的类型
public class Stt implements Comparable<Stt> {//实现这个接口中的compareTo:意思为相比于
private String name;
private Integer age;
//下面忽略get set和构造
@Override
public int compareTo(Stt o) {//这里实现接口中的该方法
//这里看下面传入了小狗和年龄23是一个元素,集合中就存储了这两个信息,一添加第二个元素中狗和20的时候,TreeSet就会去类中的看该类有没有实现接口可对比的规章,也就是实现接口`Comparable<T t>`,然后实现的方法`comparTO`中设置的规则去进行排序,每一个元素进来这里都去对比一次对象Stt中age的大小,如果是负数就存左边,正数就右边,如果左右两边都存储了元素,就再次对比左右两边元素或中的age来进行排序。
int i = this.age - o.age;//这里将年龄来设置成排序的规则
return i;
}
}
//在测试类就可以有了可以排需的规则
//测试
TreeSet<Stt> es = new TreeSet<>();
Stt e = new Stt("小狗", 23);
Stt e1 = new Stt("中狗", 20);
Stt e2 = new Stt("大狗", 32);
es.add(e);
es.add(e1);
es.add(e2);
System.out.println(es);
//结果:
[Stt{name='中狗', age=20}, Stt{name='小狗', age=23}, Stt{name='大狗', age=32}]
分析:想要给类定义一个自然排序,就让类去实现Comparable
意思是可对比,也就是将每一个Stt对象都可以对比,实现该接口中的compareTo
翻译为可比于,就是设定用来对比的值。结合下面叠层原理.
自然排序底层原理图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o5jV96Y8-1654725363524)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yfWqHA2Y-1654725363525)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xk73rcC4-1654725363525)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:也就是在类中实现了Comparable
中的comparTo
在TreeSet添的元素都会去对比前一个对象,对比comparTo
中的值的大小,如果为负数就是左边,正数就是右边。
TreeSet小案例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hwtDeRoz-1654725363526)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
public int compareTo(Stt o) {
//主要条件
int i = this.age - o.age;
//次要条件
i = i == 0 ? this.name.compareTo(o.name) : i;//这里调用的comparTo是String里面的,它的比较方式是对比字符串中的 字母一样的就对比第二个,知道出现不同的就进行排序
return i;
}
//测试
TreeSet<Stt> es = new TreeSet<>();
Stt e = new Stt("zxg", 23);
Stt e1 = new Stt("zzg", 20);
Stt e2 = new Stt("zdg", 32);
Stt e3 = new Stt("zxm", 23);
es.add(e);
es.add(e1);
es.add(e2);
es.add(e3);
System.out.println(es);
//分析: 上面的zxm与zxg是年龄相同的,就会进入到正则表达式中,String的comparTo先看第一个字母一样,就对比第二,到了第三个字母发现g的排序比m前就后返回负数,接着-1就会排在集合的左边所以zxg在zxm的左边。
理解:上面案例中如果年龄相同就然后需要对比首字母就可以使用当前元素的名称与集合中的元素做对比,如 zxg与zxm,现在存入zxm通过Stt实现的接口,中的年龄对比发现年龄一样,那么后面设置了对比名称,就是拿zxm这个name去和zxg对比,按字母的首字母开始一个一个的对比,第一个发现z 与z 一样就到第二个x与x一样,到第三个字母 m 与g 然后m是在g后面的,就会那m的值减去g的值,负数的话在zxg的左边,正数说明m比g的顺序后,所以在zxg的右边。
TreeSet比较器排序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KN6vE856-1654725363526)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//首先创建一个类
public class Teach {//注意 这里没有实现自然排序
private String name;
private Integer age;
}
//测试
//在TreeSet中传入比较器进行对比 o1是刚传入的元素o2是集合中已经存在的元素
TreeSet<Teach> teaches = new TreeSet<>(new Comparator<Teach>() {
@Override
public int compare(Teach o1, Teach o2) {
//这里的o1代表刚传入的参数
//o2代表的已经在集合中的参数
//主条件 比较年龄 年龄一样走次要条件
int i = o1.getAge() - o2.getAge();
//次要条件 比字母的大小 如abc a比b小 所以 a 在 b的左边
i = i == 0 ? o1.getName().compareTo(o2.getName()) : i;//年龄相同对比的name中的字母大小
return i;
}
});
Teach z1 = new Teach("zhangsan", 23);
Teach z2 = new Teach("lisi", 24);
Teach z3 = new Teach("wangwu", 26);
Teach z4 = new Teach("zhaoliu", 26);
teaches.add(z1);
teaches.add(z2);
teaches.add(z3);
teaches.add(z4);
System.out.println(teaches);//结果: [Teach{name='zhangsan', age=23}, Teach{name='lisi', age=24}, Teach{name='wangwu', age=26}, Teach{name='zhaoliu', age=26}]
理解:如果调用了TreeSet的无参构造,就需要在类中去实现自然排序,在类中去实现Compatatable
这个接口,告诉TreeSet对比的规则,若调用的是TreeSet的有参构造,在参数里面去重写比较器Comparator
就可以了实现上面案例。注意要按主条件和次要条件来写.
两种排序方法的小结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mx0sC6vF-1654725363526)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:这两种的排序都是当泛型中元素类型是对象类的时候,来给对象类制定的一个排序顺序。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BT5p7lpI-1654725363527)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
TreeSet<String> at = new TreeSet<String>();
at.add("ha");
at.add("h");
at.add("hada");
at.add("zjsd");
//要完成上面的排序,如果是默认的是使用的String中的自然排序,java已经帮我们写好了默认的排序
sout(at);//String默认的排序结果:[haha, hahahahaha, heheheh, sddsadasd] 发现问题,它是按字母的大小排序的没有按长度
//如果要按长度排序那我们岂不是要重写String源码中的comparTo?那是不能重写的所以这里就可以使用比较器
TreeSet<String> strings = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int i = o1.length() - o2.length();//这里是判断字符串长度刚将来的元素与集合中的元素比较长度 负数说明集集合 中的长新来的就在左边
i = i == 0 ? o1.compareTo(o2) : i;//如果长度一样,就按String中的默认规则比较他的字母大小
return i;
}
});
strings.add("sddsadasd");
strings.add("haha");
strings.add("heheheh");
strings.add("hahahahaha");
System.out.println(strings);//结果 [haha, heheheh, sddsadasd, hahahahaha]
分析:在默认的情况下是使用的对象类中的自然排序,如果默认的排序规则与想要的结果不用,就需要使用到比较去做进一步的修改,如上面的String类中java默认的实现了Comparatable
制定了一个默认的排序,就是那字母的字典规则,但案例需要对比的字符串长度,这时候不可能去修改String源码,因此就需要去使用比较器来制定一个排序的规则。
数据结构-树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VQuw1WZS-1654725363527)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:这种左右结构就可以知道集合的底层是什么结构 是什么体系中的 如上面的ArrayList Array是数组结构 list是集合中的一员
二叉树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nTbj21u0-1654725363528)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KTMXj799-1654725363528)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:A节点是BC的父节点,那么此时A节点中的左子节点存的地址就是B节点的地址值,B节点的父节点地址就是存的A节点的地址值,同理C节点的父节点地址值存A节点的地址值A节点的右节点地址值存的C节点的地址值。这样就形成了一个树结构。如果节点中没有值就默认为null上面有五个地方是null一个是A节点的父节点地址 还有B和C的左子节点地址和右子节点地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4cjat5dA-1654725363528)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:度就是说明该节点中子节点的个数,二叉树中每个节点最多只能有两个子节点,任意一个节点的度小于1或则等于2;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qJybyiGY-1654725363529)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N2Hl8KRj-1654725363529)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0LlXSHUA-1654725363530)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:根节点就是这个二叉树的最顶层
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HTJwmwzQ-1654725363530)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:根节点的左字数,就相当于根节点左子节点演变出来的,如 一个父亲两个儿子,左边的儿子生了两个儿子,那这个父亲的左边的儿子所演变出来的就是左子树,也就是根节点的左子树,同理右边演变出来的就是根节点的右子树。
二叉查找树[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SroQb2U7-1654725363530)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:普通的二叉树是任意存储的,每个节点都有两个字节,部分大小随便存储,而二叉查找树,左节点存放的是比自己小的值,右节点存储比自己大的值。
小结:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ILdcskQX-1654725363531)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
每一个树都是有节点组成的,二叉树是节点最多可以存储两个子节点,当存储左边的值小于本身,而右边的值大于本身那么这个树就是一个二叉查找树或则二叉排序树又或则二叉所搜树。
二叉查找树添加节点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NKCt9IxS-1654725363531)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-erXIkiA4-1654725363532)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:7先存储进来,然后是4进行对比发现7比4小存储在左边,后面10比7大存储在右边,这样形成了一个二叉查找树。一样的就不存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y8k73ICf-1654725363532)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:紧接着又来一个节点是5,也是先去和7对比发现比7小所以存左边,发现做节点有了一个节点4了,然后就会和4对比,发现5比4大然后5就会存在4的右边形成上面的结构。
平衡二叉树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CESxvF4o-1654725363532)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:上面的情况是二叉查找树添加形成的一次将7 10 11 12 13分别添加进来,然后发现都在右节点,此时就需要一个平衡二叉树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ILcU8fpR-1654725363533)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:这个满足了第一个二叉树左右高数差不超过1,但是第二个条件不满足,子树不是一个平衡二叉树,右节点10那里开始不是平衡的二叉树,因为10的右节点超过了左节点不止一层。
平衡二叉树旋转
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6TO7gd6v-1654725363533)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
案例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CGYryHuh-1654725363533)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-drFBPYIO-1654725363534)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:当出现这种右边节点比左边节点少时且不形成二叉平衡树时,就会调用左旋,因为右边的节点比左边的多,所以将右边的节点左旋到两边平衡为止。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HWBgWTo1-1654725363534)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
旋转后就形成了一个二叉平衡树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M9BxCSxq-1654725363535)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nGL3jW9R-1654725363535)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
当旋转时出现了10有个两个子节点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6wYv0w35-1654725363535)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:可以看出7当根节点的时候,此时二叉树不是一个平衡二叉树,需要通过旋转来形成,那么发现10这个节点中有做节点了,那么字啊旋转时限忽略9这个左节点旋转后将原先10的做节点9当做7的右节点存储。
平衡二叉树右旋
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sWPP8aIv-1654725363536)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
右旋后
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7KTrvHsr-1654725363536)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GEAEkU5j-1654725363536)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mYSj4QiA-1654725363537)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-puVYUdJ8-1654725363537)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
理解:右旋相当于二叉树的根节点左节点的升一个段位,右边的不变,左旋,就是右边子节点的全部升级,左边子节点不变
小结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g2jpGx99-1654725363537)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
为了平衡二叉树的查找顺序所以我们使用了平衡二叉树,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-La9WQfLf-1654725363538)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6aNxFlEj-1654725363538)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
平衡二叉树旋转四种情况
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k830j4sM-1654725363538)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
左左
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DcEXgFsl-1654725363539)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HPuh2E2F-1654725363539)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
左右
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZdfekzZE-1654725363540)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gxPpoP6x-1654725363540)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GaPX0roM-1654725363540)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
右右
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p3c0Ow65-1654725363541)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7fCyHTMR-1654725363541)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SG4h34EK-1654725363541)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-25smwHD2-1654725363542)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
右左
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zqRrgNiT-1654725363542)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NlBep7JE-1654725363542)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JO7vSyDL-1654725363543)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pCINlKn2-1654725363543)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
小结:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yuLSc6yZ-1654725363544)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
红黑树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bjWVkUA3-1654725363544)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bb4uGPk5-1654725363544)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kc0K1EjM-1654725363545)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
红黑规则
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R402AL94-1654725363545)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
添加节点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OG9DGfvh-1654725363546)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jQJrC55D-1654725363546)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yEC4czUQ-1654725363546)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
在这里违背了红黑规则两个红色连在了一起,这时候,22的父节点和叔叔节点都需要变成黑色,祖父节点20也要变黑,但如果祖父节点是根节点则在次变回黑色。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jwVjEEut-1654725363547)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
添加节点小结:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5UotAsNd-1654725363547)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
注意:当叔父节点为黑色时
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rW7nKEDF-1654725363547)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XIgd3cfP-1654725363548)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FW0lUQ3i-1654725363548)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bda59U1C-1654725363549)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
上面右旋
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LTMk11yP-1654725363549)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
红黑树小结:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ygGTuPb-1654725363549)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UABFIanF-1654725363550)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
红黑树小案例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Syeh79D5-1654725363550)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//Students类
public class StudentS implements Comparable<StudentS>{//在类中实现了接口 定制对比的规则
private String name;
private Integer chinese;
private Integer math;
private Integer english;
public int compareTo(StudentS o) {
//下面的方法是指定的顺序由小到大的,
//如果需要修改由大到小,就将this和o交换位置即可
//原理在下面的图片中
//这里简单概述:目前下面的代码是存入第一元素在集合中,然后那这个元素的总分去和后面新添加进来的元素它的总分来进行对比,大的右边,小的左边,那么就会形成一个小的值在左边,输出顺序也是从左到右,这样就小到大输出了,只要修改位置,修改了比第一元素大的存左边也就是拿后来的减去已经在集合中的,正数就会在左边负数在右边,然后因为顺序从左往右这样就可以大到小排序了。
//主要条件
int i = this.sum() - o.sum();//先对比总分
//次要条件
//总分一样 先对比语文成绩
i = i == 0 ? this.chinese.compareTo(o.chinese) : i;
//然后对比 数学成绩
i = i == 0 ? this.math.compareTo(o.math) : i ;
//最后对比 英语成绩
i = i == 0 ? this.english.compareTo(o.english) : i ;
//如果都一样按名字字母
i = i == 0 ? this.name.compareTo(o.name) : i ;
return i;
}
}
//测试
//使用TreeSet集合
TreeSet<StudentS> studentS = new TreeSet<>();
StudentS lili = new StudentS("lili", 80, 90, 80);
StudentS jcak = new StudentS("jack", 80, 90, 80);
StudentS mink = new StudentS("mink", 100, 90, 80);
StudentS gcet = new StudentS("gcet", 70, 100, 80);
studentS.add(lili);
studentS.add(jcak);
studentS.add(mink);
studentS.add(gcet);
Iterator<StudentS> iterator = studentS.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());//当泛型中的对象类StudentS没有实现Comparatable或TreeSet有参中没有比较器就会报错
}
//结果:
StudentS{name='gcet', chinese=70, math=100, english=80,总分=250}
StudentS{name='jack', chinese=80, math=90, english=80,总分=250}
StudentS{name='lili', chinese=80, math=90, english=80,总分=250}
StudentS{name='mink', chinese=100, math=90, english=80,总分=270}
//通过结果分析可以成绩打印成功,从小到大。
注意:TreeSet集合是没有下边的,不能使用fori来遍历只能通过迭代器和增强for
案例实现原理:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AThAhcnf-1654725363550)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
在第一学生总分240放进集合因为是第一个元素所以是一个根节点,然后依次270和300与240对比都比它大所以放240的右边
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DvltSAi0-1654725363551)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
这里两个红色链一起,不符合红黑树的规则,规则两个红色链一起,父类是和叔叔类的颜色,这里看出一红一黑,那么就将父类变黑色,祖父类变红色,然后在左旋。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-njRsoSc5-1654725363551)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
旋转后就形成了这样。注意在遍历的规则是先输出的左边在输出中间最后是右边,上面是按顺序总分少到总分多的。
下面是修改了this和o的顺序,方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W85XQ2CG-1654725363553)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
之前是由集合中的值来减去准备传入的值,比集合中存在的元素240小的放左边,现在修改了输出顺序要大到小排序,就有传入的元素减去集合中存在的元素。就会形成种种顺序,比240大都存左边,最后输出的时候就是从下面图片中的300开始最后是240
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f8yq9kch-1654725363554)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
然后就可以形成以由大到小的顺序改变
HashSet
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OfCmPzrJ-1654725363554)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//HashSet小练习
HashSet<String> drr = new HashSet<>();
drr.add("b");
drr.add("c");
drr.add("d");
drr.add("a");
drr.add("b");
Iterator<String> iterator = drr.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("-----------------------------------------------");
for (String s : drr) {
System.out.println(s);
}
//结果
a
b
c
d
-----------------------------------------------
a
b
c
d
分析:通过上面可以得出三个特性,第一个HashSet是不按输入顺序输出的是按HashSet,第二个HashSet中的元素不可以重复,第三个看下面图片,在观看源码中发现hashSet的添加是没有根据下标索引添加的,所以应正了上面是观点,hashSet不可以使用fori来遍历。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i349r3Me-1654725363555)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
哈希值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pFvSsQV0-1654725363555)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Stt xjl = new Stt("xjl", 23);
Stt xel = new Stt("xel", 23);
//因为在object类中,是根据对象的地址值计算出来的哈希值
System.out.println(xjl.hashCode());//856419764
System.out.println(xjl.hashCode());//856419764
System.out.println(xel.hashCode());//621009875
//Stt类中没有重写hashCode的方法,则调用的*类Object中的hashCode也就是上面的
//如果在Stt类中重写了hashCode方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Stt stt = (Stt) o;
if (name != null ? !name.equals(stt.name) : stt.name != null) return false;
return age != null ? age.equals(stt.age) : stt.age == null;
}
//在测试中对应的就是根据对象的属性值来计算哈希值的。就是name和age这些的属性值
//重写后调用
System.out.println(xjl.hashCode());//3680157
System.out.println(xjl.hashCode());//3680157
System.out.println(xel.hashCode());//3675352
分析:不同对象的哈希值不一样,默认的哈希值的根据对象地址计算出来的,如果在类中重写hashCode这个方法后面使用的哈希值是对象属性计算出来的哈希值。也就是默认是地址值计算出来的,从写的是根据属性值计算出来的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6x0gjFUT-1654725363555)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
常见数据结构之哈希表 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XLRTcws8-1654725363556)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
JDK8以前HashCode底层原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uFUafc8G-1654725363556)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
HashSet初始创建一个长度为16的素组
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vYqevTdZ-1654725363556)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
先根据元素值和数组长度计算出存储的位置,然后判断该位置是否存在元素,没有存在元素就存储。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hRV9CwXp-1654725363557)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
假设将添加的元素计算出来应该存放在下标为4中存储,此时发现该位置已经有了元素
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F7NLBKP1-1654725363557)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
然后判断存在该位置的值调用equals来比较属性值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1jfHXpQ2-1654725363558)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
如果对比相同则该元素不存储,不相同,就将老元素挂在新元素下面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IDf5WQfp-1654725363558)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
然后这就形成了数组加链表结构。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uab4wjLI-1654725363559)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
接着又添加元素,计算出来的值又是4同一个位置三个值,然后使用equals与4中的元素逐个对比,如果其中有一个相同就不储存,不同就将新的放存入数组,旧的挂在新的下面。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yMoQe724-1654725363559)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NUFzO7hx-1654725363559)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
添加最后一个元素,通过逐个equals对比,然后发现有一个是相同的,那么这个最后添加的元素就不存储
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-phdVmoJJ-1654725363560)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
新添加的和数组中的一样。这个新元素就不会添加到集合当中。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ukf0qXII-1654725363560)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
当元素长度满足了12就会自动扩容数组。将存储长度将原先的16改成2背 32
总结:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oExmtAiV-1654725363561)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
分析:也就是在JDK8之前不包括JDK8,创建一个HashSet它就是由数组和链表结构组成的,添加元素进入集合中,会先通过元素的哈希值和数组的长度计算出应改存储的位置,如果位置为null也就是没有值,那就将该值存入数组中,接着后面添加的元素也是先计算元素哈希值和数组长度来计算,若给出的下标位置有元素了,就通过equals来判断是否相同**(这就是hashSet不可以存用一个元素的原因)**,相同的话就不存储,不相同,就想新元素存在数组中,旧元素挂在新元素下面,后面添加的元素也都一样先通过哈希值和数组长度来判断存储位置,然后逐个对比数组中的元素逐个使用equals对比,hashSet在JDK7之前默认的数组长度为16,如果超出了12个,就自动扩容,将原先的存储空间改成32也就是原先了2倍。
HashSet在JDK8中底层优化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KroEuvPq-1654725363561)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
看上图中加入下标4中存储了很多个元素,那么新添加的元素也要存里面就需要和4之中的每个元素对比,很影响效率所以JDK8出了新的优化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F1NlT3mX-1654725363561)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
然后在JDK8的优化中,当数组中的元素长度为八就会将链表装换为红黑树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LEZXBZui-1654725363562)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UUi0xqyI-1654725363562)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xojBts8k-1654725363562)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
HashSet集合练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0wzpFW0M-1654725363563)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//使用HashSet完成上面
//Studentt类
//在这个类中没有重写equals而使用hashSet它就默认调用object中的equals来对比是使用的对象的地址值
public class Studentt {
private String name;
private Integer age;
public Studentt() {
}
public Studentt(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Studentt{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//测试类
HashSet<Studentt> studentts = new HashSet<>();
Studentt s1 = new Studentt("xiaohu", 23);
Studentt s2 = new Studentt("xiaohu", 23);
Studentt s3 = new Studentt("xiaomei", 24);
studentts.add(s1);
studentts.add(s2);
studentts.add(s3);
Iterator<Studentt> iterator = studentts.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//测试结果
Studentt{name='xiaohu', age=23}
Studentt{name='xiaomei', age=24}
Studentt{name='xiaohu', age=23}
//分析: 这里是调用的object中的equals来对比,使用的对象地址值来对比的 s1和s2虽然存储的内容一样,但是指向的对象都不一样的不是同一个地址的,所以他们会当成两个不同的值。
//------------------------------------------------------------------
//这里重写equals
//在类中
public class Studentt {
private String name;
private Integer age;
public Studentt() {
}
public Studentt(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Studentt{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Studentt studentt = (Studentt) o;
if (name != null ? !name.equals(studentt.name) : studentt.name != null) return false;
return age != null ? age.equals(studentt.age) : studentt.age == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (age != null ? age.hashCode() : 0);
return result;
}
}
//测试
HashSet<Studentt> studentts = new HashSet<>();
Studentt s1 = new Studentt("xiaohu", 23);
Studentt s2 = new Studentt("xiaohu", 23);
Studentt s3 = new Studentt("xiaomei", 24);
studentts.add(s1);
studentts.add(s2);
studentts.add(s3);
Iterator<Studentt> iterator = studentts.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//结果
Studentt{name='xiaomei', age=24}
Studentt{name='xiaohu', age=23}
//分析:重写后就是通过对比的就是成员属性计算出来哈希值,就不是地址计算出来的的哈希值了。
理解:就是HashSet要存储自定义对象的时候,必须重写hashcode和equals方法也是为存储的自定义元素的不可重复性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3yRzdRVE-1654725363563)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
当没有重写得到的地址的哈希值,那么就有两个相同属性的对象存入了集合中,需要在对象中重写equals改成对比的成员属性,才能做到对比值,并且判断值相同的不能进行存储。
HashSet小结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CLabijnw-1654725363564)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
总结:Set集合是无序的,也就是存储在Set集合中元素顺序存入与输出是不一样的,**无索引:**就是说Set集合的底层是没有索引所以没有下标不能通过下标读取其中的元素,**不可以重复:**在set集合内的值不可以重复,是唯一的。
HashSet: 它的底层是哈希表传入的自定义类型的,没有重写equal是由地址值来计算出来的哈希值,那么就会有一个问题,对象中传入的成员属性的值是一样的,那么就会有两个相同的内容存在了HashSet里面,这样并不能解决hash中只能存储唯一值的特性,所以需要在对象类中去重写hashcode与equals让它是equals是根据成员变量的值来进行计算形成的,这样不管就能让想同值的内容不存入hash中,结论:当存放的自定义类的时候,必须重写equals和hashcode方法
TreeSet: TreeSet的底层是一个红黑树,必须给它一个排序的规则,如果TreeSet<T t>
中存入了String类型,它就是通过String的字典排序来判断元素的先后顺序的,Integer就是根据的数字的大小,这些都是java给我们写好了的,那么如果传入自定义的对象类,有两种方法来定义排序的规则,第一种在对象类中实现Comparatable<这里的泛型写集合中存储的类型>
实现这个接口中的ComparTo
,然后在comparTo
中来定义规则,如年龄大的排前面小的排后面,就可以通过 - ,这里的this是代表的新插入的元素,o是集合中已经存在的元素,进行对比,正数在左边,负数在右边,第二种,就是定义TreeSet时候定义一个比较传参,然后其中 o1是新传入的值 o2是后传入的值,然后在那里面编写规则,就可以定义排序规则了。TreeSet的底层是一个红黑树,红黑树中的排序规则也是如此第一个元素进去是根节点,后面的元素就会和他对比小的排左边大的排右边,因为红黑树有自己的红黑规则,所以TreeSet的底层原理具体可以上目录中的红黑树规则。
双列集合
Map集合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BHHSXxFu-1654725363564)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HAqP1yx3-1654725363565)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AAeMD0DU-1654725363565)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g7jnInqM-1654725363565)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Map集合概述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uj6lfbet-1654725363566)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Map<String,String> mae = new HashMap<>();//map是一个接口所以要用他的实现类hashmap或则TreeMap来实现
mae.put("xiaomei", "23");
mae.put("xiaoli", "23");
mae.put("xiaohua", "23");
System.out.println(mae);
//结果:
{xiaomei=23, xiaoli=23, xiaohua=23}
Map集合基本方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A6UixZwL-1654725363583)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//创建一个map
Map<String,String> mae = new HashMap<>();
mae.put("itheima01", "xiaomei");
mae.put("itheima02", "xiaohua");
mae.put("itheima03", "xiaofan");
mae.put("itheima04", "xiaogou");
mae.put("itheima05", "xiaomao");
// V put(K key,V value) 添加元素
// 如果要添加的键不存在,就会将键值对都存入集合中
// 如果要添加的键已经存在,就会覆盖原先的值,并返回被覆盖的值
String put = mae.put("itheima01", "aaa");//结果: xiaomei 返回被覆盖的值
System.out.println(put); // xiaomei
System.out.println(mae); // {itheima01=aaa, itheima02=xiaohua, itheima05=xiaomao, itheima03=xiaofan, itheima04=xiaogou}原先的值被覆盖
//*******************************************************
// V remove(Objcet k) 根据键来删除
String itheima02 = mae.remove("itheima02");
System.out.println(itheima02);//xiaohua
System.out.println(mae);//{itheima01=aaa, itheima05=xiaomao, itheima03=xiaofan, itheima04=xiaogou}
//void clear() 用于清空集合的所有元素
mae.clear();
sout(mae);// {}
//boolean containKey(Object Key) 判断集合中是否包含指定的键
boolean itheima01 = mae.containsKey("itheima01");
System.out.println(itheima01);//true 表示集合中包含指定的键
//这里我们试一下先清空再查找
mae.clear();
mae.clear();
boolean itheima01 = mae.containsKey("itheima01");
System.out.println(itheima01);//为false
//理解: 通过测试可以看出containKey判断集合中是否存在指定的键存在返回true否则就是false
//boolean containValue(Object value) 判断集合中是否包含指定的值
boolean ea = mae.containValue("xiaogou");
sout(ea);//为true 说明集合中包含值xiaomei 如果不存在则为false
boolean sea = mea.containValue("aaas");
sout(sea);//为false 因为集合不包含该值所以返回的是 false
//boolean isEmpty() 判断集合是否为空
boolean ae = mae.isEmpty();
sout(ae);//这里返回为 false 说明该集合不为空,如果为true说明该集合是空的
//这里测试清空集合看看是否结合为空返回的是true
mea.clear();
sout(mae);//true
//用来判断集合是否为空,为空返回为true 不是空返回的false
//int size 集合的长度
int i = mae.size();
sout(i);// 4
分析:在使用Map集合时添加是使用put
,当没用相同的键就直接存入,如果该键存在,就覆盖原来的键值,删除使用的remove
,判断集合中是否包含键使用containKey(Object k)
,判断集合中是否包含值containValue(Objcet V)
,清空集合使用clear()
,判断集合是否为空使用isEmpty()
,想看集合长度使用size()
。
遍历map集合
第一种
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1wnGDHEL-1654725363584)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ftgN328-1654725363585)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tai2iwnR-1654725363585)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GVHccr40-1654725363586)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HUA3svkf-1654725363587)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aqsgIGID-1654725363587)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//第一种 根据键来遍历
HashMap<String, String> se = new HashMap<>();
se.put("OneMan", "OneWife");
se.put("TwoMan", "TwoWife");
se.put("ThireMan", "ThireWife");
se.put("FourMan", "FourWife");
//Set<K>keySet() 获取所有的键集合
Set<String> keySet = se.keySet();
for (String s : keySet) {
//V get(Object key) 根据键获取值
String s1 = se.get(s);
System.out.println(s1);
}
//keySet 以为 键集 也就是map集合中的所有键
//理解:这种遍历就先后去的map中的键然后通过键来找对应的值
//步骤先使用KeySet获取集合中的所有键值,然后逐个遍历出来,然后再根据遍历出来的每个键来通过get方法来获取对应的值
第二种方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wia1sIw9-1654725363588)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
按键值对为一个整体,一个一个那出现,一个键对应一个值看做一个整体,上面三个
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jvZljgaT-1654725363588)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-029Idxn5-1654725363589)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
然后这种遍历获取到键值对为一个整体,就可以获取其中的键和值,核心就是先获取的整体在获取的内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vlg0OgxG-1654725363589)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BlTeBzsL-1654725363589)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
HashMap<String, String> se = new HashMap<>();
se.put("OneMan", "OneWife");
se.put("TwoMan", "TwoWife");
se.put("ThireMan", "ThireWife");
se.put("FourMan", "FourWife");
//首先获取集合中所有的键值对对象
//Set集合中装的是键值对对象(Entry对象)
//而entry里面装的是键和值
Set<Map.Entry<String, String>> entries = se.entrySet();
for (Map.Entry<String, String> entry : entries) {
//然后这里获得对象中的键和值
String k = entry.getKey();
String v = entry.getValue();
System.out.println(k+"************"+ v);
}
//结果
FourManFourWife
OneManOneWife
TwoManTwoWife
ThireManThireWife
总结
两种循环,第一种是通过keySet,键集来获取每一map种的键然后通过get
方法来获得每个键所对应的值,第二种方法就是将键值对作为一个整体,先获取将键和值作为一个整体,使用EntrySet
来获取集合中的所有键值对对象,然后循环获得的对象,就可以从对象中来获得每个对象所对应的键和值了。
HashMap底层原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lfKp5VcS-1654725363590)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ghobtZJ8-1654725363590)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
这里的Entrye对象就是刚刚第二种遍历中,的键值对对象,它是将键值对看做一个整体存入,然后通过计算其中键的hash值来选择存储的位置(注意与值无关)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IcQ4bQKn-1654725363590)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
通过键计算出来存储位置,发现没有元素,直接存入
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rw7XiUWY-1654725363591)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
如果位置已经存在对应元素,就会通过equals方法来对比两个元素中的键的哈希值,如果是true就覆盖原先的元素,false就旧元素挂在新元素下面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xIT1Tgxr-1654725363591)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
这里与set一样当长度大于等于时8会转成红黑树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xOBFIxIf-1654725363592)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
HashMap练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hkznFVU4-1654725363592)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//Student类
public class Student {
private String name;
private Integer age;
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (name != null ? !name.equals(student.name) : student.name != null) return false;
return age != null ? age.equals(student.age) : student.age == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (age != null ? age.hashCode() : 0);
return result;
}
}
//*********************************************************************
HashMap<Student, String> ese = new HashMap<>();
//创建学生类对象
Student xh = new Student("小虎", 23);
Student xm = new Student("小猫", 24);
Student xg = new Student("小狗", 26);
//存入map集合中
ese.put(xh, "广东");
ese.put(xm, "湛江");
ese.put(xg, "湖南");
//遍历集合
//第一种方法循环
Set<Student> students = ese.keySet();
for (Student student : students) {
System.out.println(student+"----"+ese.get(student));
}
//第二种方法循环
Set<Map.Entry<Student, String>> entries = ese.entrySet();
for (Map.Entry<Student, String> entry : entries) {
System.out.println(entry.getKey() +"------" + entry.getValue());
}
//第三种方法循环获取
ese.forEach(
(Student s ,String a)->{
System.out.println(s+"---"+a);
}
);
//解析第三种循环,结合下面的图片,理解,调用foreach底层是先通过键集合中的元素通过键值对对象的形式遍历获得,然后获取每个对象的键与值,action这个方法的k与v,然后我们匿名内部类里面的Student s 就是action里面的k String value就是action里面的v 相当于底层通过键值对的方式遍历分别获得对象的键和值,然后通过action来返回出去。
第三种遍历方法foreach底层
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EU9fUS4z-1654725363592)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
TreeMap
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DM9wHTCp-1654725363593)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ElczXvhJ-1654725363593)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Entrye对象是map中的键值对对象,当一个元素传入,就是根节点,第二个元素传入就需要和第一个元素通过equals来对比,对比的是键的来排序的与值无关的,相同就不能存储,不同就根据键来排序。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hSZPUP1y-1654725363594)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KBw2DEgt-1654725363594)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0uYIsSWl-1654725363594)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TfIRLBRW-1654725363595)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
TreeMap小结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uolGMfy4-1654725363595)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
TreeMap练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VVA1m0RM-1654725363595)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//TreeSet 有排列顺序 自定义类需要实现Comparatable 中的comparTo来对比
public class Student implements Comparable<Student>{
private String name;
private Integer age;
@Override
public int compareTo(Student o) {
//主要条件
//先比较年龄,年龄一样
int i = this.age - o.age;
//次要条件
//对比名称的顺序
i = i == 0 ? this.name.compareTo(o.name) : i;
return i;
}
}
TreeMap<Student, String> sea = new TreeMap<>();
Student e1 = new Student("xiaomin", 23);
Student e2 = new Student("aiaohuo", 23);
Student e3 = new Student("xiaoeti", 26);
sea.put(e1, "广州");
sea.put(e2, "浙江");
sea.put(e3, "湛江");
//第一种
Set<Student> students = sea.keySet();
for (Student student : students) {
System.out.println(student+"----"+sea.get(student));
}
System.out.println("--------------------------------------------");
//第二种
Set<Map.Entry<Student, String>> entries = sea.entrySet();
for (Map.Entry<Student, String> entry : entries) {
System.out.println(entry.getKey()+"----"+entry.getValue());
}
//第三种
sea.forEach(
(Student s ,String n)->{
System.out.println(s+"----"+n);
}
);
//结果:
Student{name='aiaohuo', age=23}----浙江
Student{name='xiaomin', age=23}----广州
Student{name='xiaoeti', age=26}----湛江
--------------------------------------------
Student{name='aiaohuo', age=23}----浙江
Student{name='xiaomin', age=23}----广州
Student{name='xiaoeti', age=26}----湛江
--------------------------------------------
Student{name='aiaohuo', age=23}----浙江
Student{name='xiaomin', age=23}----广州
Student{name='xiaoeti', age=26}----湛江
分析:使用TreeSet需要设置排序规则,自定义类必需要实现Comparatable在ComparTo来第一规则,或使用比较器Comparitor来实现。
可变参数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aoMFrT2d-1654725363596)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//测试
int a = 10;
int b = 20;
int c = 30;
System.out.println(sum(a, b, c));
System.out.println(sunt(a, b));
//方法
private static int sunt(int a, int b) {
return a+b;
}
private static int sum(int a, int b, int c) {
return a+b+c;
}
//前两个需求简单,但是当需求里面的参数有无数个怎么设置参数的个数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F1oo4nwt-1654725363596)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//可变参数
//上面的练习,不知道传入的数据个数
//在JDK5之前的是通过集合来解决的
int[] arr ={1,2,3,4,5};
getSum(arr);
//方法
private static void getSum(int[] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum = sum+arr[i];
}
System.out.println(sum);
}
//结果:
15
//分析,这个方法比较繁琐需要创建数组,而且要往数组内存数据,所以后面优化了
getSuum(1,2,3,4,5);
//方法
private static void getSuum(int...arr){//这里的...就是可变参数
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum = sum+arr[i];
}
System.out.println(sum);
}
//分析: 使用了可变参数后,优化了创建数组那一步,直接调用方法,它内部帮我们创建数组,然后循环得出得数
//可变参数,就是在不确定参数类型的情况,可以使用
分析:可变参数,就是当不确定参数类型的时候可以使用,它底层是实现就是将传入的参数放入数组中,然后内部调用数组来遍历得出得数是优化了JDK4,之前的要自己创建数组,而优化后java帮我们创建数组就不需要去创建数组了。
可变参数应用场景
创建不可变集合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2IuqlHHi-1654725363596)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//不可变集合
List<String> list = List.of("a","b","c","d");
list.add("qqq");
list.set(0,"e");
sout(list);//这里就会报错,因为list是一个不可变的集合,无法修改也无法删除
//有什么作用呢?
List<String> list = new ArrayList<>(List.of("a","b","c","d"));
//可以帮我们批量的实现结合的添加,之前是通过一个个调用add来添加的元素,这样就可以批量的添加元素
//不可变集合 Set集合对象
//注意Set集合是不可以重复的,所以在使用它的这个不可变集合的时候同样参数会报错
Set<String> seee = Set.of("a","b","c");
sout(seee);
//不可变集合 Map集合
Map<Integer,String> me = Map.of(1,"haa",2,"ee",3,"cc");
//它是将第一个元素当成k1第二个元素当成v1 这样就是一个键值对的形式
//Map还有一个不可变的集合
Map<Integer,String> es = Map.ofEntries(map.entry(1,"dd"),map.entry(2,"ss"));
//这里是先将键值对封装成一个entry对象,然后存入的map中,这样和上面的方法一样,只是增加了阅读性而已
总结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C1RZGPRi-1654725363597)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
泛型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TnLZvT7a-1654725363597)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//没有泛型
ArrayList arr = new ArrayList();
arr.add("aaa");
arr.add("eee");
iterator se = arr.iterator();
while(se.hasNext){
String si = (String)se.next; //这里使用强转
se.length;//这里报错,因为object中没有length 这里我们只能通过强转 但是由于没有泛型限制强转出现错误或报错
sout(si);
}
分析:使用了泛型就是将运行时期的问题到编译时期的时候来解决。例如:上面集合中传入了Int类型,int类型是无法强壮成string的就会在运行时报错,加了泛型就能防止出现这种错误。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n6od6w25-1654725363597)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
泛型类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KyG9nZpJ-1654725363598)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
ArrayList<E> arr = new ArrayList<>()
这就是泛型类E就是指定容器中存储的类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PoExkvCg-1654725363598)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
泛型类定义格式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fKGx9GRy-1654725363598)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//定义一个泛型类
public class Box<E> {//这里的Box定义是一个泛型类,在实例该类的时候就需要传入该类可存储的类型
private E name;
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
}
//调用
Box<String> stringBox = new Box<>();//
stringBox.setName("hahah");
System.out.println(stringBox.getName());
Box<Integer> integerBox = new Box<>();
integerBox.setName(12);
System.out.println(integerBox.getName());
//结果:
hahah
12
泛型方法
泛型方法的使用
ArrayList<String> arr = new ArrayList<>();
arr.add("hahah");
arr.add("hahah");
arr.add("hahah");
//将list集合转换成一个数组并返回
//如果是空参的,那么返回的数组类型为object类型的
Object[] objects = arr.toArray();//这里就是空参,也就是不告诉Array要存储的数据类型,那么它就会默认类型为object百搭
//若此时想要获取数组中的元素字符串中的方法,这里没有设置类型,就是默认的object类型要使用
//string就需要将object强转每一个都要强转才能使用不方便
//因此可以在toArray()带参数 在括号内创建一个String类型是数组 如 (new String[]);
//这样放回的数组就是字符串数组,里面的元素都是字符串类型的
System.out.println(Arrays.toString(objects));
String[] strings = arr.toArray(new String[arr.size()]);//带参数,是创建一个类型的数组,然后将长度为集合的长度。
System.out.println(Arrays.toString(strings));
分析:泛型方法,toAarray()
与toArray(T[] t )
一个是空参,那么就是默认为object类型,如果想要使用字符传里面的方法还要使用强转将集合内的object转成string才能使用就很不方便,所以还有第二个带参数的,在toArray就设定了类型,就会生成指定类型的数组,如果需要使用字符串的方法就不需要强转更加的方便。
自定义泛型方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xXDK18kP-1654725363599)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
// 就是在方法中创建了一个类型的限制,每调用该方法泛型由调用者来添加
//下这个方法是一个自定义的泛型方法,在调用的时候需要创建集合的泛型类型
public static <T> ArrayList<T> show(ArrayList<T> list,T t1,T t2,T t3){
list.add(t1);
list.add(t2);
list.add(t3);
return list;
}
//调用
System.out.println(show(new ArrayList<String>(), "a", "b", "c"));//这里的泛型是String类型的
sout(show(new ArrayList<Integer>(),1,2,3));//这里的泛型的Integer类型的
//结果
[a, b, c]
[1,2,3]
分析:自定义的泛型方法,在调用的时候输入对应的数据类型就必须传入对应的类型,不同类型会报错。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wm9VgmkU-1654725363599)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
泛型接口:
//第一中在实现类中不给泛型
//接口
interface Geti<E>{
void show(E e);
}
//实现类
class GetiImpl<E> implements Geti<E>{//这里没有给泛型,在测试中需要给泛型
@Override
public void show(E e) {
System.out.println(e);
}
}
//测试
GetiImpl<String> ae = new GetiImpl<>();//给上泛型String
ae.show("haha");//结果 haha
//第二种直接在实现类中给了泛型
//接口
interface Geti<E>{
void show(E e);
}
//实现类
class GetiImpl implements Geti<Integer>{//在实现类中直接给接口的泛型设置了数据类型,后就在测试中调用实现类就不需要输入类型了
@Override
public void show(Integer integer) {
System.out.println(integer);
}
}
//测试
GetiImpl es = new GetiImpl();//这就不需要设置泛型了
es.show(23);
理解:当接口是一个泛型接口的时候,在实现类中若没有给改接口定义泛型类型,在测试的时候就需要加上泛型类型,若在实现类中继承并设置了接口的类型那么在调用实现类就不需要设置泛型
泛型通配符:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S3a8fx8l-1654725363600)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0y28oElD-1654725363600)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//通配符
//如下面创建两个集合 要放入一个方法中遍历,那两个集合的泛型不同怎么放入一个方法中呢?
//那么就可以使用通配符,不管什么类型都可以被接收
ArrayList<String> arr = new ArrayList<>();//这里是字符串类型
ArrayList<Integer> aee = new ArrayList<>();//这里是数字类型
printArray(arr);//代用了同一个方法
printArray(aee);
//方法
private static void printArray(ArrayList<?> list) {//这里是?就是代表不管是任何类型泛型都可以作为参数放入
}
// ?extends Number 代表只能存放Number及其子类,高于Number的不能作为参数
private static void printArray(ArrayList<? extends Number> list) {
}
//上面的 printArray(arr)就会报错,因为String类型不是Integer类型所以报错了 integer是Number的子类所以没有报错
//? super Number 代表只能存放Number及其父类泛型
private static void printArray(ArrayList<? super Number> list) {
}
//上面两个都报错了 printArray(arr)与 printArray(aee)都报错,因此可以很好的理解了
分析:当泛型通配符为?
就说明该方法的参数可以放入任何泛型,如果出现了extend
就只能调用extends后面类的及其子类的泛型参数,super
就是只能是该类型及该类型的父类才能作为参数。
Stream流
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8T6JU8MF-1654725363600)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("张三");
arrayList.add("张四");
arrayList.add("张无二");
arrayList.add("张无忌");
arrayList.add("李四");
arrayList.add("王浩飞");
arrayList.add("懂小维");
arrayList.add("姜指翼");
ArrayList<String> se = new ArrayList<>();
ArrayList<String> san = new ArrayList<>();
for (int i = 0; i < arrayList.size(); i++) {
String s = arrayList.get(i);
if(s.contains("张")){
if(s.length() == 3){
san.add(s);
}else {
se.add(s);
}
}
}
System.out.println(arrayList);
System.out.println(se);
System.out.println(san);
//要获得名字为张且长度为3的需要这样,要先遍历获得为张的后面再遍历为3的,这样步骤比较多
-----------------------------------------------------------------------------------------
//如果使用stream流可以更加的简洁方便
arrayList.stream().filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3)
.forEach(s -> System.out.println(s));
//使用Stream流就可以过滤获取更加简洁的来获取数据
//结果:
张无二
张无忌
Stream流思想
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DoLmR5JL-1654725363601)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b1GwXwXi-1654725363601)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tIkMFTZ1-1654725363601)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Stream流的使用是和我们这个流水线是类似的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9nc5K4sV-1654725363602)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cBrBewji-1654725363602)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
Stream流获取方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kyhFYjsc-1654725363602)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lEo7BJuE-1654725363603)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//Stream流的获取
//单列集合: 集合对象.stream()
//双列结合: 不能直接获取,需要简洁获取
// 集合对象.KeySet().stream();
// 集合对象.entrySet().stream();
//数组:
// (数组名)
//同一类型
// (数据一,数据二,数据三)
//单列集合
ArrayList<String> alist = new ArrayList<>();
alist.add("a");
alist.add("b");
alist.add("c");
alist.add("d");
alist.stream().forEach(s-> System.out.println(s));//结果 : a b c d
//双列集合
//不能直接生成Stream流,要先获取集合中的KeySet或则entrySet再获取Stream流
HashMap<String, Integer> se = new HashMap<>();
se.put("k", 23);
se.put("e", 26);
se.put("s", 24);
Set<String> keySet = se.keySet();//获取集合中的所有键
//然后生成流,遍历获取键集合中的所有键值
keySet.stream().forEach(s-> System.out.println(s+se.get(s)));
//获取集合中的entrySet,也就是集合中的键值对对象
Set<Map.Entry<String, Integer>> entries = se.entrySet();
//然后生成Stream流,遍历获得每个键值对对象,
entries.stream().forEach(s-> System.out.println(s));
//数组类型
int[] arr = {1,2,3,4,5,6,7,8,9};
//数组类型需要使用Arrays中的静态方法Stream将数组放入就可以生成数组的Stream流并遍历
Arrays.stream(arr).forEach(s-> System.out.println(s));
//同种数据类型的Stream流
Stream.of(1,2,3,4,6,7).forEach(s-> System.out.println(s));
理解:单列集合创建Stream流可以直接创建就可以了,双列集合不能直接创建Stream流,因为双列集合中要获取集合中的元素需要先获取的键然后对应来获取值,才能遍历集合获得里面的元素,所以不能直接创建,直接放入Stream流java不会知道如何解析,所以需要先使用KeySet,然后来生成Stream流又或则生成对象entrySet来的获取Stream流,数组的话需要调用Arrays中的Stream方法放入数组就可以了,同类型的直接调用是一个可变参数,也可以来获取。
分析:单列集合生成Stream流因为他底层是数组,在流中可以任意操作每一个元素,双列集合要先获取KeySet或者entrySet,不然Stream流无法获取双列集合中的每个元素,就无法进行后面的对元素的操作。
Stream流常见中间操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aIzGSDTn-1654725363603)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//这个方法用来过滤集合中的元素
//为true就会留下 为false就会去除
ArrayList<String> ae = new ArrayList<>();
ae.add("张一山");
ae.add("张小斐");
ae.add("张陆");
ae.add("孙一鸣");
ae.add("六五二额");
//这里先获取流,然后过滤将为张的留下不为张的过滤,最后遍历输出
ae.stream().filter(s -> s.startsWith("张")).forEach(s-> System.out.println(s));
//filter里面的s代表集合中的每一个元素进来都会先对比是否为张 forEach是别过滤完后集合里面的元素进行遍历输出
分析:filter在流中可以用来过滤集合中的元素。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C1yG3gH2-1654725363603)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
ArrayList<String> ae = new ArrayList<>();
ae.add("张一山");
ae.add("张小斐");
ae.add("张陆");
ae.add("孙一鸣");
ae.add("六五二额");
//Stream<T> limit(long maxSize) 截取指定参数个数的数据
ae.stream().limit(3).forEach(s-> System.out.println(s));
//输出
张一山
张小斐
张陆
//理解:limit就是用指定输出多少条数据,输入数字后,就从头到尾的顺序来输出指定的个数
//**********************************************************************************************
//skip用来跳过的 跳过结合中前三个数据 输出后面的 就是用来跳过数据的
ae.stream().skip(3).forEach(s-> System.out.println(s));
//输出
孙一鸣
六五二额
//理解: skip字面意思就是用来跳过的,输入数字,跳过个数,从头到尾跳过指定个数后输出剩余的
//***********************************************************************************************
//concat用来合并两个流
ArrayList<String> as = new ArrayList<>();
ae.add("张一山");
ae.add("张小斐");
ae.add("张陆");
ae.add("孙一鸣");
ae.add("六五二额");
Stream.concat(as.stream(), ae.stream()).forEach(s -> System.out.println(s));
//concat用来拼接两个流形成一个新的流
//**********************************************************************************************
//distinct 用来去除重复的数据
ArrayList<String> as = new ArrayList<>();
ae.add("张一山");
ae.add("张小斐");
ae.add("张陆");
ae.add("孙一鸣");
ae.add("六五二额");
ae.add("六五二额");
ae.add("六五二额");
as.stream().distinct().forEach(s-> System.out.println(s));
//结果:
张一山
张小斐
张陆
孙一鸣
六五二额
//理解: 用来去重
分析:使用流的时候,filter用来过滤,limit用来决定输出的数据个数,skip用来跳过指定个数的数据,concat用来将两个流拼接到一起,distinct用来去除重复。
Stream流终结方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nJ5KfHOa-1654725363604)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
是Stream流中最后执行的方法
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(5);
arrayList.add(1);
arrayList.add(3);
arrayList.add(1);
//这里遍历获取集合中的所有元素,s就是代表集合中的每一个元素 ,然后执行里面的输出方法
arrayList.stream().forEach(s-> System.out.println(s));
//long count() 返回流中的元素数量
long count = arrayList.stream().count();
System.out.println(count);
Stream收集操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EaeVx95y-1654725363604)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
ArrayList<Integer> ase = new ArrayList<>();
for (int i = 1; i <=10 ; i++) {
ase.add(i);
}
ase.stream().filter(number -> number%2 == 0 ).forEach(number-> System.out.println(number));
sout(ase);
//输出
2 4 6 8 10
1 2 3 4 5 6 7 8 9 10
//发现没有改变集合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SMhxnfsX-1654725363604)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
说明流里面的拼接也好去重还是跳过等等方法都是无法直接修改集合的
Stream流收集操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hXdmfo2z-1654725363605)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
ArrayList<Integer> asew = new ArrayList<>();
for (int i = 1; i <= 10 ; i++) {
asew.add(i);
}
asew.add(9);
asew.add(9);
asew.add(9);
asew.add(9);
asew.add(9);
//filter 是用来过滤数据的
//colletor 是用来收集数据的,收集流中筛选完的数据据
//(); 底层会创建一个list集合将流中的元素全部放入创建出来的集合后就输出
List<Integer> collect = asew.stream().filter(s -> s % 2 == 0).collect(Collectors.toList());
System.out.println(collect);
//();同理底层创建一个set集合用来存储流中的元素,然后就可以输出。
Set<Integer> collect1 = asew.stream().filter(s -> s % 2 != 0).collect(Collectors.toSet());
System.out.println(collect1);
理解:filter
是用来过滤数据的,collector
用来收集流中的数据,因为获得通过流过滤完的元素成功一个集合就需要一个收集器那就是collector
,如果需要返回的类型的list的使用,Set 的使用
两个集合的区别就是Set会自动去重。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gYTzdxQP-1654725363605)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
收集返回map集合
ArrayList<String> a = new ArrayList<>();
a.add("zhansan,23");
a.add("lisi,24");
a.add("wangwu,25");
Map<String, String> collect = a.stream().filter(
(String s) -> {
String[] split = s.split(",");
int i = Integer.parseInt(split[1]);
return i >= 24;
}
//collect只能一个接收流中筛选完的元素,不能把数据添加到容器中
//底层就创建了一个map集合
//s 依次表示流中的每一个数据
//第一个lambda表达式就是如何获取map中的键
//第二个lambda表达式就是如何获取map中的值
).collect(Collectors.toMap(
(String s) -> {
String[] split = s.split(",");
return split[0];
},
(String s) -> {
String[] split = s.split(",");
return split[1];
}
));
System.out.println(collect);
}
//结果
{lisi=24, wangwu=25}
理解:因为流中对数据的操作,是无法直接修改集合的,所以如果当需要流筛选完的集合生成一个新的集合就需要在流中创建一个collectors
来收集流中筛选完的元素,toList
和toSet
区别就是toSet
会自动去重,如果要将流中的数据生成一个map集合就是toMap
,但要告诉map`元素中哪个给数据代表的键哪个数据代表的值。
Stream流的小练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qNtwSH5D-1654725363605)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
ArrayList<Actor> actors = new ArrayList<>();
Actor man1 = new Actor("郭富城", "男");
Actor man2 = new Actor("黎明", "男");
Actor man3 = new Actor("刘德华", "男");
Actor man4 = new Actor("范志毅", "男");
Actor man5 = new Actor("梅西", "男");
Actor man6 = new Actor("剋里斯", "男");
actors.add(man1);
actors.add(man2);
actors.add(man3);
actors.add(man4);
actors.add(man5);
actors.add(man6);
//这里是将男生数组变为一个流通过filter来筛选出姓名长度为3的然后限制输出2人
//().filter(s -> ().length() == 3).limit(2)
ArrayList<Actor> actors1 = new ArrayList<>();
Actor girl1 = new Actor("杨艳芳", "女");
Actor girl2 = new Actor("杨幂", "女");
Actor girl3 = new Actor("赵薇", "女");
Actor girl4= new Actor("杨亦菲", "女");
Actor girl5 = new Actor("吉克隽逸", "女");
Actor girl6 = new Actor("古力娜扎", "女");
actors1.add(girl1);
actors1.add(girl2);
actors1.add(girl3);
actors1.add(girl4);
actors1.add(girl5);
actors1.add(girl6);
//这是将女生数组变为流,然后将名字开头为杨的筛选出来,并且跳过第一个
//().filter(s -> ().startsWith("杨")).skip(1)
Stream<Actor> se = Stream.concat(actors.stream().filter(s -> s.getName().length() == 3).limit(2), actors1.stream().filter(s -> s.getName().startsWith("杨")).skip(1));
se.forEach(s-> System.out.println(s));
//结果
Actor{name='郭富城', sex='男'}
Actor{name='刘德华', sex='男'}
Actor{name='杨幂', sex='女'}
Actor{name='杨亦菲', sex='女'}
File和IO流
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TEZt8q83-1654725363606)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SdtLGQB8-1654725363606)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ybb5UdbC-1654725363607)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
File类概述和构造方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0pjTFH0l-1654725363607)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//File(String pathname)
string path = "D:\\java吃土\\";//这个是文件夹中真是存在的
File file = new File(path); //这里相当于操作该文件夹
//问题:为什么要将字符串表示形式路径转成file对象?
//因为我们是要对file进行操作,所以要使用file里面的方法对目标进行操作
//File(String parent,String child) 从父路径名字和子路径名字创建字符串
String s1 = "D:\\JAVA吃土";
String s2 = "\\";
//相当于把两个路径进行一个拼接。
File file1 = new File(s1, s2);
System.out.println(file1);
//File(File parent,String child)
File file2 = new File("D:\\JAVA吃土");
File file3 = new File(file2, "");
System.out.println(file3);
分析:第一个方法应用场景:当要使用字符串中路径下的文件夹的时候,就可以使用将字符串转成文件夹这样就相当于对文件夹中的文件进行操作,第二给方法和第三给方法是用与拼接将两个路径拼接在一起。
绝对路径和相对路径
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TR8s0M47-1654725363607)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
绝对路径是在盘符下的不会变的,相对路径是有一个参照物,在该参照物下的就是相对路径,也就是相对与参照物下的路径为相对路径
File类创建功能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XqVeTOPP-1654725363608)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//public boolean createNewFile() 创建一个新的文件
String es = "D:\\JAVA吃土\\";//在D下的文件夹中创建一个
File file = new File(es);
//createNewFile() 用来创建一个空的文件
//注意当文件存在,创建失败,返回false
//文件不存在,创建成功,返回true
boolean newFile = file.createNewFile();//这里就获得路径和要求的文件名在对应位置创建
System.out.println(newFile);
//public boolean mkdir() 创建一个单级文件夹
String parent = "D:\\JAVA吃土\\javase";//在D盘下创建javase这个文件夹
File file = new File(parent);
//注意 这个方法只能创建单级文件夹,如果有多个会无法处理
//就算加上后缀名,也只能创建文件夹
boolean mkdir = file.mkdir();//这里就是在指定的位置下创建文件夹
System.out.println(mkdir);
//public boolean mkdirs() 创建多级的文件夹
String sse = "D:\\JAVA吃土\\aa\\bbb\\ccc";
File file = new File(sse);
//这个方法比较无敌 可以创建多层文件夹 也可以创建单层文件夹
//当要创建的文件夹存在就会创建失败
boolean mkdirs = file.mkdirs();
System.out.println(mkdirs);
分析:上面方法createNewFile
是用来给对应的路径下创建空文件的,如果要在对应路径下创建文件夹推荐使用mkidrs()
因为可以创建多层也可以创建单层。
理解:相当于给它一个路径,它就会在指定的路径下创建文件,或则是文件夹,由我们自己来定义
File删除功能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F8a6KJXD-1654725363608)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//public boolean delete() 这个方法用来删除指定的文件和文件夹
//注意点:
//这个删除方法不走回收站是直接删除的
//如果删除的是文件,那么直接删除,如果删除的是文件夹,那么只能删除空的文件夹
//如果要删除一个有内容的文件夹,只能删除文件夹中的内容,最后再删除文件夹。
String pei = "D:\\JAVA吃土\\";
File file = new File(pei);
boolean delete = file.delete();//判断是否删除成功 成功为true 失败为false
System.out.println(delete);
File file1 = new File(pei, "aa");
//当路径为文件的时候 该方法可以上传文件 但是只能删除空文件夹,如果文件夹中有内容就无法删除
boolean delete1 = file1.delete();
System.out.println(delete1);
理解:这个方法可以用来删除文件以及文件夹,返回的是boolean为true说明删除成功,为false为删除失败,注意:如果删除的是文件那么是直接删除的,在回收站是找不到的,它是直接的删除,如果删除的是文件夹,文件夹为空没有内容也是直接删除的,若文件夹中有内荣就不能直接删除,需要删除文件夹中的内容,才能删除该文件夹。
File判断和获取功能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YdzQCCYp-1654725363608)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//public boolean isDirectory 用来判断指定路径的file是不是一个文件夹 是文件夹返回是true否则false
File file = new File("D:\\JAVA吃土\\aa");//这里我们的路径是一个文件夹
boolean file1 = file.isFile();
boolean directory = file.isDirectory();
System.out.println(file1);//结果为 false
System.out.println(directory);//结果 true
//public boolean isFile 用来判断指定路径下的file是不是一个文件 是文件返回true否则false
File file = new File("D:\\JAVA吃土\\");//这里的路径是一个文件
boolean file1 = file.isFile();
boolean directory = file.isDirectory();
System.out.println(file1);//结果为 true
System.out.println(directory);//结果 false
//************************************************************************************
//public boolean exists() 测试这个路径下的file是否存在 注意这里的存在是在当前项目中存在
File file2 = new File("");//看是否在当前项目下
boolean exists = file2.exists();
System.out.println(exists);
//public String getName() 获取指定路径文件夹名字
File file = new File("D:\\JAVA吃土\\aa");
File file = new File("D:\\JAVA吃土\\");
String name = file.getName();
System.out.println(name);//输出 aa
String nae = file.getName();
sout(nae);//输出
//分析:如果要获取名称的是文件的话,就会输出名称连着后缀输出,如果是文件夹,只输出文件夹名称
分析:isFile
判断指定路径的文件是否是一个文件,isDistory
判断指定路径的文件是不是一个文件夹,这个两个返回的都是布尔值,是为TRUE不是为false,exists
是用来判断该文件是否在当前项目 下,getName
就是用来获取文件或者文件夹的名称,如果是文件输出的是文件名和后缀名,如果是文件夹,就只输出文件夹名称。
File高级获取功能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dt27eiBn-1654725363609)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
String se = "D:\\";//指定路径
File file = new File(se);
File[] files = file.listFiles();//用来指定文件夹下的所有file,不管是隐藏的还是为隐藏的都可以获取到
for (File file1 : files) {
System.out.println(file1);
}
//如果调用者是一个文件,那么就会报错,因为文件不能读取的
//如果调用者是一个文件夹,那么就会读取里面的文件内容和隐藏的也能读取
//如果调用者是一个空的文件夹,就返回0
//如果调用则是一个有权限才能进去的,也会返回null
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WhOjx3ut-1654725363609)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
File练习
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sOWOKm4U-1654725363610)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
File file = new File("D:\\LearnMybatis\\ch06-dynamic-sql\\src\\main\\java\\com\\bjpowernode\\aa");
if(file.exists()){//这里先判断aa是否在项目中
//如果存在直接拼接并创建文件
File file1 = new File(file, "");
file1.createNewFile();
}else {
//如果不存在,先创建文件夹,然后在拼接路径创建文件
file.mkdirs();
File se = new File(file, "");
se.createNewFile();
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NioDTj6Z-1654725363610)(C:\Users\82053\AppData\Roaming\Typora\typora-user-images\)]
//方法
String pate="C:\\Users\\82053\\Desktop\\src";
File file = new File(pate);
DeletAll(file);
//方法
private static void DeletAll(File file) {
File[] files = file.listFiles();
for (File file1 : files) {
if(file1.isFile()){
file1.delete();
}else {
if(file1.length()==0){
file1.delete();
}else {
DeletAll(file1);
}
}
}
file.delete();
}
王者荣耀职业选手龙师傅
龙师傅射手
马可带净化用个6元皮肤加十点战斗力,先出鞋子,然后再差不多出基地把鞋子卖掉换攻速匕首。
eam().filter(s -> ().length() == 3).limit(2), ().filter(s -> ().startsWith(“杨”)).skip(1));
(s-> (s));
//结果
Actor{name=‘郭富城’, sex=‘男’}
Actor{name=‘刘德华’, sex=‘男’}
Actor{name=‘杨幂’, sex=‘女’}
Actor{name=‘杨亦菲’, sex=‘女’}
# File和IO流
[外链图片转存中...(img-TEZt8q83-1654725363606)]
[外链图片转存中...(img-SdtLGQB8-1654725363606)]
[外链图片转存中...(img-ybb5UdbC-1654725363607)]
### File类概述和构造方法
[外链图片转存中...(img-0pjTFH0l-1654725363607)]
```java
//File(String pathname)
string path = "D:\\java吃土\\";//这个是文件夹中真是存在的
File file = new File(path); //这里相当于操作该文件夹
//问题:为什么要将字符串表示形式路径转成file对象?
//因为我们是要对file进行操作,所以要使用file里面的方法对目标进行操作
//File(String parent,String child) 从父路径名字和子路径名字创建字符串
String s1 = "D:\\JAVA吃土";
String s2 = "\\";
//相当于把两个路径进行一个拼接。
File file1 = new File(s1, s2);
(file1);
//File(File parent,String child)
File file2 = new File("D:\\JAVA吃土");
File file3 = new File(file2, "");
(file3);
分析:第一个方法应用场景:当要使用字符串中路径下的文件夹的时候,就可以使用将字符串转成文件夹这样就相当于对文件夹中的文件进行操作,第二给方法和第三给方法是用与拼接将两个路径拼接在一起。
绝对路径和相对路径
[外链图片转存中…(img-TR8s0M47-1654725363607)]
绝对路径是在盘符下的不会变的,相对路径是有一个参照物,在该参照物下的就是相对路径,也就是相对与参照物下的路径为相对路径
File类创建功能
[外链图片转存中…(img-XqVeTOPP-1654725363608)]
//public boolean createNewFile() 创建一个新的文件
String es = "D:\\JAVA吃土\\";//在D下的文件夹中创建一个
File file = new File(es);
//createNewFile() 用来创建一个空的文件
//注意当文件存在,创建失败,返回false
//文件不存在,创建成功,返回true
boolean newFile = file.createNewFile();//这里就获得路径和要求的文件名在对应位置创建
System.out.println(newFile);
//public boolean mkdir() 创建一个单级文件夹
String parent = "D:\\JAVA吃土\\javase";//在D盘下创建javase这个文件夹
File file = new File(parent);
//注意 这个方法只能创建单级文件夹,如果有多个会无法处理
//就算加上后缀名,也只能创建文件夹
boolean mkdir = file.mkdir();//这里就是在指定的位置下创建文件夹
System.out.println(mkdir);
//public boolean mkdirs() 创建多级的文件夹
String sse = "D:\\JAVA吃土\\aa\\bbb\\ccc";
File file = new File(sse);
//这个方法比较无敌 可以创建多层文件夹 也可以创建单层文件夹
//当要创建的文件夹存在就会创建失败
boolean mkdirs = file.mkdirs();
System.out.println(mkdirs);
分析:上面方法createNewFile
是用来给对应的路径下创建空文件的,如果要在对应路径下创建文件夹推荐使用mkidrs()
因为可以创建多层也可以创建单层。
理解:相当于给它一个路径,它就会在指定的路径下创建文件,或则是文件夹,由我们自己来定义
File删除功能
[外链图片转存中…(img-F8a6KJXD-1654725363608)]
//public boolean delete() 这个方法用来删除指定的文件和文件夹
//注意点:
//这个删除方法不走回收站是直接删除的
//如果删除的是文件,那么直接删除,如果删除的是文件夹,那么只能删除空的文件夹
//如果要删除一个有内容的文件夹,只能删除文件夹中的内容,最后再删除文件夹。
String pei = "D:\\JAVA吃土\\";
File file = new File(pei);
boolean delete = file.delete();//判断是否删除成功 成功为true 失败为false
System.out.println(delete);
File file1 = new File(pei, "aa");
//当路径为文件的时候 该方法可以上传文件 但是只能删除空文件夹,如果文件夹中有内容就无法删除
boolean delete1 = file1.delete();
System.out.println(delete1);
理解:这个方法可以用来删除文件以及文件夹,返回的是boolean为true说明删除成功,为false为删除失败,注意:如果删除的是文件那么是直接删除的,在回收站是找不到的,它是直接的删除,如果删除的是文件夹,文件夹为空没有内容也是直接删除的,若文件夹中有内荣就不能直接删除,需要删除文件夹中的内容,才能删除该文件夹。
File判断和获取功能
[外链图片转存中…(img-YdzQCCYp-1654725363608)]
//public boolean isDirectory 用来判断指定路径的file是不是一个文件夹 是文件夹返回是true否则false
File file = new File("D:\\JAVA吃土\\aa");//这里我们的路径是一个文件夹
boolean file1 = file.isFile();
boolean directory = file.isDirectory();
System.out.println(file1);//结果为 false
System.out.println(directory);//结果 true
//public boolean isFile 用来判断指定路径下的file是不是一个文件 是文件返回true否则false
File file = new File("D:\\JAVA吃土\\");//这里的路径是一个文件
boolean file1 = file.isFile();
boolean directory = file.isDirectory();
System.out.println(file1);//结果为 true
System.out.println(directory);//结果 false
//************************************************************************************
//public boolean exists() 测试这个路径下的file是否存在 注意这里的存在是在当前项目中存在
File file2 = new File("");//看是否在当前项目下
boolean exists = file2.exists();
System.out.println(exists);
//public String getName() 获取指定路径文件夹名字
File file = new File("D:\\JAVA吃土\\aa");
File file = new File("D:\\JAVA吃土\\");
String name = file.getName();
System.out.println(name);//输出 aa
String nae = file.getName();
sout(nae);//输出
//分析:如果要获取名称的是文件的话,就会输出名称连着后缀输出,如果是文件夹,只输出文件夹名称
分析:isFile
判断指定路径的文件是否是一个文件,isDistory
判断指定路径的文件是不是一个文件夹,这个两个返回的都是布尔值,是为TRUE不是为false,exists
是用来判断该文件是否在当前项目 下,getName
就是用来获取文件或者文件夹的名称,如果是文件输出的是文件名和后缀名,如果是文件夹,就只输出文件夹名称。
File高级获取功能
[外链图片转存中…(img-Dt27eiBn-1654725363609)]
String se = "D:\\";//指定路径
File file = new File(se);
File[] files = file.listFiles();//用来指定文件夹下的所有file,不管是隐藏的还是为隐藏的都可以获取到
for (File file1 : files) {
System.out.println(file1);
}
//如果调用者是一个文件,那么就会报错,因为文件不能读取的
//如果调用者是一个文件夹,那么就会读取里面的文件内容和隐藏的也能读取
//如果调用者是一个空的文件夹,就返回0
//如果调用则是一个有权限才能进去的,也会返回null
[外链图片转存中…(img-WhOjx3ut-1654725363609)]
File练习
[外链图片转存中…(img-sOWOKm4U-1654725363610)]
File file = new File("D:\\LearnMybatis\\ch06-dynamic-sql\\src\\main\\java\\com\\bjpowernode\\aa");
if(file.exists()){//这里先判断aa是否在项目中
//如果存在直接拼接并创建文件
File file1 = new File(file, "");
file1.createNewFile();
}else {
//如果不存在,先创建文件夹,然后在拼接路径创建文件
file.mkdirs();
File se = new File(file, "");
se.createNewFile();
}
[外链图片转存中…(img-NioDTj6Z-1654725363610)]
//方法
String pate="C:\\Users\\82053\\Desktop\\src";
File file = new File(pate);
DeletAll(file);
//方法
private static void DeletAll(File file) {
File[] files = file.listFiles();
for (File file1 : files) {
if(file1.isFile()){
file1.delete();
}else {
if(file1.length()==0){
file1.delete();
}else {
DeletAll(file1);
}
}
}
file.delete();
}
王者荣耀职业选手龙师傅
龙师傅射手
马可带净化用个6元皮肤加十点战斗力,先出鞋子,然后再差不多出基地把鞋子卖掉换攻速匕首。