Java学习笔记
参考链接:学习笔记:黑马程序员Java-基础篇(第一部分)-CSDN博客
1 Java安装
1.1 JDK安装
需要安装JDK(Java Development Kit : Java开发者工具包)Oracle 官网下载JDK
推荐下载,LTS:long-term support 长期支持版(JDK 8 、11、17、21)
1.2 JDK的组成
- JVM (Java Virtual Machine): Java虚拟机,真正运行Java程序的地方。
- 核心类库:Java自己写好的程序,给程序员自己的程序调用的。
- JRE (Java Runtime Environment): Java 的运行环境。
- JDK (Java Development Kit):Java开发工具包 (包括上面所有)。
1.3 配置JDK的环境变量
- 目前较新的JDk在安装时,会自动配置javac、java程序的路径到Path环境变量中。
- 较老版本的JDK不会自动配置,需要手动配置
- 建议为JDK再配置JAVA_ HOME环境变量
JAVA_HOME:是用于告诉操作系统JDK安装在了哪个位置(将来其他技术要通过这个环境变量找JDK)
例如:JAVA* HOME D:\develop\java \jdk-21 Path %JAVA* HOME%\bin
1.4 Java编译解释
1、打开命令行,切换到有java文件的路径
2、运行javac <文件名>.java, 可以生成<文件名>.class文件
3、运行java <类名>,运行java程序(必须与代码里所谓的类名称一致)
1.5 IDEA开发
步骤:
- project -> module -> package -> class
- 一个project中可以创建多个module
- 一个module中可以创建多个package
- 一个package中可以创建多个class
2 Java基础语法
Java功能的最小单元:方法
2.1 Java注释
- 单行注释
// 注释内容,只能写一行- 多行注释
/*
注释内容1
注释内容2
*/- 文档注释:
/**
注释内容
注释内容
*/2.2 关键字
2.2.1 概述
Java关键字就是被Java赋予了特定含义的英文单词。当我们在代码中写了关键字之后,程序在运行的时候,就知道要做什么事情了。
2.2.2 分类
Java 关键字是编程语言中预定义的具有特殊含义的词汇,这些关键字用于控制程序的结构、流程和行为
TIP
修饰符关键字:public、protected、private、static、final、abstract 访问控制关键字:public、protected、private、default(默认) 类、接口和包关键字:、class、interface、enum、package、import、extends、implements 方法关键字:void、return、this、super 流程控制关键字:if、else、switch、case、default、while、do、for、break、continue、return 异常处理关键字:try、catch、finally、throw、throws 逻辑关键字:true、false、null 其他关键字:new、instanceof、synchronized、transient、volatile、assert
2.3 字面量
2.3.1 概述
Java 字面量是程序中直接使用的常量值,它表示各种数据类型的固定值。字面量可以是整数、浮点数、字符、字符串等数据类型的常量值,它们在代码中直接出现,不需要进行计算或转换。
2.3.2 分类
1、整数字面量:表示整数值,可以使用十进制、八进制(以0开头)和十六进制(以0x或0X开头)表示法。例如:42, 012,0xFF。
2、浮点数字面量:表示浮点数值,包括普通的浮点数和科学计数法表示。例如:3.14, 2.0e-5。
3、字符字面量:表示单个字符,使用单引号括起来。例如:'A', '1', '@','露'。
4、字符串字面量:表示一个字符串,使用双引号括起来。例如:"Hello, World!", "Java"。
5、布尔字面量:表示布尔值,只有两个取值:true 和 false。
6、null 字面量:表示空引用,用于表示对象引用不指向任何有效的对象。
7、转义序列:一些特殊的字符序列,以反斜线 \ 开头,用于表示无法直接输入的字符,如换行符
\n、制表符 \t 等。
8、数组字面量:用花括号 {} 表示,用于初始化数组。例如:{1, 2, 3}。
9、枚举常量:枚举类型的常量值,表示枚举中的特定选项。
10、字符编码字面量:表示字符的Unicode编码,以 \u 开头,后面跟着四个十六进制数字。例如:\u0041 表示字符 'A'。
2.4 数据类型
2.4.1 概述
Java 数据类型是用来定义变量或表达式可以存储的数据类型的分类
2.4.2 分类
2.4.2.1 基本数据类型
1、整数类型(Integer Types):
byte:8位,范围为 -128 到 127、
short:16位,范围为 -32,768 到 32,767、
int:32位,范围为 -2^31 到 2^31 - 1、
long:64位,范围为 -2^63 到 2^63 - 1
2、浮点类型(Floating-Point Types):
float:32位,用于表示单精度浮点数、
double:64位,用于表示双精度浮点数
3、字符类型(Character Type):
char:16位,用于存储一个 Unicode 字符
4、布尔类型(Boolean Type):
boolean:用于表示布尔值,只有两个取值:true和false
2.4.2.2、引用数据类型
1、类(Class):类是用来创建对象的模板。它定义了对象的属性(成员变量)和方法(成员方法)。通过实例化类,可以创建类的对象,并使用对象调用类的方法。
2、接口(Interface):接口定义了一组方法的规范,但没有实际的方法体。类可以实现一个或多个接口,从而获得接口定义的方法,并在类中实现这些方法。
3、数组(Array):数组是一种用于存储相同类型元素的数据结构。它可以是一维数组或多维数组,用于在内存中连续存储多个元素。
4、枚举(Enum):枚举是一种特殊的类,用于表示一组预定义的常量。枚举常常用于表示一组相关的值。
5、字符串(String):字符串是一种引用数据类型,但它具有特殊的性质,可以像基本数据类型一样进行操作。字符串实际上是一个字符序列,它有许多方法用于处理字符串操作。
6、自定义引用类型:除了上述内置的引用数据类型,开发人员还可以创建自定义的类和接口,以及它们的实例,从而构建更复杂的数据结构和功能。
NOTE
基本数据类型:基本数据类型是按值传递的,它们在Java虚拟机栈中分配内存空间,并直接存储值本身。当基本数据类型的变量被赋值时,实际上是将该变量中的值复制到另一个变量中,这两个变量之间没有任何关联。
引用数据类型:引用数据类型是按引用传递的,它们在Java虚拟机堆中分配内存空间,存储的是对象的引用(内存地址)。当引用数据类型的变量被赋值时,实际上是将该变量中的引用复制到另一个变量中,这两个变量指向同一个对象。
2.4.3 数据类型转换
1、自动类型转换(小-->大)
类型范围小的变量,可以直接赋值给类型范围大的变量。
取值范围关系: byte < short (char) < int < long < float < double
byte、short、char三种类型的数据在运算的时候,都会直接先提升为int,然后再进行运算。
多种混合运算时,先转换成容量最大的再做运算
2、强制类型转换(大-->小)
默认情况下,大范围类型的变量直接赋值给小范围类型的变量会报错! 可以强行将类型范围大的变量、数据赋值给类型范围小的变量
格式:数据类型 变量1= (数据类型)变量2、数据
注意:
- 可能出现数据丢失,有精度损失。
- 小数强制转换成整数是直接截断小数保留整数。
- boolean不能参与类型转换,其他都行
2.5 标识符
在Java中,标识符是用来标识程序中各种元素的名称,比如变量、方法、类、接口等。标识符是由字母、数字、下划线(_)和美元符号($)组成的序列,且必须以字母、下划线或美元符号开头。标识符在编程中用于命名各种实体,使得程序易于阅读、理解和维护
2.5.1 硬性要求
必须要这么做,否则代码会报错。
- 必须由数字、字母、下划线_、**美元符号$**组成。
- 数字不能开头
- 不能是关键字
- 区分大小写的。
2.5.2 软性建议
1、小驼峰命名法
适用于变量名和方法名
- 如果是一个单词,那么全部小写,比如:name
- 如果是多个单词,那么从第二个单词开始,首字母大写,比如:firstName、maxAge
2、大驼峰命名法
适用于类名
- 如果是一个单词,那么首字母大写。比如:Demo、Test。
- 如果是多个单词,那么每一个单词首字母都需要大写。比如:HelloWorld
2.6 权限修饰符
2.6.1 概述
在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限。
public:公共的,所有地方都可以访问。protected:本类 ,本包,其他包中的子类都可以访问。默认(没有修饰符):本类 ,本包可以访问。注意:默认是空着不写,不是default
private:私有的,当前类可以访问。
==public > protected > 默认 > private==
2.6.2 权限访问能力
权限范围:public > protected > 默认 > private
| public | protected | 默认 | private | |
|---|---|---|---|---|
| 同一类中 | ||||
| 同一包中的类 | ||||
| 不同包的子类 | ||||
| 不同包中的无关类 |
编写代码时,如果没有特殊的考虑,建议这样使用权限:
- 成员变量使用
private,隐藏细节。 - 构造方法使用
public,方便创建对象。 - 成员方法使用
public,方便调用方法。
补充:
不加权限修饰符,就是默认权限
2.6.3 权限使用规则
实际开发中,一般只用private和public
- 成员变量私有
- 方法公开
注意:
如果方法中的代码是抽取其他方法中共性代码,这个方法一般也私有
2.6 方法
2.6.1 概述
方法(method)是程序中最小的执行单元
注意:
- 方法必须先创建才可以使用,该过程成为方法定义
- 方法创建后并不是直接可以运行的,需要手动使用后,才执行,该过程成为方法调用
2.6.2 定义和调用
1、方法定义完整格式:
修饰符 返回值类型 方法名 (形参列表){
方法体代码(需要执行的功能代码)
return 返回值;
}1、方法调用完整格式:
方法名(形参列表)注意:
- 方法必须先定义,后调用,否则程序将报错
- 参数是由数据类型和变量名组成 - 数据类型 变量名 例如:int a
- 方法定义时,参数中的数据类型与变量名都不能缺少,缺少任意一个程序将报错
- 方法定义时,多个参数之间使用逗号( ,)分隔
- 方法调用时,参数的数量与类型必须与方法定义中的设置相匹配,否则程序将报错
2.6.3 方法重载
满足下列条件的多个方法相互构成重载
- 多个方法在同一个类中
- 多个方法具有相同的方法名
- 多个方法的参数列表不同(个数不同或者类型不同或者顺序不同)
TIP
方法重载与方法的返回类型无关
例如,以下不是方法重载,而且报错:
public class MethodDemo {
public static void fn(int a) {
//方法体
}
public static int fn(int a) { /*错误原因:重载与返回值无关*/
//方法体
}
}2.7 运算符和表达式
1、概述:
Java运算符是用于对一个或多个操作数执行操作的特殊符号
表达式是由变量、常量、运算符和方法调用组成的符合语法规则的语句
运算符和表达式区别:
运算符就是对常量或者变量进行操作的符号
表达式就是符合Java语法的式子就是表达式
2、算术运算符:
定义:算术运算符是用来执行基本的数学运算的
例如:
+、-、 *、 /3、自增自减运算符:
定义:自增自减运算符是一种特殊的算数运算符,用于对变量的值进行加1或减1操作
例如:
++、--4、赋值运算符:
定义:赋值运算符是Java中用于给变量赋值的运算符
例如:b = 20
5、扩展赋值运算符:
定义:扩展赋值运算符是将算术运算符和赋值运算符组合在一起的运算符
例如: "+="、 "-="、 "*="、 "/="、 "%="
特点:扩展的赋值运算符中隐层还包含了一个==强制转换,==,例如:
a += b; //等价于a = (a的类型)(a + b);6、关系运算符:
含义:关系运算符是用于比较两个值之间的大小关系
例如:a > b
注意:区分 == 和 = 赋值运算符和关系运算符
7、逻辑运算符:
含义:用于多个布尔表达式组合在一起,以生成新的布尔表达式
例如:true & true、false & false
注意:逻辑运算符还有!、& 、 |、^
8、短路逻辑运算符:
含义:如果已经可以确定整个表达式的结果时,就不再继续计算剩下的表达式
例如:用户名正确 && 密码正确
9、三元运算符:
含义:被称为条件运算符,它是Java中唯一的具有三个操作数的运算符
格式:关系表达式 ? 表达式1 :表达式2 ; 例如:a > b ? a : b
10、运算符优先级:小括号优先( )
11、隐式转换与强制转换
隐式转换:自动类型提升
- 取值关系:byte < short < int < long < float < double
- 注意:float类型的存储空间比long类型小,但float类型的表示范围比long类型大
强制转换:强制类型提升
格式:
目标数据类型 变量名 = (目标数据类型)被强转的数据12、字符串的+操作(特例):
含义:当+操作中出现了字符,会拿着字符到计算机内置的ASCII码表中去查对应的数字,然后再进行计算
例如:
char c = 'a';
int result = c + 0;
System.out.println(result);//92.8 数组
2.8.1 定义
数组指的是一种容器,可以同来存储同种数据类型的多个值
2.8.2 定义方式
- 格式一:
数据类型 [] 数组名;
//例如
int [] array;- 格式二
数据类型 数组名 [];
//例如
int array [];- 注意:不同的数据类型对应不同的默认值
整数类型:0 小数类型:0.0 布尔类型:false 字符类型:'\u0000' 引用类型:null2.8.3 初始化
1、静态数组初始化
- 格式一:
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3,元素4...};
//例如
double[] arr = new double[]{1.1,1.2,1.3};- 格式二:
数据类型[] 数组名 = {元素1,元素2,元素3,元素4...};
//例如
int[] array = {1,2,3,4,5};2、动态数组初始化
数据类型[] 数组名 = new 数据类型[数组的长度];
//例如
double[] arr = new double[10];区别:
- 语法不同
- 数组长度不同
- 赋值时机不同
- 注意:无论是何种数组,数组的最大长度为,数组的长度-1。例如:arr.length - 1
2.8.4 地址值
数组的地址值是指向数组对象的指针或引用
例如:
int[] arr = {1,2,3,4,5};
System.out.println(arr); //[I@6d03e736
/*
[ :表示现在打印的是一个数组。
I:表示现在打印的数组是int类型的。
@:仅仅是一个间隔符号而已。
6d03e736:就是数组在内存中真正的地址值。(十六进制的)
*/2.9 抽象类和接口
2.9.1 抽象类
1、概述:
- 定义:没有方法体的方法称为抽象方法,包含抽象方法的类就是抽象类
- 抽象方法:没有方法体的方法
// 抽象方法
public abstract void abstractMethod();- 抽象类:包含抽象方法的类
public abstract class AbstractClass {
// 抽象方法
public abstract void abstractMethod();
}WARNING
注意:抽象类不一定有抽象方法,但是有抽象方法的类必须定义成抽象类。
2、abstract介绍
使用:==被继承==
特征: 1、抽象类得到了拥有抽象方法的能力,也就是说有了自己的一套规范
2、抽象类失去了创建对象的能力,也就是说不能创建对象
细节:
抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象
抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的
抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类
抽象类的子类,必须重写抽象父类中所有的抽象方法,否则子类也必须定义成抽象类,编译无法通过而报错
抽象类存在的意义是为了被子类继承
意义:抽象类存在的意义是为了被子类继承,否则抽象类将毫无
抽象类和接口区别,主要在于构造函数、成员变量、继承关系(单继承,多实现)
2.9.2 接口
1、概述
- 含义:接口是一种规范或契约,它只定义了方法签名、常量以及嵌套类型的声明,没有方法实现或属性
- 格式:
//接口的定义格式:
interface 接口名称{
// 抽象方法
}
// 接口的声明:interface
// 接口名称:首字母大写,满足“驼峰模式”特点:
1、抽象方法:会自动加上public abstract修饰
2、常量:会自动加上 public static final修饰
2、基本实现
- 实现方式:使用
implements关键字 - 格式:
/**接口的实现:
在Java中接口是被实现的,实现接口的类称为实现类。
实现类的格式:*/
class 类名 implements 接口1,接口2,接口3...{
}- 要求:接口体现的是一种规范,接口对实现类是一种强制性的约束。需要强制重写或定义为抽象类
3、接口与接口的多继承
- 含义:一个接口可以继承另一个或多个接口,这被称为接口的多继承
- 格式:
public interface SportMan extends Law , Abc {
void run();
}补充:接口和类之间的关系
- 类和类是继承关系,只能单继承,不能多继承
- 类与接口是实现关系,可以单实现,还可以多实现
- 接口与接口是继承关系,可以单继承,还可以多继承
4、JDK中接口新增:
- JDK7以前:接口中只能定义抽象方法。
- JDK8以后:新增默认方法(default method)
格式:public default 返回值类型 方法名(参数列表) { }
// 例如
public default void show(){
System.out.println("InterA接口中的默认方法 ---- show");
}特点:
1、默认方法不是抽象方法,所以不强制被重写
2、解决接口升级的问题
注意:
1、静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
2、public可以省略,static不能省略
JDK9以后:新增private修饰符 格式:
- 格式 : private返回值类型方法名(参数列表){}
- 范例: private void show() { }
- 格式: private static返回值类型方法名(参数列表){}
- 范例: private static void method(){ }5、接口的多态
- 含义:当一个方法的==参数是接口==时,可以传递接口所有实现类的对象,这种方式称之为==接口多态==
6、接口的细节
- 实现类可以同时继承==A类==也可以实现接口,不过需要实现所有方法
- 实现类可以同时继承==抽象类==也可以实现接口,不过需要重写所有方法
- 实现类实现了两个接口,且两个接口存在相同抽象方法,此时只需重写==一次==
- 当实现了接口,子类实现类中的方法跟父类方法同名是,==看需求==选择重写
- 做空重写:只需要重写实现类中的==部分==接口,可先创建类进行重写,在将此类继承,实现部分
2.9.3 抽象类和接口的异同点
(1)相同点:
- 都是抽象形式,都可以有抽象方法,都不能创建对象
- 都是派生子类模式:抽象类是被子类继承使用,接口是被实现类实现
- 一个继承抽象类或者实现接口,都必须重写它们的抽象方法,否则自己成为抽象类或者报错
- 都能支持多态,都能够实现解耦合
(2)不同点
- 抽象类中可以定义类的全部普通成员,接口只能定义常量,抽象方法 (JDK8新增的三种方式)
- 抽象类只能被类单继承,接口可以被类多实现。
- 一个类继承抽象类就不能再继承其他类,一个类实现了接口 (还可以继承其他类或者实现其他接口)。
- 抽象类体现模板思想:更利于做父类,实现代码的复用性。 最佳实践
- 接口更适合做功能的解耦合:解耦合性更强更灵活。 最佳实践
| 抽象类 | 接口 | |
|---|---|---|
| 方法实现 | 可以有实现的方法和非抽象方法 | 只有方法签名,无方法实现 |
| 构造函数 | 可以有构造函数 | 无法定义构造函数 |
| 成员变量 | 可以有成员变量 | 只能定义常量,无成员变量 |
| 继承关系 | 子类只能继承一个抽象类 | 类可以实现多个接口 |
| 功能实现 | 提供对类的部分实现 | 定义契约和行为规范 |
2.10 代码块
代码块是类的5大成分之一(成员变量、构造器、方法、代码块、内部类)。 代码块分为两种: 静态代码块: 格式: static {} 特点:类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次。 作用:完成类的初始化,例如:对静态变量的初始化赋值。
实例代码块: 格式: {} 特点:每次创建对象时,执行实例代码块,并在构造器前执行。 作用:和构造器一样,都是用来完成对象的初始化的,例如:对实例变量进行初始化赋值。
2.11 Lambda表达式
Lambda表达式: Lambda表达式只能替代函数式接口的匿名内部类
什么是函数式接口? 有且仅有一个抽象方法的接口。 注意:将来我们见到的大部分函数式接口,上面都可能会有一个@Functionallnterface的注解,该注解用于约束当前接口必须是函数式接口。
3 Java高级语法
3.1 集合类
3.1.1 概述
集合分为单列集合与双列集合
单列集合:Collection 双列集合:Map
3.1.2 单列集合
3.1.2.1 List系列集合
特点:有序、可重复、有索引
实现类:
- ArrayList:底层是基于数组存储数据,查询快,增删慢
- LinkedList:底层是基于双向链表存储数据,增删相对快,查询慢,首尾操作比较快
用LinkedList实现队列和栈
java// 队列 LinkedList<String> queue = new LinkedList<>(); queue.addLast("Java"); queue.addLast("C"); queue.addLast("C++"); queue.addLast("Python"); queue.addLast("C#"); System.out.println(queue); // [Java, C, C++, Python, C#] System.out.println(queue.removeFirst()); // Java System.out.println(queue.removeFirst()); // C System.out.println(queue); // [C++, Python, C#] //栈 LinkedList<String> stack = new LinkedList<>(); stack.push("Java"); stack.push("C"); stack.push("C++"); stack.push("Python"); stack.push("C#"); System.out.println(stack); // [C#, Python, C++, C, Java] System.out.println(stack.pop()); // C# System.out.println(stack.pop()); // Python System.out.println(stack); // [C++, C, Java]
3.1.3.2 Set系列集合
特点:无序、不可重复、无索引
实现类:
- HashSet:无序、不可重复、无索引,底层是由
JDK8之前:数组、链表,JDK8之后:数组、链表、红黑树组成 - LinkedHashSet:有序、不可重复、无索引,底层是由数组、链表、红黑树组成,增加双链表添加顺序
- TreeSet:排序展示(默认按升序排序)、不可重复、无索引
3.1.3 双列集合
3.1.3.1 Map集合
特点:无序、不可重复、无索引
实现类:
- HashMap:无序、不重复、无索引,基于哈希表实现,底层是由
JDK8之前:数组、链表,JDK8之后:数组、链表、红黑树组成,可以存储null键和null值,键相同时会覆盖 - LinkedHashMap:有序、不重复、无索引,基于哈希表实现,可以存储null键和null值,键相同时会覆盖
- TreeMap:排序展示(默认按升序排序)、不可重复、无索引,基于红黑树实现,按照键的自然顺序或者自定义的比较器排序,不允许有null键,但可以有null值
HashMap跟HashSet的底层原理是一模一样的,都是基于哈希表实现的。HashSet集合的底层原理就是HashMap。
LinkedHashMap跟LinkedHashSet的底层原理是一模一样的,都是基于哈希表+双向链表实现的,LinkedHashSet集合的底层原理就是LinkedHashMap。
TreeMap 跟TreeSet集合的底层原理是一样的,都是基于红黑树实现的排序。TreeSet集合的底层原理就是TreeMap。
3.2 Stream流
3.2.1 概述
在 Java 8 中,Stream 是一种处理集合的机制,它可以对集合进行各种操作(过滤、映射、排序等)并生成新的集合,同时支持并行处理
作用:结合了Lambda表达式,简化集合、数组的操作
3.2.2 使用步骤
1、获取Stream流对象
- Collection体系集合:使用默认方法stream()生成流, default Stream stream()
- Map体系集合:把Map转成Set集合,间接的生成流
- 数组:通过Arrays工具类中的静态方法stream生成流
- 同种数据类型的多个零散数据:通过Stream接口的静态方法of(T… values)生成流
2、使用中间方法处理数据
(1)filter过滤
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("张");
}
})(2)limit获取前几个元素
list.stream().limit(3)(3)skip跳过前几个元素、
list.stream().skip(2)(4)distinct:元素去重,(注意,当使用自定义对象进行去重时,依赖hashCode和equals方法)
list1.stream().distinct()(5)concat:合并a和b两个流为一个流
Stream.concat(list1.stream(),list2.stream())
//注意:在使用时,此处使用Stream对象中的concat静态方法(6)map:转换流中的数据类型
// Function<原本数据类型,需要转换的目标数据类型>
list.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
String[] arr = s.split("-");
String ageString = arr[1];
int age = Integer.parseInt(ageString);
return age;
}
})3、使用终结方法处理数据
(1)forEach:遍历
list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
})(2)count统计
list.stream().count();(3)toArray:收集流中的数据,放到数组中
list.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
System.out.println(Arrays.toString(arr));(4)collect:收集流中的数据,放到集合中
Map<String, Integer> map = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toMap(
new Function<String, String>() {
@Override
public String apply(String s) {
return s.split("-")[0];
}
},
new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.valueOf(s.split("-")[2]);
}
}
));3.3 File 文件
3.3.1 概述
- 含义:
java.io.File类是文件和目录路径名的抽象表示 - 路径:绝对路径和相对路径
- 作用:用于操作文件和目录,例如创建、删除,获取文件的信息。注意,File类不能获取文件内的详细内容!
3.3.2 常用方法
1、判断、获取:isDirectory()、isFIle()、exists()、length()、getAbsolutePath()、getPath()、getName()、lastModified() 2、创建、删除:createNewFile()、mkdir()、mkdirs()、delete()
3、获取并遍历:ListFiles()(重点)
示例(在某个目录中递归查找文件):
public class demo{
public static void main(String[] args) {
//完成文件搜索
File dir = new File("D:/");
searchFile(dir, "QQ.exe");
}
/**
* 递归搜索文件
* @param dir 搜索的目录
* @param fileName 搜索的文件名
*/
public static void searchFile(File dir, String fileName) {
if (dir == null || !dir.exists() || dir.isFile() || !dir.canRead()) {
return; //不搜索
}
File[] files = dir.listFiles();
// System.out.println(Arrays.toString(files));
if (files != null && files.length > 0) {
for (File file : files) {
// 判断当前对象是否为文件
if (file.isFile()&&file.getName().equals(fileName)) {
System.out.println("找到目标文件" + file.getAbsolutePath());
}
else{
searchFile(file, fileName);
}
}
}
}
}3.4 IO流
3.4.1 概述
定义:IO指对文件进行输入输出操作
分类:
- 输入流、输出流:读取数据和写出数据
- 字节流、字符流:任何二进制文件和处理字符。底层传输的始终为二进制数据
流体系结构:
IO流体系 | |---------字节流 |---------------字节输入流 |---------------------------InputStream(抽象类) |---------------------------FileInputStream(实现类) |---------------------------BufferedInputStream(实现类) | |---------------字节输出流 |---------------------------OutputStream(抽象类) |---------------------------FileOutputStream(实现类) |---------------------------BufferedOutputStream(实现类) | | |---------字符流 |---------------字符输入流 |---------------------------Reader(抽象类) |---------------------------FileReader(实现类) |---------------------------BufferedReader(实现类) |---------------------------InputStreamReader(实现类) | |---------------字符输出流 |---------------------------Writer(抽象类) |---------------------------FileWriter(实现类) |---------------------------BufferedWriter(实现类)
3.4.2 字节流
含义:从文件中读取字节数据
文件拷贝
字节流实现:
public static void copyFile(String srcFile, String destFile){
long start = System.currentTimeMillis();
// 1、创建一个文件字节输入流和输出流管道与源文件接通
InputStream fis = null;
OutputStream fos = null;
try {
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
// 2、读取一个字节数组,写入一个字节数组
byte[] buf = new byte[1024];
int len;
while ((len = fis.read(buf)) != -1) {
fos.write(buf, 0, len); //读取多少个字节,就写入多少个字节
}
System.out.println("复制成功");
fos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 3、释放资源
try {
if (fos != null) {
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (fis != null) {
fis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("time" + (end - start) + "ms");
}
}新写法:
public static void copyFile02(String srcFile, String destFile){
long start = System.currentTimeMillis();
// 1、创建一个文件字节输入流和输出流管道与源文件接通
try (
// 这里只能放置资源对象,用完后,最终会自动调用其close方法进行关闭
InputStream fis = new FileInputStream(srcFile);
OutputStream fos = new FileOutputStream(destFile);
){
// 2、读取一个字节数组,写入一个字节数组
byte[] buf = new byte[1024];
int len;
while ((len = fis.read(buf)) != -1) {
fos.write(buf, 0, len); //读取多少个字节,就写入多少个字节
}
// fos.flush();
System.out.println("复制成功");
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("time" + (end - start) + "ms");
}字节缓冲流写法:
public static void copyFile03(String srcFile, String destFile){
long start = System.currentTimeMillis();
try (
InputStream fis = new FileInputStream(srcFile);
InputStream bis = new BufferedInputStream(fis);
OutputStream fos = new FileOutputStream(destFile);
) {
byte[] buf = new byte[1024];
int len;
while((len = bis.read(buf)) != -1){
fos.write(buf, 0, len);
}
System.out.println("复制成功");
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("time" + (end - start) + "ms");
}推荐使用字节缓冲流,性能更高。
字节缓冲流先使用8K的容量进行缓冲,等满了在导入内存或者硬盘
3.4.3 字符流
含义:从文件中读取字符数据
1、构造方法:
输入流:
- FileReader(File file)
- FileReader(String fileName)
输出流:
- FileWriter(File file)
- FileWriter(String pathName)
2、成员方法:
输入流:
- read()
- read(char[] cbuf)
输出流:
- write(int/string c)
- write(char[] cbuf)
- write(char[] cbuf, int off, int len)
- flush()
示例:
字符输入流:
try (
Reader fr = new FileReader(""); //路径自定义
BufferedReader br = new BufferedReader(fr);
) {
// 使用FilerReader
// char[] buf = new char[1024];
// int len;
// while ((len = fr.read(buf)) > 0) {
// System.out.print(new String(buf, 0, len));
// }
// 使用BufferReader
String s;
while ((s = br.readLine()) !=null) {
System.out.println(s);
}
}catch (Exception e) {
e.printStackTrace();
}字符输出流;
try (
Writer wr = new FileWriter("",true);//路径自定义,true时表示追加,没有时表示覆盖
BufferedWriter bw = new BufferedWriter(wr);
) {
wr.write("Hello World \ndjklasdkljasdkljasdkljas");
wr.write('d');
wr.write("\r\n");
wr.write('\n');
wr.flush();
bw.newLine();
}
catch (Exception e) {
e.printStackTrace();
}3.4.4 字符集
- 定义:是将一个字符集中的字符映射为一个或多个数字的方法
- 乱码产生原因:读取数据,未读完整个数据、解码和编码时的字符集方式不统一
- Java中编码和解码:
- GBK编码使用两个字节来存储一个中文字符
- UTF-8编码使用三个字节来存储一个中文字符
示例:
字符串加密:
import java.util.Arrays;
public class charsetDemo {
public static void main(String[] args) throws Exception {
String name = "我爱你中国(_的我)";
// 编码
byte[] bytes = name.getBytes("GBK");
System.out.println(bytes.length);
System.out.println(Arrays.toString(bytes));
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) (bytes[i] + 3);
// System.out.println(aByte);
}
// 解码
System.out.println(Arrays.toString(bytes));
String str = new String(bytes, "GBK");
System.out.println(str);
int[] a = {1, 2, 3};
System.out.println(Arrays.toString(a));
for (int i = 0; i < a.length; i++) {
a[i] = a[i] + 1;
}
for (int i : a) {
i++;
System.out.println(i);
}
System.out.println(Arrays.toString(a));
}
}
/*输出:
17
[-50, -46, -80, -82, -60, -29, -42, -48, -71, -6, 40, 95, -75, -60, -50, -46, 41]
[-47, -43, -77, -79, -57, -26, -39, -45, -68, -3, 43, 98, -72, -57, -47, -43, 44]
颜潮擎儆箭+b盖颜,
[1, 2, 3]
3
4
5
[2, 3, 4]
*/