重拾JavaSE学习笔记

  • 1、常用DOS命令
  • 2、了解Java
    • 2.1 、java特性
    • 2.2、JDK 、JRE、JVM
    • 2.3、java的加载和执行
  • 3、开发环境搭建
    • 3.1、安装jdk
    • 3.2、配置环境变量
  • 4、JavaSE
    • 4.1、开发准备
      • 4.1.1、注释
      • 4.1.2、标识符
      • 4.1.3、关键字
      • 4.1.4、main方法 实现 hello world
    • 4.2、JavaSE基础知识点
      • 4.2.1、变量
      • 4.2.2 、数据类型
      • 4.2.3 、运算符
        • 4.2.3.1、算术运算符
        • 4.2.3.2、赋值运算符
        • 4.2.3.3、比较运算符
        • 4.2.3.4、逻辑运算符
        • 4.2.3.5、三元运算符
      • 4.2.4、选择结构(if 、switch)
      • 4.2.5、循环结构(for、while、do - while)
      • 4.2.6 、方法
      • 4.2.7 、数组
      • 4.2.8、Java内存
      • 4.2.9、Scanner
      • 4.2.10、Random
      • 4.2.11、String
      • 4.2.12、Arrays数组工具类
      • 4.2.13、Math类
      • 4.2.14、 Object 类(根类)
      • 4.2.15 、Date类
      • 4.2.16、 DateFormat 类
      • 4.2.17、 Calendar 类
      • 4.2.18 、System 类
      • 4.2.19 、StringBuilder 类
    • 4.3、面向对象
      • 4.3.1 、面向对象思想
      • 4.3.2 、类和对象
      • 4.3.3、 面对对象的三大特征-封装性
      • 4.3.4、静态Static 关键字
      • 4.3.5、继承
      • 4.3.6、抽象
      • 4.3.7、接口
      • 4.3.8、多态(对象的多态性)
      • 4.3.9、 instanceof 关键字
      • 4.3.10、 final关键字
      • 4.3.11 、四种权限修饰符
      • 4.3.12 、内部类
    • 4.4、Java进阶知识点
      • 4.4.1、ArrayList
      • 4.4.2、包装类
      • 4.4.4、 数据结构(简单了解)
      • 4.4.5 、Collection集合
        • 4.4.5.1、List集合
        • 4.4.5.2 、set集合
        • 4.4.5.3 、泛型
        • 4.4.5.4 、迭代器(Iterator)
        • 4.4.5.5 、增强for循环
      • 4.4.6 、Map集合
      • 4.4.7、JDK9 对集合(List、Set、Map)的新特性
      • 4.4.8、调试、异常
        • 4.4.8.1、Debug调试
        • 4.4.8.2、异常
        • 4.4.8.3 、异常处理
        • 4.4.8.4、 异常处理注意事项
        • 4.4.8.5 、自定义异常类
      • 4.4.9、线程
        • 4.4.9.1、线程介绍
        • 4.4.9.2、主线程
        • 4.4.9.3 、多线程
          • 4.4.9.3.1、创建多线程的第一种方式
          • 4.4.9.3.2、创建多线程的第二种方式
        • 4.4.9.4 、匿名内部类方法实现线程创建
        • 4.4.9.5 、线程安全问题
          • 4.4.9.5.1、解决线程问题方法一[同步技术-同步代码块]
          • 4.4.9.5.2、解决线程问题方法二 [同步技术-同步方法]
          • 4.4.9.5.3、解决线程问题方法三 [同步技术-Lock锁]
        • 4.4.9.6 、线程状态
        • 4.4.9.7 、线程池
      • 4.4.10、Lambda表达式
      • 4.4.11、File类
      • 4.4.12、递归
      • 4.4.13、IO流
        • 4.4.13.1、字节流
          • 4.4.13.1.1、字节输出流 (OutputStream 抽象类是所有字节输出流的超类)
          • 4.4.13.1.2、字节输入流 (InputStream 抽象类是所有字节输入流的超类)
          • 4.4.13.1.3、字节缓冲输入流(BufferedInputStream )
          • 4.4.13.1.4、字节缓冲输出流(BufferedOutputStream )
        • 4.4.13.2、字符流
          • 4.4.13.2.1、字符输入流 (Reader抽象类是所有字符输入流的超类)
          • 4.4.13.2.2、字符输出流 (Writer抽象类是所有字符输出流的超类)
          • 4.4.13.2.3、字符缓冲输入流(BufferedReader)
          • 4.4.13.2.4、字符缓冲输出流(BufferedWriter)
        • 4.4.13.3、缓冲流原理
        • 4.4.13.4、转换流
          • 4.4.13.4.1、字符编码、字符集
          • 4.4.13.4.2、OutputStreamWriter
          • 4.4.13.4.3、InputStreamReader
        • 4.4.13.4、序列化流
          • 4.4.13.4.1、对象序列化流 (ObjectOutputStream)
          • 4.4.13.4.2、对象反序列化流 (ObjectInputStream)
          • 4.4.13.4.3、解决修该成员类 序列号变化导致反序列化失败(InvalidClassException)
        • 4.4.13.5、JDK7、JDK9 流相关新特性
        • 4.4.13.6、Properties配置文件
      • 4.4.14、网络编程
        • 4.4.14.1、网络编程基础知识点
          • 4.4.14.1.1、软件结构
          • 4.4.14.1.2、网络通信协议
          • 4.4.14.1.3、协议分类
          • 4.4.14.1.4、网络编程三要素
        • 4.4.14.2、TCP通信
          • 4.4.14.2.1、TCP通信客户端
          • 4.4.14.2.2、TCP通信服务端
        • 4.4.14.2、综合案例 文件上传
        • 4.4.14.3、BS结构TCP通信(扩展)
      • 4.4.15、函数式接口
      • 4.4.16、Stream流
        • 4.4.16.1、获取流
        • 4.4.16.2、常用方法
      • 4.4.17、方法引用
      • 4.4.18、Junit单元测试
      • 4.4.19、反射
      • 4.4.20、注解

1、常用DOS命令

1、打开DOS命令窗口
win键+r 打开运行窗口
输入cmd
2、创建文件夹 make directory
mkdir 文件夹名
地址为当前执行地址
3、DOS命令窗口复制内容
win7 :右键-》标记-》选中要复制的内容-》点击右键-》复制到剪贴板
win10:左键选中-》右键单击-》复制到剪贴板
4、切换盘符
直接输入盘符
c: -》回车
e: -》回车
5、切换目录
有盘符的是绝对路径
cd (change directory)
cd -》空格+绝对路径
cd -》空格+相对路劲
cd .当前目录
cd … 回到上级目录
cd / 回到根目录
6、查看当前目录下的内容
dir
7、清屏
cls
8、退出dos
exit
9、删除文件
del 文件名
扩展例:del *.class 删除当前目录下的所有.class后缀的文件
10、删除文件夹
rd 文件夹名
11、查看本机的ip地址
ipconfig
ipconfig -all 查看更详细的信息
12 、查看两台机是否能够通信
ping ip地址
ping ip地址 -t 持续ping测试网络稳定性
ctrl +c 退出持续命令

2、了解Java

2.1 、java特性

java 语言的特性
1、简单性 相对于C++
在java语言中真正操作内存的是jvm(java 虚拟机)
所有的java程序都是运行在jvm中,jvm执行过程中再去操作内存

java语言底层是c++,所以jvm是用c++语音写好的一个虚拟电脑。
安装jdk之后 jvm代表安装好了
java 是面对对象的

2、健壮性 相对于c++
java 有自动垃圾回收机制 GC机制
java不容易导致内存的泄露
jvm负责调度GC机制

缺点,不能及时释放内存,有限定值自动释放

java 完全/完美支持多线程并发

3、可以移植性/跨平台

2.2、JDK 、JRE、JVM

  • JDK:java工具箱
  • JRE:java运行环境
  • JVM:java虚拟机

jdk包括jre ,jre 包括jvm
jvm是不能独立安装的
jre和jdk都可以独立安装

2.3、java的加载和执行

java程序员直接编写的java代码是无法执行被jvm识别的。需要进行编译。 普通文本编译成字节码


*网上资源截图

3、开发环境搭建

3.1、安装jdk

https://www.oracle.com/cn/index.html
甲骨文官网自行下载

选jiava ->jdk->Jdkdownload

选择对应系统的版本,安装即可。

3.2、配置环境变量

Path
方法1
计算机-》属性-》高级系统设置-》环境变量-》系统环境变量-》找到path 添加jdk安装路劲的bin目录路径
D:\Program Files\Java\jdk1.8.0_131\bin;
注意,每个配置之间以;分割开
方法2
计算机-》属性-》高级系统设置-》环境变量-》系统环境变量-》
新建系统变量 JAVA_HOME
D:\Program Files\Java\jdk1.8.0_131
找到Path
%JAVA_HOME%\bin;
印象中Tomcat 需要新建JAVA_HOME 用于方法2方式配置jre
新的tomcat 好像不配置也木有问题

classpath 给类加载器指定路劲
.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;

4、JavaSE

4.1、开发准备

4.1.1、注释

单行注释
//

多行注释
/* 内容
内容
*/

javadoc注释 java 可识别,可以提取注释的内容
/**
*
*
*/
javadoc -d 文件名 名字.java 提取某个java文件中信息的存放到设定的文件夹

// 良好的注释习惯很重要

4.1.2、标识符

自己有权利命名的单词都是标识符
标识符可标识
类名、方法名、变量名、接口名、常量名 等等

标识符命名规则:语法机制,必须遵守
规则1、标识符只能右数字、字符(包括中文)、下划线、美元符号组成
规则2、标识符不能以数字开头
规则3、标识符之间不能有空格
规则4、关键字 public 、 static 、void、class 等 不能作为标识符
规则5、严格区分大小写,字符一样大小写不一样会编译第一个

标识符命名规范:
规范1、命名要见名知意
规范2、驼峰(一高一低)区分、分割单词如: MyDemo
规范3、类名、接口名 首字母大写,后面每个单词首字母大写
规范4、变量名、方法名 首字母小写,后面每个单词首字母大写
规范5、常量名 全部大写,单词见_ (下划线)衔接

4.1.3、关键字

注意 java 中关键字全部都是小写
开发工具中蓝色字符

4.1.4、main方法 实现 hello world

public class Demo1{//入口,一个类只有一个入口public static void main(String [] args){system.out.println("hello world!!!");}
}


扩展:
类可以没有public ,但是如果有的话,代码中类名必须与保存的文件名一致,否则报错

hello world 一般用来检测环境配置是否正常

4.2、JavaSE基础知识点

4.2.1、变量

字面量
程序中的数据叫做字面量
字面量可以分成很多种类
整数型字面量:1、2、3、4
浮点型字面量:1.2、1.3
布尔型字面量:false 、true

变量
变量是内存中存储数据的最基本单元
变量必须先声明再赋值才可以访问
变量声明同一个域内不能重复(和类型没有关系,不能同名)
方法内局部变量
方法外 类内 成员变量
符合java 就近原则

变量声明
数据类型 变量名
如: int num;

变量赋值
num=5;

 public class Demo1{//成员变量 int i=100;public static void main(String [] args){//声明局部变量int age;//变量赋值age=1;System.out.println(age);//变量再次赋值age=3;System.out.println(age);}
}


-encoding utf-8 解决中文无法被识别的问题

扩充:根据不同的数据类型 jvm分配不同大小的空间

4.2.2 、数据类型

数据类型两种
第一种:基本数据类型
基础数据类型又可以划分4大类8小钟
第一类:整数型
byte、short、int 、long
第二类:浮点型
float、double
第三类:布尔型
boolen
第四类:字符型
char

第二种:引用数据类型
除了基本数据类型,其他都是引用数据类型,比如string

补充:1个字节=8个bit

类型 占用字节数量(byte)
byte 1
short 2
int 4
long 8
float 4
double 8
boolen 1
char 2

数据类型转换
自动类型类型抓换(隐式)
1、特点:无需进行处理,自动完成
2、规则:数据范围从小到大
强制类型转换(显式)
注意:强转要注意溢出,不要超出小的那个类型的取值范围

 public class Demo1{public static void main(String [] args){//int ->long 符合自动转换原则。自动类型转换long num1=100;System.out.println(num1);//float=>double 符合double mum2=2.5F;System.out.println(num2);//long -》int  大到小,需要强转//int num3=100L;   int num3=(int)100L;System.out.println(num3);//long强转int  数据溢出int num4=(int)6000000000L;System.out.println(num4);                  }
}

4.2.3 、运算符

4.2.3.1、算术运算符

运算符:进行特定操作的符号
四则运算
加:+
减:-
乘:*
除:/
取模(余数):%
1、两个常量之间可以进行数学运算
2、两个变量之间也可以进行数学运算
3、常量和变量之间也可以混合使用
4、只有对于整数的除法来说,取模运算才有意义
5、运算中有不同类型的数据,那么结果将会是数据类型范围大类型

+的三种用法
1、对于数值来说,就是加法
2、对于字符char类型来说,在计算前,char会提升成为int再计算 。char 对照ASCII Unicode
3、对于String来说,加号代表连接操作,结果会变成字符串例如:“hello”+10 ===>“hello10”

自增运算符++、自减运算符–
1、在单独使用的时候,前++ 后++ 效果一样 都是加1
2、混合使用,例如 赋值混合、打印操作混合等
A:前++ 变量马上+1
B:后++ 使用变量值,再+1
- -也是如此。

 public class Demo1{public static void main(String [] args){int num1=100;//单独使用后加num1++;System.out.println(num1);//101//单独使用前加++num1;System.out.println(num1);//102//混合使用 先加加System.out.println(++num1);//103//混合使用后加加System.out.println(num1++);//103System.out.println(num1++);//104}
}

4.2.3.2、赋值运算符

基本赋值运算符
= 代表将右侧的值交给左侧的变量

复合赋值运算符

复合运算符 例子 相当于
+= a+=3 a=a=3
-= a-=3 a=a-3
*= a*=3 a=a*3
/= a/=3 a=a/3
%= a%=3 a=a%3

注意
1、只有变量才能使用赋值运算符。常量不能进行赋值 例如50=30
2、复合运算符中 byte会进行是强制类型转换。例如:

4.2.3.3、比较运算符

比较运算符 说明
> 大于
< 小于
>= 大于等于
<= 小于等于
= 等于
!= 不等于

注意:
1,运算结果是boolen
2、运算只能两两比较,不能a>b>c

4.2.3.4、逻辑运算符

逻辑运算符 符号 说明
与(并且) && 全是true ,才是true,否则就是false
或(或者) || 至少一个true ,就是true。全是false 才是false
非(取反) ! true、false 取反

4.2.3.5、三元运算符

一元:只需要1个数据就可以进行操作。例如:取反、自增、自减
二元:只需要2个数据就可以进行操。例如:加法、赋值
三元:需要3个数据进行操作。

格式
数据类型 变量A= 条件判断 B?表达式C:表达式D;
条件B=true , A=C
条件B=false, A=D

注意
1、注意C、D 符号变量A的数据类型
2、三元运算的结果必须被使用

4.2.4、选择结构(if 、switch)

if

  public class Demo1{public static void main(String [] args){int num=100;//单if语句if(num>99){System.out.println("大于99成立,执行");}//标准if语句if(num>99){System.out.println("大于成立,执行");}else{System.out.println("小于等于99,执行");}zhiXing(90);zhiXing(102);zhiXing(101);}public static void zhiXing(int num1){//复合if语句if(num1>101){System.out.println("大于101成立,执行");}else if(num1<101){System.out.println("小于101成立,执行");}else{System.out.println("等于100成立,执行");}}
}


switch

 public class Demo1{public static void main(String [] args){zhiXing(1);zhiXing(2);zhiXing(3);zhiXing(4);}public static void zhiXing(int num1){switch(num1){case 1:System.out.println("等于1 执行");break; //break 退出结束switchcase 2:System.out.println("等于2 执行");break;case 3:System.out.println("等于3 执行");break;       default:System.out.println("所有条件都没有满足,执行");break;}}
}


注意:
1、case后面的数值不能重复
2、case后面的数值类型
byte 、short、 char 、int 、String、\enum
3、case整体 顺序不用固定,只要保持格式就行

4.2.5、循环结构(for、while、do - while)

for

 public class Demo1{public static void main(String [] args){for(int i=5;i!=0;i--){//1、初始化,一开始直接执行一次带入值5//2、当i!=0 成立时 循环执行继续,不成立退出结束循环//3、执行System.out.println(i);//4、步进语句i--,每次循环结束都要执行一次i--//循环执行2、3、4 //break  结束循环 //continue 跳出当次循环,不执行2、3 直接执行4/*if(i==3){break;}*//*if(i==3){continue;}*/System.out.println(i);}}}


while

 public class Demo1{public static void main(String [] args){int i=5;while(i!=0){//1、初始化,一开始直接执行一次,带入值5//2、当i!=0 成立时 循环执行继续,不成立退出结束循环//3、执行System.out.println(i);//4、步进语句,每次循环结束都要执行一次i--//循环执行2、3、4//break  结束循环 /*if(i==3){break;}*/System.out.println(i);i--;}}}


do -while

 public class Demo1{public static void main(String [] args){int i=5;do{//1、初始化,一开始直接执行一次 //System.out.println(i);//i--;//不管i!=0是否成立,至少会执行1次//2、当i!=0 成立时 循环继续,不成立退出结束循环//3、执行System.out.println(i);//4、步进语句,每次循环结束都要执行一次i--//循环执行2、3、4//break  结束循环 /*if(i==3){break;}*/System.out.println(i);i--;}while(i!=0);}}


注意:步进和条件要注意逻辑,逻辑不通会死循环

4.2.6 、方法

格式
修饰符 返回值类型 方法名(参数名称,参数名称,…){
方法体
return 返回值
}
方法分类
可分为 有参、无参
有返回值,无返回值

方法重载
public int sum(int a,int b){}
public int sum(int a,int b,int c){}

可变参数
jdk1.5+
使用前提,当方法的参数列表数据类型确定,但是参数的个数不确定,就可以使用可变参数

修饰符 返回值类型 方法名(确定的数据类型…参数名称){
方法体
return 返回值
}
参数个数(0-n)取决于方法调用传参调用

4.2.7 、数组

数组的概念
是一种容器,可以同时存放多个数据值

数组的特点
1、数组是一种引用数据类型
2、数组中的数值类型必须一致
3、数组长度在程序运行期间不可改变

数组的初始化
在内存当中创建一个数组,并向其中赋予一些默认值

两种常见的数组初始化方式
1、动态初始化(指定长度)
数据类型 [] 数组名字=new 数据类型(数组长度)
2、静态初始化(指定内容)
数据类型 [] 数组名字=new 数据类型[]{数值1,数值2,数值3}
数据类型 [] 数组名字={数值1,数值2,数值3}

注意事项:
1、静态初始化没有直接指定长度,但是依然会自动算的到产股
2、动态、静态初始化标准格式可以分为两个步骤
3、静态简略初始化不可拆分两个步骤

访问数组元素
数组名[索引]
索引是一个int 类型。代表与元素编号
注意,索引从0才开始,到数组长度-1 为止

如果动态数组未赋值。
int 类型默认0
浮点0.0
字符’\u000’
引用类型 null
扩展: 静态数组在内存也是经过默认值才读取到{}中的数据值

数组元素赋值
数组名[索引]=数值;

数组长度
数组名.length

package com.myStudy.demo1;public class Demo1 {public static void main(String[] args) {//静态数组简化初始化int [] array1= {7,6,4,5,1,2,3};    //打印数组内存地址System.out.println(array1);       //访问数组元素System.out.println(array1[0]);//7       //数组长度System.out.println(array1.length); //7    //冒泡for (int i = 0; i < array1.length-1; i++) {for (int j = 0; j <array1.length-1-i; j++) {//-i 减少循环次数。 i代表已经排序好的索引个数。if (array1[j]>array1[j+1]) {int max=array1[j];array1[j]=array1[j+1];array1[j+1]=max;     }}}//输出冒泡结果for (int i = 0; i < array1.length; i++) {System.out.println(array1[i]);}//打印溢出的索引元素System.out.println(array1[8]);//报错,不存在,ArrayIndexOutOfBoundsExcption 数组索引越界异常     //静态数组标准初始化int [] array11=new int[] {1,3,5,7,2};       //动态数组标准初始化int [] array2=new int[4];       //动态拆分int [] array3;array3=new int [4];        //静态拆分int [] array4;array4=new int[] {1,2,3};}}
数组参数、数组返回值(返回的是数组地址)

4.2.8、Java内存

Java内存需要划分成为5个部分
1、栈(Stack):存放的都是方法中的局部变量。方法的运行一定要在栈当中。
   局部变量:方法的参数,或者是方法内部的变量。
   作用域:一但超出作用域,立刻从栈内消失
2、堆(Heap):凡是new出来的 都在堆中。堆内存里面的东西都是一个地址值(16进制)。堆内的数据都有默认自规则:
   int 类型默认:0
   浮点:0.0
   字符’:\u000’
   boolen::alse
   引用类型 :null
3、方法区(Method Ares):存储class相关信息,包含方法的信息
4、本地方法栈(Native Method Stack):与操作系统相关
5、寄存器(Pc Register):与cpu相关

一个数组的内存图

4.2.9、Scanner

Java Api Scanner 类的功能,可以实现键盘输入数据到程序当中。

package com.myStudy.demo1;//导包
import java.util.Scanner;public class Demo2 {public static void main(String [] args) {//创建//System.in 代表从键盘进行输入Scanner scan = new  Scanner(System.in);//获取键盘输入的int数字int result1 =scan.nextInt();System.out.println("输入的第一个数字是"+result1);//获取键盘输入的int数字int result2 =scan.nextInt();System.out.println("输入的第二个数字是"+result2);System.out.println("第一和第二个数字求和结果"+(result1+result2));//获取键盘输入的int数字int result3 =scan.nextInt();System.out.println("输入的第三个数字是"+result3);int temp=result1>result2?result1:result2;int max=temp>result3?temp:result3;System.out.println("输入的三个数字最大的是"+max);}
}

4.2.10、Random

Java API Random类 用来生成随机数字。

package com.myStudy.demo1;
//导包
import java.util.Random;
import java.util.Scanner;
/*猜3个骰子总点数*/
public class Demo2 {public static void main(String [] args) {//创建Random ran = new Random();Scanner scan =new Scanner(System.in);
//      //获取随机数字
//      int result1 =ran.nextInt();
//      System.out.println("随机数是"+result1);while(true) {//参数17 限定范围,随机0-17 之间的数字int result2=ran.nextInt(17)+1;System.out.println("请输入您猜的数字");int result3=scan.nextInt();if (result2==result3) {System.out.println("您猜对了");break;}else  {System.out.println("猜错了,再玩一次");}}System.out.println("游戏结束");}
}

4.2.11、String

程序中双引号字符串都是String类的对象。
字符串的特点
1、字符串的内容用不可变。
2、正因为字符串不可改变,所以字符串是可以共享使用的。
3、字符串效果上相当于char[] 字符数组,但是底层原理是byte[] 字节数组
创建字符串常见3+1种方式
三种构造方法
1、public String(),创建一个空白字符串,不含任何内容
2、public String(char[] array),根据字符数组的内容,来创建对应的字符串
3、public String(byte[] array),根据字节数组的内容,来创建对应的字符串
4、String str =“abc”;一种直接创建。
字符串的常用方法
比较相关
public boolear equals(Object obj),参数可以是任意对象,只有参数是一个字符串并且内容相同,才会是true .
备注:1、任何对象都能用Object进行接收。
2、如果比较双方一个变量一个常量。建议将常量放在前面。(变量null话,会出现空指针异常)
public boolear equalsIgnoreCase(Object obj),忽略大小写进行比较。
获取相关
public int length() ,获取字符串当中含有的字符串个数,拿到字符串长度。
public String concat(String str)将当前字符串和参数字符拼接成为返回值新的字符串
public char charAt(int index),获取指定索引位置的单个字符。索引从0开始
public int indexOf(String str),查找参数字符串在本字符串当中首次出现的索引位置,如果没有返回-1
截取相关
public String substring (int index ) ,截取从参数位置一直到末尾,返回新的字符串
public String substring(int begin ,int end),截取从begin开始到end结束中间的字符串, begin 包含左边,end不包含右边
转换相关
public char[] toCharArray() ,将当前字符串拆分成字符数组作为返回值
public byte[] getBytes() 获得当前字符串底层的字节数组
public String replace(CharSequence oldString ,CharSequence newString ) ,将所有出现的字符串替换成为新的字符串,返回替换之后的字符串。
备注:CharSequence 意思是可以接受的字符串类型。
分割字符串
public Sting[] split (String regex), 按照参数发的规则分割字符串成为 字符串数组返回

package com.myStudy.demo1;public class Demo3 {public static void main(String [] args) {String str1=new String();System.out.println(str1);//char[] charArray= {'a','b','c'};String str2=new String(charArray);System.out.println(str2);//abcbyte[] byteArray= {97,98,99};String str3=new String(byteArray);System.out.println(str3);//abcString str4="abc";System.out.println(str4);//abcString str5="Abc";System.out.println(str4.equals(str2));//trueSystem.out.println(str4.equalsIgnoreCase(str5));//trueSystem.out.println(str4.length());//3System.out.println(str4.concat("d"));//abcdSystem.out.println(str4.charAt(0));//aSystem.out.println(str4.indexOf("a"));//0System.out.println(str4.substring(1));//bcSystem.out.println(str4.substring(1,2));//bSystem.out.println(str4.toCharArray());//['a','b','c']byte[] byte1=str4.getBytes();for (int i = 0; i < byte1.length; i++) {System.out.println(byte1[i]); //97 98 99}System.out.println(str4.replace("a", "d"));//dbcString str6="a b c";String [] arrayString=str6.split(" ");for (int i = 0; i < arrayString.length; i++) {System.out.println(arrayString[i]);//a b c}}
}

4.2.12、Arrays数组工具类

java.util.Arrays是一个与数组相关的工具类,里面提供了大量的静态方法,用来实现数组的常见操作。

public static String toString(数组) ,将参数数组变成字符串,默认格式[元素1,元素2…]
public static void sort(数组),按照默认升序(从小到大)对数组进行排序
注意:1、如果是数值,默认按照从小到大
2、如果是字符串,默认按照字母升序
3、如果是自定义类型,那么这个自定义类型需要有Comparable或者Comparator 接口的支持

4.2.13、Math类

public static double abs(double num),获取绝对值
public static double ceil (double num),向上取整()
public static double floor(double num) 向下取整(抹零)
public static long round(double num) 四舍五入

4.2.14、 Object 类(根类)

java .lang.Object 是类层次结构的根类,每个类都使用Object 作为父类,所有对象都实现这个类的方法。
toString() 返回该对象的字符串表示
equals(object obj) 指示其他某个对象是否与此对象“相等”
存在多态 、向下转型

4.2.15 、Date类

java.util.Date
表示时间日期的类
1000毫秒=1秒
时间原点 1970年1月1 日 00:00:00
毫秒的作用,可以对时间进行计算。
注意:
1、中国属于东八区,会把时间增加8个小时
Date() 当前时间
Date(long date) 传递毫秒转换成时间(从原点基础上开始计算) Date date =new Date (毫秒);
long getTime() 日期转换成毫秒

4.2.16、 DateFormat 类

时间格式化,继承的Format类
SimpleDateFormat(string pattern) 用给定的模式和默认的语言环境的日期格式符号构造。格式可以随意指定,只要符合字母要求
String format(Date date) 按指定格式,把日期格式化为指定格式的字符串。
Date parse(String date)按指定格式,把符合格式的日期文本解析为指定格式的日期。
注意:parse 方法声明了一个解析异常。
需要调用一个抛出了溢出的方法。

package com.myStudy.demo1;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;public class Demo5 {public static void main(String [] args) throws ParseException {SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date date = new Date();System.out.println(sdf.format(date));System.out.println(sdf.parse(sdf.format(date)));}
}

4.2.17、 Calendar 类

日历类
static Calendar getInstonce() 使用默认时区和语言获的一个日历
public int get(int field) 返回给定的日历值
public void set(int field,int value) 将给定的日志值赋予具体数值
public abstract void add(int field,int aount)根据日志的规则,为自定的日历字段添加或者减去指定的时间量
public Date getTime() 返回一个表示此Calender时间值(从历元到现在的毫秒偏移量)的Date对象

package com.myStudy.demo1;import java.text.ParseException;
import java.util.Calendar;public class Demo5 {public static void main(String [] args) throws ParseException {Calendar c = Calendar.getInstance();System.out.println(c);int year=c.get(Calendar.YEAR);System.out.println(year);int month=c.get(Calendar.MONTH)+1; //月份西方0-11System.out.println(month);}
}

4.2.18 、System 类

java.lang.System类中有大量的静态方法,可以获取系统相关的信息或系统级操作
常用方法
public static long currentTimeNillis() 返回以毫秒为单位的当前时间
public static void arraycopy(Object src ,int srcPos Object dest,int destPos,int lenth) 将制定数组中指定的数据拷贝(覆盖)到另外一个数组中

4.2.19 、StringBuilder 类


StringBuilder (String str) 构造函数,创建并赋值
public StringBuilder oppend(…) 添加任意类型数据的字符串形式,并返回当前对象自身
public StringBuilder reverse() 倒叙输出
public String toString() StringBuilder 转换成String

package com.myStudy.demo1;import java.text.ParseException;public class Demo5 {public static void main(String [] args) throws ParseException {StringBuilder b1= new StringBuilder();StringBuilder b2=b1.append("abc");System.out.println(b1);// abcSystem.out.println(b1);//abcSystem.out.println(b1==b2);//两个是同一个对象//使用append 方法无需接受返回值b1.append("1");b1.append(true);b1.append(2);System.out.println(b1);// abc1true2//反转b1.reverse();System.out.println(b1);// 2eurt1cba//String->StringBuilderString str="hello";StringBuilder bu= new StringBuilder(str);bu.append("world");System.out.println(bu);// helloworld//StringBuilder->StringString str1=bu.toString();System.out.println(str1);// helloworld}
}

4.3、面向对象

4.3.1 、面向对象思想

面向过程:当需要实现一个功能的时候,每一个具体的步骤都要亲力亲为,详细处理每一个细节
面向对象:当需要实现一个功能的时候,不关系具体的步骤,而是找一个已经具有该功能的人,来帮我做事。

4.3.2 、类和对象


是一组相关属性和行为的集合,可以看成是一类事物的模板。使用事物的属性特征和行为特征来描述该类的事物。
属性:就是该事物的状态信息
行为:就是该事物能够做什么
举例:小猫
属性:名字、体重、年龄、颜色
行为:走、跑、叫

对象
是一类事物的具体体现,对象是类的一个实例。必然具备该类事物的属性和行为。

类和对象的关系
类是一类事物的描述,是抽象的
对象是一类事物的实例,是具体的
类是对象的模板,对象是类的实体

类的定义、类的创建使用

package com.myStudy.demo1;/* 定义类成员变量(属性)String name //姓名int age //年龄成员方法(行为)public void eat(){}//吃饭public void sleep(){}//睡觉public void study(){}//学习*/
//快捷键 ctrl +shift+F  格式化代码 public class Student {String name; // 姓名int age;// 年龄public void eat() {System.out.print("吃饭");}public void sleep() {System.out.print("睡觉");}public void study() {System.out.print("学习");}
}
package com.myStudy.demo1;/* 类的使用
1、导包,如果在同一包下可以省略
import 包名称.类名称
2、创建对象
类名称 对象名= new 类名称();
3、使用
使用成员变量:对象名.成员变量名
使用成员方法:对象名.成员方法名
注意事项:如果成员变量没有进行赋值,那么将会有一个默认值。规则与数组一致
*/public class Demo1 {public static void main(String[] args) {Student stu= new Student();System.out.println(stu.age);System.out.println(stu.name);stu.age=18;stu.name="张三";System.out.println(stu.age);System.out.println(stu.name);}}
对象可以作为方法的参数、返回值

一个对象的内存图

扩展:成员变量(A)和局部变量(B)的区别
1、定义的位置不一样
A:在方法的外部,直接写在类中
B::在方法的内部

2、作用范围不一样
A:整个类都可以通用
B;方法内才能使用

3、默认值不一样
A:有默认值,与数组一样
B:没有默认值,必须手动赋值

4、内存位置不不一样
A:堆内
B:栈内

5:生命周期不一样
A:随对象的创建而诞生
B:随方法进栈而诞生,方法结束 出栈消失

匿名对象
匿名对象只有右边的对象,没有左边的名字和赋值运算符

new 类名称()
匿名对象也可以作为方法的参数、返回值

int name=new Study().geetName();
public Study test(){return new Study();
}

4.3.3、 面对对象的三大特征-封装性

封装性在java中的体现
1、方法就是一种封装
2、关键字private 也是一种封装

封装就是将一些细节信息隐藏起来,对于外界不可见。

关键this
当方法的局部变量和类的成员变量重名的时候。根据就近原则。优先使用局部变量。这个可以用this来区分。
this.成员变量名(通过谁调用的方法,就是谁的this)

构造方法
构造方法是专门用来创建对象的方法,当我们通过关键字 new 来创建对象时就是在调用构造方法。

格式
public 类名称 (参数类型 参数名称){}

注意事项:
1、构造方法的名称必须也类名称完全一样。
2、构造方法不要写返回值类型,连void 都不写。
3、构造方法不能return一个具体的返回值
4、如果没有编写任何构造方法,那么编译器会默认给一个构造方法,没有参数,方法体什么都不做。

类的封装

package com.myStudy.demo1;/* 定义类类的封装source->Generate GEtters and Setters*/public class Student {private String name; // 姓名public String getName() {return name;}public void setName(String name) {this.name = name;}private int age;// 年龄public int getAge() {return age;}public void setAge(int age) {this.age = age;}//构造方法public Student ( ){}//重载构造方法public Student (String name ,int age ){this.name=name;this.age=age;}
}
public class Demo1 {public static void main(String[] args) {Student stu= new Student("张三",17);System.out.println(stu.getName());System.out.println(stu.getAge());stu.setAge(18);;stu.setName("张三");System.out.println(stu.getName());System.out.println(stu.getAge());}}

快捷封装

4.3.4、静态Static 关键字

一旦使用static 关键字,那么这样的内容都不再属于对象自己,而是属于类的。所以凡是本类的对象,都共享同一份。
注意:静态不能访问非静态

package com.myStudy.demo1;/* 定义类静态成员变量,静态成员方法同样*/public class Student {private String name; // 姓名private int age;// 年龄static String room;public static String getRoom() {return room;}public static void setRoom(String room) {Student.room = room;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Student() {}public Student(String name,int age) {this.name=name;this.age=age;}
}
package com.myStudy.demo1;public class Demo4 {public static void main(String [] args) {Student one =new Student("张三",1);Student.setRoom("10楼2教室");System.out.println("学生"+one.getName()+"年龄"+one.getAge()+"在教室"+Student.getRoom());Student two =new Student("李四",2);System.out.println("学生"+two.getName()+"年龄"+two.getAge()+"在教室"+Student.getRoom());}
}

静态代码块
格式:
public class 类名{
static {
//静态代码块内容
}

特点:当第一次用到本类时,静态代码执行唯一的一次
静态内容总是优先于非静态,所以静态代码块比构造方法限制性
静态代码块的典型用途:用来一次性的对静态成员变量进行赋值

4.3.5、继承

继承是多态的前提,没有继承就没有多态
继承主要解决的问题就是:共性抽取

在继承的关系中,子类就是一个父类,也就是说,子类可以被当做父类看待
格式
定义父类的格式(一个普通的类定义)
定义子类的格式:
public class 子类名称 extends 父类名称{

特点
jiava语言是单继承的。
java语言可以多级继承B extends A C extends B

继承中的成员变量特点
在父子类的继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式
1、直接通过子类对象访问成员变量。
对象等号左边是谁,就优先用谁,没有则向上找、
2、 间接通过成员方法访问成员变量

区分子类中成员变量的方法
1、局部变量,直接写成员变量名
2、本类的成员变量 ,this.成员变量名
3、父类的成员变量, super.成员变量名

继承中的成员方法的使用特点
1、创建的对象是谁,就优先用谁,如果没有向上找

重写(Override)
在继承关系中,方法名一样,参数列表也一样

覆盖重写(Override):方法名一样,参数列表也一样
重载(Overload):方法名一样,参数列表一样
注意
1、必须保证父子类之间方法的名称,参数一致
@Override, 写在方法的前面,用来检测是不是有效的正确的覆盖重写。
这个注解就算不写,只要格斯正确,也是可以
2、子类方法的返回值必须【小于等于】父类方法的返回值范围
3、子类方法的权限修饰符必须【大于等于】父类方法的权限修饰符。
扩展:pulic >protected>defoult>private
备注,defoult不是关键字 default。而是什么都不写。留空。

继承类中的构造方法的访问特点
1、子类构造方当中有一个默认的super(),,不写默认赠送
2、可以通过super(参数)关键字来调用父类重载方法。
3、一个子类构造方法只能调用一个super

super三种用法
1、在子类的成员方法中,方位父类的成员变量
2、在子类的成员方法中,访问父类的成员方法
3、在子类的构造方法中,访问父类的构造方法

this的三种用法
1、在本类的成员方法中,访问本类的 成员变量
2、在本类的成员方法中,访问本类的另一个成员方法
3、在本类的构造方法中,访问本来的另外一个构造方法。

4.3.6、抽象

抽向方法,就是加上abstract 关键字,然后去掉大括号,直接分好结束
抽象类:抽象方法所在的类,直接在class 前加入abstract

如何使用抽象类和方法
1、不能直接创建new 抽象类对象
2、必须写一个子类来继承抽象父类
3、子类必须覆盖重写抽象父类当中所有的抽象方法

注意事项
1、抽象类不能创建对象
2、抽象类中,可以有构造方法
3、抽象类,不一定有抽象方法,只要保证是抽象类
4、父类抽象类的子类必须实现所有的抽象方法

4.3.7、接口

接口无处不在,生活中的接口就是一套规范

接口是多个类的公共规范
接口是一种引用数据类型,最重要的内容就是其中的抽象方法。

如何定义一个接口的格式:
public interface 接口名称{
//接口内容

备注,clas换成interface 后编译后仍然是生成class
java 7 接口中可以有
1、常量 2、接口方法
java8 还可以有
3、静态方法、4、默认方法
java 9还可以有
5、私有方法

接口中定义抽象方法
1、接口当中的抽象方法,修饰符必须是两个固定的关键字、pubic 、abstract

Java 8、9
2、这两个关键字修饰符,可以选择性的省略
3、方法的三要素可以随意定义

接口的使用步骤
1、接口不能直接使用,必须有一个实现类来实现接口
2、接口的实现类必须要覆盖重写(实现)接口中的所有抽象方法
3、创建实现类的对象,进行使用

接口中的默认方法如何使用(Java8以上)
格式
public default 返回值类型 方法名(参数列表){
方法体

备注,接口中的默认方法可以用于接口升级

接口中的静态方法(java 8以上)
格式:
public statci 返回值类型 方法名(参数列表){
方法体

注意:不能通过接口实现类的对象来调用接口当中的静态方法
正确用法
通过接口名称直接调用其中的静态方法
接口名称.静态方法名(参数列表)

接口中的私有方法(Java 9)
我们需要抽取一个共有方法,用来解决两个默认方法之间重复的代码
1、普通私有方法,解决多个默认方法之间重复代码的问题
private 返回值类型 方法名(参数列表){}
2、静态私有方法,解决多个静态方法之间重复代码的问题
private static 返回值类型 方法名(参数列表){}

接口中的常量的使用
public static final 数据类型 常量名称=数据值;
备注:
一旦使用final 关键字进行修饰,说明不可变。
注意事项
1、接口当中的变量,可以省略public static final 不写依然是这样
2、接口中的常量,必须进行赋值。不能不赋值
3、接口中常量名称,建议全部使用大写字母,字母之间用下划线连接
使用:
接口名.变量名

继承多个接口
public class 当前类名 implements 接口A,接口B
注意:
1、如果实现类所实现的多个接口中,存在重复的抽象方法,覆盖重写一次就可以。
2、如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类必须是一个抽象类。
3、如果实现类所实现的多个接口中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
4、父类》接口

package com.myStudy.demo1;public interface MyInterfaceAbstract {abstract void methodAbs1();abstract void methodAbs2();abstract void methodAbs3();public default void methDefault() {System.out.println("默认方法");    }public static void methStatic() {System.out.println("静态方法方法");   }
}
package com.myStudy.demo1;public class MyInterfaceAbstractImpl implements MyInterfaceAbstract {@Overridepublic void methodAbs1() {System.out.println("实现类1方法1");}@Overridepublic void methodAbs2() {System.out.println("实现类1方法2");}@Overridepublic void methodAbs3() {System.out.println("实现类1方法3");}}
package com.myStudy.demo1;public class MyInterfaceAbstractImpl1 implements MyInterfaceAbstract{@Overridepublic void methodAbs1() {System.out.println("实现类2方法1");}@Overridepublic void methodAbs2() {System.out.println("实现类2方法1");}@Overridepublic void methodAbs3() {System.out.println("实现类2方法1");}}
package com.myStudy.demo1;public class DemoInterface {public static void main(String [] args) {MyInterfaceAbstractImpl myinterface= new MyInterfaceAbstractImpl();myinterface.methodAbs1();myinterface.methDefault();MyInterfaceAbstractImpl1 myinterface1= new MyInterfaceAbstractImpl1();myinterface1.methodAbs1();myinterface1.methDefault();MyInterfaceAbstract.methStatic();}}

4.3.8、多态(对象的多态性)

举例,小明同学。对象学生、对象人

代码中体现多态性,父类引用指向子类对象
格式
父类名称 对象名=new 子类名称();
接口名 对象名= new 实现类名称();

多态中成员变量的使用
1、直接 通过对象名访问成员变量,看等号左边是谁就优先用谁,没有则向上查找
2、间接通过成员方法访问成员变量,看该方法属于谁,优先用谁,没有向上查找。

多态中成员方法的使用
看new的是谁,就优先用谁,没有则向上找

为什么要用多态

对象向上转型(多态)

对象向下转型(调用子类特有方法【还原】)
格式:
父类名称 对象名A= new 子类名称();
子类名称 对象名= (子类名称)对象名A;
注意:
1、必须保证对象本来创建的时候子类与还原的时候是一致的
2、如果对象创建时本来不是猫,非要向下转型成为猫,报错。

4.3.9、 instanceof 关键字

向下转型做类型判断
if(animal instanceof Cat)

4.3.10、 final关键字

4中用法
修饰类、方法、局部变量、成员变量
修饰类
格式:
public final class 类名称{}
final修饰的类不能有任何 子类。

修饰方法
格式:
修饰符 final 返回值类型 方法名(参数列表){}
注意,对于类和方法 抽象关键字abstract和final 不能同时使用

修饰局部变量
final 类型 变量名=数值;
fiina 修饰的局部变量 不能进行更改。保证唯一一次赋值。
对于基本数据类型来说 ,数值不可变
对于引用类型来说,地址不可变

修饰成员变量
对于成员变量来说,使用final 修饰,那么这个变量也不可变。
1、由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了
2、要么直接赋值,要么通过构造方法赋值。
3、必须保证类中所有的构造方法都对final 修饰的成员变量赋值。

4.3.11 、四种权限修饰符

访问情况 publi> protected> (default)(不写修饰符默认为这个)> private
同一个类(我自己) yes yes yes yes
同一个包(我邻居) yes yes yes no
不同包子类(我儿子) yes yes no no
不同包非子类(陌生人) yes no no no

4.3.12 、内部类

举例:车子和发动机 身体和心脏
一个事物的内部包含另外一个事物,那么这就是一个类内部包含另外一个类。
分类
成员内部类
局部内部类(包含匿名内部类)

定义一个类时,权限修饰符规则
1、外部类 :public 、(default)
2、成员内部类:public、protected、 (default)、private
3、局部内部类:什么都不要写

成员内部类
修饰符 class 外部类名{
修饰符 classs 内部类名

注意:内用外,随意访问,外用内,需要内部类对象。
如何使用内部类
1、间接方式,在外部类方法中,使用内部类,然后main只调用外部类的方法。
2、直接使用
外部类名称.内部类名称 对象名=new 外部类名称().new 内部类名称();

使用内部类中的变量和方法。 外部类名称.内部类名称.变量|方法

局部内部类
如果一个类定义在一个方法中,那么这个类就是局部内部类。

局部内部类(匿名内部类)
如果接口的实现类(或者是父类的子类)只需要使用唯一一次。那么这种情况可以省略掉该类的定义,而改成使用匿名内部类。

匿名内部类定义格式
接口名称 对象名= new 接口名称(){
//覆盖重写所有的抽象方法
};
注意事项:
1、匿名内部类在创建对象的时候,只能使用唯一一次
2、如果希望多次创建,而且类的内容一样的话,必须单独定义实现类
3、匿名对象在调用方法是只能调用一次
new 方法名(){}.方法名();

4.4、Java进阶知识点

4.4.1、ArrayList

ArrayList 集合的长度可以随意变化
对于ArrayList 来说,有一个尖括号 代表泛型
泛型只能是引用类型,不能是基本类型,如果要用基本类型,可以使用基本类型包装类
格式
ArrayList<引用类型> 集合名称 = new ArrayList<引用类型>();
ArrayList的常用方法
add:向集合中添加元素,参数类型与泛型一致‘,返回值代表是否成功。
get:从集合中获取元素,参数是索引编号。返回值就是对应位置的元素
remove:从集合中删除元素,参数是索引编号,返回值是被删除的元素
size:获取集合的尺寸长度,返回值是集合中包含的元素的个数

package com.myStudy.demo1;import java.util.ArrayList;public class Demo3 {public static void main(String [] args) {ArrayList<String> list = new  ArrayList<String>();//默认值System.out.println(list);//[]//添加元素list.add("宋小宝");list.add("贾玲");System.out.println(list);//[宋小宝,贾玲]//获取元素System.out.println(list.get(0));//宋小宝//删除元素list.remove(0);System.out.println(list);//[贾玲]//获取元素个数System.out.println(list.size());//1//基本数据 用包装类使用ArrayList<Integer> list1= new  ArrayList<Integer>();}
}

4.4.2、包装类

基本类型 包装类
byte
short Short
int Integer(特殊)
long Long
float Float
double Dpible
char Character(特殊)
boolean Boolean

装箱
把基础类型的数据,包装到包装类中
构造方法
Integer(int value) 构造一个新分配的Integer 对象,它表示指定的int值
Integer(String str)构造一个新分配的Integer 对象,它表示String 参数所指定的int值,字符串必须是基本类型的字符串 否则抛出异常
静态方法
static Integer valueOf(int i )返回一个表示指定的int值得Integer实例
static Integer valueOf(String s)返回保存指定的String 的值得Integer实例

拆箱
在包装类中取出基本类型的数据
成员方法
int intValue() 以int类型的返回该Integer 的值

自动装箱和自动拆箱(JDK5+)
Integer i=1; 直接把int类型的数据赋值给包装类
i=i+2;包装类 i无法直接 参与运算,可以自动转换为基本类型的数据,在参与计算

String 转换成对应的基本类型
使用包装类中的静态方法
Interger类 static int parseInt(基础类型)(String str)
其他基本类型数据同格式使用

**基本类型转换成对应的String **
1、基本类型数据的值+“”
2、包装类中的static String toString(基本类型 数据)
3、String 类中的 valueOf

4.4.4、 数据结构(简单了解)



队列

数组

链表

红黑树

哈希表
哈希值:一个十进制的逻辑地址

4.4.5 、Collection集合

集合是一种容器,可以用来存储多个数据,长度可以变化
举例 数组和ArrayList


Collection常用方法
boolean add(E e) 向集合中添加元素
boolean remove(E e) 删除集合中的指定元素
void clear() 清空集合中所有元素[]
boolean contains(E e) 判断集合中是否包含某个元素
int size() 获取集合的长度
boolean isEmpty 判断集合是否为空
Object [] toArray() 将集合转换成一个数组

Collection工具类常用方法
public static boolean addAll(Collection c, T … elements); 往集合里面添加一些元素
public static void shuffle(List<?> list) 打乱集合中的顺序

public static void sort(List list) 将集合中元素的默认规则排序 ,默认升序
排序自定义类型,重写Comparator中的comparaeTo方法
this.变量-变量 升序 变量-this.变量 降序

public static void sort(List list,Comparator<? super T> ) 将集合中元素的默认规则排序 ,调用方法时重写Comparator
升降序规则看下方代码

Collections.sort(a1, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {// TODO Auto-generated method stub// o1-o2 升序 o2-o1 降序return 0;}});

4.4.5.1、List集合

特点
1、有序的集合,存储元素和取出元素的顺序是一致的
2、有索引,包含一些带索引的方法
3、允许存储重复的元素

List 接口中带索引的方法(特有)
public void add(int index,E element)将指定元素,添加到该集合中的指定位置上。
public E get(int index) 返回集合中指定位置的元素
public E remove(int index) 移除列表中指定位置的元素,返回的是被移除的元素
public E set(int index,E element) 用指定的元素替换指定位置的元素,返回的是被替换的元素

注意,操作索引的时候,一定要防止索引越界异常

ArrayList
底层是数组 多线程
查询快,增删慢

LinkedList
底层是链表 多线程
查询慢,增删快
LinkedList 特有方法(不能使用多态)
public void addFirst(E e) 将指定元素插入此列表的开头
public void addLast(E e) 将指定元素插入此列表的结尾
public void push(E e) 将指定元素推入此列表表示的堆栈,等效于 addfirst

public E getFirst() 返回此列表第一个元素
public E getLast() 返回此列表的最后一个元素
boolean isEmpty 判断集合是否为空

public E removeFirst() 移除并返回此列表第一个元素
public E removeLast() 移除并返回此列表的最后一个元素

Vector
底层是数组,单线程
最开始版本的集合,已被 ArrayList 取代
elements() 早期迭代器结构
hasMoreElement
nextElement

4.4.5.2 、set集合

特点
1、不允许存储重复元素
2、没有索引,没有带索引的方法,也不能使用普通的for循环遍历
set集合在调用add方法的时候,会调用hashCode(对比哈希值)和equals(对比地址值)方法,判断元素是否重复

HashSet
特点:1、set集合通用特点
2、是一个无序的集合,存储元素和取出元素的顺序有可能不一致
3、底层是哈希表结构(查询速度非常的快)

存储自定义类型元素
注意,要重写 hashCode 和 equals方法用来保证 没有重复元素

LinkedHashSet
extends HashSet
特点
底层是一个哈希表(数组+链表+红黑树),多了一条链表记录排序顺序,保证元素有序

4.4.5.3 、泛型


不使用泛型
好处:集合不使用泛型,默认的类型就是Object类型,可以存储任意类型的数据
坏处:不安全,会引发异常 (向下转型使用特有方法时)
使用泛型
好处:
1、集合是什么类型数据,取出就是什么类型数据
2、运行期溢出提前到编译期
坏处:
泛型是什么类型,就只能存储什么类型数据

package com.myStudy.demo1;import java.util.ArrayList;
import java.util.Iterator;public class Demo6 {public static void main(String [] args) {//不使用泛型ArrayList list = new ArrayList();list.add("a");list.add(1);list.add(false);Iterator it = list.iterator();while (it.hasNext()) {Object object = (Object) it.next();System.out.println(object);//向下转型使用String 的 length方法,int向下转型成String 会异常}//使用泛型ArrayList<String> list1 = new ArrayList<>();list1.add("a");//只能存储String类型数据//list1.add(1); //list1.add(false);}}

含有泛型的类使用

package com.myStudy.demo1;public class GenericClass<E> {private E name;public E getName() {return name;}public void setName(E name) {this.name = name;}
}
package com.myStudy.demo1;public class Demo6 {public static void main(String [] args) {//ObjectGenericClass gc1=new GenericClass<>();gc1.setName("aaaaa");//intGenericClass<Integer> gc2=new GenericClass<>();gc2.setName(1);//StringGenericClass<String> gc3=new GenericClass();gc3.setName("a");}}

含有泛型的方法

package com.myStudy.demo1;public class GenericMethod {public<M> void method1(M m) {System.out.println(m);}public static <M> void method2(M m) {System.out.println(m);}
}
package com.myStudy.demo1;public class Demo6 {public static void main(String [] args) {GenericMethod me1= new GenericMethod();me1.method1("aaaa");me1.method1(1);me1.method1(true);GenericMethod.method2("aaa");GenericMethod.method2(1);GenericMethod.method2(true);}}

含有泛型的接口

package com.myStudy.demo1;public interface GenericInterface<I> {public abstract void method1(I i);
}

第一种方法

package com.myStudy.demo1;public class GenericInterfaceImp1 implements GenericInterface<String>{@Overridepublic void method1(String i) {// TODO Auto-generated method stubSystem.out.println(i);}
}

第二种方法

package com.myStudy.demo1;public class GenericInterfaceImp2 <I> implements GenericInterface<I> {@Overridepublic void method1(I i) {// TODO Auto-generated method stubSystem.out.println(i);}
}
package com.myStudy.demo1;public class Demo6 {public static void main(String [] args) {GenericInterfaceImp1 gii1=new GenericInterfaceImp1();gii1.method1("aaaaa");GenericInterfaceImp2<String> gii2=new GenericInterfaceImp2<>();gii2.method1("aaaaa");}}

泛型的通配符 ?
通配符代表任意类型
作为方法参数使用

package com.myStudy.demo1;import java.util.ArrayList;
import java.util.Iterator;public class Demo6 {public static void main(String [] args) {ArrayList<Integer> a1= new ArrayList<Integer>();a1.add(1);ArrayList<String> a2= new ArrayList<String>();a2.add("aaa");printArray(a1);printArray(a2);}public static void printArray(ArrayList<?> list) {Iterator<?> it =list.iterator();while (it.hasNext()) {System.out.println(it.next());}}
}

泛型通配符的进阶
泛型的上限限定: ? extends E 代表使用的泛型只能是E类型的子类/本身
泛型的下限限定: ? super E 代表使用的泛型只能是E类型的父类/本身

package com.myStudy.demo1;import java.util.ArrayList;
import java.util.Iterator;public class Demo6 {public static void main(String [] args) {ArrayList<Integer> a1= new ArrayList<Integer>();        ArrayList<String> a2= new ArrayList<String>();     ArrayList<Number> a3= new ArrayList<Number>();ArrayList<Object> a4= new ArrayList<Object>();//Integer extends  Number extends Object//String extends ObjectgetElement1(a1);getElement1(a2); //报错getElement1(a3);getElement1(a4); //报错getElement2(a1); //报错getElement2(a2);//报错getElement2(a3);getElement2(a4);}public static void getElement1(ArrayList<? extends Number> list) {}public static void getElement2(ArrayList<? super Number> list) {}
}

4.4.5.4 、迭代器(Iterator)

Colection集合元素的通用获取方式,在取元素之前先要判断集合中有没有元素,有的话取出,直到集合中所有元素全部取出。这种取出方式专业术语称为迭代

迭代器中常用方法
boolean hasNext() 判断集合中还有没有下一个元素,有返回true,没有false
E next() 取出集合中的下一个元素。
Iterator iterator() 返回在此Collection的元素上进行迭代的迭代量
迭代器是一个接口,无法直接使用,需要使用Iterator接口的实现类对象

package com.myStudy.demo1;import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;public class IteratorStudy {public static void main(String [] args) {//创建集合Collection<String> co1=new ArrayList<>();//添加数据co1.add("a");co1.add("b");co1.add("c");co1.add("d");//实例迭代器Iterator<String> it1=co1.iterator();//判段是否有下一个元素boolean b1=it1.hasNext();//取出元素String s1=it1.next();//循环取出while (it1.hasNext()) {System.out.println(it1.next());}for (Iterator<String> it2=co1.iterator();it2.hasNext(); ) {System.out.println(it2.next());}    }
}

4.4.5.5 、增强for循环

底层使用的也是迭代器,使用for循环格式,简化迭代器的书写
Collection extends iterable 所有的单例集合都可以使用增强for循环
public interface Iterable 实现这个接口允许对象成为foreach语句的目标
格式
for(集合/数组数据类型 变量名:集合名/数组名){

        ArrayList<String> list = new ArrayList<>();list.add("a");list.add("b");list.add("c");list.add("d");for (String s : list) {System.out.println(s);}

4.4.6 、Map集合

Map集合特点:
1、Map集合是一个双列集合,一个元素包含两个值 key,value
2、Map集合中的元素,key,value的数据类型可以相同,也可以不同
3、Map集合中的元素,key不允许重复
4、Map集合中的元素,key ,value是对应的

HashMap

常用方法
底层是哈希表,查询速度非常的快。无序的集合
多线程执行

public V put(K key, V value); 把指定的键与指定的值添加进Map集合中
1、key不重复,返回null
2、key 重复,返回被替换的value

public V remove(Object key); 根据指定的键把该键值数据从Map中移除
1、key不存在,返回null
2、key 存在,返回被删除的value

public V get(Object key); 根据指定的键获取值
1、key不存在,返回null
2、key 存在,返回value

boolean containskey(Object key) 判断集合中是否存在包含指定的键

遍历
Set keySet()把 Map中的所有key 取出存入Set集合

Set<Map.Entry<k,v>> entrySet()把 Map中的所有Entry对象 取出存入Set集合
Entry对象有 getKey() 和getValue 两个方法

package com.myStudy.demo1;import java.util.HashMap;
import java.util.Map;
import java.util.Set;public class Demo7 {public static void main(String [] args) {HashMap<Integer,String> hm1=new HashMap<Integer, String>();hm1.put(1, "a");hm1.put(2, "b");hm1.put(3, "c");hm1.put(4, "d");hm1.put(5, "e");//keySetSet<Integer> hs1= hm1.keySet();for(Integer it:hs1) {System.out.println(it.toString()+","+hm1.get(it));}//entrySetSet<Map.Entry<Integer,String>> hs2= hm1.entrySet();for(Map.Entry<Integer,String> it:hs2) {System.out.println(it.getKey()+","+it.getValue());}}}

HashMap 存储自定义类型键值
作为key元素,必须重写hashCode 和equals 两个方法

LinkedHashMap
有序
Hashtable
单线程集合,速度慢
与 Vector 类型,被HashMap取代
Hashtable 的子类Properties 仍在使用 IO流

4.4.7、JDK9 对集合(List、Set、Map)的新特性

staitc List of(E … elements) 一次性添加多个元素
使用前提:当集合中存储的元素的个数已经确定,不再改变时使用
注意:
1、of 方法只适用于List、Set、Map 接口,不适用于接口的实现类
2、返回的是一个不能改变的集合,集合不能在再使用put,add 方法添加元素,会抛出异常

3、Set、Map 使用 of不能有重复元素

4.4.8、调试、异常

4.4.8.1、Debug调试

用Debug模式运行程序, 代码左边点击添加断点
根据编码工具的快捷点进行跟踪调试

4.4.8.2、异常

Exception:编译期异常,进行编译,java程序出现的问题
   RuntimeException:运行期异常,java程序运行过程出现的问题
可处理,处理后程序正常继续执行
Error:错误
不可处理,必须重新修改源代码,程序才能继续执行

4.4.8.3 、异常处理

throw
运行期异常,抛给jvm处理
作用:可以使用throw 关键字,在指定的方法中抛出指定的异常
格式:throw new xxxException(“异常原因”)
注意:1、throws关键字必须写在方法的内部
2、throw关键字后面的new 对象必须是Exception或者是它的子类对象
3、throw关键字抛出异常对象,我们就必须处理这个异常对象
4、throw关键字后面new的是RuntimeException或者是RuntimeException的子类对象,我们可以不处理,默认交给jvm处理
5、throw 后面new的是编译异常(写代码时报错),我们就必须处理这个异常,throws声明或者try catch

** throws 声明抛出**
格式:
修饰符 返回值类型 方法名(参数列表)throws AAAException,BBBException…{
throw new AAAException(“异常原因”)
throw new BBBException(“异常原因”)
}

try catch 捕获:
编译期异常,自行处理
格式:
try{
//可能出现异常的代码
}catch(异常类名 变量){
//异常处理
}finally{
//finally 根据需求添加
}
String getMessage() 返回此throwable的简短描述
String toString() 返回此throwable 的详细消息字符串
void printStachTrace() JVM打印异常对象,默认此方法。打印的异常信息最全面

finally
1、必须和ty catch一起使用。
2、finally 一班用于资源释放(资源回收),无论程序是否出现异常,最后都要执行里面内容

Objects非空判断
public static T requireNonNull(T obj) 查看指定引用对象是不是null

4.4.8.4、 异常处理注意事项

多个异常处理方式
1、多个异常分别处理
2、多个异常一次铺货,多次处理
3、多个异常一次铺货,一次处理

package com.myStudy.demo1;import java.util.ArrayList;public class Demo8 {public static void main(String[] args) {// 多个异常分开捕处理try {int[] arr = { 1, 2, 3 };System.out.println(arr[3]);} catch (IndexOutOfBoundsException e) {System.out.println(e.getMessage());}try {ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);System.out.println(list.get(3));} catch (ArrayIndexOutOfBoundsException e) {System.out.println(e.getMessage());}// 多个异常一次捕获,多次处理try {int[] arr = { 1, 2, 3 };System.out.println(arr[3]);ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);System.out.println(list.get(3));} catch (ArrayIndexOutOfBoundsException e) {System.out.println(e.getMessage());} catch (IndexOutOfBoundsException e) {System.out.println(e.getMessage());}// 多个异常一次捕获,一次处理try {int[] arr = { 1, 2, 3 };System.out.println(arr[3]);ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);System.out.println(list.get(3));} catch (Exception e) {System.out.println(e.getMessage());}}}

子父类异常
1、如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常
2、父类没有抛出异常,子类重写时也不可以抛出异常,此时子类产生的异常,只能铺货处理,不能声明抛出

4.4.8.5 、自定义异常类

package com.myStudy.demo1;//extends  Exception 或者 RuntimeException
public class RegisterException extends Exception {private static String[] str = { "张三,李四,王五" };public RegisterException() {super();// TODO Auto-generated constructor stub}// Exception 有处理异常信息的构造方法 super父类public RegisterException(String message) {super(message);// TODO Auto-generated constructor stub}public static void checkUserName1(String name) throws RegisterException {for (String s : str) {if (s.equals(name)) {throw new RegisterException("该用户已经被注册");// 继承RuntimeExcption 不需要声明 交给jvm处理}}System.out.println("注册成功!");}public static void checkUserName2(String name) {for (String s : str) {if (s.equals(name)) {try {throw new RegisterException("该用户已经被注册");} catch (Exception e) {e.printStackTrace();return;}}}System.out.println("注册成功!");}
}

4.4.9、线程

4.4.9.1、线程介绍

线程概念

线程调度
1、分时调度
所有线程轮流使用cpu的使用权,平均分配每个线程占用cpu的时间
2、抢占式调度
优先让优先级高的线程使用cpu,如果线程的优先级相同,那么会随机选择一个(线程随机性)。java使用的为抢占式调度

4.4.9.2、主线程

主线程:执行主(mian)方法的线程
单线程程序:java 程序中只有一个线程
执行从main方法开始,从上到下依次执行

4.4.9.3 、多线程

4.4.9.3.1、创建多线程的第一种方式

Thread类
java.lang.Thread类:是描述线程的类,我们要实现多线程程序,就必须继承Thread类

常用方法
String getName() 返回该线程的名称
static Thread currentThread() 返回对当前正在执行的线程对象的引用(配合getName 获取当前线程名字)

void setName(String name) 改变线程名称,使之与参数name相同
Thread(String name){} 构造方法 改变线程名称,使之与参数name相同

static void sleep(long millis) 线程睡眠 【millis单位毫秒 1000 =1秒】

实现步骤
1、创建一个Thread类的子类
2、子类中重写Thread类中的run方法,设置线程任务
3、创建子类对象
4、调用Thread类中的start方法,开始新的线程,执行【run】方法。

注意:1、结果是两个线程并发运行,main和当前线程。
2、多次启动一个线程是非法的,特使是当线程已经结束执行后。不能再重新启动

package com.myStudy.demo1;public class MyThread1 extends Thread {public void run() {for (int i = 0; i < 20; i++) {System.out.println("nmae"+i);}}
}
package com.myStudy.demo1;public class ThreadDemo {public static void main(String[] args) {MyThread1 mt1=new MyThread1();mt1.start();for (int i = 0; i < 20; i++) {System.out.println("main"+i);}}
}


多线程内存图

4.4.9.3.2、创建多线程的第二种方式

Runnable 接口

实现步骤
1、创建一个Runnable接口的实现类
2、重写Runnalbe 接口的run方法,设置线程任务
3、创建 实现类对象
4、创建Thread类对象,构造方法中传递Runable接口的实现类对象
5、调用Thread类的start方法,开始新线程执行run方法

package com.myStudy.demo1;public class MyThread2 implements Runnable {@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println("nmae"+i);}}}
package com.myStudy.demo1;public class ThreadDemo {public static void main(String[] args) {/*MyThread1 mt1=new MyThread1();mt1.start();System.out.println(mt1.getName());System.out.println();for (int i = 0; i < 20; i++) {System.out.println("main"+i);}*/MyThread2 mt2=new MyThread2();new Thread(mt2).start();}
}

实现Runnable 接口的创建多线程的好处
1、避免单线程的局限性
一个类只能继承一个类,继承Thread就不能继承别的类
实现Runnable接口,还可以继承其他的类,实现其他的接口
2、增强程序的扩展性,降低了程序的耦合性
实现Runnable 接口的方式,把设置线程任务和开启新线程进行了分离(解耦)

4.4.9.4 、匿名内部类方法实现线程创建

package com.myStudy.demo1;public class InnerClassThread {public static void main(String[] args) {new Thread() {// 重写run方法,设置线程任务@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println("nmaeA" + i);}}}.start();Runnable r = new Runnable() {@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println("nmaeB" + i);}}};new Thread(r).start();//简写new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println("nmaeC" + i);}}}).start();}
}

4.4.9.5 、线程安全问题

线程安全问题概述

4.4.9.5.1、解决线程问题方法一[同步技术-同步代码块]

格式:
synchronized(锁对象){
//可能会出现线程安全问题的代码

注意:
1、通过代码块中的锁对象,可以使用任意对象
2、但是必须保证多个线程使用的锁对象是同一个
3、锁对象作用:把同步代码块锁住只让一个线程在同步代码中执行

package com.myStudy.demo1;public class RunnableImp1 implements Runnable {private int TICKET_COUNT = 100;// 创建一个锁对象Object obj = new Object();@Overridepublic void run() {//使用死循环(测试使用)while (true) {// 创建一个同步代码块synchronized (obj) {if (TICKET_COUNT > 0) {try {// 设定睡觉时间,加大安全问题出现几率Thread.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在卖第" + TICKET_COUNT + "张票");TICKET_COUNT--;}}}}
}
package com.myStudy.demo1;public class ThreadDemo {public static void main(String[] args) {RunnableImp1 rbl=new RunnableImp1();Thread t1=new Thread(rbl);Thread t2=new Thread(rbl);Thread t3=new Thread(rbl);t1.start();t2.start();t3.start();}
}
4.4.9.5.2、解决线程问题方法二 [同步技术-同步方法]

步骤:
1、把访问共享数据的代码抽取出来,放到一个方法中调用
2、在方法上添加一个synchronized 修饰符

package com.myStudy.demo1;public class RunnableImp1 implements Runnable {private int TICKET_COUNT = 100;// 创建一个锁对象Object obj = new Object();@Overridepublic void run() {//使用死循环(测试使用)while (true) {payTicket();}}public synchronized void payTicket() {if (TICKET_COUNT > 0) {try {// 设定睡觉时间,加大安全问题出现几率Thread.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在卖第" + TICKET_COUNT + "张票");TICKET_COUNT--;}}
}

解决线程问题方法二 [同步技术-静态同步方法]
静态同步方法
锁定对象不是this,而是本类的class 文件对象(下方反射内容有介绍)

package com.myStudy.demo1;public class RunnableImp1 implements Runnable {private static int TICKET_COUNT = 100;// 创建一个锁对象Object obj = new Object();@Overridepublic void run() {//使用死循环(测试使用)while (true) {payTicket();}}public static synchronized void payTicket() {if (TICKET_COUNT > 0) {try {// 设定睡觉时间,加大安全问题出现几率Thread.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在卖第" + TICKET_COUNT + "张票");TICKET_COUNT--;}}
}
4.4.9.5.3、解决线程问题方法三 [同步技术-Lock锁]

ReentrantLock Lock接口实现类
Lock接口 中的方法
void lock() 获取锁
void unlock()释放锁

步骤
1、在成员位置创建一个ReentrantLock 对象
2、在可能出现安全问题的代码前调用Lock接口中的lock方法
3、在可能出现安全问题的代码后调用Lock接口中的unlock方法

package com.myStudy.demo1;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class RunnableImp1 implements Runnable {private  int TICKET_COUNT = 100;// 创建一个ReentrantLock对象Lock l1 = new ReentrantLock(); @Overridepublic void run() {//使用死循环(测试使用)while (true) {try {//获取锁l1.lock();if (TICKET_COUNT > 0) {try {// 设定睡觉时间,加大安全问题出现几率Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在卖第" + TICKET_COUNT + "张票");TICKET_COUNT--;}} catch (Exception e) {e.printStackTrace();}finally {//释放锁l1.unlock();}}}}

4.4.9.6 、线程状态


重点知识点:Waiting 【无限等待 】的等待唤醒【线程之间的通信】

概述

Object 类中的方法
void wait() 在其他线程调用此对象notyfy方法或者notyfyAll方法前,线程一直等待
void wait(long m) 在m毫秒时间后,如果没有唤醒,自行唤醒
void notify() 唤醒此对象监视器上等待的单个线程
会继续执行wait后面的代码
void notifyAll()唤醒此对象监视器上等待的所有线程

package com.myStudy.demo1;public class WaitAndNotyfyDemo1 {// 接待10个顾客private static int WORK_COUNT = 10;public static void main(String[] args) {// 创建锁对象Object obj = new Object();// 创建顾客线程new Thread() {@Overridepublic void run() {while (WORK_COUNT > 0) {synchronized (obj) {System.out.println("来了个顾客告诉老板包子订单数量种类");try {obj.wait();} catch (InterruptedException e) {e.printStackTrace();}// 唤醒之后执行的代码System.out.println("包子做好了,包子给顾客");WORK_COUNT--;}}}}.start();// 创建老板线程new Thread() {@Overridepublic void run() {while (WORK_COUNT > 0) {try {// 老板5秒钟做包子Thread.sleep(5000);} catch (InterruptedException e1) {e1.printStackTrace();}synchronized (obj) {System.out.println("做好包子了,唤醒顾客来拿包子");obj.notify();}}}}.start();}
}

4.4.9.7 、线程池

线程池:一个容纳多个线程的容器–>集合(ArrayList 、HashSet、LinkedList(最佳)、HashMap)

Executors类(JDK1.5+)中的静态方法
static ExecutorService newFixedThreadPool(int nThreads )创建一个可重用固定线程数(nThreads)的线程池
返回的是ExecutorService接口的实现类对象

submit() 用来从线程池中获取线程,调用start方法,执行线程任务
void subdown() 销毁线程池

线程池使用步骤
1、使用线程池工程类Executors 里的静态方法newFixedThreadPool生成一个指定线程数量的线程池
2、创建一个类,实现Runnable接口,重写run方法
3、调用ExecutorService 中的submit方法,开始线程执行任务
4、销毁线程池(不建议执行)

package com.myStudy.demo1;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class DemoThreadPool {public static void main(String [] args) {ExecutorService es= Executors.newFixedThreadPool(2);es.submit(new MyThread2());es.submit(new MyThread2());es.submit(new MyThread2());}}

4.4.10、Lambda表达式

Llambda 表达式的标准格式
由三个部分组成
a、一些参数 b、一个箭头 c、一段代码

格式
(参数列表)->{一些重写方法的代码}

解释说明格式
():接口中抽象方法的参数列表,没有参数就空着,有参数就写出参数,多个参数使用逗号分隔
->:传递的意思,把参数传递给方法体{}
{}:重写接口的抽象方法

接口作为参数,重写接口抽象方法时使用,如匿名类方式创建多线程、Arrays sort排序、自定义接口作为参数且有抽象方法

无参无返回值例子

package com.myStudy.demo1;public class DemoLambda {public static void main(String [] args) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println("创建一个多线程:"+Thread.currentThread().getName());}}).start();//Lambda表达式new Thread(()-> {System.out.println("创建一个多线程:"+Thread.currentThread().getName());}).start(); }}

有参有返回值例子

package com.myStudy.demo1;public class Person {private String  name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}//方便打印结果,重写toString@Overridepublic String toString() {return "Person [name=" + name + ", age=" + age + "]";}
}
package com.myStudy.demo1;import java.util.Arrays;
import java.util.Comparator;public class DemoLambda {public static void main(String [] args) {Person [] arr= {new Person("张三", 18),new Person("李四",17),new Person("王五",19)};Arrays.sort(arr,new Comparator<Person>() {@Overridepublic int compare(Person o1, Person o2) {return o1.getAge()-o2.getAge();}});for(Person per: arr) {System.out.println(per);}//LambdaArrays.sort(arr,(Person o1, Person o2)->{return o2.getAge()-o1.getAge();});for(Person per: arr) {System.out.println(per);}}}

有参有返回值例子(自定义接口)

package com.myStudy.demo1;public interface Calculator {public abstract   int calc(int a,int b);
}
package com.myStudy.demo1;public class DemoLambda {public static void main(String [] args) {subNum(1, 2, new Calculator() {@Overridepublic int calc(int a, int b) {// TODO Auto-generated method stubreturn a+b;}});//LambdasubNum(1,2,(int a,int b)->{return a+b;});}public static void  subNum(int a,int b ,Calculator cal) {System.out.println(cal.calc(a, b));}
}

4.4.11、File类

java .io.File 类
文件和目录路径名的抽象表示形式
可以对文件和文件夹进行操作

file :文件
directory:文件夹、目录
path:路径

File类的静态成员变量
static String pathSeparator 与系统有关的路劲分隔符,为了方便,它被表示为一个字符串(windows ;分号 linux :冒号)
static char pathSeparatorChar 与系统有关的路劲分隔符

static String separator 与系统有关的是默认名称分隔符,为了方便,它被表示为一个字符串(windows /反斜杠 linux \正斜杠)
static char separatorChar 与系统有关的是默认名称分隔符

绝对路劲和相对路劲
绝对路劲:是一个完整的路径,以盘符开始的路径
相对路径:是一个简化的路径,【相对】指定是相对于当前项目的根目录

注意:
1、路径是不区分大小写
2、反斜杠是转义字符,两个反斜杠表示一个反斜杠

FIle 构造方法
File(String pathName) 通过将给定的路径名字字符串转换为抽象路径名来创建一个新的File实例。
参数:
String pathName : 字符串的路径名称
路径可以文件或者文件夹结尾
可以是相对路径和绝对路径
路径可以是存在或者不存在,不考虑路径的真假情况

File(String parent,String child) 通过将给定parent的路径名字字符串和child路径名字字符串创建一个新的File实例。
参数将路径分为父路径和子路径
好处:父路径和子路径,可以单独书写,使用起来非常灵活。

File(File parent,String child) 通过将给定parent的抽象路径名字和child路径名字字符串创建一个新的File实例。
好处:
1、父路径和子路径,可以单独书写,使用起来非常灵活。
2、父路径创建后可以做相关处理再进行FIle 创建实例

File常用方法

获取
public String getAbsolutePath() 返回此FIle的绝对路径名字字符串
public String getPath() 将File转换为路径名字字符串,创建的时候是什么返回什么,与toString 效果一致
public String getName() 返回此FIle表示的文件或者目录名称(结尾)
public long length() 返回此FIle的表示的文件的长度,路径结尾是文件夹或者文件不存在 返回0

判断
public boolean exists() 此File表示的文件或者目录是否实际存在
public boolean isDirectory() 此File表示的是否为目录(路径必须是实际存在)
public boolean isFIle() 此File表示的是否为文件(路径必须是实际存在)

创建、删除(路径必须是实际存在)
public boolean createNewFile()当且仅当具有该名称的文件尚不存在时,创建一个新的空文件 ,路劲不是实际存在会抛出IO异常
public boolean delete()删除由此File表示的文件或目录
public boolean mkdir()创建由此File表示的目录(单级文件夹),类型不对不会抛异常,也不会创建
public boolean mkdirs()创建由此FIle表示的目录,包括任何必须单不存在的父目录(多级文件夹),类型不对不会抛异常,也不会创建

目录遍历(遍历的必须是构造方法中的实际存在的地址,否则抛出空指针异常)
public String [] list() 返回一个String数组,表示该FIle目录中所有子文件或目录名称
public File [] listFile 返回一个FIle数组,表示该FIle目录中的所有的子文件或目录抽象路径

文件过滤器
文件过滤器:FileFilter 接口
File [] listFiles (FileFilter filter) 用来过滤文件
   boolean accept(File pathname) 测试抽象路径名是否应该包含在某个路径名的列表中。

File [] listFiles (FilenameFilter filter) 用来过滤文件名
   boolean accept(File dir, String name) 测试文件名是否应该包含在某个路径名的列表中。

4.4.12、递归

递归分类
直接递归:自己调用自己
间接递归:A调用B,B调用C ,C调用A

注意
递归一定要有条件限定,保证递归能停下来,否则会发生栈内存溢出
递归虽然有限定条件,但是递归次数不能过多,否则会发生栈内存溢出
构造方法禁止使用递归

使用前提
当调用方法的时候,方法的主体不变,每次调用方法的参数不同,可以使用递归

FIle和递归综合例子:文件搜索

File通用方法+递归

package com.myStudy.demo1;import java.io.File;
import java.util.Scanner;public class DemoFileSerch {private static String resultPath = "未查找到";public static void main(String[] args) {Scanner scn = new Scanner(System.in);System.out.println("请输入要查询的文件名字");String name = scn.next();System.out.println("正在查找请稍后");File file = new File("E:\\Project\\JavaProject\\MyJavaStudy");fileSerch1(file, name);System.out.println("查询结果:" + resultPath);}public static String fileSerch(File dir, String name) {try {File[] dirs = dir.listFiles();for (File s : dirs) {if (s.isDirectory()) {fileSerch(s, name);} else {if (s.getName().equals(name)) {resultPath = s.getAbsolutePath();break;}}}} catch (Exception e) {e.printStackTrace();}return resultPath;}
}

文件过滤器+递归(可改为内部类、Lambda方式)

package com.myStudy.demo1;import java.io.File;
import java.io.FilenameFilter;public class FileFileterImp1 implements FilenameFilter{private String name;@Overridepublic boolean accept(File dir, String name) {// TODO Auto-generated method stubSystem.out.println(name+"||"+name.equals("Demo1.java"));//第一个条件判断是否是文件夹 ,name相当于抽象路径 getName() ;第二个是做最终的判断是否是这个文件是的话才会加入到FIle数组//继承FileFilter做判断的话就是要把 name.equals(this.name)  改为,dir.getName().equals(this.name)if(new File(dir,name).isDirectory()||name.equals(this.name)) {return true;}return false;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
package com.myStudy.demo1;import java.io.File;
import java.io.FilenameFilter;
import java.util.Scanner;public class DemoFileSerch {private static String resultPath = "未查找到";static FileFileterImp1 i = new FileFileterImp1();public static void main(String[] args) {Scanner scn = new Scanner(System.in);System.out.println("请输入要查询的文件名字");String name = scn.next();// 赋值遍历条件i.setName(name);System.out.println("正在查找请稍后");File file = new File("E:\\Project\\JavaProject\\MyJavaStudy");fileSerch(file, name);System.out.println("查询结果:" + resultPath);}public static String fileSerch1(File dir, String name) {try {File[] dirs = dir.listFiles(i);for (File s : dirs) {if (s.isDirectory()) {fileSerch1(s, name);} else {resultPath = s.getAbsolutePath();break;}}} catch (Exception e) {e.printStackTrace();}return resultPath;}
}

内部类方式

public static String fileSerch2(File dir, String serchName) {try {File[] dirs = dir.listFiles(new FilenameFilter() {@Overridepublic boolean accept(File dir, String name) {if(new File(dir,name).isDirectory()||name.equals(serchName)) {return true;}return false;}});for (File s : dirs) {if (s.isDirectory()) {fileSerch2(s, serchName);} else {resultPath = s.getAbsolutePath();break;}}} catch (Exception e) {e.printStackTrace();}return resultPath;}

Lambda

public static String fileSerch3(File dir, String serchName) {try {File[] dirs = dir.listFiles(( file, name) ->  new File(file,name).isDirectory()||name.equals(serchName));for (File s : dirs) {if (s.isDirectory()) {fileSerch3(s, serchName);} else {resultPath = s.getAbsolutePath();break;}}} catch (Exception e) {e.printStackTrace();}return resultPath;}

4.4.13、IO流

4.4.13.1、字节流

4.4.13.1.1、字节输出流 (OutputStream 抽象类是所有字节输出流的超类)

定义了一些基本共性方法
public void close() 关闭此输出流并释放与此流相关联的任何系统资源
public void flush() 刷新此输出流并强制任何缓冲的输出字节被写出
public void write(byte[] b) 将b.length字节从指定的字节数组写入此输出流
public void write(byte [] b,int off,int len) 从指定的字节数组写入len字节,从偏移量off 开始输出到此输出流
public abstract void write(int b) 将指定的字节输出流

字节流子类FileOutputStream (文件字节输出流)
作用:把内存中的数据写入到硬盘的文件中

构造方法
FileOutputStream (String name) 创建一向具有指定名称的文件中写入数据的输出文件流
FileOutputStream (File file) 创建一向具有指定File对象表示的文件中写入数据的输出文件流
   参数
   String name :目的地是一个文件的路径
   File file :目的地是一个文件

追加写/续写:两个构造方法
FileOutputStream(String name ,boolean append)创建一个向具有指定name的文件中写入数据的输出文件流
FileOutputStream(String name ,boolean append)创建一个像具有指定File对象表示的文件中写入数据的输出文件流
   参数
   name file:写入数据目的地
   append追加写开关,true 创建对象不会覆盖源文件,继续在文件的末尾追加写数据

写换行
windows:\r\n
Linux: /n
mac :/r

字节输出流的使用步骤(子类FIleOutputStream 举例)
1、创建一个FIleOutputStream 对象,构造方法中传入写入数据的目的地
2、调用FIleOutputStream 对象中的方法write 把数据写入到文件中
3、释放资源

package com.myStudy.demo1;import java.io.FileOutputStream;
import java.io.IOException;public class DemoFileOUtputStream {public static void main(String[] args) {fileOutputStream1();}public static void fileOutputStream1() {FileOutputStream fos1 = null;try {fos1 = new FileOutputStream("FilesSouse\\1.txt");// 可以是相对路径// 单个字节写入fos1.write(97);// 多个字节写入String a = "你好";byte[] b1 = a.getBytes();fos1.write(b1);//z指定写入位置和长度String a1 = "123";byte[] b2 = a1.getBytes();fos1.write(b2,1,1);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {try {if (fos1 != null) {fos1.close();}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
}
4.4.13.1.2、字节输入流 (InputStream 抽象类是所有字节输入流的超类)

定义了一些基本共性方法
colse() 关闭此输入流并释放与此流相关联的任何系统资源
public int read() 从输入流中读取数据的下一个字节 没有返回-1
public int read(byte [] b) 从输入流中读取一定数量的字符,并将其存储到缓冲区数组b中

字节流子类FileInputStream (文件字节输入流)
作用:ba’yi把硬盘文件中的数据,读取到内存中使用

构造方法
FIleInputStream (String name) 创建一个FIleInputStream 对象,指定到要读取的文件
FIleInputStream (File file)创建一个FIleInputStream 对象,指定到要读取的文件

字节输入流的使用步骤(子类FIleInputStream 举例)
1、创建一个FIleInputStream 对象,构造方法中绑定要读取的数据源
2、调用FIleInputStream 对象中的方法read 读取数据
3、释放资源

package com.myStudy.demo1;import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;public class DemoFileInputStream {public static void main(String[] args) {//fileInputStream1();fileInputStream2();}//单个字节读取public static void fileInputStream1() {FileInputStream fos1 = null;Reader read1 = null;try {fos1 = new FileInputStream("FilesSouse\\1.txt");// 可以是相对路径read1 = new InputStreamReader(fos1, "gbk");// 解决中文乱码 (转换流)txt保存成了ansi格式,指定码表gbkint len = 0;while ((len = read1.read()) != -1) {System.out.println((char) len);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if (fos1 != null) {try {fos1.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if (read1 != null) {try {read1.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}// 多个字节读取public static void fileInputStream2() {FileInputStream fos1 = null;try {fos1 = new FileInputStream("FilesSouse\\1.txt");// 可以是相对路径byte[] by1 = new byte[10];int len = 0;while ((len = fos1.read(by1)) != -1) {System.out.println(new String(by1,0,len));}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if (fos1 != null) {try {fos1.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
}
4.4.13.1.3、字节缓冲输入流(BufferedInputStream )

BufferedInputStream extends InputStream
继承来自父类的共性方法

构造方法
BufferedInputStream (InputStream in)创建一个新的缓冲输入流,并保存期参数,及in ,以便后面使用
BufferedInputStream (InputStream in,int size)创建一个指定大小新的缓冲输入流,并保存期参数,及in ,以便后面使用
   参数
   InputStream in:字节输入流
      我们可以传递FileInputStream ,缓冲区会给FileInputStream 增加一个缓冲区,提高效率
   int sizi :指定缓冲流内部缓冲区大小,不指定默认

使用步骤(FileInputStream 举例)
1、创建FileInputStream ,构造方法中绑定要读取的数据源
2、创建BufferedInputStream 对象,传递FileInputStream 对象
3、使用BufferedInputStream 对象中的read方法,读取文件
4、释放资源

public static void fileInputStream2() {BufferedInputStream bis1=null;try {FileInputStream fos1 = new FileInputStream("FilesSouse\\1.txt");// 可以是相对路径bis1=new BufferedInputStream(fos1);byte[] by1 = new byte[10];int len = 0;while ((len = bis1.read(by1)) != -1) {System.out.println(new String(by1,0,len));}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if (bis1 != null) {try {bis1.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
4.4.13.1.4、字节缓冲输出流(BufferedOutputStream )

BufferedOutputStream extends OutputStream
继承来自父类的共性方法

构造方法
BufferedOutputStream (OutputStream out)创建一个新的缓冲输出流,已将数据写入指定的底层输出流
BufferedOutputStream (OutputStream out,int size)创建一个新的缓冲输出流,已将指定的缓冲区大小的数据写入指定的底层输出流
   参数
   OutputStream out :字节输出流
      我们可以传递FileOutputStream ,缓冲区会给FileOutputStream 增加一个缓冲区,提高效率
   int sizi :指定缓冲流内部缓冲区大小,不指定默认

使用步骤(FileOutputStream举例)
1、创建FileOutputStream,构造方法中绑定要输出的目的地
2、创建BufferedOutputStream 对象,传递FileOutputStream对象
3、使用BufferedOutputStream 对象中的write方法,把数据写入缓冲区
4、BufferedOutputStream 对象中的flush刷新到文件中
5、释放资源(会先调用flush,第4步可以省略)

package com.myStudy.demo1;import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class DemoFileOUtputStream {public static void main(String[] args) {fileOutputStream1();}public static void fileOutputStream1() {BufferedOutputStream buf1 = null;try {FileOutputStream fos1 = new FileOutputStream("FilesSouse\\1.txt");// 可以是相对路径buf1 = new BufferedOutputStream(fos1);// 单个字节写入buf1.write(97);// 多个字节写入String a = "你好";byte[] b1 = a.getBytes();buf1.write(b1);// z指定写入位置和长度String a1 = "1234";byte[] b2 = a1.getBytes();buf1.write(b2, 1, 3);//buf1.flush();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {try {if (buf1 != null) {buf1.close();}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
}

4.4.13.2、字符流

4.4.13.2.1、字符输入流 (Reader抽象类是所有字符输入流的超类)

定义了一些基本共性方法
colse() 关闭此输入流并释放与此流相关联的任何系统资源
public int read() 从输入流中读取数据的下一个字节 没有返回-1
public int read(char[] cbuf) 从输入流中读取一定数量的字符,并将其存储到缓冲区数组b中

字符流子类FileReader (文件字符输入流)
作用:ba’yi把硬盘文件中的数据,读取到内存中使用
FileReader extedns InputStreamReaderr extends Reader

构造方法
FileReader (String name) 创建一个FileReader 对象,指定到要读取的文件
FileReader (File file)创建一个FileReader 对象,指定到要读取的文件

字符输入流的使用步骤(子类FileReader 举例)
1、创建一个FileReader 对象,构造方法中绑定要读取的数据源
2、调用FileReader 对象中的方法read 读取数据
3、释放资源

package com.myStudy.demo1;import java.io.FileReader;
import java.io.IOException;public class DemoFileReader {public static void main(String[] args) {fileReader1();//fileReader2();}//单个字节读取public static void fileReader1() {FileReader fos1 = null;try {fos1 = new FileReader("FilesSouse\\1.txt");// 可以是相对路径int len = 0;while ((len = fos1.read()) != -1) {System.out.println((char) len);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if (fos1 != null) {try {fos1.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}// 多个字节读取public static void fileReader2() {FileReader fos1 = null;try {fos1 = new FileReader("FilesSouse\\1.txt");// 可以是相对路径char[] by1 = new char[10];int len = 0;while ((len = fos1.read(by1)) != -1) {System.out.println(new String(by1, 0, len));}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if (fos1 != null) {try {fos1.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
}
4.4.13.2.2、字符输出流 (Writer抽象类是所有字符输出流的超类)

定义了一些基本共性方法
public void close() 关闭此输出流并释放与此流相关联的任何系统资源(要先刷新)
public void flush() 刷新改流缓冲
public void write(String str) 写入字符串
public void write(String str,int off,int len) 写入字符串的一部分,off字符串为开始索引,字符串个数为len
public abstract void write(char[] cbuf ,int off,int len) 写入字符数组的一部分,off字符为开始索引,字符个数为len

字符流子类FileWriterr (文件字符输出流)
作用:把内存中的字符串数据写入到文件中
FileWriter extedns OutputStreamWriter extends Writer

构造方法
FileWriter (String name) 根据指定的文件名构造一个FileWriter对象
FileWriter (File file)根据指定的File 对象构造一个FileWriter对象
续写、换行与字节输出流一样

字符输出流的使用步骤(子类FileWriterr举例)
1、创建一个FileWriterr对象,构造方法中绑定要写入数据的目的地
2、调用FileWriterr对象中的方法write把数据写入到内存中(字符转字节的过程)
3、使用flush ,把内存缓冲区的数据,刷新到文件中
4、colse()关闭流 释放资源(会先把内存中的缓冲数据刷新到文件中)

4.4.13.2.3、字符缓冲输入流(BufferedReader)

BufferedReader extends Reader
继承来自父类的共性方法

构造方法
BufferedReader(Reader in)创建一个新的缓冲输入流,并保存期参数,及in ,以便后面使用
BufferedReader(Reader in,int size)创建一个指定大小新的缓冲输入流,并保存期参数,及in ,以便后面使用
   参数
   InputStream in:字符输入流
      我们可以传递FileReader ,缓冲区会给FileReader 增加一个缓冲区,提高效率
   int sizi :指定缓冲流内部缓冲区大小,不指定默认

特有成员方法
void readLine() 读取一个文本行,读取一行数据,没有了返回null
使用步骤(FileReader 举例)
1、创建BufferedReader对象,传递FileReader 对象
2、使用BufferedReader对象中的read/readLine方法,读取文件
3、释放资源

package com.myStudy.demo1;import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;public class DemoFileReader {public static void main(String[] args) {fileReader1();//fileReader2();}//单个字节读取public static void fileReader1() {BufferedReader br1=null;try {br1=new BufferedReader(new FileReader("FilesSouse\\1.txt"));String len ;while ((len=br1.readLine())!= null) {System.out.println(len);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if (br1 != null) {try {br1.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}// 多个字节读取public static void fileReader2() {try(BufferedReader br1=new BufferedReader(new FileReader("FilesSouse\\1.txt"))) {      char[] by1 = new char[10];int len = 0;while ((len = br1.read(by1)) != -1) {System.out.println(new String(by1, 0, len));}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
4.4.13.2.4、字符缓冲输出流(BufferedWriter)

BufferedWriter extends Writer
继承来自父类的共性方法

构造方法
BufferedWriter (Writer out)创建一个新的缓冲字符输出流
BufferedWriter (Writer out,int size)创建一个使用给定大小的新的缓冲字符输出流
   参数
   Writer out :字符输出流
      我们可以传递FileWriter ,缓冲区会给FileWriter增加一个缓冲区,提高效率
   int sizi :指定缓冲流内部缓冲区大小,不指定默认

特有的成员方法
void newLine() 写入一个行分隔符。会根据不同的操作系统,获取不同的行分隔符。

使用步骤(FileWriter 举例)

1、创建BufferedWriter 对象,传递FileWriter 对象
3、使用BufferedWriter 对象中的write方法,把数据写入缓冲区
4、BufferedWriter 对象中的flush刷新到文件中
5、释放资源

package com.myStudy.demo1;import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;public class DemoBufferedWirter {public static void main(String[] args) {fun1();}public static void fun1() {//测试使用JDK7新特性try (BufferedWriter bw1 = new BufferedWriter(new FileWriter("FilesSouse\\1.txt"))) {for (int i = 0; i < 10; i++) {bw1.write("荒野乱斗");bw1.newLine();}bw1.flush();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}

4.4.13.3、缓冲流原理

具体使用见上方流知识点中的缓冲流

4.4.13.4、转换流

4.4.13.4.1、字符编码、字符集

编码:字符–》字节
解码:字节–》字符
字符编码:就是一套自然语言字符和二进制数之间的对应规则
编码表:生活中文字和计算机中二进制的对应规则





4.4.13.4.2、OutputStreamWriter

OutputStreamWriter extends Writer
继承来自父类的共性方法

构造方法
OutputStreamWriter(OutputStream out)创建一个使用默认字符编码的OutputStreamWriter
OutputStreamWriter (OutputStream out,String charsetName)创建一个使用指定字符编码(charsetName)的OutputStreamWriter
   参数
   OutputStream out :字节输出流
      可以用来写转换后的字节到文件中
   String charsetName :指定的编码名称,不区分大小写
使用步骤
1、创建OutputStreamWriter对象,构造方法中传递字节输出流和指定编码表名称
2、使用OutputStreamWriter中的write,把字符转换为字节存储到缓冲区中(编码)
3、使用OutputStreamWriter中的flush,写入
4、释放资源

4.4.13.4.3、InputStreamReader

InputStreamReader extends Reader
继承来自父类的共性方法

构造方法
InputStreamReader (InputStream in)创建一个使用默认字符编码的InputStreamReader
InputStreamReader (InputStream in,String charsetName)创建一个使用指定字符编码(charsetName)的InputStreamReader
   参数
   OutputStream out :字节输入流
      可以用来读取文件中保存的文件
   String charsetName :指定的编码名称,不区分大小写
使用步骤
1、创建InputStreamReader 对象,构造方法中传递字节输入流和指定编码表名称
2、使用OutputStreamWriter中的read,读取文件(解码)
3、释放资源

4.4.13.4、序列化流

序列化反序列化概述

注意
1、必须实现Serializable接口
2、readObject抛出ClassNotFoundException
3、static 修饰的成员变量不能被序列化(静态优先于非静态加载到内存中)
4、transient (瞬态关键字) 不能被序列化,可以用来做特定成员变量不序列化

4.4.13.4.1、对象序列化流 (ObjectOutputStream)

ObjectOutputStream extends OutputStream
作用:把对象以流的方式写入到文件中保存

构造方法
ObjectOutputStream(OutputStream out)创建写入指定OutputStream 的ObjectOutputStream
   参数
   OutputStream out :字节输出流

特有的成员方法
void writeObject(Object obj) 将指定的对象写入ObjectOutputStream

使用步骤
1、创建ObjectOutputStream对象,构造方法中传递字节输出流2、使用writeObject,把对象写入到文件中
3、释放资源

package com.myStudy.demo1;import java.io.Serializable;
//序列化、反序列化,必须继承Serializable接口
public class Person implements Serializable {private String  name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person [name=" + name + ", age=" + age + "]";}}
package com.myStudy.demo1;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;public class DemoObjectOutputStream {public static void main(String [] args) throws IOException {objectOutputStreamFun1();}public static void objectOutputStreamFun1() throws IOException {ObjectOutputStream  oos1=new ObjectOutputStream(new FileOutputStream("FilesSouse\\person.txt") );oos1.writeObject(new Person("张三",18));oos1.close();}}
4.4.13.4.2、对象反序列化流 (ObjectInputStream)

ObjectInputStream extends InputStream
作用:把对象以流的方式写入到文件中保存

构造方法
ObjectInputStream (InputStream in)创建从指定InputStream 读取的ObjectInputStream
   参数
   InputStream in :字节输入流

特有的成员方法
void readObject() 读取对象

使用步骤
1、创建ObjectInputStream对象,构造方法中传递字节输入流2、使用readObject,读取保存对象的文件
3、释放资源
4、使用读取的出来的对象

package com.myStudy.demo1;import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
//readObject抛出ClassNotFoundException,当不存在Person时会抛出
public class DemoObjectInputStream {public static void main(String [] args) throws IOException, ClassNotFoundException {objectInputStreamFun1();}public static void objectInputStreamFun1() throws IOException, ClassNotFoundException {ObjectInputStream  oos1=new ObjectInputStream(new FileInputStream("FilesSouse\\person.txt") );Object o= oos1.readObject();oos1.close();System.out.println(o);Person p=(Person)o;System.out.println(p.getName()+p.getAge());}
}
4.4.13.4.3、解决修该成员类 序列号变化导致反序列化失败(InvalidClassException)

static final long serialVersionUID=42L;

4.4.13.5、JDK7、JDK9 流相关新特性

JDK7新特性
try后面可以增加一个(),在括号内可以定义流对象
那么这个流对象的作用域就在try中有效。
try代码执行完毕,会自动把流对象释放。不用写finally
格式:
try(定义流对象;定义流对象…){
}catch(){}

JDK9新特性
try后面可以增加一个(),在括号内可以直接引入流对象名称
那么这个流对象的作用域就在try中有效。
try代码执行完毕,会自动把流对象释放。不用写finally
格式:
A a=new A();
B b=new B();
try(a,b){
}catch(){}

4.4.13.6、Properties配置文件

已过时的Hashtable的Properties集合
持久的属性集,可以保存在流中或从流中加载

Properties集合是一个唯一和IO流相结合的集合
  store:把结合中的临时数据,持久化写入到硬盘中存储
  void store(OutputStream out,String commentes)
  void store(Writer writer,String commentes)
    commentes :注释,用来解释说明保存的文件是做什么用的(不能使用中文,默认unicode ,一般使用“”)

  load:把硬盘中保存的文件(键值对),读取到集合中使用
  void load(InputStream in )
  void load(Reader reader)

属性列表中每个键及其中对应的值是一个字符串
  Properties集合是一个双列集合,key和value默认都是字符串

Properties集合中的一些操作字符串的特有方法
Objiect setProperty(String key,String value) 调用Hashtable的put
String getProperty(String key) 通过key找到value,此方法相当于Map中的get方法
Set stringPropertyNames() 返回此属性列表中的键集

注意
1、存储键值对的文件中,键与值默认的连接符可以使用=,空格,其他符号
2、存储键值对的文件中,可以使用#注释
3、存储键值对的文件中,键与值已经是字符串了,不用加双引号

package com.myStudy.demo1;import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;public class Reflect {public static void main(String[] args) throws Exception {// TODO Auto-generated method stubProperties pro = new Properties();//获取class目录下的配置文件ClassLoader cld=Reflect.class.getClassLoader();InputStream is=cld.getResourceAsStream("pro.properties");pro.load(is);String className=pro.getProperty("className");System.out.println(className);String methodName=pro.getProperty("methodName");System.out.println(methodName);}}

4.4.14、网络编程

4.4.14.1、网络编程基础知识点

4.4.14.1.1、软件结构

B/S :浏览器程序+服务端程序
C/S:客户端程序+服务端程序

4.4.14.1.2、网络通信协议

4.4.14.1.3、协议分类

UDP(用户数据报协议)

数据报:网络传输的基本单位

UDP是无连接通信协议,即在数据传输是,数据发送端和数据接收端建立逻辑连接。当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发送数据。同样接收端在收到数据时,也不会向发送端反馈是否收到数据

UDP协议消耗资源小,通信效率高。所以通常用于音频,视频和普通数据传输,例如视频会议。
UDP是面向无连接性,不能保证数据的完整性
特点:数据被限制在64K以内,超出这个范围就不能发送了

TCP(传输控制协议)

TCP协议是面向连接的通信协议。在传输数据之前,建立逻辑连接,然后再传输数据。它提供了两台计算机之间可靠无差错的数据传输。
三次握手:保证连接的可靠,客户端和服务器之间的三次交互
第一次握手:客户端向服务器发出连接请求,等待服务器确认
第二次握手:服务器端向客户端回送一个响应,通知客户端收到了连接请求
第三次握手:客户端再次向服务器端发送确认信息,确认连接

4.4.14.1.4、网络编程三要素

协议
计算机网络通信必须遵守的规则。上面以介绍

IP地址
互联网协议地址
IP地址分类

  • IPv4:一个32位的二进制,通常被分为4个字节,表示成a.b.c.d的形式,其中abcd都是0-255之间的十进制数,那么最多可以表示42亿个
  • IPv6:由于互联网的蓬勃发展,ip地址需求量越来越大,但是网络地址资源有限。使得ip的分配越发紧张。为了扩大地址空间,拟通过ipv6重新定义地址空。采用128位的地址长度,每16个字节一组。分成8组十六紧进制数。表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789,号称可以为全世界的每一粒石子编上一个网址

端口号
是一个逻辑端口,我们无法直接看到,可以使用一些软件查看端口号。
当我们使用网络软件一打开,那么操作系统就会为网络软件分配一个随机的端口号或者网络软件在打开的时候和系统要指定的端口号。
端口号是由两个字节组成,取值范围在0-65535之间
注意
1024之前的端口号我们不能使用,已经被系统分配给已知的网络软件了。网络软件的端口号不能重复
例:qq 5000 , 飞秋 6000 ,msn 7000

常用端口号
1、80端口:网络端口 www.baiudu.com:80
2、mysql :3306 oracle:1521
3、tomcat:8080

4.4.14.2、TCP通信

TCP通信能实现两台计算机之间的数据交互,通信的两端要严格区分客户端和服务端

两端通信步骤
1、服务端程序,需要事先启动,等待客户端的连接
2、客户端主动连接服务器,连接成功才能通信。服务端不可以 主动连接客户端

实现原理图

4.4.14.2.1、TCP通信客户端

Socket
实现客户端套接字,套接字是两台机器间通信的端点。
套接字:包含了IP地址和端口的网络单位

构造方法
Socket(String host ,int port) 创建一个流套接字并将其连接到指定主机上的指定端口。
   参数:
  String host :服务器 主机的名称或者IP地址
  int portt:服务器的端口号

成员方法
OutputStream getOutputStream() 返回此套接字的输出流
InputSteam getInputStream() 返回此套接字的输入流
void close() 关闭此套接字

实现步骤
1、创建一个客户端端对象Socket,构造方法绑定服务器的ip地址和端口号
2、使用getOutputStream 获取网络字节输出流对象
3、使用网络字节输出流的write ,给服务器发送数据
4、使用Socket对象中的getInputStream获取网络字节输入流对象
5、使用网络字节输入流对象中的read,读取服务器回写的数据
6、释放socket资源

注意:
1、客户端和服务器进行交互,必须使用Socket中提供的网络流,不能使用自己创建的流对象
2、当我们创建客户端对象的时候,就会去请求服务器和服务器经过3次握手建立连接通路。
这时如果服务器没有启动,那么就会抛出异常。如果已经启动就可以进行交互

package com.myStudy.demo1;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;public class TcpClient {public static void main(String [] args) throws  IOException {//1、创建一个客户端端对象Socket,构造方法绑定服务器的ip地址和端口号Socket socket= new Socket("127.0.0.1",8888);//2、使用getOutputStream 获取网络字节输出流对象OutputStream o=socket.getOutputStream();//3、使用字节输出流的write ,给服务器发送数据o.write("你好服务器".getBytes());//4、使用Socket对象中的getInputStream获取输入流对象InputStream i=socket.getInputStream();byte [] by =new byte[1024];//5、使用输入流对象中的read,读取服务器回写的数据int len=i.read(by);System.out.println("服务器回传数据"+new String(by,0,len));//6、释放socket资源socket.close();}}
4.4.14.2.2、TCP通信服务端

ServerSocket
实现服务端套接字。

构造方法
ServerSocket(nt port) 创建绑定到特定的端口的服务器套接字
   参数:
  int portt:服务器指定的端口号
服务器必须明确一件事情,必须的得知道是哪个客户端请求的服务器,所以可以使用accept 获取到请求的客户端对象Socket

成员方法
Socket accept() 侦听并接受到此套接字的连接。

实现步骤
1、创建一个服务端对象ServerSocket,指定端口号
2、使用accept 获取请求的客户端对象Socket
3、使用Socket对象中的getInputStream获取网络字节输入流对象
4、使用网络字节输入流对象中的read,读取客户端发送的数据
5、使用Socket对象中的方法getOutputStream获取网络字节输出流对象
6、使用网络字节输出流的write,给客户端回写数据
7、释放Socket、ServerScoket资源

package com.myStudy.demo1;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class TcpServer {public static void main(String[] args) throws IOException {// 1、创建一个服务端对象ServerSocket,指定端口号ServerSocket sSocket = new ServerSocket(8888);// 2、使用accept 获取请求的客户端对象SocketSocket so = sSocket.accept();// 3、使用Socket对象中的getInputStream获取输入流对象InputStream in = so.getInputStream();// 4、使用输入流对象中的read,读取客户端发送的数据byte[] by = new byte[1024];int len = in.read(by);System.out.println(new String(by, 0, len));// 5、使用Socket对象中的方法getOutputStream获取输出流对象OutputStream out = so.getOutputStream();// 6、使用输出流的write,给客户端回写数据out.write("收到谢谢".getBytes());// 7、释放Socket、ServerScoket资源so.close();sSocket.close();}
}

4.4.14.2、综合案例 文件上传

package com.myStudy.demo1;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;public class TcpServer {public static void main(String[] args) throws IOException {String uploadFloerName = "upload";File file = new File(uploadFloerName);if (!file.exists()) {file.mkdir();}ServerSocket sSocket = new ServerSocket(8888);// 持续监听while (true) {String fileName = System.currentTimeMillis() + new Random().nextInt(999999) + ".jpg";FileOutputStream fout = new FileOutputStream(uploadFloerName + "\\" + fileName);Socket so = sSocket.accept();// 开始线程跑上传操作,提高效率new Thread(new Runnable() {@Overridepublic void run() {try {InputStream in = so.getInputStream();byte[] by = new byte[1024];int len = 0;while ((len = in.read(by)) != -1) {fout.write(by);}OutputStream out = so.getOutputStream();out.write("上传成功!".getBytes());// sSocket.close();} catch (IOException e) {// TODO: handle exceptione.printStackTrace();} finally {if (so != null) {try {so.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}).start();}}
}
package com.myStudy.demo1;import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;public class TcpClient {public static void main(String [] args) throws  IOException {//上传本地数据FileInputStream fin =new FileInputStream("FilesSouse\\1.jpg");Socket socket= new Socket("127.0.0.1",8888);OutputStream o=socket.getOutputStream();byte [] by1=new byte[1024];int len=0;while((len=fin.read(by1))!=-1){o.write(by1);}//解决阻塞问题socket.shutdownOutput();//服务器返回接受结果InputStream i=socket.getInputStream();while((len=i.read(by1))!=-1){System.out.println("上传状态:"+new String(by1,0,len));}       socket.close();}}

4.4.14.3、BS结构TCP通信(扩展)

4.4.15、函数式接口

概念
函数式接口在java中是指:有且仅有一个抽象方法的接口。

函数式接口,即适用于函数式编程场景的接口。而java中函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,java中的Lambda 才能顺利地进行推导。

格式
修饰符 interface 接口名称{
public abstract 返回值类型 方法名称(可选参数信息)

@Functionallnterface注解
与@Override 注解的作用类似,Java8中专门为函数式接口引入一个新的注解@Functionallnterface 用于接口的定义

作用:检测接口是否是一个函数式接口

package com.myStudy.demo1;@FunctionalInterface
public interface DemoFunctionallnterface {public abstract void method() ;
}
package com.myStudy.demo1;public class DemoFunctionallnterfaceTest {public static void show(DemoFunctionallnterface df) {df.method();}public static void main(String[] args) {//方法1show(new DemoFunctionallnterface() {@Overridepublic void method() {// TODO Auto-generated method stubSystem.out.println("使用匿名内部类重写接口中的抽象方法");}});//方法2 Lambdashow(() -> {System.out.println("使用匿名内部类重写接口中的抽象方法");});//Lambda简写 {}中只有一行代码的情况 {}、;可以去掉show(() -> System.out.println("使用匿名内部类重写接口中的抽象方法"));}
}

Lambda 特点
延时加载

常用函数式接口

1、Supplier
Supplier接口被称为生产型接口,T是什么类型,get就会生产什么类型的数据

T get() 获取一个泛型参数指定类型的对象数据

package com.myStudy.demo1;import java.util.function.Supplier;
//利用Supplier 获取数组中的最大值
public class DemoSupplier {public static int getMax(Supplier<Integer> sup) {return sup.get();}public static void main(String[] args) {int [] arr= {1,5,7,3,2};int maxvalue=getMax(()->{int max=arr[0];for(int i:arr) {if(i>max) {max=i;}}return max;});System.out.println(maxvalue);}}

2、Consumer
Consumer接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据。其数据类型由泛型决定。

Consumer接口是一个消费型接口,泛型执行什么数据类型,就可以使用accept方法消费什么类型的数据

void accept(T t) 为消费者指定泛型的数据

默认方法
addThen 需要两个Consumer接口,可以把两个Consumer接口组合到一起,在对数据进行消费

package com.myStudy.demo1;import java.util.function.Consumer;
//格式化打印信息 姓名:XX 年龄::yy
public class DemoConsumer {public static void method(String [] arr, Consumer<String> con1, Consumer<String> con2) {for(String message:arr) {con1.andThen(con2).accept(message);}}public static void main(String[] args) {String [] array={"张三,男","李四,女","王五,男","赵六,男"};method(array, (message) -> {String name=message.split(",")[0];System.out.print("姓名:"+name);}, (message) -> {String name=message.split(",")[1];System.out.println("  年龄:"+name);});}
}

3、Predicate
Predicate 对某种数据类型的数据进行判断,结果返回一个boolean值

boolean test用来对指定数据类型数据进行判断的方法

默认方法
and:表示并且关系,也可以用于连接两个判断条件

default Predicate and (Predicate<? super T> other ){Objects.requireNonNull(ohrer));
returm(t)->this.test(t)&& other.test(t);}

or:表示或关系,也可以用于连接两个判断条件

default Predicateor(Predicate<? super T> other ){Objects.requireNonNull(ohrer));
returm(t)->this.test(t)|| other.test(t);}

package com.myStudy.demo1;import java.util.function.Predicate;public class DemoPredicate {public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2) {// and// return pre1.test(s)&&pre2.test(s);// return pre1.and(pre2).test(s);// or// return pre1.test(s)||pre2.test(s);return pre1.or(pre2).test(s);}public static void main(String[] args) {String s = "adbcdef";boolean b = checkString(s, (String str) -> {return str.length() > 5;}, (String str) -> {return str.contains("B");});System.out.println(b);}
}

negate 取反
default Predicate negate(){
return(t)->! test(t);
}

4、Function
Function 根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件

R apply用来根据类型T的参数获取类型R的结果。使用的场景例如:将String 类型转换为Integer类型。

默认方法
andThen 用来进行组合操作

package com.myStudy.demo1;import java.util.function.Function;public class DemoFunction {public static void change(String s, Function<String, Integer> fun1, Function<Integer, String> fun2) {String ss = fun1.andThen(fun2).apply(s);System.out.println(ss);}public static void main(String[] args) {String s = "123";
//      change(s, (String str) -> {//          return Integer.parseInt(s);
//      }, (Integer i) -> {//          return i + "";
//      });change(s,  str -> Integer.parseInt(s),  i -> i + "");}}

4.4.16、Stream流

Lambda的衍生物
处理集合、数组
JDK1.8+
关注的是做什么,而不是怎么做

4.4.16.1、获取流

所有的Collection集合都可以通过stream默认方法获取流
default Steam stream()

Stream 接口的静态方法of可以获取数组对应的流
static Stream of(T… values)
参数是一个可变参数,那么我们就可以传递一个数组

package com.myStudy.demo1;import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;public class Demo1Stream {public static void main(String []args) {List<String> list =new ArrayList<String>();Stream<String> stream1=list.stream();Stream<Integer> stream =Stream.of(1,2,3,4,5);Integer [] i= {1,2,3,4,5};Stream<Integer> stream2 =Stream.of(i);}}

4.4.16.2、常用方法

1、forEach 循环
void forEach(Consumer<? super T> action)
该方法接收一个Consumer 接口函数,会将每一个流元素交给该函数进行处理
该方法是一个终结方法,遍历以后不能继续调用Stream流中的其他方法

public static void main(String []args) {Stream<Integer> stream =Stream.of(1,2,3,4,5);//stream.forEach((s)->{System.out.println(s);});stream.forEach(s->System.out.println(s));}

2、filter 过滤
Stream filter(Predicate<? super T> predicate)
对数据进行过滤
注意:
Steam 流属于管道流,只能被消费一次
第一个流调用完毕,数据就会转流到下一个流上。第一个流会关闭

public static void main(String []args) {     Stream<Integer> stream =Stream.of(1,2,3,4,5);Stream<Integer> stream1=stream.filter(i-> i>2 );stream1.forEach(i->System.out.println(i));}

3、map 映射
Stream map (Function<? super T, ? extend R>,mapper)
该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另外一种R类型数据的流

public static void main(String []args) {     Stream<Integer> stream =Stream.of(1,2,3,4,5);Stream<String> stream1= stream.map((Integer i)->{return i+"";});stream1.forEach(str->System.out.println(str));}

3、skip 跳过
Stream skip (long n)
如果流当前的长度大于n,则跳过前n个,否则将会得到一个长度为0的流

public static void main(String []args) {     Stream<Integer> stream =Stream.of(1,2,3,4,5);Stream<Integer> stream1= stream.skip(3);stream1.forEach(i->System.out.println(i));}

4、limit 取用前几个
Stream limit (long n)
如果流当前的长度大于n,则取前n个,否则不操作

public static void main(String []args) {     Stream<Integer> stream1 =Stream.of(1,2,3,4,5);Stream<Integer> stream2=stream1.limit(3);stream2.forEach(i->System.out.println(i));}

5、concat 组合
static Stream concat(Stream<? extends T> a,Stream<? extends T> b)
用于把流组合到一起

public static void main(String []args) {     Stream<Integer> stream1 =Stream.of(1,2,3,4,5);Stream<Integer> stream2 =Stream.of(3,4,5,6,7);Stream<Integer> stream3 =Stream.concat(stream1,stream2);stream3.forEach(i->System.out.println(i));}

6、count 统计Stream流中的元素个数
Long count ()
count 是一个终结方法,返回值是一个Long类型的整数

public static void main(String []args) {     Stream<Integer> stream1 =Stream.of(1,2,3,4,5);System.out.println(stream1.count());}

4.4.17、方法引用

Lambda表达式的代码优化,解决Lambda冗余

双冒号为引用运算符,而他所在的表达式称为方法引用,如果Lambda要表达的函数方法已经存在于某个方法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者

1、方法引用_成员方法

package com.myStudy.demo1;public class MethodRerObject {//定义一个成员方法public void printUpperCaseString(String str) {System.out.println(str.toUpperCase());}
}
package com.myStudy.demo1;@FunctionalInterface
public interface Printable {void print(String s);
}
 package com.myStudy.demo1;public class DemoObjectMethodReference {public static void printString(Printable p) {p.print("Hello");
}
public static void main(String []args) {//LambdaprintString((s)->{MethodRerObject obj=new MethodRerObject();obj.printUpperCaseString(s);});//引用方法写法MethodRerObject obj1=new MethodRerObject();printString(obj1::printUpperCaseString);
}
}

2、方法引用_静态成员方法

 package com.myStudy.demo1;public class DemoObjectMethodReference {public static void printString(Printable p) {p.print("Hello");
}
public static void main(String []args) {//LambdaprintString((s)->{MethodRerObject.printUpperCaseString(s);});//引用方法printString(MethodRerObject::printUpperCaseString);
}
}

3、方法引用_父类成员方法

 printString(super::父类成员方法名);

3、方法引用_本类成员方法

 printString(this::本类成员方法名);

4、方法引用_构造方法(构造器)

 printString(类名::new);

5、方法引用_数组构造器

 printString(数组长度,数据类型[]::new);

4.4.18、Junit单元测试

测试分类
1、黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值
2、白盒测试,需要写代码。关注程序具体的执行流程

Junit 使用:白盒测试
步骤
1、定义一个测试类
建议:
测试类名 :被测试的类名Test
包名:xxx.xxx.xx.test

2、定义测试方法:可以独立运行
建议:
方法名:test测试的方法名
返回值:void
参数列表:空参

3、给方法加@Test 注解
4、导入Junit依赖环境
结果
5、断言 Assert.assertEquals(期望的结果,运算的结果)

注解:
@Before
初始化方法,用于资源申请,所有测试方法在执行之前都会先执行该方法
版本4 ,版本5改成了@BeforeEach

@After
释放资源方法,在所有测试方法执行完成后,都会自动执行该方法
版本4 ,版本5改成了@AfterEach

package com.myStudy.demo1;public class Calculator {public    int add(int a,int b) {return a+b;}
}
package com.myStudy.test;import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.jupiter.api.Test;import com.myStudy.demo1.Calculator;public class CalculatorTest {@BeforeEachpublic void init() {System.out.println("已经加载");}@AfterEcahpublic void close() {System.out.println("已经释放");}/*** 测试add*/@Testpublic void testAdd() {Calculator ca = new Calculator();int result = ca.add(1, 2);System.out.println("执行完成");Assert.assertEquals(3, result);}}

4.4.19、反射

反射是框架设计的灵魂
框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
反射:将类的各个组成部分封装成其他对象,这就是反射机制
   好处:
   1、可以在程序运行过程中,操作这些对象
   2、可以解耦,提高程序的可扩展性

获取Class 对象方式
获取Class对象
方法1:
Class 对象名=Class.forName(“全类名”);
多用于配置文件,将类名定义在配置文件中。读取文件,加载类

方法2:
Class 对象名 =类名.class;
多用于参数的传递

方法3:
Class 对象名 =类对象.getClass()
多用于对象的获取字节码的方式

注意: 同一个字节码文件(.class)在一次运行程序过程中,只会被加载一次,不论通过哪种方式获取Class对象都是同一个。

Class对象功能
*1、成员变量
     Field [] getFileds() 获取所有public修饰的成员变量
      Field getFiled(String name) 获取name这个public修饰的成员变量
      Field [] getDeclaredFileds() 获取所有的成员变量,不区分修饰符
      Field getDeclaredField(String name) 获取name这个成员变量的,不区分修饰符
      get(对象名) 获取成员变量值
      set(对象名,要设置的数据)设置成员变量值
      setAccessible(true) 忽略访问权限修饰符的全全检查(暴力反射)

*2、构造方法
      Constructor<?> [] getConstructors() 获取所有public修饰的构造方法
      Constructor getConstructor(类<?>…parameterTypes)获取指定类型的public修饰的构造方法
      Constructor<?> [] getDeclaredConstructors()获取所有构造方法
      Constructor getDeclaredConstructor(类<?>…parameterTypes)获取指定类型的构造方法
      newInstance 创建对象,空参创建可以简化Class.newInstance()
      setAccessible(true) 忽略访问权限修饰符的全全检查(暴力反射)

*3、成员方法
      Method [] getMethod s() 获取所有public修饰的成员方法
      Method getMethod (String name,类<?>…parameterTypes) 获取指定参数的public修饰的成员方法
      Method [] getDeclaredMethods() 获取所有的成员方法
      Method getDeclaredMethod(String name,类<?>…parameterTypes) 获取指定参数的成员方法
      invoke() 执行方法
      getName() 获取方法名
      setAccessible(true) 忽略访问权限修饰符的全全检查(暴力反射)

*4、获取类名
      String getName() 获取全类名

package com.myStudy.demo1;public class Person {private String name;private int age;public String a;public String b;public String getA() {return a;}public void setA(String a) {this.a = a;}public String getB() {return b;}public void setB(String b) {this.b = b;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}private Person(String name, int age, String a, String b) {super();this.name = name;this.age = age;this.a = a;this.b = b;}@Overridepublic String toString() {return "Person [name=" + name + ", age=" + age + ", a=" + a + ", b=" + b + "]";}public void eat() {System.out.println("空参public成员方法");}public void eat(String name) {System.out.println("1个参public成员方法"+name);}private void eat(String name,String name1) {System.out.println("2个参Private成员方法"+name+name1);}}
package com.myStudy.demo1;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class DemoClass {public static void main(String []args) throws Exception {//1、Class 对象名=Class.forName("全类名");Class cl=Class.forName("com.myStudy.demo1.Person");    System.out.println(cl);//2、Class 对象名 =类名.class;Class c2=Person.class; System.out.println(c2);//3、Class 对象名 =类对象.getClass()Person person= new Person();Class c3=person.getClass();  System.out.println(c3);//不论通过哪种方式获取Class对象都是同一个System.out.println(cl==c2);System.out.println(cl==c3);System.out.println(c2==c3);//获取成员变量Field [] fileds=c2.getFields();for(Field fil:fileds) {System.out.println(fil);}Field filed1=c2.getField("a");System.out.println(filed1);Field [] fileds1=c2.getDeclaredFields();for(Field fil:fileds1) {System.out.println(fil);}Field filed2=c2.getDeclaredField("age");System.out.println(filed2);//private 暴力反射filed2.setAccessible(true);filed2.set(person, 18);Object o1=filed2.get(person);System.out.println(o1);//获取构造方法Constructor [] con1=c2.getConstructors();for(Constructor con:con1) {System.out.println(con);}Constructor  con2=c2.getConstructor(String.class,int.class);System.out.println(con2);Object person1=con2.newInstance("张三",19);System.out.println(person1);//空参简写Object person2=c2.newInstance();System.out.println(person2);Constructor [] con3=c2.getDeclaredConstructors();for(Constructor con:con3) {System.out.println(con);}Constructor  con4=c2.getDeclaredConstructor(String.class,int.class,String.class,String.class);System.out.println(con4);//暴力反射con4.setAccessible(true);         Object person3=con4.newInstance("张三",19,"a","b");System.out.println(person3);//获取成员方法Method[] m1=c2.getMethods();for(Method m:m1) {System.out.println(m.getName());}Method m2=c2.getMethod("eat");m2.invoke(person);Method m3=c2.getMethod("eat",String.class);m3.invoke(person, "饭");Method[] m4=c2.getDeclaredMethods();for(Method m:m4) {System.out.println(m.getName());}Method m5=c2.getDeclaredMethod("eat");m5.invoke(person);Method m6=c2.getDeclaredMethod("eat",String.class,String.class);m6.setAccessible(true);m6.invoke(person, "饭","菜");//获取类名String o4=c2.getName();System.out.println(o4);
}
}

4.4.20、注解

概念:说明程序的。给计算机看的

定义:J注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

作用分类
①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
② 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

JDK内置注解

  • @Override 检测被该注解标注的方法是否是继承自父类(接口)的
  • @Deprecated 该注解标注的内容,表示已过时,但仍可以使用
  • @SuppressWarnings 压制警告 一般传递参数all @SuppressWarnings(“all”)

自定义注解

  • 格式:public @interface 注解名称{}
  • 本质:注解本质上就是一个接口,该接口默认继承Annotation接口
  • 属性:接口里面的抽象方法
          要求:
          1、属性的返回值类型
                基本数据类型
                String
                枚举
                注解
                以上类型的数组
          2、定义了属性,在使用时需要给属性赋值
                如果定义属性时,使用defalult关键字给属性默认初始化值,则使用注解时可以不进行属性的赋值
                如果只有一个属性需要赋值,并且属性的名称是value,z则使用时value可以省略,直接定义值即可
                数组赋值用{}包裹。如果数组中只有一个值,{}省略

元注解
用于用于描述注解的注解

  • @Target 描述注解能够作用的位置
        ElementType
            TYPE :可以作用于类上
            METHOD :可以作用于成员方法上
            FIELD:可以作用于成员变量上
  • @Retenttion 描述注解被保留的阶段
        RetentionPolicy
            SOURCE:不会保留到class字节码文件中
            CLASS:保留到class字节码文件中,但是不会被jvm读取到
            RUNTIME:保留到class字节码文件中,并被jvm读取到
  • @Documented 描述注解是(保留该注解)否(删除该注解)被抽取到api文档中
  • @Inherited 描述注解是(保留该注解)否(删除该注解)被子类继承

解析注解

package com.myStudy.demo1;import java.lang.reflect.Method;@Pro(className = "com.myStudy.demo1.ProDemo1", methodName = "show")
public class ReflectTest {public static void main(String[] args) throws Exception{// TODO Auto-generated method stub//1.解析注解//1.1获取该类的字节码文件对象Class<ReflectTest> ref=ReflectTest.class;//1.2.获取上边的注解对象,其实就是在内存中生成一个该注解接口的子类实现对象Pro pr=ref.getAnnotation(Pro.class);//1.3.调用注解对象中定义的抽象方法。获取返回值String className=pr.className();String methodName=pr.methodName();System.out.println(className);System.out.println(methodName);//2获取注解中定义的数据加载进内存Class cls=Class.forName(className);//3创建对象Object obj=cls.newInstance();//4获取方法对象Method method =cls.getMethod(methodName);//5执行方法method.invoke(obj);}}
package com.myStudy.demo1;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 操作配置文件*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro {String className();String methodName();
}
package com.myStudy.demo1;public class ProDemo1 {public void show() {System.out.println("com.myStudy.demo1--->ProDemo--->show");
}
}

案例简单的测试框架

package com.myStudy.demo1;import java.io.BufferedWriter;
import java.io.FileWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class CheckTest {public static void main(String[] args) throws Exception {Calculator cal= new Calculator();Class calss=cal.getClass();Method [] methods=calss.getMethods();BufferedWriter buf=new BufferedWriter(new FileWriter("FilesSouse/errCout.txt"));for(Method m:methods) {//判断是否有@Checkif(m.isAnnotationPresent(Check.class)) {try {m.invoke(cal);} catch (Exception e) {// TODO: handle exceptionbuf.write(m.getName()+"方法发生异常了");buf.newLine();buf.write("异常名称:"+e.getCause().getClass().getSimpleName());buf.newLine();buf.write("异常原因:"+e.getCause().getMessage());buf.newLine();}}}buf.close();}
}
package com.myStudy.demo1;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {}
package com.myStudy.demo1;public class Calculator {@Checkpublic void add() {System.out.println("1+0=" + (1 + 0));}@Checkpublic void sub() {System.out.println("1-0=" + (1 - 0));}@Checkpublic void mul() {System.out.println("1*0=" + (1 * 0));}@Checkpublic void div() {System.out.println("1/0=" + (1 / 0));}public void show() {System.out.println("永无bug");}
}

重拾JavaSE学习笔记相关推荐

  1. JavaSE学习笔记(持续更新)

    这里写目录标题 JavaSE学习笔记(持续更新) Java跨平台原理与核心机制 1.跨平台原理: 2.两种核心机制: JDK11的安装流程 Java程序开发的三个步骤(无编辑器版) Eclipse安装 ...

  2. 重拾强化学习的核心概念_强化学习的核心概念

    重拾强化学习的核心概念 By Hannah Peterson and George Williams (gwilliams@gsitechnology.com) 汉娜·彼得森 ( Hannah Pet ...

  3. 【JavaSE学习笔记】

    JavaSE学习笔记 一.java的基本语法 变量运算规则 编码情况1中l后面没有加L,默认是int变量 编码情况2中b1=b+1中的1默认是int型变量,会出错 string类型 string里面可 ...

  4. javaSE学习笔记01 入门篇

    javaSE学习笔记01 入门篇 java语言概述 Java背景知识 java是 美国 sun 公司 在1995年推出的一门计算机高级编程语言. java早期称为Oak(橡树),后期改名为Java. ...

  5. JavaSE学习笔记-Day1

    笔者是一名大二在读本科生,最近闲着无聊重拾起Java这门语言,看了些许教学视频后居然还觉得挺有意思,"情不知所起,一往而深".于是决心认真学习这门语言!由于身居科班,自然不是零基础 ...

  6. 重学前端-学习笔记-JavaScript对象

    说明 重学前端是程劭非(winter)在极客时间开的一个专栏,在此主要整理我的学习笔记.如有侵权,请联系我,谢谢. javascript对象特征 对象具有唯一标识性:完全相同的两个对象,也不是同一个对 ...

  7. 我的javaSE学习笔记

    layout: post title: "我的JAVASE自学笔记" date: 2019-05-18 20:23:25 +0800 我的JAVASE自学笔记 作者:吴甜甜 个人博 ...

  8. linux给数据库重命名,Linux学习笔记:mv移动或文件重命名

    mv命令是move的缩写,可以用来移动文件或者将文件改名(move (rename) files),是Linux系统下常用的命令,经常用来备份文件或者目录. 语法:mv 源文件 目标文件 视mv命令中 ...

  9. JavaSE学习笔记(一)基础知识

    本章包含内容有: java环境配置.注释.标识符.数据类型.类型转换.变量.常量.运算符.包机制.顺序结构.选择结构.循环结构.方法的定义和调用.命令行传参.可变参数. 点击这里查看更多JavaSE的 ...

最新文章

  1. 树上启发式合并问题 ---- D. Tree Requests [状态压缩+树上启发式合并]
  2. shell获取当前进程pid和上一个进程pid
  3. Spring Integration关键案例与现实生活场景
  4. 在maven本地仓库导入jar包
  5. 里面怎么打中文字_“标题党”英语应该怎么翻译?不要翻译成“title party”!...
  6. 是!“不会数据分析的,全是假程序员”!HR:太真实……
  7. jQuery Hello世界
  8. Python 如何从字符串中提取 URL 链接
  9. FFTW3在VS环境下的安装(亲测)
  10. python查看系统句柄数量_查看Linux某个进程打开的文件句柄(file descriptor)数量...
  11. eclipse如何导入okhttp 2.x源码
  12. cad计算机土方软件,土方计算软件FastTFT - 飞时达软件
  13. NTP-网络时间协议
  14. SolidWorks二次开发---简单的参数化示例
  15. arbexpress使用教程_信号发生器使用说明
  16. 【理科】2020年高考数学(第三章导数)考点与题型全归纳
  17. 安装夜深模拟器无法打开或进度条一直卡住解决方法
  18. 大三使用Turtle库画太极八卦图
  19. 【LeetCode】1405-最长快乐字符串
  20. 计算机设置了桌面显示为什么没有,电脑桌面没有图标怎么回事?如何解决?

热门文章

  1. 做知识付费平台网课系统你所需要知道的事
  2. bigemap+vue+electron做桌面端GIS开发(3D 版)
  3. 南邮的计算机学院地址,南京邮电大学校区有几个 地址是什么
  4. 计算机装固态硬盘会不会卡,装上SSD的电脑还是卡?只要2步即可彻底解决卡顿,电脑运行如飞!...
  5. SSM框架:springmvc实现图片的上传与图片上传路径的设置
  6. Win10 1909最新版OBS Studio录制黑屏怎么办?
  7. npm-adduser
  8. conda管理虚拟环境
  9. 去掉烦人的微软正版提示
  10. 2019人力资源管理师考试成绩查询发布信息(一周汇总)