javaOOP基础总结
类和对象
1.类和对象的关系
1.类
简单来说:类是抽象的,是对对象的抽象。
具体来说:类是对现实生活中一类具有共同特征的事物的抽象,实质是一种复杂的数据类型,不存在于内存中,不能被直接操作,只有被实例化为对象时,才会变得可操作。
2.对象
简单来说:对象也是抽象的,是对客观事物的抽象。又是具体的,是类实例化的结果。
具体来说:对象是人们要进行研究的任何具体事物,它不仅能表示具体的事物,还能表示抽象的规则、计划或事件。对象具有状态,一个对象用数据值来描述它的状态。对象还有操作,用于改变对象的状态,对象及其操作就是对象的行为。对象实现了数据和操作的结合,使数据和操作封装于对象的统一体中。
3.类是对象的概括,对象是类的具体体现
根据一类对象进行概括,将对象的特征概括为属性,将对象的行为概括为方法,将这一类对象用一个类表示 — 类是对象的概括/抽取,通过new关键字来创建这个对象,然后可以给对象中的属性赋值,也可以调用方法
2.成员变量和局部变量
局部变量和成员变量
1.定义的位置不一样:
1) 局部变量:在方法的内部
2) 成员变量: 在方法的外部,直接写在类当中
2.作用范围不一样:
1) 局部变量:只有方法当中才可以使用,出了方法就不能再用了
2) 成员变量:整个类全都可以使用
3.默认值不一样:
1) 局部变量:没有默认值,如果想要使用,必须手动进行赋值
2) 成员变量:如果没有赋值,会有默认值,规则和数组一样。
4.内存位置不一样:
1) 局部变量:位于栈内存
2) 成员变量:位于堆内存
5.生命周期不一样:
1) 局部变量随着方法进栈而诞生,随着方法的出栈而消失
2) 随着对象的创建而诞生,随着对象被垃圾回收而消失
3.构造方法
java可以向C#一样,通过无参或带参数的构造方法(Constructor)完成赋值的初始化
在Penguin类中增加一个无参的构造方法Penguin(),如下
/**
* 宠物企鹅类,测试无参构造方法
*/
public class Penguin{
String name = "无名氏"; //昵称
int health = 100; //健康值
int love = 0; //亲密度
String sex = "Q仔"; //性别
/**
* 无参构造方法
*/
public Penguin(){
name = "楠楠";
love = 20;
sex = "Q妹";
System.out.println("执行构造方法");
}
/**
* 输出企鹅的信息
*/
public void print(){
System.out.println("宠物的自白:\n我的名字叫" + this.name
+ ",健康值是" + this.health + ",和主人的亲密度是"
+ this.love + ",性别是" + this.sex + "。");
}
/**
* 测试无参构造方法的使用
*/
public static void main(String[] args){
Penguin pgn = null;
pgn = new Penguin();
pgn.print();
}
}
Penguin()方法就是Penguin类的构造方法,构造方法是一个特殊的方法,当没有Penguin()方法时,系统会提供一个空的Penguin()方法。
构造方法的名称和类名相同,没有返回值类型,构造方法的主要作用就是在创建对象时执行一些初始化操作,比如给成员属性赋初始值。
1.方法重载(overload)
如何定义重载。方法的重写和重载只有一个字不同,很多初学者认为这两者十分相似,其实不然。方法重载是让类以统一的方式处理不同类型数据的一种手段。调用方法时通过传递给它们的不同个数和类型的参数来决定具体使用哪个方法,这就是多态性。
所谓方法重载是指在一个类中,多个方法的方法名相同,但是参数列表不同。参数列表不同指的是参数个数、参数类型或者参数的顺序不同。方法的重载在实际应用中也会经常用到。不仅是一般的方法,构造方法也可以重载。
2.方法重写
如何定义重写:在Java程序中,类的继承关系可以产生一个子类,子类继承父类,它具备了父类所有的特征,继承了父类所有的方法和变量。子类可以定义新的特征,当子类需要修改父类的一些方法进行扩展,增大功能,程序设计者常常把这样的一种操作方法称为重写,也叫称为覆写或覆盖。重写体现了Java优越
性,重写是建立在继承关系上,它使语言结构更加丰富。在Java中的继承中,子类既可以隐藏和访问父类的方法,也可以覆盖继承父类的方法。在Java中覆盖继承父类的方法就是通过方法的重写来实现的。
所谓方法的重写是指子类中的方法与父类中继承的方法有完全相同的返回值类型、方法名、参数个数以及参数类型。这样,就可以实现对父类方法的覆盖。
1.重写规则
- 必须在同一个类里
- 方法名相同
- 参数列表(方法参数的个数或参数类型)不同
- 与方法返回值和方法修饰符没有任何关系
在使用this调用自身的其他构造方法时,只能作为第一条语句
2.在重写方法时,需要遵循以下的规则:
1.父类方法的参数列表必须完全与被子类重写的方法的参数列表相同,否则不能称其为重写而是重载。
2.父类的返回类型必须与被子类重写的方法返回类型相同,否则不能称其为重写而是重载。
3.Java中规定,被子类重写的方法不能拥有比父类方法更加严格的访问权限。
3.方法重写与方法重载的区别
区别点 | 重载 | 重写 |
---|---|---|
英文 | Overloading | Overiding |
定义 | 方法名称相同,参数的类型或个数不同 | 方法名称、参数类型、返回值类型全部相同 |
方法名称相同,参数的类型或个数不同 | 被重写的方法不能拥有更严格的权限 | |
范围 | 发生在一个类中 | 发生在继承类中 |
4.结束语
在面向对象程序设计的思想中,类的继承和多态性主要就是体现在子类重写父类的方法。而构造方法的重载作为方法重载的一个典型特例,可以通过重载构造方法来表达对象的多种初始化行为。灵活的运用方法重写与方法重载,不仅能减少编码的工作量,也能大大提高程序的可维护性及可扩展性。用好重写和重载
可以设计一个结构清晰而简洁的类,可以说重写和重载在编写代码过程中的作用非同一般。
4.this关键字
public Person(String name, int age, String sex) {
//有参构造
this.name = name; //区别参数和成员变量
this.age = age;
this.sex = sex;
}
this :表示对本类对象的引用
this(); 调用无参构造方法,必须写在构造方法中的第一行
5.static关键字
封装:将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问
封装的步骤
1,私有化属性
private String name;
private int age;
2,提供的公共方法来实现对隐藏信息的操作和访问(getter/setter)
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;
}
3,在方法中加入控制语句
public void setAge(int age) {
if(age<=0)
this.age=2;
this.age = age;
}
封装
1、方法、继承都是封装的一种体现,private(私有的)也是封装的一个体现。被private修饰的成员变量只能在本类中使用,外部不能直接通过对象属性改变。获取和改变需要提供设置器(访问接口|访问方法)和访问器来进行操作。
特点:
1、可以隐藏内部细节,对外提供公共访问方式。
2、提高安全性,提高代码的复用性。
2、这种多个封装的模板类统称之为javabean,模板类需要满足的一些规则
1)类是公共的
2)私有的属性
3)提供公有的访问方式 set、get
4)最好定义一个空构造
3、四种权限修饰关键字
1)private:只能被本类访问
2)default: 默认属性,并且不能写出来 只要你没有用其他修饰默认就是default
能被同包目录下访问
3)protected:除了能被同包访问,还可以给不同包下的字类访问
4)public:公共的 可以被其他包访问
4、注意:类名只能被 public和default修饰
继承
1,继承(extends)
extends:延伸 拓展
继承:子类继承父类,拥有父类的属性和方法。
public class Animal {
public String name;
public String sex;
}
class Dog extends Animal{
}
Dog dog = new Dog();
特点:
1,继承父类的属性和方法
2,不能继承父类的
private 修饰的属性和方法
父类的构造方法
子类和父类不在同一包下,使用默认的访问修饰符
3,java中的类只有单继承,一个子类只有一个父类。但是可以多重继承
4,一个类如果没有extends继承,默认继承Object。Object是所有类的父类
5,父类又叫超类,基类。子类又叫派生类。
2,方法的重写
当父类的方法满足不了子类的需求,这个时候需要子类重写父类的方法
特点:方法名和父类的方法名一致,返回值类型一致,参数列表一致,
子类方法的访问权限不能比父类的更严格。
子类的返回值可以是父类返回值对象的子类对象
public float eat(int a){
}
public int eat(int b){
}
3,super关键字
super:表示对父类对象的引用
super(); 调用父类的无参构造 必须写在构造方法中的第一行
super只能出现在子类的方法和构造方法中
super调用构造方法时,只能是第一句
super不能访问父类的private成员
4,访问修饰符
访问修饰符 | 本类 | 同包 | 子类 | 其他 |
---|---|---|---|---|
private | √ | |||
默认 不写 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
private - 默认 - protected - public
5,重载(overload)和重写(override)的区别
位置 | 方法名 | 参数表 | 返回值 | 访问修饰符 | |
---|---|---|---|---|---|
方法重写 | 子类 | 相同 | 相同 | 相同或是其子类 | 不能比父类更严格 |
方法重载 | 同类 | 相同 | 不相同 | 无关 | 无关 |
多态
多态(polymorphism)具有表现多种形态的特征,更专业化的说话是同一个实现接口,使用不同的实例而执行不同的操作
多态
1、多态:同一个对象,在不同时刻体现出来的不同状态。
2、多态的前提:
1)要有继承关系或实现关系(接口);
2)要有方法重写;
3)要有父类或者父接口引用指向子类`Fu f= new Zi();
注意:形参实参形式的(形参父类实参子类)。
3、多态的分类:
1)具体类多态
class Fu{}
class Zi extends Fu{}
Fu f= new Zi()//父类引用指向子类
2)抽象类多态(常用)
abstract class Fu{}
class Zi extends Fu{}
Fu f= new Zi();//抽象父类引用指向子类
3)接口多态(常用)
interface Fu{}
class Zi implements Fu{}
Fu f= new Zi();//父接口引用指向子类
多态中成员访问特点
如,Fu f= new Zi();//左父类右子类
重点:成员方法,运行时,结果为子类重写的成员方法的结果。
- 成员变量:编译看左边,运行看左边。
- 构造方法:创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
- 成员方法:编译看左边,运行看右边。(方法重写的意义)
- 静态方法:编译看左边,运行看左边。静态和类相关,算不上重写,所以访问还是左边的。
提醒:理解这些的时候要记得继承啊方法重写它们存在的意义所在。就好理解啦。
向上转型和向下转型
一、概念
向上转型是指将子类的实例赋值给父类类型的变量。
向下转型是指将父类的实例赋值给子类类型的变量。
二、向上转型
1、向上转型后父类的引用所指向的属性是父类的属性。
2、如果子类重写了父类的方法,那么父类引用指向的或者调用的方法是子类的方法,这个叫动态绑定(实现多态)。
3、父类引用不能调用子类自己的方法。
4、向上转型会丢失子类的新增方法,同时会保留子类重写的方法。
三、向下转型
编译时需要强制类型转换,father前面的必须添加(Son)。
运行时会出现java.lang.ClassCastException错误,可使用instanceof来避免出错此类错误。
向下转型可以得到子类的所有方法(包含父类的方法)。
抽象类和接口
1.抽象类(abstract)
抽象类怎么定义?
语法:
[修饰符列表] abstract class 类名{
类体;
}
抽象类是无法实例化的,无法创建对象的,所以抽象类是用来被子类继承的,抽象类的子类可以是抽象类,也可以是非抽象类。
注意:final和abstract不能联合使用,这两个关键字是对立的。
抽象类虽然无法实例化,但是抽象类有构造方法,这个构造方法是供子类使用的。
抽象类关联到一个概念:抽象方法。什么是抽象方法?
抽象方法表示没有实现的方法,没有方法体的方法。例如:
public abstract void doSome();
抽象方法的特点:
特点1:没有方法体,以分号结尾
特点2:前面修饰符列表中有abstract关键字‘。
抽象类
抽象类中不一定必须有抽象方法,也可以有非抽象方法。 有抽象方法的必须是抽象类。
一个非抽象的类继承抽象类,必须将抽象类中的抽象方法实现。
1.final 关键字(最终的,不可变的)
1.可以修饰类
2.可以修饰方法
3.可以修饰局部变量
4.可以修饰成员变量
1.当final修饰一个类的时候:
格式: public final class …
表示这个类不可以有任何子类,所以其中的成员方法也不可以进行覆盖重写
2.当final修饰一个方法的时候:
格式:修饰符 final 返回值 方法名(){}
表示这个方法是最终方法,不可以被覆盖重写
3.当final修饰一个局部变量的时候:
两种情况:
1.基本类型变量:变量当中的数值不可以改变
2.引用类型变量:变量中的地址是不可以改变的,但可以通过setter改变变量的内容。
4.当final修饰一个成员变量的时候:
因为成员变量时有默认值的,当我们使用final后,他不再有默认值,所以必须一步直接赋值
或者通过构造方法进行赋值。
注意:必须保证所有重载构造方法都会对final修饰的变量进行赋值。
2.接口
需求:要求实现防盗门的功能。门有“开”和“关”的功能,锁有 “ 上锁 ” 和 “ 开锁 ” 的功能。
分析:首先防盗门是一个门,他有一把锁。按照之前学过的面向对象的思想,可以将门和锁分别定义成抽象类。但是,不能让防盗门在继承门的同时又继承锁。原因有两点:第一,防盗门不是锁,不符合继承中 is a 的关系;第二,java只支持单继承。如何解决这个问题呢?这时就要用到接口。可以将锁定义为接口,让防盗门继承门,实现锁的接口。
1.什么是接口
在生活中,接口是一套规范,只要满足这个规范的设备,就可以将它们组装到一起,从而实现该设备的功能。现在以USB接口为例,来学校接口的含义。USB接口实际上是某些企业和组织等制定的一种约定和标准,规定了接口的大小,形状,各引脚信号的范围和含义、通信速度、通信流程等,并按照该约定或标准来设计各种设备,如U盘、USB风扇、USB鼠标都可以插到USB口上正常工作
语法
interface 接口名 extends 父接口1,父接口2,......{
//常量定义
//方法定义
}
class 类名 extends 父类名 implements 接口1,接口2,......{
//类成员
}
说法:接口的命名规则与类相同。如果修饰符是public,则该接口在整个项目中可见;如果省略修饰符,则该接口只在当前包可见
接口中可以定义常量,不能定义变量。接口中的属性都会自动用 public static final 修饰,即接口中的属性都是全局静态常量。接口中的常量必须在定义时指定初始值
异常(exception)
1.什么是异常?
程序开发和运行过程中会出现编译错误和运行错误。编译错误容易被发现并排除,而运行错误(逻辑错误和异常)很难预料。因此为了程序的稳定性和可靠性,就需要对程序异常处理和保护。
2.为什么要使用异常
程序开发和运行过程中会出现编译错误和运行错误。编译错误容易被发现并排除,而运行错误(逻辑错误和异常)很难预料。因此为了程序的稳定性和可靠性,就需要对程序异常处理和保护。
3.异常的产生
<1>可以由Java虚拟机在执行程序时自动发现并产生异常。
<2>也可以在程序中显式地生成异常,这种方法称为抛出异常(ThrowExceptions)。抛出异常采用throw语句,格式:
throw new ArithmeticException( );
//或者:
ArithmeticException e=new ArithmeticException( );
throw e;
4.异常的处理
<1>捕捉异常(try_catch_finally语句)
try{
//可能产生异常的语句;
}catch(Exception1 e1){
//处理语句1;
}catch(Exception2 e2){
//处理语句2;
}finally{
//语句序列;
}
1)catch语句块可以有多个;
2)catch语句块和finally语句块可以同时存在,也可以只有其一;
3)如果发生异常,则会跳转到捕捉对应异常的catch语句块,发生异常语句之后的语句序列不会被执行。
4)不管异常是否发生,finally语句块总是会被执行,除非碰到强制退出程序的System.exit(0)语句;
5)如果try语句块或catch语句块中有return语句,则会执行完finally语句块再执行返回。
一个demo:
public class J_ExceptionCatch
{
public static void main(String args[ ])
{
try
{
System.out.println("try语句块");
throw new Exception( );
}
catch(Exception e)
{
System.err.println("catch语句块");
e.printStackTrace( );
}
finally
{
System.out.println("finally语句块");
} // try-catch-finally结构结束
} // 方法main结束
} // 类J_ExceptionCatch结束
运行流程:
1.try语句块捕捉throw的异常
2.跳转到相关的catch语句块
3.最后执行finally语句块的内容
<2>throws抛出异常
public class Test{
public static void main(String[] args) throws IOException{
FileInputStream fis = new FileInputStream("a.txt");
}
}
上面的main方法throws了IOException,声明但不去处理,所以在运行之后,
该异常就会交给JVM处理,程序一旦遇到该异常,就会打印该异常的跟踪栈信息
并结束程序
5.自定义异常
public class NewException extends Exception{
//自定义的异常类
public NewException (msg){
super(msg);
}
}
//第一种用法:直接在一个判断语句下throw该异常
public class Test{
public static void main(String[] args){
if(条件){
throw new NewException("我是抛出的新异常!");
}
}
}
//第二种:throws之后,再try——catch
public static void test()throws NewException{
if(条件){
throw new NewException("我是抛出的新异常!");
}
}
public class Test{
public static void main(String[] args){
try{
test();
}catch(NewException e){
System.out,println(e.getMessage());
}
}
}
多线程
1.进程(Program)
进程(Program)是程序的一次动态执行过程,他对应了从代码加载。执行完毕的一个完整过程,这个过程也是进程本身从产出、发展至消亡的过程。
进程的特点:
-
进程是系统运行程序的基本单位。
-
每一个进程都有自己独立的一块内存空间、一组系统资源。
-
每一个进程的内部数据和状态都是完全独立的。
2.多线程的好处
-
充分利用CPU的资源:执行单线程程序时,若程序发生阻塞,CPU可能会处于空闲状态,这将造成计算机资源浪费,而使用多线程可以在某个线程处理休眠或阻塞状态时运行其他的线程,这样,大大提高了资源利用率
-
简化编程模型:一个既长又复杂的进程可以考虑分为多个线程,成为几个独立的运行部分,如使用时,分,秒俩描述当前时间,如果写成单线程程序可能需要多重循环判断,而如果使用多线程,时、分、秒各使用一个线程控制,每个线程仅需实现简单的流程,简化了程序逻辑,这样更有助于开发人员对程序的理解和维护。
-
带来良好的用户体验:由于多个线程可以交替执行,减少或避免了因程序阻塞或意外情况造成的相应过慢现象,降低了用户等待的几率。
3.Thread类及其常用方法
构造方法 | 说明 |
---|---|
Thread() | 分配新的Thread对象 |
Thread(Runnable target) | 分配新的Thread对象,target为run()方法被调用的对象 |
Thread(Runnable target,String name) | 分配新的Thread对象,target为run()方法被调用的对象,name为新线程的名称 |
void run() | 执行任务操作的方法 |
void start() | 使该线程开始执行,java虚拟机调用该线程的run()方法 |
void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行) |
String getName() | 返回线程的名称 |
int getPriority() | 返回线程的优先级 |
void setPrority(int newPriority) | 更改线程的优先级 |
boolean isAlive | 测试线程是否处于活动状态 |
void join() | 等待该线程终止 |
void interrupt() | 中断线程 |
void yield() | 暂停当前正在执行的线程对象,并执行其他线程 |
4.主线程
- 他是产生其他子线程的线程
- 通常它必须最后完成执行,因为它执行各种关闭动作
尽管主线程在程序启动时自动创建,但它可以由一个Thread对象控制
使用一个线程的过程
- 定义一个线程,同时指明这个线程所要执行的代码,即期望完成的功能
- 创建线程对象
- 启动线程
- 终止线程
5.继承Thread类创建线程
使用此方法创建线程类,此线程类需要继承Thread类并重写run()方法
线程的状态
1.创建状态
- 用构造方法创建了一个线程对象后,新的线程对象就处于创建状态,此时,它已经获取了相应的资源,但还没有处于可运行状态,这时可以通过Thread类的方法开设置线程对象属性,如设置线程名(setName)、设置线程优先级(setPriority)
2.就绪状态
- 线程创建之后,就可以通过 start() 方法启动线程,即进入就绪状态
3.运行状态
- 当就绪状态的线程获得CPU资源时,即可转入运行状态,执行run()方法
4.阻塞状态
- 一个正在运行的线程因某种原因不能继续运行时,空没阻塞状态、
使线程暂停执行的条件
- 由于线程优先级比较低,因此它不能获得CPU资源
- 使用sleep()方法使线程休眠
- 通过调用wait()方法,使线程等待
- 通过调用yield()方法,线程显式出让CPU控制权
- 线程由于等待一个文化,1/0时间被阻塞
5.死亡状态
- 一个线程的run()方法运行完毕,线程进入死亡状态。处于死亡状态的线程不具有继续运行的能力
6.实现runnable接口
(1)定义 MyRunnable 类实现 Runnable 接口,并实现 Runnable 接口的 run() 方法,在 run() 方法中实现输出数据
(2)创建 MyRunnable 类的对象 myRunnable。
(3)创建一个 Thread 类的对象 myThread,将 myRunnble 对象作为 Thread 类构造方法的参数传入。
(4)调用 myThread 对象的 start() 方法启动线程。
7.线程的优先级
线程的优先级用1~10表示,1表示优先级最低,10表示优先级最高,默认值是5,这些优先级对应一个Thread类的公用静态常量。
public static final int NORM_PRIORITY=5;
public static final int MAX_PRIORITY=10;
public static final int MIN_PRIORITY=1;
8.线程的休眠
在程序中允许一个线程进行暂时的休眠,直接使用 Thread.slepp() 方法即可以实现线程的休眠。
sleep() 方法的语法:
public static void sleep(long millis)
sleep() 方法会让当前线程休眠(停止执行)millis毫秒,线程由运行中的状态进入不可运行状态,睡眠时间过后线程会再次进入可运行状态。
9.线程的强制运行
join() 方法使当前线程暂时执行,等待调用该方法的线程结束后再继续执行本线程。它有三个重载方法
public final void join()
public final void join(long mills)
public final void join(long mills,int nanos)
与sleep() 方法一样,调用 join() 方法需要处理 InterruptedException 异常。
File I/O
1.常用方法
1.boolean exists():判断文件或者目录是否存在
// 判断文件是否存在 不存在则新建文件
// 创建file对象
File file = new File("E:/ll.txt");
if (file.exists()) {
System.out.println("文件已经存在!");
} else {
// 新建文件
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
2.Boolean isFile():判断是否是文件
// 判断此路径属性文件还是文件夹
if (file.isFile()) {
System.out.println("此路径是文件格式!");
} else {
System.out.println("此路径不是文件格式!");
}
3.boolean isDirectory():判断是否是目录
// 判断此路径属性文件还是文件夹
if (file.isDiectroy()) {
System.out.println("此路径是文件夹!");
} else {
System.out.println("此路径不是文件夹格式!");
}
4.String getPath():获取相对路径
System.out.println("文件相对路径:" + file.getPath());
5.String getAbsolutePath():获取绝对路径
System.out.println("文件绝对路径:" + file.getAbsolutePath());
6.String getName():返回对象的文件/目录名
System.out.println("文件名:" + file.getName());
7.boolean delete():删除对象的文件/目录
if (file.exists()) {
file.delete();
System.out.println("文件删除成功!");
}else{
System.out.println("未找到文件!");
}
8.boolean createNewFile():创建新的文件,不创建文件夹
9.long length():返回文件的长度,单位字节/字符 如果不存在则返回0L
System.out.println("文件大小:" + file.length() + "字节");
10.isHidden():判断文件/目录是否隐藏
// 判断文件是否属于隐藏文件
if (file.isHidden()) {
System.out.println("隐藏");
}else{
System.out.println("未隐藏");
}
11.mkdir():创建单层目录
//创建文件夹
File file1=new File("E:\\123/789");
//判断是否文件
if (file1.exists()) {
System.out.println("文件夹已存在!");
}else{
file1.mkdirs();
}
2.流
什么是流?
流是指一串流动的字符,是以先进先出的方式发送信息的通道(InputStream读入---->OutputStream写出)
流的分类
输入/输出流
输入流(读):把文件中的数据读取到程序中 InputStream
输出流(写):把程序的数据保存写出到文件中 OutputStream
当然了,输入输出又分为字节和字符
3.字节
字节:一个英文字母,数字,符号在内存中占一个字节的空间
字符:一个汉字在内存当中占一个字符的空间
PS:(1字符=2字节)
字节输入流:InputStream
字节输出流:OutputStream
字符输出流:Writer
字符输入流:Reader
这里怎么理解怎么记的话,我先大概说一下自己是怎么记得
首先,我们得知道流分为输入/输出,所谓输入就是进入,而在流和文件中,我们先把程序当成“中心”,输入就相当于把你要传入给“中心”的数据通过先进先出的方式传入进去。而处理单元有字符和字节,既然要输入,则字符和字节都要有,上面说的InputStream则是字节输入流,字符输入流则为“读”的英文Reader,就是我理解的“读入,写出”,按这种理解的话,就很方便记住
读入:读—>reader 入—>InputStream
写出:写—>writer 出—>OutputStream
以上的四种是基本流(抽象类)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6kXnhWgG-1595244782705)(C:\Users\杰弟弟\AppData\Roaming\Typora\typora-user-images\1594622188949.png)]
(1)按照流的流向进行划分,可以分为输入流和输出流
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wChuj2z7-1595244782706)(C:\Users\杰弟弟\AppData\Roaming\Typora\typora-user-images\1594622254175.png)]
输入流:只能从中读取数据,而不能向其中写入数据
输出流:只能向其中写入数据,而不能从中读取数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hOYivfFg-1595244782707)(C:\Users\杰弟弟\AppData\Roaming\Typora\typora-user-images\1594622347132.png)]
输入流(InputStream)
1.字节输入流InputStream类
字节输入流InputStream的作用就是将文件中的数据输入到内部存储器(简称内存)中,它提供了一系列和读取数据有关的方法
方法名称 | 说明 |
---|---|
int read() | 读取一个字节的数据 |
int read(byte[] b) | 将数据读取到字节数组中 |
int read(byte[] b,int off,int len) | 从输入流中读取最多len长度的字节,保存到字节数组b中,保存的位置从off开始 |
void close() | 关闭输入流 |
int available() | 返回输入流读取的估计字节数 |
2.字节输入流FileInputStream类
(1)FileInputStream(File file)。其中,file指定文件数据源。使用此构造方法创建文件输入流对象
File file=new File("C:\\test.txt");
InputStram fileObject=new FileInputStream(file);
(2)Fileinput(String name)。其中,name指定文件数据源,包含路径信息。使用此构造方法创建文件输入流对象
InputStream in=new FileInputStream("C:\\test.txt");
3.使用FileInputStream读取文件
(1)引入相关的类
import java.io.IOException;
import java.io.InputStream;
import java.io.FileInputStream;
(2)创建一个文件输入流对象
InputStream fileObject=new FileInputStream("C:\\test.txt");
(3)利用文件输入流的方法读取文本文件的数据
fileObject.available(); //可读取的字节数
fileObject.read(); //读取文件的数据
(4)关闭文件输入流对象
fileObject.Close();
输出流(OutputStream)
1.字节输出流OutputStream类
字节输出流OutputStream类的作用是把内存中的数据输出到文件中,它提供了一系列向文件中写数据的方法
方法名称 | 说明 |
---|---|
void write(int c) | 写入一个字节数据 |
void write(byte[] buf) | 写入数字buf的所有字符 |
void write(byte[] b,int off,int len) | 将字节数组中从off位置开始,长度为len的字节数据输出到输出流中 |
void close() | 关闭输出流 |
2.字节输出流FileOutputStream类
(1)FIleOuputStream(FIle file)。其中,file指定文件数据源。使用此构造方法创建文件输出流对象
File file=new File("C:\\test.txt");
FIleOutputStram fos=new FileOutputStream(file);
(2)Fileinput(String name)。其中,name指定文件数据源,包含路径信息。使用此构造方法创建文件输出流对象
FileOutputStream fos=new FileOutputStream("C:\\test.txt");
(3)FileOutputStream(String name,boolean append)。其中,name指定文件目标数据源,包含路径信息。append表示是否在文件末尾添加数据,若设置为true,则在文件末尾添加数据。使用此构造方法创建文件输出流对象
FileOutputStream fos=new FileOutputStream("C:\\test.txt",true);
3.使用FileOutputStream写文本文件
(1)引入相关的类
import java.io.IOException;
import java.io.OutputStream;
import java.io.FileOutputStream;
(2)构造一个文件输出流对象
OutputStream fos=new FileOutputStream("C:\\test.txt");
(3)利用文件输出流的方法把数据写入文本文件中
String str="好好学习 java";
(4)关闭文件输出流
fos.Close();
字符输入流(Reader)
1.字符输入流Reader类
Reader类是读取字符流的抽象类,它提供了常用的方法
方法名称 | 说明 |
---|---|
int read() | 从输入流中读取单个字符 |
int read(byte[] c) | 从输入流中读取c.length长度的字符,保存到字符数组c中,返回实际读取的字符数 |
read(char[] c,int off,int len) | 从输入流中读取最多len的长度字符,保存到字符数组c中,保存的位置从off位置开始,返回实际长度的字符长度 |
void close() | 关闭流 |
2.字符输入流FileReader类
FileReader类是Reader的子类,常用的构造方法格式
FIleReader(String fileName)
其中,fileName是指要从中读取数据的文件的名称,使用此构造方法创建字符输入流对象
Reader fr=new fileReader("C:\\myTest.txt");
3.使用FileReader读取文件
(1)引入相关的类
import java.io.Reader;
import java.io.FileReader;
import java.io.IOException;
(2)创建一个FileReader对象
Reader fr=new FileReader("C:\\myTest.txt");
(3)利用FileReader类的方式读取文本文件的数据
int read(); //读取单个单词
(4)关闭相关的流对象
fr.Close()
5.字符输入流BufferedReader类
BufferedReader类是Reader类的子类,它与FileReader类发区别在于,BufferedReader类带有缓冲区,它可以先把一批数据读到缓冲区,接下来的读操作都是从缓冲区内获取数据,避免每次都从数据源读取数据进行字符编码转换,从而提高读取操作的效率。BufferedReader类常用的构造方法格式
BufferedReader(Reader in)
使用此构造方法创建字符输入对象
Reader fr=new FIleReader("C:\\myTest.txt");
BufferedReader br=new BufferedReader(fr);
其中,br就是创建的一个使用默认大小输入缓冲区的缓冲字符输入流
6.使用FIleReader和BufferedReader读取文本文件
(1)引入相关的类
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
(2)创建一个BUfferedReader对象
Reader fr=new FileReader("C:\myTest.txt");
BufferedReader br=new BufferedReader(fr);
(3)利用BufferedReader类的方法读取文本文件的数据
br.readLine(); //读取第一行数据,返回字符串
readLine()方法是BufferedReader类特有的方法,用来按行读取内容
(4)关闭相关的流对象
br.close();
fr.close();
字符输出流(Write)
1.字符输入流 Writer 类
Writer 类是向文件写入数据的字符流,它提供了常用的方法
方法名称 | 说明 |
---|---|
write(String str) | 将字符串里包含的输出到指定的输出流中 |
write(String str,int off,int len) | 将str字符串从off位置开始长度为len的字符输出到输出流中 |
void close() | 关闭输出流 |
void flush() | 刷新输出流 |
2.字符输出流File Writer 类
FileWriter 类是 Reader 的子类,常用的构造方法:
FileWrite(String fileName)
其中,fileName 表示与系统有关的文件名,使用此构造方法创建字符输出流对象:
Writer fr=new FileWriter("C:\\myTest.txt");
3.使用 FileWriter 写文本文件
使用字符流类FileWriter 将数据写入文本文件的具体操作步骤
(1)引入相关的类
import java.io.FileWriter;
import java.io.IOException;
(2)创建一个FileWriter 对象
Writer fw=new FileWriter("C:\\myTest.txt");
(3)利用FileWriter 类的方法写文本文件
bw.write("hello");
(4)相关流对象的情况和关闭
bw.flush(); //刷新该流的缓冲
fw.close(); //关闭此流
4.字符输出流 BufferedWriter类
BufferedWriter 是 Writer 类的子类。BufferedWriter 与 BufferedReader 的流方向正好相反,BufferedWriter是把一批数据写到缓冲区,当缓冲区满的时候,再把缓冲区的数据写到字符输出流中。这就可以避免每次都执行物理写操作,从而提高输入/输出操作的效率。BufferedWriter 类的常用构造方法:
BufferedReader(Writer out);
使用此构造方法创建字符输出流对象
Writer fw=new FileWriter("C:\\myTest.txt");
BufferedWriter bw=new BUfferedWriter(fw);
其中,bw 就是创建的使用默认大小输出缓冲区的缓冲字符输出流。
5.使用 BufferedWriter 和 FileWriter 写文本文件
使用字符流类 BufferedWriter 和FIleWriter 将数据写入文本文件的具体操作步骤
(1)引入相关的类
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
(2)构造一个BufferedWriter对象
FileWriter fw=new FIleWriter("C:\\myTest.txt");
BufferedWriter bw=new BufferedWriter(fw);
(3)利用BufferedWriter类的方法写文本文件
bw.write("hello");
(4)相关流对象清空和关闭
bw.flush(); //刷新该流的缓冲
fw.close(); //关闭此流
4.二进制文本读写
使用字节流类DataInputStream读二进制文件
DataInputStream 类是FileInputStream 的子类,它是 FileInputStream类的扩展。利用 DataInputStream 类读取二进制文件的实现步骤其实与用 FileInputStream 类读取文本文件的步骤极其相似,而且还要用发哦FileInputStream 类。
(1)引入相关的类
import java.io.FileInputStream;
import java.io.DataInputStream;
(2)构造一个数据输入流对象
FileInputStream fis=new FIleInputStream("C:\\HelloWirld.class");
DataInputStream dis=new DataInputStream(fis);
(3)利用数据输入流类的方法读取二进制文件的数据
dis.read(); //读取数据字节
(4)关闭数据输入流
dis.close(); //关闭数据输入流
使用字节流类DataOutputStream 写二进制文件
DataOutputStream 类是 FileOutputStream的子类,它是FIleOutputStream 类的扩展。利用DataOutputStream 类写二进制文件的实现步骤其实与用 FileOutputStream 类写文本文件的步骤及其相似,而且还要用到FileOutputStream 类。具体操作步骤:
(1)引入相关的类
import java.io.FileOutputStream;
import java.io.DataOutputStream;
(2)构造一个数据输出流对象
FileOutputStream outFIle=new FIleOutputStream("C:\\HelloWirld.class");
DataOutputStream out=new DataOutputStream(outFile);
(3)利用数据输出流类的方法读取二进制文件的数据
out.write(1); //将指定字节数据写入二进制文件
(4)关闭数据输出流
out.close();
iter(fw);
(3)利用BufferedWriter类的方法写文本文件
bw.write("hello");
(4)相关流对象清空和关闭
bw.flush(); //刷新该流的缓冲
fw.close(); //关闭此流
4.二进制文本读写
使用字节流类DataInputStream读二进制文件
DataInputStream 类是FileInputStream 的子类,它是 FileInputStream类的扩展。利用 DataInputStream 类读取二进制文件的实现步骤其实与用 FileInputStream 类读取文本文件的步骤极其相似,而且还要用发哦FileInputStream 类。
(1)引入相关的类
import java.io.FileInputStream;
import java.io.DataInputStream;
(2)构造一个数据输入流对象
FileInputStream fis=new FIleInputStream("C:\\HelloWirld.class");
DataInputStream dis=new DataInputStream(fis);
(3)利用数据输入流类的方法读取二进制文件的数据
dis.read(); //读取数据字节
(4)关闭数据输入流
dis.close(); //关闭数据输入流
使用字节流类DataOutputStream 写二进制文件
DataOutputStream 类是 FileOutputStream的子类,它是FIleOutputStream 类的扩展。利用DataOutputStream 类写二进制文件的实现步骤其实与用 FileOutputStream 类写文本文件的步骤及其相似,而且还要用到FileOutputStream 类。具体操作步骤:
(1)引入相关的类
import java.io.FileOutputStream;
import java.io.DataOutputStream;
(2)构造一个数据输出流对象
FileOutputStream outFIle=new FIleOutputStream("C:\\HelloWirld.class");
DataOutputStream out=new DataOutputStream(outFile);
(3)利用数据输出流类的方法读取二进制文件的数据
out.write(1); //将指定字节数据写入二进制文件
(4)关闭数据输出流
out.close();