Java面向对象基础呕心沥血三千字

# 一、初识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);
      }
  }
  ~~~

#### ②管道流

## 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值