Java内部类与常用类
学习地内容:
- 内部类
- Object类
- Object类常用方法
- 包装类
- String类
- BigDecimal类
内部类
内部类分类:
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
内部类概念
在一个类的内部再定义一个完整的类
class Body{
class Head{
}
}
为什么要这样做呢,就比如上面的代码,头是身体的一部分,所以我们把它定义为Body的内部类
特点:
- 可以内部类和外部类都会生成一个字节码文件 Body.class Body$Head.class
- 内部类可以调用外部类的私有成员
- 内部类可以为外部类提高必要组件
成员内部类
在类的内部定义,和实例变量、实例方法 同级别的类
外部类的一个实例部分,创建内部类一定要先创建外部类,通过外部类实例来new内部类对象
Outer outer = new Outer();
Inner inner = outer.new Inner();
//或者可以进行简化
Inner inner = new Outer().new Inner();
当外部类与内部类存在重名属性时,优先访问内部类
对象是内部类对象
inner.show();
成员内部类不能定义静态成员
但是能包含静态常量
public static final String name = “张三”;
静态内部类
静态内部类级别和外部类相同
不需要通过外部类创建对象,可以直接调用
目的是给外部类提供一些功能
public class Outer{
private String name = "张三";
private int age = 17;
static class Inner{
private String address = "上海";
private String phone = "111";
private static int count = 100;
public void show(){
//调用外部类属性,要创建外部类的对象
Outer outer = new Outer();
System.out.println(outer.name);
//调用静态内部类属性
System.out.println(address);
//调用静态内部类的静态属性
System.out.println(Inner.count);
}
}
}
创建静态内部类对象
Outer.Inner inner = new Outer.Inner();
inner.show();
只有内部类才能用static修饰
局部内部类
定义在外部类方法里面的类
public class Outer{
private String name = "张三";
private int age = 35;
public void show(){
String address = "深圳";
//局部内部类不能加任何访问修饰符
class Inner{
}
}
}
静态方法内部不能访问非静态属性
因为静态方法出现的时候还没有非静态方法
Outer outer = new Outer();
outer.show(); //不会打印出任何结果
要想打印出结果应该要在Inner类外面,show()里面加上一段代码
Inner inner = new Inner();
inner.show2();
show2()如何访问局部变量,就是和class Inner同级别的常量address
可以直接访问,但是jdk会直接把他转化成常量
为什么?
因为调用show()的时候,调用完了以后局部变量就释放掉了,但是inner在堆里,所以还存在
同时局部内部类也不能定义静态成员变量,只能是常量,和成员内部类一样。
private static final int AGE = 17;
局部内部类作用范围仅仅在所在方法中
匿名内部类
没有类名的局部内部类(一切特征都与局部内部类相同)
必须继承一个父类或者实现一个接口
定义类、实现类,创建对象的语法合并,只能创建一个该类对象
优点:减少代码量
缺点:可读性较差
也有一个字节码(.class)文件
public interface Usb {
void service();
}
public class TestUsb {
public static void main(String[] args) {
/*Usb usb = new Mouse();
usb.service();*/
// //局部内部类
// class Fan implements Usb{
// @Override
// public void service() {
// System.out.println("连接电脑成功,风扇开始工作了");
// }
// }
// //使用局部内部类创建对象
// Usb usb = new Fan();
// usb.service();
//
// //因为这个类只用一次,这个定义很麻烦,所以用匿名内部类优化
//匿名内部类
Usb usb = new Usb(){
@Override
public void service() {
System.out.println("风扇开始工作!");
}
};
usb.service();
}
}
Object类
Object类是所有列的父类
没有写extends都默认直接继承Object类
否则为间接继承Object类
Object类可以存储任何对象:
- 作为参数,可以接收任何对象
- 作为返回值可以返回任何对象
Object类中所具有的方法是所有对象都具备的方法
getClass()方法
public final Class<?> getClass(){}
返回引用中存储的实际对象类型
应用:判断两个引用中实际存储对象类型是否一致
public class TestStudent{
public static void main(String[] args){
Student s1 = new Student("aaa",20);
Student s2 = new Student("bbb",30);
Class class1 = s1.getClass();
Class class2 = s2.getClass();
if(class1 == class2)
System.out.println("s1和s2属于同一个类")
}
}
hashCode()方法
public int hashCode(){}
返回对象的哈希码值
hash值根据对象的地址或字符串或数组根据hash算法计算出来的int类型的数值
一般情况下,相同对象返回相同哈希码
public class TestStudent{
public static void main(String[] args){
Student s1 = new Student("aaa",20);
Student s2 = new Student("bbb",30);
Class class1 = s1.getClass();
Class class2 = s2.getClass();
if(class1 == class2)
System.out.println("s1和s2属于同一个类")
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
Sudent s3 = s1;
System.out.println(s3.hashCode());
//s3和s1相同,和s2不同
}
}
toString()方法
public String toString(){}
返回该对象的字符串表示
可以根据程序需求覆盖(重写),比如展示对象各个属性值
System.out.println(s1.toString());
System.out.println(s2.toString());
打印出来的是 包的名称@hashCode
//Student类中
public String toString(){
return "Student[name"+name+"age="+age+"]";
}
equals()方法
public boolean equals(Object obj){}
默认实现为(this == obj), 比较两个对象地址是否相同
可进行覆盖,标记连个对象内容是否相同
System.out.println(s1.equals(s2)) //判断地址是否一样
重写equals()
return false
finalize() 方法
当对象被判定为垃圾对象,JVM自动调用次方法,用以标记垃圾对象,进入回收队列
自动回收:JVM内存耗尽,一次性回收所有垃圾对象
手动回收机制:使用 System.gc(); 通知JVM执行垃圾回收
包装类
什么是包装类?
基本数据类型所对应的引用数据类型
Object类可以统一所有数据,包装类的默认类型是null
Java.lang 包内
类型转换:装箱和拆箱
类型转换:基本类型与包装类的转换
基本类型数据存在栈中
引用数据类型存放在堆中,栈中只有一个引用,指向堆中
栈中基本数据类型比如说 int a = 10;
要把a放入堆中,这个过程叫装箱
堆中拿到栈里面叫拆箱
- 装箱:基本类型转换成引用类型
- 拆箱:引用类型转换为基本类型
public class Demon{
public static void main(String[] args){
//装箱操作
int num1 = 10;
Integer integer1 = new Integer(num1);
Integer integer2 = Integer.valueOf(num1);
//拆箱操作
Integer integer3 = new Integer();
int num2 = integer3.intValue();
//jdk1.5之后提供自动装箱以及拆箱功能
int age = 30;
//自动装箱
Integer integer = age;
//自动拆箱
int age2 = integer;
}
}
基本数据类型与字符串的转换
基本类型转字符串
//1、利用+号
int n1 = 15;
String s1 = n1+"";
//2、使用toString()方法
String s2 = Integer.toString(n1);
String s3 = Integer.toString(n1,16); //转换成16进制的
字符串转基本类型
String str = "150";
//使用Integer.parseXXX()
int n2 = Integer.parseInt(str);
//boolean字符串转基本类型, "true"----->true , 非"true"-------->false
整数缓存区
面试题
public class Demon2{
public static void main(String[] args){
Integer integer1 = new Integer(100);
Integer integer2 = new Integer(100);
System.out.println(integer1 == integer2);//答案是false,比较的是栈中的地址值
}
}
String
字符串是常量,创建后不可改变
字符串字面值存储在字符串池中,可以共享
String s = “hello”; //字符串池中存储
String s = new String(“hello”); 创建两个对象,堆和池中各创建一个
public static void main(String[] args){
String name = "hello";
name = "zhangsan";
String name2 = "zhangsan";
String str = new String("java");
String str2 = new String("java");
System.out.println(str == str2); //结果是false
System.out.println(str.equals(str2)); //结果是true
}
String中的常用方法
- public int length() 返回字符串长度
- public char charAt(int index) 根据下标获取字符
- public boolean contains(Stirng str) 判断当前字符串中是否包含str
String content = "java是世界上最好的语言";
System.out.println(content.length());
System.out.println(content.charAt(0));
System.out.println(content.contains("java"));
重要方法:
equals() 和 compareTo()
String s1 = "hello";
String s2 = "HeLLo";
System.out.println(s1.equals(s2));
System.out.println(s1.equalsIgnoreCase(s2)); //忽视大小写
String s1 = "abc";
String s2 = "xyz";
System.out.println("s1.compareTo(s2)"); s1与s2第一个字符ASCII码值的差, 97-120 结果是-23
第一个一样比第二个
可变字符串(StringBuffer StringBuilder)
String增强类
StringBuffer:可变长字符串,jdk1.0提供,运行效率慢,线程安全
StringBuilder:可变长字符串,jdk5.0提供,运行效率快,线程不安全
这两个类效率比String高,比String节省内存
public static void main(String[] args){
StringBuffer sb = new StringBuffer();
//1.append()添加
sb.append("java天下第一");
System.out.println(sb.toString());
sb.append("java真香");
System.out.println(sb.toString());
//显示java天下第一
//java天下第一java真香
//2.insert() 插入
sb.insert(0,"php"); 在什么位置插入
//3.replace()
sb.replace(0,4,"phps"); //0到4是索引位置,前闭后开
//4.delete()
sb.delete(0,4); //索引位置,前闭后开
sb.delete(0,sb.lenght()); //清空
}
StringBuilder和StringBuilder基本一样
BigDecimal类
public class Demon{
public static void main(String[] args){
double d1 = 1.0;
double d2 = 0.9;
System.out.println(d1-d2); //打印出来的是0.09999999999
//原因是因为double类型存储的是近似值
}
}
在需要精确运算的时候double就不能满足要求,这时候我们需要一个精度更加高的类
BigDecimal类(精确计算浮点数)
在java.math包中
BigDecimal创建对象时要传入字符串
BigDecimal bd1 = new BigDecimal("1.0");
BigDecimal bd2 = new BigDecimal("0.9");
//减法
BigDecimal r1 = bd1.subtract(bd2);
System.out.println(r1);
//加法bd1.add(bd2);
//乘法bd1.multiply(bd2);
//除法bd1.divide(bd2)
//divide方法有其他参数(保留几位小数具体查文档)
Data类
Date表示特定瞬间,精确到毫秒。Data类中大多数方法 已经被Calendar类中方法取代
时间单位:
- 1秒 = 1000毫秒
- 1毫秒 = 1000微秒
- 1微秒 = 1000纳秒
很多方法已经过时,具体查jdk文档
Java集合框架
课程目标:
- 集合的概念
- Collection接口
- List接口与实现类
- 泛型与工具类
- Set接口与实现类
- Map接口与实现类
集合的概念
概念:对象的容器,定义了对多个对象进行操作的方法,可实现数组功能
和数组区别:
- 数组长度固定,集合不固定
- 集合只能存储引用类型,基本类型要进行装箱操作
位置:java.util.*
Collection接口
Collection父接口:
//创建Collection对象
Collection collection = new ArrayList();
//遍历数组元素,不能用for语句,因为Collection对象无下标
//1.可以用增强for
for(Object object:collection){
System.out.println(object);
}
//2.可以用迭代器(专门用来遍历集合的一种接口)
//注意:迭代过程中不能调用collection remove方法
//可以调用Iterator对象的remove方法
Iterator it = collection.iterator();
While(it.hasNext()){
String s = (String)it.next();
System.out.println(s);
it.remove();
}
List集合
List子接口
特点:有序、有下标,元素可以重复
//遍历集合中元素
List list = new ArrayList<>();
//1.普通for
//2.增强for
for(Object object:list){
System.out.println(object);
}
//3.迭代器
Iterator it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//4.允许程序员按任意方向遍历列表
//和Iterator区别:可以向前、向后遍历、添加、删除、修改元素
ListIterator lit = list.listIterator();
while(lit.hasNext()){
System.out.println(lit.nextIndex()+":"+lit.next());
}
while(lit.hasPrevious){
System.out.println(lit.previousIndex()+":"+lit.previos());
}
//List存储数字元素会自动装箱
List list = new ArrayList<>();
list.add(20);
//删除值为20的元素
list.remove(0);//删除索引为0的元素
//想要表示删除值为20的元素
list.remove(new Integer(20));
//或者
list.remove((Object)20);
//返回子集合
list.subList(1,3);
List实现类
ArrayList 重点
- 数据结构实现,查询快、增删慢
- JDK1.2 运行效率快,线程不安全
Vector
- 数据结构实现,查询快,增删慢 (和ArrayList很像)
- JDK1.0 运行效率慢,线程安全
LinkedList:
- 链表结构实现,增删快,查询慢
ArrayList使用
添加元素
ArrayList arrayList = new ArrayList<>();
Student s1 = new Student("刘德华",20);
Student s2 = new Student("张学友",30);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
删除元素:
arrayList.remove(s1);
源码剖析:
DEFAULT_CAPACITY = 10 默认容量
注意:如果没有添加元素,那么是0
elementData 存放元素的数组
size 存放元素个数
Vector使用
创建Vector对象
Vector vector = new Vector<>();
添加元素
vector.add("苹果");
vector.add("草莓");
vector.add("香蕉");
System.out.println("元素个数:"+vector.size());
删除元素:
vector.remove(0);
vector.remove("西瓜");
vector.clear(); //清空
遍历
//用枚举器
Enumeration en = vector.elements();
while(en.hasMoreElements()){
Object o = en.nextElement();
}
判断
vector.contains("西瓜");
vector.isEmpty();
LinkedList使用
链表实现,增删快,查询慢
LinkedList linkedList = new LinkedList<>();
Student s1 = new Student("张三",21);
Student s2 = new Student("李四",21);
Student s3 = new Student("王五",21);
添加元素
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
System.out.println(linkedList.size());
System.out.println(linkedList.toString());
删除元素:
linkedList.remove(s1);
linkedList.clear();
遍历
//1.for遍历
for(int i = 0;i<linkedList.size();i++){
System.out.println(linkedList.get(i))''
}
//2.增强for
for(Object object:linkedList){
Student s = (Student)object;
System.out.println(s.toString());
}
//3.使用迭代器
Iterator it = linkedList.iterator();
while(it.hasNext()){
Student s = (Student)it.next();
System.out.println(s.toString());
}
//4.使用列表迭代器
ListIterator lit = linkedList.listIterator();
while(lit.hasNext()){
//这里面和Iterator一样
}
获取
System.out.println(linkedList.indexOf(s1));//获取位置
ArrayList和LinkedList区别
泛型(Generic)
Java泛型是jdk1.5引入的一个新特性
其本质是参数化类型
把类型作为参数传递
常见形式:
- 泛型类
- 泛型接口
- 泛型方法
语法:
<T…> T称为类型占位符,表示一种引用类型
好处:
- 提高代码重用性
- 防止类型转换异常
- 提高代码安全性
泛型类
public class MyGeneric<T>{
//1.创建变量
T t;
//2.添加方法
public void show(T t){
}
//3.泛型作为方法的返回值
public T get(){
return t;
}
}
MyGeneric<Integer> mg1 = new MyGeneric<>();//<>里面一定得是引用类型
MyGeneric<String> mg2 = new MyGeneric<>();
//不同类型的泛型对象不能相互赋值
mg1 = mg2; //这么写会报错,一个是Integer,一个是String
泛型接口
public interface MyInterface<T>{
String name = "张三";
T server(T t);
}
public class MyInterfaceImp1 implements MyInterface<String>{
public String server(String t){
System.out.println(t);
}
}
MyInterfaceImp1 mfi1 = new MyInterfaceImp1();
public class MyInterfaceImp2<T> implements MyInterface<T>{
}
MyInterfaceImp2 mfi2<String> = new MyInterfaceImp2<>();
泛型方法
public class MyGenericMethod{
//这里有了<T> 所以参数和函数体内才能右T
public <T> void show(T t){
System.out.println("泛型方法");
}
}
MyGenericMethod mgm = new MyGenericMethod();
mgm.show("中国加油"); //show()方法里面的参数按照传入值的类型决定
泛型集合
见之前用过的各类集合
Set子接口
无序、无下标、不能重复
Set<String> set = new HashSet<>();
set.add("苹果");
set.add("华为");
set.remove("苹果");
//遍历
for(String s:set){
System.out.println(s);
}
Iterator<String> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
实现类
HashSet
- 基于HashCode计算元素存放位置
- 当存入的哈希码相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入
- 存储结构:哈希表
使用和上面的一样
就是remove不能用index删除,因为没有index
TreeSet
- 基于排列顺序实现元素不重复
- 实现了SortedSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排列顺序
- 通过CompareTo方法确定是否重复元素。
Map接口
Map接口的特点:
- 用于存储任意键值对(Key-Value)
- 键:无序,无下标,不允许重复
- 值:无序、无下标、允许重复
IO流
java IO流原理
- IO技术用于处理设备间数据传输。如读写数据,网络通信
- Java程序中,对于数据的输入输出操作以流(stream)的方式进行
- java io包下提供了各种流类和接口,用于获取不同种类的数据
一本文本文件用字符流
视频、图片用字节流
在以有的流上包一层的叫处理流
上面四个类是抽象类
IO流体系
后缀:InputStream、OutputStream都是字节流
Reader、Writer都是字符流
前缀:File的都是节点流,其他都是处理流,除了上图四个
抽象基类:InputStream OutputStream Reader Writer
访问文件: FileInputStream FileOutputStream FileReader FileWriter 这四个都是节点流
缓冲流: BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
转换流: InputStreamReader OutputStreamWriter
对象流: ObjectInputStream ObjectOutputStream
从FileReader中读取数据
@Test : Junit测试 用于新写的方法的测试,不用创建main方法就能测试出结果
@org.junit.Test
public void testFileReader() throws IOException {
//1.实例化File对象,指明要操作的文件
File file = new File("Hello.txt");
//2.提供具体的流
FileReader fr = new FileReader(file);
//3.数据读入
//read()返回读入的一个字符,如果读到文件末尾就返回-1
int data = fr.read();
while(data != -1){
System.out.print((char)data);
data = fr.read();
}
//对上述语句进行语法上的修改
int data2;
while((data2 = fr.read()) != -1){
System.out.println(data2);
}
//4.流的关闭操作
fr.close();
}
上面这个throws异常做法不好,因为假如第一步没有异常,那么就创建好了流,然后第三步出现异常就会导致抛出异常后边的就不执行了,那么第4步不执行流就没有关闭,会造成资源的浪费
用try catch finally 改进
选中一块区域,ctrl+alt+t调出surrounded with , 快速写try catch finally
@org.junit.Test
public void testFileReader() {
FileReader fr = null;
try {
//1.实例化File对象,指明要操作的文件
File file = new File("Hello.txt");
//2.提供具体的流
fr = new FileReader(file);
//3.数据读入
//read()返回读入的一个字符,如果读到文件末尾就返回-1
int data = fr.read();
while(data != -1){
System.out.print((char)data);
data = fr.read();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭操作
try {
//假如没有创建流就不用close
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
第二步出现异常是由于文件找不到
对read()操作升级
步骤:
- FIle类的实例化
- FileReader流的实例化
- 读入的操作
- 资源的关闭
大致一样,后面的操作就是第二第三步不一样,第二步流不一样,第三步读入操作会改成写出操作
@Test
public void testFIleReader2(){
FileReader fr = null;
try {
//1.File类的实例化
File file = new File("Hello.txt");
//2.FileReader流的实例化
fr = new FileReader(file);
//3.读入的操作
//方法一
//返回每次读入cbuf[]字符的个数,如果达到文件末尾就返回-1
char[] cbuf = new char[5];
int len;
while((len = fr.read(cbuf)) != -1){
//这么写是错误的
//for(int i = 0;i<cbuf.length;i++)
//错误原因:每次读五个,Hello.txt里面是helloworld123
//第一次读hello,第二次读world
//第三次cbuf里面是world,前三个被覆盖成了123,后面两个没动所以是:123ld
//正确写法
for(int i = 0;i<len;i++){
System.out.print(cbuf[i]);
}
//方法二:
//错误写法
// String str = new String(cbuf);
// System.out.print(str);
//正确写法:
String str = new String(cbuf,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileReader写出(从内存中写出数据到具体文件中去)
/*
* 内存中读出数据到硬盘中的文件中
*
* 注意:
* 1.输出操作,对应的File可以不存在 ,如果不存在,在输出过程中会自动创建
* 2.如果存在,看FileWriter构造器参数是true还是false
* */
@Test
public void testFileWriter() throws IOException {
//1.提供File对象,指明写出到的文件
File file = new File("hello1.txt");
//2.提供FileWriter对象,用于数据的写出,true表示在原有文件上添加
//false就是覆盖原文件
FileWriter fw = new FileWriter(file,true);
//3.写出的操作
fw.write("I have a dream!\n");
fw.write("You need to have a dream!");
//4.流的关闭
fw.close();
}
用FileReader和FileWriter实现文本复制
@Test
public void testFileReaderFileWriter(){
FileReader fr = null;
FileWriter fw = null;
try {
//1.创建File类对象
File srcFile = new File("Hello.txt");
File destFile = new File("hello2.txt");
//2.创建输入输出流对象
fr = new FileReader(srcFile);
fw = new FileWriter(destFile);
//3.数据的读入和写出工作
char[] cbuf = new char[5];
int len; //记录每次读入到cbuf数组中数据的长度
while ((len = fr.read(cbuf)) != -1){
fw.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭
//这里前面的try catch执行了以后后边的也会执行
try {
if(fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
用FileReader 和 FileWriter 不能实现图片复制
要用FileInputStream 和 FileOutputStream
FileInputStream和FileOutputStream
FileInputStream读取文本文件(文本文件应该用字符流来读)
文本文件(.txt.java.cpp.c) 非文本文件(.jpg,.PNG,.doc,.ppt)
@Test
public void testInputStream(){
FileInputStream fis = null;
try {
File file = new File("Hello.txt");
fis = new FileInputStream(file);
byte[] cubf = new byte[5];
int len;
while((len = fis.read(cubf)) != -1){
String str = new String(cubf,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileInputStream与FileOutputStream读写非文本文件
@Test
public void testFileInputOutputStream(){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File srcFile = new File("5.png");
File destFile = new File("51.png");
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
byte[] buffer = new byte[5];
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileInputStream 与 FileOutputStream文件复制操作写成方法
public void copyFile(String srcPath,String destPath){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File srcFile = new File(srcPath);
File destFile = new File(destPath);
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
byte[] buffer = new byte[5]; //读取视频一般用new byte[1024]
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void testCopyFile(){
long start = System.currentTimeMillis();
String srcPath = "5.png";
String destPath = "52.png";
copyFile(srcPath,destPath);
long end = System.currentTimeMillis();
System.out.println("复制操作花费的时间为"+(end - start));//毫秒
}
缓冲流
缓冲流是一种处理流
在节点流的基础上进行包装
节点流:FileReader FileWriter FileInputStream FileOutputStream
缓冲流是为了提高文件读写效率
缓冲流:BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
作用:提升流的读取和写入的效率
缓冲流实现非文本文件复制
@Test
public void BufferedStreamTest(){
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1,File对象的创建
File srcFile = new File("6.png");
File destFile = new File("6-1.png");
//2.造流
//2.1造两个节点流
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
//2.2造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.复制的细节,读取与写入的过程
byte[] buffer = new byte[10];
int len;
while((len = bis.read(buffer)) != -1){
bos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//4.资源关闭
//要求:先关闭外层的流,再关闭内层的流
//说明:关闭外层流的时候内层流也会进行关闭
// fos.close();
// fis.close();
}
缓冲流与节点流读写速度对比
提高读写速度的原因是因为内部提供了一个缓冲区
public void copyFileWithBuffered(String srcPath,String destPath){
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1,File对象的创建
File srcFile = new File(srcPath);
File destFile = new File(destPath);
//2.造流
//2.1造两个节点流
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
//2.2造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.复制的细节,读取与写入的过程
byte[] buffer = new byte[10];
int len;
while((len = bis.read(buffer)) != -1){
bos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//4.资源关闭
//要求:先关闭外层的流,再关闭内层的流
//说明:关闭外层流的时候内层流也会进行关闭
// fos.close();
// fis.close();
}
@Test
public void testCopyFileWithBuffered(){
long start = System.currentTimeMillis();
String srcPath = "6.png";
String destPath = "6-1.png";
copyFileWithBuffered(srcPath,destPath);
long end = System.currentTimeMillis();
System.out.println("复制操作花费的时间为"+(end - start));//毫秒
}
缓冲流练习
加密操作
byte[] buffer = new byte[20];
int len;
while((len = bis.read()) != -1){
for(int i = 0;i < len;i++){
byte[i] = (byte)(byte[i] ^ 5);
}
bos.write(buffer,0,len);
}
m ^n ^n ==m
解密操作:就是再做一遍上述代码就行了
转换流
转换流提供了在字节流与字符流之间的转换
Java API提供了两个转换流
InputStreamReader 将InputStream转换成Reader
OutputStreamWriter 将Writer 转换成OutputStream
字节流中的数据都是字符时,转换成字符流会更加高效
很多时候我们用转换流来处理文件乱码问题
转换流都是字符流,看后面,后面是Reader和Writer就都是字符流
解码:字节、字节数组–>字符数组,字符串
编码:字节、字节数组–>字符数组,字符串
@Test
public void test1(){
InputStreamReader isr = null;
try {
FileInputStream fis = new FileInputStream("dcbt.txt");
isr = new InputStreamReader(fis,"UTF-8");
char[] cubf = new char[20];
int len;
while((len = isr.read(cubf)) != -1){
String str = new String(cubf,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(isr != null){
try {
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
转换流实现文件的读入和写出
@Test
public void test2() {
InputStreamReader isr = null;
OutputStreamWriter osw = null;
try {
File file1 = new File("dcbt.txt");
File file2 = new File("dcbt_gbk.txt");
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
//以utf-8编码格式读入
isr = new InputStreamReader(fis,"utf-8");
//以gbk编码形式写出
osw = new OutputStreamWriter(fos,"gbk");
char[] cbuf = new char[20];
int len;
while((len = isr.read(cbuf)) != -1){
osw.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(isr != null){
try {
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(osw != null){
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
标准输入输出流
System.in :标准 输入流
System.out:标准输出流