JavaSE
文章目录
- JavaSE
-
- MEMO1 前置内容
- MEMO2 DeBug、标识符、数据类型、进制相关
- MEMO3 运算符
- MEMO4 switch语句、循环语句
- MEMO5 数组、内存分配
- MEMO6 方法、方法重载
- MEMO7 类和对象
- MEMO8 String、StringBuilder
- MEMO9 ArrayList
- STEP0 分包思想
- STEP1 static关键字及应用
- STEP2 继承、重写、权限修饰符、抽象类及模板、final
- STEP3 接口、多态
- STEP4 内部类、Lambda、常用API
- STEP5 包装类、算法、Arrays工具类、异常
- STEP6 Date类、集合、迭代器、数据结构
- STEP7 泛型、TreeSet、二叉树
- STEP8 HashSet、Map集合、可变参数
- STEP9 Stream流、File
- STEP10 IO流及字符流、字节流
- STEP11 转换流、对象操作流、Properties、Clone
- STEP12 多线程
- STEP13 线程池、网络编程
- STEP14 TCP、日志、枚举
- STEP15 类加载器、反射
- STEP16 XML、文档约束DTD&schema
下划线 Ctrl+U 删除线 Alt+Shift+5 / ~~删除线~~ 水平分割线 *** / - - - / _ _ _ 高亮 ==高亮== / `高亮` 下标 ~下标~ 上标 ^上标^ 代码 Ctrl+Shift+` / ``` 选中一行 Ctrl+L 选中一个单词 Ctrl+D 选中相同格式的文字 Ctrl+E 生成目录 [TOC] 创建表格 Ctrl+T 创建超链接 Ctrl+K / [链接名称](链接地址) 搜索并替换 Ctrl+H 插入图片 Ctrl+Shift+I / [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-39kXtOIh-1658368869048)(图片地址)] 表情 :happy: / :smiley: / :cry: 向左缩进 Shift+Tab 可选框 - [ ] /- [x] (方括号前后都需加空格) 单换行 Shift+Enter HTML文本居中流程图语法居中文字 HTML键盘符 shift 增加注释
flow: strat:开始框 operation:处理框 condition:判断框 inputoutput:输入输出框 end:结束框 subroutine:子流程 各框通过“->”连接。定义上述基本元素的语句是: 元素ID=>元素类型:展示文字 元素ID(方向)->元素ID 方向:top、bottom、right、left st=>start: Start e=>end op=>operation: My Operation cond=>condition: Yes or No? st(right)->op(bottom)->cond cond(yes)->e cond(no)->op /********************************/ graph: graph TD; A-->B; A-->C; B-->D;IDEA
自动导包:setting->搜索auto->Auto Import->java.Add unambiguous.. Ctrl+Shift + Enter,语句完成 Ctrl+E,最近的文件 Ctrl+Shift+E,最近更改的文件 Shift+Click,可以关闭文件 Ctrl+[ OR ],可以跑到大括号的开头与结尾 Ctrl+F7,可以查询当前元素在当前文件中的引用,然后按 F3 可以选择 Ctrl+N,可以快速打开类 Ctrl+Shift+N,可以快速打开文件 Alt+Q,可以看到当前方法的声明 Ctrl+P,可以显示参数信息 Ctrl+Shift+Insert,可以选择剪贴板内容并插入 Ctrl+Alt+T,可以把代码包在一个块内,例如:try/catch Ctrl+Enter,导入包,自动修正 Ctrl+Alt+I,将选中的代码进行自动缩进编排,这个功能在编辑 JSP 文件时也可以工作 Ctrl+Alt+O,优化导入的类和包 Ctrl+R,替换文本 Ctrl+Shift+Space,自动补全代码 Ctrl+空格,代码提示(与系统输入法快捷键冲突) Ctrl+Shift+Alt+N,查找类中的方法或变量 Alt+Shift+C,最近的更改 Ctrl+J,自动代码(例如:serr) Ctrl+Alt+J,用动态模板环绕 Ctrl+Q,显示注释文档 Alt+F1,查找代码所在位置 Ctrl+Alt+left/right,返回至上次浏览的位置 Ctrl+Shift+Up/Down,向上/下整体移动语句 Tab,代码标签输入完成后,按 Tab,生成代码 Ctrl+Shift+F7,高亮显示所有该文本,按 Esc 高亮消失 Alt+F3,逐个往下查找相同文本,并高亮显示 Ctrl+Up/Down,光标中转到第一行或最后一行下 Ctrl+Shift+Backspace,跳转到上次编辑的地方 Ctrl+O,重写方法 Ctrl+Alt+Space,类名自动完成 Ctrl+Alt+Up/Down,快速跳转搜索结果 Ctrl+Shift+J,整合两行 Alt+F8,计算变量值 Ctrl+Shift+V,可以将最近使用的剪贴板内容选择插入到文本 Ctrl+Alt+Shift+V,简单粘贴 Shift+Esc,不仅可以把焦点移到编辑器上,而且还可以隐藏当前(或最后活动的)工具窗口 F12,把焦点从编辑器移到最近使用的工具窗口 Shift+F1,要打开编辑器光标字符处使用的类或者方法 Java 文档的浏览器 Ctrl+I,实现方法 Ctrl+Shift+U,大小写转化 Ctrl+J,查看更多 Ctrl+Shift+F,全局查找 Ctrl+F,查找/Shift+F3,向上查找/F3,向下查找 Ctrl+Shift+S,高级搜索 Ctrl+U,转到父类 Ctrl+Alt+S,打开设置对话框 Alt+Shift+Inert,开启/关闭列选择模式 Ctrl+Alt+Shift+S,打开当前项目/模块属性 Ctrl+G,定位行 Alt+Home,跳转到导航栏 Ctrl+Enter,上插一行 Ctrl+”+/-”,当前方法展开、折叠 【调试部分、编译】 Ctrl+F2,停止 Alt+Shift+F9,选择 Debug Alt+Shift+F10,选择 Run Ctrl+Shift+F9,编译 Ctrl+Shift+F10,运行 Ctrl+Shift+F8,查看断点 F8,步过 F7,步入 Shift+F7,智能步入 Shift+F8,步出 Alt+Shift+F8,强制步过 Alt+Shift+F7,强制步入 Alt+F9,运行至光标处 Ctrl+Alt+F9,强制运行至光标处 F9,恢复程序 Alt+F10,定位到断点 Ctrl+F8,切换行断点 Ctrl+F9,生成项目 Alt+1,项目 Alt+2,收藏 Alt+6,TODO Alt+7,结构 Ctrl+Shift+C,复制路径 Ctrl+Alt+Shift+C,复制引用,必须选择类名 Ctrl+Alt+Y,同步 Ctrl+~,快速切换方案(界面外观、代码风格、快捷键映射等菜单) Shift+F12,还原默认布局 Ctrl+Shift+F12,隐藏/恢复所有窗口 Ctrl+F4,关闭 Ctrl+Shift+F4,关闭活动选项卡 Ctrl+Tab,转到下一个拆分器 Ctrl+Shift+Tab,转到上一个拆分器 【重构】 Ctrl+Alt+Shift+T,弹出重构菜单 Shift+F6,重命名 F6,移动 F5,复制 Alt+Delete,安全删除 Ctrl+Alt+N,内联 【查找】 Ctrl+F,查找 Ctrl+R,替换 F3,查找下一个 Shift+F3,查找上一个 Ctrl+Shift+F,在路径中查找 Ctrl+Shift+R,在路径中替换 Ctrl+Shift+S,搜索结构 Ctrl+Shift+M,替换结构 Alt+F7,查找用法 Ctrl+Alt+F7,显示用法 Ctrl+F7,在文件中查找用法 Ctrl+Shift+F7,在文件中高亮显示用法
IDEA快捷键
- F2: 高亮错误或警告快速定位
- Shift + F6: 重命名
- Shift/Ctrl+ Enter:向下/向上插入新行(Space + Enter)
- Alt + 1:打开/关闭 左边工程目录
- Alt + 4:打开/关闭 控制台
- Alt + F7:查找整个工程中使用的某一个类、方法或者变量的位置
- Alt + Ins:生成构造器、getter、setter
- Alt + Shift + ↑/↓:代码上移/下移一行
- Alt + ←/→:切换活动窗口
- Alt + ↑/↓:在方法间快速移动
- Alt + Enter:修正代码
- Ctrl + X/Y:删除行
- Ctrl + H:显示类结构图(类的继承层次)
- Ctrl + P:显示形参列表
- Ctrl + N:全局查找类
- Ctrl + B:快速打开光标处的类或方法(跳转到定义处)
- Ctrl + W:可以选择单词继而语句继而行继而函数
- Ctrl + BackSpace:按单词删除
- Ctrl + F12:查看类的大纲
- Ctrl + Alt + V / method().var:快速声明接收方法返回值的变量
- Ctrl + Alt + M:抽取语句生成方法
- Ctrl + Alt + L:代码规范化(Space + T)
- Ctrl + Alt + T:代码块提取为循环
- Ctrl + Alt + Space:自动补全代码
- Ctrl + Alt + ←/→,返回至上次浏览的位置
- Ctrl + Shift + M:移动到光标所在行最近的大括号的始末端
- Ctrl + Shift + /:多行注释(Space + G)
- Ctrl + Shift + +/-:全部展开、折叠
- num.sout:快速输出变量值
- num.fori / arr.fori:快速生成for循环
EXPAND
数据交换原理:一个整数与另一个整数进行两次异或运算后还是原来的数据
a = a ^ b;
b = a ^ b; //b = a ^ b ^ b = a
a = a ^ b; //a = a ^ a ^ b = b开闭原则:对扩展内容开放,对修改内容关闭
- 不直接修改原代码,而是在同一个包下新建一个Other+原类名的类
- native关键字表示调用本地的方法(JDK底层或操作系统)
System.out.println(System.getProperty("user.dir"));
: 查看当前文件路径order by convert(name using gbk) asc
:按姓名首字母排序
TIPS
若方法返回的内容为随机产生的值,返回值在不赋值变量的情况下,整个方法调用语句仅能作为参数执行一次,否则会产生多个值
- 返回值不固定时,方法调用后先赋值
Scanner类录入字符串数据时,nextInt()方法以enter作为录入结束标记,若之前有其它数据类型的键盘录入则会直接enter其后的字符串录入
- 字符串数据优先录入
- 用next()录入字符串(以空格或Tab为结束标记)
- 实际问题场景:switch输入int型case后再在分支语句中输入字符串
当常量和变量都能调用方法时,优先用常量调用,避免空指针
- “abc”.equals(str)
在操作对象前,都须进行非空判断
- 关闭流对象
在分支语句中(包括 if 和try…catch)进行的操作,编译器都会认为可能不会被执行,所以不能当作一个确定的结果来写逻辑;而是必须在每种可能情况下都做类似的操作,才能通过编译
重写方法可以实现扩展方法作用域的效果,如重写Object中的由protected修饰的clone方法
MEMO1 前置内容
javac.exe: 编译命令
java.exe: 解释运行时用的命令
javadoc.exe: 生成文档注释时的命令
- javadoc文档注释:注释内容可以被jdk工具javadoc所解析,生成一套以网页文件形式体的该程序的说明文档(写在代码之前)
/**
文档注释
@author wyw
@version v1.0
*/JDK(java程序开发工具包) = JRE + Java开发工具(java.exe javac.exe javadoc.exe)
JRE(Java程序运行环境) = JVM + Java SE标准类库
MEMO2 DeBug、标识符、数据类型、进制相关
- DeBug设置一个断点和多个断点区别:
- 一个断点:从断点开始,每条语句依次运行
- 多个断点:上个断点所在语句运行完后,Resume Program即跳至下一个断点,中间语句静默运行
- 循环语句中右键断点可以跳转到指定的循环次数
标识符命名规则:不能以数字开头;不能占用关键字
- 小驼峰式命名:
适用于:变量名、方法名
比如:name、firstName- 大驼峰式命名:
适用于:类名
比如:Name、FirstName数据类型
- byte、short、char在进行运算时会直接提升为int型
- 对于常量之间的运算,会在编译阶段优先运算出常量结果,再予以赋值,即为java常量优化机制
数据类型 关键字 内存占用 取值范围 整数 byte 1 -128~127 整数 short 2 -215 ~ 215-1 (-32768~32767) 整数 int 4 -231 ~ 231-1 (约21亿) 整数 long 8 -263 ~ 263-1 (19位数) 浮点数 float 4 1.401298e-45到3.402823e38 (38位数) 浮点数 double 8 4.9000000e-324 到1.797693e308 (308位数) 字符 char 2 0-65535 布尔 boolean 1 true,false 二进制:
- 二进制:以0b或0B开头
八进制:以数字0开头
十六进制:以0x或0X开头
- 任意进制转十进制:各位数 * 基数的权次幂相加 0567 = 7 * 80 + 6 * 81 + 5 * 82
- 十进制转任意进制:十进制%基数,整数部分除尽为止,各余数从右向左排列 20 % 8 = 4,2 % 8 = 2,所以20的八进制为024
- 二进制按每三位划分即为八进制,每四位划分则为十六进制
- 原码、反码、补码:
- 正数原反补码一致
- 负数反码为原码除符号位以外各位取反,补码为反码+1
- 计算机中以补码形式进行运算,负数补码符号位参与运算(规定10000000表示-128)
- 位移运算:符号位不变,其余数据向指定方向移动
- 左位移<<:原数据 * 2n (n为移动位数)
- 右位移>>:原数据 / 2n
- 无符号位运算:空出的数位统一为0(负数右移变为整数)
MEMO3 运算符
后自增自减操作符总是变量先参与操作再进行自增自减
- int a = 10; b = a++ + a++; //a = 12, b = 21
复合赋值运算符(+=、-=…) 自带强转效果
| 优先级 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| ------ | --------- | ------ | ------- | ---- | ----------- | --------------- | ------- | ---- | ---- | ---- | ---- | ---- | ----- | ------ |
| 运算符 | . () {} | ! ++ | * / % | + - | << >> >>> | < <= instanceof | == != | & | ^ | | | && | || | ? : | = += |取反逻辑运算符使用场景:
- 例:除了数字3、11、14其余都可通过 ! (num == 3 | num == 11 | num == 14)
&& 和 || 具有短路效果,即在已经确定运算结果的情况下,不会进行后续运算
MEMO4 switch语句、循环语句
案例:输出一定范围内的质数
switch语句:
案例:switch语句执行顺序
switch()中可以接收的数据类型:byte、short、int、char、String、枚举
(仅取值范围较小的数据类型)
jdk14开始,switch语句中,一个case后可以编写多个值
switch中变量
一旦匹配上case或default,便不再继续匹配关键字
,仅会依次执行语句无论default写在哪儿,一定是最后匹配
int num = 4; switch (num){ default: System.out.println(45); case 1: System.out.println(1); break; case 2: System.out.println(2); case 3: System.out.println(3); }}}//输出结果为45 1 /**************************************************/ int num = 2; switch (num){ case 1: System.out.println(1); case 2: System.out.println(2); case 3: System.out.println(3); default: System.out.println(45); }}}//输出结果为2 3 45
- break关键字仅能在
循环语句和switch语句
中使用- continue关键字仅能在
循环语句
中使用 //输出一定范围内的质数 for(int i = 2;;i++){ for(int j = 2;j <\= i ; j++) { if(i % j == 0) { if(i == j){ System.out.println(i); } else break; } } } /***************************/ for(int i = 2;;i++){ boolean trigger = true; for(int j = 2;j < i;j++) { if(i % j == 0){ trigger = false; break; } } if(trigger) System.out.println(i); }
MEMO5 数组、内存分配
- 定义格式:
- int[ ] arr = new int[0];
- int[ ] arr = {1,2,3};或 int[ ] arr = new int[ ]{1,2,3};//静态初始化中,后中括号内不得定义数组长度
- 注意事项:
- 数组静态初始化时,每个数组索引对应的值先默认为0或null,随即再被静态赋值
- 例:int[ ][ ] = new int[3][ ] ; arr[0] = null ; //因为一维数组没有初始化,所以没有地址值
- 二维数组中的一组一维数组地址用另一个一维数组地址赋值时,即被新的数组取代,即不受定义二维数组的数组长度限制
Arrays.toString()
:按既定格式表示数组元素//二维数组遍历 for (int i = 0 ; i < arr.length ; i++) { for (int j = 0 ; j < arr[i].length ; j++) { System.out.println(arr[i][j]); }}
- java内存分配
栈:方法运行时所进入的内存
堆:new出来的东西会在堆中开辟空间并产生地址
方法区:字节码文件(.class)加载时进入,随后JVM自动调用main方法,然后进栈内存
本地方法栈
寄存器
整体流程:字节码文件加载进方法区,同时加载所有方法进方法区,随后JVM自动调用main方法进栈;在栈内调用其他方法,执行结束后按先进后出顺序出栈,最后main方法出栈
一维、二维数组内存图![一维数组内存图](https://img-blog.csdnimg.cn/img_convert/8c0fd9b2c5ffcf989548e93ced9b1dcd.png)4. *空指针异常*:当一个引用数据类型(*数组,类,接口*)的变量,记录到null之后,代表和堆内存的连接就被切断了,此时若访问该地址,即出现此错误
MEMO6 方法、方法重载
- return在方法中全部被条件语句(if和for循环)控制时,编译器会报错,因为return可能无法被执行
- 方法中传递参数时,基本数据类型传递的是数值,引用数据类型传递的是地址值
- 方法重载必要条件:同一个类中,方法名相同,参数不同
- 参数不同:个数不同、类型不同、顺序不同
MEMO7 类和对象
- 类的字节码文件被调用时才会加载进方法区
- 构造方法:用于创建对象,可以给成员变量赋值
- 构造方法中可以写return,但是不能有返回值
- 构造方法不能被对象调用
- JavaBean中要求提供一个public的空参构造
- 便于通过反射创建运行时类的对象
- 便于子类继承此运行时类时,能够调用super();
- 创建对象代码执行顺序:初始化父类完成再创建子类对象
先加载类
① 加载父类:父类的静态成员
② 加载子类本身:子类本身的静态成员
创建对象
③ 加载父类非静态和构造代码块
④ 加载父类构造器内部代码
⑤ 加载子类非静态和构造代码块
⑥ 加载子类构造器内部代码
MEMO8 String、StringBuilder
一、String
- String对象间使用==作比较时,比较的是字符串地址值而非内容
- 打印String对象并非显示地址值
- System.out.println(stu + 100 + " "); //编译不通过
- stu在底层会调用toSting方法,但stu实际上是地址值,地址值和常量不能直接做运算
- String字符串一旦被创建,该字符串对象就不可更改
String s = "abc"; s = "def" //s指向新对象的地址,原来的"abc"内容没有变化,直到被JVM自动清理 //相当于 Student stu = new Student("张三",24) stu = new Student("李四",25)
- 字符串常量池:
- 在使用 " " 创建字符串对象的时候,会先检查该数据在常量池中是否存在,若存在,则对象指向该地址;使用多个对象创建相同内容字符串,都会指向常量池中同一地址
- 在使用带参构造创建字符串常量时(
new String("abc")
)(该条语句创建了两个字符串对象),检查常量池中是否存在,存在则拷贝一份副本进堆内存,再将堆内存中的地址交给对象;不存在则创建,再重复上述地址赋值操作
- JDK8以后,字符串常量池在堆内存中
- 字符串和字符数组可以相互转换
- str.toCharArray()
- str.charAt(int Index):返回指定索引处的元素
- String str = new String(new char[ ] chs)
- String类常用方法
public String substring(int beginIndex)
:根据索引截取字符串public String substring(int beginIndex,int endIndex)
:根据首尾索引截取字符串 [beginIndex,endIndex)public void concat(String str)
:在末尾添加字符串public String replace(String target,String replacement)
:新值替换旧值public String toUpperCase()
:小写转大写public int compareTo(String s)
:按字典顺序依次比较两个字符串的对应字符,返回码表中对应字符串相减的结果public String[] split(String regex)
:根据传入参数,作为规则切割字符串,并返回切割后的数据
- str =192.168.0.1 ;
String sArr = str.split(".")
二、StringBuilder
- 字符串拼接原理:
StringBuilder sb = new StringBuilder();
flowchat
op1=>operation: 系统自动创建sb对象
op2=>operation: 自动调用sb.append()拼接
append()可链式调用
op3=>operation: 自动调用sb.toString()转换成字符串
op1(right)->op2(right)->op3(right)StringBuilder线程不安全,StringBuffer线程安全(加锁),其余功能相同
MEMO9 ArrayList
体系结构:LinkedList、HashSet、LinkedHashSet、TreeSet、ArrayList……
ArrayList原理:
flowchat
op0=>operation: 底层先创建一个长度为0的数组
当执行add操作时,再创建一个长度为10的数组
(形参内可指定初始长度)
op1=>operation: 数据量超出长度时,会自动创建
一个原数组1.5倍大小的新数组
op2=>operation: 原数组内容自动
拷贝进新数组
op3=>operation: 超出数据存入新数组
op0(right)->op1(right)->op2(right)->op3(right)3. 格式:ArrayList\<E\> list = new ArrayList<\>(); * <E\>:Integer、Character、其余基本数据类型首字母大写 4. 常用方法: 1. 增: * `public boolean add(E e)`:尾部添加数据 * `public void add(int Index,E e)`:插队添加数据 * `public boolean addAll(Collection<? extends E> c)`:将原集合的所有数据添加到新集合的末尾 * `public boolean addAll(int index,Collection<? extends E> c)`:将原集合的所有数据添加到新集合的指定位置 2. 删: * `public E remove(int Index)`:删除指定索引位置的元素 * `public boolean remove(Object o)`:删除*首次*出现的元素(整数类型的集合中形参默认为索引而非元素) 3. 改: * `public E set(int Index,E e)`:修改指定索引位置为传入元素 4. 查: * `public E get(int Index)`:获取指定索引位置的数据 * ==public int size()==:返回集合中元素个数 * `public boolean contains(Object o)`:检查集合中是否包含参数
STEP0 分包思想
类与类之间的访问:
- 同一个包下的类,可以互相直接访问
- 不同包下的类,必须先导包才可以访问
- 若类中使用不同包下的相同类名,只能默认导入一个包,另一个类需要使用全名访问
业务通用架构:
flowchat
op0=>operation: entry包(程序入口)
op1=>operation: controller包(展示层)
与用户交互并封装用户数据
op2=>operation: service包(业务层)
业务逻辑处理
op3=>operation: dao包(数据层)
操作数据库(增删改查)
op0(right)->op1(right)->op2(right)->op3(right)
STEP1 static关键字及应用
一、static
- 静态成员变量、静态成员方法:
- 相同点:
- 由static修饰,都属于类,可由类直接调用
- 和类一起加载,只加载一次,内存中只有一份
- 可以被共享访问、修改
- 同一个类中可以单独调用(不加类名.)
- 不同点:
- 静态成员变量只在堆内存中存储一份
- 静态成员方法只在方法区中存储一份
- 使用场景:以执行一个通用功能为目的,或为方便访问
- 注意事项:
- 静态方法只能访问静态成员,不可直接访问实例成员
- 实例方法可以访问静态成员,也可访问实例成员
- 静态方法中不可出现this关键字(没有对象)
- static不能修饰局部变量(局部变量不可能随类一同加载)
二、工具类,代码块,单例模式
工具类:可将常用方法封装到工具类中,方法统一用static修饰,方便调用
- 工具类无需创建对象,所以可将构造器私有化
代码块:{ }
- 静态代码块:由static修饰,属于类,与类一起优先加载一次,自动执行,用于初始化静态资源(如斗地主中初始化54张牌)
- 局部代码块:定义在方法中,用于限定变量的生命周期,可以及早释放,提高内存利用率(不会优先执行)
- 构造代码块:定义在类中方法外,每次调用构造器创建对象时,会优先执行代码块中代码,用于初始化实例资源。用于将多个构造方法中相同的代码,抽取到构造代码块中,提高复用性
- 单例模式:构造器私有,内部创建对象相关属性静态化
饿汉单例:提前创建好对象,并声明一个静态变量存储
懒汉单例:需要对象时,才会创建一个对象(声明一个静态方法以返回创建好的对象)
懒汉单例中静态变量应私有化,以防初始化前 直接调用该静态变量出现空指针
好处:即用即加载,节约内存
坏处:线程不安全
解决线程不安全:获取对象的方法加锁 或 使用双重检查锁
//双重检查锁 class Student1 { //1 私有构造方法 private Student1() { } //2 在类的内部声明该对象的变量 private static Student1 s = null; //3 提供公共的方法(静态的)创建该对象 并返回返回该对象 public static Student1 getStudent() { if (s == null) { synchronized (Student1.class) { if (s == null) { s = new Student1(); } } } return s; } }
- 相比于静态方法加锁,双重检查依据对象是否被初始化进行了分流,若已被初始化则直接返回对象, 避免了每个变量都须通过检查获取锁对象,提高了运行效率
STEP2 继承、重写、权限修饰符、抽象类及模板、final
一、继承
格式:public class 子类 extends 父类
定义:父类的公共属性和方法可以由子类共享
继承设计规范:子类们共性特征放在父类中定义,独有的特征定义在各自子类中
构造器:
- 子类不能继承父类的构造器
- 子类构造器第一行语句默认为super();(可省略),以调用父类无参构造器初始化其数据空间;
- 子类调用父类有参构造:子类构造器编写super(参数…) (参数为子类构造器形参)
构造器中使用this调用本类其他构造参数:
初始化部分参数的有参构造可以通过this()调用本类的其他有参构造以提高代码复用性,传入参数以外的参数可以写死(new关键字才会创建对象,对象个数与调用几个构造器无关)
public A(int num){
this(num , “其他固定参数”); }
public A(int num,String str){
this.num = num;
this str = str; }
```
通过this调用其他构造器时,这些构造器也会通过super默认调用父类构造器
由于this()和super()都只能放在构造器的第一行,所以两者不能共存于同一个构造器中
特点:
- 单继承:一个类只能继承一个直接父类(只有一个亲爹)
- 父子类中特征冲突则执行就近原则,使用*super.*可以访问父类特征
- 若支持多继承,则可能出现两个父类中有重复特征而造成调用冲突
- 支持多层继承(子父爷)
- java中所有的类都是Object类的子类
补充说明:
- 子类实际上也继承了父类的私有特征,但无法直接调用,可以暴力访问 //TODO
- 父类的公共静态特征可以被子类名调用,且实际上可以在子类中直接无类名调用父类的静态方法
二、重写
@override //重写校验注解:不构成重写时报红 public void method(){ super.method(); 新增语句……; }
注意事项:
- 重写方法的返回值、名称、形参列表必须与被重写方法保持一致*(声明不变,重新实现)*
- 子类的返回值类型必须是父类返回值类型或其子类
- 私有、静态方法不能被重写
- 子类重写方法的修饰权限不小于父类相应方法
flowchat
op0=>operation: public
不同包的无关类
可访问
op1=>operation: protected
同一个包内和不同包的子类
可访问
op2=>operation: default
同一个包中子类无关类
可访问
op3=>operation: private
同一个类中
可访问
op0(right)->op1(right)->op2(right)->op3(right)***三、抽象类*** 1. 定义:若一个类中存在抽象方法,那么该类就*必须*声明为抽象类 * 抽象方法:将共性行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体定义,该方法就可以定义为抽象方法 2. 注意事项: * 抽象类不能创建对象(以防调用到抽象方法) * 抽象类中有构造方法(给子类创建对象时调用) * 抽象类的子类必须重写抽象类中的所有抽象方法(子类也可声明为抽象类,但意义不大) * 抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类 ***四、final*** 1. 可修饰对象: * ① 方法:表明该方法不能被重写 * ② 类:表明该类不能被继承 * ③ 变量:表明该变量是常量,*不能再次被赋值* * 基本数据类型变量:值不能更改 * 引用数据类型:地址值不能更改,但可以修改对象属性 * 修饰成员变量时有三个赋值时机:1.声明时赋值 2.构造方法中赋值 3.*代码块中赋值* 2. 模板设计模式:抽象类整体可以看做一个模板,模板中不能定义的方法抽取成抽象方法,在子类中重写 * 可以用final修饰模板,以防被重写,破坏原结构功能
STEP3 接口、多态
一、接口
- 定义:内部是抽象方法的特殊抽象类
- 格式:public interface 接口名 {}
- JDK8后新特性:
- 允许在接口中定义非抽象方法,但须使用关键字default修饰。
用于解决接口扩展后,实现类也必须进行非必要的重写问题
- 格式:public default void method() { }
- 允许在接口中定义静态方法
- 静态方法只能通过接口名调用,不能通过实现类类名或对象名调用
- static和default不能共存。
静态方法不能被重写- 可以使用private修饰仅在接口类中使用的方法,须去掉default(JDK9)
- 接口实现:接口和类之间是实现关系,通过implements关键字表示
- 接口可以单实现,也可以多实现 :public class 实现类名 implements 接口名1,接口名2 {}
- 接口和接口之间可以多继承,接口只能继承接口 (实现和继承的主要区别)
- 接口的实现类必须重写接口中的所有抽象方法,或者声明为抽象类(不推荐)
- 接口类组成:
- 成员变量:默认被public static final修饰(可省略)
- 由于接口的多实现特性,若变量不声明为静态,则会在多个实现类中出现变量名冲突(java不允许多继承的原因之一);且静态常量可以只在内存中存在一份,节省内存。同时接口作为标准规范,不允许实现类随意修改数据,所以须用final修饰
- 构造器:无。
由于内部有抽象方法,所以不能实例化,也就没有构造器- 成员方法:默认被public abstract修饰(可省略)
- 接口注意事项:
- 默认方法不是抽象方法,但可以被重写,重写时须去掉default
- 若实现类实现了多个接口,且多个接口中存在相同的default方法声明,实现类必须重写该方法
- 一个类的父类和接口类中出现相同的方法声明且代码逻辑不同,优先使用父类的方法(亲爹 > 干爹)
- 接口不会默认继承Object类
- 接口使用思路:
- 若类中都是抽象方法,则可将该类改进为一个接口
- 涉及到接口大面积更新,而不想修改每一个实现类,就可以将更新的方法定义为带有方法体的default方法
- 希望default方法调用更加简洁,可以考虑设计为静态方法(须去掉default)
- default方法中出现了重复代码,可以考虑抽取出一个私有方法以仅供内部调用(须去掉default)
二、多态
- 前提:
- 需要继承 \ 实现关系
- 需要方法重写
- 需要父类对象指向子类对象 Animal a = new Cat();
- 成员访问特点:
- 构造方法:同继承一样,子类通过super访问父类构造方法
- 成员变量:编译看左边(父类),执行看左边
- 成员方法:编译看左边,执行看右边(子类)
- 因为成员方法有重写,成员变量没有
- 优缺点:
- 优点:提高了程序扩展性(定义方法时,使用父类型为参数,该方法就可以接收父类的任意子类对象)
- 缺点:不能使用子类的特有功能
- 转型:
- 向上转型:父类引用指向子类对象
Fu f = new Zi();
- 向下转型:父类引用转为子类对象
Zi z = (Zi)f;
- 类进行强转时,编译器会检查是否为继承关系,非继承关系则报错;
- 接口进行强转时,由于接口是多实现,编译器会认为任何类都可以实现任何接口,所以会编译通过,但是运行时会报错
- instanceof:待强转变量名 instanceof 目标类型
- 判断关键字左边的变量,是否是右边的类型,返回boolean
- 总结:
- 对象的类型永远不变
- 只能调用引用所属类型中的方法
- 运行时,会优先找子类重写后的方法,否则用父类的方法
- 静态方法由于没有重写,所以谁调用就用谁的
STEP4 内部类、Lambda、常用API
一、内部类
创建内部类对象格式:Outer.Inner oi = new Outer().new Inner();
类型:
成员内部类:也属于类成员,随成员在实例化时一同初始化
常用用法:
防止类名冲突:同一包下的其中一个相同类名可以声明为内部类
间接实现多继承:
class A extends Super{
class B extends Super{ }
}
注意事项:内部类中外部类的this格式为Outer.this
静态成员内部类访问格式:Outer.Inner oi = new Outer.Inner(); Outer.Inner.method();
- 静态内部类不会随外部类加载而加载
- 创建静态内部类对象时,外部构造器不会执行
- 静态内部类推荐不创建对象,直接使用
- 静态内部类中可以有常量和静态常量。因为java中常量存放在常量池中,编译时,加载常量是不需要先加载类的
局部内部类:在方法中创建的类,只能在方法中创建对象并访问
- 局部内部类不仅可以访问外部类的私有成员,还可以访问所在方法的局部变量
- 被内部类访问的局部变量会被拷贝一份到内部类中,即Inner类中存在一个成员变量,用于记录被访问的局部变量的值。若局部变量不是final的,其取值就可以被修改,而Inner对象中保存的是其原来的值,这就会出现数据不同步的问题。Java为了避免数据不同步的问题,做出了内部类只可以访问final的局部变量的限制。在java8中,可以不使用final,如果局部变量被内部类访问,那么该局部变量相当于自动使用了final修饰。
匿名内部类:将继承\实现、方法重写、创建对象三个步骤整合在一起
格式:new 类名或接口名(){
重写语句;
}.重写方法名();
匿名内部类编译后会产生一个单独的字节码文件,格式为 外部类$数字.class
二、Lambda表达式
格式:
doMethod( new interfaceA(形参) { public void method() { 代码块 } }); //Lambda格式 doMethod( (形参) -> { 代码块 });
使用前提:
- 仅适用于接口
- 接口中有且仅有一个抽象方法
省略格式:
- 参数类型可以省略
- 参数有且仅有一个时,小括号可以省略
- 代码块中的语句仅有一条时,可以省略大括号、分号和return(省略return后默认返回语句结果)
补充:Lambda表达式编译后没有单独的.class字节码文件,对应的字节码会在运行时动态生成。匿名内部类则会产生一个单独的字节码文件
三、常用API
- Math类:
public static int abs(int a)
:返回参数的绝对值public static double ceil(double a)
:向上取整public static double floor(double a)
:向下取整public static int round(float a)
:四舍五入public static int max(int a,int b)
:返回最大值public static int min(int a,int b)
:返回最小值public static double pow(double a,double b)
:返回a的b次幂public static double random()
:返回[0,1)的double值- Math.sqrt()开方、Math.PI 圆周率
- System类:
public static void exit(int status)
:终止当前运行的虚拟机public static longcurrentTimeMillis()
:获取当前时间距离1970年1月1日的毫秒数arraycopy(原数组,起始索引,目标数组,起始索引,拷贝个数)
- Objects类:
public static String toString(Object o,nullDefault)
:返回对象的字符串表现形式,若为空,则返回nullDefaultpublic static Boolean isNull / nonNull(Object o)
:判断对象是否为空 / 不为空- BigDecimal类:用于精确计算
public BigDecimal add/subtract/multiply/divide (BigDecimal bd2)
:使用形参为字符串类型的构造方法才能精确计算
- 只能传入数字类型的字符串
public BigDecimal divide(BigDecimal bd2,精确几位,舍入模式)
:ROUND_UP(进一法)、ROUND_FLOOR(去尾法)、ROUND_HALF_UP(四舍五入)
STEP5 包装类、算法、Arrays工具类、异常
一、包装类
- 概述:将基本数据类型封装成对象,即可以在对象中定义更多的功能方法以操作数据
- 常用方法:
- 常量: MAX_VALUE / MIN_VALUE: int类型的最值
public static Integer valueOf(int i)
:int --> Integerpublic static Integer valueOf(String s)
:数字形式的String --> Integerpublic Integer(int value)/(String s):根据int/String创建Integer对象(已过时)public int intValue()
:Integer --> intpublic static parseInt(String s)
:数字形式的String --> int
- int --> String:①加" ";②
public static String valueOf(int i)
- 自动装箱和自动拆箱:
- 装箱:把基本数据类型转换为对应的包装类类型
- 拆箱:把包装类类型转换为对应的基本数据类型
- Object o = 12;(自动拆装箱)
- 注意事项:若需操作包装类类型时,须先判断是否为null(适用于所有对象)
二、算法
- 冒泡排序:元素排列方向必须与遍历方向相同,否则无法将最值筛选出来
- 递归:将一个复杂问题转换为一个较小规模的问题
- 具体实现为:在方法中再次调用该方法。必须在最小规模处给一个return出口
三、Arrays
- 常用方法:
static binarySearch(Object o,Object target)
static compare(Object[] a,Object b)
static copyOf(Object[] o,int newLength)
static copyOfRange(Object[] o,int from,int to)
static sort(Object[] o) / sort(Object[] o,int fromIndex,int toIndex)
static toSting(Object[] o)
四、异常
JVM的默认处理方案:把异常的名称,异常原因及异常出现的位置等信息输出在控制台并在异常出现处终止程序
异常类继承结构:
throws 异常类名:写在方法定义处,表示调用该方法可能出现该异常;当异常发生时,将异常抛给调用者
- 当调用者调用该方法时,必须选择继续向上抛异常 或 自行处理异常
- 编译时异常必须写在方法后 进行显示声明
- 运行时异常可以省略不写
throw new 异常类名():写在方法中,手动抛出异常,并结束该方法运行
- 使用时机:①当参数传递有误时,就没有继续运行的意义,则抛出异常终止该方法运行;②告诉调用者出现了问题
- 可使用有参构造输出自定义的错误信息
异常抛出总结:
- 当方法体中抛出运行时异常时,可处理可不处理
- 当方法体中抛出编译时异常时,则必须选择在方法声明处throws向上抛 或 自行try…catch
Throwable常见方法:
getMessage()
:返回throwable的详细字符串信息toString()
:返回异常类名+详细字符串信息printStackTrace()
:把异常错误信息输出到控制台(红色字体其实打印的就是异常堆栈信息)try…catch…:手动处理异常
- try中出现异常,会直接跳转到对应的catch语句中;当catch语句全部执行完毕,则会继续执行try…catch体系之后的代码
- 出现catch没有捕获的问题或没有手动编写异常处理代码,则默认交给虚拟机处理
- 有多个异常就编写多个catch;若异常之间存在继承关系,则父类一定要写在下面
- 子类重写的方法不能抛出 父类方法抛出的异常类及其子类 以外的异常(但可以所有抛出运行时异常)(子类重写的方法也可以不抛出异常,也符合该规则),为了满足多态的要求。子类在覆盖父类方法的时候,父类的引用是可以调用该方法的,如果父类的引用调用子类的方法,那么这个多抛出来的异常,就可能处于一种无法被处理的状态(多态的用法)
- catch中能添加的异常分支必须是try语句中可能抛出的异常。对于未检查异常而言,程序运行过程中都有可能抛出,所以都能添加;而对于已检查异常,若try中没有声明抛出,则无法添加
finally:必须写在try…catch体系后,无论有无异常,finally中的代码都会执行。(System.exit()除外)
- 与return同时存在时,先执行finally,再执行return
- 用于关闭数据库资源,关闭IO流资源,关闭socket资源
自定义异常类:
- 须继承Exception类,无参构造和有参构造可以直接通过super()调用父类构造器
STEP6 Date类、集合、迭代器、数据结构
一、Date类
构造方法:
public Date()
:创建读取当前计算机上的时间public Date(long date)
:表示从时间原点开始,过了指定毫秒的时间(在不同地区会加上时差)常用成员方法:
public long getTime()
:获取时间对象距时间原点的毫秒值public void setTime(long time)
:设置时间,参数为距时间原点的毫秒值SimpleDateFormat类:可以对Date对象进行格式化和解析
- 2020-11-11 12:10:15 --> yyyy-MM-dd HH:mm:ss
- 构造方法:
public SimpleDateFormat()
:使用默认格式创建对象public SimpleDateFormat(String pattern)
:使用指定格式创建对象- 成员方法:
public final String format(Date date)
:Date --> String(Date对象按SDF指定格式转为字符串)public Date parse(String source)
:String --> Date(字符串格式必须与SDF类中 有参构造中的格式保持一致)二、集合
集合类体系结构:最底层为实现类,其余都是接口