接口(特殊的抽象类)
//接口就是为两个不相关的类提供交流的设备(语言,两个人交流)
1.所有的属性都是公开静态常量
2.所有的方法都是公开抽象方法
3.没有构造方法
abstract class ClassA{ //抽象类(有默认构造方法)
public static final int M=10;
public static final double N=2.78;
public abstract void ma1();
public abstract void ma2();
}
----------------------------------------------------
interface IA{ //接口(没有构造方法)
int M=10;
double N=2.78;
void ma1();
void ma2();
}
一个类去实现(继承)接口,要么成为抽象类,要么就必须实现接口中所有方法
class Impl implements IA{ //实现IA
public void ma1(){} //必须加public,因为接口中的方法是public
public void ma2(){}
}
接口之间也可以继承
interface IA{void ma();}
interface IB extends IA{void mb();} //IB有两个方法ma,mb
如果有一个类要实现 IB 接口,则必须实现 ma 和 mb 两个方法
class IAIBImpl implements IB{
public void ma(){} //public
public void mb(){}
}
接口和类的区别:
1.接口之间可以多继承(一个接口可以继承多个接口)
interface IB{void mb();}
interface IC{void mc();}
interface ID extends IB,IC{void md();} //ID有三个方法:mb();mc();md();
2.一个类在继承另外一个类的同时,还可以实现多个接口
abstract class ClassE{
public abstract void me();
}
class Impl extends ClassE implements IA,ID{} //先继承类,再实现接口,必须实现所有的方法
子类对象可以赋值给 父类|其他实现的接口,需强制类型转换
--------------------------------------------------------
任意类型对象都可以强转为接口类型
……main{
Animal a=new Snoopy(); //创建Snoopy对象,赋值给Animal a
Dog d=(Dog)a; //强制类型转换,a可能是Dog
Person p=(Person)a; //a可能实现Person接口,所以可以强制类型转换
}
class Animal{}
class Dog extends Animal{}
interface Person{}
class Snoopy extends Dog implements Person{}
接口的作用:
1.用接口实现多继承
蜘蛛侠(SpiderMan)既是蜘蛛(Spider)的子类,又是人(Man)的子类
class SpiderMan extends Man implements Spider
为什么java要间接的实现多继承?
1).使用接口实现多继承,能够区分主要类型和次要类型。
实现接口与继承父类相比,是处于相对“次要”的地位
父类可以认为是对子类主要共性的抽象,而接口可以认为是对子类次要共性的“再抽象”。
eg:移动硬盘(主要类型:存储设备;次要类型:usb设备)
让一个类继承自其主要类型,而次要类型,可以作为接口,让这个类来实现。
蜘蛛侠(SpiderMan),Man 是主要类型,而 Spider 是次要类型,是接口。
忍者神龟,乌龟是主要类型,其次实现了“忍者”接口。
2).单继承相对多继承的好处,就在于单继承具有简单性。
用接口实现的多继承,则不会破坏类之间树状结构的简单性。
2.用接口来进行解耦合(接口作为标准)
接口,把接口使用者和接口实现者分离。
在生活中,对象之间的弱耦合关系也是通过标准来实现的。
硬盘坏,可以更换其他品牌硬盘,对主板CPU没有影响,因为,硬盘厂商遵循统一标准生产硬盘
接口回调
在定义接口后,先有接口的使用者,后有接口的实现者
使用者通过接口调用实现者中的方法
系统中的方法 ———(调用)———> 接口 <———(实现)——— 程序员写的代码
java.util.Arrays.sort 方法必然会用到对象类型的排序规则
即,程序员提供排序规则,而在 sort 方法中,调用了这个排序规则
class Student implements Comparable<Student>{ //<泛型>
int age;
String name;
public int compareTo(Student s){ //返回一个整数
/*
确定this和s对象,谁排在前面
如果希望this排在s前面,返回负数
如果希望this排在s后面,返回正数
如果希望this和s不分前后,返回0
*/
}
}
//s1.compareTo(s2) 表示把s1和s2进行比较。“当前对象”指s1
内部类
内部类编译后会生成独立的.class 文件 -- 外部类名$内部类名.class
1.成员内部类
class MyOuterClass{
private int value; //成员变量
class InnerClass{ //成员内部类
public void m(){
System.out.println(value);
}
}
}
1).定义位置:类内部,方法外部(也就是定义成员变量的位置)
2).在内部类中可以访问外部类的私有成员,而不破坏封装
3). private 可以修饰成员内部类 -- 表示只能在 MyOuterClass 的内部使用InnerClass 类
4).使用成员内部类创建对象:
1).在外部类中,可以直接创建内部类的对象
public void f(){ //为 MyOuterClass 添加一个 f 方法
InnerClass ic = new InnerClass();
ic.m();
}
2).在外部类的外部创建对象
//内部类对象的类型,需要写成"外部类.内部类"。
//创建一个内部类对象的时候,必须首先创建一个外部类的对象
MyOuterClass moc = new MyOuterClass();
//通过外部类对象.new 构造内部类对象
MyOuterClass.InnerClass inner = moc.new InnerClass();
5).成员发生命名冲突时,用 MyOuterClass.this.value 访问外部类属性 -- 外部类名.this.成员名
6).由于成员内部类必须与外部类某一个对象相关联,因此成员内部类中不能定义静态成员。
2.静态内部类(成员内部类+static)
class MyOuterClass{
class MemberInner{} //成员内部类
static class StaticInner{} //静态内部类 --- static 关键字能够用来修饰内部类
}
成员内部类中不能定义静态方法;成员内部类中能够访问外部类的所有静态以及非静态的成员;
静态内部类中可以定义静态方法,静态内部类中只能访问外部类的静态成员(静态属性或静态方法)
创建静态内部类的对象:
1)在外部类中,可以直接创建内部类的对象
2)直接使用"外部类.内部类"的方式就能够创建
MyOuterClass.InnerClass2 in2 = new MyOuterClass.InnerClass2();
3.局部内部类
定义在方法内部的类
public void m(){
final int localValue = 300; //外部类的局部变量 -- final
class Inner{ //局部内部类 -- 其访问范围就是在方法内部
public void f(){
//局部内部类能够访问外部类的私有属性、静态属性
}
}
Inner in = new Inner();
in.f();
}
在局部内部类中能够访问外部类的局部变量,但是要求该变量必须是 final 的!
jvm中内存类型:
栈:独立 先入后出 局部变量、引用在栈中分配空间
堆:共享 对象在堆中分配空间
4.匿名内部类(特殊的局部内部类)
特殊性:
1、该内部类继承自某个类或者实现某个接口;
2、该内部类在整个方法中只创建了一个对象。
new 接口名 () { 实现接口的代码 } ;
没有类名的局部内部类,将类定义、实现接口以及创建对象合三为一
将接口公开 实现类隐藏在方法中 从而实现强制弱耦合
匿名内部类无法定义构造方法(没有类名)
public static Teacher getTeacher(int n){
//Jim 依然采用局部内部类的写法
class Jim implements Teacher{ //类定义、实现接口
public void teach(){
System.out.println("Jim teach");
}
}
//匿名内部类
if (n == 10) return new Teacher(){
public void teach(){
System.out.println("Tom teach");
}
}; //;是return的结尾
else return new Jim(); //创建对象
}
Object类:所有类的父类,Java继承树的根
class ClassA{} //ClassA 继承 java.lang.Object
class ClassB extends ClassA{} //ClassB 继承 ClassA
1).Java中所有的对象,都能够赋值给Object类型的引用(子类对象可以直接赋值给父类引用)
2).Object类中所有的公开方法都能被子类继承
1.finalize() 在对象被垃圾回收时由垃圾回收器调用。
采用的是“最少”回收的机制
class Student{
String name;
int age;
}
……main{
Student stu1 = new Student(); //占据内存,无法被使用,垃圾对象
stu1 = new Student(); //stu1指向新的对象
}
1)垃圾回收器,如何判定一个对象是一个垃圾对象? 零引用算法
2)垃圾回收器,何时回收垃圾对象??? 内存不足时(必须释放时)
2.getClass() 返回对象的实际类型。
class Animal{}
class Dog extends Animal{}
class Courser extends Dog{}
dog instanceof Dog //true 指向Dog类型的对象
courser instanceof Dog //true 问题:Courser是Dog子类,也会返回true
解决:
Dog d1 = new Dog();
Dog d2 = new Dog();
Dog d3 = new Courser();
//d1 和 d2 实际类型相同,因此 getClass 方法返回值相同,输出 true
System.out.println(d1.getClass() == d2.getClass());
//d1 和 d3 实际类型不同,因此 getClass 方法返回值不同,输出 false
System.out.println(d1.getClass() == d3.getClass());
3.toString() 返回对象的String形式
这个方法是 Java 中所有对象都有的方法
Student stu = new Student();
直接打印 stu 对象,就相当于调用这个对象的toString()的返回值
System.out.println(stu.toString()); //手动调用 toString 方法--Student@c17164
System.out.println(stu); //直接打印 stu 对象--Student@c17164
//@XXXXX 表示的是对象相应的内存地址
为了让 toString 方法能打印出我们想要的内容,我们可以覆盖这个方法如下:
public String toString(){ //方法覆盖
return name + " " + age;
}
4.equals(Object o) 判断当前对象(this)和o内容是否相同
public boolean equals(Object o)
String str1 = new String("abc");
String str2 = new String("abc");
//比较两个引用是否指向同一个对象,输出 false
System.out.println(str1 == str2);
//比较两个对象内容是否相等,输出为 true
System.out.println(str1.equals(str2)); //当前对象就是str1对象,而o对象就是str2对象。
程序员应当自己来指定两个对象的比较准则。
实现的 equals 方法,应当满足以下几个条件:
自反性:一个对象自己跟自己比较,必须为 true
对称性:(交换律)
两个不为 null 的引用x和y,如果x.equals(y)为 true ,则 y.equals(x)也为 true
而如果 x.equals(y)为 false ,则 y.equals(x)也为 false
传递性:
三个不为 null 的引用a、b、c,
如果a.equals(b)为 true ,b.equals(c)为 true ,则a.equals(c)也必然为 true
一致性:
两个不为 null 的引用x 和y,在不改变x和y的属性的前提下,每次调用x.equals(y)返回的值都相同
如果x不为 null ,则x.equals(null)应当返回 false
方法重写
public boolean equals(Object o){
//1判断 obj 是否和 this 相等,保证自反性
if (this == o) return true;
//2判断 o 是否为 null,保证最后一条准则
if (o == null) return false;
//3判断两个对象的实际类型是否相等,
//如果不相等,则说明比较的是两个不同种类的对象,应当返回 false
if (this.getClass() != o.getClass()) return false;
//4将o强制类型转换
Student stu = (Student) o;
//5逐个判断每个属性是否相等
// 对于基本类型的属性用“==”比较,对象类型的属性用equals比较
if (this.age == stu.age && this.name.equals(stu.name) )
return true;
else return false;
}
-------------------------------------------------
总结一下,覆盖 equals 方法的五个步骤:
1).判断 this == obj
2).判断 obj == null
3).判断两个对象的实际类型(使用 getClass()方法)
4).强制类型转换
5).依次判断两个对象的属性是否相等
常用类:包装类和String类
包装类:
为8种基本类型提供对象形式,能够让Object统一所有的数据
对于数值类型的属性,区分0和 null
基本类型 包装类型
byte Byte
short Short
int Integer
long Long
char Character
float Float
double Double
boolean Boolean
六种转换:三种类型(字符串类型、基本类型、包装类类型)
1)基本类型和包装类之间的转换:
//new 包装类名(基本类型值);
Integer ii = new Integer(10); //利用Integer的构造方法,以int作为参数创建相应的Integer对象
//包装类名.valueOf(基本类型值)
Integer ii = Integer.valueOf(10);
Double dd = Double.valueOf(2.2);
------------------------------------
//包装类对象.xxxValue();
int i = ii.intValue(); //直接调用Integer对象的intValue方法
double d = dd.doubleValue();
2)String 类型与包装类之间的转换:
//利用包装类的构造方法
Integer i = new Integer("123");
//包装类名.valueOf(str);
Integer i = Integer.valueOf("123");
---------------------------------------------------------
String str2 = ii2.toString(); //把对象转化为字符串 ---- 直接调用包装类对象的toString方法,就能返回该对象的字符串表现形式
*3)基本类型和字符串类型之间转换:
//String.valueOf(基本类型值);
String str3 = String.valueOf(10); //使用 String 类中定义的一个静态方法:valueOf ----- 定义了一系列重载的valueOf方法(把不同的基本类型转换为字符串类型)
------------------------------------------------------------
String str4 = "" + i; //用一个空字符串加上一个整数,从而把这个整数转化为一个字符串。
---------------------------------------------------------------
//包装类名.parseXXX(字符串);
int i = Integer.parseInt("123"); //调用Integer类的parseInt方法,把字符串转化为int
double d = Double.parseDouble("12.2");
自动封箱和拆箱( JDK5.0 以后)
由编译器自动完成基本类型和包装类之间的转换
//把 int 类型直接赋值给 Integer 类型
Integer myInteger = 10;
//把 Integer 类型直接赋值给 int 类型
int i = myInteger;
注意: 包装类型对象间比较内容时使用equals 基本类型使用 ==
String类常用方法:
char charAt(int index);返回下标对应的字符
int compareTo(String str);按照字典顺序进行比较
boolean contains(String s);判断是否包含特定字符串
boolean endsWith(String s);判断字符串是否以指定后缀结尾
boolean equalsIgnoreCase(String str);不区分大小写比较字符串的内容
int indexOf(String s);返回指定字符串出现的首次下标
int indexOf(int s);返回字符出现的首次下标
String[] split(String s);将字符串按照指定字符分割成字符串
int length();返回字符串的字符长度
String trim();返回去除头部和尾部空格的字符串
String valueOf(char[] cs);使用char数组构建一个String对象
String valueOf(8种基本类型 );将8种基本类型转换为字符串
集合框架
集合:容器,一个对象,用来储存和管理多个对象。
eg:抽屉,书架
接口:
1.Collection接口
特点:元素是Object
方法:
boolean add(Object o)
把对象o放入集合中
如果元素加入集合成功,则返回 true ,否则返回 false
boolean contains(Object o)
判断对象o在集合中是否存在
boolean isEmpty()
判断集合是否为空
Iterator iterator()
用来完成集合的迭代遍历操作
boolean remove(Object o)
把对象o从集合中删除。返回值表示删除是否成功
void clear()
清空集合
int size()
返回集合中元素的个数
实现类:无
某些实现类实现了Collection接口的子接口,这样能够间接的实现Collection接口。
2.List接口(Collection的子接口)
元素是对象
元素有顺序(下标),可以重复。
方法:
void add(int index, Object o)
表示把对象o插入到集合中index下标处
? Object get(int index) /
返回下标为index的元素
Object set(int index, Object o)
把下标为index的元素替换为o
int indexOf(Object o)
表示在List中进行查找。
如果List中存在o元素,则返回相应的下标;不存在则返回-1。
boolean remove(int index)
删除index上的元素
遍历:
(1)下标遍历:
for(int i = 0; i
Comparable与排序
Collections 类与 Comparable
Collections.sort方法,对一个 List 进行排序
Collections.max 方法,可以找到集合中的最大值
Collections.min 方法,可以找到集合中的最小值
foreach循环
主要解决遍历的问题
for(变量 : 集合){
循环体;
}
这段代码表示,遍历整个集合,每次迭代时都把集合中的一个元素赋值给 foreach 循环中的变量,并执行循环体。
迭代遍历:
Iterator iter = set.iterator();
while(iter.hasNext()){
Object value = iter.next();
System.out.println(value);
}
-----------------------------------------
for(Object value : set){
System.out.println(value);
}
遍历数组:
String[] ss = new String[]{“hello”, “world”, “java”};
for(String obj : ss){
System.out.println(obj);
}
泛型 模板编程 参数化类型
List<E> -- E表示List的泛型。
//创建一个只能用来保存 Dog 对象的 List
List<!-- <Dog> --> list = new ArrayList<!-- <Dog> -->();
类型可以有多态,但是泛型不能够有多态!
不同泛型之间不能相互赋值
泛型的通配符:? 接受任意类型的作为泛型
? extends Number 表示Number类或Number的任何子类
? super Number 表示Number类或Number的任何父类
? extends Comparable 表示任何实现Comparable接口的类
泛型方法:
<T extends Number & Comparable> 表示T既是Number的子类,又实现Comparable接口
泛型类: class A<!-- <T extends Number> -->{}
泛型技术应用在集合框架中:实现类型安全的集合
泛型:约定集合中的元素类型
JDK 5.0新特性
自动封箱和拆箱
for-each
静态引入
用到一个类中静态成员时,可以省略类名
import static java.lang.System.*;
out.println();
可变长参数
由编译器负责将多个实参封装成数组
一个方法中,最多只能有一个变长参数,且必须是参数表中最后一个参数
void method(String... str){} //可以传入0~n个字符串 -- 相当于String[] str
method();
method("hgh");
method("hgh","klk");
格式化输入输出
枚举
枚举是个类:这个类的对象是构造好的,不允许用户构造该类的新对象
特殊的类 默认是Enum的子类 final 类
所有的构造方法都是私有的
枚举值:枚举类的对象,也是枚举类中的公开静态常量
枚举中可以定义抽象方法,由枚举值分别实现
eg:男、女 红黄绿灯 季节
enum Season{ //
SPRING, //public static final Season SPRING=new Season();
SUMMER, //public static final Season SUMMER=new Season();
AUTUMN, //public static final Season AUTUMN=new Season();
WINTER; //public static final Season WINTER=new Season();
}
Season s = Season.SPRING;
s.name() //枚举值的名字
s.ordinal() //枚举值的序号(0,1,2,3……)
Season.values() //返回枚举的所有属性
异常处理
提高程序的容错性
java.lang.Throwable 所有错误的父类
方法:
String getMessage();//返回异常的详细信息
void printStackTrace();//打印异常的追踪信息(异常出现的位置、出现的方法处)
-Error(Throwable的子类) 严重的底层错误,无法处理
-Exception(Throwable的子类) 异常,异常处理的主要对象
RuntimeException 未检查异常(运行时异常),可以避免,尽量避免可不处理
非RuntimeException 已检查异常(编译时异常),无法避免,必须处理
当函数产生并抛出一个异常时,异常会沿着方法调用链反向传递。
throw + Throwable 对象 //throw new NullPointerException();
throw 是一个动作,表示手动抛出
throws 是一个声明,表示本方法一旦发生这些异常,本方法不作处理,异常由调用这个方法的方法来处理。
try-catch 捕获异常
try-catch-finally try-finally
try{
可能发生异常的代码; //有可能不执行
}catch(捕获的异常类型 1 e){
异常处理 1…
}catch(捕获的异常类型 2 e){
异常处理 2…
} catch(捕获的异常类型 n e){
异常处理 n…
}finally{ //一般用于释放资源
无论程序执行时是否发生异常,最终都会被执行
}
未检查异常同样可以被捕获、被处理。
捕获 Exception,意味着任何类型的异常都能够被捕获(多态)
捕获子类异常的 catch 语句写在前面,捕获父类异常的 catch 语句写在后面。
异常与方法覆盖
子类的覆盖方法不能比父类的被覆盖方法抛出更多(范围更宽)的异常。
子类要么抛出跟父类相同的异常
要么不抛出异常
要么抛出的异常是父类抛出异常的子类。
创建异常类
一般继承于Exception 或 RuntimeException
必须拥有两个构造方法
class MyException extends Exception{ //继承Exception | RuntimeException
public MyException(){}
public MyException(String str){
super(str);
}
}
多线程
进程:操作系统中并发执行的一个任务
并发:宏观上并行,微观上串行。
宏观上,一个系统同时运行多个程序,这些程序是并行执行的;
微观上,每个时刻都只有一个程序在运行,这些程序是串行执行的。
一个进程并发多个线程。(迅雷 -- 多个下载任务)
线程运行时所需要的三大条件:
1、CPU OS进行调度
2、Data(数据) 堆空间共享 栈空间独立
堆空间:存储对象(存储实例变量) | 保存的是我们利用 new 关键字创建出来的对象;
栈空间:存储局部变量 | 保存的是程序运行时的局部变量。
3、Code(代码) 程序员完成,分配给线程的任务
线程对象的创建:
一个Thread对象代表一个线程
1.继承Thread类
class MyThread1 extends Thread{ //继承Thread 类
public void run(){} //重写run()方法
}
main…{
Thread t1 = new MyThread1(); //创建了 t1 线程对象
t1.start(); // start()是从 Thread 类中继承来
}
2.实现Runnable接口
class MyRunnable2 implements Runnable{ //实现 Runnable 接口
public void run(){} //实现run方法
}
main…{
Runnable target = new MyRunnable2(); //创建目标对象
Thread t2 = new Thread(target); //利用目标对象创建线程对象
t2.start(); //注意:不可重复启动同一线程
}
线程的状态
初始状态:创建了线程对象,而没有调用这个线程对象的start()方法
可运行状态:线程已经为运行做好准备,只等着获得 CPU 来运行。
运行状态:获得了 CPU 时间片,正在执行代码
终止状态:一个线程执行完了 run()方法中的代码
主线程的启动没有必要经历初始状态
主线程进入终止状态,并不意味着整个程序就结束了
阻塞状态
public static void sleep(long millis) throws InterruptedException //静态方法。休眠()毫秒,释放cpu时间片,不会释放锁标记
join() //优先 eg:t1:t2.join() t1阻塞
public final void join(long millis) throws InterruptedException
线程同步
多个线程并发访问临界资源(同一个对象),如果破坏了原子操作(不可分割的操作),则有可能产生数据不一致的情况(“同步”问题)
synchronized
同步代码块: synchronized(o){} //对对象o加锁的代码块
任何一个对象都有一个互斥锁标记,用来分配给线程
只有获得对象锁标记,才能进入到对该对象加锁的同步代码块中
同步方法:用 synchronized修饰的方法
public synchronized void m(){}
相当于对当前对象加锁
只有获得当前对象的对象锁标记,才能执行该同步方法,方法执行完毕,释放锁标记
-------------------------------------------------------------------------------------
当一个线程正在访问某个对象的同步方法时,其他线程不能访问同一个对象的任何同步方法
一个线程可以同时拥有多个对象的锁标记(同步代码块可以嵌套)
可能造成死锁
wait 与 notify 解决死锁机制 (线程间通信:等待-通知)
对某个对象调用 wait()方法,表明让线程暂时释放该对象的锁标记。
调用notify()方法,会从其等待状态中的多个线程里挑选一个线程进行唤醒。
调用notifyAll() 会把其对象等待状态中的所有线程都唤醒。
修饰符组合:
synchronized 和 static 联用: 可以 对当前类对象加锁
synchronized 和 abstract 联用:不可以 (抽象方法没有代码块,不能同步)
synchronized 和 构造方法 联用:不可以 (构造方法没有创建对象结束,同步方法必须对对象加锁)
获取当前线程对象的名字:
Thread.currentThread().getName();
I/O框架
数据的输出:将 JVM 中的数据写出去 ( Output )
数据的输入:将数据读入 JVM ( Input )
File 类
File对象代表磁盘上的一个文件或目录。
构造方法:
File(String pathname):表示一个路径名。用来创建一个代表给定参数的文件或者文件夹。
File(String parent, String child):用来代表名字为 parent/child 的文件或者文件夹。
File(File parent, String child):parent表示父目录
D:\\abc D:/abc
createNewFile() : 创建新文件。如果文件已经存在, 该方法不会覆盖原有文件。
mkdir():创建新目录
mkdirs():用来创建多层文件夹
delete() : 删除。会被立刻删除
deleteOnExit() : 也用来删除文件或者文件夹。等到程序退出以后再删除。
getPath() : 返回路径
getName() : 返回文件名
getParent() : 返回所在的文件夹
getAbsolutePath() : 返回绝对路径。
getCanonicalPath() : 返回规格化以后的路径。需要注意的是这个方法会抛出一个异常。
exists() : 判断 File 对象表示的文件或目录是否存在
isFile() : 判断 File 对象代表的是否是文件
isDirectory() : 判断 File 对象代表的是否是目录
listFiles() : 返回一个 File 数组,表示 File 对象所代表文件夹下所有的内容
I/O 分类
流:对象,用于jvm和外部数据源进行数据传输 (电线:传输电力;水管:传输水;输油管:传输石油)
按照流的方向分:
输入流:从外部数据源到jvm读入数据的流
输出流:从jvm写出数据到外部数据源的流
按照流的数据单位分:
字节流:传输数据以字节为单位,可以读写所有类型数据
字符流:传输数据以字符为单位,只能读写文本数据
按照流的功能来分:
节点流:真正能够完成传输功能的流
过滤流:为节点流增强功能
eg:输电线
节点流:真正能够传输电力的金属丝
过滤流:一层绝缘的胶布,增加了绝缘保护的功能
装饰模式
字节流:
InputStream/OutputStream(字节流的父类,抽象类)
FileInputStream 是文件输入流,节点流,能够读取硬盘上的文件;
FileInputStream(String filename) : 通过文件路径,获得文件输入流
FileInputStream(File file) :通过文件对象,获得文件输入流。
close() : 用来关闭文件流,释放资源。
int read():返回每次从文件中读取的一个字节。当读到流末尾时,返回-1
int read(byte[] bs) : 把读取到的数据放入 bs 数组中,一次调用尽量读取 bs.length 个字节。当读到流末尾时,返回-1。
int read(byte[] bs, int off, int len)
读取数据的时候,会让数据在数组中以下标为 off 的地方开始,并且最多只读取 len 个。当读到流末尾时,返回-1
FileOutputStream 是文件输出流,节点流,能够写入文件。
FileOutputStream(String path) : 根据路径创建文件输出流
FileOutputStream(File file) : 根据文件对象创建文件输出流
FileOutputStream(String path, boolean append)如果文件已存在,用追加的方式写文件
FileOutputStream(File file, boolean append)如果文件已存在,用追加的方式写文件
close(): 关闭流
void write(int v) : 每次调用时写入一个字节。
void write(byte[] bs) : 写入一个 byte 数组。
void write(byte[] bs, int off, int len) : 写入byte数组的一段,数据内容从数组下标 off 的位置开始,写入 len 个字节。
字节过滤流:
DataInputStream 和 DataOutputStream 数据读写流 增强了读写八种基本类型和String的功能
过滤流的创建方式:
1、创建一个节点流 InputStream in = new FileInputStream("test.dat");
2、使用过滤流包装节点流 DataInputStream dis = new DataInputStream(in);
3、读、写数据
4、关闭资源:关闭过滤流
BufferedInputStream 和 BufferedOutputStream 缓存读写流 增强了缓冲区的功能
PrintStream 增强的功能:缓冲区的功能、写八种基本类型和字符串、写对象
ObjectInputStream 和 ObjectOutputStream
对象序列化:对象通过流进行传输的过程
eg:搬家(可序列化:家具、电器;不可序列化:窗户、地板)
实现Serializable接口,才成为可序列化的类
transient 修饰属性(临时属性):表示这个属性不参与序列化。
使用对象序列化的时候,注意:
不要使用追加的方式写对象
如果一个对象的属性又是一个对象,则要求这个属性对象也实现了Serializable接口
如果一个对象的属性是一个集合,则要求集合中所有对象都实现 Serializable 接口
字符流:
字符编码
ASCII、GB2312/GBK、ISO-8859-1、Big5、UTF-8
当字符编码方式和解码方式不统一的时候,可能会造成乱码
Writer/Reader 字符流的父类(抽象类)
FileReader:表示文件输入字符流(节点流)
FileWriter:表示文件输出字符流(节点流)
字符过滤流:
读入使用 BufferedReader 提供了缓冲区功能
public String readLine()
写出使用 PrintWriter
增强的功能:缓冲区的功能、写八种基本类型和字符串、写对象
InputStreamReader 和 OutputStreamWriter
桥转换:字节流向字符流转换 (此时可以指定编解码方式)
利用桥转换进行编程,需要以下五个步骤:
1、 创建节点流
2、 桥转换为字符流
3、 在字符流的基础上封装过滤流
4、 读/写数据
5、 关闭外层流