# 一、初识Java
## 1.java关键字
public 公共的、公开的
class 类
static 静态的
void 空的
main main方法
String 字符串
System 系统
## 2.注意点
1)注意大括号、小括号、中括号成对出现
2)注意每一行代码后有分号结束
3)注意所有符号都是英文符号
4)注意缩进(tab shift+tab)
5)公共类的类名要和源文件名同名
## 3.java注释
### 1)单行注释
//
### 2)多行注释
/*
....
*/
### 3)文档注释(javadoc注释)
/**
....
*/
## 4.常用快捷键
ctrl + s 保存
ctrl + c 复制
ctrl + v 粘贴
ctrl + x 剪切
ctrl + z 撤销上一步操作
ctrl + y 返回下一步操作
ctrl + a 全选
ctrl + shift + 左右键 选择单词
shit + home/end 选择一整行
alt + 上下键 把光标所在行上下移动
alt + shift + r 重命名
alt + insert 新建
shift + 上下左右键 选择内容
ctrl + / 注释
ctrl + shift + f 格式化代码
# 二、变量、数据类型以及运算符
## 1.变量
变量类型:char、int、double、String
java中的8种基本类型:
byte char short int long float double boolean
变量命名规范:
可以由字母、数字、下划线、$符号组成,开头不能是数字
使用骆驼命名法命名(首字母小写,后面每个单词首字母大写)
起有意的名字,见名知意
## 2.常量
final关键字用来修饰常量
final int num = 10;
num=100;//这一行报错,因为常量不允许修改
## 3.运算符
### 1)赋值运算符
= 运算时把右侧的值赋值给左侧
### 2)算术运算符
+ -/ %
注意:
如果操作数都是整数
/ 是用来取商的
% 是用来取余数的
如果操作数中有一个是double(也可以都是)
则 / 可以计算出小数,需要用double来接收结果
### 3)比较运算符
==、>、<、>=、<=、!=
### 4)逻辑运算符
&& : 并且(与)
|| : 或者(或)
! : 非
优先级:非、与、或
/*
* 讨论关于java中几种运算符之间的执行优先级
* 1."()"运算优先级最高,一般可用于手动改变表达式中不同运算符的运算顺序
* 2.“!”,“++”,“--”称为单目运算符(只对一个操作数进行运算称为单目),优先级高
* 3.对一些常用的运算符(双目)之间:算术运算符 > 关系运算符 > 逻辑运算符
* 3.1 算术运算符中: + - * / % ++ --
* 除++,--之外:* / % 优先于 + - ,当有并列优先级时例如: 4 * 5 / 2,从左向右运算
* 3.2 关系运算符: == != > < >= <=
* > < >= <= 只能用于数值类型的数据比较
* > < >= <= 优先级高于 == !=
* 当有并列优先级时例如: 5 > 3 == 2 < 4 ,从左向右运算
* 3.3 逻辑运算符: & && | || !
* 除!外:&& 优先于 ||
* 逻辑与(&) 同 短路与(&&) 相比:不论第一个操作数是否为false,都会运算第二个操作数,而短路与不会
* 逻辑(|) 同 短路或(||) 相比: 不论第一个操作室是否为true,都会运算第二个操作数,而短路或不会
* 4. “=”,"?:","!","++","--"这5个符合在运算时从右向左。
* 总结:
* "!","++","--"(同时出现在一个表达式中时,从右向左)
* 优先于
* "*","/","%" (从左向右)
* 优先于
* "+","-" (从左向右)
* 优先于
* ">","<",">=","<="(从左向右)
* 优先于
* "&","&&"
* 优先于
* "|","||"
* 优先于
* "?:"
* 以上优先级为java表达式运算时的默认执行顺序,任何一个运算符在使用“()”时都将提升为最高,
* 有多个()并列出现时,从左往右
* 有多个()嵌套出现时,从内向外
*/
## 4.类型转换
### 1)自动类型转换
int a = 5;
double b = 2.5;
double c = a + b; //表达式中如果有double类型,则整体运算结果提升为double类型
int a = 5;
double b = a; //自动提升,int可以直接赋值给double
### 2)强制类型转换
double a = 123.567;
int b = a; //这样会报错,double类型不能直接赋值给int类型,数据宽度问题
int b = (int)a; // 这样就是强转了,b的结果是123,小数部分舍弃
## 5.其他
### 1)从控制台输入
先导包
import java.util.Scanner;
再声明Scanner对象
Scanner input = new Scanner(System.in)
再使用相应的方法从控制台获取用户输入的数据
String name = input.next();
int age = input.nextInt();
double score = input.nextDouble();
### 2)++的问题
int a = 5;
a++; //等价于 a = a + 1
# 三、流程控制—选择结构和循环结构
## 1.流程图
菱形:条件判断
矩形:运算
平行四边形:输入、输出
圆角矩形:开始、结束
![image-20211202161501565](images/image-20211202161501565.png)
## 2.if语句
if(条件){
//代码块
}
if(条件){
//代码块1
}else{
//代码块2
}
多重if语句 :
if(条件1){
//代码块1
}else if(条件2){
//代码块1
}else{
//...
}
嵌套if语句:
if(条件1){
//...
if(条件2){
//...
}
//...
}else{
//....
}
## 3.字符串的判断相等
equals() 字符串等值比较
equalsIgnoreCase() 忽略字母大小写进行比较
## 4.switch
注意点:
1)switch的变量类型允许的:
int、char、byte、short、String(jdk1.8以后)
1)case后的常量不能重复
2)case的顺序可以调换
3)break如果省略,会出现贯穿的情况
4)default一般放在最后,其中的break可以省略
从语法上来看default也可以省略
/*
* switch分支结构的特点:
* 1、只能用于表达式运算结果和case之后的常量值之间的等值判断
* 2、表达式只能是:int,short,byte,char,String,枚举这些类型
* 3、在每个case后的break可以省略,
* 若省略则执行该case分支代码后将“贯穿”执行下一个case的代码块,
* 这种“贯穿”直到遇到break或者switch的”}“为止
* 4、多个case后的常量值不能相同
* 5、如果default的位置不在最后,表达式判断的顺序不变,
* 仍旧是先判断所有case,在不满足任何case后才执行default分支
* 6、当有等值判断的多分支需求时,超过3个以上分支使用switch效率比多重if要高
*/
![image-20211207143658364](images/image-20211207143658364.png)
# 四、数组
## 1.数组的定义
存储固定大小的同类型元素
## 2.数组的创建
~~~java
int[] nums;//声明数组
nums = new int[5];//创建数组
int[] nums1 = new int[5];//声明并创建数组
int nums2 = {1,2,3,4,,5};//创建的同时并给数组赋初始值
int nums3 = new int{1,2,3,4,5};//创建的同时并给数组赋初始值
~~~
## 3.数组的访问
通过下标访问
# 五、面向对象和封装
## 1.类和对象的关系
类是对象的抽象,对象是类的具体表现
## 2.类的成员:
+ 属性:描述类的静态特征
+ 类变量:类加载时就会分配空间,通过类名调用,不提倡通过对象调用
+ 成员变量:调用构造函数时才会分配空间,只能通过对象调用。
+ 方法:描述类的动态行为
+ 代码块:
+ 静态代码块:加载类是执行的代码块
+ 代码块:定义对象是执行的代码块
## 3.构造方法
+ 初始化类的属性
+ 方法名与类名相同
## 4.对象的创建
~~~java
Car car = new Car(); //new 关键字创建空间,构造方法用于初始化属性
~~~
# 六、继承和多态
## 1.继承的基本概念
继承是从已有的类创建新类的过程。
+ 继承是面向对象的三大特征之一
+ 被继承的类被称为父类(超类),继承父类的类叫做子类(派生类)
+ 继承是指一个对象直接使用另一个对象的属性和方法
+ 通过继承可以实现代码重用
## 2.继承的限制
+ java只能实现单继承,也就是一个类只能又一个父类。
+ 允许多层继承,即:一个子类可以有一个父类,一个父类还可以有其他的父类。
+ 继承只能继承非私有的属性和方法。
+ 构造方法不能被继承
![image-20211223163501262](images/image-20211223163501262.png)
## 3.子类的实例化过程
在子类经行实例化操作的时候,首先会让其父类进行初始化操作,之后子类再自己进行实例化操作。
### 1)子类的实例化过程:
子类实例化时会先调用父类的构造方法,如果父类中没有默认的构造方法,在子类的构造方法中必须显示的调用父类的构造方法 。
### 2)结论:
构造方法只是用于初始化类中的字段以及执行一些初始化代码,**调用构造方法并不代表会产生对象**。
## 4.方法重写
### 1)方法重写:
在java中,子类可以继承父类中的方法,而不需要重新编写相同的方法。但有时子类不想原封不动地继承父类的方法,而是想做一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。在子类和父类中,重写方法后,在调用时,以创建的对象类型为准,会调用谁的方法。
### 2)方法重写的一些特性
+ 发生在子父类中,方法重写的两个方法的返回值、方法名、参数列表必须完全一致。
+ 子类抛出的异常不能超过父类相应方法抛出的异常。
+ 子类方法的访问级别不能低于父类相应方法的访问级别。
+ 父类中的方法若使用private、static、final任意修饰符修饰,不能被子类重写。
![image-20211224100007100](images/image-20211224100007100.png)
## 5.super关键字
+ 使用super调用父类中的属性,可以从父类实例中获得信息。
+ 使用super调用父类中的方法,可以委托父类对象帮助完成某件事情。
+ 使用super调用父类的构造方法(super(实参)形式),必须在子类构造方法中的第一条语句,调用父类中相应的构造方法,若不显示的写出来,默认调用父类无参的构造方法。
## 6.final关键字
+ 使用final关键字声明一个变量:修饰属性或者修饰局部变量,也称为常量。
+ 使用final关键字声明一个方法:该方法为最终方法,只能被子类继承,不能被子类改写。
+ 使用final关键字声明一个类:该类就转变成为最终类,无法被继承。
+ 在方法参数中使用final关键字:在方法内部不能修改参数的值(在内部中详解)。
## 7.多态性
+ 方法的重写与重载就是方法的多态性表现
+ 多个子类就是父类中的多种形态
+ 父类引用可以指向子类对象,自动转换
+ 子类对象指向父类引用需要强制转换(类型不对会报异常)
+ 在实际开发中尽量使用父类引用(更利于扩展)
## 8.instanceof关键字
是用于检查对象是否为指定的类型,通常在把父类引用强制转换为子类引用时要使用,以避免发生类型转换异常(ClassCastException)。
# 七、抽象类、接口和异常
## 1.抽象类的基本概念
+ 很多具有相同特征和行为的对象可以抽象为一个类,很多具有相同特征和行为的类可以抽象为一个抽象类
+ 使用abstract关键字声明的类为抽象类
+ 抽象类不能被实例化
## 2.抽象方法的基本概念
+ 在Java中,当一个类的方法被abstract关键字修饰时,该方法称为抽象方法。抽象方法所在的类必须定义为抽象类。
+ 抽象方法没有方法体。
## 2.接口
### 1)接口的使用规则
+ 定义一个接口使用interface关键字
+ 在一个接口中,只能定义常量、抽象方法,JDK1.8后可以定义默认的实现方法
+ 接口可以继承多个接口:extends xxx,xxx
+ 一个具体类实现接口使用implements关键字
+ 一个类可以实现多个接口
+ 抽象类实现接口可以不实现接口的方法
+ 在接口中定义的方法没有声明访问修饰符,默认为public
+ 接口不能有构造方法
+ 接口不能被实例化
### 2)面向对象设计原则
+ 对修改关闭,对扩展开放
+ 面向接口编程
## 3.oo原则总结
+ 开闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
+ 合成/聚合复用原则:新对象的某些功能在已创建好的对象里实现,那么尽量用已有对象提供的功能,使之成为新对象的一部分,而不要再重新创建。
+ 依赖倒置原则:高层模块不依赖底层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
+ 接口隔离原则:客户端不应该依赖它不需要的接口,一个类对另一个类的依赖应该建立在最小的接口之上。
+ 迪米特法则:一个对象应该对其它对象保持最少的了解。
+ 里氏替换原则:所有引用基类的地方必须能够透明地使用其子类对象。
+ 单一职责原则:不要存在多于一个导致类变更地原因,即一个类知负责一项原则。
## 4.抽象类与接口的异同点
相同点:
+ 不能实例化对象,只能通过子类(实现类)对象指向指向自己的引用
+ 都可以有抽象方法、属性
+ 都属于父级元素
不同点:
+ 接口的方法只能是抽象方法和静态方法,抽象类可以有抽象方法,也可以没有,其他类型的方法也都可以有
+ 接口中的属性只能是公有静态属性(public static final),抽象类没有限制
+ 本质不同,一个是类,一个是接口
## 5.异常
### 1.异常的定义:
异常是指在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序。
### 2.异常处理的五个关键字:
try、catch、finally、throws、throw
finally代码块只有在catch块中有System.exit()时才不会执行,其他任何情况都会执行。
![image-20211230101038341](images/image-20211230101038341.png)
# 八、Object类和内部类
## 1.Object类
每个类都是用Object类作为超类。所有对象(包括数组)都实现这个类的方法。
## 2.内部类
### 1)成员内部类
~~~java
public class Demo5 {
public static void main(String[] args) {
A a = new A();
A.B b = a.new B();
b.say();
}
}
class A{
private int num;
class B{
public void say(){
System.out.println("我是内部类");
}
}
}
~~~
图8.1
~~~java
public class Demo5 {
public static void main(String[] args) {
A a = new A();
a.printB();
}
}
class A{
private int num;
public void printB(){
B b = new B();
b.say();
}
private class B{
public void say(){
System.out.println("我是成员内部类");
}
}
}
~~~
图8.2
上述两份代码皆为内部类方法的调用,建议使用第二种。第二种封装了内部类,向外提供了使用内部类的接口(方法)。
### 2)方法内部类
+ 方法内部类只能在定义该内部类的方法内进行实例化,不可以在方法外进行实例化。
+ 方法内部类对象不能使用该内部类所在方法的非final局部变量(jdk1.8之后一旦使用了没有final修饰符的局部变量,该变量就成了就成了final变量,不能再修改其值)。
~~~java
public class Demo5 {
public static void main(String[] args) {
A a = new A();
a.printB();
a.method();
}
}
class A{
private int num;
public void printB(){
B b = new B();
b.say();
}
private class B{
public void say(){
System.out.println("我是成员内部类");
}
}
public void method(){
class C{
public void say(){
System.out.println("我是方法内部类");
}
}
C c = new C();
c.say();
}
}
~~~
### 3)静态内部类
静态的含义是该内部类可以像其它静态成员一样,没有外部类对象时,也能够访问它。静态内部类仅能访问外部类的静态成员和方法。
~~~java
public class Demo5 {
public static void main(String[] args) {
A a = new A();
a.printB();
a.method();
A.D d = new A.D();
d.say();
}
}
class A{
private int num;
public void printB(){
B b = new B();
b.say();
}
private class B{
public void say(){
System.out.println("我是成员内部类");
}
}
public void method(){
class C{
public void say(){
System.out.println("我是方法内部类");
}
}
C c = new C();
c.say();
}
static class D{
public void say(){
System.out.println("我是静态内部类");
}
}
}
~~~
### 4)匿名内部类
+ 继承式匿名内部类
~~~java
public class Demo5 {
public static void main(String[] args) {
Cat cat = new Cat(){
public void say(){
System.out.println("我是继承式匿名内部类");
}
};
cat.say();
}
}
abstract class Cat{
abstract public void say();
}
~~~
+ 接口式匿名内部类
~~~java
public class Demo5 {
public static void main(String[] args) {
Cat cat = new Cat(){
public void say(){
System.out.println("我是继承式匿名内部类");
}
};
cat.say();
Icat cat1 = new Icat() {
public void say(){
System.out.println("我是接口式匿名内部类");
}
};
cat1.say();
}
}
abstract class Cat{
abstract public void say();
}
interface Icat{
void say();
}
~~~
+ 参数式匿名内部类
~~~java
public class Demo5 {
public static void main(String[] args) {
Demo demo = new Demo();
demo.say(new Icat() {
public void say(){
System.out.println("我是参数式匿名内部类");
}
});
}
}
interface Icat {
void say();
}
class Demo {
public void say(Icat icat) {
icat.say();
}
}
~~~
### 5)使用匿名内部类的原则:
+ 不能有构造方法,只能由一个实例
+ 不能定义任何静态成员、静态方法(没有类名)
+ 一定是跟在new的后面,用其隐含实现一个接口或继承一个类
+ 匿名内部类为局部的,所以局部内部类的所有限制都对其生效
### 6)内部类的作用:
每个内部类都能独立地继承自一个(接口地)实现,所以无论外部类是否继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。
# 九、数据结构之链表
~~~java
public class Demo5 {
public static void main(String[] args) {
NodeManager nodeManager = new NodeManager();
nodeManager.add(5);
nodeManager.add(4);
nodeManager.add(3);
nodeManager.print();
System.out.println("删除"+nodeManager.del(2));
nodeManager.print();
System.out.println("查找"+nodeManager.find(2));
System.out.println("更新"+nodeManager.updata(4,6));
nodeManager.print();
nodeManager.insert(0,1);
nodeManager.print();
}
}
class NodeManager {
private Node root; //根节点
private int currentIndex = 0;
public void add(int data) {
if (root == null) {
root = new Node(data);
} else {
root.addNode(data);
}
}
public boolean del(int data) {
if(root == null) return false;
if (root.getData() == data) {
root.next = root;
return true;
} else {
return root.delNode(data);
}
}
//打印所有
public void print() {
if (root != null) {
System.out.print(root.getData() + " ");
root.printNode();
System.out.println();
}
}
//查找是否存在节点
public boolean find(int data) {
if (root != null) {
if (root.getData() == data) {
return true;
} else {
return root.findNode(data);
}
}
return false;
}
public boolean updata(int oldData, int newData) {
if(root == null) return false;
if(root.getData() == oldData){
root.setData(newData);
return true;
}else {
return root.updataNode(oldData,newData);
}
}
public void insert(int index, int data) {
if(index < 0)return;
currentIndex = 0; //初始化
if(index == currentIndex){
Node newNode = new Node(data);
newNode.next = root.next;
root.next = newNode;
}else {
root.insertNode(index,data);
}
}
class Node {
private int data;
private Node next;
public Node(int data) {
this.data = data;
}
public void setData(int data) {
this.data = data;
}
public int getData() {
return data;
}
//添加节点
public void addNode(int data) {
if (this.next == null) {
this.next = new Node(data);
} else {
this.next.addNode(data);
}
}
//删除节点
public boolean delNode(int data) {
if(this.next == null)return false;
if (this.next.getData() == data) {
this.next = this.next.next;
return true;
} else {
return this.next.delNode(data);
}
}
//打印所有节点
public void printNode() {
if (this.next != null) {
System.out.print(this.next.getData() + " ");
this.next.printNode();
}
}
//查找节点是否存在
public boolean findNode(int data) {
if (this.next != null) {
if (this.next.getData() == data) {
return true;
} else {
return this.next.findNode(data);
}
}
return false;
}
//修改节点
public boolean updataNode(int oldData, int newData) {
if(this.next == null) return false;
if(this.next.getData() == oldData){
this.next.setData(newData);
return true;
}else {
return this.next.updataNode(oldData,newData);
}
}
//插入节点
public void insertNode(int index, int data) {
currentIndex++;
if(index == currentIndex){
Node newNode = new Node(data);
newNode.next = this.next.next;
this.next.next = newNode;
}else {
this.next.insertNode(index, data);
}
}
}
}
~~~
# 十、基本数据类型包装类
## 1.装箱及拆箱操作
将一个基本数据类型转换为包装类,那么这样的操作称为装箱操作。将一个包装类转换为基本数据类型,这样的操作称为拆箱操作。
~~~java
public class Demo1 {
//将基本数据类型转换为包装类,称为自动装箱
Integer i1 = new Integer(10);
//将包装类转换为基本数据类型,称为自动拆箱
int i2 = i1.intValue();
Integer i3 = 10; //建议方式
Integer i4 = new Integer("123");
//把数值字符串转换为int类型
String num1 = "12";
int i5 = Integer.parseInt(num1);
Integer i6 = Integer.valueOf(num1);
int i7 = Integer.valueOf(num1); //自动拆箱
}
~~~
# 十一、常用类库
## 1.String类
+ String类可以表示一个字符串
+ **String类实际上是用字符数组存储的**
+ 使用final修饰,不能被继承
### 1)String类的两种赋值方式:
~~~java
//直接赋值
String name1 = "小白";
//通过关键字new调用String的构造方法赋值
//下面的代码会创建两个对象(如果常量池中没有小黑,就会在常量池中创建这个对象,然后通过new再在堆中创建一个小黑对象
String name2 = new String("小黑");
~~~
### 2)直接赋值字符串连接的4种情况:
考虑编译期和运行期,如果代码在编译期就可以被确定,那么就使用已有的对象,否则会在运行其创建新的对象。
~~~java
public class Demo1 {
public static void main(String[] args) {
//结果为false
String a = "a";
String a1 = a+1; //在编译期a1看到的a是变量所以a1不能确定
String a2 = "a1";
System.out.println(a1 == a2);
//结果为true
final String b = "b";
String b1 = b+1; //b被申明为常量,b1在编译期可以确定
String b2 = "b1";
System.out.println(b1 == b2);
//结果为false
String c = getC();
String c1 = getC() + 1; //方法只有在运行期才被调用,所以c1的值也无法确定,要在运行期在堆中用new创建
String c2 = "c2";
//结果为false
final String d = getD();
String d1 = getD() + 1; //原因同第3种
String d2 = "d2";
}
private static String getC(){
return "c";
}
private static String getD(){
return "d";
}
}
~~~
### 3)String类的常用方法
#### ①String类字符与字符串操作方法
+ 普通方法 public char charAt(int intdex) 根据下标找到指定的字符
+ 普通方法 public char [] toCharArray() 以字符数组的形式返回字符串的全部内容
+ 构造方法 public String (char [] value) 将全部的字符数组变为字符串
+ 构造方法 public String (char [],int offset,int count) 将指定范围内的字符数组变为字符串
#### ②String类字节与字符串操作方法
+ 普通方法 public byte [] getBytes() 将字符串变为字节数组
+ 构造方法 public String(byte [] bytes) 将字节数组变为字符串
+ 构造方法 public String(byte [] bytes,int offset,int count) 将指定范围内的字节数组变为字符串
+ 构造方法 public String(byte [] bytes,String charsetName) 通过使用指定的charset解码指定的byte数组,构造一个新的String对象
将字节数组转换为字符数组:
~~~java
String s = "小黑";
System.out.println(s.toCharArray());
System.out.println(Arrays.toString(s.getBytes()));
~~~
#### ③String类判断是否以指定内容开头或结尾
+ 普通方法 public boolean startWith(String prefix) 从第一个位置开始判断是否以指定的内容开头
+ 普通方法 public boolean startWith(String prefix,int toffset) 从指定的位置开始判断是否以指定的内容开头
+ 普通方法 public boolean endWith(String suffix) 判断是否以指定的内容结尾
#### ④String类替换操作
+ 普通方法 public String replace(char oldChar,char newChar) 替换指定字符
+ 普通方法 public String replace(CharSequence target,CharSequence replacement) 替换指定字符串
+ 普通方法 public String replaceAll(String regex,String replacement) 替换指定的字符串
+ 普通方法 public String replaceFirst(String regex,String replacement) 替换第一个满足条件的字符串
#### ⑤String类字符串截取操作
+ 普通方法 public String subString(int beginIndex) 从指定位置开始一直截取到末尾
+ 普通方法 public String subString(int beginIndex,int endIndex) 截取指定范围内的字符串
#### ⑥String类字符串拆分操作
+ 普通方法 public [] String spit(String regex) 按照指定的字符串拆分
+ 普通方法 public [] String spit(String regex,int limit) 拆分字符串,并指定拆分的个数
#### ⑦String类字符串查找操作
+ 普通方法 public boolean contains(String s) 返回一个字符串是否存在
+ 普通方法 public int indexOf(int ch) 从头查找指定的字符是否存在,char->int,如果存在则返回位置,不存在则返回“-1”
+ 普通方法 public int indexOf(int ch,int fromIndex) 从指定位置查找指定的字符是否存在,char->int,如果存在则返回位置,不存在则返回“-1”
+ 普通方法 public int indexOf(String str) 从头查找指定的字符串是否存在,如果存在则返回位置,不存在则返回“-1”
+ 普通方法 public int indexOf(String str,int fromIndex) 从指定位置查找指定的字符串,如果存在则返回位置,不存在则返回“-1”
+ 普通方法 public int lastindexOf(int ch) 从字符串的最后向前查找指定的字符是否存在,char->int,如果存在则返回位置,不存在则返回“-1”
+ 普通方法 public int lastindexOf(int ch,int fromIndex) 从指定的末尾向前查找指定的字符是否存在,char->int,如果存在则返回位置,不存在则返回“-1”
+ 普通方法 public int lastindexOf(String str) 从字符串的最后向前查找指定的字符串是否存在,如果存在则返回位置,不存在则返回“-1”
+ 普通方法 public int lastindexOf(String str,int fromIndex) 从指定的末尾向前查找指定的字符串,如果存在则返回位置,不存在则返回“-1”
#### ⑧String类的其它操作方法
+ 普通方法 public boolean isEmpty() 判断字符串的内容是否为空,**不是null**
+ 普通方法 public int length() 取得字符串的长度
+ 普通方法 public String toLowerCase() 转小写
+ 普通方法 public String toUpperCase() 转大写
+ 普通方法 public String trim() 去掉开头和结尾的空格,中间的空个不去
+ 普通方法 public String concat(String str) 字符串连接操作
## 2.StringBuffer类
### 1)StringBuffer介绍
使用String连接字符串,代码性能会非常低,因为String的内容不可变。StringBuffer使用动态数组的方式扩充数组,使得StringBuffer对象的内容是可变的,有效地解决了连接字符串时代码性能低的问题。
### 2)StringBuffer常用操作方法
+ 构造方法 public StringBuffer() 构造一个空的StringBuffer对象
+ 构造方法 public StringBuffer(String str) 将指定的String变为StringBuffer的内容
+ 构造方法 public StringBuffer(CharSequence seq) 接收CharSequence接口的实例
+ 普通方法 public StringBuffer append(数据类型 b) 提供了很多append()方法,用于进行字符串连接
+ 普通方法 public StringBuffer delete(int start,int end) 删除指定位置的内容
+ 普通方法 public int indexOf(String str) 字符串的查询功能
+ 普通方法 public StringBuffer insert(int offset,数据类型 b) 在指定位置增加一个内容
+ 普通方法 public StringBuffer replace(int start,int end,String str) 将指定范围内的内容替换成其它内容
+ 普通方法 public String substring(int start,int end) 截取指定范围内的字符串
+ 普通方法 public String substring(int start) 字符串截取
+ 普通方法 public StringBuffer reverse() 字符串反转
## 3.StringBuilder类
StringBuilder介绍
一个可变的字符序列。此类提供了与StringBuffer兼容的API,但不保证同步。该类被设计用作StringBuffer的一个简易替换,用在字符缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议先采用该类,因为在大多数的实现中,它比StringBuffer要快。
## 4.Math与Random类
### 1)Math类的常用方法:
+ abs(double a) 返回double值的绝对值
+ random() 返回带正号的double值,该值大于等于0.0且小于1.0
+ round(double a) 返回最接近参数并且等于某一整数的double值
+ sqrt(double) 返回正确舍入的double值的平方根
### 2)Random类的常用方法
此类的实例用于生成伪随机数流
+ nextLong() 返回下一个伪随机数的long值
+ nextBoolean() 返回下一个伪随机数的boolean值、
+ nextDouble() 返回下一个伪随机数,在0.0和1.0之间的double值
+ nextFloat() 返回下一个伪随机数,在0.0和1.0之间的float值
+ nextInt() 返回下一个伪随机数的int值
+ nextInt(int n) 返回下一个伪随机数,在0(包括)和指定值分布的int值
## 5.日期操作类
### 1)Date类
类Date表示特定的瞬间,精确到毫秒,也就是程序运行时的当前时间。
~~~java
Date date = new Date(); //实例化Date对象,表示当前时间
~~~
### 2)Calendar类(抽象类)
日历类,使用此类可以将时间精确到毫秒显示
~~~java
//两种实例化方式
Calendar c1 = Calendar.getInstance();
Calendar c2 = new GregorianCalendar();
int year = c1.get(Calendar.YEAR) //获取当前时间的年份
int month = c1.get(Calendar.MONTH) //获取当前时间的月份
int day = c1.get(Calendar.DAY_OF_MONTH) //获取当前时间的天数
int hour = c1.get(Calendar.HOUR_OF_DAY) //获取当前时间的小时数
int minute = c1.get(Calendar.MINUTE) //获取当前时间的分钟数
int second = c1.get(Calendar.SECOND) //获取当前时间的秒数
int millisecond = c1.get(Calendar.MILLISECOND) //获取当前时间的毫秒数
~~~
### 3)DateFormat类及子类SimpleDateFormat
格式化日期的表示形式
~~~java
DateFormat df = new SimpleDateFormat("yyyy年MM月dd日HH:MM:ss SSS");
String nowData = df.format(new Date());
System.out.println(nowData);
~~~
## 6.Comparable与Comparator
### 1)Comparable接口
此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为他的自然比较方法。
### 2)Comparator接口
Comparable接口是要求自定义类去实现,按照oo原则,对修改关闭,对扩展开放。Comparator接口强行对某个对象collection进行整体排序的比较。
## 7.Cloneable(对象的克隆)
将一个对象复制一份,称为对象的克隆技术。
在Object类中存在一个clone()方法:protected Object clone() throws CloneNotSupportedException
如果某个类的对象想要被克隆,则对象所在的类必须实现Cloneable接口。此接口没有定义任何方法,是一个标记接口。
~~~java
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Cat cat = new Cat("咪咪",2);
Cat newCat = (Cat) cat.clone();
System.out.println(cat);
System.out.println(newCat);
System.out.println(cat==newCat);
}
}
class Cat implements Cloneable {
private String name;
private int age;
public Cat() {
}
public Cat(String name, int age) {
this.name = name;
this.age = 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;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
~~~
## 8.System与Runtime类
### 1)System类
System代表系统,系统级的很多属性和控制方法都放置在该类的内部。该类位于java.lang包。
+ **成员变量**:System类内部包含in、out和err三个成员变量,分别代表标准输入流(键盘输入),标准输出流(显示器)和标准错误输出流。
+ **成员方法**:
public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length) 该方法的作用是数组拷贝,也就是将一个数组中的内容复制到另一个数组中的指定位置,由于该方法时native方法,所以性能上比使用循环高效。
public static long currentTimeMillis() 该方法的作用时返回计算机的当前时间,时间的表达格式和GMT(格林威治时间)所差的的毫秒数。
public static void exit(int status) 该方法的作用是退出程序。其中status的值为0代表正常退出,非零代表异常退出
public static void gc() 该方法的作用时请求系统进行垃圾回收。至于系统是否回收垃圾,则取决于系统中垃圾回收算法的实现以及系统执行时的情况。
public static String getProperty(String key) 该方法的作用是获得系统中属性名为key的属性对应的值。
~~~java
int [] num1 = {1,2,3,4};
int [] num2 = new int[5];
//参数:源数组,源数组的起始位置,目标数组,目标数组的起始位置,复制的长度
System.arraycopy(num1,0,num2,1,num1.length);
System.out.println(Arrays.toString(num2));
System.out.println(System.currentTimeMillis());
~~~
### 2)Runtime类
每个应用程序都有一个Runtime的实例,使应用程序能够与其运行的环境连接。
~~~java
//获取java运行时相关的运行时对象
Runtime rt = Runtime.getRuntime();
System.out.println("处理器数量:"+rt.availableProcessors()+"个");
System.out.println("Jvm总内存数:"+rt.totalMemory()+"byte");
System.out.println("Jvm空闲内存数:"+rt.freeMemory()+"byte");
System.out.println("Jvm可用最大内存数:"+rt.maxMemory()+"byte");
//在单独的进程中执行指定的字符串命令
rt.exec("notepad");
~~~
## 9.数字处理工具类
### 1)BigInteger
可以让超过integer范围内的数据进行运算
~~~java
String val1 = "12374456546415165";
String val2 = "3498745983578590454";
BigInteger b1 = new BigInteger(val1);
BigInteger b2 = new BigInteger(val2);
b1.add(b2); //加
b1.subtract(b2); //减
b1.multiply(b2); //乘
b1.divide(b2); //除
b1.remainder(b2); //取余
b1.divideAndRemainder(b2); //除和取余,返回一个数组
~~~
### 2)BigDecimal
由于在运算的时候,float和double很容易丢失精度,为了能精确的表示,计算浮点数,java提供了BigDecimal,不可变的、任意精度的有符号十进制数。
~~~java
String val3 = "123.7445654641516545";
String val4 = "349.8745983578590454";
BigInteger b3 = new BigInteger(val3);
BigInteger b4 = new BigInteger(val4);
b3.add(b4); //加
b3.subtract(b4); //减
b3.multiply(b4); //乘
b3.divide(b4); //除,可能会有除不尽的情况发生,这时会报异常 ,解决办法是:b3.scale()-b4.scale()
b3.remainder(b4); //取余
b3.divideAndRemainder(b4); //除和取余,返回一个数组
~~~
### 3)DecimalFormat
java提供DecimalFormat类,帮你快速用最快的速度将数字格式化为你需要的样子。
~~~java
double pi = 3.1415927;
//取一位整数,结果是3
System.out.println(new DecimalFormat("0").format(pi));
//取一位整数和两位小数,结果是3.14
System.out.println(new DecimalFormat("0.00").format(pi));
//取两位整数和三位小数,整数不足部分以0填补,结果是:03.142
System.out.println(new DecimalFormat("00.000").format(pi));
//取所有整数部分,结果为:3
System.out.println(new DecimalFormat("#").format(pi));
//以百分比方式计数,并取两位小数,结果为:314.16%
System.out.println(new DecimalFormat("#.##%").format(pi));
~~~
## 10.MD5工具类
MD5的全称是Message-DigestAlgorithm(信息摘要算法)
~~~java
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
public class Demo {
static String savePassword = "4QrcOUm6Wau+VuBX8g+IPg==";
public static void main(String[] args) {
login("123456");
}
public static void login(String password){
if(savePassword.equals(md5(password))){
System.out.println("登录成功!");
}else {
System.out.println("登录失败!");
}
}
public static String md5(String password){
try {
MessageDigest md = MessageDigest.getInstance("md5");
//通过MD5计算摘要
byte[] bytes = new byte[0];
try {
bytes = md.digest(password.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//System.out.println(Arrays.toString(bytes));
// a-z A-Z 0-9 /* BASE64编码算法
String str = Base64.getEncoder().encodeToString(bytes); //加密后的密码
//System.out.println(str);
return str;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
}
~~~
## 11.数据结构之二叉树实现
### 1)简介
树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为节点)按分支关系组织起来的结构。二叉树是每个节点最多有两个子树的有序树。通常子树被称为”左子树“和”右子树“。
### 2)二叉树算法的排序规则
+ 选择第一个元素作为根节点
+ 之后如果元素大于根节点放在右子树,小于根节点则放在左子树
+ 最后按照中序遍历的方式进行输出
~~~java
public class Demo {
public static void main(String[] args) {
BinaryTree binaryTree = new BinaryTree();
binaryTree.add(1);
binaryTree.add(2);
binaryTree.add(3);
binaryTree.add(4);
binaryTree.add(5);
binaryTree.print();
}
}
class BinaryTree {
//private int data;
private Node root;
public BinaryTree(){}
public void add(int data) {
if (root == null) {
root.data = data;
}else {
root.addNode(data);
}
}
public void print() {
root.printNode();
}
class Node {
private int data;
private Node left;
private Node right;
public Node() {}
public Node(int data) {
this.data = data;
}
public void addNode(int data) {
if (this.data > data) {
if (this.right == null) {
this.right.data = data;
} else {
this.right.addNode(data);
}
} else {
if (this.left == null) {
this.left.data = data;
} else {
this.left.addNode(data);
}
}
}
public void printNode() {
if (this.left != null) {
this.left.printNode();
}
System.out.print(this.data + "->");
if (this.right != null) {
this.right.printNode();
}
}
}
}
~~~
# 十二、文件与IO
## 1.File类的使用
### 1)File类的基本概念
+ File类:表示文件和目录路径名的抽象表示形式
+ File类可以实现文件的创建、删除、重命名、得到路径、创建时间等等,是唯一与文件本身有关的操作类。
### 2)File类的操作方法
+ public static final String separator 表示路径分隔符
+ public File(String pathname) 构造File类实例,要传入路径
+ public boolean creatNewFile() 创建新文件
+ public boolean delete() 删除文件,文件夹中有文件时删除不了,得清空文件夹才能删除
+ public boolean isFile() 判断给定的路径是否是文件
+ public String [] list() 列出文件夹中文件,字符串数组的形式
+ public File [] listFiles() 列出文件夹中的所有文件,返回文件数组
+ public boolean mkdir() 创建新的文件夹
+ public boolean reanmeTo(File dest) 为文件重命名并且移动到指定的路径处,等同于剪切并复制
+ public long length() 返回文件的大小
~~~java
package com.demo;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class Test {
public static void main(String[] args) {
File f1 = new File("F://ideaspace//test//src//com//demo//test.text");
if(!f1.exists()){
try {
f1.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
// 是否为文件夹:f.isDirectory()
System.out.println("是否为文件"+f1.isFile());
File f2 = new File("F://ideaspace");
String [] names = f2.list();
System.out.println(Arrays.toString(names));
File [] fs = f2.listFiles();
for (File f3 : fs) {
System.out.println("length="+f3.length());
System.out.println("name="+f3.getName());
System.out.println("相对路径="+f3.getPath());
System.out.println("绝对路径= "+f3.getAbsolutePath());
System.out.println("是否为隐藏文件="+f3.isHidden());
System.out.println("是否为可读文件="+f3.canRead());
Date date = new Date(f3.lastModified());
DateFormat dateFormat = new SimpleDateFormat("yyyy:MM:dd:HH:mm:ss");
System.out.println("文件最后修改时间="+dateFormat.format(date));
System.out.println("------------------------------------");
}
//返回指定后缀名的文件数组
File [] files =f2.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".txt");
}
});
}
}
~~~
### 3)指定目录查找文件示例
~~~java
package com.demo;
import java.io.File;
public class Test1 {
public static void main(String[] args) {
findFile(new File("F://ideaspace"),"java");
}
public static void findFile(File target,String ext){
if(target == null)return;
if(target.isDirectory()){
File [] files = target.listFiles();
if(files != null){
for (File f : files) {
findFile(f,ext);
}
}
}else {
if(target.getName().toLowerCase().endsWith(ext));
System.out.println(target.getAbsolutePath());
}
}
}
~~~
## 2.IO流
+ 概述:IO流是输入输出流。流是一组有序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流。流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观地进行数据操作。
+ IO流地分类:根据处理数据类型地不同分为:字符流和字节流;根据流向不同分为:输出流和输入流。
### 1)字节输入输出流
#### ①字节输出流
OutputStream类定义
public abstract class OutputStream extends Object implements Closeable,Flushable
此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到InputStream类某个接收器要向文件中输出,使用FileOutputStream类
#### ②字节输入流
public abstract class IutputStream extends Object implements Closeable
此抽象类是表示字节输入流的所有类的超类
FileInputStream从文件系统中的某个文件获得输入字节
~~~java
package com.demo;
import java.io.*;
public class Test2 {
public static void in(){
File f2 = new File("F://ideaspace//test//src//com//demo//test.text");
try {
InputStream in = new FileInputStream(f2);
byte[] bytes = new byte[1024];
StringBuilder stringBuilder = new StringBuilder();
try {
int len = in.read(bytes);
while (len != -1){
stringBuilder.append(new String(bytes,0,len));
len = in.read(bytes);
}
in.close();
System.out.println(stringBuilder);
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static void out(){
File f1 = new File("F://ideaspace//test//src//com//demo//test.text");
try {
OutputStream out = new FileOutputStream(f1,true);
String info = "独开众卉已凋谢,不畏风霜向晚欺\r\n";
try {
out.write(info.getBytes());
out.close();
System.out.println("成功写入!");
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
//out();
in();
}
}
~~~
### 2)字符输入输出流
#### ①Writer
写入字符流抽象类。子类必须实现的方法有write(char[],int,int)、flush()、close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其它功能。 与OutputStream一样,对文件的操作使用:FileWriter完成。
#### ②Reader
用于读取字符的抽象类。子类必须实现的方法有read(char[],int,int)和close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其它功能。与InputStream一样,对文件的操作使用:FileReader完成。
~~~java
package com.demo;
import java.io.*;
public class Test3 {
public static void out(){
try {
Writer out = new FileWriter(new File("F://ideaspace//test//src//com//demo//test.text"),true);
out.write("扫码领红包\r\n");
out.close();
System.out.println("写入成功");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void in(){
try {
Reader in = new FileReader(new File("F://ideaspace//test//src//com//demo//test.text"));
char[] chars = new char[3];
StringBuilder stringBuilder = new StringBuilder();
int len = -1;
while ((len = in.read(chars)) != -1){
stringBuilder.append(chars,0,len);
}
in.close();
System.out.println(stringBuilder);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// out();
in();
}
}
~~~
### 3)文件复制示例
~~~java
package com.demo;
import java.io.*;
public class Test4 {
public static void main(String[] args) {
copy("F://ideaspace//test//src//com//demo//test.text","F://ideaspace//test//src//com//demo//test1.text");
}
public static void copy(String src,String target){
File srcFile = new File(src);
File targetFile = new File(target);
try {
InputStream in = new FileInputStream(srcFile);
OutputStream out = new FileOutputStream(targetFile,true);
byte[] bytes = new byte[5];
int len = -1;
while ((len = in.read(bytes)) != -1){
out.write(bytes,0,len);
}
in.close();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
~~~
### 4)字节字符转换流
转换流,可以将一个字节流转换为字符流,也可以将一个字符流转换为字节流。
#### ①OutputStreamWriter
可以将输出的字符流转换为字节流的输出形式
~~~java
package com.demo;
import java.io.*;
public class Test5 {
public static void main(String[] args) {
try {
OutputStream out = new FileOutputStream(new File("F://ideaspace//test//src//com//demo//test.text"));
writer(out);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static void writer(OutputStream out){
Writer writer = new OutputStreamWriter(out);
try {
writer.write("独开众卉已凋时,不畏风霜向晚欺");
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
~~~
#### ②InputStreamReader
将输入的字节流转换为字符流输入形式
~~~java
package com.demo;
import java.io.*;
public class Test5 {
public static void main(String[] args) {
// try {
// OutputStream out = new FileOutputStream(new File("F://ideaspace//test//src//com//demo//test.text"));
// writer(out);
// } catch (FileNotFoundException e) {
// e.printStackTrace();
// }
try {
InputStream in = new FileInputStream(new File("F://ideaspace//test//src//com//demo//test.text"));
try {
reader(in);
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static void writer(OutputStream out){
Writer writer = new OutputStreamWriter(out);
try {
writer.write("独开众卉已凋时,不畏风霜向晚欺");
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void reader(InputStream in) throws IOException {
Reader reader = new InputStreamReader(in);
char [] chars = new char[2];
int len = -1;
while ((len = reader.read(chars)) != -1){
System.out.println(new String(chars,0,len));
}
reader.close();
}
}
~~~
### 5)缓冲流
对文件或其它目标频繁的读写操作,效率低,性能差。使用缓冲流的好处是,能够更高效的读写信息,原理是将数据先缓存起来,然后一起写入或者读取出来。
#### ①字节缓冲流
+ BufferedInputStream 为另一个输入流添加一些功能,在创建BufferedInputStream时,会创建一个内部缓冲区数组,用于缓冲数据。
+ BufferedOutputStream 通过设置这种输出流,应用程序就可以将各个字节写入底层输入流中,而不必针对每次字节写入调用底层系统。
~~~java
package com.demo;
import java.io.*;
public class Test7 {
public static void main(String[] args) {
File file = new File("F://ideaspace//test//src//com//demo//test1.text");
try {
OutputStream out = new FileOutputStream(file,true);
BufferedOutputStream bos = new BufferedOutputStream(out);
bos.write("你好".getBytes());
bos.write("java".getBytes());
bos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
~~~
#### ②字符缓冲流
+ FileReader 内部使用InputStreamReader,解码过程,byte->char,默认缓存大小为8k。
+ BufferedReader 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
默认缓存大小为8k,但可以手动指定缓存的大小,把数据读取到缓存中,减少每次转换过程,效率更高
+ BufferedWriter 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
默认缓存大小为8k,但可以手动指定缓存的大小,把数据写入到缓存中,减少每次转换过程,效率更高
### 6)打印流
+ PrintStream 字节打印流
~~~java
package com.demo;
import java.io.*;
public class Test7 {
public static void main(String[] args) {
File file = new File("F://ideaspace//test//src//com//demo//test1.text");
try {
OutputStream out = new FileOutputStream(file,true);
BufferedOutputStream bos = new BufferedOutputStream(out);
PrintStream ps = new PrintStream(bos);
ps.print("你好");
ps.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
~~~
+ PrintWriter 字符打印流
~~~java
package com.demo;
import java.io.*;
public class Test7 {
public static void main(String[] args) {
File file = new File("F://ideaspace//test//src//com//demo//test1.text");
try {
Writer out = new FileWriter(file,true);
BufferedWriter bw = new BufferedWriter(out);
PrintWriter pw = new PrintWriter(bw);
pw.print("你好");
pw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
~~~
### 7)对象流与序列化
#### ①ObjectOutputStream
将java对象的基本数据类型和图形写入OutputStream
~~~java
package com.demo;
import java.io.*;
//如果一个类创建的对象,需要被序列化,那么该类必须实现Serializable接口
//Serializable是一个标记接口,没有任何定义,为了告诉JVM该对象可以被序列化
//什么时候对象需要被序列化?
//1.把对象保存到文件中
//2.对象在网络上传输
public class Test8 {
public static void main(String[] args) {
Dog dog = new Dog("旺财",2,"公");
File file = new File("F://ideaspace//test//src//com//demo//test.text");
OutputStream out = null;
try {
out = new FileOutputStream(file);
ObjectOutputStream op = new ObjectOutputStream(out);
op.writeObject(dog);
op.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
static class Dog implements Serializable{
private String name;
private int age;
private String sex;
public Dog() {
}
public Dog(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
}
}
~~~
#### ②ObjectInputStream
对以前使用ObjectOutputStream写入的基本数据和对象进行反序列化。
~~~java
package com.demo;
import java.io.*;
public class Test8 {
public static void main(String[] args) {
File file = new File("F://ideaspace//test//src//com//demo//test.text");
try {
InputStream in = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(in);
Dog dog = (Dog)ois.readObject();
ois.close();
System.out.println(dog.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
static class Dog implements Serializable{
private String name;
private int age;
private String sex;
public Dog() {
}
public Dog(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
}
~~~
### 8)数据流
#### ①DataOutputStream
数据输出流允许应用程序以适当的方式将基本java数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。
~~~java
public static void out(){
File file = new File("F://ideaspace//test//src//com//demo//test1.text");
try {
OutputStream out = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(out);
DataOutputStream dos = new DataOutputStream(bos);
dos.writeInt(10);
dos.writeByte(1);
dos.writeUTF("汪林");
dos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
~~~
#### ②DataInputStream
数据输入流允许应用程序以与机器无关方式从底层输入流中读取java基本数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。DataInputStream对于多线程访问不一定是安全的。线程安全是可选的,它有此类方法的使用者负责。
~~~java
public static void in(){
File file = new File("F://ideaspace//test//src//com//demo//test1.text");
try {
InputStream in = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(in);
DataInputStream dis = new DataInputStream(bis);
int a = dis.readInt();
byte b = dis.readByte();
String name = dis.readUTF();
dis.close();
System.out.println(a+","+b+","+name);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
~~~
### 9)文件分割合并示例
~~~java
package com.demo;
import java.io.*;
import java.util.Enumeration;
import java.util.Vector;
public class Test10 {
/**
* 文件的分割
* targetFile 要分割的文件
* cutSize 每个文件的大小
*/
public static void devision(File targetFile,long cutSize){
if(targetFile == null)return;
//计算总分割的文件数
int num = targetFile.length()%cutSize == 0 ?
(int)(targetFile.length()/cutSize) : (int)((targetFile.length()/cutSize)+1);
//构造一个文件输入流
try {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(targetFile));
BufferedOutputStream bos = null;
byte [] bytes = null; //每次要读取的字节数
int len = -1;
int count = 0; //每一个文件要读取的次数
for (int i = 0; i < num; i++) {
bos = new BufferedOutputStream(new FileOutputStream("F://"+(i+1)+"-temp"+targetFile.getName()));
if(cutSize <= 1024){
bytes = new byte[(int)cutSize];
count = 1;
}else {
bytes = new byte[1024];
if(cutSize%1024 == 0){
count = (int)(cutSize/1024);
}else {
count = (int)(cutSize/1024)+1;
}
}
while (count>0 && (len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
bos.flush();
count--;
}
bos.close();
}
bis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 文件的合并
*/
public static void merge(Enumeration<InputStream> es){
SequenceInputStream sis = new SequenceInputStream(es);
try {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("F://实验报告.doc"));
byte[] bytes = new byte[1024];
int len = -1;
while ((len=sis.read(bytes))!=-1){
bos.write(bytes,0,len);
bos.flush();
}
bos.close();
sis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// File file = new File("E://大学课程//web实验//web实验报告.doc");
// devision(file,1024*512);
try {
InputStream in1 = new FileInputStream(new File("F://1-tempweb实验报告.doc"));
InputStream in2 = new FileInputStream(new File("F://2-tempweb实验报告.doc"));
InputStream in3 = new FileInputStream(new File("F://3-tempweb实验报告.doc"));
Vector<InputStream> vector = new Vector<InputStream>();
vector.add(in1);
vector.add(in2);
vector.add(in3);
Enumeration<InputStream> es= vector.elements();
merge(es);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
~~~
### 10)字符串流与管道流
#### ①字符串流
+ 定义:以一个字符串为数据源,来构造一个字符流
+ 作用:在WEB开发中,我们经常要从服务器上获取数据,数据的返回格式通常是一个字符串(XML,JSON),我们需要把这个字符串构造成一个字符流,然后再用第三方的数据解析器来解析数据。
~~~java
package com.demo;
import java.io.IOException;
import java.io.StreamTokenizer;
import java.io.StringReader;
public class Test11 {
public static void main(String[] args) {
String info = "good good study day day up";
StringReader sr = new StringReader(info);
//流标记器
StreamTokenizer st = new StreamTokenizer(sr);
int count = 0;
while (st.ttype != StreamTokenizer.TT_EOF){
try {
if(st.nextToken() == StreamTokenizer.TT_WORD){
count++;
}
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("count = "+count);
}
}
~~~
#### ②管道流
##