java学习 asleer 2022/6/27
想成为大佬,就是要通过学习和积累,提升自己的各方面能力,比较抽象,共勉!
团队协作能力
高效沟通能力
需求分析能力
架构设计能力
抽象复用能力
独立创造能力
问题解决能力
归纳总结能力
自主学习能力
工具利用能力
高效编码能力
信息检索能力
开源建设能力
源码阅读能力
自测审查能力
文档编写能力
知识表达能力
绘图描述能力
兴趣驱动(长期学习能力)
保持好奇心
其他
视频
文档
老师忠告
JAVA_HOME= 指向jdk安装的主目录%JAVA_HOME%\bin.class字节码文件.class加载到jvm运行在命令台使用table可以实现命令补全
中文符号不需要转义,英文符号需要
介绍:
用于注解说明解释程序的文字,提高了代码的可阅读性,是良好的编程习惯。将自己的思想通过注释先整理出来,再用代码体现。对自己写的代码负责。
类型:
单行注释://后跟注释,快捷键:ctrl+/
多行注释:/* 注释 */,快捷键:ctrl+shift+/
多行注释里不能nest多行注释
文档注释:注释内容可以被javadoc所解析,生成一套以网页文件形式体现的该程序的说明文档,一般写在类
/*** @author asleer* @version 1.0*/javadoc -d 文件夹名 -xx -yy 文件名.java
shift+tab整体向左边移动 
dir:查看当前目录有什么内容
cd:切换到其他盘,切换到c盘:cd /D c:
切换到当前盘的其他目录,看上图所示,两种写法
cd ..:切换到上一级
cd \:切换到根目录
tree:查看指定目录下的自己目录
cls:清屏
退出dos exit
了解内容:
echo ok > hello.txt主要用于Linux
变量是程序的基本组成单位
概念:
类型+名称+值
for example:
int a = 1;计算机分配一个内存存储数值1,a是访问这个内存的方式(地址)
+号的使用
基本数据类型
数值型
字符型(char[2]):存放单个字符“a”或汉字
布尔型(boolean[1]):存放true,false
引用数据类型
byte[字节]:-128 ~ 127
short[短整型]:-(2^15) ~ 2^15-1等价于-32768 ~32767
int[整型]:-2^31 ~ 2^31-1
long[长整型]:-2^63 ~ 2^63-1
使用细节
l 或 L float[单精度]:-3.403E38 ~ 3.403E38
double[双精度]:-1.798E308 ~ 1.798E308
说明一下
使用细节
java的浮点型常量默认为double型,可以但不必要在后加 D 或 d,声明float型常量,需后加 f 或 F
浮点型常量的两种表示形式
通常情况下,应该使用double类型,因为他比float精度更高
浮点数使用陷阱:2.7和8.1/3比较
当我们对运算结果是小数的进行相等判断要小心。应该以两个数的差值的绝对值,在某个精度范围内判断
xxxxxxxxxxpublic class floatdetail{ public static void main(String[] args){ double num1 = 2.7; double num2 = 8.1 / 3; System.out.println(num1);//2.7 System.out.println(num1);//2.666666669 if( num1 == num2 ){ System.out.println("num1 == num2,equal"); } System.out.println(Math.abs(num1 - num2)); if(Math.abs(num1 - num2) < 0.000001){ System.out.println("差值非常小,认为相等"); } }}char:表示单个字符,可以存放汉字,多个字符使用字符串String
使用细节:
\n 表示单个字符(int) 字符System.out.println('a'+10) = 107本质:
存储:‘a’=>码值97=>二进制(1100001)=>存储
字符和码值的对应关系是通过字符编码表决定的
介绍:boolean类型数据只允许取值true和false,占用1个字节。不能用0或非0的整数替代。
精度小的类型自动转换为精度大的类型。
数据类型按精度大小排序:
char => int => long => float => double
byte => short => int => long => float => double
自动类型转换注意和细节
自动类型转换的逆过程,将容量大的数据类型转换为容量小的数据类型,使用时要加上强制转换符( ),但可能造成精度降低或外溢,格外要注意。
基本数据类型 => String:n + ""
String => 基本数据类型:
通过基本类型的包装类调用parseXX方法即可
使用基本数据类型对应的包装类的相应方法,得到基本数据类型
xfor example: String num = "123";int num = Integer.parseInt(num);//得到数字123System.out.println(num.charAt(0));//得到字符'1'xxxxxxxxxxInteger.parseInt("");Double.parseDouble("");Float.parseFloat("");Short.parseShort("");Long.parseLong("");Boolean.parseBoolean("");Byte.parseByte("");xxxxxxxxxxString yyy = "xxx";"xxx".equals(yyy)//则为true中文在线文档:Java 8 中文版 - 在线API中文手册 - 码工具 (matools.com)
使用方式:


% 取模的本质:a % b = a - a / b * b,如果a是小数,则 a % b = a - (int)a / b * b
自增++:
独立使用时:i++; == ++i; == i = i +1;
作为表达式使用:
++i先自增后赋值i++先赋值后自增
结果都是boolean,注意不要把 == 写成 =

基本赋值运算符:int a = 10;
复合赋值运算符:
a += b; [等价于a = a + b]a -= b;[等价于a = a - b]*=, /=, %=特点
运算顺序从右往左
复合赋值运算符会进行类型转换
xxxxxxxxxxbyte b = 3;b += 2;//等价于 b = (byte)(b + 2);b++;// b = (byte)(b + 1);xxxxxxxxxxa > b ? a : b;true?new Integer(1):new Double(2.0);1.0//因为三元运算符是一个整体,后者提高了前者的运算级别运算规则:
使用细节:
if--else语句
概念:对各种变量、方法和类等命名时使用的字符序列,或凡是自己可以起名字的地方
规则:
规范:
二进制:binary
四种表示方式:
转十进制:从最低位(右边)开始,将每个位上的数提取出来,乘以2/8/16的(位数-1)次方,然后求和
十进制转其他:将该数不断除以2/8/16,直到商为0为止,然后将每步得到的余数倒过来,就是对应的二进制
34转成二进制 = 0B00100010,0B后面自动补成八位
二进制转其他:
转二进制:
对于有符号的而言:
~2 = ?2的原码等于补码:00000000 00000000 00000000 00000010
~2的补码:11111111 11111111 11111111 11111101
~2的反码:11111111 11111111 11111111 11111100
~2的原码:10000000 00000000 00000000 00000011
所以答案为-3
&:两位全为1,结果为1,否则为0|:两位有一个为1,结果为1,否则为0^:两位一个为0,一个为1,结果为1,否则为0~:0->1,1->0>>:低位溢出,符号位不变,并用符号位补溢出的高位。本质是除以移动位数的2<<:符号位不变,低位补0。本质是乘以移动位数的2>>>:也叫无符号右移,运算规则是:低位溢出,高位补0 程序按顺序从上到下进行执行
xxxxxxxxxxif(条件表达式1){ 执行代码块1;//可以有多条语句}else if(条件表达式2){ 执行代码块2;}......else{ 执行代码块n;}switch和if的比较
- 如果判断的具体数值不多,而且符合六种数据(byte,short,int,char,enum[枚举],String)类型,虽然两个语句都可以,但是建议使用switch语句
- 其他情况:对区间判断,对结果为boolean类型判断,使用if,if的使用范围更广
xxxxxxxxxxswitch(表达式){ case 常量1://当表达式返回值对于常量1时执行 语句块1; break;//表示退出switch,而不是退出程序。如果没有break,---> 则不经过判断,直接执行语句块2(穿透) <--- case 常量2: 语句块2; break; ...... default: default语句块; break;//这个break可有可无}需要注意的细节:
xxxxxxxxxxfor(循环变量初始化;循环条件;循环变量迭代){循环操作(语句);}使用细节:
xxxxxxxxxxwhile(循环条件){ 循环体(语句); 循环变量迭代;}xxxxxxxxxxdo{ 循环体(语句); 循环变量迭代;}while(循环条件);;用法:用于终止某个语句块的执行,等于跳出本次循环,一般使用在switch或者循环中。
用法:用于结束本次循环,继续执行下一次循环
用法:使用在方法,表示跳出所在的方法;如果return写在main方法,退出程序
动态初始化(类似创建变量的两种方式)
xxxxxxxxxx数据类型 数组名[] = new 数据类型[];数据类型[] 数组名 = new 数据类型[];int[] a = new int[5];xxxxxxxxxx数据类型[] 数组名;int[] a;数组名 = new 数据类型[大小];a = new int[10];静态初始化
要求知道数组有多少元素,具体指
xxxxxxxxxxdouble[] hens = {3, 5, 1, 3.4, 2, 50}hens.length//可以得到数组的长度 String strs[] = new String[]{"a", "b", "c"};//okString[] strs = new String[3]{"a", "b", "c"};//error,编译不通过数组内数据赋值同样遵守自动类型转换
数组中的元素可以使任何数据类型,包括基本数据类型和引用数据类型,但不能混用
数组创建后,如果没有赋值,有默认值:
数组的下标从0开始
数组的下标必须在指定范围内使用,否则报:下标越界异常

xxxxxxxxxxint[] arr1 = {1, 2, 3};//地址传递int[] arr2 = arr1;//值传递int[] arr2 = new int[arr1.length];for(int i = 0; i < arr1.length; i++){ arr2[i] = arr[1];}xxxxxxxxxxint[] arr = {1, 2, 3};int[] arrNew = new int[arr.length +1 ];//选择创建一个新的数组来存放新的元素for(int i = 0; i < arr.length; i++){ arrNew[i] = arr[i];}arrNew[arrNew.length - 1] = 4;arr = arrNew;xxxxxxxxxximport java.util.Scanner;public class arrayadd{ public static void main(String[] args){ Scanner scanner = new Scanner(System.in); int[] arr = {1, 2, 3}; do { int[] arrNew = new int[arr.length + 1]; for(int i = 0; i < arr.length; i++){ arrNew[i] = arr[i]; } System.out.println("请添加数值"); int addnum = scanner.nextInt(); arrNew[arrNew.length - 1] = addnum; arr = arrNew; System.out.println("扩容后数组为"); for(int i = 0; i < arrNew.length; i++){ System.out.print(arrNew[i] + "\t"); } System.out.println(); System.out.println("添加成功,是否继续?y/n"); char key = scanner.next().charAt(0); if(key == 'n') break; }while(true); System.out.println("退出程序~~"); }}xxxxxxxxxximport java.util.Scanner;public class arrayReduce{ public static void main(String[] args){ Scanner scanner = new Scanner(System.in); int[] arr = {1, 2, 3, 4, 5}; int temp; do{ int[] arrNew = new int[arr.length - 1]; System.out.println("请选择你要删除的元素"); int reducenum = scanner.nextInt(); for(int i = 0; i < arr.length; i++){ if(arr[i] == reducenum){ for(int j = i; j < arr.length - 1; j++){ arrNew[j] = arr[j + 1]; } break; }else{ arrNew[i] = arr[i]; } } arr = arrNew; System.out.println("缩减后的数组为"); for(int i = 0; i < arrNew.length; i++){ System.out.print(arrNew[i] + "\t"); } System.out.println(); if(arrNew.length == 1){ System.out.println("当前只剩最后一个元素,不能再缩减"); break; } System.out.println("是否继续缩减?y/n"); char addnum = scanner.next().charAt(0); if(addnum == 'n') break; }while(true); System.out.println("退出程序~~"); }}将多个数据依指定的顺序进行排列的过程
思想:通过对待排序序列从后向前,依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就像水底下的气泡一样逐渐向上冒
xxxxxxxxxxpublic class BubbleSort{ public static void main(String[] args) { int[] arr = {22, 55, 44, 77, 99, 33, 11}; int temp; 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]){ temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } System.out.println(""); for(int i = 0; i < arr.length; i++){ System.out.print(arr[i] + "\t"); } }}常用的查找:
dimensional:维数
xxxxxxxxxxint[][] yint[] y[]int y[][]xxxxxxxxxx//列数相等int[][] arr = new int[5][6];//列数不确定形//1//2 2//3 3 3int[][] arr = new int[3][];//创建了3个一维数组,但每个元素没有开空间for(int i = 0; i < arr.length; i++){ arr[i] = new int[i + 1];//给元素开空间 for(int j = 0; j < arr[i].length; j++){ arr[i][j] = i + 1; }}把所有猫的特性(属性)提取出来 ===>
猫类Cat:自定义的数据类型,包含:
===> 猫对象:具体的一只猫,而不再是一个种类
xxxxxxxxxxpublic class xxx{ public static void main(String[] args){ //cat是对象名(对象引用) //new Cat()创建的对象空间(数据)才是真正的对象 Cat cat = new Cat(); cat.name = "xioabai"; cat.age = 3; cat.color = "white"; }}class Cat{ String name; int age; String color;}
栈里的cat是对象的名字,堆里空间与数据才是真正的对象
java内存的结构分析
java创建对象的流程简单分析
属性(成员变量/field即字段)
属性的定义语法同变量
属性如果不赋值,有默认值,规则和数组一致。
类似于数组

简单介绍:某些情况下,我们需要定义方法。比如人类,除了属性外,还有一些行为,这时候需要使用成员方法。
作用/好处:
xxxxxxxxxx//main里面写//先创建对象//再调用输出Person p = new Person();p.speak();int returnRes = p.getSum(10, 20);class Person{ String name; int age; //方法(成员方法) //public表示方法是公开的 //void表示方法没有返回值 //speak():speak是方法名,()是形参列表 //{}是方法体,里面写需要执行的代码 public void speak(){ System.out.println("我是一个好人"); } public int getSum(int num1, int num2){ int res = num1 + num2; return res; }}xxxxxxxxxxpublic(访问修饰符) void/返回数据类型 方法名 (形参列表){ //方法体 语句; return 返回值;}使用细节:
形参列表的细节:
printArr(int[][] map),或对象 Person p方法调用细节:

parameter:参数
基本数据的传参机制
引用数据的传参机制
递归就是方法自己调用自己,每次调用时传入不同的变量,递归有助于解决复杂的问题,同时让代码变得更简洁

xxxxxxxxxx//打印问题,输出2,3,4public void recursion(int n){ if(n > 2){ recusion(n - 1); } System.out.println("n=" + n);}//阶乘问题public int factorial(int n){ if(n == 1){ return 1; }else{ return factorial(n - 1) * n; }}递归的重要规则
xxxxxxxxxxpublic class MiGong{ public static void main(String[] args){ int[][] map = new int[8][7]; for(int i = 0; i < 7; i++){ map[0][i] = 1; map[7][i] = 1; } for(int i = 0; i < 8; i++){ map[i][0] = 1; map[i][6] = 1; } map[3][1] = 1; map[3][2] = 1; map[2][2] = 1;//导致回溯 System.out.println("=====当前地图====="); for(int i = 0; i < map.length; i++){ for(int j =0; j < map[i].length; j++){ System.out.print(map[i][j] + " "); } System.out.println(); } T ti = new T(); ti.findWay(map, 1, 1); System.out.println("=====新地图====="); for(int i = 0; i < map.length; i++){ for(int j =0; j < map[i].length; j++){ System.out.print(map[i][j] + " "); } System.out.println(); } }}class T{ //找到就返回true,否则就返回false //i和j表示老鼠当前的坐标 //规定,0是可走的路,1是障碍物,2是走过的确认可走的路,3是走过的确认不可走的路 //当map[6][5] = 2就说明找到了通路 //规定策略,下->右->上->左 public boolean findWay(int[][] map, int i, int j){ if(map[6][5] == 2){ return true; }else{ if(map[i][j] == 0){ map[i][j] = 2; if(findWay(map, i + 1, j)){ return true; }else if(findWay(map, i, j + 1)){ return true; }else if(findWay(map, i - 1, j)){ return true; }else if(findWay(map, i, j - 1)){ return true; }else{ map[i][j] = 3; return false; } }else{ return false; } } }}xxxxxxxxxxpublic class HanoiTower{ public static void main(String[] args){ Tower tower = new Tower(); tower.move(3, 'A', 'B', 'C'); }}class Tower{ //num表示要移动的个数,a,b,c分别表示A塔,B塔,C塔 public void move(int num, char a, char b, char c){ //如果只有一个盘 if(num == 1){ System.out.println(a + "->" + c);//指的是将A塔上的移动到C塔上 }else{ //如果有多个盘,可以看成是两个,最下面是一个,上面所有盘是一个 num-1 //先移动上面所有盘到b,借助c move(num - 1, a, c, b); //把最下面的盘移动到c System.out.println(a + "->" + c); //再把b塔的所有盘移动到c,借助a move(num - 1, b, a, c); } }}
定义:java中允许同一个类中,多个同名方法的存在,但要求形参列表不一致
注意事项:
定义:java允许将同一个类中多个同名同功能但参数个数不同的方法,封装成同一个方法
xxxxxxxxxxpublic int sum(int... nums){ int res = 0; for(int i =0; i < nums.length; i++){ res += nums[i]; } return res;}注意事项:
基本使用
在java编程中,主要的变量就是属性(成员变量)和局部变量
局部变量一般指的是在成员方法中定义的变量(或代码块)
java中作用域的分类
全局变量可以不赋值,直接使用,因为有默认值;局部变量必须赋值后才能使用,因为没有默认值
注意事项:
属性和局部变量可以重名,访问时遵循就近原则
在同一个作用域中,比如在同一个成员方法中,两个局部变量不能重名
作用域范围不同
xxxxxxxxxxpublic class test{ public static void main(String[] args){ Person p1 = new Person(); T t = new T(); t.test1();//第一种方法 t.test2(p1);//第二种方法 }}class T{//在类的方法中中调用其他类的属性 public void test1(){ Person p1 = new Person(); System.out.println(p1.name); } public void test2(Person p){ System.out.println(p.name); }}class Person{ String name = "jack"; int age = 10;}修饰符不同
定义:是类的一种特殊方法,作用是完成对新对象的初始化。构造器对于方法较多的情况下非常好用。
基本语法
xxxxxxxxxx[修饰符] 方法名 (形参列表){ 方法体;}public class test{ public static void main(String[] args){ //new对象时,可以直接通过构造器指定名字和年龄 Person p1 = new Person("jack", 80); }class Person{ String name; int age; //创建构造器,完成对象属性的初始化 public Person(String pName, int pAge){ name = pName; age = pAge; }}使用细节:
看一个案例:
xxxxxxxxxxclass Person{ int age = 90; String name; Person(String n, int a){ name = n; age = a; }}Person p = new Person("小倩",20);分析:
在方法区中先加载了Person类信息,只会加载一次
在堆中分配空间
完成对象初始化
把对象在堆中的地址返回给p(p是对象的引用)
对象里面隐藏一个this属性,this属性指向方法自己。简单地说,哪个对象调用,this就代表哪个对象
使用细节:
this可以用来访问本类的属性、方法、构造器
this可以区分当前类的属性和局部变量,即不受局部变量的影响,this.准确定位到属性
访问成员方法的语法:this.方法名(参数列表);
访问构造器语法:this(参数列表);(注意只能在构造器中调用另外一个构造器,且这条语句必须是构造器中的第一个语句)
this不能在类定义的外部使用,只能在类定义的方法中使用
this先调用本类的,然后再调用不同名的父类
xxxxxxxxxxclass T{ public T(){ this("jack", 10);//必须放在第一句话 System.out.println("T()构造器"); } public T(String name, int age){ System.out.println("T(String name, int age)构造器"); }}比较两个人是否相同
xxxxxxxxxxpublic class TestPerson{ public static void main(String[] args){ Person p1 = new Person("jack",21); Person p2 = new Person("tom",21); System.out.println(p1.compareTo(p2)); }}class Person{ String name; int age; public Person(String name, int age){ this.name = name; this.age = age; } public boolean compareTo(Person p){ return this.name.equals(p.name) && this.age == p.age; }}包的简单介绍:
作用:
包的本质:创建不同的文件夹来保存类文件
包的命名
常用的包
如何导入包
注意事项
java提供四种访问控制修饰符,用于控制方法和属性的访问权限(范围)
注意事项:
封装的理解
好处:
封装的实现步骤
基本介绍:
基本语法:class 子类 extends 父类{}
带来的便利:
注意事项:
继承的本质

介绍
基本语法
super.属性名;访问父类的属性,但不能访问父类的private属性super.方法名(参数列表)访问父类的方法,但不能访问父类的private方法 使用细节
介绍:子类有一个方法和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法
使用细节
xxxxxxxxxx //重写equals方法,比较两个对象的属性是否相等 public boolean equals(Object obj) { if(this == obj){ return true; } if(!(obj instanceof Doctor)){ return false; } Doctor doctor = (Doctor) obj; return this.name.equals(doctor.name) && this.age == doctor.age && this.gender == doctor.gender && this.job.equals(doctor.job) && this.sal == doctor.sal; }介绍:方法和对象具有多种形态。
方法的多态:重写和重载
对象的多态(记住)
多态的细节讨论:
向上转型
本质:父类的应用指向了子类的对象
语法:父类类型 引用名 = new 子类类型();
调用方法的规则
向下转型
语法:子类类型 引用名 = (子类类型) 父类引用
调用规则
属性没有重写之说法。属性的值直接看编译类型
instanceof是比较操作符,用于判断对象的运行类型是否为XX类型或其子类型
==
equals
System.out.println(Person); == System.out.println(Person.toString());快捷键
xxxxxxxxxx访问修饰符 static 数据类型 变量名;//(推荐)static 访问修饰福 数据类型 变量名; //访问方式:类名.类变量名;//(推荐)对象名.类变量名;注意事项:
xxxxxxxxxx//推荐访问修饰福 static 返回类型 方法名(){}static 访问修饰福 返回类型 方法名(){}//访问方式:类名.类对象名();//(推荐)对象名.类对象名();使用:
使用细节:
xxxxxxxxxxpublic static void main(String[] args){}解释main方法的形式
基本介绍:
基本语法:[修饰符]{代码}; ;号可以省略
好处:
说明注意:
修饰符是否写可选,写的话也只能写static。static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象都会执行一次
类什么时候被加载 [重要]
普通代码块会在创建对象实例时,被隐式的调用。如果只是使用类的静态成员,普通代码块不会被调用
创建一个对象时,类的调用过程是:
构造器的最前面隐含了super()和调用普通代码块
创建一个子类对象时,调用顺序:
静态代码块只能调用静态成员,普通代码块可以调用任意成员
介绍:采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
饿汉式步骤
xxxxxxxxxxpublic class single01 { public static void main(String[] args) { System.out.println(GirlFriend.getInstance()); }}class GirlFriend{ private String name; private static GirlFriend gf = new GirlFriend("凌华"); private GirlFriend(String name) { this.name = name; } public static GirlFriend getInstance() { return gf; } public String toString() { return "GirlFriend{" + "name='" + name + '\'' + '}'; }}懒汉式步骤
xxxxxxxxxx//只有当用户使用getInstance时,才返回cat对象。后面再次调用时,会返回上次创建的cat对象,从而保持了单例public class single02 { public static void main(String[] args) { System.out.println(Cat.getInstance()); }}class Cat{ private String name; private static Cat cat; private Cat(String name) { this.name = name; } public static Cat getInstance() { if(cat == null){ cat = new Cat("团子"); } return cat; } public String toString() { return "Cat{" + "name='" + name + '\'' + '}'; }}小结:
基本介绍:可以修饰类、属性、方法、局部变量
应用场景:
使用细节
final修饰的属性又叫常量,一般用XX_XX_XX来命名
final修饰的属性在定义时必须赋初值,并且以后不能再改,赋值可以在如下的位置之一:
如果final修饰的属性是static的,则初始化的位置可以是:
final类不能继承,但能实例化对象
如果类不是final类,但是含有final方法,则该方法虽然不能被重写,但可以被继承
一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法了
final不能修饰构造器
final和static往往搭配使用,效率更高,不会导致类加载。底层编译器做了优化处理
包装类(Integer,Double,Float,Boolean,String等)都是final
介绍:
访问修饰符 abstract 类名名叫抽象类访问修饰符 abstract 返回类型 方法名(参数列表);名叫抽象方法。注意抽象方法没有方法体细节讨论:
模板设计模式
xxxxxxxxxxabstract class Template{ public abstract void job(); public void calculateTime(){ long start = System.currentTimeMillis(); job(); long end = System.currentTimeMillis(); System.out.println((end - start)); }}xxxxxxxxxxinterface 接口名{ //属性 //方法(1.抽象方法 2.默认实现方法 3.静态方法)}class 类名 implements 接口{ //自己属性; //自己方法; //必须实现的接口的抽象方法;}//接口名.属性//类名.属性//类创建的对象名.属性//这三种方式都能访问到接口内的属性 //在JDK7前,接口里的所有方法都没有方法体,都是抽象方法//JDK8之后接口可以有静态方法,默认方法(default),也就是说接口中可以有方法的具体实现使用细节
实现接口 VS 继承类
接口的多态特性
定义:局部内部类是定义在外部类的局部位置上的,通常在方法中
使用细节:
本质:
xxxxxxxxxx//语法:new 类或接口(参数列表){ 类体};//调用方法:new A(){//方法1,因为匿名内部类本质是返回对象 public void cry(){ }}.cry();=============A a = new A(){//方法2,此处编译类型是A,运行类型是匿名内部类 public void cry(){ }};a.cry();使用细节
使用场景:
xxxxxxxxxxpublic class hhhhh { public static void main(String[] args) { f(new IB() {//匿名内部类传参法 public void show() { System.out.println("show()"); } }); f(new BB());//传统方法 } public static void f(IB ib){//写一个方法传递接口类型参数 ib.show(); }}interface IB{ void show();}class BB implements IB{//硬编码 public void show() { System.out.println("show()"); }}xxxxxxxxxxpublic class Homework04 { public static void main(String[] args) { CellPhone cellPhone = new CellPhone(); cellPhone.testWork(new Computer() {//匿名内部类作为参数传递 public double work(double num1, double num2) { return num1 + num2; } }, 10, 20); cellPhone.testWork(new Computer() { public double work(double num1, double num2) { return num1 * num2; } }, 10, 5); //这里可以看出匿名内部类是很方便的,可以重写来改变计算方法 }}interface Computer {//接口 public double work(double num1, double num2);}class CellPhone {//接口的方法只调用,让匿名内部类实现 public void testWork(Computer computer, double num1, double num2) { double result = computer.work(num1, num2); System.out.println(result); }}定义:成员内部类是定义在外部类的成员位置,并且没有static修饰
使用细节
xxxxxxxxxxpublic class innerClass01 { public static void main(String[] args) { new Outer().new Inner().say();//方式1 new Outer().getInner().say();//方式2 }}class Outer{ public class Inner{ private int n = 1; public void say(){ System.out.println("ok"); } } public Inner getInner(){ return new Inner(); }}定义:静态内部类是定义在外部类的成员位置,并且有static修饰
使用细节
可以直接访问外部类的所有静态成员
可以添加任意访问修饰符
作用域为整个类体
外部其他类访问静态内部类方式
new Outer.Inner();如果外部类和静态内部类的成员重名时,静态内部类访问时,遵循就近原则;如果想访问外部类的成员,则可以使用(外部类名.成员)来访问
实现方法
注意细节
使用
,分隔xxxxxxxxxxenum Season{ SPRING("春天", "温暖"), SUMMER("夏天", "炎热"), AUTUMN("秋天", "凉爽"), WINTER("冬天", "寒冷"); private String name; private String desc; Season(String name, String desc) { this.name = name; this.desc = desc; } public String getName() { return name; } public String getDesc() { return desc; } public String toString() { return "Season{" + "name='" + name + '\'' + ", desc='" + desc + '\'' + '}'; }}注意事项
enum常用方法的使用
toString:Enum类已经重写过了,返回的是当前的对象名,子类也可以重写该方法,使其返回对象的属性信息
name:输出枚举对象的名称
ordinal:输出的是该枚举对象的编号(从0开始)
values:返回枚举类的数组,遍历枚举对象(原码内看不到values,但可以通过javap反编译看到)
xxxxxxxxxxSeason[] values = Season.values();for(Season season: values){//增强for循环,values的值直接赋给season System.out.println(season);}valueOf:将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则会报错
compareTo:比较两个枚举变量,比较的是编号。返回值为编号相减
细节讨论
介绍:
xxxxxxxxxx//@Override源码(ElementType.METHOD)//说明只能修饰方法,@Taeget是修饰注解的注解,成为元注解(RetentionPolicy.SOURCE)public @interface Override {}//@interface表示一个注解类,而不是接口使用:
@SuppressWarning({""})中可以写入希望抑制的警告信息类型说明各种值
类型
@Retention说明
只能用于修饰一个Annotation定义,用于指定其可以保留多长时间
包含一个RetentionPolicy类型的成员变量,三种值为
基本概念:java语言中,将程序执行中发生的不正常称为异常(不包括语法错误和逻辑错误)
分类:

运行异常
编译异常
xxxxxxxxxxtry{ //代码/可能有异常}catch(Exception e){ //当异常发生时,系统将异常封装成Exception对象e,传递给catch,得到异常对象后,程序员自己处理。 //注意,如果没有发生异常,catch代码块不执行}finally{ //不管try代码块是否有异常发生,始终要执行finally,finally可以不写 //所以通常将释放资源的代码放在finally中}注意事项
基本介绍
使用细节
步骤
throw和throws
定义:包装类就是基本数据类型对应的引用数据类型
除了Character和Boolean包装类,其余6个包装类的父类是Number
包装类和基本数据类型的转换(以int为例)
JDK5前的手动装箱:基本类型->包装类型,反之是拆箱
xxxxxxxxxxint n1 = 100;Integer integer = new Integer(n1);//过时Integer integer1 = Integer.valueOf(n1);int i = integer.intValue();JDK5后实现了自动装箱和拆箱
xxxxxxxxxxint n2 = 200;Integer integer2 = n2;//底层仍然含有Integer.valueOf()int n3 = integer2;自动装箱底层调用的是valueOf方法,比如Integer.valueOf()
包装类型和String相互转换
xxxxxxxxxx//Integer->StringInteger i = 10;//方法1String s1 = i + "";//方法2String s2 = String.valueOf(i);//方法3String s3 = i.toString();//String->IntegerString s = "123";//方法1Integer i1 = Integer.valueOf(s);//方法2Integer i2 = new Integer(s);//已过时Integer类和Character类的常用方法
String类实现了Serializable和Comparable接口,前者说明String可以串行化(可以进行网络传输),后者说明String对象可以相互比较
理解
本质:String有属性private final char values[];用于存放字符串类型,且values是final类型,不可修改(地址)
xxxxxxxxxx//方式一:直接赋值String s = "asleer";//方式二:调用构造器String s1 = new String("asleer");.intern()//可以返回常量池的地址xxxxxxxxxxString a = "abc";String b = "def";String c = a + b;System.out.println("abc"+"drf" == c);//false//常量相加和变量相加规则不同xxxxxxxxxx//1. equals比较字符串是否相等,区分大小写String str1 = "hello";String str2 = "Hello";System.out.println(str1.equals(str2));//false//2. equalsIgnoreCase忽略大小写的判断内容是否相等String username = "John";System.out.println("john".equalsIgnoreCase(username));//true//3. length获取字符的个数,字符串的长度System.out.println("asleer".length());//6//4. indexOf获取字符在字符串对象中第一次出现的索引,索引从0开始,如果找不到返回-1String s1 = "asleer@*(@)";int index = s1.indexOf('@');System.out.println(index);//6System.out.println(s1.indexOf("ee"));//3//5. lastIndexOf获取字符在字符串中最后一次出现的索引,如果找不到返回-1index = s1.lastIndexOf('@');System.out.println(index);//9//6.substring截取指定范围的子串String name = "hello,张三";System.out.println(name.substring(6));//张三,从索引6开始截取后面的字符System.out.println(name.substring(2,5));//llo,截取[2,5)位置的字符[2,5)//7. trim删除前后空格//8. charAt(n)获取某索引处的字符xxxxxxxxxx//1. toUpperCaseString s = "hello";System.out.println(s.toUpperCase());//HELLO//2. toLowerCaseSystem.out.println(s.toLowerCase());//hello//3. concat拼接字符串String s1 = "faker.";s1 = s1.concat("uzi.").concat("theshy.").concat("together");System.out.println(s1);//faker.uzi.theshy.together//4. replace替换字符串中的字符//s1.replace返回的结果才是替换过的,对s1本身没有影响s1 = s1.replace(".", " ");System.out.println(s1);//faker uzi theshy together//5. split分割字符串,对于某些分割字符,需要转义String poem = "a,b,c,d";String[] split = poem.split(",");//abcdpoem = "E:\\aa\\bb";split = poem.split("\\\\");//E:aabbfor (int i = 0; i < split.length; i++) { System.out.print(split[i]);}//6. toCharArray转换成字符数组,再调用String构造器可以转换回去s = "happy";//拆开了分行输出happychar[] chs = s.toCharArray();for (int i = 0; i < chs.length; i++) { System.out.println(chs[i]);}//7. compareTo 比较两个字符串的大小//比较第一个不同的字符之间相差多少//如果都相等则比较长度String a = "tca";String b = "tam";System.out.println(a.compareTo(b));//2String c = "tama";String d = "tam";System.out.println(c.compareTo(d));//1//8. format格式字符串String name = "ll";int age = 18;double score = 56.789;char gender = '男';//占位符//%s表示由后面变量来替换//%d是整数来替换//%.2f表示使用小数来替换,保留两位小数并且四舍五入//%c使用char类型来替换String formatStr = "我的名字是%s,年龄是%d,成绩是%.2f,性别是%c";String info = String.format(formatStr,name,age,score,gender);System.out.println(info);结构剖析
StringBuffer构造器
StringBuffer转换
xxxxxxxxxx//String->StringBufferString str = "hello";//方式1 使用构造器StringBuffer stringBuffer1 = new StringBuffer(str);//方式2 使用append方法StringBuffer stringBuffer2 = new StringBuffer();stringBuffer2 = stringBuffer2.append(str);//StringBuffer->StringStringBuffer stringBuffer3 = new StringBuffer("hello");//方式1 使用StringBuffer提供的toString方法String s = stringBuffer3.toString();//方式2 使用构造器String s1 = new String(stringBuffer3);xxxxxxxxxxStringBuffer s = new StringBuffer("hello");//1. append增加s.append(',');s.append("world");//2. delete删除s.delete(5,8);//删除索引为[5,8),即hellorld//3. replace替换s.replace(5,8,",asleer");//hello,asleer//4. indexOf查找指定字符串第一次出现的索引,如果找不到返回-1int indexOf = s.indexOf("asleer");//6//5. insert在索引的位置插入内容s.insert(6,"my");//hello,myasleer//6. length长度System.out.println(s.length());//14基本介绍
结构剖析
String、StringBuffer、StringBuilder
abs:绝对值
pow:求幂指数
ceil:向上取整
floor:向下取整
round:四舍五入
sqrt:求开方
random:求0~1内的随机数
求2~7之间的一个随机整数
(int)(2 + Math.random() * (5 + 1));
max:求两个数的最大值
min:求两个数的最小值
xxxxxxxxxxArrays.sort(arr);Arrays.sort(arr, new Comparator(){ public int compare(Object o1, Object o2){ Integer i1 = (Integer) o1; Integer i2 = (Integer) o2; return i2 - i1; }});//倒序,使用匿名内部类实现接口方法的自定义实现//定制排序,定制冒泡排序法public static void main(String[] args) { int[] arr = {1, -1, 8, 0, 20}; Bubble(arr, new Comparator() { public int compare(Object o1, Object o2) { int i1 = (Integer) o1; int i2 = (Integer) o2; return i2 - i1;//可以通过返回值改变排序顺序 } }); System.out.println(Arrays.toString(arr));}public static void Bubble(int[] arr, Comparator c){ int temp = 0; for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length - 1 - i; j++){ if(c.compare(arr[j], arr[j + 1]) > 0){ temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } }}return -(low + 1);Arrays.copyOf(arr, arr.length()); 从arr数组中,拷贝arr.length个元素到新数组中。如果拷贝的长度>arr.length就在新数组的后面增加null。如果拷贝长度<0,就抛出NegativeArraySizeException。该方法的底层使用的是System.arraycopy()List asList = Arrays.asList(2, 3, 4, 5, 6, 1);返回的asList编译类型是List(接口),运行类型是java.util.Arrays$ArrayList,是Arrays类的内部类常见方法
System.arraycopy(src, 0(srcPos), dest, 0(destPos), src,length)BigInteger
xxxxxxxxxxBigInteger bigInteger = new BigInteger("1234567890987654321");BigInteger bigInteger1 = new BigInteger("100");BigInteger add = bigInteger.add(bigInteger1);//加法BigInteger subtract = bigInteger.subtract(bigInteger1);//减法BigInteger multiply = bigInteger.multiply(bigInteger1);//乘法BigInteger divide = bigInteger.divide(bigInteger1);//除法BigDecimal
xxxxxxxxxxBigDecimal bigDecimal = new BigDecimal("12345678.90987654321");BigDecimal bigDecimal1 = new BigDecimal("100.1");BigDecimal add = bigDecimal.add(bigDecimal1);//加法BigDecimal subtract = bigDecimal.subtract(bigDecimal1);//减法BigDecimal multiply = bigDecimal.multiply(bigDecimal1);//乘法BigDecimal divide = bigDecimal.divide(bigDecimal1, RoundingMode.CEILING);//除法//可能抛出异常ArithmeticException,如果除不尽出现无限循环小数的话//在调用divide方式时,指定一个精度即可xxxxxxxxxx//1. 获取当前系统时间,在java.util包下//默认输出的日期格式是国外的方式,因此通常需要对格式进行转换Date date = new Date();System.out.println(date);//2. 创建SimpleDateFormat对象,可以指定相应的格式//format:将日期转换成指定格式的字符串SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");String format = sdf.format(date);System.out.println(format);//3. 通过指定毫秒数得到时间Date date1 = new Date(9999999);//4. String->Date,使用的sdf格式需要和你给的String的格式一致,否则会抛出转换异常String s = "2022年07月21日 11:37:22 星期四";Date parse = sdf.parse(s);System.out.println(parse);Calendar类(日历)
xxxxxxxxxxCalendar c = Calendar.getInstance();System.out.println(c);//列出日历类对象的方法System.out.println(c.get(Calendar.HOUR));//返回小时,所获得的小时数是12进制的。24进制为HOUR_OF_DAY//月份是从0开始计数的,所以要+1后输出System.out.println(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" + c.get(Calendar.DAY_OF_MONTH));前两代日期类的不足分析:
JDK1.0中包含的java.util.Date类大多数方法都在JDK1.1引入Calendar类后被弃用了。而Calendar存在的问题为:
第三代日期类在JDK8加入
xxxxxxxxxx//1. 使用now()返回当前日期时间LocalDateTime ldt = LocalDateTime.now();System.out.println(ldt);//2. 使用DateTimeFormatter对象来进行格式化DateTimeFormatter d = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH小时mm分钟ss秒");String format = d.format(ldt);System.out.println(format);//3. Instant时间戳,类似于DateInstant now = Instant.now();Date date = Date.from(instant);//Instant->DateInstant instant = date.toInstant();//Date->Instantldt.getYear();ldt.getMonth();//英文的月ldt.getMonthValue();//数字的月ldt.getDayOfMonth();ldt.getHour();ldt.getMinute();ldt.getSecond();

在开发中选择什么集合实现类,主要取决于业务特点
先判断存储的类型:一组对象(单列)或一组键值对(双列)
一组对象:Collection接口
允许重复:List
不允许重复:Set
一组键值对:Map
Collection接口常用方法
Collection接口遍历元素方式1—Iterator(迭代器)
xxxxxxxxxxCollection col = new ArrayList();col.add(new Book("三国","罗贯中", 10.5));col.add(new Book("水壶","吴承恩", 12.5));col.add(new Book("红楼","曹雪芹", 4.5));//1. 先得到col对应的迭代器Iterator iterator = col.iterator();//2. 使用while循环遍历,快捷键为itit//hasNext:判断是否还有下一个元素while (iterator.hasNext()) { //next():1.指针下移 2.将下移以后的位置上的元素返回 Object next = iterator.next(); System.out.println(next);}//3. 当退出while循环后,iterator迭代器指向最后的元素iterator.next();//NoSuchElementException//4. 如果希望再次遍历,需要重置迭代器iterator = col.iterator();Collection接口遍历元素方式1—for循环增强
增强for在底层仍然是Iterator迭代器
快捷方式:
Ixxxxxxxxxxfor (Object book : col) { System.out.println(book);//输出和上面一模一样}基本介绍
List接口的常用方法
list.add(1, "hello");默认在索引为1的位置插入hellolist.addAll(1, list2);,在索引为1的位置插入list2中的所有元素list.set(1, "marry");,替换索引为1的位置的元素为marrylist.subList(int fromIndex, int toIndex)返回[fromIndex, toIndex)的子集合List接口的遍历方法
xxxxxxxxxxfor(int i = 0; i < list.size(); i++){ System.out.println(list.get(i));}ArrayList
注意事项
ArrayList底层结构和源码分析
transient Object[] elementData;//transient表示瞬间的、短暂的,表示该属性不会被序列化Vector
Vector注意事项
protected Object[] elementData;Vector底层结构和源码剖析
LinkedList
LinkedList注意事项
LinkedList底层实现了双向链表和双端队列特点
可以添加任意元素(元素可以重复),包括null
线程不安全,没有实现同步
改查的操作多选择ArrayList,增删的操作多选择LinkedList。一般使用ArrayList
Set接口基本介绍
Set接口常用方法和Collection一样
Set接口的遍历方式
同Collection的遍历方式
HashSet
说明
底层机制分析:add如何实现
HashSet扩容和转成红黑树机制
16*2=32,新的临界值是32*0.75=24,依次类推。LinkedHashSet
说明
注意事项
Map接口实现类的特点

解读
Entry<Map.Entry<k,v>>Map接口常用方法
Map接口遍历方法
Set keyset = hashMap.keySet();Collection values = hashMap.values();Set entrySet = hashMap.entrySet();xxxxxxxxxxHashMap hashMap = new HashMap();hashMap.put(1,"asl");hashMap.put(2,"lsgaf");hashMap.put(3,"sssl");//1. 先取出所有的key,通过key取出对应的valueSet keyset = hashMap.keySet();//(1)增强forfor (Object key : keyset) { System.out.println(key + "-" + hashMap.get(key));}//(2)iterator迭代器Iterator iterator = keyset.iterator();while (iterator.hasNext()) { Object key = iterator.next(); System.out.println(key + "-" + hashMap.get(key));}//2. 把所有的values取出Collection values = hashMap.values();//这里可以使用Collections使用的遍历方法//(1) 增强forfor (Object value : values) { System.out.println(value);}//(2) iterator迭代器Iterator iterator1 = values.iterator();while (iterator1.hasNext()) { Object value = iterator1.next(); System.out.println(value);}//3. 通过EntrySet来获取k-vSet entrySet = hashMap.entrySet();//(1) 增强forfor (Object entry : entrySet) { //将entry转成Map.Entry,向下转型 Map.Entry m = (Map.Entry) entry; System.out.println(m.getKey() + "-" + m.getValue());}//(2) iterator迭代器Iterator iterator2 = entrySet.iterator();while (iterator2.hasNext()) { Object entry = iterator2.next(); //System.out.println(entry.getClass());//HashMap$Node-实现->Map.Entry(getKey,getValue) //向下转型 Map.Entry Map.Entry m = (Map.Entry) entry; //System.out.println(m.getClass());//HashMap$Node,所谓万变不离其宗 System.out.println(m.getKey() + "-" + m.getValue());}说明
HashMap底层原理和扩容机制和上面的HashSet完全相同。区别是HashSet是相同key会无法加入,HashMap相同key会替换value
介绍
Hashtable底层和扩容机制
int newCapacity = (oldCapacity << 1) + 1Hashtable和HashMap对比
介绍
Properties类继承Hashtable类并实现了Map接口,使用k-v键值对保存数据
使用特点和hashtable类似
Properties可以用于从xxx.properties文件中加载数据到Properties类对象,并进行读取和修改。说明:xxx.properties文件通常作为配置文件
TreeSet
xxxxxxxxxxTreeSet treeSet = new TreeSet(new Comparator() { public int compare(Object o1, Object o2) { return ((String) o2).length() - ((String) o1).length();//比较长度 //return ((String) o2).compareTo((String) o1);//比较字符 }});treeSet.add("c");treeSet.add("cee");treeSet.add("agggg");treeSet.add("fff");//添加失败,因为已经有3个长度的key了System.out.println(treeSet);xxxxxxxxxxTreeMap treeMap = new TreeMap(new Comparator() { public int compare(Object o1, Object o2) { return ((String) o1).length() - ((String) o2).length(); //return ((String) o2).compareTo((String) o1); }});treeMap.put("a","琪亚娜");//第一次添加,把k-v封装到Entry对象,放入root,调用了compare方法了,检测是否为null会抛出异常treeMap.put("bb","芽衣");treeMap.put("ccc","布若妮亚");treeMap.put("asdf","草履虫");treeMap.put("kzlz","空之律者");//key=kzlz添加失败,因为存在4个长度的key,但value=“空之律者”会替换“草履虫”System.out.println(treeMap);Collection工具类介绍
排序操作
查找和替换
xxxxxxxxxxArrayList dest = new ArrayList();for(int i = 0; i < list.size(); i++){//为了完成一个完整的拷贝,需要先给dest赋值,大小和list.size()一样 dest.add("");}Collections.copy(dest, list);dest.addAll(list);//这种方式也能直接拷贝试分析HashSet和TreeSet分别如何实现去重的
泛型的好处
泛型说明
xxxxxxxxxx//声明interface 接口<T>{}class 类<k,v>{}//其中T,K,V不代表值,而是表示类型//任何字母都可以,常用T表示,是type的缩写//实例化List<String> strList = new ArrayList<>();Iterator<Customer> iterator = cunsomers.iterator();注意事项和细节
xxxxxxxxxxclass 类名<T,R...>{成员}注意细节
xxxxxxxxxxinterface 接口名<T,R...>{成员}注意细节
xxxxxxxxxx修饰符 <T,R...>返回类型 方法名(参数列表){}class Cat{ public void run(){}; public<T,R> void fly(T t, R r){};}class Fish<T,R>{ public void swim(){};//普通方法 public<U,M> void eat(U u, M m){};//泛型方法 public void hi(T t){};//修饰符后没有泛型的方法不是泛型方法,而是使用了泛型}注意细节
说明
List<Object> list = new ArrayList<String>();是不正确的JUnit
什么是线程
其他相关概念
继承Thread就是开启了一个子线程,所有线程执行完后,进程才会退出
start方法
xxxxxxxxxxStudent student = new Student();Thread thread = new Thread(student);thread.start();xxxxxxxxxxpublic class Runnable_ { public static void main(String[] args) { Student student = new Student(); ThreadProxy threadProxy = new ThreadProxy(student); threadProxy.start(); }}class Person{}class Student extends Person implements Runnable{ public void run() { System.out.println("学生学习中..."); }}class ThreadProxy implements Runnable{//极简地模拟了Thread内部结构 private Runnable target = null; public void run() { if(target != null){ target.run(); } } public ThreadProxy(Runnable target) { this.target = target; } public void start(){ start0(); } public void start0(){ run(); }}实现Runnable接口的方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制。建议使用Runnable
线程终止
常用方法1:
注意事项和细节
常用方法2:
用户线程和守护线程(Daemon)
setDaemon()),后开启线程start()xxxxxxxxxx//example:使用线程X2控制线程X1,可以使用守护线程,或者使用线程X2控制looppublic class Homework01 { public static void main(String[] args) { X1 x1 = new X1(); X2 x2 = new X2(); x1.setDaemon(true);//启动守护线程,X2输入Q退出时,X1就退出 x1.start(); x2.start(); }}class X1 extends Thread{ static boolean loop = true; public void run() { while(loop){ System.out.println((int)(Math.random() * 100 + 1)); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } /*public static void setLoop(boolean loop) { X1.loop = loop; }*/}class X2 extends Thread{ Scanner scanner = new Scanner(System.in); public void run() { while(true){ System.out.println("请输入Q退出"); char c = scanner.next().toUpperCase().charAt(0); if(c == 'Q'){ //X1.setLoop(false); break; } } }}七大线程状态
New:尚未启动的线程处于此状态
Runnable:在java虚拟机中执行的线程处于此状态
Blocked:被阻塞等待监视器锁定的线程处于此状态
Waiting:正在等待另一个线程执行特定动作的线程处于此状态
TimedWaiting:正在等待另一个线程执行动作达到指定等待时间的线程处于此状态
Teminated:已退出的线程处于此状态

线程同步机制
同步具体方法
xxxxxxxxxx//1.同步代码块synchronized(对象){//得到对象的锁,才能操作同步代码 //需要被同步的代码}//2.synchronized还可以放在方法声明中,表示整个方法为同步方法public synchronized void m(){ //需要被同步的代码}Thread.currentThread().getName()返回当前线程的名字基本介绍
注意事项和细节
同步方法如果没有使用static修饰:默认锁对象this,this对象锁是非公平锁
同步方法使用static修饰:默认所当前类.class
实现的落地步骤
基本介绍
释放锁的操作
不会释放锁的操作
文件流
常用的文件操作
xxxxxxxxxx//1. new File(String pathname),根据路径构建一个File对象public void Create01() throws IOException { String filePath = "e:\\news1.txt";//这里也可以使用"e:/news1.txt",但推荐前者 File file = new File(filePath); file.createNewFile();}//2. new File(File parent, String child),根据父目录文件+子路径构建public void Create02() throws IOException { File parentFile = new File("e:\\"); String fileName = "news2.txt"; File file = new File(parentFile, fileName); //这里的file对象,在java程序中只是一个对象 //只有执行了对象的createNewFile方法,才会真正的在磁盘创建该文件 file.createNewFile();}//3. new File(String parent, String child),根据父目录+子路径构建public void Create03() throws IOException { String parentPath = "e:\\"; String fileName = "news3.txt"; File file = new File(parentPath, fileName); file.createNewFile();}获取文件信息
目录操作和文件删除(目录又叫文件夹,可以当做一种特殊的文件)
java IO流原理
流的分类
IO流体系图

基本介绍
图解:2-5:节点流,6后:处理流

节点流和处理流的区别和联系
xxxxxxxxxx//1. Reader_抽象类,在抽象类中使用read方法统一管理public abstract class Reader_ { public abstract void read();}//2. FileReader_实现Reader_public class FileReader_ extends Reader_{ public void read(){ System.out.println("读取文件..."); }}//3. StringReader_实现Reader_public class StringReader_ extends Reader_ { public void read() { System.out.println("读取字符串..."); }}//4. BufferedReader_将实现了Reader_的类封装public class BufferedReader_ extends Reader_ { private Reader_ reader_; public BufferedReader_(Reader_ reader_) { this.reader_ = reader_; } public void read(){ reader_.read(); } public void read(int num){//在不改变原有方法的基础上扩展功能 for (int i = 0; i < num; i++) { reader_.read(); } }}//5. 测试public class Test{ public static void main(String[] args) {//对象的动态绑定机制 BufferedReader_ bufferedReader_ = new BufferedReader_(new FileReader_()); bufferedReader_.read(10); BufferedReader_ bufferedReader_1 = new BufferedReader_(new StringReader_()); bufferedReader_1.read(5); }}处理流的功能
标准输入流:System.in
public final static InputStream in = null标准输出流:Syetem.out
public final static PrintStream out = null
InputStreamReader和OutoutStreamWriter
xxxxxxxxxxpublic static void main(String[] args) throws IOException { String filePath = "e:\\hello.txt"; //把FileInputStream转成InputStreamReader InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk"); //把InputStreamReader转成BufferedReader,可以和上面合在一起写 BufferedReader br = new BufferedReader(isr); String s = null; while((s = br.readLine()) != null){ System.out.println(s); } br.close();}

可以看到PrintStream可以输入文件,字符串,字节流,PrintWriter可以放入文件,字符串,字节流,字符流
xxxxxxxxxx//只演示PrintStream,PrintWriter同理PrintStream out = System.out;//或是PrintStream out = new PrintStream(System.out);//默认情况下,PrintStream输出数据的位置是标准输出out.print("hello");//print底层使用的是write,所以可以直接调用write进行打印out.write("hello?".getBytes());out.close();//我们可以去修改打印流输出的位置,setOut调用了native属性的setOut0方法System.setOut(new PrintStream(filePath));System.out.println("hello");//这个时候不会打印在显示器,会打印在filePath位置

xxxxxxxxxxpublic void readFile() throws IOException { String filePath = "e:\\hello.txt"; byte[] buf = new byte[8];//一次性读取8个字节 int readLen = 0; FileInputStream fileInputStream = null; fileInputStream = new FileInputStream(filePath); while((readLen = fileInputStream.read(buf)) != -1){//如果返回-1,表示读取完毕 System.out.print(new String(buf, 0, readLen)); } fileInputStream.close();//关闭文件流,释放资源}xxxxxxxxxxpublic void writeFile() throws IOException { String filePath = "e:\\a.txt"; FileOutputStream fileOutputStream = null; //1. new FileOutputStream(filePath)创建方式,当写入内容时会覆盖掉原来的内容 //2. new FileOutputStream(filePath, true)创建方式,当写入内容时会追加到文件后面 fileOutputStream = new FileOutputStream(filePath); //写入一个字节 fileOutputStream.write('H'); //写入字符串 String str = "hello,world???"; //字符串->字节数组 fileOutputStream.write(str.getBytes()); //将len字节从偏移量off的指定字节数组写入此文件输入流 fileOutputStream.write(str.getBytes(), 1, 3);//ell fileOutputStream.close();}xxxxxxxxxxpublic static void main(String[] args) throws IOException { String srcfilePath = "e:\\hello.jpg"; String destfilePath = "e:\\ssss.jpg"; BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcfilePath)); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destfilePath)); byte[] buf = new byte[1024]; int readLen; while((readLen = bis.read(buf)) != -1){ bos.write(buf, 0, readLen); } bis.close(); bos.close();}处理流(此处也可叫对象流):ObjectInputStream和ObjectOutputStream
序列化和反序列化
序列化:保存数据时,保存数据的值和数据类型,ObjectOutputStream提供了此功能
反序列化:恢复数据时,恢复数据的值和数据类型,ObjectInputStream提供了此功能
需要让某个类的对象支持序列化机制,则必须让其类是可序列化的,必须实现如下两个接口之一:
细节说明
xxxxxxxxxx//1. ObjectOutputStream public static void main(String[] args) throws IOException { //序列化后,文件是按照他的格式来保存的 String filePath = "e:\\data.dat"; ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath)); oos.writeInt(100);//int->Interget oos.writeBoolean(true); oos.writeChar('a');//char->character oos.writeDouble(9.5);//double->Double oos.writeUTF("薪炎之律者");//String本身实现了Serializable oos.writeObject(new Dog("旺财", 3)); oos.close(); }public class Dog implements Serializable { private String name; private int age; private static final long serialVersionUID = 1L;//序列化的版本号,可以提高兼容性 public Dog(String name, int age) { this.name = name; this.age = age; } //Getter和Setter方法 //重写toString}//2. ObjectInputStreampublic static void main(String[] args) throws IOException, ClassNotFoundException { String filePath = "e:\\data.dat"; ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath)); //读取(反序列化)的顺序需要和保存数据(序列化)的顺序一致,否则会出现异常 System.out.println(ois.readInt()); System.out.println(ois.readBoolean()); System.out.println(ois.readChar()); System.out.println(ois.readDouble()); System.out.println(ois.readUTF()); Object dog = ois.readObject(); System.out.println(dog.getClass()); System.out.println(dog); //1. 如果需要调用Dog方法,需要向下转型 //2. 需要我们将Dog类的定义,拷贝到可以引用的地方 Dog dog1 = (Dog) dog; System.out.println(dog1.getName()); ois.close();}FileReader
常用方法
相关API
xxxxxxxxxxpublic void FileReader_() throws IOException { String filePath = "e:\\story.txt"; FileReader fileReader = null; char[] chars = new char[8]; int readLen = 0; fileReader = new FileReader(filePath); while((readLen = fileReader.read(chars)) != -1){ System.out.print(new String(chars, 0, readLen)); } fileReader.close();}FileWriter
常用方法
相关API
注意:FileWriter使用后,必须关闭(close)或刷新(flush),否则写不到指定的文件
BufferedReader
xxxxxxxxxxpublic static void main(String[] args) throws IOException { String filePath = "e:\\story.txt"; BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath)); String line;//按行读取效率高 while((line = bufferedReader.readLine()) != null){//返回null时读取完毕 System.out.println(line); } bufferedReader.close();}xxxxxxxxxxpublic static void main(String[] args) throws IOException { String filePath = "e:\\hello.txt"; BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath, true));//追加 bufferedWriter.write("asleer,hello1"); bufferedWriter.newLine();//插入一个和系统相关的换行 bufferedWriter.write("asleer,hello2"); bufferedWriter.newLine(); bufferedWriter.write("asleer,hello3"); bufferedWriter.newLine(); bufferedWriter.close();}基本介绍
Properties方法
读取文件
xxxxxxxxxxpublic static void main(String[] args) throws IOException { //1. 创建Properties对象 Properties properties = new Properties(); //2. 加载指定配置文件 properties.load(new FileReader("test_project01\\src\\com\\chapter2_8\\Properties_\\mysql.properties")); //3. 把k-v显示在控制台 properties.list(System.out); //4. 根据key获取对应的值 String user = properties.getProperty("user"); System.out.println(user);}xxxxxxxxxxpublic static void main(String[] args) throws IOException { Properties properties = new Properties(); properties.setProperty("charset", "utf8"); properties.setProperty("user", "老王");//会存储为unicode码 properties.setProperty("pwd", "369369"); properties.store(new FileOutputStream("test_project01\\src\\com\\chapter2_8\\Properties_\\mysql2.properties"), null); System.out.println("配置成功");}
域名
www.baidu.com端口号



TCP协议:传输控制协议
UDP协议:用户数据协议
相关方法
基本介绍


xxxxxxxxxxpublic class SocketTCP01Server { public static void main(String[] args) throws IOException { //1. 在本机9999端口监听,等待连接,要求在本机没有其他服务在监听9999 // 这个ServerSocket可以通过accept()返回多个Socket[多个客户端连接服务器的并发] ServerSocket serverSocket = new ServerSocket(9999); System.out.println("服务端在9999端口监听,等待连接..."); //2. 当没有客户端连接9999端口时,程序会阻塞,等待连接 // 如果有用户连接,则会返回Socket对象,程序继续 Socket socket = serverSocket.accept(); System.out.println("服务端 socket = " + socket.getClass()); //3. 通过socket.getInputStream读取客户端写入到数据通道的数据 InputStream inputStream = socket.getInputStream(); //4. IO读取 byte[] buf = new byte[1024]; int readLen; while((readLen = inputStream.read(buf)) != -1){ System.out.println(new String(buf, 0, readLen)); } //5. 关闭流和socket inputStream.close(); socket.close(); serverSocket.close(); }}public class SocketTCP01Client { public static void main(String[] args) throws IOException { //1. 连接服务端 // 连接本机的9999端口,如果连接成功,返回Socket对象 Socket socket = new Socket(InetAddress.getLocalHost(), 9999); System.out.println("客户端 socket = " + socket.getClass()); //2. 连接上后,生成Socket对象,通过socket.fetOutputStream // 得到和socket对象关联的输出流对象 OutputStream outputStream = socket.getOutputStream(); //3. 通过输出流,写入数据到数据通道 outputStream.write("hello, server".getBytes()); //4. 关闭流对象和socket outputStream.close(); socket.close(); System.out.println("客户端退出..."); }}案例2:客户端和服务端互发消息
socket.shutdownOutput()
write.newLine()作为结束标记,但要求读取时使用readLine()来读取。但推荐使用socket.shutdownOutput()
xxxxxxxxxxpublic class SocketTCP02Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(9999); Socket socket = serverSocket.accept(); BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line = null; while((line = br.readLine()) != null){//这里传入多句时,没有shutdownOutout会走不动 System.out.println(line); } BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bw.write("hello,clinet"); bw.newLine(); bw.flush(); socket.shutdownOutput(); bw.close(); br.close(); socket.close(); serverSocket.close(); }}public class SocketTCP02Client { public static void main(String[] args) throws IOException { Socket socket = new Socket(InetAddress.getLocalHost(), 9999); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bw.write("hello,server"); bw.newLine(); bw.flush(); socket.shutdownOutput(); BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String s = br.readLine(); System.out.println(s); br.close(); bw.close(); socket.close(); }}netstat -an:可以查看当前主机网络情况,包括端口监听情况和网络连接情况
netstat -an|more:可以分页显示
netstat -anb:可以显示地址对应的程序
要求在dos控制台执行,win+r
说明
当客户端连接到服务端后,实际上客户端也是通过一个端口和服务端通讯的,这个端口是TCP/IP来分配的,是随机的
基本介绍
基本流程

xxxxxxxxxxpublic class UDPReceiverA { public static void main(String[] args) throws IOException { //1. 创建一个DatagramSocket对象,准备在9999端口接受数据 DatagramSocket socket = new DatagramSocket(9999); //2. 构建一个DatagramPacket对象,准备接受数据 // 一个数据报最大64K byte[] buf = new byte[1024]; DatagramPacket packet = new DatagramPacket(buf, buf.length); //3. 调用接受方法,将通过网络传输的DatagramPacket对象填充到packet对象 System.out.println("接收端A等待接受数据..."); socket.receive(packet); //4. 可以把packet进行拆包,取出数据并显示 int length = packet.getLength();//实际接受到的数据字节长度 byte[] data = packet.getData();//接受到的数据 String s = new String(data, 0, length); System.out.println(s); //5. 关闭资源 socket.close(); System.out.println("A端退出"); }}public class UDPSenderB { public static void main(String[] args) throws IOException { //1. 创建DatagramSocket对象,准备在9998端口接受数据 DatagramSocket socket = new DatagramSocket(9998); //2. 将需要发送的数据封装到DatagramPacket对象 byte[] data = "hello 明天吃火锅".getBytes(); DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("172.25.252.138"), 9999); socket.send(packet); socket.close(); System.out.println("B端退出"); }}xxxxxxxxxxpublic class SocketTCP03Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(8888); Socket socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); byte[] buf = new byte[1024]; int readLen = 0; FileOutputStream fileOutputStream = new FileOutputStream("picture.jpg"); while((readLen = inputStream.read(buf)) != -1){ fileOutputStream.write(buf, 0, readLen); } OutputStream outputStream = socket.getOutputStream(); outputStream.write("收到消息".getBytes()); socket.shutdownOutput(); outputStream.close(); fileOutputStream.close(); inputStream.close(); socket.close(); serverSocket.close(); }}public class SocketTCP03Client { public static void main(String[] args) throws IOException { Socket socket = new Socket(InetAddress.getLocalHost(), 8888); String filePath = "e:\\明日方舟图.jpg"; FileInputStream fileInputStream = new FileInputStream(filePath); byte[] buf = new byte[1024]; int readLen = 0; OutputStream outputStream = socket.getOutputStream(); while((readLen = fileInputStream.read(buf)) != -1){ outputStream.write(buf, 0, readLen); } socket.shutdownOutput(); InputStream inputStream = socket.getInputStream(); byte[] bytes = new byte[1024]; readLen = 0; while((readLen = inputStream.read(bytes)) != -1){ System.out.println(new String(bytes, 0, readLen)); } inputStream.close(); outputStream.close(); fileInputStream.close(); socket.close(); }}xxxxxxxxxxpublic class Homework03Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(9999); System.out.println("9999正在监听..."); Socket socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); byte[] buf = new byte[1024]; int readLen; String s = ""; while((readLen = inputStream.read(buf)) != -1){ s = new String(buf, 0, readLen); } System.out.println(s); if(s.equals("齐天")||s.equals("魔女之旅")){ s += ".mp3"; }else{ s = "齐天.mp3"; } String filePath = "src\\chapter3_1\\socket\\homework\\" + s; FileInputStream fileInputStream = new FileInputStream(filePath); OutputStream outputStream = socket.getOutputStream(); byte[] music = new byte[1024]; while((readLen = fileInputStream.read(music)) != -1){ outputStream.write(music, 0, readLen); } socket.shutdownOutput(); outputStream.close(); inputStream.close(); socket.close(); serverSocket.close(); System.out.println("程序结束退出"); }}public class Homework03Client { public static void main(String[] args) throws IOException { Socket socket = new Socket(InetAddress.getLocalHost(), 9999); OutputStream outputStream = socket.getOutputStream(); Scanner scanner = new Scanner(System.in); System.out.println("请输入歌曲名"); String s = scanner.next(); outputStream.write(s.getBytes()); socket.shutdownOutput(); byte[] music = new byte[1024]; int readLen; InputStream inputStream = socket.getInputStream(); FileOutputStream fileOutputStream = new FileOutputStream("e:\\" + s + ".mp3"); while((readLen = inputStream.read(music)) != -1){ fileOutputStream.write(music, 0, readLen); } fileOutputStream.close(); inputStream.close(); outputStream.close(); socket.close(); System.out.println("程序结束退出"); }}
反射的优点和缺点
反射调用优化——关闭访问检查

基本介绍
xxxxxxxxxxString classAllPath = "chapter3_2.Car";//1. 获取到Car类对应的Class对象,<?>表示不确定的java类型Class<?> cls = Class.forName(classAllPath);//2. 输出clsSystem.out.println(cls);//显示cls对象是哪个类的Class对象 class chapter3_2.CarSystem.out.println(cls.getClass());//输出运行类型 class java.lang.Class//3. 得到包名System.out.println(cls.getPackage().getName());//chapter3_2//4. 得到全类名System.out.println(cls.getName());//chapter3_2.Car//5. 通过cls创建对象实例Car car = (Car)cls.getDeclaredConstructor().newInstance();System.out.println(car);//car.toString//6. 通过反射获取属性brandField brand = cls.getField("brand");//car.brand不能用,因为car里面没有getter方法,只能使用反射得到System.out.println(brand.get(car));//宝马//7. 通过反射给属性赋值brand.set(car, "奔驰");//真正的Car类里brand是没变的,变得是car对象的brandSystem.out.println(brand.get(car));//奔驰//8. 得到所有的属性Field[] fields = cls.getFields();for (Field f : fields) { System.out.println(f.getName());//获取字段名称 System.out.println(f.get(car));}Class.forName()
Class<?> aclass = Class.forName("chapter3_2.Car");类名.class
Class<Car> carClass = Car.class;对象名.getClass()
Class<? extends Car> aClass = car.getClass();类加载器
实例:
xxxxxxxxxxClassLoader classLoader = car.getClass().getClassLoader();Class<?> aClass1 = classLoader.loadClass("chapter3_2.Car");基本数据类型
Class<Integer> integerClass = int.class;基本数据类型对应的包装类
Class<Character> type = Character.TYPE;如下成员有Class对象
基本说明
类加载时机

