环境
安装JDK8并配置环境变量
jvm+核心类库=jre
jre+开发工具=jdk
Java基础运行流程,代码从上到下,从左往右,只运行一次
桌面—>新建文件夹—>新建记事本—>打开编写代码
public class Hello{public static void main(String[] args){System.out.println("Hello luckyNwa ");}
}
—>修改记事本名称为 Hello.java ---->路径栏输入cmd回车出现终端---->
javac Hello.java
---->生成class文件—>运行
java Hello
过程:源文件A.java—>javac编译—>A.class—>java运行到JVM中
再打印中加入中文发现乱码,解决
文件改成ANSI格式另存覆盖原来的utf-8 或者在javac那指令改成如下
javac -encoding UTF-8 Hello.java
IDEA的快捷键
ctrl+/ 单行注释
/**回车 文档注释
/* */ 多行注释
shift+ctrl+enter 光标到下一行,也可以补齐;
mian 生成入口函数
alt +enter 用于前面的变量定义 比如 new Scanner(System.in);
ctrl+n 查类的说明文档 比如Math类
fori 回车直接打出循环 数组a.for回车 foreach快捷键
shift+tab 向前退一格
ctrl+alt+t 可以添for while try catch 等
命名规范
标识符(变量)规则:由字母,数字,下划线和$组成,不能以数字开头 ,不能用关键字
业内规定:
类:首字母大写,驼峰命名法
包:小写字母组成,域名倒置
变量/方法:首字母小写,驼峰命名法,需要语义化,见名知意
常量:全部大写字母,单词之间下划线隔开 要加个final修饰,不可改变
关键字:Java官方用掉的名字
数据类型
数据类型分为基本数据类型和引用数据类型(复合数据类型)
基本数据类型(四类八型)
整数类型: byte 8 short 16 int(默认) 32 long 64 数字是位数
浮点类型: float 32 单精度 double(默认) 64 双精度 float范围比long大因为它是小数的。浮点数不能用来表示精确的值,如货币
字符型: char 只有这用单引号,其他基本都是双引号 char letter = ‘A’;
布尔型 Boolean: true false(默认)
引用数据类型
它们是通过类来定义的。Java 中的引用数据类型包括:
- 类
- 接口
- 数组
复合数据类型有无数种,自带方法和属性,如String、Scanner、Random等
基本数据类型在内存中存储实际的值,而引用数据类型则存储对对象的引用(即内存地址)。在使用基本数据类型时,实际的值直接存储在变量中,而在使用引用数据类型时,变量存储的是对象的引用,对象本身存储在堆内存
数据类型转换
低的变高,是自动转换;高的变低必须强转,会精度损失
浮点转整需要舍弃小数位
byte到double 从低到高,byte 类型是 8 位,最大值为127,所以当 int 强制转换为 byte 类型时,值 128 时候就会导致溢出
低 ------------------------------------> 高byte,short,char—> int —> long—> float —> double
int i =128;
byte b = (byte)i;
float型转换为double型
float f1=100.00f;
Float F1=new Float(f1);
double d1=F1.doubleValue();//F1.doubleValue()为Float类的返回double值型的方法
简单类型的变量转换为相应的包装类,可以利用包装类的构造函数。即:Boolean(boolean value)、Character(char value)、Integer(int value)、Long(long value)、Float(float value)、Double(double value)
而在各个包装类中,总有形为××Value()的方法,来得到其对应的简单类型数据。
运算符
-
算术运算符
+、-、*、/、% 、++、-- (%取余5%2=1)
-
关系运算符
== 、!=、>、<、>=、<=
-
位运算符
& |(计算二进制的,用处少)
7 二进制过程—> 7/2 =3 1 3/2=1 1 1/2= 1 0111 7的二进制结果倒着余数 111
9 二进制过程—> 9/2=4 1 4/2=2 0 2/2=1 0 1/2= 1 1001 结果倒着余数 1001
0001 7&9结果1 &必须2个是1才是1
-
逻辑运算符
&&(逻辑与,2真才真,也叫短路运算符,1假则不会继续下个判断了) 、||(逻辑或,1真就真)、 !(逻辑非)
-
赋值运算符
=、+=,-=…(c-=a 等价于 c=c-a 其他同理)
-
条件运算符
条件运算符也被称为三元运算符。该运算符有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量。
int a = 10;int b = 20;int max = a < b ? b : a; //10<20所以将b的值给max否则a,就是三元运算符
条件
Java 中的条件语句允许 程序 根据条件的不同执行不同的代码块
if(布尔表达式 1){//如果布尔表达式 1的值为true执行代码
}else if(布尔表达式 2){//如果布尔表达式 2的值为true执行代码
}else if(布尔表达式 3){//如果布尔表达式 3的值为true执行代码
}else {//如果以上布尔表达式都不为true执行代码
}
上面可以各种用
switch case
判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。
switch(expression){case value ://语句break; //可选case value ://语句break; //可选//你可以有任意数量的case语句default : //可选//语句
}
public class Test {public static void main(String args[]){int i = 2;switch(i){case 0:System.out.println("0");case 1:System.out.println("1");case 2:System.out.println("2");default:System.out.println("default");}}
}
匹配成功后,从当前 case 开始,后续所有 case 的值都会输出
2
default
如果i是6,都匹配不到则返回默认的default里的值,一般匹配到就break打断了
循环
Java中有三种主要的循环结构:
-
while 循环
只要布尔表达式为 true,循环就会一直执行下去。
while( 布尔表达式 ) {//循环内容 }
-
do…while 循环
do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。
do {//代码语句 }while(布尔表达式);
-
for 循环
for循环执行的次数是在执行前就确定的
for(初始化; 布尔表达式; 更新) {//代码语句 }
java5引入foreach—>数组的增强型 for 循环 数组a.for回车快速生成
for(声明语句 : 表达式)
{//代码句子
}
public class Demo1 {public static void main(String[] args) {int[] numbers = {10, 20, 30, 40, 50};for (int item : numbers) {System.out.println(item);}}
}
配合的关键字
break主要用于停止,整个循环语句或者 switch 语句,循环语句后面的代码还会运行
continue用于循环里面让程序跳过当前循环,立刻进入下一次的循环
return用于返回方法类型指定的值也可以是对象,还能可以结束后面代码的执行
public class Demo1 {public static void main(String[] args) {int[] numbers = {10, 20, 30, 40, 50};for (int item : numbers) {
// if (item == 10) {
// continue;//跳过当前满足的条件,继续循环 ---->20,30,40,50,哈哈
// }System.out.print(item);System.out.print(",");if (item == 10) {
// break;//满足条件时候跳出循环,循环后面的哈哈还是打印---->10,哈哈return;//直接返回,不执行后续代码 ---->10}}System.out.println("哈哈");}
}
总结
for和while都被称为前置判断循环 do…while是后置判断循环
while和do while都属于不确定次数的循环语句
for 是属于确定次数的循环语句
数组
数组的创建
入口函数那是推荐main(String[] args) 或者写main(String args[])
声明
dataType[] arrayRefVar; // 首选的方法
或
dataType arrayRefVar[]; // 效果相同,但不是首选方法
arrayRefVar = new dataType[arraySize];
创建数组
dataType[] arrayRefVar = new dataType[arraySize]; //动态声明
dataType[] arrayRefVar = new dataType[]{value0, value1, ..., valuek};//用的少,使用1、3
dataType[] arrayRefVar = {value0, value1, ..., valuek}; //静态声明方式
一维数组
public class Demo1 {public static void main(String[] args) {// 数组大小int size = 5;double[] myList = new double[size];myList[0] = 5.6;myList[1] = 4.5;myList[2] = 3.3;myList[3] = 13.2;myList[4] = 4.0;// 计算所有元素的总和double total = 0;for (int i = 0; i < size; i++) {total += myList[i];}System.out.println("总和为: " + total);// 查找最大元素double max = myList[0];for (int i = 1; i < myList.length; i++) {if (myList[i] > max) max = myList[i];}System.out.println("Max is " + max);System.out.println("-------------------");int[] arr = {1, 2, 3, 4, 5};for (int x : arr) { //这里x只是变量名System.out.println(x);//如果里面还有一个循环int y :x}}
}
二维数组
type[][] typeName = new type[typeLength1][typeLength2];
type 可以为基本数据类型和复合数据类型,typeLength1 和 typeLength2 必须为正整数,typeLength1 为行数,typeLength2 为列数
int[][] a = new int[2][3];
a 可以看成一个两行三列的数组
public class Demo1 {public static void main(String[] args) {String[][] s = new String[2][];s[0] = new String[2];s[1] = new String[3];s[0][0] = new String("Good");s[0][1] = new String("Luck");s[1][0] = new String("to");s[1][1] = new String("you");s[1][2] = new String("!");
// System.out.println(s[0][1]);//Luckyfor (String[] strings : s) {for (String string : strings) {System.out.print(string.concat("\t"));}}}
}
public class Demo1 {public static void main(String[] args) {String[] stu1 = {"张三", "Jx202211", "男", "22"};String[] stu2 = {"李四", "Jx202212", "女", "21"};String[] stu3 = {"王五", "Jx202213", "男", "25"};String[] stu4 = {"小六", "Jx202214", "女", "20"};String[][] stu = {stu1, stu2, stu3, stu4};for (int i = 0; i < stu.length; i++) {for (int j = 0; j < stu[i].length; j++) {System.out.print(stu[i][j] + "\t");}System.out.println();}}
}
函数(方法)
函数是一段具备特定功能的、高度封装的代码块
函数声明:
修饰符 返回值类型 方法名(参数类型 参数名){...方法体...return 返回值;
}
1、修饰符 public static 公开的 静态的
2、返回值类 void 表返回值为null,就不需要return,其他都需要
3、函数名 小驼峰命名
4、参数列表
5、方法体 要执行的代码块
public class Demo1 {public static void main(String[] args) {Demo1.nPrintln("lucky", 2);//正常静态方法调用-->类名.方法名称() Demo1 demo1 = new Demo1();//如果不是静态在类上需要new出来再.System.out.println("最大值是" + demo1.max(1, 2));System.out.println("最大值是" + demo1.max(11.2, 32.2));printMax(new double[]{1, 2, 3});//在本类中可以直接调用,无需类名printMax(new double[]{});}public static void nPrintln(String message, int n) {for (int i = 0; i < n; i++) {System.out.println(message);}}public int max(int num1, int num2) {return num1 > num2 ? num1 : num2;}public Double max(Double num1, Double num2) {return num1 > num2 ? num1 : num2;}public static void printMax(double... numbers) {//JDK 1.5 开始,Java支持传递同类型的可变参数给一个方法if (numbers.length == 0) { //在指定参数类型后加一个省略号...,传了个数组过来System.out.println("No argument passed");return;}double result = numbers[0];for (int i = 1; i < numbers.length; i++) {if (numbers[i] > result) {result = numbers[i];}}System.out.println("The max value is " + result);}
}
形参与实参:函数声明里就是形参,而调用那里输入则是实参
返回值:看声明里返回值类,void则没有返回值,如int则返回整型n,如果是类,返回一个对象类
函数的递归:即函数里调用函数自己
变量作用域:方法内声明的变量(局部变量),方法外不可用
方法重载:同一类中方法名相同,参数数量和类型不同。构造方法(对象里的)就可以利用重载
对象
世界万物皆对象,对象的特点是属性、对象的行为是方法,对象的行为必须是自发的
特征
- 封装
- 继承
- 多态
封装
私有化属性并设置公有的get、set方法 IDEA右键—>生成—选择需要的
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问
比如该类是公开的属性,那么外部new这个对象时候便可以直接.属性去修改,现在我们封装了它无法直接修改需要调用set方法去修改,比如年龄想修改1000岁是不正常的,我们便可以再set方法中加逻辑
public class Lucky {private String name;public Lucky() { //默认存在这个空构造}public Lucky(String name) { //方法的重载this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Override //方法的重写,原来是打印这个对象的引用地址public String toString() {//下面的值return "Lucky{" +"name='" + name + '\'' +'}';}
}
public class Demo1 {public static void main(String[] args) {Lucky name = new Lucky("小维");System.out.println(name);Lucky name2 = new Lucky();name2.setName("小米");System.out.println(name2);}
}
结果:
Lucky{name=‘小维’}
Lucky{name=‘小米’}
this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突
构造函数
是一个没有返回值,并且函数名和类型相同的函数,在对象实例化的一瞬间就会执行,利用构造函数的参数,对属性进行赋值
继承
继承就是子类继承父类的属性和方法 苹果是水果可以继承水果类 食草动物是动物可以继承动物类
必须满足is-a关系 父类更通用 子类更具体
关键字是extends 写在类名后面
一个类只能继承一个抽象类, 继承不可滥用,牵一发而动全身,父类改变一次,其他全部受到影响,即耦合性过高,
继承一般继承Java官方的类
class 父类 {
}class 子类 extends 父类 {
}
现在有3个类如下
public class Penguin {private String name;private int id;public Penguin(String myName, int myid) {name = myName;id = myid;}public void eat() {System.out.println(name + "正在吃");}public void sleep() {System.out.println(name + "正在睡");}public void introduction() {System.out.println("大家好!我是" + id + "号" + name + ".");}
}
public class Mouse {private String name;private int id;public Mouse(String myName, int myid) {name = myName;id = myid;}public void eat() {System.out.println(name + "正在吃");}public void sleep() {System.out.println(name + "正在睡");}public void introduction() {System.out.println("大家好!我是" + id + "号" + name + ".");}
}
public class Demo1 {public static void main(String[] args) {Penguin penguin = new Penguin("企鹅", 1);penguin.eat();penguin.sleep();penguin.introduction();Mouse mouse = new Mouse("老鼠", 2);mouse.eat();mouse.sleep();mouse.introduction();}
}
会发现代码存在重复,导致代码量大且臃肿,而且维护性不高(主要表现是后期需要修改的时候,需要修改很多的代码,容易出错)
要从根本上解决这两段代码的问题,就需要继承,将两段代码中相同的部分提取出来组成 一个父类
public class Animal {private String name;private int id;public Animal(String myName, int myid) {name = myName;id = myid;}public void eat(){System.out.println(name+"正在吃");}public void sleep(){System.out.println(name+"正在睡");}public void introduction() {System.out.println("大家好!我是" + id + "号" + name + ".");}
}
改造子类,extends单继承,子类只能有一个父类,可以多重继承比如a给b继承,b给c继承,没用过。子类不继承父类的构造器
public class Penguin extends Animal{public Penguin(String myName, int myid) {super(myName, myid);}
}
public class Mouse extends Animal {public Mouse(String myName, int myid) {super(myName, myid);//调用父类的构造并传入参数}
}
关键字 super :放在代码里 用来子类给父类的构造函数的参数传参,还能调用父类的方法 ,不过继承就有父方法了
如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器
继承关系下
首先,会调用父类的构造函数。如果子类构造函数的第一行没有显式调用父类构造函数(通过 super()
),则会自动调用父类的无参构造函数。如果父类没有无参构造函数,并且子类没有显式调用父类的其他构造函数,则编译器会报错
然后,执行父类的构造函数体
接着,再执行子类的构造函数。如果子类构造函数的第一行没有显式调用其他构造函数(通过 this()
或 super()
),则会自动调用父类的无参构造函数,然后执行子类的构造函数体
最后,执行子类的构造函数体
重写(Override)
子类定义了一个与其父类中具有相同名称、参数列表和返回类型的方法,并且子类方法的实现覆盖了父类方法的实现。 即外壳不变,核心重写!
父类的方法,子类写的一模一样,最终执行的是子类的方法
重写规则:修饰符不能强于父类,返回值类型、方法名、参数列表必须一样
重载(overloading)
在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同
多态
多态指同一个事物能呈现出多种形态的能力 多态是继承的一种体现
方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现
多态就是同一个接口,使用不同的实例而执行不同操作
多态存在的三个必要条件:
- 继承
- 重写
- 父类引用指向子类对象:Parent p = new Child();
AnimalT能呈现出多种形态的能力
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法
public class Demo1 {public static void main(String[] args) {AnimalT a = new Lion();//父类引用指向子类对象,执行的是子类的方法,这就是多态 向上转型 a.eat();a.sleep();}
}
// 动物类 AnimalT.java
abstract class AnimalT {abstract void eat();abstract void sleep();}
// 狮子类 Lion.java
class Lion extends AnimalT {public void eat() {System.out.println("狮子吃");}public void sleep() {System.out.println("狮子睡");}
}
// 老虎类 Tiger.java
class Tiger extends AnimalT {public void eat() {System.out.println("老虎吃");}public void sleep() {System.out.println("老虎睡");}
}
class Animal {public void makeSound() {System.out.println("动物发出声音");}
}class Dog extends Animal {@Overridepublic void makeSound() {System.out.println("狗发出汪汪声");}
}class Cat extends Animal {@Overridepublic void makeSound() {System.out.println("猫发出喵喵声");}
}public class Main {public static void main(String[] args) {Animal animal1 = new Dog(); // 使用父类引用指向子类对象Animal animal2 = new Cat(); // 使用父类引用指向另一个子类对象animal1.makeSound(); // 调用被重写的方法,输出:狗发出汪汪声animal2.makeSound(); // 调用被重写的方法,输出:猫发出喵喵声}
}
这就是多态的体现,通过父类的引用调用被子类重写的方法
接口
接口并不是类,类描述对象的属性和方法。接口则包含类要实现的方法
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类
接口:没有方法体的方法的集合
- 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(JDK8后default也行,其他修饰符会报错)
- JDK 1.8 以后,接口里可以有静态方法和方法体
implements关键字
使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)
public interface A { //定义A接口interface关键字void eat();void sleep();
}public interface B { //定义B接口void show();
}public class C implements A,B { //实现类 需要全部实现接口中的方法
}
有方法体的方法 被称为 实例方法
没方法体的方法 被称为 抽象方法
包装类
所有的包装类**(Integer、Long、Byte、Double、Float、Short)**都是抽象类 Number 的子类
这种由编译器特别支持的包装称为装箱,所以当内置数据类型被当作对象使用的时候,编译器会把内置类型装箱为包装类。相似的,编译器也可以把一个对象拆箱为内置类型。Number 类属于 java.lang 包
public class Test{public static void main(String[] args){Integer x = 5; // x 被赋为整型值时,由于x是一个对象,所以编译器要对x进行装箱x = x + 10; //为了使x能进行加运算,所以要对x进行拆箱System.out.println(x); }
}
修饰符
访问控制修饰符
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
- default (无修饰): 本类、同一包的类可见
- private : 私有的 能且仅能在本类中使用 注意:不能修饰类(private class Demo1 )错误
- public : 对所有类可见。使用对象:类、接口、变量、方法
- protected : 本类、子类、同一包的类可见 注意:不能修饰类(外部类)
static
static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量
static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据
它的特性:只会在类加载的时候执行一次。
final
final 表示"最后的、最终的"含义,变量一旦赋值后,不能被重新赋值。被 final 修饰的实例变量必须显式指定初始值
final修饰类中的属性或者变量 无论属性是基本类型还是引用类型,final所起的作用都是变量里面存放的“值”不能变,这个值,对于基本类型来说,变量里面放的就是实实在在的值,而引用类型变量里面放的是个地址,所以用final修饰引用类型变量指的是它里面的地址不能变,并不是说这个地址所指向的对象或数组的内容不可以变,这个一定要注意
final 修饰符通常和 static 修饰符一起使用来创建类常量。
public class MyClass {public static int count = 0; //静态变量public static final int MAX_SIZE = 100; // 使用大写蛇形命名法 常量
}
访问
MyClass.count = 10; // 通过类名访问
MyClass obj = new MyClass();
obj.count = 20; // 通过实例名访问
final 属性 声明变量时可以不赋值,而且一旦赋值就不能被修改了,用来new的那个对象里有final修饰的属性那个属性必须赋值
final 方法 可以被子类继承,但是不能被子类重写。声明 final 方法的主要目的是防止该方法的内容被修改
final 类 不能被继承
abstract(抽象类)
抽象类不能用来实例化对象
一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误
抽象类可以包含抽象方法和非抽象方法
abstract class Caravan{ //被abstract修饰就是抽象类private double price;private String model;private String year;public abstract void goFast(); //抽象方法public abstract void changeColor();
}
抽象方法是一种没有任何实现的方法,该方法的具体实现由子类提供
抽象方法不能被声明成 final 和 static
如果一个类包含抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法
继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也必须声明为抽象类
构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法
抽象方法的声明以分号结尾,例如:public abstract sample();
public abstract class SuperClass{abstract void m(); //抽象方法
}class SubClass extends SuperClass{//实现抽象方法void m(){.........}
}
synchronized
synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符。
public synchronized void showDetails(){
.......
}
枚举类
枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一年的 12 个月份,一个星期的 7 天,方向有东南西北等—>场景:颜色(红黄蓝绿…)、星期、反射做多个oss桶时候
常量类是指一组声明为静态的、不可改变的常量变量,它们通常用于定义一些全局性的常量,如数学常数π、还有一些不变的值,项目中必定有一个常量类,final关键字,表示这些变量不能被修改—> 场景:分页的当前页、限制页数、返回的数据成功、失败…
Java 枚举类使用 enum 关键字来定义,各个常量使用逗号 , 来分割
enum Color {RED, GREEN, BLUE;private Color() // 构造函数只能使用 private 访问修饰符,所以外部无法调用{System.out.println("Constructor called for : " + this.toString());}public void colorInfo() {//枚举既可以包含具体方法,也可以包含抽象方法。 如果枚举类具有抽象方法,则枚举类的每个实例都必须实现它System.out.println("枚举的方法");}
}
每个枚举都是通过 Class 在内部实现的,且所有的枚举值都是 public static final 的,所以可以 类名.名称
- values() 返回枚举类中所有的值。
- ordinal()方法可以找到每个枚举常量的索引,就像数组索引一样。
- valueOf()方法返回指定字符串值的枚举常量。
public class Demo1 {public static void main(String[] args) {Color c1 = Color.RED;System.out.println(c1);for (Color myVar : Color.values()) {System.out.println(myVar);}// ------------------------------------------------Color myVar = Color.BLUE;switch (myVar) {case RED:System.out.println("红色");break;case GREEN:System.out.println("绿色");break;case BLUE:System.out.println("蓝色");break;}// ------------------------------------------------Color[] arr = Color.values();// 迭代枚举for (Color col : arr) {// 查看索引System.out.println(col + " at index " + col.ordinal());}// 使用 valueOf() 返回枚举常量,不存在的会报错 IllegalArgumentExceptionSystem.out.println(Color.valueOf("RED"));// ------------------------------------------------Color green = Color.GREEN;//下面2个结果一样green.colorInfo();Color red = Color.RED;red.colorInfo();}
}
工作中的写法1
public enum ErrorCode {OK(0) {public String getDescription() {return "成功";}},ERROR_A(100) {public String getDescription() {return "错误A";}},ERROR_B(200) {public String getDescription() {return "错误B";}}; //分号private int code;// 构造方法:enum的构造方法只能被声明为private权限或不声明权限private ErrorCode(int number) { // 构造方法this.code = number;}public int getCode() { // 普通方法return code;} // 普通方法public abstract String getDescription(); // 抽象方法
}
写法2 效果和调用一样
public enum ErrorCodeEn {OK(0, "成功"),ERROR_A(100, "错误A"),ERROR_B(200, "错误B");ErrorCodeEn(int number, String description) {this.code = number;this.description = description;}private int code;private String description;public int getCode() {return code;}public String getDescription() {return description;}
}
public class Demo1 {public static void main(String[] args) {// 获取枚举常量的值System.out.println(ErrorCodeEn.OK.getCode()); // 输出: 0System.out.println(ErrorCodeEn.ERROR_A.getCode()); // 输出: 100System.out.println(ErrorCodeEn.ERROR_B.getCode()); // 输出: 200// 获取枚举常量的描述System.out.println(ErrorCodeEn.OK.getDescription()); // 输出: 成功System.out.println(ErrorCodeEn.ERROR_A.getDescription()); // 输出: 错误ASystem.out.println(ErrorCodeEn.ERROR_B.getDescription()); // 输出: 错误B}
}
补充
面向对象与面向过程区别
面向过程:只关注事情本身的完成,不关注谁去做,就像大象塞进冰箱,不管是谁把冰箱打开,谁把大象弄进去
面向对象:更多关注 谁去做事情 各有各的好处
对象的生命周期
对象的出生:一旦被声明被赋值之后 对象即出现
对象的销毁:当该对象没有被指向 就会被自动销毁
String a;这是空,没有对象,所以没有出生和销毁
IO流
IO 流:按照流动的方向,以内存为基准,分为输入 input 和输出 output ,即流向内存是输入流,流出内存的输出流
(1)明确要操作的数据是数据源还是数据目的(也就是要读还是要写)
(2)明确要操作的设备上的数据是字节还是文本
(3)明确数据所在的具体设备
(4)明确是否需要额外功能(比如是否需要转换流、高效流等)
输入流(读数据 硬盘---->内存)、输出流(写数据 内存—>硬盘)
分类:
1.字节流:字节流又分为字节输入流、字节输出流 2.字符流:字符流由分为字符输入流、字符输出流
字符流的由来:因为数据编码的不同,字节流直接读中文会乱码 字符流 = 字节流 + 编码表
数据流向内存就是输入流,流出内存就是输出流,根据数据的类型分为
字节流和字符流,如名字的为单位
字节流对应的输入流 InputStream 输出流 OutputStream
字符流对应的输入流 Reader 输出流 Writer
超类(父类)以这四个名称结尾都是它的子类
比如常见的 FileInputStream 文件输入流
1 个字符=2 个字节
字节流适合读取视频、音乐、图片等二进制文件,字符流比较适合读取纯文本文件
字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据
File 类
java.io.File 类是专门对文件进行操作的类,只能对文件本身进行操作,不能对文件进行读和写也就是输入和输出
File 类构造方法不会给你检验这个文件或文件夹是否真实存在,因此无论该路径下是否存在文件或者目录,都不影响 File 对象的创建。
下面一个测试类
package com.nwa;import org.junit.Test;import java.io.*;/*** @Author Lucky友人a* @Date 2023/8/10 -10:34*/
public class FileDemo {@Testpublic void fun1() throws IOException {File f = new File("C:\\Users\\FF\\Desktop\\1.txt"); //就算文件1.txt不存在也不影响file对象的创建if (!f.exists()) {System.out.println("是否创建:"+f.createNewFile()); // true 如果没有文件则创建并返回true}System.out.println("是否创建:"+f.createNewFile()); //已经存在,所以就false了System.out.println("文件绝对路径:"+f.getAbsolutePath());//文件绝对路径:C:\Users\FF\Desktop\1.txtSystem.out.println("文件构造路径:"+f.getPath()); //文件构造路径:C:\Users\FF\Desktop\1.txtSystem.out.println("文件名称:"+f.getName()); //文件名称:1.txtSystem.out.println("文件长度:"+f.length()+"字节");// 判断是文件还是目录System.out.println("文件:"+f.isFile());System.out.println("目录:"+f.isDirectory());//一个路径下全部文件名,先将字符串转目录
// String path = "D:\\workspace";
// File file = new File(path);
// printFile(file);}
//结果1 传进的file不一样结果不一样,如果是绝对位置那么构造啥的都是绝对的
// 是否创建:false
// 文件绝对路径:C:\Users\FF\Desktop\1.txt
// 文件构造路径:C:\Users\FF\Desktop\1.txt
// 文件名称:1.txt
// 文件长度:0字节
// 文件:true
// 目录:false//结果2 如果是直接1.txt则会相对这个项目来创建这个文件
// 是否创建:true
// 是否创建:false
// 文件绝对路径:E:\LuckyWorckSpace\lucky_api\1.txt
// 文件构造路径:1.txt
// 文件名称:1.txt
// 文件长度:0字节
// 文件:true
// 目录:false@Testpublic void testDemo2() { //目录的创建等,使用相对这个项目下的目录来测试了// 目录的创建File f2= new File("newDira");
// System.out.println("是否存在:"+f2.exists());// false
// System.out.println("是否创建:"+f2.mkdir()); // 这个是创建的意思,并返回true
// System.out.println("是否存在:"+f2.exists());// true// 创建多级目录
// File f3= new File("newDira\\newDirb");
// System.out.println(f3.mkdir());// false,没有加s指南创建单层的目录File f4= new File("newDira\\newDirb");// System.out.println(f4.mkdirs());// true,可以创建多级别的目录// 文件和目录的删除 delete方法,如果此File表示目录,则目录必须为空才能删除。// System.out.println(f2.delete());// true// System.out.println(f4.delete());// false如果是删除多层目录只能删除最底层的比如这个的newDirb目录,外newDira没有删掉}@Testpublic void demo3() {File file = new File("E:\\other\\study\\学习sp\\实用篇");printFile(file);}public static void printFile(File file) {
// //获取当前目录下的文件以及文件夹的名称。
// File[] files = file.listFiles();
// for (File a:files) {
//
// if (a.isFile()) {
// System.out.println( a.getName());
// }else {
// printFile(a);
// }
// }// //下面的只获取一层,上面是里面全部获取
// String[] names = file.list();
// for(String name : names){
// System.out.println(name);
// }
// //获取当前目录下的文件以及文件夹对象,只要拿到了文件对象,那么就可以获取更多信息
// File[] files = file.listFiles(); //listFiles指定的必须是目录。否则容易引发返回数组为null,出现NullPointerException异常
// for (File fi : files) {
// System.out.println(fi);
// }// 递归全部//1、判断传入的是否是目录if(!file.isDirectory()){//不是目录直接退出return;}//已经确保了传入的file是目录File[] files = file.listFiles();//遍历filesfor (File f: files) {//如果该目录下文件还是个文件夹就再进行递归遍历其子目录if(f.isDirectory()){//递归printFile(f);}else {//如果该目录下文件是个文件,则打印对应的名字System.out.println(f.getName());}}}public static void demo2(){//从d盘下的a.txt文件拷贝到另个盘下try {File file1 = new File("D:\\workspace\\a.txt");//这是源文件long flen=file1.length();System.out.println("源文件的大小是"+flen+"字节");FileInputStream fis = new FileInputStream(file1);File file2 = new File("D:\\workspace\\b.txt");//这是复制到的地方FileOutputStream fos = new FileOutputStream(file2);byte[] bytes = new byte[1024]; //这是1兆1兆传int len = 0;long readSize=0;while ((len = fis.read(bytes)) != -1) {//-1就是最后一个结束fos.write(bytes,0,len); //比如一个文件是1024*8+244,那么len就是244fos.flush();//强制输出,推送数据readSize+=len;if (readSize== flen) {break;}}System.out.println("读的大小"+readSize+"字节");} catch (Exception e) {e.printStackTrace();}}public static void demo1() {File file = new File("E:\\1.txt");File file1 = new File("E:\\222.txt");try {FileInputStream fis = new FileInputStream(file);FileOutputStream fos = new FileOutputStream(file1);BufferedInputStream bis = new BufferedInputStream(fis);byte[] bytes = new byte[1024];while (bis.read(bytes) != -1) {fos.write(bytes);fos.flush();System.out.println("aaaa");}} catch (Exception e) {e.printStackTrace();}}
}
FileOutputStream
FileOutputStream outputStream = new FileOutputStream("abc.txt");
这行代码做了下面的事情
1、调用系统功能去创建文件【输出流对象才会自动创建】
2、创建outputStream对象
3、把foutputStream对象指向这个文件
创建输出流对象的时候,系统会自动去对应位置创建对应文件,而创建输出流对象的时候,文件不存在则会报 FileNotFoundException 异常,也就是系统找不到指定的文件异常。
当你创建一个流对象时,必须直接或者间接传入一个文件路径。比如现在我们创建一个 FileOutputStream 流对象,在该路径下,如果没有这个文件,会创建该文件。如果有这个文件,会清空这个文件的数据
为什么是输入流呢
1、因为流是相对于内存来说的,现在 abc.txt 就是要保存到磁盘里面的文本,就是说从内存---->磁盘,那必须是输出流,用 FileWrite 和 FileOutputStream 都可以
2、传入路径时候是它的一种构造方法,不会继续写到文本中,所以用它的另外的构造函数即可解决这个问题。
-
public FileOutputStream(File file, boolean append) 一般不需要用这个,因为文件创建,输出流自动会帮我们生成,没必要多此一举暂时
-
public FileOutputStream(String name, boolean append) true 表示追加数据
Windows 系统里,每行结尾是 回车+换行 ,即\r\n;
Unix 系统里,每行结尾只有 换行 ,即\n;
Mac 系统里,每行结尾是 回车 ,即\r。从 Mac OS X 开始与 Linux 统一。
FileInputStream
流进内存的,输入流
1、 FileInputStream(File file): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File 对象 file 命名。
2、 FileInputStream(String name): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name 命名。
当你创建一个输入流对象时,必须传一个文件路径。该路径下,如果没有该文件,会抛出 FileNotFoundException
使用字节数组读取:read(byte[] b) 效率更高
int len = 0 ;byte[] bys = new byte[1024];while ((len = inputStream.read(bys)) != -1) {System.out.println(new String(bys,0,len));//len输出有效的字节数
Reader
字符输入流的所有类的超类 输入流
FileWriter
写出字符到文件的便利类 输出流
//关闭资源时,与 FileOutputStream 不同。 如果不关闭,数据只是保存到缓冲区,并未保存到文件。
// fw.close();
关闭 close 和刷新 flush
因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要 flush 方法了。
flush :刷新缓冲区,流对象可以继续使用。清空缓冲区的数据流
close:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
缓冲流
1、使用了底层流对象从具体设备上获取数据,并将数据存储到缓冲区的数组内。
2、通过缓冲区的 read()方法从缓冲区获取具体的字符数据,这样就提高了效率。
3、如果用 read 方法读取字符数据,并存储到另一个容器中,直到读取到了换行符时,将另一个容器临时存储的数据转成字符串返回,就形成了 readLine()功能。
也就是说在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统 IO 次数,从而提高读写的效率。
缓冲书写格式为 BufferedXxx,按照数据类型分类:
字节缓冲流:BufferedInputStream,BufferedOutputStream
字符缓冲流:BufferedReader,BufferedWriter
构造方法
public BufferedInputStream(InputStream in) :创建一个新的缓冲输入流,注意参数类型为 InputStream。
public BufferedOutputStream(OutputStream out): 创建一个新的缓冲输出流,注意参数类型为 OutputStream。
BufferedReader:public String readLine(): 读一行数据。 读取到最后返回 null,就这个特别一点,判断条件都需要修改了
BufferedWriter:public void newLine(): 换行,由系统属性定义符号。
转换流
简单一点的说就是:
编码:字符(能看懂的)–字节(看不懂的)
解码:字节(看不懂的)–>字符(能看懂的)
String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组
byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组编码:把看得懂的变成看不懂的
String -- byte[]解码:把看不懂的变成看得懂的
byte[] -- String
字符集 Charset:也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。
在 java 开发工具 IDEA 中,使用 FileReader 读取项目中的文本文件。由于 IDEA 的设置,都是默认的 UTF-8 编码,所以没有任何问题。但是,当读取 Windows 系统中创建的文本文件时,由于 Windows 系统的默认是 GBK 编码,就会出现乱码。
转换流 java.io.InputStreamReader,是 Reader 的子类,从字面意思可以看出它是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。
构造方法
InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。
InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。
构造代码如下:
InputStreamReader isr = new InputStreamReader(new FileInputStream("in.txt"));
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("in.txt") , "GBK");
OutputStreamWriter同理
案例 1
package com.nwa;import org.junit.Test;import java.io.*;/*** @Author Lucky友人a* @Date 2023/8/10 -10:34*/
public class FileDemo {@Testpublic void fun1() throws IOException {File f = new File("C:\\Users\\FF\\Desktop\\1.txt"); //就算文件1.txt不存在也不影响file对象的创建if (!f.exists()) {System.out.println("是否创建:"+f.createNewFile()); // true 如果没有文件则创建并返回true}System.out.println("是否创建:"+f.createNewFile()); //已经存在,所以就false了System.out.println("文件绝对路径:"+f.getAbsolutePath());//文件绝对路径:C:\Users\FF\Desktop\1.txtSystem.out.println("文件构造路径:"+f.getPath()); //文件构造路径:C:\Users\FF\Desktop\1.txtSystem.out.println("文件名称:"+f.getName()); //文件名称:1.txtSystem.out.println("文件长度:"+f.length()+"字节");// 判断是文件还是目录System.out.println("文件:"+f.isFile());System.out.println("目录:"+f.isDirectory());//一个路径下全部文件名,先将字符串转目录
// String path = "D:\\workspace";
// File file = new File(path);
// printFile(file);}
//结果1 传进的file不一样结果不一样,如果是绝对位置那么构造啥的都是绝对的
// 是否创建:false
// 文件绝对路径:C:\Users\FF\Desktop\1.txt
// 文件构造路径:C:\Users\FF\Desktop\1.txt
// 文件名称:1.txt
// 文件长度:0字节
// 文件:true
// 目录:false//结果2 如果是直接1.txt则会相对这个项目来创建这个文件
// 是否创建:true
// 是否创建:false
// 文件绝对路径:E:\LuckyWorckSpace\lucky_api\1.txt
// 文件构造路径:1.txt
// 文件名称:1.txt
// 文件长度:0字节
// 文件:true
// 目录:false@Testpublic void testDemo2() { //目录的创建等,使用相对这个项目下的目录来测试了// 目录的创建File f2= new File("newDira");
// System.out.println("是否存在:"+f2.exists());// false
// System.out.println("是否创建:"+f2.mkdir()); // 这个是创建的意思,并返回true
// System.out.println("是否存在:"+f2.exists());// true// 创建多级目录
// File f3= new File("newDira\\newDirb");
// System.out.println(f3.mkdir());// false,没有加s指南创建单层的目录File f4= new File("newDira\\newDirb");// System.out.println(f4.mkdirs());// true,可以创建多级别的目录// 文件和目录的删除 delete方法,如果此File表示目录,则目录必须为空才能删除。// System.out.println(f2.delete());// true// System.out.println(f4.delete());// false如果是删除多层目录只能删除最底层的比如这个的newDirb目录,外newDira没有删掉}@Testpublic void demo3() {File file = new File("E:\\other\\study\\学习sp\\实用篇");printFile(file);}public static void printFile(File file) {
// //获取当前目录下的文件以及文件夹的名称。
// File[] files = file.listFiles();
// for (File a:files) {
//
// if (a.isFile()) {
// System.out.println( a.getName());
// }else {
// printFile(a);
// }
// }// //下面的只获取一层,上面是里面全部获取
// String[] names = file.list();
// for(String name : names){
// System.out.println(name);
// }
// //获取当前目录下的文件以及文件夹对象,只要拿到了文件对象,那么就可以获取更多信息
// File[] files = file.listFiles(); //listFiles指定的必须是目录。否则容易引发返回数组为null,出现NullPointerException异常
// for (File fi : files) {
// System.out.println(fi);
// }// 递归全部//1、判断传入的是否是目录if(!file.isDirectory()){//不是目录直接退出return;}//已经确保了传入的file是目录File[] files = file.listFiles();//遍历filesfor (File f: files) {//如果该目录下文件还是个文件夹就再进行递归遍历其子目录if(f.isDirectory()){//递归printFile(f);}else {//如果该目录下文件是个文件,则打印对应的名字System.out.println(f.getName());}}}public static void demo2(){//从d盘下的a.txt文件拷贝到另个盘下try {File file1 = new File("D:\\workspace\\a.txt");//这是源文件long flen=file1.length();System.out.println("源文件的大小是"+flen+"字节");FileInputStream fis = new FileInputStream(file1);File file2 = new File("D:\\workspace\\b.txt");//这是复制到的地方FileOutputStream fos = new FileOutputStream(file2);byte[] bytes = new byte[1024]; //这是1兆1兆传int len = 0;long readSize=0;while ((len = fis.read(bytes)) != -1) {//-1就是最后一个结束fos.write(bytes,0,len); //比如一个文件是1024*8+244,那么len就是244fos.flush();//强制输出,推送数据readSize+=len;if (readSize== flen) {break;}}System.out.println("读的大小"+readSize+"字节");} catch (Exception e) {e.printStackTrace();}}public static void demo1() {File file = new File("E:\\1.txt");File file1 = new File("E:\\222.txt");try {FileInputStream fis = new FileInputStream(file);FileOutputStream fos = new FileOutputStream(file1);BufferedInputStream bis = new BufferedInputStream(fis);byte[] bytes = new byte[1024];while (bis.read(bytes) != -1) {fos.write(bytes);fos.flush();System.out.println("aaaa");}} catch (Exception e) {e.printStackTrace();}}
}
案例 2
package com.nwa;import org.junit.Test;
import org.omg.CORBA.PUBLIC_MEMBER;import java.io.*;/*** @Author Lucky友人a* @Date 2023/8/10 -14:14*/
public class IoDemo {@Testpublic void demo1() throws IOException {//public void write(int b)//public void write(byte[] b)//public void write(byte[] b,int off,int len) //从`off`索引开始,`len`个字节//构造方法中加入true即可追加数据,否则就是清空了FileOutputStream fos = new FileOutputStream("a.txt", true);//输出流,如果没有文件则帮忙创,有的话清空里面数据fos.write(97);//对于内存里流向本地磁盘,所以是输出流,而且会帮忙创建文件,并写入数据,所以才会清空fos.write(("我要吃汉堡").getBytes());fos.close();//a我要吃汉堡 97字节对于的是小写的a,字符串这个是转字节了FileWriter fileWriter = new FileWriter("b.txt");fileWriter.write("ss");//这个可以直接写入fileWriter.close();//写出指定长度字节数组:write(byte[] b, int off, int len) ,每次写出从off索引开始,len个字节// 使用文件名称创建流对象FileOutputStream fos2 = new FileOutputStream("a2.txt");// 字符串转换为字节数组byte[] b = "abcde".getBytes();// 写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。fos2.write(b, 2, 2);// 关闭资源fos2.close();}@Testpublic void delTxt() {new File("a.txt").delete();}@Testpublic void arrDemo() throws IOException {// 使用文件名称创建流对象FileOutputStream fos = new FileOutputStream("fos.txt");// 定义字节数组byte[] words = {97, 98, 99, 100, 101};// 遍历数组for (int i = 0; i < words.length; i++) {// 写出一个字节fos.write(words[i]);// 写出一个换行, 换行符号转成数组写出fos.write("\r\n".getBytes());}// 关闭资源fos.close();}@Testpublic void inputS() throws IOException {// 使用File对象创建流对象File file = new File("a2.txt");//这个文本中只有cd2个字符FileInputStream fis = new FileInputStream(file);//我把a.txt删了它就找不到了报错
// int read = fis.read();
// System.out.println((char)read);//不加char的话会转数字那种99---c
// int read1 = fis.read();//继续读取下一个字符
// System.out.println((char)read1);
// int read2 = fis.read();//如果是最后一个字符,它会返回-1,通过-1知道到底了
// System.out.println(read2);
// fis.close();//改进版1
// int b;
// while ((b = fis.read()) != -1) {
// System.out.println((char)b);
// }
// fis.close();//改进版2将文本里的值变成的abced,一次读取2个,结果出现了abcded//1 a b 2 c d 3e d 因为没替换就流着了,要解决一下改进3// 定义变量,作为有效个数
// int len;
// // 定义字节数组,作为装字节数据的容器
// byte[] b = new byte[2];
// // 循环读取
// while (( len= fis.read(b))!=-1) {
// // 每次读取后,把数组变成字符串打印
// System.out.println(new String(b));
// }// 关闭资源// fis.close();
// 改进3int len;// 定义字节数组,作为装字节数据的容器byte[] b = new byte[2];// 循环读取while ((len = fis.read(b)) != -1) {// 每次读取后,把数组变成字符串打印System.out.println(new String(b, 0, len));//len是每次读取有效的个数}// 关闭资源fis.close();}@Testpublic void copyPic() throws IOException {//将本地图片复制到项目下面FileInputStream fis = new FileInputStream("C:\\Users\\FF\\Desktop\\6.png");//输入流到内存FileOutputStream fos = new FileOutputStream("1.png");//内存输出到项目下面byte[] b = new byte[1024];int len;while ((len = fis.read(b)) != -1) {fos.write(b, 0, len);}fos.close();fis.close();}@Testpublic void readI() throws IOException {FileInputStream fis = new FileInputStream("1.txt");//输入流。文本中是中文你是大聪明,正常字节流去解析会乱码int len;byte[] bytes = new byte[1024];while ((len = fis.read(bytes)) != -1) {System.out.println((char) len); //乱码System.out.print(new String(bytes, 0, len));//String里自带了utf8解码所以可以。不过比较麻烦直接字符流解决}//下面用字符流FileReader fr = new FileReader("1.txt");int len2;while ((len2 = fr.read()) != -1) {System.out.print((char) len2);}}@Testpublic void copyText() throws IOException{FileWriter fileWriter = new FileWriter("66.md");FileReader fileReader = new FileReader("E:\\后端代码接收解析.md");char[] c=new char[1024];int len;while ((len = fileReader.read(c)) != -1) {fileWriter.write(c, 0, len);}fileWriter.flush();//清空缓冲区的数据流fileWriter.close();fileReader.close();}//下面开始测试缓存流的速度效率,1是正常,2是加入缓存@Testpublic void Buff1() throws IOException{long start = System.currentTimeMillis();FileOutputStream fos = new FileOutputStream("ps2015.zip");FileInputStream fis = new FileInputStream("E:\\other\\装机必备软件\\必备软件\\ps2015.zip");byte[] bytes = new byte[1024];int len;while ((len = fis.read(bytes)) != -1) {fos.write(bytes, 0, len);}fis.close();fos.close();// 记录结束时间long end = System.currentTimeMillis();System.out.println("普通流复制时间:"+(end - start)+" 毫秒");//33000}@Testpublic void Buff2() throws IOException{long start = System.currentTimeMillis();BufferedOutputStream fos =new BufferedOutputStream(new FileOutputStream("ps2015.zip")) ;BufferedInputStream fis =new BufferedInputStream(new FileInputStream("E:\\other\\装机必备软件\\必备软件\\ps2015.zip")) ;byte[] bytes = new byte[1024];int len;while ((len = fis.read(bytes)) != -1) {fos.write(bytes, 0, len);}fis.close();fos.close();// 记录结束时间long end = System.currentTimeMillis();System.out.println("缓冲流复制时间:"+(end - start)+" 毫秒");//缓冲流复制时间:4314 毫秒}@Testpublic void BuffRead() throws IOException {BufferedReader br = new BufferedReader(new FileReader("b.txt"));// 两个黄鹂鸣翠柳,一行白鹭上青天。 窗含西岭千秋雪,门泊东吴万里船。System.out.println(br.readLine()); // 读取一行的String len=null;while ((len = br.readLine()) != null) {System.out.println((len));}br.close();}@Testpublic void transform() throws IOException{// 定义文件路径,文件为gbk编码String FileName = "C:\\Users\\FF\\Desktop\\1.txt";// 创建流对象,默认UTF8编码InputStreamReader isr = new InputStreamReader(new FileInputStream(FileName));// 创建流对象,指定GBK编码InputStreamReader isr2 = new InputStreamReader(new FileInputStream(FileName) , "GBK");// 定义变量,保存字符int read;// 使用默认编码字符流读取,乱码while ((read = isr.read()) != -1) {System.out.print((char)read);}isr.close();// 使用指定编码字符流读取,正常解析while ((read = isr2.read()) != -1) {System.out.print((char)read); //如果这个txt默认是ANSI编码就需要GBK就不会乱码,如果本身就utf就不需要编码了}isr2.close();}}
异常处理
异常处理是一种重要的编程概念,用于处理程序执行过程中可能出现的错误或异常情况
必须捕获的异常,包括Exception
及其子类,但不包括RuntimeException
及其子类,这种类型的异常称为Checked Exception
不需要捕获的异常,包括Error
及其子类,RuntimeException
及其子类
- 数值类型的格式错误------------NumberFormatException
- 要打开的文件不存在------------FileNotFoundException
- 空指针------------NullPointerException------------对某个
null
的对象调用方法或字段 - 数组索引越界------------ArrayIndexOutOfBoundsException
- 数据库表不存在
- 向方法传递了一个不合法或不正确的参数
- 无法加载某个Class------------NoClassDefFoundError
- 栈溢出------------StackOverflowError
错误: 错误不是异常,而是脱离程序员控制的问题,错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的
所有的异常类是从 java.lang.Exception 类继承的子类。
Exception 类是 Throwable 类的子类。除了Exception类外,Throwable还有一个子类Error
异常类有两个主要的子类:IOException 类和 RuntimeException 类
捕获异常
如果不捕获异常,就需要抛出异常,直到有人捕获或者最高一级
使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。ctrl+alt+t
throws 是写在类那里--------------------throw 是直接在方法里面抛出
try/catch代码块中的代码称为保护代码,使用 try/catch 的语法如下:
try
{// 程序代码
}catch(ExceptionName e1)
{//Catch 块
}
throw 关键字用于在代码中抛出异常,而 throws 关键字用于在方法声明中指定可能会抛出的异常类型
当方法内部throws抛出指定类型的异常时,该异常会被传递给调用该方法的代码,并在该代码中处理异常。
public class Demo1 {public static void main(String[] args) {
// Scanner scanner = new Scanner(System.in);
// scanner = null;
// scanner.next(); //空指针java.lang.NullPointerException// int[] a = new int[]{1, 2};
// System.out.println(a[2]); //数组索引越界java.lang.ArrayIndexOutOfBoundsException// try {
// System.out.println(11 / 0); //0不能为除数java.lang.ArithmeticException异常
// } catch (ArithmeticException e) {
// System.out.println("捕获到了0不能为除数的异常");//这里抛出了运行时异常
// } catch (Exception e) {//最大异常,上面捕获了下面就捕获了
// throw new RuntimeException(e); //这里抛出了运行时异常
// } finally {
// System.out.println("这里必运行,一般用来关闭");
// }// checkNumber(-1);//非法参数异常IllegalArgumentExceptiontry {// readFile("D:\\1.txt");//去d盘新建1.txt,内容随便写点readFile("D:\\1.txt");//没找到就会有异常System.out.println("找到了");} catch (IOException e) {throw new RuntimeException(e);}}public static void checkNumber(int num) {if (num < 0) {throw new IllegalArgumentException("Number must be positive");//当代码执行到某个条件下无法继续正常执行时,可以使用 throw 关键字抛出异常,以告知调用者当前代码的执行状态}}public static void readFile(String filePath) throws IOException {// 包含了文件没找到异常,如果还有其他异常,隔开继续写BufferedReader reader = new BufferedReader(new FileReader(filePath));String line = reader.readLine();while (line != null) {System.out.println(line);line = reader.readLine();}reader.close();}
}
JDK7 之后,Java 新增的 try-with-resource 语法结构,旨在自动管理资源,确保资源在使用后能够及时关闭,避免资源泄露 。
try (resource declaration) {// 使用的资源
} catch (ExceptionType e1) {// 异常块
}
public class Demo1 {public static void main(String[] args) {String line;try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {//如果多个;隔开继续newwhile ((line = br.readLine()) != null) {System.out.println("Line =>" + line);}} catch (IOException e) {System.out.println("IOException in try block =>" + e.getMessage());}}
}
结果:IOException in try block =>test.txt (系统找不到指定的文件。)
public class Demo1 {public static void main(String[] args) {BufferedReader br = null;String line;try {System.out.println("Entering try block");br = new BufferedReader(new FileReader("test.txt"));while ((line = br.readLine()) != null) {System.out.println("Line =>" + line);}} catch (IOException e) {System.out.println("IOException in try block =>" + e.getMessage());} finally {//比较繁琐System.out.println("Entering finally block");try {if (br != null) {br.close();}} catch (IOException e) {System.out.println("IOException in finally block =>" + e.getMessage());}}}
}
全局异常处理器
在应用程序中,当抛出异常时,如果没有特定的异常处理器来处理该异常,就会尝试使用全局异常处理器来处理
@RestControllerAdvice
public class RRExceptionHandler {private Logger logger = LoggerFactory.getLogger(getClass());/*** 处理自定义异常*/@ExceptionHandler(RRException.class)public R handleRRException(RRException e){R r = new R();r.put("code", e.getCode());r.put("msg", e.getMessage());return r;}@ExceptionHandler(NoHandlerFoundException.class)public R handlerNoFoundException(Exception e) {logger.error(e.getMessage(), e);return R.error(404, "路径不存在,请检查路径是否正确");}@ExceptionHandler(DuplicateKeyException.class)public R handleDuplicateKeyException(DuplicateKeyException e){logger.error(e.getMessage(), e);return R.error("数据库中已存在该记录");}@ExceptionHandler(AuthorizationException.class)public R handleAuthorizationException(AuthorizationException e){logger.error(e.getMessage(), e);return R.error("没有权限,请联系管理员授权");}@ExceptionHandler(Exception.class)public R handleException(Exception e){logger.error(e.getMessage(), e);return R.error();}
}
自定义异常类
public class RRException extends RuntimeException {private static final long serialVersionUID = 1L;private String msg;private int code = 500;public RRException(String msg) {super(msg);this.msg = msg;}public RRException(String msg, Throwable e) {super(msg, e);this.msg = msg;}public RRException(String msg, int code) {super(msg);this.msg = msg;this.code = code;}public RRException(String msg, int code, Throwable e) {super(msg, e);this.msg = msg;this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public int getCode() {return code;}public void setCode(int code) {this.code = code;}
}
API
Random
获取随机数
public class Demo1 {public static void main(String[] args) {Random random = new Random(); //new出这个对象int randomValue1 = random.nextInt(2); //调用这个对象的方法 范围是0~1的整数System.out.println(randomValue1);int randomValue2 = random.nextInt(90) + 10;//范围是10-99的整数System.out.println(randomValue2);int randomValue3 = random.nextInt(1000) - 500;//范围-500~500,500取不到System.out.println(randomValue3);}
}
Scanner
获取控制台输入的值
public class Demo1 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入名称:");String name = scanner.nextLine();System.out.println("请输入密码:");String pwd = scanner.nextLine();System.out.println(name + "--左名称右密码--" + pwd);System.out.println("请输入整数n:");int i = 0;if (scanner.hasNextInt()) { //加个判断防止异常,还有hasNextDouble等i = scanner.nextInt(); // 判断输入的是否是整数System.out.println("整数数据:" + i);} else {System.out.println("输入的不是整数!"); // 输入错误的信息}System.out.println("i为" + i);scanner.close(); //用完就关闭}
}
Date
java.util 包提供了 Date 类来封装当前的日期和时间。 Date 类提供两个构造函数来实例化 Date 对象
public class Demo1 {public static void main(String[] args) {Date date = new Date();// 参考https://www.runoob.com/java/java-date-time.htmlSystem.out.printf("全部日期和时间信息:%tc%n", date);System.out.printf("年-月-日格式:%tF%n", date);System.out.printf("月/日/年格式:%tD%n", date);System.out.printf("HH:MM:SS PM格式(12时制):%tr%n", date);System.out.printf("HH:MM:SS格式(24时制):%tT%n", date);System.out.printf("HH:MM格式(24时制):%tR%n", date);System.out.printf("%tY-%tm-%td %tH:%tM:%tS %tZ%n", date, date, date, date, date, date, date);System.out.println("-----------------------------------");Date dNow = new Date();//yyyy 是完整的公元年,MM 是月份,dd 是日期HH:mm:ss 是时、分、秒 SSS毫秒SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss:SSS");String format = ft.format(dNow);System.out.println("当前时间为: " + format);//当前时间为: 2024-06-12 04:59:08:803}
}
Calendar
Calendar类是一个抽象类,在实际使用时实现特定的子类的对象,创建对象的过程对程序员来说是透明的,只需要使用getInstance方法创建即可
我们如何才能设置和获取日期数据的特定部分呢,比如说小时,日,或者分钟? 我们又如何在日期的这些部分加上或者减去值呢? 答案是使用Calendar 类
public class Demo1 {public static void main(String[] args) {String months[] = {"Jan", "Feb", "Mar", "Apr","May", "Jun", "Jul", "Aug","Sep", "Oct", "Nov", "Dec"};int year;// 初始化 Gregorian 日历// 使用当前时间和日期// 默认为本地时间和时区GregorianCalendar gcalendar = new GregorianCalendar();// 显示当前时间和日期的信息System.out.print("Date: ");System.out.print(months[gcalendar.get(Calendar.MONTH)]);System.out.print(" " + gcalendar.get(Calendar.DATE) + " ");System.out.println(year = gcalendar.get(Calendar.YEAR));System.out.print("Time: ");System.out.print(gcalendar.get(Calendar.HOUR) + ":");System.out.print(gcalendar.get(Calendar.MINUTE) + ":");System.out.println(gcalendar.get(Calendar.SECOND));// 测试当前年份是否为闰年if (gcalendar.isLeapYear(year)) {System.out.println("当前年份是闰年");} else {System.out.println("当前年份不是闰年");}}
}
Math
Java 的 Math 包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数
Math 的方法都被定义为 static 形式,通过 Math 类可以在主函数中直接调用
public class Test { public static void main (String []args) { System.out.println("返回两个参数中的最大值:" + Math.max(1, 2));System.out.println("返回两个参数中的最小值:" + Math.min(0, 3));System.out.println("60度的正切值:" + Math.tan(Math.PI / 3));System.out.println("1的反正切值: " + Math.atan(1));System.out.println("π/2的角度值:" + Math.toDegrees(Math.PI / 2));System.out.println(Math.PI);}
}
String
String 类是不可改变的final修饰,所以你一旦创建了 String 对象,那它的值就无法改变
如果需要对字符串做很多修改,那么应该选择使用 StringBuffer & StringBuilder 类
String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上
public class Demo1 {public static void main(String[] args) {String s1 = "Runoob"; // String 直接创建String s2 = "Runoob"; // String 直接创建String s3 = s1; // 相同引用String s4 = new String("Runoob"); // String 对象创建String s5 = new String("Runoob"); // String 对象创建System.out.println(s1 == s2);System.out.println(s1 == s3); //s1、s2、s3都是直接创建,都指向同一个公共池里的值和对象System.out.println(s1.equals(s3)); //true 值肯定相等、并且都在公共池中System.out.println(s4 == s5); //false 这个比较是对象引用,2个不同对象在不同堆中,值相同System.out.println(s4.equals(s5)); //true 这个比较的是值}
}
public class Demo1 {public static void main(String[] args) {String str = "Hello World";System.out.println(str.length()); //结果11,返回字符串的长度空格和!都算,用于不确定字符串长度时候System.out.println(str.charAt(1)); //e,返回字符串1的位置,从0开始,长度是str的长度-1,可用于验证码的实现System.out.println(str.indexOf("h")); //-1,查找这个字符,没查到则返回-1System.out.println(str.indexOf("o")); //4,查找第一个,并返回索引值System.out.println(str.substring(4)); //o World,字符串的截取 从下标4开始System.out.println(str.substring(4, str.length() - 2)); //o Wor,[4,9)参数1是开始位置 参数2是结束,左闭右开System.out.println(str.toLowerCase()); //全部转小写System.out.println(str.toUpperCase()); //全部转大写String[] split = str.split(" ");//Hello//World//根据空格切割for (int i = 0; i < split.length; i++) {System.out.println(split[i]);}System.out.println("-----------------------------------");String str1 = "Hello1 World2";System.out.println(str1.indexOf("1", 4)); //5,查的必须是字符串类型,第二次参数是开始位置,这是正向搜、4,5刚好就是1返回5System.out.println(str1.lastIndexOf("l")); //10,查找最后一个l,并返回它的索引值System.out.println(str1.lastIndexOf("l", 11));//10,11是d,然后开始反向搜到l直接返回索引System.out.println("-----------------------------------");System.out.println("abc".compareTo("abcde")); //-2,返回整型,比较对应字符的大小(ASCII码顺序)System.out.println("abc".compareTo("abc")); //0,相同返回0System.out.println("12789".compareTo("123")); //4,回字符串长度,比较7和3返回4System.out.println("abc".equals("a")); //false,判断2个字符串是否相等,需要完全一样System.out.println("abc".equals("abc")); //TrueSystem.out.println("abc".equalsIgnoreCase("ABC")); //true,忽略大小写System.out.println("abc".concat("derfg")); //abcderfg 字符串拼接,用+也可以System.out.println("nnnwa".replace("n", "g")); //gggwa,替换所有n,第一个参数是需要被替换的,第二个是替换的System.out.printf("浮点型变量的值为 " +"%f, 整型变量的值为 " +" %d, 字符串变量的值为 " +"is %s", 1.12f, 16, "LuckyNwa");System.out.println("nwa".contains("nw")); //true,包含它返回布尔值,顺序有影响System.out.println("nwa".endsWith("a")); //true,包含它返回布尔值,测试是否以字符a结尾System.out.println(" hello world ".trim()); //hello world,去除前后空格,不去中间}
}
https://www.runoob.com/java/java-string.html 参考这
总结
length方法使用地方特别多,比如数组遍历时候就需要,字符串同,不知道长度可以直接用这方法获取
s=“aascsaxaca”;它的下标就是0到s.length()-1
indexOf可以用来查询是否存在,返回值为-1则不存在,也可以查询这个字符串第一次出现的地方
charAt方法可用于验证码的实现,把验证码需要的字符串存在一个变量里,通过charAt(new Random().nextInt(codeBox.length()))来获取随机字符
trim方法去首尾空格,用于登录时候输入有空格的把空格直接去掉,用的范围也挺广 以及split用的很多,可以根据空格,-等分割
isEmpty判断是否为空
StringBuffer 和 StringBuilder
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象
StringBuilder 类在 Java 5 中被提出,StringBuilder不是线程安全,StringBuffer 线程安全
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类
public class Demo1 {public static void main(String[] args) {StringBuilder sb;sb = new StringBuilder(10);sb.append("Runoob..");System.out.println(sb);sb.append("!");System.out.println(sb);sb.insert(8, "Java");System.out.println(sb);sb.delete(5, 8);System.out.println(sb);StringBuilder luckyNwa = new StringBuilder("LuckyNwa");luckyNwa.append("你好啊");System.out.println(luckyNwa);}
}
其他
转义序列
前面有反斜杠(\)的字符代表转义字符,它对编译器来说是有特殊含义的
列表展示了Java的转义序列: