赞
踩
ps:忽发奇想,把自己的学习笔记发成博客,记录下自己的成长路线,也方便日后回顾;有什么问题请多多指正呦!
day01
〇、常见异常
1、java.lang.ClasscastException @ 类型转化异常
2、java.lang.NullpointerException @ 空指针异常
3、IndexOut0fBoundsException @ 数组下标越界异常
4、NumberFormatException @ 数字格式化异常
一、常用DOS命令
1、mkdir 目录名 @ 创建目录
2、目标盘: @ 切换盘符
3、cd 目录 @ 切换目录
绝对路径 @ 相对于当前的位置
相对路径 @ 以盘符开头
4、cls @ 清屏
5、dir @ 查看当前目录下有什么东西
6、cd … @ 回到上一级目录
7、cd \ @ 回到根目录
day02
8、del 文件 @ 删除文件
9、rd 空目录 @ 删除空目录
10、ipconfig @ 查看ip地址 ipconfig/all @ 更详细的地址信息
11、ping 域名或ip -t @ 测试网速
二、常用快捷键
撤销 Ctrl+z
重做 Ctrl+y
回到行首 home键
回到行尾 end键
选中一行 shift+home和shift+end
回到文件头 Ctrl+home
回到文件尾 Ctrl+end
day04
三、Java环境配置及使用
0、java语言的健壮性体现在GC(垃圾回收机制) #主要针对堆内存当中的对象,当没有任何引用指向该对象时,就会被GC判定为垃圾
1、javac 源文件的路径 @ javac命令(编译)的使用
2、java 类名 @ java命令(运行)的使用 #只能跟类名,不能加class,也不能加路径而是事先要cd过去
四、注释
①//
②/*
/
③/* #可以被javados命令读取,相当于展现给用户的注释,一般产品参数说明
*
…
*/
五、知识点
1、java文件中是一个一个的类,java语句要写在类体中,写在类外面会报错;
2、class文件会从main方法开始运次,没有main类编译能通过但是运行会报错;
3、java文件可以有多个类,编译时会生成多个class文件,每个class文件都可以单独运次,实际开发不会这样用;
4、但是最多只能有一个(可以一个都没有)class文件能含有public关键字,且该类名要和文件名严格一致。
5、一个文件如果有多个class类,那也可以有多个main方法,运行时指定运行哪个class文件就可以
day05
六、标识符和关键字、变量
1、标识符命名规则 @ ①字母、数字、下划线、美元符号、中文 ②不能以数字开头 ③不能有空格 ④严格区分大小写
2、标识符命名规范 @ ①见名知意 ②接口名、类名首字母大写,后面每个单词首字母大写
③变量名、方法名首字母小写,后面每个单词首字母大写 ④常量名全部大写,并且单词和单词之间用下划线分割
3、关键字 @ ①全部小写 ②有几十个,在edit中变蓝的那些都是
4、字面量 @ java程序中的数据
①整数型字面量
②浮点型字面量
③布尔型字面量 只有true和false
④字符型字面量 单引号引起来的,里面只能有一个字符,否则会报错
⑤字符串型字面量 双引号引起来的
5、变量赋值 @ int a,b,c=100在java中只会给c赋值 但可以这么做 @ int a=100,b=100,c=100
[记]6、局部变量 @ 方法体中的变量
成员变量(实例变量) @ 方法体外、类内的变量
①成员变量有默认值,Boolean默认值是false,引用数据类型默认值是null,可以不用赋值
②要想用这个变量必须实例化,哪怕是在同一个class文件中,因此它是存储在堆内存当中的
③怎么访问 @ 引用.成员变量名
7、出了大括号(域)就不认识了,不同方法中的变量名相同不会冲突,像循环语句里定义的变量也不能在外面访问,和Python的区别
day06
七、数据类型
1、基本数据类型(4大类8小种)
[记] 整型 @ byte(1)、short(2)、int(4)、long(8) 浮点型 @ float(4)、double(8)
布尔型 @ boolean(1) 字符型 @ char(2)
引用数据类型
其实就是一些写好的类,像String其实也是官方写好的一个类而已
整型:
2、进制
[记] 八进制 0… 十六进制 0x… 二进制 0b…
3、整数类型默认是int类型
long i=2047483648 会报错 @ long i=2047483648L才对
4、int可以直接转化为long,long转化为int需要加强制转换运算符 (超范围的话会损失一部分值)
long a=100L; int b=(int)a; #但是byte和short只要没超范围可以不加强制转化,超范围就要加,不加会报错
5、char x="\u4e2d"; 这里\u表示Unicode编码
day07
字符型
6、char a=97; 这种写法是允许的,表示97对应的Unicode的字符
7、多种类型做混合运算时,最终的结果是最大容量对应的类型,byte、char、short除外,他们做混合运算,首先先转化为int。
0、short i=100这种写法是可以的,只有右边没有超出short的取值范围都是可以的,规定,byte也一样,但是long到int就不行
8、short右边是个含变量的表达式时会报错,short虽然知道右边是个int但是不知道是否超范围,就算没有超范围他也会报错,加了强制转化符就不会报错了
浮点型
9、浮点型默认被当做double,要想转化为float需要在后面加F 例如float i=12.5F
0、float i=12.5 是错误的
0、float和double的存储空间永远比整数类型的大
布尔型
10、只有true和false,不能写成1和0
在类型转换时需要遵循的规则
11、八种数据类型除了boolean外,其他的都可以相互转换
12、如果整数型没有超出byte、char、short,可以直接将其转化为byte、char、short
[记]13、任何浮点型的容量都比整型大,虽然long占8个字节,float占四个字节,仍然如此
容量大小顺序是 byte<short(char)<int<long<float<double
14、多种类型做混合运算时,最终的结果是最大容量对应的类型,byte、char、short除外,他们做混合运算,首先先转化为int。
八、运算符
14、关系运算符 @ < <= > >= != ==
15、逻辑运算符 @ &(逻辑与) |(逻辑或) !(非) &&(短路与) ||(短路或)
逻辑运算符两边都要是布尔型,并且最终的运算结果也要是布尔型
&&和&的区别 @ &&是当左边的表达式是false时右边被短路了不再执行,
而&是无论什么情况两边都会执行 #大多情况都是使用&&,执行效率高
16、赋值运算符 @ = += -= *= /= %=
重要规则:x=x+1和x+=1是有一些区别的,x+=1不会改变变量类型,相当于在x=x+1加了一个强制类型转换符
17、条件运算符(三目运算符) @ 布尔表达式 ? 表达式1:表达式2;
18、字符串和数字相加结果还是字符串
day08
九、控制语句
0、输入扫描器语句 @ java.util.Scanner 变量名=new java.util.Scanner(System.in);
int i=变量名.nextInt(); String j=变量名.next();
1、if语句 没有冒号
2、switch语句 @ P127
〇switch(变量){
case 常量: 语句;break;
…
default: 语句;break;
}
①case后面是冒号没有大括号(多条语句也不加大括号),而且case可以合并 ②值是int或String,但是可以向下兼容,long不行
③记得加break,否则会穿透(后面的即使没匹配上也会执行,直到遇到break或者循环结束)
3、for(初始化表达式;条件表达式;更新表达式){
循环语句;
}
#①初始化表达式只执行一次 ②循环体有可能一次都不执行
③初始表达式定义的变量不能在循环体外面用 ④初始化表达式、更新表达式不写,分号也不能少
for(初始化表达式 : 数组或集合){
循环语句;
}
#增强型for循环;缺点是没有下标
4、while循环
5、do…while
do…while循环的while后面有个分号别忘了
6、break;语句 @ 结束“整个循环”或者整个switch语句
①break;只能用在switch和循环语句当中
②可以在for前面加个 a: 给这个for循环起个名字,之后break a;来选定终止哪个for循环。用的少,不用在意
7、continue;语句 @ 结束“当前这一次”循环
day11
十、方法
1、修饰符列表 返回值类型 方法名(形式参数列表){
方法体;
} #其中修饰符列表不是必须的
2、return是用来结束当前方法的,return只要执行,当前方法结束。
return不能在if语句里面,编译通不过去
3、返回值类型 @ void的话单return用来终止方法也可以不写,其他的则必须有return … ,一一对应
4、形式参数列表 @ 要写出数据类型;形参直接用逗号分隔;可以有0个到很多个
十一、JVM(java虚拟机)
[记] java虚拟机主要有三块内存空间(还有别的) @ 方法区、栈内存、堆内存
方法区 @ classloader将class文件装载在虚拟机上的时候,存放代码块的地方,类就是在这个地方放着
栈内存 @ 方法被调用的时候,该方法执行需要的内存空间以及存储局部变量的内存空间在栈中分配
〇静态变量是存储在方法区当中(属于成员变量)
实例变量是存储着堆内存当中(属于成员变量)
局部变量是存储在栈内存当中
①方法不调用是不会在栈中分配内存空间的
②方法执行结束,栈中的内存空间会立即被释放,发生出栈(弹栈)
③方法调用又叫做进栈(压栈、push),分配内存;方法结束又叫做出栈(弹栈、pop),释放内存
堆内存 @ 存储对象的,只要new出来的对象都存储在堆内存当中
day12
十二、方法重载(overload)
1、使用场合 @ 功能相似时用方法重载,可以少记一些方法的名字
[记]2、条件 @ 同一个类中;方法名相同;参数不同
参数不同 @ 参数个数不同;参数类型不同;参数顺序不同
3、注意点 @ 调用别的类里面的相同的方法名的方法不叫方法重载;
只是修饰符列表和返回值类型不同也不叫方法重载,会报错
十三、方法递归
1、递归必须要有结束条件,否则会发生栈溢出错误;
2、就算递归是合法的,有时候也会出现栈溢出错误,因为递归得太深,栈内存不够用,可以手动调节栈的内存(java -x查看相关命令)
3、能使用循环代替递归尽量使用循环,但是某些情况必须使用递归才能实现功能
day13
十四、面向对象
1、面向过程 @ 缺:耦合度太高,扩展力差 优:效率高
[记]2、面向对象的整个软件研发的过程都是采用OO进行贯穿
OOA:面向对象分析
OOD:面向对象设计
OOP:面向对象编程
[记]3、面向对象的三个特征 @ 封装、继承、多态
4、类 @ 是一个模板,是某些事物所具有的共同特征
类中有属性(成员变量)和方法
5、对象(实例) @ 类的具体化,是实际存在的个体
6、实例化 @ 通过类这个模板创建对象的过程
7、抽象 @ 多个对象具有共同特征,进行思考总结创建共同特征的过程
8、创建类的语法 @ 类名 变量名(引用) = new 类名();
①这里的引用指向堆内存的一块空间
②引用和对象的区别 @ 引用是一个存储对象地址的变量(不一定是局部变量),对象是堆里new出来的
day14
十五、构造方法
[记]0、作用 @ 创建对象,并且创建对象的过程中给对象中的成员变量赋初始值
#构造方法可以直接调用自己这个class中的成员变量,毕竟还要在这里给成员变量赋初始值
1、格式 @ 修饰符列表 方法名(参数列表){
方法体
}
2、方法名必须和类名完全一致;不能有返回值类型
3、注意点 @ ①当一个类中没有提供构造方法,系统默认一个无参数构造方法,称为缺省构造器
②手动提供一个有参数的构造方法,无参构造方法会丢失,因此建议手动给他构造出来,否则会影响到子类构造方法的构建
③类构造方 法支持重载,因此是可以同时有多个类构造方法的
十六、封装
1、作用 @ 安全和操作简单
0、用private把局部变量封装起来,让外部不能直接访问它,而要通过一些窗口才能访问
2、实例方法 @ 不带static修饰符的方法,这样这个方法通过[类名.方法名]不能调用,必须实例化new出来才能调用,就叫做实例方法
3、私有变量 @ 用private修饰,这个类外的任何东西都无法访问这个变量,只有这个类里面的方法可以访问,通过定义一些方法提供窗口函数
day15
十七、static(静态)
[记] 1、有static关键字的变量和方法称为静态变量和静态方法,没有的话称为实例变量和实例方法
2、静态变量和静态方法调用方式 @ [类名.变量名/方法名]
实例变量和实例方法调用方式 @ [引用名.变量名/方法名],所以使用时必须new创建一个对象
#同一个类中的实例方法访问本类中的实例变量看起来是直接访问的,其实是省略了this.
3、静态变量存储在方法区中
实例变量存储在堆内存中
注意点:如果一个类所有对象的某个属性都是相同的,建议把它定义为静态变量,这样只用存储一次,节省空间
一个方法中访问了实例变量,那么这个方法一定要是实例方法,如果加static的话会报错,因为调用静态方法时那个实例变量没有new,废了
4、静态代码块 @ static{
代码块;
}
①静态代码块存储在方法区,只执行一次。
②静态代码块在main方法前访问
③静态代码块和静态变量在执行时遵循自上而下的执行顺序,是程序运行时最先执行的。
5、实例代码块 @ {
代码块;
}
①每次执行构造方法前都要执行一次示例代码块
②用得极少
十八、this
[记] 0、语法是 @ this.和this()
1、this保存内存地址指向对象自身,只能用在实例方法中,谁new这个实例方法this就是谁
2、this不能省略的情况 @ 当构造方法和实例方法的局部变量和实例变量的变量名一样的时候不能省略
3、this() @ 只能使用在构造方法中,且只能在第一行
表示当前构造方法调用本类其他构造方法
其目的是代码复用
day16
十九、继承类
[记] 1、class 子类名 extends 父类名{ #父类又称为基类、超类,子类又称为派生类、扩展类
类体;
}
2、继承了什么 @ 除了构造方法外其他的都继承过来了[private修饰的私有变量不能直接在子类中访问,可以间接访问]
3、缺点 @ 耦合性太强,父类稍有改变子类也跟之改变
4、object是老祖先类,所有类默认继承这个类
二十、方法重写/方法覆盖(override)
1、使用场合 @ 继承了父类的方法后,对父类的某些方法不满意,就需要方法重写
2、条件 @ ①方法重写必须有继承关系
②重写方法与原方法的返回值、方法名、参数列表必须相同 #返回值类型是引用类型的话可以变小,实际开发一般都是一样,研究意义不大
③返回值类型
③访问权限不能更低,可以更高 protected ——> public
④重写之后的方法不能比原方法抛出更多的异常
3、注意点 @ ①私有方法无法覆盖,静态方法不谈覆盖
②构造方法不能被继承自然也不能被覆盖
③方法覆盖只是针对实例方法,静态方法覆盖没有意义
day17
二一、多态
1、 向上转型和向下转型双方必须有继承关系(可以理解为自动转换和强制转换)
向上转型 @ 子 ——> 父
向下转型 @ 父 ——> 子
向下转型需要加强制类型转换符,有风险,要用instanceof判断 ,养成习惯
语法 @ [引用 instanceof 类型]
2、多态 @ Animal a = new Cat();
a.move();
编译的时候move()是Animal的,执行时调用的是Cat重写的move()方法
day18
3、多态在开发中的作用 @ 降低耦合度,提高程序的可扩展性
4、方法覆盖就是为多态服务的,否则单单方法覆盖没有意义
二一、super
[全记]0、语法是 @ super.和super()
1、super()只能出现在构造方法第一行,表示通过当前构造方法调用父类的构造方法。
2、既没有this()又没有super()的话,默认会有一个super(),无论如何super()必然会有
3、java中允许子类和父类中有同名属性,会覆盖从父类那里继承过来的属性,和方法重写一个道理(按理属性不存在重写这里只是形象比喻),
但是父类的属性和方法在父类里面仍然存在,super.和super()是直接跳到父类去拿方法或属性
4、super.什么时候不能省 @ 子类和父类有同名属性或方法,想在子类访问父类属性或方法,super.不能省略
5、父类中的私有变量子类不能super.
进阶
day19
一、IDEA使用
1、快捷键以及一些简单的设置
1.1字体设置
file --> settings --> font
1.2快捷生成main方法
psvm
1.3快速生成System.out.println()
sout
1.4删除一行
Ctrl+y
1.5运行
Ctrl+shift+F10
1.6窗口的放大缩小
Ctrl+shift+F12
1.7程序的切换
Alt+左右箭头
1.8窗口的打开关闭
Alt+窗口标号
1.9任何新建、新加的快捷键
Alt+ins键
1.10单行注释
Ctrl+/
1.11多行注释
Ctrl+shift+/
1.12提示方法的参数
Ctrl+P
1.13定位方法/变量
按着Ctrl点击鼠标左键
1.14纠错
Alt+回车
1.15查看一个类的属性和方法
Ctal+F12
day20
二、final
1、final修饰类 @ 该类不可被继承
2、final修饰方法 @ 该方法不可被重写
[给变量赋值原理是一样的,只能赋一次值]
3、final修饰引用变量 @ 该变量只能存储一次内存地址,跟对象就绑死了,不可修改,但是对象里面的值可以修改
4、final修饰局部变量 @ 该变量只能赋一次值
5、final修饰实例变量 @ 该变量只能在声明或构造方法中赋一次值,两者都不赋值会报错,不会赋默认值,Sun公司要甩锅
6、常量 @ 用[static final]修饰的变量是常量,一般在前面再加个public直接公开也无妨,反正改不了
三、抽象类和抽象方法
1、抽象类的定义 @ [修饰符列表] abstract class 类名{
类体;
}
2、抽象类不能实例化new,只能等待着被子类继承,因此不能用final修饰,final和abstract是对立的
3、抽象类的子类还可以是抽象类
4、抽象类有构造方法,默认也是有的,供子类的super()调用,这些都有,只是表面上看不到
5、抽象类中既可以有抽象方法也可以有普通方法
6、抽象方法的定义 @ public abstract 返回值类型 方法名();
注意:抽象方法在子类中必须重写,不然会报错
四、接口
0、接口没有构造方法
1、接口的定义 @ [修饰符列表] interface 接口名{
类体;
}
2、接口编译后也是class文件
0、接口与接口之间支持多继承,一个类可以实现多个接口
3、接口比抽象类还要抽象,他的类体中只能有常量和抽象方法,
4、接口中所有的元素都是public修饰的,接口中的(抽象)方法的public abstract修饰符可以省略,“方法名();”
接口中的常量的public static final,“数据类型 变量名 = 值;”
day21
5、接口的实现 @ 用implements #可以理解为继承,不过用的关键字不一样
6、接口的实现类中的方法必须要加public,因为接口中其实是有public的只是省略了,这里的实现也必须要有
7、一个类可以同时实现多个接口,每个接口中的方法都要实现才行
8、extends和implements可以并存,extends在前,implements在后
五、类型与类型之间的关系
1、 is a
能用is a描述的是“继承关系”
cat is a Animal
2、has a
能用has a描述的是“关联关系”,通常以属性的形式存在
I has a Pen
3、like a
能用like a描述的是“实现关系”,通常指”接口的实现“
Cooker like a FoodMenu(厨师像一个菜单一样)
六、package
0、用来创建目录,也可以说是建包,必须写在程序第一行
1、格式 @ package 包名;
0、完整类名 @ 包名.class名
2、在cmd中编译和运行 @ 编译:javac -d . class名.java #会自动建目录,还是很方便的,这里的点要注意别丢了,
运次:java 包名.class名 #完整类名是[包名.class名]
七、import
1、用来导入其他包下的class文件,必须出现在package语句之下class语句之上
2、格式 @ import 完整类名; #完整类名是[包名.class名]
3、lang包自动导入,不需要手动导包
day22
八、访问控制权限
1、访问控制符 本类 同包 子类 所有位置
--------------------------------------------------
public 可以 可以 可以 可以
protected 可以 可以 可以 不可
”默认“ 可以 可以 不可 不可
private 可以 不可 不可 不可
2、public和“默认”可以修饰类、接口、方法、属性
protected和private只可以修饰属性、方法
九、lang包下的类和方法
Object类(在lang包下)
toString方法 @ "引用.toString()"返回一个字符串,一般都会重写;直接写引用默认调用这个方法
equals方法 @ “a.equals(b)” 用来判断两个“引用”是否相等,一般会重写,否则就和==没什么区别了
finalize方法 @ 在对象被JVM销毁时自动调用该方法,跟实例代码块功能相似,可以重写之后用来记录这个时刻,但是可能不会执行,用的很少
hashCode方法 @ "引用.hashCode()"返回一个对象的内存地址的hash值
String类(在lang包下)
String类里面重写了toString方法和equals方法,这样用equals就可以自动判断字符串是否相等了,不用手动重写
结论:字符串类型比较必须使用equals比较
day23
十、匿名内部类
new 接口名(){
类体;
}
缺点 @ 只能使用一次;代码可读性差
别人写要能看懂
十一、数组
1、类型 @ 静态声明 @ 数据类型[] 数组名 = {值1,值2…};
动态声明 @ 数据类型[] 数组名 = new 数据类型[数组长度];
当做参数直接用 @ new 数据类型[数组长度]{值1,值2…} #后面的值的个数要和数组长度对应
0、数组的长度 @ 数组名.length;
2、关于args这个main中2021/2/18行是[java 类名 字符串1 字符串2 …]
在idea中的话: run --> deit configorations
目的:一般用来给一个程序设置登录名和密码
3、数组扩容 @ 调用arraycopy方法:arraycopy(数组1,起始位置,数组2,起始位置,长度);
4、二维数组 @ 数据类型 [][] 数组名 = {数组1,数组2…};
5、排序的方法 @ import java.util.Arrays; --> Arrays.sort(数组);
6、查找的方法 @ Arrays.binarysearchg(数组,要查找的元素); #找到的话就返回索引值,没找到就返回一个负数
day25
十二、lang包下常用工具类(查参考文档)
[记] 1)类String(在lang包下) @
1、构造方法有很多,可以把字符数组、字节码数组转化为字符串,自己看参考文档
①所有的字符串都存储在方法区当中的[字符串常量池]中,且不用new就可以用。因为它使用很频繁,这样效率高。
但如果new的话在堆内存当中保存有这个字符串的内存地址,然后栈中保存有一个指向堆内存的内存地址(属实多余)。
②所以new不new还是有区别的,同一个字符串new的话变量指向堆内存中的不同地址,这几个对象再指向方法区中的同一个地址
不new的话变量直接指向方法区中的同一个内存地址。
2、方法(看参考文档) @
charAt() @ 返回指定索引处字符
compareTo() @ 比较两个字符串大小
contains() @ 判断该字符串是否包含指定字符串
endsWith() @ 判断该字符串是否以指定字符串结尾
startsWith() @ 判断该字符串是否以指定字符串开始
equals()
equalsIgnoreCase() @ 忽略大小写的情况下判断两个字符串是否相等
getBytes() @ 将字符串转化为字节码数组返回
indexOf() @ 返回指定字符串在该字符串中第一次出现时的索引
lastIndexOf() @ 返回指定字符串在该字符串中最后一次出现时的索引
isEmpty() @ 判断此字符串是否为空
length() @ 返回此字符串的长度
replace() @ 将此字符串中的一个指定子字符串替换为另一个指定字符串返回
split() @ 将此字符串以指定字符串进行拆分,返回一个字符串数组
substring() @ 两种用法 ①只有一个索引的话以该索引为起点返回该索引以后的子字符串返回 ② 两个索引的话返回这两个索引之间的子串返回
toCharArray() @ 将该字符串转化为字符数组返回
toLowerCase()、toUpperCase() @ 将该字符串转化为小、大写的字符串返回
trim() @ 去除该字符串的前后空白并返回
String.valueOf() @ String中的唯一一个静态方法
将非字符串转化为字符串返回。println()方法中也调用了valueOf(),所以在控制台输出的值都是字符串类型。
2)类StringBuffer()和StringBuilder() @
1、用法 @ StringBuffer 变量名 = new StringBuffer(初始化容量); #字符串实际是在数组中存储着,初始化容量不写的话默认值是16
变量名.append(添加字符串);
0、相对于String()的好处是可变,就算给定的容量满了也会可以自动扩容,我们应给定适合的初始化容量,因为数组的容量小了扩容以及容量大了都会影响效率
2、StringBuffer()和StringBuilder()区别 @ StringBuffer()是线程安全的,StringBuilder()是非线程安全的
3)类Byte、Short、Integer、Long、Float、Double、Boolean、Character
1、这8个类是八种基本数据类型的包装类,其中前六种都继承了Number类
2、装箱 @ Integer 变量名 = new Integer(int或String类型的数据); #Integer.valueOf()也可以把int转化为Integer
3、拆箱 @ int 变量名 = Integer类型的变量.intValue();
4、自动装包和自动拆包 @ java5之后就不用手动装包和拆包了,自动完成,也就是上面学的那两个方法用不着了。
#加减乘除里面有个基本数据类型都会触发自动拆包机制,但是==不会触发
day26
5、整数型常量池 @ 在方法区中提前new好了[-128~127]这256个对象,存储在缓存中称为整数型常量池
6、Integer.parseInt() @ 字符串转化为整型 #Integer类(lang包下)中的方法,类型不符会报NumberFormatException异常
7、Integer.toString() @ 整型转化为字符串 #String.valueOf()也能实现这个功能
4)int、String、Integer之间的相互转化 @
int --> String @ String.valueOf()
String --> int @ Integer.parseInt()
int --> Integer @ 自动装箱
Integer --> int @ 自动拆箱
Integer --> String @ String.valueOf()
String --> Integer @ Integer.valueOf()
十三、常用类的常用方法
1)Date --> String:
1、java.util.Date() @ 当前时间
0、java.util.Date(毫秒数) @ 获取1970.1.1 00:00:00经过了这么多毫秒数之后的时间
2、SimpleDateFormat()构造方法 @ 格式化时间
3、format()(SimpleDateFormat类下的方法) @
用法实例 @ Date myDate = new Date(); #Date类在java.util包下
System.out.println(myDate); #Tue Feb 16 10:51:49 CST 2021
SimpleDateFormat myFormat = new SimpleDateFormat(“yyy-MM-dd HH-mm-ss-SSS”); #括号中的双引号,大小写注意,SimpleDateFormat类在java.text下
String nowDate = myFormat.format(myDate); #返回的是String,用了SimpleDateFormat类中的format()
System.out.println(nowDate); #2021-02-16 10-51-49-473
2)String --> Date:
4、parse()(SimpleDateFormat类下的方法) @
用法实例 @ String str = “1999-11-09 12:0:0:0”;
SimpleDateFormat myFormat = new SimpleDateFormat(“yyy-MM-dd HH:mm:ss:SSS”); #双引号里面的格式必须和上面字符串格式对应
Date myDate = myFormat.parse(str); #用到SimpleDateFormat类中的parse()
System.out.println(myDate); #Tue Nov 09 12:00:00 CST 1999
3)1970到现在的毫秒数
5、System.CurrentTimeMillis()(lang包下的System类下的静态方法) #要用long类型数据来接收结果,数据太大了
4)BigDecimal类(math包下) @
6、BigDecimal @ 超高精度浮点型,用于财务管理
7、add() @ BigDecimal类型的数据相加
5)Random类(util包下) @
8、Random()用法实例 @ Random random = new Random();
int num = random.nextInt();
9、nextInt(整数) @ 在[0~整数-1]取随机数,没有的话默认的数还是很大的
十四、枚举(enum)
1、用法 @ (public) enum 枚举名{
值1,值2,值3… #没有分号;一般大写,相当于常量
}
2、调用 @ enum.值1 #可以用在switch语句中
day27
十五、异常处理
#异常有编译时异常(又叫受控异常,ExceptionSubClass)和运行时异常(又叫非受控异常RunTimeException);所有异常都发生在运行阶段,前者发生概率高;
编译时异常必须处理,运行时异常处不处理都可以,难以预测
1、处理异常的两种方式 @
throws 异常名 @ 上抛异常 #写在方法声明处
try{} catch(异常名 变量名){两种方法的提示信息或者手动输出提示信息} (finally{}) @ 抓取异常
#catch可以写多个;在一个catch里面可以写多个异常,用“|”连接;finally一般用于关闭流,避免流关闭不了
2、异常对象的两个非常重要的方法 @
变量名.printStackTrace(); @ 打印异常跟踪的堆栈信息 #一般写这个,idea默认也是这个
String 变量名2 = 变量名.getMessage(); --> System.out.print(变量名2); @ 获取异常简单的描述信息 #这个返回的结果就是简略的一句话
3、自己写异常类(两步) @ 继承Exception或者RuntionException --> 定义一个无参构造方法 一个有参构造方法(String s) {super(s);}
4、手动抛出异常 @ throw new 自己写的异常(“简单异常信息”); #要记得把异常层层抛给调用者,在上面某一个调用者用try…catch语句抓取异常
day28
十六、集合
[记] 1、集合继承结构图 @ 见附件 #集合中的元素必须是引用类型,如果是基本数据类型会自动装箱
2、Collection(接口) @
常用方法 @ void add(Object o) : 添加一个元素到集合里面 #存储的是内存地址,不能存储基本数据类型,基本数据类型都自动装箱了
int size() : 获取集合中元素的个数
boolean contains(Object o) : 判断集合中是否包含元素o
boolean remove(Object o) : 删除集合中的元素o
void clear() : 清空集合
boolean isEmpty() : 判断集合是否为空
Object[] toArray() : 将集合转化为数组
3、迭代器 @ #集合的遍历要用迭代器;迭代器对象相当于一个照片;集合元素发生改变要重新构建迭代器,否则会报错;
Iterator iterator()(Iterator这个老祖宗的唯一方法) @ 返回迭代器对象 #挺特别,方法里面返回的是对象
boolean havNext() @ 判断集合里面是否还有元素
Object Next() @ 获取迭代器的下一个元素 #这两个方法一般结合使用,使用泛型这里Object可以变成泛型里面的类型
void remove() @ 删除迭代器中的元素,同时集合中的元素也被删掉 #和集合的remove()是不一样的,在迭代器里面 不能用[集合.remove()]
用法实例 @ Collection c = new ArrayList(); #创建集合对象
c.add(“abc”);
c.add(“def”);
Iterator it = c.iterator(); #调用iterator()创建构造器
while(it.hasNext()){ #通过循环和迭代器的方法取出集合中所有的元素
System.out.println(it.next());
}
4、List(接口,List又继承了Collection接口)
特有方法 @ void add(int index,Object o) @ 在指定位置上插入元素,后面元素后移一位 #一般不用,list数据类型插入效率太低
void set(int index,Object o) @ 把指定位置上元素替换为另一个元素,其他不变
Object get(int index) @ 获取指定位置的元素
int indexOf(Object o) @ 获取指定元素的第一个索引
int listIndexOf(Object o) @ 获取指定元素的最后一个索引
void remove(int dex) @ 删除指定位置上的元素
4.1、ArrayList(类,继承了List接口)
注意点:底层是数组;初始化容量是10,每次扩容为原来的1.5倍;非线程安全的
在所有集合类型中ArrayList用的最多;它检索效率最高,增删元素效率低,这是由数组的特性决定的
①Collections.synchronizeList(集合对象); @ 变为线程安全
②Collections.sort() @ 排序 #只能给List类型数组排序;如果集合里面元素类型是自己写的类型,这个类型要继承Comperable类,并重写compereTo()方法
③构造方法 @ ArrayList() @ 创建默认容量为10的集合
ArrayList(int n) @ 创建默认容量为n的集合
ArrayList(Collection c) @ 将一个其他类型的Collection集合转化为ArrayList类型的集合
4.2、LinkedList(类,继承了List接口)
注意点:底层是双向链表;检索效率低,随机增删元素效率高,由链表的特性决定的
4.3、Vector(类,继承了List接口)
#用的极少;线程安全;底层是数组;初始容量也是10,但是每次扩容为原来的2倍
5、treeSet(类,继承SortedSet接口)
注意点:无序不可重复,但是元素是按照大小顺序排序的;
添加的元素如果是自定义的类,一定要继承Comperabal类,并且要重写compereTo(继承类 c),怎么重写? @ return this.>c.; 是升序
或者还有一种方式,写一个比较器,在创建集合时传进去,是有这样的构造方法的,当需要在多个比较规则之间切换,用这个方法比较好
6、Map (接口)
常用方法 @
put(key,value) @ 向Map集合中添加键值对
get(key) @ 返回key对应的value
void clear() @ 清空Map集合
boolean containsKey(key) @ 判断Map集合中是否包含指定key
boolean containsValue(Value) @ 判断Map集合中是否包含指定Value
int size() @ 返回Map集合中元素个数
boolean isEmpty() @ 判断Map集合中元素个数是否为0
remove(key) @ 通过key删除键值对
Set() keySet() @ 获取Map集合中所有的key(所有的key用一个Set集合接收) #注意这里返回的是Set集合
Collection() value() @ 获取Map集合中所有的value(所有的value用一个Collection集合接收) #注意这里返回的是Collection集合
Set(<Map.Entry<K,V>>) entrySet() @ 将Map集合转化为Set集合 #这里Map.Entry<K,V>是一个静态内部类,相当于一个个小节点,里面K和V可以指定类型,后面通过getKey()和getValue()返回
实例 @ Set<Map.Entry<Integer,String>> myKv = map.entrySet(); #事先定义好了一个Map集合,起名map,事先放入了元素<1,“张三”>进去
for(Map.Entry<Integer,String> i : myKv){
System.out.println(i.getKey()); #返回1
System.out.println(i.getValue()); #返回"张三"
System.out.println(i); #返回1=张三
}
6.1、HashMap(类,继承了Map接口)
#创建集合
注意点:无序不可重复;初始化容量是16,默认加载因子是0.75,每次扩容为原来的2倍,当哈希单向链表元素小于6个时,单向链表变为红黑树,当哈希红黑树中的元素超过8时,红黑树又变为单向链表;
放在HashSet上的元素和HashMap的key上的元素一定要同时重写hashCode()和equals();非线程安全的;key和value都可以为空,key只能有一个空,没啥用
遍历HashMap集合的两种方式 @ ①先获取所有的key,遍历key的时候获取value
②通过entrySet()将HashMap集合转化为Set集合,Set集合中的元素是Node节点,每个节点有key和value,可以通过getKey()和getValue()获取
6.2、HashList(类,继承了Map接口)
注意点 @ 线程安全的,但是效率低,用得少;初始化容量是11,扩容是原容量*2+1;底层也是哈希表数据结构;key和value不允许为空
6.2.1、Properties(类,继承了HashLish类)
特有方法 @ setproperty() @ 存入键值对,底层调用put(),功能一样
getproperty(key) @ 通过key获取value,和get()功能一样
6.3、treeMap(类,继承了Map接口)
注意点 @ 无序不可重复,但是元素是按照大小顺序排序的
day31
十七、IO流
1、IO流的四大家族 @ InputStream(字节输入流)、OutputStream(字节输出流)、Reader(字符输入流)、Writer(字符输出流),都是抽象类
2、所有流都实现了java.io.Closeble接口 @ 用完流要记得调用close()关闭流
3、所有的输出流都是可关闭的 @ 用完输出流要记得调用flush()清空/清空管道
4、16个常用流 @
文件专属 @ FileInputStream (掌握)
FileOutputStream (掌握)
FileReader
FileWriter
缓冲流专属 @ BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter
数据流专属 @ DateInputStream
DateOutputStream
对象专属流 @ ObjectInputStream (掌握)
ObjectOutputStream (掌握)
转换流专属(将字节流转化为字符流) @
InputStreamReader
OutputStreamWriter
标准输出流 @ PrintWriter
PrintStream (掌握)
5、FileInputStream @
读取文件(只贴了try部分) @ #读中文会乱码
FileInputStream file = null;
try {
file = new FileInputStream(“C:\Users\ADMIN\IdeaProjects\text.txt”); #双引号
byte[] lists = new byte[4]; #这里是byte类型的,因为FileInputStream每次就是读取一个字节,用别的类型来接收都是浪费
int readCound = 0;
while ((readCound = file.read(lists)) !=-1){ #这里的file.read(lists)返回的是这个数组中元素的数量,lists在这里已经被存有元素了
System.out.print(new String(lists,0,readCound));
}
其他方法 @
available() @ 获取流当中剩余没有读到的字节数 #利用这个函数创建数组长度可以一下子把流读完,大大减少往数组的读写次数
skip (数目) @ 跳过几个字节不读 #用在一些特殊书写风格的文件里,比如文件隔指定长度有一个需要的数据
6、FileOutputStream @
写入文件(只贴了try部分) @
FileOutputStream myfile = null;
try {
myfile = new FileOutputStream(“my_file”,true); #这里不加true的话原文件里的内容会被清空再写入
String str = “我是中国人,我骄傲!!”;
myfile.write(str.getBytes());
byte s = 98;
myfile.write(s); #这里的write()里面的参数也可以只截取其中的一部分
}
7、copy一个文件的步骤 @ (只贴了try部分)
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(“E:\Java课堂笔记\Javase笔记\杜老师笔记\day01课堂笔记.txt”);
fos = new FileOutputStream(“E:\Java课堂笔记\Javase笔记\我的笔记\day01课堂笔记.txt”); #这里的day01课堂笔记.txt要加上
byte[] lists = new byte[1024 * 1024];
int readCound = 0;
while ((readCound = fis.read(lists)) != -1){
fos.write(lists,0,readCound);
}
fos.flush();
}
8、FileReader @
和FileInputStream用法一样,不同在于 ①只能读取普通文本文件
②这里read()里面放的参数是char数组
9、FileWriter @
和FileOutputStream用法一样,不同在于 ①只能写普通文本文件
②这里write()里面放的参数是char数组或者[字符串]***
10、BufferedReader @ (只贴了try部分)
FileReader file =null;
BufferedReader in =null;
try {
file = new FileReader(“C:\Users\ADMIN\IdeaProjects\text1.txt”); #BufferedInputStream可以调用InputStreamReader()转化为BufferedReader
in = new BufferedReader(file); #这个构造方法里面不能传入文件地址,而是要传入一个read流;传入的流称为节点流,外面的流称为包装流
String str = null;
while ((str = in.readLine()) != null) { #这个当文件全部读完返回的是null而不是-1;readLine()是读取一行,用这个流主要就是用这个方法,可以不用定义数组;
System.out.println(str); #换行符没有读取,因此这里用println()可以返回和原文件一样的格式
}
} #关流的时候只用关最外层的包装流
11、BufferedWriter
#跟FileWriter用法相同
12、PrintStream
#通常用于记录日志
写日志类(只贴了日志类,可以在main方法中调用) @
public static void log(String amg){
try {
#获取日期并格式化
Date nowTime = new Date();
SimpleDateFormat sdf = new SimpleDateFormat(“yyy-MM-dd HH-mm-ss-SSS”);
String strTime = sdf.format(nowTime);
#更改输出方向(默认是控制台)
PrintStream out = new PrintStream(new FileOutputStream(“log.txt”,true)); #这里PrintStream()这个构造方法中必须是OutputStream流;true要放在节点流里
System.setOut(out);
System.out.println(strTime+": "+amg);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
13、ObjectInputStream (反序列化)
14、ObjectOutputStream (序列化)
注意点 @ ①当有多个对象需要序列化时,必须用集合的方式,否则存入第二个对象会报错
②被序列化的对象要继承Serializable接口,用来给对象生成序列化版本号,
手动设置序列化版本号 @ private static final long serialVersionUID = 设置的序列化号L; #这个变量不能随便写,这样即使改代码JVM也能识别出来是同一个类,就能照样反序列化,否则改代码的话反序列化时会报错
③对象中被transient关键字修饰的属性可以不参与序列化
15、File类
常用方法 @
new File(“目录名”) @ 构造方法
boolean exists() @ 判断该目录或文件是否存在
boolean createNewFile() @ 当不存在此文件时,把它创建出来
boolean mkdir @ 不存在此目录时,将他创建出来
boolean mkdirs @ 创建一连串目录
String getParent() @ 获取此路径的父路径
File getParentFile() @ 获取此路径的父File,返回的是File类型的文件
String getAbsolutePath() @ 获取此File的绝对路径
void delete() @ 删除文件
String getName() @ 获取文件名
boolean isFile() @ 判断此路径是否是一个文件
boolean isDirectory() @ 判断此路径是否是一个目录
long lastModified() @ 获取此路径最后一次修改的毫秒数,返回的是1970年到最后一次修改之间的毫秒数(要用Date的构造方法来获得真正的时间)
File[] listFiles() @ 获取此路径的所有子路径
16、IO+Properties联合使用 (写配置文件) #写的配置文件等号两边不要有空格;配置文件中的注释用’#’
用法 @
public static void main(String[] args) throws Exception{
FileReader myFile = new FileReader(“C:\Users\ADMIN\Desktop\temp.properties”); #这个配置文件一般以properties作为后缀
Properties myList = new Properties();
myList.load(myFile); #只需通过一个load()就可以将目标文件中等号两边的内容读取到字典中
String admin = myList.getProperty(“admin”);
System.out.println(admin);
}
十八、进程和线程
1、三种创建线程的方法 @ #start()就是一瞬间之后是多线程并行的
①通过继承Thread类创建进程(不好) @ #这种方法没有面向接口编程,
public class ThreadTest01 {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
for(int i = 0;i <= 1000;i++){
System.out.println(“主方法–>”+i);
}
}
}
class MyThread extends Thread{ public void run() { for(int i = 0;i <= 1000;i++){ System.out.println("分支-->"+i); } } } ②通过实现Runnable接口创建进程 @ #面向接口编程 public class ThreadTest01 { public static void main(String[] args) { Thread t = new Thread(new MyThread()); t.start(); for(int i = 0;i <= 1000;i++){ System.out.println("主方法-->"+i); } } } class MyThread implements Runnable{ public void run() { for(int i = 0;i <= 1000;i++){ System.out.println("分支-->"+i); } } } ③通过匿名内部类创建进程 @ public class ThreadTest01 { public static void main(String[] args) { Thread t = new Thread(new Runnable() { @Override public void run() { for(int i = 0;i <= 1000;i++){ System.out.println("分支-->"+i); } } }); t.start(); for(int i = 0;i <= 1000;i++){ System.out.println("主方法-->"+i); } } } ④创造有返回值的进程 @ 2、线程对象的生命周期 新建状态,就绪状态,运行状态,阻塞状态,死亡状态 3、设置线程对象名字 @ #默认线程对象的名字是Thread-0、Thread-1... setName() 4、获取线程对象名字 @ getName() 4、获取当前对象 @ (是个静态方法) Thread.currentThread() 5、让当前线程睡眠指定的时间 @ (是个静态方法) Thread.sleep(睡眠毫秒数) 6、强行中断此线程的睡眠 @ interrupt() #依靠的是异常处理机制,在此线程的run方法中只能try/catch,不能throws 7、终止线程的执行 @ 在线程中定义一个boolean类型的变量,再写一个if语句,通过return结束进程,在主线程中通过改变这个变量的值结束进程 8、设置线程的优先级 setPriority() #优先级是1~10,默认是5 9、获取线程的优先级 getPriority() 10、线程让位 Thread.yield() #让位一下时间片,像8,9,10这三个方法都是概率上的,只是让发生的概率大一些 11、合并线程 join() #此线程合并到当前线程,当前线程停止执行,转而执行此线程,直到此线程执行完毕当前线程才会执行,当一个线程必须等待另一个线程执行结束才能执行时使用jion()
day33
十九、多线程的安全问题
1、两个专业术语 @ 异步编程模型(并发)、同步编程模型(排队)
2、synchronized @ 排它锁
三种使用方法 @
同步代码块 @ synchronized(线程共享对象){同步代码块} #共享对象可以是this、字符串、指定对象
实例方法中使用synchronized关键字 #共享对象一定是this
静态方法中使用synchronized关键字 #锁的是类,不管创建了几个对象只要是同一个类他们就要排队
3、死锁
synchronized在嵌套使用时很可能会发生死锁,因为只要这个代码块没有执行完成就不会释放锁住的对象,要是其他的程序锁住了他里面需要锁的对象他就陷入停滞,同样如果他也锁住了其他程序需要的对象双方同时陷入停滞,发生死锁。
应用实例 @ class MyThread1 extends Thread{
Object o1;
Object o2;
public MyThread1(Object o1,Object o2){
this.o1 = o1;
this.o2 = o2;
}
public void run(){
synchronized (o1){
synchronized (o2){}
}
}
}
class MyThread2 extends Thread{ Object o1; Object o2; public MyThread2(Object o1,Object o2){ this.o1 = o1; this.o2 = o2; } public void run(){ synchronized (o2){ synchronized (o1){} } } } 4.尽量不使用synchronized关键字,会使系统吞吐量降低,影响效率。 其他的解决方案 @ ①使用局部变量代替“实例变量和静态变量” ②一个线程创建一个对象 #但有时候不得不使用synchronized 5、设置为守护线程 @ setDaemon(true) 6、设置定时器 @ 通过Timer()这个构造方法创建一个定时器,通过schedule()这个方法指定定时任务 应用实例 @ Timer timer = new Timer(); #构造方法中如果写上参数true,则表示创建的是守护线程的方式 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date firstTime = sdf.parse("2021-4-21 19:10:00"); timer.schedule(null,firstTime,1000*10); #第一个参数放F的是任务,那个任务在创建是要继承TimerTask这个抽象类 第二个参数是开始时间,是个Date类型的变量 第三个参数是间隔时间,每隔多少毫秒执行一次 7、对象.wait() @ 让对象上的当前线程陷入等待(自然要把锁也释放了,否则就是永久占着茅坑不拉屎) 对象.notify() @ 唤醒对象上的所有线程
二十、反射机制
1、三种获取Class的方法 @
Class 变量 = Class.forName(“完整类名带包名”);
Class 变量 = 对象.getClass();
Class 变量 = 任何类型.class;
2、使用1获取Class变量创建对象 @ #1和2的例子看ReflectTest01
变量.newInstance()
3、获取绝对路径 @ #可跨软件、跨系统;要求要获取的文件以类的根路径(src)作为起点。
String path = Thread.currentThread().getContextClassLoader().getResource(“文件名”).getPath();
4、流的方式获取文件 @ #4的例子看InputStreamTest01
InputStream liu = Thread.correntThread().getContextClassLosd().getResourceAsStream(文件路径); #这里一长串方法的最后一个跟上面不一样
△5、资源绑定器 @ #5的例子看ResourceBundleTest
#注意点 @ 这里是不带后缀的路径;路径只能在src目录下;
ResourceBundle 变量1 = ResourceBundle.getBundle(“不带后缀的文件路径”); #这里引入ResourceBundle.getBundle()
String 变量2 = 变量1.getString(); #这里引入getString()
△6、通过反射机制获取对象 @ #例子看ReflectTest05,视频看671
public static void main(String[] args) throws Exception{
Class studentClass = Class.forName(“com.bjppewernode.javase.reflect.Student”);
Object student = studentClass.newInstance();
Method method = studentClass.getMethod(“login”,String.class,String.class);
Object returnValue = method.invoke(student,“张三”,“123”);
System.out.println(returnValue);
}
△7、通过反射机制获取属性 @ #例子看ReflectTest06,视频看667
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。