本人自己总结的corejava的知识点如下
环境变量的搭建
编程语言
人与人沟通 自然语言 汉语、英语、日语、韩语…
人机对话 编程语言
低级: 机器语言
中级:汇编语言、C语言
高级:Java、Python
Java语言
Java的由来
- 95 sun Green项目组 James Golsing(詹姆斯高斯林)
- 99 分为三大方向:J2SE、J2EE、J2ME – > 05 JavaSE、JavaEE、JavaME
- 09 被Oracle收购
- 14 JDK 8.0
Java的语言特点
- 面向对象
- 简单性
- 跨平台
如何实现跨平台???
Oak 中小型消费电子产品 (收音机、微波炉)
—》 Java
-
Java运行机制:先编译,后解释
编译:将
源文件(.java文件)
编译成.class文件
(字节码文件,无限接近于二进制的文件)解释并运行: 将
.class文件
解释并运行
特点 : 跨平台,执行效率高
理念:Write Once Run Anywhere 一次编写,到处运行
-
**JVM(Java虚拟机) **: 屏蔽底层操作系统(OS)差异
JRE运行环境: JVM+解释器
JDK开发环境:JRE + 编译器+开发工具包(JDK类库+调试工具)
配置环境变量
JAVA_HOME : jdk的安装目录, 例: C:\Program Files\Java\jdk1.8.0_92
Path : JDK 安装目录下的bin目录,例:C:\Program Files\Java\jdk1.8.0_92\bin
classpath : .
类路径
DOS命令操作
- 打开:
win+r cmd
- 查看当前目录下的所有文件及文件夹:
dir
- 进入文件夹:
cd 文件夹名称
- 盘符切换:
d:
- 清屏 :
cls
- 退出:
exit
第一个Java应用程序
-
创建
.java
文件 -
代码
- 类 代码的容器
- 主函数 程序的入口
- 打印语句 :在控制台输出一句话
- 每句代码以分号(英文格式 ; )结尾
class HelloWorld{ public static void main(String[] args){ System.out.println("9班的同学们,你们好"); //换行打印 System.out.print("晚上要好好敲代码..."); //不换行打印 } }
-
编译:
javac 源文件名称.java
javac A.java -
运行/解释:
java 类名
java HelloWorld
注意:
1. 一个类中只能定义一个主函数
- 一个源文件中可以定义多个类,每个类都会生成对应的.class文件;但是类名不能相同
公开类
被public
修饰的类,称为公开类
- 公开类类名必须和源文件名称保持一致
- 一个源文件中只能定义一个公开类
public class Test{
public static void main(String[] args){
System.out.println("早上好");
}
}
包package
作用:管理.class
文件
语法:package 包名
位置:源文件有效第一行
带包编译:javac -d . 源文件名称.java
带包运行 : java 包名.类名(全限定名)
编码规范
-
书写格式
层级之间要有缩进(一个制表符(tab))
一行只写一句代码
-
代码注释
单行注释
// 注释内容
多行注释
/* 多行注释内容 */
文档注释 (生成外部文档javadoc -d 文件夹名称 源文件名称.java)
/**文档注释内容 */
【了 解】注意:注释不参与编译
-
标识符的命名规范
- 语法规定:
- 只能由字母、数字、_ 、$组成,数字不能开头
- 严格区分大小写
- 没有长度限制
- 不能使用关键字、保留字(goto、const)、特殊字(true、false、null)
- 约定成俗:
- 望文生义、遵循驼峰命名法
- 类名:由一个、多个单词组成,每个单词的首字母大写
HelloWorld
- 函数名、变量名:由一个、多个单词组成,首单词首字母小写,后面的单词首字母大写
helloWorldTest
- 包名:全小写,包与包之间使用
.
隔开。采用域名倒置 ,www.baizhi.com
-->com.baizhi.entity
- 常量名 : 全大写 , 每个单词之间使用
_
隔开HELLO_WORLD
- 语法规定:
变量
**概念:**计算机内存中的一块存储空间,用来存储数据
变量的组成:变量名、变量类型、变量值
变量的使用流程
- 声明变量 让jvm分配内存
变量类型 变量名;
int a;
- 赋值 为变量赋上数据
变量名 = 变量值;
a = 10;
- 变量的使用 通过变量名获取
System.out.println(a);
变量声明的多种方式
声明的同时并赋值 int b = 20;
同时声明多个变量并赋值
int b = 10,c,d = 40;
c = 30;
注意: Java是强类型的语言,数据类型
必须和变量类型
保持一致
数据类型
-
基本|原始数据类型
-
整数
数据类型 字长 取值范围 byte 1Byte (字节) -128~127 short 2B -32768~32767 int 4B -2147483648~2147483647 long 8B -9223372036854775808
~9223372036854775807
-90京 ~ 90京需要在字面值后追加L或l 注意:整数的默认类型是int
-
小数,浮点数
数据类型 字长 精度 float 4B 单精度 必须在字面值后追加F或者f double 8B 双精度 D或d 可加可不加 注意:浮点数的默认类型是double
-
字符型
char
字长2B 0~65535采用 Unicode字符集 万国码
字面值形式 :
字符型 ‘A’
整数型 65-‘A’ 97 - ‘a’ 48-‘0’
16进制 ‘\u0041’ - ‘A’
转义字符:
转义字符 描述 \n
换行符 \t
缩进(制表位) \\
反斜线 \'
单引号 \''
双引号 -
布尔类型
boolean
true( 真 )\false(假)注意:布尔类型不参与算数运算
-
-
引用|对象数据类型
字符串 String
String s = "ashdjasd";
注意:字符串可以是0-n个字符组成
类型转换
-
自动类型提升
两种类型相互兼容
目标类型 范围大于 源类型
byte --> short --> int --> long --> float --> double char --> int
-
强制类型转换
两种类型相互兼容
目标类型 范围小于 源类型
int a = 10; short s = (short)a;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6zgUBbAq-1574690630589)(D:/feiq/Recv Files/CoreJava/day02 ----变量及运算符/笔记/1571734285201.png)]
-
算数运算时类型提升
double + double/其他类型 --> double
float +其他类型(不含double) – > float
long + 其他类型(不包含double+float) --> long
int + 其他类型(不包含double+float+long) --> int
byte、short之间进行运算 --> int
注意: String类型可以和任意类型进行
+
运算 , 结果自动提升为String类型 --》字符串拼接
运算符
表达式:使用运算符连接的变量或字面值,并可以得到一个最终结果。
算数运算符: + - * /(除) %(求模)
一元运算符: ++ 、-- 让自身+1 或者-1
a++ : 先取值,后自增 ; ++a : 先自增,后取值
赋值运算: = 、-=、+=、*=、/=、%= (不会进行类型转换)
关系运算符:< 、>、<= 、>=、==(判断是否相等)、!=(不等于) ——> 布尔表达式
逻辑运算符:
&&(并且|与) 两者都为true --> true
|| (或者|或) 有一个为true --> true
! (取反) !true --> false ; !false–>true
三元运算符: ? :
布尔表达式?值1:值2
思考:如何让a+1, 小于原来的a ??? [面试题]
条件分支流程
控制台输入
- Scanner(扫描仪):接收用户输入的数据
//创建扫描仪
java.util.Scanner sc = new java.util.Scanner(System.in);
//让用户在控制台输入数据
//并且进行接收
String s = sc.next(); //接收一个字符串
int a = sc.nextInt(); //接收一个整数
double d = sc.nextDouble(); //接收一个小数
**注:**如果输入了不匹配的数据,则会产生java.util.InputMismatchException
- import 导包语句
定义位置:package 语句下方,class语句上方
语法:import 包名.类名;
import java.util.*; //导入 java.util包下的所有类
**注意:**默认导入java.lang包,String、System 都位于java.lang包;同包下的类不需要导入
条件分支语句
概念:根据某个条件是否成立,来决定某段代码是否执行。
分支语句的执行次数0-1
次
if分支【重点】
if(布尔表达式){
//if代码块
}else{
//else代码块
}
- 若布尔表达式为true,则执行if代码块
- 若布尔表达式为false,则执行else代码块
多重if
if(布尔表达式1){ 代码块1 }
else if(布尔表达式2){ 代码块2 }
else if(布尔表达式3){ 代码块3 }
else{ 代码块4 }
后续代码...
- 若布尔表达式1 - true,则执行代码块1;跳出分支语句,执行后续代码
- 若所有的表达式结果为false,则执行代码块4(else代码块)
- 只能执行其中之一
嵌套if
if(){
if(){}else if(){}else{}
}else{
} //当外层条件满足时,才会判断内层条件
if(){}
if(){}else{}
if(){}else if(){}else{}
if(){
if(){}else if(){}else{}
}else{
if(){}else if(){}else{}
}
switch… case
switch(int表达式){
case 值1:代码块1
case 值2:代码块2
case 值3:代码块3
...
}
后续代码...
- int表达式的值与那个case值相匹配从哪进入switch代码块(决定了入口)
break
: 跳出switch代码块(手动添加出口)default
: 当所有的case不匹配时执行
// 5 6 7差 8 9良好 10优秀
Scanner sc = new Scanner(System.in);
int score = sc.nextInt();
switch(score){
case 5:
case 6:
case 7:System.out.println("差");break;
case 8:
case 9:System.out.println("良好");break;
case 10:System.out.println("优秀");break;
default:System.out.println("输入有误");
}
细节:
- switch后的表达式 可以是
int
以及所有能够提升为int
的数据类型 , byte、short、char、int - since JDK 7.0 可以使用String作为表达式类型
对比:
用switch case 能做的,用if else 一定能做
用if else能做的 , 用switch case 不一定能做
思考:为什么可以用String类型???怎么实现的???
局部变量【重中之重】
概念:声明在函数内部的变量,称之为局部变量
特点:必须先赋值,后使用
作用范围:从定义行开始,到所在的代码块结束
注意:相同作用范围内
不允许命名重复
循环执行流程
概念:根据某个条件是否成立,来多次执行同一段代码
循环的四部分:
- 循环变量的初始化
- 循环变量的迭代
- 循环条件
- 循环体
while循环
执行次数:0-n次
while(布尔表达式){ //若布尔表达式为true,则执行逻辑代码;直至布尔表达式为false,则执行后续 代码
//逻辑代码
}
...
//打印10遍HelloWorld
int i = 0; //循环变量的初始化
while(i<10){ //循环条件 -- 决定了循环次数
System.out.println("HelloWorld"+i); //循环体
i++; //循环变量的迭代
}
while(true){ //死循环 -- 无限循环,没有结束的出口
System.out.println(111111);
}
int i = 0;
while(i<10){
System.out.println(111111);
}
do…while循环
执行次数:1-n次
do{
//逻辑代码
}while(布尔表达式);
- 不管条件是否成立,先执行一遍do代码块
- 执行一遍后,若结果仍然为true,则再次执行逻辑代码
- 直到结果为false,结束循环
for循环
for(循环变量的初始化;循环条件;循环变量的迭代){
//循环体 逻辑代码
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n6jN92MO-1574690630590)(D:/feiq/Recv Files/CoreJava/day04 ----循环/笔记/1571901148280.png)]
i = 0;i<10 执行10遍
i = 0;i<=10 11遍
i = 1;i<10 9遍
i = 1;i<=10 10遍
for(;;){ //死循环
System.out.println(1111);
}
流程控制语句
break;
跳出switch代码块、循环结构
continue;
跳出本次循环
嵌套循环
for(int i=0;i<3;i++){ //外层循环决定行数
for(int j=0;j<5;j++){ //内层循环决定列数
System.out.print("*");
}
System.out.println(); //换行
}
// i=0 j=0 1 2 3 4 * * * * *
// i=1 j=0 1 2 3 4 * * * * *
// i=2 j=0 1 2 3 4 * * * * *
label标签【了解】
outer:for(int i=1;i<=5;i++){ //label标签 给循环起的名字
inner:for(int j=1;j<=4;j++){
if(j==2) break outer; //跳出的时候 指定跳出的循环
System.out.print("i="+i+",j="+j+"\t");
}
System.out.println();
}
函数执行
概念:一段功能代码,可以反复使用
函数的使用流程
-
函数的声明 约定了函数的功能
public static 返回值类型 函数名(形参列表)
-
参数【重点】:调用者向被调用者传递的
数据
形式参数(形参):变量的声明,相当于函数内部的
局部变量
实际参数(实参):为形参
赋值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LhPSfH9x-1574690630590)(D:/feiq/Recv Files/CoreJava/day05 ----函数/笔记/1571986656196.png)]
注意:实参和形参必须保证,
数量、类型、顺序
一致 -
返回值【重点】:被调用者返回给调用者的数据
返回值类型 :
void : 没有返回值
八种基本数据类型、String
public static void main(String[] args){ int d = add(); System.out.println(d); } //计算两个数的和 public static int add(){ return 10; //return value; 将数据value进行返回 }
return 关键字:
- 结束函数的执行,
return value;
语句后不要定义代码 - 一个函数只能有一个
return value;
语句被执行 - 如果函数内部有分支结构,保证每一个分支都具有
return value;
语句 - 若函数返回值类型为void,可以用
return
关键字,控制函数执行流程
- 结束函数的执行,
-
-
函数的实现 实现约定的功能
{ //代码块 }
-
定义位置 类以内,与主函数并列
-
函数的调用【重点】
无参调用:函数名();
有参调用:函数名(实参列表);
有返回值调用:数据类型 变量名 = 函数名(实参列表);
注意:
数据类型
跟返回值类型
一致
public static 返回值类型 函数名(形参列表){
//函数的实现代码
}
返回值类型、函数名、形参列表 ---》 函数三要素
函数的作用
- 提高可读性
- 减少代码冗余
- 提高复用性
- 提高可维护性
函数的嵌套调用
在一个函数内部调用另外一个函数
递归【了解】
一个函数调用了它本身,称之为递归调用
注意:需要为递归函数手动添加出口,否则会无穷递归,运行报错
报错信息为java.lang.StackOverflowError
(内存溢出)
递归的思想:
当解决一个大问题时,可以分解为多个小问题;而且小问题的解决方案跟大问题一致。可以使用递归
数组
概念:一组连续的存储空间,一次性存储多个相同
数据类型的数据
数组的使用流程:[重点]
-
声明数组 :
数据类型[] 变量名;
int[] a; int []a; int a[];声明数组的多种方式 声明的同时并分配空间:数据类型[] 数组名 = new 数据类型[长度]; 声明的同时并为元素赋值:int[] a = new int[]{元素值1,元素值2,元素值3,...}; 注意:不再为其分配长度 int[] a = {元素值1,元素值2,元素值3,...}; 注意: int[] a ; a = {元素值1,元素值2,元素值3,...}; //error
-
分配空间:
变量名 = new 数据类型[数组的长度];
a = new int[5];
数组的下标范围: 0 - 数组名.length-1
元素访问 : 数组名[下标];
当访问超出下标范围的元素,则运行报错:
报错信息为:java.lang.ArrayIndexOutOfBoundsException(下标越界)
数组的长度:数组名.length
数组的遍历:一一获取所有元素
for(int i=0;i<a.length;i++){
System.out.print(a[i]+"\t");
}
System.out.println();
数组元素具有默认值:
byte\short\int\long 0
float\double 0.0
char 空字符|0
boolean false
String null
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r7IWApB3-1574690630590)(D:/feiq/Recv Files/CoreJava/day06 ----数组01/笔记/1572234738834.png)]
数组的内存特点:内存空间是连续的
优点:便于通过数组的首地址,计算出每一个元素的地址 查询快
a[i] = 首地址+字长*i
缺点:长度固定
数组的扩容
一、【理解】
1. 定义一个新数组,长度大于原数组
2. 将原数组中的元素一一挪到新数组
3. 更新地址
int[] a = {10,20,30,40};
int[] b = new int[a.length*2];
for(int i=0;i<a.length;i++){
b[i] = a[i];
}
a = b;
二、使用Arrays工具类【开发重点】
int[] a = {10,20,30,40};
a = java.util.Arrays.copyOf(a,a.length*2); //返回一个扩容后的数组
三、了解
//将原数组中的元素 挪到新数组
System.arraycopy(原数组,起始下标,新数组,存储元素的起始下标,长度);
数组的应用
数组应用于参数:实参为形参赋值时,传递的是地址
数组应用于返回值:需将函数内部数组的地址进行返回
可变长参数【了解】
概念:可接收多个同类型
实参的参数 , 不限个数
语法:数据类型…参数名
使用方式和数组相同
public static void m1(int...a){ //可变长参数a
//遍历数组
for(int i=0;i<a.length;i++){
System.out.print(a[i]+"\t");
}
System.out.println();
}
注意:可变长参数只能定义在形参列表最后,而且只能定义一个
数组排序
冒泡排序 : 相邻的两个元素比较大小,互换位置【面试重点】
//实现将数组进行从小到大进行排列
//相邻的两个元素进行比较,大的后挪
int[] a = {8,7,6,4,3};
/* 8 7 6 4 3
0-1 7 8 6 4 3 比较轮数 长度-1
1-2 7 6 8 4 3 每一轮做的事 a[i]>a[i+1] 交换位置
2-3 7 6 4 8 3
3-4 7 6 4 3 8
0-1 6 7 4 3 8
1-2 6 4 7 3 8
2-3 6 4 3 7 8
0-1 4 6 3 7 8
1-2 4 3 6 7 8
0-1 3 4 6 7 8
*/
for(int i=0;i<a.length-1;i++){ //外层循环控制比较轮数
//每一轮的内容
for(int j=0;j<a.length-1-i;j++){ //内层循环表示元素下标
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
选择排序:拿固定元素和后面的元素做比较【面试重点】
for(int i=0;i<a.length-1;i++){ //固定下标
for(int j=i+1;j<a.length;j++){ //表示后面的元素对应的下标
if(a[i]>a[j]){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
JDK排序【开发重点】
java.util.Arrays.sort(数组名称); //将数组按升序排序
二维数组
概念:一维数组中的一维数组。一维数组的元素又是一个一维数组。
使用流程:
- 声明 数据类型
[][]
a;int[][] a;
- 分配空间
a = new int[行数|高维数组的长度][列数|低维数组的长度];
二维数组的多种声明方式
int[][] a = new int[3][4];
int[][] a = new int[][]{{10,20,30},{1,2},{10,30,50,60},...}; //不规则二维数组
int[][] a = {{10,20,30},{1,2},{10,30,50,60},...};
int[][] a = new int[3][];
a[0] = new int[3];
a[1] = new int[2];
a[2] = new int[5];
-
元素访问:
数组名[行号|高维数组的下标][列号|低维数组的下标];
-
二维数组的遍历
数组名.length --> 高维数组的长度
for(int i=0;i<a.length;i++){
for(int j=0;j<a[i].length;j++){ //表示低维数组的下标
System.out.print(a[i][j]+"\t");
}
System.out.println();
}
5.二维数组的内存特点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vLwCuC0l-1574690630591)(D:/feiq/Recv Files/CoreJava/day06 ----数组01/笔记/1572333835072.png)]
面向对象
面向过程:自顶向下、逐步求精
面向对象:
- 准备好所需对象
- 对象之间相互配合
对象的组成
- 特征:属性,代表对象有什么
- 行为:方法,代表对象能做什么
- 计算机中 ,使用
类
来去描述对象
类和对象的关系
- 类是对象的模板
- 对象是类的实例
类的定义
-
属性:代表有什么 ——> 实例变量、成员变量
语法:
数据类型 变量名;
定义位置:类以内,方法外部
属性具有默认值:
数值类型:0/0.0
布尔类型:false
引用类型:null
成员变量和局部变量的区别???
成员变量 局部变量 定义位置 类以内,方法外部 方法内部 是否具有默认值 具有默认值 必须先赋值,后使用 作用范围 类的内部 定义行开始,到所在的代码块结束 命名冲突 成员变量和局部变量命名冲突时,局部变量优先 相同作用范围内,不允许命名冲突 -
方法:代表行为 ——> 成员方法
语法:public 返回值类型 方法名(形参列表){
//方法实现
}
定义位置:类以内,其他方法外部
-
创建对象 : 在内存中开辟连续的空间
new关键字
类名 对象名 = new 类名();
Student s = new Student(); -
访问属性:
对象名.属性名
访问方法:
对象名.方法名(实参);
方法重载OverLoad
-
概念:在一个类内部,定义了多个相同名字的方法
-
要求:方法名相同,但是参数列表不同(类型不同、顺序不同、个数不同)
-
作用:会根据传入的参数,精确匹配对应的方法
-
注意:若不能精确匹配,则
就近向上匹配
;但是要避免混淆public void m1(double d,int a){ System.out.println("m1(double,int)"); } public void m1(int a,double d){ System.out.println("m1(int,double)"); } ---------------------------------------------- m1(10,10); //混淆 -- 编译报错
-
好处:使代码更加灵活、屏蔽差异
构造方法
- 特殊的方法。
- 语法:
public 类名(){ }
构造方法名必须和类名保持一致;没有返回值类型,连void都没有 - 定义位置:类以内,其他方法外部
- 注意:
- 构造方法在new对象时调用,调用一次;不能手动调用
2. 若不手动定义构造方法,则默认提供无参构造;若手动提供构造,则系统不再提供
- 构造方法在new对象时调用,调用一次;不能手动调用
- 作用:
- 创建对象时使用
- 为属性赋值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VG8PcuYl-1574690630591)(D:/feiq/Recv Files/CoreJava/day08 ----面向对象/笔记/1572425174639.png)]
对象的创建过程
- 分配空间 为属性赋默认值
- 初始化属性 为属性赋初始值(第二次)
- 调用构造方法 第三次为属性赋值
this关键字
-
this.
: this 代表当前对象 ,可以在成员方法、构造方法
中使用this.属性名: 获取当前对象的属性
this.方法名(实参) : 调用当前对象其他方法
-
this()
: 调用本类其他构造方法,只能使用在构造方法
中this() : 调用本类的无参构造
this(实参):调用本类的有参构造
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bkuMMh40-1574690630591)(D:/feiq/Recv Files/CoreJava/day08 ----面向对象/笔记/1572493516402.png)]
注意: 1. 必须定义在构造方法有效第一行
2. 避免递归调用构造方法 ```java public B(){ this(10); } public B(int a){ this(); } //erro 递归调用构造方法
#### 引用 1. 对象类型的变量称之为引用 `类名 引用名 = new 构造方法名();` ***注意:*** 引用数据类型必须和对象类型保持一致 2. 引用中存储的是对象的首地址 3. 每个对象空间在堆空间中,相互独立 4. 引用之间相互赋值赋的是地址 基本数据类型之间传递的是数值 5. 当引用值为null时,使用属性和方法,会运行报错: 报错信息为:`java.lang.NullPointerException(空指针异常)` 6. 引用的应用:应用于参数、返回值、数组 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3cwiKo2b-1574690630592)(D:/feiq/Recv Files/CoreJava/day08 ----面向对象/笔记/1572507779188.png)]
三大特性
封装
-
private 修饰属性 --> 私有属性
只能在本类中访问
-
需要提供对应的方法
- set方法 --》 设值
public void setXXX(形参){ //setXXX set+属性名,属性名首字母大写 属性 = 参数值; }
- get方法 --》 取值
public 返回值类型 getXXX(){ //getXXX get+属性名,属性名首字母大写 return 属性值; }
- 可以在set、get方法内部 监测数据的安全性
private int age; //属性私有化 //提供set方法 --》 为age赋值 public void setAge(int age){ if(age>0&&age<150){ this.age = age; }else{ System.out.println("请输入合法的年龄"); } } //提供get方法 -- > 获取属性值 public int getAge(){ return this.age; }
***注意:***一个get方法只能获取一个属性值;一个set方法只能为一个属性赋值
继承
红笔 is a 笔
狗 is a 动物
学生 is a 人
概念:类和类之间建立 is a
关系
- 关键字 :
extends
class Student extends Person{}
Student 继承于 Person
子类 继承于 父类
- 子类可以使用父类中属性和方法
3. 一定要满足 is a关系 ,不能随便建立
4. 父类抽取了 子类的共性
继承的好处
- 提高代码的复用性
- 提高代码的可扩展性
方法覆盖(override)
-
在子类中定义和父类中一致的方法
-
要求:方法三要素(返回值类型、方法名、参数列表)相同
访问修饰符 要求相同或更宽
注意:若形参列表不同,则不会编译报错,而是构成方法重载
-
若子类中覆盖了父类中的方法,则实际运行是子类中覆盖后的方法
继承的特点
-
Java中的类是单继承,一个子类只能有一个直接父类;
但是可以多级继承,一个子类可以有多个间接父类。
-
属性和方法是逐级叠加的
哪些可以继承??
-
构造方法不能被继承
-
属性和方法由访问修饰符决定是否被继承:
访问修饰符访问权限
本类 同包 非同包子类 非同包非子类 private(私有的) √ × × × [default]
(默认的)√ √ × × protected(受保护的) √ √ √ × public(公开的、公共的) √ √ √ √ 从严到宽
哪些属性、方法可以被继承:
private修饰 不可被继承
[default] 修饰 同包子类可以被继承
protected 可以继承
public 可以继承
继承关系下的对象创建过程
在创建子类对象时,会先构建父类对象
-
分配空间 (父类+子类)
-
递归的构建父类对象
i. 初始化父类属性
ii.调用父类构造方法
-
初始化子类属性
-
调用子类构造方法
super关键字
-
super() : 调用父类中的构造方法
super(); 调用父类无参构造
super(实参); 调用父类有参构造
注意:
- 使用在子类构造方法中,决定了JVM在构建父类对象时,使用哪一个父类构造方法
- super() /super(实参) 只能定义在子类构造方法中的有效第一行
- 若子类构造方法中 没有定义super() / super(实参),则JVM默认提供
super();
- super() 和 this() 不能同时出现
-
super.
super 代表父类对象super.父类属性名;
调用父类的属性super.父类方法名(实参);
调用父类的方法多态
概念:父类类型的引用 指向 子类类型对象【重点】
Animal a = new Dog();
父类引用 子类对象
- 父类类型的引用只能使用父类中的属性和方法
- 如果子类中覆盖了父类中的方法,则实际运行的是覆盖后的方法
类型转换
-
类型提升 ---->向上转型
Dog d = new Dog(); Animal a = d; //多态
-
强制类型转换 ---->向下转型
Animal a = new Dog(); Dog d = (Dog)a;
注意【重点】:
1. 若转换双方存在继承关系,则强转一定编译通过;但是若引用中存储的实际对象类型和目 标类型不匹配,则运行报错 , 报错信息为:
java.lang.ClassCastException(强制类型转换异常)
Animal a = new Cat(); Dog d = (Dog)a; //运行报错 强制类型转换异常
2. 若转换双方没有继承关系,则编译报错
-
如何避免强制类型转换异常??? 【重点】
关键字:instanceof
用法:
引用名 instanceof 对象类型(目标类型)
判断引用中存储的实际对象类型和目标类型是否一致;
若一致,则为true;若不一致,则为false
多态的应用
- 多态应用于返回值: 返回值父类 + 所有子类类型
- 多态应用于参数:实参类型父类+所有子类类型
- 多态应用于数组:元素类型可以是父类+所有子类类型
多态的好处
屏蔽了子类差异,使代码更加灵活
三大修饰符
abstract(抽象的)
- 修饰类 ——> 抽象类
- 不能创建对象,但是可以声明引用
- 具有构造方法,是在创建子类对象时,先构建父类对象这一步使用
- 修饰方法 ——> 抽象方法
- 语法:
public abstarct 返回值类型 方法名(参数列表);
- 抽象方法只有声明,没有实现,连 {} 都没有
- 抽象方法只能定义在抽象类中
- 若子类继承了抽象类,则必须实现抽象类中的所有抽象方法;否则子类也必须声明为抽象类
- 语法:
- 好处:强制使用多态
static(静态的)
-
修饰属性 ——> 静态属性、类变量
-
全类共有的,与创建多少对象无关
-
访问方式:
类名 . 静态属性名
——>常用 对象名 . 静态属性名
-
-
修饰方法 ——> 静态方法
-
语法:
public static 返回值类型 方法名(参数列表){ //方法实现 }
注意:public 和 static 没有先后顺序
-
访问方式:
类名.静态方法名(实参)
——> 常用 对象名 . 静态方法名 (实参)
-
注意:
-
静态方法中不能访问非静态成员(属性、方法)
静态方法中只能访问静态成员(属性、方法)
-
非静态方法可以访问非静态成员和静态成员
-
静态方法中不能使用this和super关键字
-
静态方法允许被覆盖,但是只能被静态方法覆盖;而且没有多态
class MyClass{ public static void m1(){ System.out.println("m1()..."); } } class SubClass extends MyClass{ public static void m1(){ System.out.println("子类m1()..."); } } -------------------------------------------- MyClass mc03 = new SubClass(); mc03.m1(); //m1()...
-
-
修饰初始代码块 ——> 静态代码块
-
初始化代码块【了解】:
定义位置:类以内,方法外部
执行:在创建对象的第二步执行,与初始化属性,根据定义的先后顺序来去执行
-
静态代码块【开发应用重点】:
定义位置:类以内,方法外部,被static修饰
执行:在类加载时执行,与初始化静态属性,按照定义的先后顺序来去执行。
只执行一次。
类加载【理解+面试重点】
当JVM第一次使用一个类时,会通过classpath(类路径)加载它的所有信息(包名、类名、父类、方法、属性、构造方法…),保存在JVM内存中。这个过程称之为类加载。
-
类加载只会执行一次。
-
类加载的时机:
i. 第一次创建对象时:先进行类加载,再创建对象
ii. 第一次通过类名访问静态属性、静态方法
iii. Class.forName(“类全限定名”);
iv. 当创建子类对象时
先进行父类类加载,再进行子类类加载;
先创建父类对象,再创建子类对象;
-
-
-
final(最终的)
-
修饰变量(属性、局部变量、类变量)
-
被final修饰的变量称之为
作用范围内的常量
:只允许赋值一次;不可被更改 -
修饰属性:
被final修饰的属性没有默认值
赋值时机:显示初始化,初始化代码块,构造方法
注意:三个机会,只能选其一
-
修饰类变量(静态变量)
被final修饰的静态变量
(static final int b; //静态常量)
没有默认值 赋值时机:显示初始化,静态代码块
注意:只能任选其一
-
被final修饰的基本数据类型 值不可以更改
被final修饰的引用数据类型 指向的地址不可以更改
-
-
修饰方法
-
语法:
访问修饰符 final 返回值类型 方法名(形参列表){ }
注意:访问修饰符和 final不分先后
-
可以继承,不允许覆盖
-
-
修饰类(断子绝孙类)
- 不可被继承(没有子类)
注意
- abstract、final、static 都不能修饰构造方法
- private 和 abstract 不能连用
- final 和 abstract 不能连用
- static 和 abstract 不能连用
接口
概念:是一种标准,是使用者和实现者都必须遵循的标准;代表一种能力【理解】
语法:【重点】
- 定义:
interface 接口名{}
- 接口会生成对应的.class文件
- 接口不能创建对象,但是可以声明引用
- 接口没有构造方法
- 属性默认为公开静态常量(默认被public static final修饰)
- 方法默认是公开抽象方法(默认被public abstract 修饰)
interface MyInter{
int a = 10; //public static fianl int a = 10;
void m1(); //public abstract void m1();
}
注意:接口不是类
实现类【重点】
-
class MyClass implements 接口名{}
-
实现类必须实现接口中的所有方法。访问修饰符只能是public
-
使用 :
//接口类型的引用 指向 实现类类型的对象 -->多态 MyInter mi = new MyClass();
继承关系
-
类和类之间是单继承
-
接口和接口之间是多继承
interface 接口名1 extends 接口名2,接口名3,...{}
-
一个类可以实现多个接口
class 类名 implements接口1,接口2,...{}
-
一个类可以继承父类的同时,实现多个接口
class 类名 extends 父类名 implements接口1,接口2,...{}
继承关系产生的影响[了解]
互相强转的双方,若一方是接口类型,则强转编译一定通过;
但是运行时会判断,引用中指向的实际对象类型和目标类型是否匹配,
若匹配,则编译通过,运行通过;
若不匹配,则编译通过,运行报错:
报错信息为:java.lang.ClassCastException
(类型转换异常)
接口的好处【理解】
- 扩充子类的能力:主要功能定义在父类中,次要功能定义在接口中
- 解耦合:降低代码之间的耦合度
接口回调【了解】
先有接口的使用者,后有接口的实现者。
Object类(java.lang)
-
所有类的超类、根类、父类
-
Object类型的引用可以指向任意类型的对象。
Object o = new Student();
-
Object类中方法,是所有类所共有的
常用方法
-
getClass()
: 获取引用中存储的实际对象类型【重点】通常用于判断两个引用中指向的实际对象类型是否一致
//o引用中指向的实际对象类型是否和p引用中指向的实际对象类型一致
if(o.getClass()==p.getClass()) {
System.out.println("一致...");
} else {
System.out.println("不一致...");
}
-
int hashCode()
: 返回该对象的哈希码值(对象的整数表现形式) -
String toString()
: 返回该对象的字符串表现形式(所有的属性内容)[重点]要求:需要重写toString()方法
public String toString(){ return 属性值拼接成的字符串; }
-
boolean equals(Object o)
: 比较对象的内容是否相同[重点]==:比较基本数据类型,比较的是数值
比较引用数据类型,比较的是地址
对象之间比较内容(属性值)是否完全相同,需通过equals方法,自定义类型需要重写equals
重写规则:
public boolean equals(Object o) { //1. 自反性(比较this和o是否指向同一对象) if(this==o) return true; //2. 非空判断 判断o是否为null if(o==null) return false; //3. 判断当前对象和o是否是同一类型 if(this.getClass()!=o.getClass()) return false; //4. 强制类型转换 Dog d = (Dog)o; //5. 逐一比较属性 if(this.age==d.age&&this.sex==d.sex&& this.name.equals(d.name)) { return true; } return false; }
-
finalize()
:垃圾回收器回收垃圾对象时调用的方法【不要在这个方法中定义逻辑代码】垃圾对象:没有引用指向的对象,称之为垃圾对象
垃圾回收:销毁垃圾对象,清理内存空间
垃圾回收器回收垃圾 对象的时机【了解】:
自动回收机制:当JVM内存耗尽时,垃圾回收器会自动回收所有垃圾对象
手动回收机制:通过
System.gc();
手动的通知垃圾回收器做垃圾回收。 若垃圾收器空闲,则回收;若忙,则不回收。
内部类
**概念:**在一个类的内部定义了一个完整的类。
特点 :
- 内部类也会生成对应的.class文件 , 文件名为
Outer$Inner.class
- 内部类可以访问外部类的私有属性,不破坏封装性
- 内部类分为:成员内部类,静态内部类,局部内部类,匿名内部类(重点)
-
成员内部类(10%)
定义位置 : 类的内部,方法外部
如何创建对象:
//创建外部类对象 //依赖外部类-->创建内部类对象 Outer o = new Outer(); Outer.Inner inner = o.new Inner();
注意事项:
-
外部类对象
外部类类名.this
访问外部类对象的属性
外部类类名.this.属性名
-
成员内部类中不能定义静态成员(属性、方法)
-
-
静态内部类(10%)
定义位置:类的内部,方法外部,被static修饰
如何创建对象:
Outer.Inner inner = new Outer.Inner();
注意事项:
- 静态内部类只能访问外部类的静态成员
-
局部内部类(30%)
定义位置 : 方法内部
如何创建对象:
在定义它的方法内部创建,要创建在类定义完成之后
public static void main(String[] args) { class Inner{ //局部内部类 int a = 10; public void m1() { System.out.println(111); } } new Inner(); //创建局部内部类对象 }
注意事项:
-
它可以访问它所在方法的局部变量,但是这个变量必须被final修饰(语法规定)
在JDK 1.8开始, 局部变量默认被final修饰(语法糖)
好处:做到接口公开,实现隐藏;实现弱耦合
-
-
匿名内部类(50%)
定义位置:定义方法内部,一个特殊的局部内部类(局部内部类具有的特点它都有)
创建对象:
没有类名,必须实现一个接口或者继承一个父类
new 接口名(){ //匿名内部类的内容-->必须实现的接口的方法 } ------------------------------ new 父类类名(){ //类的内容 }
注意:
- 只能创建一次对象
- 匿名内部类定义完成 , 则对象创建完毕
坏处:可读性差
好处:使代码更加灵活 , 减少代码量
常用类
包装类
**概念:**为八种基本数据类型提供的对象数据类型。
基本数据类型 | 包装类类型(java.lang) |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
相互转换
int <——>Integer
- int —— > Integer【重点】
int a = 10;
Integer i1 = new Integer(a); //通过构造方法
// static Integer valueOf(int i) :将整数转换为Integer对象
Integer i2 = Integer.valueOf(a);
- Integer —— > int 【重点】
// int intValue() 返回Integer对象的int值
int b = i2.intValue();
String <——> Integer
- String ——> Integer【重点】
String s = "123";
Integer i3 = new Integer(s); //通过构造方法
// static Integer valueOf(String s)
Integer i4 = Integer.valueOf(s);
- Integer ——> String
String s1 = i3+"";
String s2 = i3.toString();
String <——>int
- String——>int【重点】
// static int parseInt(String s)
int c = Integer.parseInt(s);
- int ——>String
int a = 10;
String s = a+"";
注意: String 转换为 数值类型时,String字面值必须是纯数字格式;
否则,会运行报错,报错信息为:java.lang.NumberFormatException(数字格式转换异常)
Since JDK 5.0 提供了自动拆箱和自动装箱的功能。基本数据类型和包装类类型之间可以自动转换。
自动拆箱:包装类类型——>基本数据类型
自动装箱:基本数据类型——>包装类类型
缓冲区【理解】
在自动装箱时,默认调用valueOf方法;对-128~127之间的数做了预先包装,存放在缓冲区内(常量池)。提高效率。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hyXn4i9I-1574690630593)(D:/feiq/Recv Files/CoreJava/day16 ----常用类/笔记/1573454017007.png)]
作用【理解】
用于区分0和null,用于区分有效数据和无效数据
String(字符串)(java.lang)
常用方法【重点】
-
char charAt(int index):
根据下标返回对应的字符 -
int length()
: 返回值字符串的长度*注意:*s.length() , 调用方法获取长度
数组名.length :获取数组长度
-
int indexOf(String str):
返回字符串str在当前字符串中第一次出现的下标; 若不存在此字符串,则返回 -1
-
int lastIndexOf(String str)
: 返回字符串str在当前字符串中最后一次出现的下标; 若不存在此字符串,则返回 -1
-
String substring(int beginIndex,int endIndex)
: 返回beginIndex ~ endIndex组成的字符串 (包含beginIndex ,不包含endIndex )
-
String[] split(String str):
根据str 对字符串进行拆分,返回拆分后的数组 -
String toUpperCase()
: 将字符串转换成全大写 -
String toLowerCase()
: 将字符串转换成全小写 -
boolean endsWith(String str) :
判断字符串是否以str结尾 -
boolean contains(String str)
: 判断字符串中是否包含str;若包含-true,若不包含-false
创建对象的两种方式【理解+面试重点】
String s = "abc"; 字面值形式
只会产生一个对象 存放在串池中
String s = new String("abc"); 构造方法创建
产生两个对象 一个存放在串池中,一个存放在堆空间中
intern() : 返回 s 对象在串池中的字符串对象
String 具有不可变性【理解+面试重点】
String s1 = "abc";
String s2 = s1;
s1+="bcd"; //s1指向的地址发生改变
System.out.println(s2); //abc
System.out.println(s1); //abcbcd
String类型在做拼接时,不会在原有的对象上进行改变,而是创建新的空间存储拼接后的对象。
导致,字符串拼接效率过低
可变长字符串【面试重点】
StringBuffer
: JDK 1.0 线程安全,运行效率低
StringBuilder
: JDK 5.0 线程不安全,运行效率高
常用:
append(String s)
:拼接字符串 (类似于String的+)
BigDecimal(java.math)
- 作用:精确表示、计算浮点数
- 创建BigDecimal对象(方式很多,以参数为字符串为例):
BigDecimal bd=new BigDecimal(“1.0”);(推荐使用)
- 常用方法:
BigDecimal add(BigDecimal bd)
加
BigDecimal subtract(BigDecimal bd)
减
BigDecimal multiply(BigDecimal bd)
乘
BigDecimal divide(BigDecimal bd)
除
BigDecimal bd6 = new BigDecimal("10");
BigDecimal bd7 = new BigDecimal("3");
// 2 :表示取小数点后两位
//BigDecimal.ROUND_HALF_UP:四舍五入
BigDecimal bd8 = bd6.divide(bd7,2,BigDecimal.ROUND_HALF_UP); // bd8 = bd6/bd7
注意: 若不能整除则需指定取舍位数,否则运行报错
集合
**概念:**存储多个对象的容器,本身也是一个对象。
Collection集合(java.util)
- 特点:Collection 体系的根接口。能够存储多个对象。
- 常用方法:
add(Object o):
增加一个元素
contains(Object o):
判断集合中是否包含元素o
remove(Object o):
删除元素o
int size():
返回有效元素个数
- 实现类:见子接口中的实现类
List接口(java.util)
-
特点:有序有下标元素可以重复
-
常用方法:
* add(Object o):
增加一个元素* add(int index,Object o)
: 向指定位置处插入一个元素* remove(int index):
根据下标删除元素* set(int index, Object o)
: 将index下标处对应的元素,替换为o* get(int index)
: 根据下标获取对应的元素* int size():
返回有效元素个数contains(Object o):
判断集合中是否包含元素oindexOf(Object o)
: 返回元素第一次出现的下标,若不包含则返回-1lastIndexOf(Object o)
: 返回元素最后一次出现的下标,若不包含则返回-1subList(int fromIndex, int toIndex)
: 返回fromIndex(包含)~toIndex (不包含) 之间元素组成的List集合
-
实现类:ArrayList
实现类之间的区别???【面试重点】
-
ArrayList
JDK 1.2 线程不安全 效率高 数组实现 内存空间连续,查询快,增删慢
-
Vector
JDK 1.0 线程安全 效率低 -
LinkedList
链表实现 内存空间不连续,查询慢,增删快
查询多 ——> ArrayList
增删多 ——> LinkedList
-
-
遍历
下标遍历:
for(int i=0;i<list.size();i++) { System.out.println(list.get(i)); }
-
for-each遍历
for(数据类型 变量名:集合名称|数组名称){ // 变量名 --> 表示元素 } 注意: 数据类型和泛型类型保持一致
泛型集合【重点】
概念:类型安全的集合,强制集合元素类型一致
List<Student> list = new ArrayList<Student>();
注意:
- 编译时即可检查元素类型是否一致
- 引用泛型必须和对象泛型保持一致;没有多态
自定义泛型类 [了解]
class MyClass<T>{ //自定义泛型类
private T a;
public T getA() {
return a;
}
public void setA(T a) {
this.a = a;
}
}
注意:
-
泛型的类型 在创建对象时决定
MyClass<String> mc = new MyClass<>(); //决定泛型为String类型
-
通常使用T/K/V/E作为泛型标识
-
since jdk 1.5 可以定义泛型接口
interface IA<K,V>{
void m1(K k);
void m2(V v);
}
class MyClass01<K,V> implements IA<K,V>{
public void m1(K k) {}
public void m2(V v) {}
}
-------------------------------------------------
IA<Integer,String> ia = new MyClass01<>();
Collections[了解]
概念:一个工具类,提供了操作集合的方法
static void reverse(List list)
: 反转集合中的元素
static void shuffle(List list)
: 将集合中的元素 , 随机重置
static void sort(List list):
对集合中的元素进行升序排序
注意:若集合中元素是自定义类型,则需要自定义类实现Comparable接口,实现comparTo方法
public int compareTo(Student o) {
//定义排序的规则
//拿当前对象的属性 和 参数o的属性值 做对比
//如果当前对象的属性值 > 参数O对象的数值 则返回正整数 1
//如果当前对象的属性值 < 参数O对象的数值 则返回负整数 -1
//如果当前对象的属性值 == 参数O对象的数值 则返回0
if(this.age>o.age) return 1;
else if(this.age<o.age) return -1;
else {
//代表年龄相等的情况
return this.name.compareTo(o.name);
}
}
Set接口(java.util)
-
特点:无序无下标,元素内容不可以重复
-
常用方法:全部继承于Collection
-
实现类:
HashSet
***HashSet如何实现元素内容不重复???***【面试重点】
-
基于hashCode值实现元素内容不重复
-
当hashCode值相同时 , 会调用equals方法进行比较内容是否一致
-
hashCode的重写规则: 目的是保证属性值相同的两个对象,哈希码值相同
public int hashCode() { //把所有的属性值进行计算出一个整数 进行返回 return name.hashCode()+age+(int)score; }
-
-
遍历方式:
for-each
迭代器遍历
//1. 获取迭代器对象 iterator():返回迭代器对象 Iterator:表示迭代器 //2. 调用方法 判断指针后是否还有元素 hasNext():判断是否还有元素 若有- true;若没有-false //3. 调用方法 使指针后移一位,并且将跨过的元素进行返回 next():返回下一个元素 Iterator<String> iterator = set.iterator(); while(iterator.hasNext()) { String s = iterator.next(); System.out.println(s); }
异常
概念:在程序运行过程中,产生的意外情况
**异常处理:**提高程序的容错性,提前准备好应对异常的代码,正常情况下不执行
try{
插入银行卡
输入密码和金额
金额-=2000
吐钱2000
}catch(){
金额+=2000
}finally{
退卡
}
异常的分类[理解]
-
Throwable
:所有异常的父类,位于java.lang
包下-
Error : 严重错误,无法处理
java.lang.StackOverflowError
内存溢出 -
Exception
-
RuntimeException
运行时异常|未检查异常可以避免,可处理可不处理
NullPointerException
: 空指针异常IndexOutOfBoundsException
: 下标越界异常ClassCastException
: 类型转换异常NumberFormatException
: 数字格式转换异常 -
非
RuntimeException
非运行时异常|已检查异常不可避免,必须处理
FileNotFoundException
: 文件找不到异常EOFException
: 文件到达结尾异常
-
-
异常的产生【理解】
-
自动产生:程序运行过程中,遇到错误的代码,导致程序终止。
-
手动产生:
throw new 异常类名(); //手动产生异常
1)定义在方法内部
2)相当于return语句,导致方法的终止
异常的传递【理解】
按着方法的调用链方向反方向传递,直至JVM,最终导致程序终止。
异常的处理【重点】
- 消极处理 : 声明上抛
throws: 定义在方法声明之后
public static void m2(int i) throws 异常名1,异常名2{}
注意 : 只是推卸责任的处理方式,最终异常并没有得到解决
-
方法覆盖(终极版)
返回值类型、方法名、参数列表 要和父类保持一致
访问修饰符 相同或更宽
不能比父类抛出更多、更宽的异常
- 积极处理:try-catch 捕获
try{
//可能出现异常的代码
}catch(异常类名1 e){
//当异常出现时会执行的代码
}catch(异常类名2 e){
// 当另外一个异常出现时会执行的代码
}
- try块中产生的异常会跟catch后面异常进行比较,哪一个匹配执行哪一个catch代码块
- catch 可以捕获父类异常,也可以捕获子类异常;但父类异常一定要定义在子类异常之后
try{ //有可能发生异常的代码 }
catch() { //异常发生时执行的代码 }
finally{ //不管是否发生异常 都一定会执行的代码 }
- finally 代码块通常用于关闭资源
- 若方法有返回值,那么在try和catch代码块中都需要定义return语句;但是通常情况下 不要在finally代码中定义return语句
//常用结构小结
try{}catch(){}
try{}catch(){}catch(){}catch(){}
try{}catch(){}finally{}
try{}catch(){}catch(){}catch(){}finally{}
try{}finally{}
try{try{}catch(){}finally }catch(){}
try{}catch{ try{}catch(){}finally{} }
try{}catch(){}finally{ try{}catch(){}finally{} }
1. try 后必须跟一个catch或者finally代码块
2. 若catch和finally同时出现,则finally必须定义在catch之后
自定义异常类【了解】
-
要继承于Exception|RuntimeException ;
继承于Exception 表示已检查异常;继承于RuntimeException 未检查异常
-
提供有参无参构造
class CheckPasswordException extends Exception{ public CheckPasswordException() { super(); } public CheckPasswordException(String message) { super(message); } }
I/O流
概念:内存与存储设备之间传输数据的通道、管道
IO流的分类
-
按方向划分(以JVM为参照物):
输入流:从外部存储设备 ——> JVM内存 读
输出流:从JVM内存——>外部存储设备 写
-
按单位划分
字节流:以字节为单位,可以操作任意类型的文件
字符流:以字符为单位,只能操作文本类型的文件;
文本类型的文件:使用记事本能够打开的文件.txt, .java , .html…
-
按功能划分
节点流 : 只具有基本的读写功能
过滤流: 在节点流的基础上,增加新的功能。
字节流
-
字节流抽象父类
OutputStream
(字节输出流) --> 写操作 |- write(int b):向外部存储设备 写入一个字节
|- write(byte[] b) : 写入b.length个字节
|- write(byte[] b, int off, int len): b表示数组,off表示开始下标,len表示写入的长度
InputStream
(字节输入流) --> 读操作 |- int read() : 从外部存储设备读取一个字节。若没有读取到 则返回-1。
|- read(byte[] b) : 一次性读取多个字节,并且将读取到的数据存放在b数组中
|- read(byte[] b, int off, int len):一次性读取len个字节,并且将读取到的数据存放在b数· 组中;存储的位置从off开始,
-
文件字节流
FileOutputStream
: 文件字节输出流
创建对象
FileOutputStream fos = new FileOutputStream("文件路径"); 注意: 1. 文件路径中指定的文件,若文件存在则选择已经存在的,若不存在则新创建一个; 若文件夹不存在,则不新创建,而是运行报错: 报错信息为:java.io.FileNotFoundException 2. 路径可以定义为绝对路径或者相对路径 绝对路径:E:/CoreJava/day20 ----流IO/笔记/a.txt 相对路径: a.txt 产生的文件在当前项目的根目录下 3. FileOutputStream fos = new FileOutputStream("文件路径",true); true 代表在原有的文件上进行追加 false 代表在原有的文件上进行覆盖,默认为false
FileInputStream
: 文件字节输入流
FileInputStream fos = new FileInputStream("文件路径"); 注意: 1. 路径中指定的文件必须存在,否则运行报错 报错信息为:java.io.FileNotFoundException
如何实现文件复制???
FileInputStream fis = new FileInputStream("E:\\CoreJava\\day20 ----流IO\\上课录屏\\文件字节输入流.wmv");
FileOutputStream fos = new FileOutputStream("file\\文件字节输入流.wmv");
//一边读一边写
while(true) {
int i = fis.read(); //一次性读取一个字节
if(i==-1) break;
fos.write(i); //写一个字节 90m = 90*1024*1024B
}
fis.close();
fos.close();
FileInputStream fis = new FileInputStream("E:\\CoreJava\\day20 ----流IO\\上课录屏\\文件字节输入流.wmv");
FileOutputStream fos = new FileOutputStream("file\\文件字节输入流.wmv");
byte[] bs = new byte[1024];
while(true) {
//一次循环读取 1024个字节 = 1KB
int read = fis.read(bs);
if(read==-1) break;
//一次循环写入 1024个字节 = 1KB
fos.write(bs);
}
fis.close();
fos.close();
包装流
- 过滤流
BufferedInputStream/BufferedOutputStream
- 提供了缓冲区,提高了IO效率;减少访问磁盘的次数
- 一定要记得清空缓冲区 通过flush()方法;也可以直接close();
//1. 创建一个文件字节输入输出流
FileInputStream fis = new FileInputStream("E:\\CoreJava\\day20 ----流IO\\上课录屏\\文件字节输入流.wmv");
FileOutputStream fos = new FileOutputStream("file\\文件字节输入流.wmv");
//2. 创建过滤输入输出流
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
//3. 边读边写
while(true) {
int i = bis.read();
if(i==-1) break;
bos.write(i);
}
//4. 关流
bis.close();
bos.close();
-
数据包装流
DataOutputStream/DataInputStream
-
可以操作八种基本数据类型
WriteByte(int n)/readByte()
、writeShort(int n)/readShort()
writeInt(int n)/readInt()
、writeLong(long n)/readLong()
writeFloat(float f)/readFloat()
、writeDouble/readDouble()
-
可以操作String数据:
writeUTF(String str)/readUTF()
-
-
对象过滤流
ObjectInputStream/ObjectOutputStream
-
增强了基本的读写功能
-
可以操作八种基本数据类型、字符串类型
-
增强了读写对象的功能
readObject()
: 从流中读取一个对象writeObject(Object obj):
向流中写入一个对象- 进行对象序列化时(把对象放在流上进行传输):需要自定义类实现
Serializable
接口
- 进行对象序列化时(把对象放在流上进行传输):需要自定义类实现
2. 当读取超出数量的对象时,会运行报错,报错信息为:
java.io.EOFException
文件到达结尾异常 3. 若自定义类型的属性也是自定义类型,那么属性类型也需实现
Serializable
接口 4. 在传输集合对象时,若元素是自定义类型,则元素对应的类也必须实现
Serializable
接口 5.
transient
:修饰属性,代表此属性不参与序列化
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-obkiuTCR-1574690630593)(D:\feiq\Recv Files\day20 ----流IO\笔记\IO流总结.jpg)]
字符流
编解码
乱码:编码方式和解码方式不一致导致。
常用的编码集
ANSCII 美国
ISO8859 - 1 西欧
GBK 简体中文
BG2312 简体中文
BIG5 繁体中文
UTF-8 万国码
字符流的抽象父类
-
Reader(字符输入流) ——>读操作
-
int read()
: 读取的字符内容,若没有则返回-1 -
int read(char[] c)
: 一次读取多个字符,存放在char数组中 -
int read(char[] b,int off,int len)
:一次读取多个字符,存放在char数组中; 存储的起始下标是off,初始数量len
-
-
Writer(字符输出流) ——>写操作
write(int n)
: 写入一个字符write(String s)
: 写入一个字符串write(char[] c )
: 将数组中的字符 写入到文件中
节点流
FileWriter
文件字符输出流FileReader
文件字符输入流
过滤流
-
BufferedReader
: 过滤字符输入流String readLine()
: 一次性读取一个文本行;若文件到达结尾则返回null -
PrintWriter
: 过滤字符输出流println(String s)
: 换行写入一个字符串当使用缓冲流写入一个对象时,写入的实际上是 对象的字符串表现形式(toString方法的返回值)。
桥转换流
InputStreamReader
/ OutputStreamWriter
- 将字节流转换为字符流
- 在转换为字符流时,设置编解码方式
// 1. 创建字节流对象
FileInputStream fis = new FileInputStream("file/e.txt");
// 2.创建桥转换流 将字节流——>字符流
InputStreamReader isr = new InputStreamReader(fis,"utf-8");
步骤总结:
创建字节节点流
创建桥转换流,同时设置编解码方式包装过滤流,
方便读写操作读/写操作
关闭流:只需要关闭最外层流
线程
进程:在os(操作系统)中并发的一个任务。
并发:由cpu分配时间片,决定当前执行哪个任务。微观串行(交替执行),宏观并行。
线程:进程中并发的一个任务。
线程的组成【了解】
- CPU时间片
- 数据:栈空间独立,堆空间共享
- 代码
创建线程的两种方式【重重点】
Thread(java.lang)
:表示线程类
1. 定义一个任务类 实现Runnable接口
2. 创建任务对象
3. 创建Thread对象,提交线程任务
class MyTask implements Runnable{
//重写run方法
public void run(){}
}
------------------------------------
MyTask mt = new MyTask();
Thread t1 = new Thread(mt);
1. 继承Thread类,重写run方法
2. 创建线程子类对象
class MyThread extends Thread{
public void run(){}
}
------------------------------------
Thread t2 = new MyThread();
start():
启动线程
线程的状态【理解+面试重点】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iD92Jn82-1574690630594)(D:/feiq/Recv Files/day22 ----线程01(1)]/笔记/1574155841632.png)
sleep(long mills)
: 让当前线程陷入有限期的休眠状态。
t.join()
: 让当前线程陷入等待,等待 t 线程执行完毕。
注意: JDK 5.0 开始 就绪状态和运行状态 统称为Runnable状态
线程同步、线程安全【理解+重点】
线程不安全【面试重点】
当多个线程并发访问同一个对象(临界资源)时,破坏了不可被分割的操作(原子操作),会导致数据不一致。
同步代码块
synchronized(Obj){ //obj表示Object对象
//不可分割的代码(原子操作)
}
- 每一个obj对象,都具有一个互斥锁标记。
- 想进入同步代码块,必须拥有互斥锁标记。
- 同步代码块执行完毕,释放锁标记
同步方法
public synchronized 返回值类型 方法名(){
//不可分割的代码(原子操作)
}
- 使用当前对象(this)作为临界资源,进行加锁
反射
类的对象
:根据一个类实例化的对象(new出来的对象
类对象
:类加载的产物,保存在这个类的所有信息(类名、包名、父类、属性、方法、接口、构造方 法…)
获取类对象的三种方式
- 通过实例对象获取。
对象名.getClass()
;
Student s = new Student();
Class c1 = s.getClass();
- 通过类名获取
类名.class
Class c2 = Student.class;
- 通过静态方法
Class.forName("类的全限定名");
Class c3 = Class.forName("demo.Student"); //全限定名:包名+类名
java.lang.reflect包下的类
Filed : 属性
Method : 方法
Constructor : 构造方法
Class类中的方法
getFields()
: 获取公开属性(父类+子类)c.getDeclaredFields()
: 获取所有属性(只包含本类)getMethods()
: 获取公开方法(父类+子类)c.getDeclaredMethods()
: 获取所有方法(只包含本类)c.getConstructors()
: 获取所有的构造方法
根据类对象获取实例对象
Class c = Class.forName("类的全限定名");
Object o = c.newInstance(); //根据类对象获取实例对象
设计模式
单例模式:实现一个类只能创建一个对象
//饿汉式
class B{
private static final B b = new B();
private B() {}
public static B getInstance() {
return b;
}
}
//懒汉式
class C{
private static C c = null;
private C() {}
public static synchronized C getInstance() {
if(c==null) {
c = new C();
}
return c;
}
}
饿汉式:浪费空间。 懒汉式:效率较低
class D{
private static class Inner{
static D d = new D();
}
public static D getInstance() {
return Inner.d;
}
private D() {}
}
开闭原则:对扩展开放,对修改关闭
工厂设计模式
- 使用反射实现工厂设计模式
public class TestFactory {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
String name = sc.next();
Animal a = getAnimal(name);
a.m1();
}
//工厂 : 参数表示类的全限定名
public static Animal getAnimal(String className) throws Exception {
Class c = Class.forName(className); //类对象
Object o = c.newInstance(); //根据类对象获取实例对象
Animal a = (Animal)o; //类型转换
return a;
}
}
- 利用流和Properties集合 进行读取配置文件
public class TestFactory {
public static void main(String[] args) throws Exception {
Animal a = getAnimal();
a.m1();
}
public static Animal getAnimal() throws Exception {
// className 使用流进行读取
// 1. 创建字节流
FileInputStream fis = new FileInputStream("config.xml");
// 2. 创建Properties集合 调load方法
Properties p = new Properties();
// 将配置文件中的数据加载集合中 以=为分割 =前是key =后是value
p.load(fis);
String className = p.getProperty("className"); //根据key获取value
Class c = Class.forName(className); //类对象
Object o = c.newInstance(); //根据类对象获取实例对象
Animal a = (Animal)o; //类型转换
return a;
}
}
同步方法*
public synchronized 返回值类型 方法名(){
//不可分割的代码(原子操作)
}
- 使用当前对象(this)作为临界资源,进行加锁
反射
类的对象
:根据一个类实例化的对象(new出来的对象
类对象
:类加载的产物,保存在这个类的所有信息(类名、包名、父类、属性、方法、接口、构造方 法…)
获取类对象的三种方式
- 通过实例对象获取。
对象名.getClass()
;
Student s = new Student();
Class c1 = s.getClass();
- 通过类名获取
类名.class
Class c2 = Student.class;
- 通过静态方法
Class.forName("类的全限定名");
Class c3 = Class.forName("demo.Student"); //全限定名:包名+类名
java.lang.reflect包下的类
Filed : 属性
Method : 方法
Constructor : 构造方法
Class类中的方法
getFields()
: 获取公开属性(父类+子类)c.getDeclaredFields()
: 获取所有属性(只包含本类)getMethods()
: 获取公开方法(父类+子类)c.getDeclaredMethods()
: 获取所有方法(只包含本类)c.getConstructors()
: 获取所有的构造方法
根据类对象获取实例对象
Class c = Class.forName("类的全限定名");
Object o = c.newInstance(); //根据类对象获取实例对象
设计模式
单例模式:实现一个类只能创建一个对象
//饿汉式
class B{
private static final B b = new B();
private B() {}
public static B getInstance() {
return b;
}
}
//懒汉式
class C{
private static C c = null;
private C() {}
public static synchronized C getInstance() {
if(c==null) {
c = new C();
}
return c;
}
}
饿汉式:浪费空间。 懒汉式:效率较低
class D{
private static class Inner{
static D d = new D();
}
public static D getInstance() {
return Inner.d;
}
private D() {}
}
开闭原则:对扩展开放,对修改关闭
工厂设计模式
- 使用反射实现工厂设计模式
public class TestFactory {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
String name = sc.next();
Animal a = getAnimal(name);
a.m1();
}
//工厂 : 参数表示类的全限定名
public static Animal getAnimal(String className) throws Exception {
Class c = Class.forName(className); //类对象
Object o = c.newInstance(); //根据类对象获取实例对象
Animal a = (Animal)o; //类型转换
return a;
}
}
- 利用流和Properties集合 进行读取配置文件
public class TestFactory {
public static void main(String[] args) throws Exception {
Animal a = getAnimal();
a.m1();
}
public static Animal getAnimal() throws Exception {
// className 使用流进行读取
// 1. 创建字节流
FileInputStream fis = new FileInputStream("config.xml");
// 2. 创建Properties集合 调load方法
Properties p = new Properties();
// 将配置文件中的数据加载集合中 以=为分割 =前是key =后是value
p.load(fis);
String className = p.getProperty("className"); //根据key获取value
Class c = Class.forName(className); //类对象
Object o = c.newInstance(); //根据类对象获取实例对象
Animal a = (Animal)o; //类型转换
return a;
}
}