导图社区 JavaSE进阶
黑马程序员课程,主要包含面向对象进阶、 集合、Stream、 杂项、 高新技术、IO流、 多线程等。
编辑于2024-03-21 20:54:44JavaSE进阶
查看详细可依次练测平台、课程代码、黑马PPT、API文档
面向对象进阶
static
static修饰成员变量
main函数加载到堆中。 类加载到方法区中,对象保存在推内存中。
类变量(静态成员变量):属于类,在内存中只有一份,用类名调用 实例变量(对象变量):属于对象,每一个对象都有一份,用对象调用
static类变量的应用场景
如果某个数据只需要一份,且希望能够被共享(访问、修改),则该数据可以定义成类变量来记住。
static修饰成员方法
类方法(静态方法):static修饰的方法 可以被类名调用,是因为它是随着类的加载而加载的; 所以类名直接就可以找到static修饰的方法; 属于类,可以用类名调用,也可以用对象调用,但是不建议用对象调用,因为对象调用会多一次内存开销
staic应用场景-工具类
staic注意事项
实例方法中既可以直接访问类成员,也可以直接访问实例
类方法中可以直接访问类方法,但不可以直接访问实例方法
实例方法中可以出现this关键字
类方法中不可以出现this关键字
代码块
静态代码块,类加载时自动执行,只执行1次
实例代码块,每次创建对象时执行1次
设计模式
具体问题的最优解决方案
单例设计模式
构造器私有,看练测平台。 好处:任务管理器对象、获取运行时对象;在这些业务场景下,使用单例模式,可以避免浪费内存。
饿汉式单例
拿对象时,对象早就创建好了
懒汉式单例
拿对象时,才开始创建对象
模板方法设计模式
见练测平台抽象类应用案例
继承
特点
子类能继承父类的非私有成员(成员变量、成员方法)
Java是单继承的,可以多层继承。
权限修饰符
看练测平台
方法重写@Override
子类访问
在子类方法中访问其他成员(成员变量、成员方法),依照就近原则
先子类局部范围找。 然后子类成员范围找。 然后父类成员范围找,如果父类范围还没有找到则报错。
子类构造器
看练测平台
子类的全部构造器,都会先调用父类的构造器,再执行自己
默认情况下,子类全部构造器的第一行代码都是 super() (写不写都有) ,它会调用父类的无参数构造器。 如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写super(….),指定去调用父类的有参数构造器。
可以通过super关键字,指定访问父类的成员:super.父类成员变量/父类成员方法
兄弟构造器
我理解就是构造器重载
特点:1.this(…)和super(…)都必须放在构造器的第一行,否则报错
this:代表本类对象的引用;super:代表父类存储空间的标识
2.子类中的全部构造器,都必须先调用父类的构造器,再执行自己
3.super(…)调用父类有参数构造器的常见应用是为对象中包含父类这部分的成员变量进行赋值
4.this(…)一般用做在构造器中调用本类的其他构造器
多态
看练测平台!
多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态。
多态的前提:有继承/实现关系;存在父类引用子类对象;存在方法重写
注意事项:多态是对象、行为的多态,Java中的属性(成员变量)不谈多态
好处:可以解耦合,扩展性更强;使用父类类型的变量作为方法的形参时,可以接收一切子类对象
问题:多态下不能直接调用子类的独有方法
要强转,见练测平台,转不对可能出现类型转换异常(ClassCastException)
强转前,Java建议使用instanceof关键字,判断当前对象的真实类型,再进行强转
final关键字
修饰类:该类被称为最终类,特点是不能被继承了。 修饰方法:该方法被称为最终方法,特点是不能被重写了。 修饰变量:该变量只能被赋值一次。
常量
使用了 static final 修饰的成员变量就被称为常量
抽象类
最主要的特点:1.抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。2.抽象类就是为了更好的支持多态。
abstract修饰类,这个类就是抽象类; abstract修饰方法,不能写方法体,这个方法就是抽象方法
1.抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。 2.类该有的成员(成员变量、方法、构造器)抽象类都可以有。 3.一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。 4.抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。
好处:1.支持多态,提高代码的灵活性 2.让子类继承实现,方便系统拓展
接口
见练测平台!好处、应用案例
注意:接口不能创建对象;接口是用来被类实现(implements)的,实现接口的类称为实现类
一个类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类
好处:1.弥补了类单继承的不足,一个类同时可以实现多个接口。 2.让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现(更利于程序的解耦合)
JDK8后新增
默认方法:使用default修饰,使用实现类的对象调用。 静态方法:static修饰,必须用当前接口名调用 私有方法:private修饰,jdk9开始才有的,只能在接口内部被调用。 他们都会默认被public修饰。
作用:增强了接口的能力,更便于项目的扩展和维护
其它注意事项
1、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承。 2、一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现。 3、一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的。 4、一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
内部类
成员内部类
可以直接访问外部类的实例成员、静态成员
可以拿到当前外部类对象,格式是:外部类名.this
静态内部类
static修饰,可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员
匿名内部类
用于更方便的创建一个子类对象
通常作为一个参数传递给方法
枚举类
枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象
比较能限制规范实用,磊哥代码
枚举类构造器私有,故对外不能创建对象
为最终类不能被继承
第二行开始,可以定义类的其他各种成员
使用枚举类可设计单例模式
泛型
定义类、接口、方法时,同时声明了一个或者多个类型变量(如:<E>) ,称为泛型类、泛型接口,泛型方法、它们统称为泛型。
本质是把具体的数据类型作为参数传给类型变量
泛型类
泛型接口
泛型方法、泛型通配符、上下限
常见API
Object
StringBuilder
StringBuilder比String更适合做字符串的修改操作,效率会更高,代码也会更简洁
对于字符串相关的操作,如频繁的拼接、修改等,建议用StringBuidler,效率更高!
StringBuffer的用法与StringBuilder是一模一样的 但 StringBuilder是线程不安全的 StringBuffer是线程安全的
StringJoiner
JDK8出现的一个可变的、操作字符串的容器
不仅能提高字符串的操作效率,并且在有些场景下使用它操作字符串,代码会更简洁
Math
工具类,里面提供的都是对数据进行操作的一些静态方法,绝对值,向上向下取整,四舍五入,获取较大值,返回b次幂,0和1间随机数
System
工具类
currentTimeMillies(),返回从C语言诞生1970.01.01开始至今的毫秒值
exit()终止虚拟机
Runtime
虚拟机相关,可启动终止某程序
BigDecimal
用于解决浮点型运算时,出现结果失真的问题
时间
LocalDate
年、月、日
LocalTime
时、分、秒
LocalDateTime
年、月、日、时、分、秒
ZoneId
时区
ZonedDateTime
带时区的时间
DateTimeFormatter
用于时间的格式化和解析
Instant
时间戳
Period
时间间隔(年,月,日)
Duration
时间间隔(时、分、秒,纳秒)
Arrays
课程代码,看练测平台。
自定义排序规则方式一:让对象所在的类实现比较规则接口Comparable,重写compareTo方法,来指定比较规则
自定义排序规则方式二:sort存在重载的方法,支持自带Comparator比较器对象来直接指定比较规则
Lambda
见课程代码,练测平台。Lambda已经变成了标准和规范。
作用:简化函数式接口的匿名内部类
只有一个抽象方法的接口就是函数式接口
注意 : Lambda表达式只能简化函数式接口的匿名内部类!!!@FunctionalInterface
参数类型可以省略不写。 如果只有一个参数,参数类型可以省略,同时()也可以省略。 如果Lambda表达式中的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号!此时,如果这行代码是return语句,也必须去掉return不写
静态方法的引用
类名::静态方法
使用场景:如果某个Lambda表达式里只是调用一个静态方法,并且前后参数的形式一致,就可以使用静态方法引用。
实例方法的引用
对象名::实例方法
使用场景:如果某个Lambda表达式里只是调用一个实例方法,并且前后参数的形式一致,就可以使用实例方法引用
特定类型的方法引用
类型::方法
如果某个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。
构造器引用
类名::new
如果某个Lambda表达式里只是在创建对象,并且前后参数情况一致,就可以使用构造器引用
算法
见课程代码
冒泡排序
选择排序和优化
二分查找(折半查找)
前提条件:数组中的数据必须是有序的
实现步骤: 定义变量记录左边和右边位置。 使用while循环控制二分查询(条件是左边位置<=右边位置) 循环内部获取中间元素索引 判断当前要找的元素如果大于中间元素,左边位置=中间索引+1 判断当前要找的元素如果小于中间元素,右边位置=中间索引-1 判断当前要找的元素如果等于中间元素,返回当前中间元素索引
正则表达式
可以用文心一言解析,来写。 手机号码和邮箱的解析、及详细用法见课程代码。
中括号包起来的只能匹配一个
注意在Java中\为转义字符
replaceAll(String regex , String newStr) 按照正则表达式匹配的内容进行替换
split(String regex) 按照正则表达式匹配的内容进行分割字符串,反回一个字符串数组。
集合、Stream
List系列集合注意并发修改异常
HashSet/HashMap集合的底层原理
hashCode方法产生的值和表长度计算,得到元素的存储位置
JDK8之前:数组+链表
JDK8之后:数组+链表+红黑树
数据添加的流程
创建一个默认长度16的数组,默认加载因子为0.75,数组名table 使用元素的哈希值对数组的长度求余计算出应存入的位置判断当前位置是否为null,如果是null直接存入 如果不为null,表示有元素,则调用equas方法比较相等,则不存,不相等,则存入数组 JDK8之前,新元素存入数组,占老元素位置,老元素挂下面 JDK8开始之后,新元素直接挂在老元素下面
Collections集合工具类
综合案例:斗地主
map系列集合
1.HashMap:无序、不重复、无索引
2.LinkedHashMap:有序、不重复、无索引
3.TreeMap:可排序、不重复、无索引
键找值遍历、键值对遍历、Lambda遍历
Stream流
1.用来简化集合的操作,搭配Lambda表达式使用
2.三个阶段
1.获取流
1.针对集合
2.针对数组
2.操作流
1.filter():过滤数据
2.sorted():排序
3.distince():去重
4.limit():获取前面指定个数
5.skip():忽略前面的多个
6.map():映射
7.concat():拼接流
3.收集流
1.count():计数
2.max()和min():最大和最小
3.forEach():遍历流里面的元素
4.collect():收集流
杂项
File
1.用来操作文件,操作文件夹
2.具体使用
1.判断文件信息、获取文件的信息
2.创建文件、删除文件
3.遍历文件夹
1.list:返回String[],装名字
2.listFiles:返回File[]
综合案例:递归文件搜索
高新技术
Junit单元测试
反射
注解
动态代理
多线程
创建线程法1:继承Thread类,重写run方法,创建线程对象,在主函数中start启动
缺点:扩展性较差,不能再继承其他的类,不能返回线程执行的结果
创建线程法2:实现Runnable接口,重写run方法,在主函数中new Thread(实现Runnable接口的对象),再start启动
缺点:编程相对复杂,不能返回线程执行的结果
创建线程法3:实现Callable接口,重写call方法封装要做的事情和返回的数据,把Callable类型的对象封装成FutureTask(线程任务对象),把线程任务对象交给Thread对象处理,再start启动,最后通过FutureTask对象的get方法获取线程任务执行的结果
缺点:编程相对复杂
Thread常用方法:
sleep方法可以让当前线程睡眠一定时间再继续执行任务率。 join方法可以让当前线程优先执行的一种线程调度方法,一般用于对任务执行有顺序要求的场景。
解决线程安全问题
法1:同步代码块
实例方法建议用this作为所对象
静态方法建议用字节码(类名.class)对象作为锁对象
法2:同步方法
法3:Lock锁
线程通信
1.wait:让线程进行等待状态
2.notify:唤醒一个等待的线程
3.notifyAll:唤醒所有等待的线程
线程池
1.概念:存储线程的内容,管理线程,避免频繁创建销毁线程,浪费资源
2.创建方式
1.ThreadPoolExcutor:推荐使用
1.执行Runable任务
2.执行Callable任务
2.Executors工具类
线程状态
新建
就绪
锁阻塞
等待
计时等待
终止
IO流
字符集
GBK、UTF-8(默认编码)、ASCⅡ、ios-8859-1
编码:把字符串转化成字节数组:"".getBytes()
解码:把字节数组转化成字符串:new String(bytes[])
字节流
FileInputStream
1.一次读单个字节:read()
2.一次读多个字节:read(byte[])
3.一次读所有字节:read(byte[])或readAllBytes()
FileOutputStream
1.写入一个字节:write()
2.写入多个字节:write(byte[])
3.写入指定长度的字节:write(byte[],offset,len)
应用案例:拷贝文件
字符流
用来读取字符,按照字符单位来操作文件 FileReader & FileWriter 操作的单位都是字符,比较适合用来操作文本文件内容
缓冲流
1.对字节流或者字符流进行包装
2.具体使用
1.字节流:BufferedReader、BufferedWriter
2.字符流:BufferInputStream、BufferedOutputStream
3.读写性能得到了提升
转换流
1.把字节流转换成字符流,可以设置字符集。纺织读取中文数据出现乱码
具体使用
1.InputStreamReader
2.OutputStreamWriter
打印流
1.可以实现打印什么就输出什么的效果
2.PrintStream、PrintWriter
数据流
1.写入数据可把类型也写出去:DtaOutputStream
2.可以直接读取指定类型的数据:DataInputStream,如readUTF()
2.writeInt(),readInt()
对象流
序列化:把内存中的对象保存到硬盘文件中,序列化流:ObjectOutputStream
反序列化:把硬盘文件的内容读取到内存中,使用对象来接收:ObjectInputStream
要求:JavaBean类,必须实现接口Serializable
IO框架
1.commons-io
2.FileUtils和IOUtils
特殊文件、日志技术
读Properties配置文件
键值对形式,键不能重复
解析、生成properties文件,都直接用properties对象操作即可
解析XML文件
作用:用来做项目、系统配置文件
解析XML:dom4j
生成XML:不使用dom4j的API,直接使用I/O操作即可
Logback日志
实现类:JUL、log4j、logback
接口:jcl、slf4j
添加logback-core、logback-classic、slf4j这3个jar包; 构建Logger对象,调用trace() debug() info() warn() error(); logback.cml放在src下面