2018.4.21
单例
需求:
在整个程序的运行过程中,有且只能有一个当前类的类对象存在。
单例思想。
方案1:
在整个程序的运行过程中,有且只调用一个构造方法
问题:
你知道只能调用一次,但是别人知道吗?
这里除了自己,别人都不会这么认为,任何一个调用者都可以非常简单的
通过new 关键字,借助于当前类的构造方法,创建一个新的对象,违背当前情况
解决:
让类外无法轻松的调用和这个构造方法,私有化构造方法
问题:
私有化之后的构造方法,在类外无法使用,如何在类外创建对象或者说获取对象???
环境:
构造方法不能用
类外没有对象
所有和对象有关的方法的都不能使用。
现在能够使用的方法只能是静态(static)方法
方案:
借助于静态(static)方法获取或者创建类对象。
该方法要提供给类外使用所以权限修饰符为public
调用时不能通过对象来调用,用类名调用,使用static修饰
该方法是要获取当前类的类对象,所以返回值应该是当前类对象对象 SingleDemo
方法名字:[getInstance(int num)]
参数要和类内私有话的构造方法所需参数一致:int num;
问题:
南辕北辙,创建对象麻烦了,但是效果是一样的。
需求:
如果能判断当前程序当中有没有SingleDemo的类对象
如果没有,创建,调用私有化的构造方法
如果有,不创建。
需要一个变量来保存创建对象的地址
变量数据类型SingleDemo
位置:
假设:
1.用局部变量保存地址。
不行。 每一个调用时,之前的局部变量已经被销毁了。
2.用成员变量。
不行。静态方法中不能使用非静态的成员变量。
3.用静态成员变量
解决:
用静态成员变量来保存之前创建的对象地址
问题:
发现类外可以直接 通过类名来修改静态成员变量的数据
解决:
private修饰
class SingleDemo {
int num;
private static SingleDemo s = null;
private SingleDemo(int num) {
this.num = num;
}
public void test() {
System.out.println(this.getClass()+"的test方法");
}
public static SingleDemo getInstance(int num) {
//私有话的构造方法可以在类内使用
if(s == null) {
s = new SingleDemo(num);
}
return s;
}
}
public class Demo1 {
public static void main(String[] args) {
//解决方案1
//SingleDemo singleDemo = new SingleDemo();
SingleDemo s1 = SingleDemo.getInstance(5);
System.out.println(s1);
// SingleDemo s = null;
SingleDemo s2 = SingleDemo.getInstance(19);
System.out.println(s2);
}
}
结果:
com.bitware.single.SingleDemo@5ecb5608
com.bitware.single.SingleDemo@5ecb5608
两个类对象是同一个。
IO流
Input Output
IO流的参照物:
当前运行成语:
从硬盘中读取数据到内存中使用: input
从程序的内存中将数据保存到硬盘中: output
pipe 管道文件
socket 套接字
按照处理的数据单位来做划分:
字节流:
完全按照二进制编码格式,一个字节一个字节获取 -------迅雷下载
字符流:
其实也是字节操作,但是会考虑当前系统的编码问题
会将读取的字节数据,根据当前使用的字符集进行翻译
GBK GB2312 BIG5(繁体 台湾香港) UTF8(国际编码)
字符流 = 字节流 + 解码
输入流和输出流
字节流和字符流
InputStream
FileinputStream
OutputStream
FileOutpuStream
Reader
FileReader
Writer
FilrWriter
1.使用缓冲区效率更高,原因是解决了内存访问硬盘的次数过多,导致的时间上的浪费。
通常缓冲流使用的缓冲空间一般都是4KB或者8KB
2.FileWriter 不是直接把数据写入到磁盘,而是在内存中建立了一个缓冲区用于保存
用户想要写入到硬盘的数据,有三种情况才会真正的写入数据到硬盘:
1>缓冲区满了
2>调用了flush方法,清空缓冲区
3>FileWriter输出管道关闭。
3.字节流和字符流选择
字节流基本上可以满足所有的文件内容传输需求
字符流,只用来处理记事本可以打开的可视化文件
输入字节流 FileInputStream
字节流:
输入字节流 input 从硬盘到内存的流向,读取数据操作
---| InputStream 所有字节流的基类/父类 抽象类(没有类对象,有些方法没有方法体)
------| FileInputStream 读取文件的输入字节流
获取文件的操作步骤:
1.找到文件
是否是一个普通文件
是否存在
String字符串路径
2.创建FileInputStream 输入管道 resource 资源
3.读取文件
4.关闭管道(资源)
输出字节流 FileOutputStream
写入文件的操作流程:
1.找到要操作的文件(可以存在,也可以不存在,但是要操作的文件必须有后缀名。)
2.创建输出管道
3.写入数据
4.关闭资源
---| OutPut 所有输出字节流的基类,父类,抽象类。
------| FileOutputStream 文件输出字节流
FileOutputStream注意事项:
1.使用OutputStream写入数据到文件中,该文件可以存在可以不存在,FileOutputStream是拥有创建文件的能力
2.默认情况下,FileOutputStream采用的是覆盖写入数据的方式,如果想要使用追加写
使用FileOutputStream(File file, boolean append),boolean决定是否添加追加写。
3.小写字母a,ascii码为97
0110 0001
写入的数据是353
0000 0000 0000 0000 0000 0001 0110 0001
写入的结果都是小写字母a
因为FileOutputStream调用write(int b)方法,写入的数据其实是整个int数据
内部二进制的低8位,高24位对于write方法来说是无效数据。
汉字无法输入:
因为一个汉字在GBK编码下占用的是2个字节,
在UTF8编码下占用的是3个字节。
public class demo2 {
public static void main(String[] args) throws IOException {
output();
input();
}
public static void output() throws IOException {
//创建文件也要抛出异常 因为可能没有创建权限。
//1.赋给file2要写入的文件路径
File file = new File("C:/aaa/6.txt");
//2.判断文件是否存在 是否是一个普通文件
if(!file.exists()||!file.isFile()) {
throw new FileNotFoundException();
}
//3.创建字节流输出管道,默认覆盖写入 如果要使用追加写,考虑需要使用FileOutputStream(File file ,boolean append)
FileOutputStream fos = new FileOutputStream(file,true);
//3.写入数据
// write方法只能写入Ascii码值或者byte [] 数组一个字节 所以要将字符串转换成数组再写入。
// fileOutputStream.write('H');
// fileOutputStream.write('e');
// fileOutputStream.write('l');
// fileOutputStream.write('l');
// fileOutputStream.write('v');
// fileOutputStream.write('b');
// fileOutputStream.write(97); ASCII码 并不能直接写入数字
//定义一个要写入的字符串。
String str = "我喜欢你啊";
//把字符串转换成Byte[] 数组
byte[] buffer = str.getBytes();//返回值为一个Byte数组
fos.write(buffer);
//4.关闭资源
fos.close();
}
public static void input() throws IOException {
//1.赋给file2要读取的文件路径
File file2 = new File("C:/aaa/6.txt");
//2.判断文件是否存在 是否是一个普通文件
if(!file2.exists()||!file2.isFile()) {
throw new FileNotFoundException();
}
//3.创建字节流输入管道
FileInputStream fis = new FileInputStream(file2);
//4.准备缓冲区读取文件
int length = -1;
byte[] buffer1 = new byte[1024];//存储的缓冲区字节个数
//按照read()内规定的数据个数来读取管道所拥有的路径指向的文件数据。
while((length = fis.read(buffer1)) != -1) {
System.out.println(new String(buffer1));
}
//4.关闭管道资源
fis.close();
}
}
字节流拷贝图片实例
public class CopyImage {
public static void main(String[] args) throws IOException {
//1.找到源文件
File srcFile = new File("C:\\Users\\bitware13\\Desktop\\1.jpg");
//判断源文件是否存在,是否是一个普通文件
if(!srcFile.exists()||!srcFile.isFile()) {
throw new FileNotFoundException();
}
//2.确定要拷贝的地址
File dstFile = new File("C:\\Users\\bitware13\\Desktop\\2.jpg");
//3.打开input和output通道
FileInputStream fileInputStream = new FileInputStream(srcFile);
FileOutputStream fileOutputStream =new FileOutputStream(dstFile);
//4.利用缓冲从硬盘上读取数据
int length = -1;//读取到的字节个数
byte[] buffer = new byte[1024*4];//缓冲区4Kb/8Kb左右符合我们硬盘的扇区
while ((length = fileInputStream.read(buffer)) != -1) {//把数组中内容写进去
//fileOutputStream.write(buffer);会有可能导致复制之后的文件会变大。原因是从硬盘读取数据
//时,最后一次有可能无法填充满整个缓冲区,但是写入时没有判断缓冲区里面的数据是不是都是图片数据。
fileOutputStream.write(buffer, 0, length);
}
//5.关闭资源,先开后关,后开先关。
fileOutputStream.close();
fileInputStream.close();
}
}
输入字符流 FileReader
Io input Output
字节流:
InputStream
FileInputStream
OutputStream
FileOutputStream
字符流:
字符流 = 字节流 + 解码
字符流读取数据,输入字符流
---| Reader 输入字符流的基类/超类 抽象类。
-----| FileReader 读取文件的输入字符流
使用方式:
1.找到文件
判断文件是否存在,是否是一个普通文件
2.建立FileReader读取通道
3.读取数据
4.关闭资源
public class Demo1 {
public static void main(String[] args) throws IOException {
//readerTest1();
readerTest2();
}
public static void readerTest2() throws IOException {
//1.找到文件
File file = new File("C:\\aaa\\2.txt");
//判断文件是否存,是否是个文件
if(!file.exists() || !file.isFile()) {
throw new FileNotFoundException();
}
//2.建立FileReader 输入字符流管道
FileReader fReader = new FileReader(file);
//3.建立缓冲区,利用缓冲区读取数据,创建字符数组
int length = -1;//用于保存读取到的字符个数
char[] buffer = new char[1024];
while((length = fReader.read(buffer)) != -1) {
System.out.println(new String(buffer));
}
//4.关闭资源
fReader.close();
}
}
/*
输出字节流 FileWriter
输出字符流:
---| Writer 输出字符流的基类/父类 抽象类
------| FileWriter 文件操作的输出字符流
操作流程:
1.找到目标文件’
2.建立输出管道
3.写入数据】
4.关闭资源
[发现]
1.如果写入的数据不多,程序如果中止,在目标文件中没有任何的数据,但是程序继续运行,
数据会写入到文件中
2.如果写入的数据很大,程序如果中止 ,可能会在目标文件中写入一部分数据,当程序继续运行
之后的数据也会写入到文件中。
java字符流的一个特征:
目的是减少对于磁盘的写入操作,写入数据到硬盘是对硬盘有一定损耗的,所以JAVA中就使用了一种缓冲机制
当调用FileWrtier的writer方法,并不是直接写入数据到硬盘,而是现行保存在FileWriter类对象
里面的缓冲区中,在这个缓冲区是一个【字符】数组,这个数组默认的元素格式【1024个字符】
有三种情况,可以直接把数据写入到文件中:
1.关闭FileWriter资源
2.缓冲区满了,会直接清空缓冲区,把数据写入到硬盘众
3.调用flash方法,立即清空缓冲区,直接写入数据到硬盘。
注意事项:
FileWriter在操作文件时,如果文件不存在,畏怯文件夹权限允许,可以直接创建文件,
如果想要追加写,调用
FileWriter(File file ,boolean append);
public class Demo1 {
public static void main(String[] args) throws IOException {
writerTest();
}
public static void writerTest() throws IOException {
//1.找到或创建一个要写入数据的文件
File file = new File("C:/aaa/writerTest.txt");
//2.建立管道
FileWriter fWriter = new FileWriter(file);
//3.准备要写入的数据
fWriter.write(new String("今天清明节很难受兄弟"+"今天清明节很难兄弟" ));
//4.关闭资源
fWriter.close();
}
}
字符流拷贝图片弊端
每一次复制之后的文件都是缺少固定的字符个数
是因为使用字符流读取数据时,数据会进行一个解码的过程,根据当前系统规定默认字符集你隐形编码
而在解码的过程中,如果解码的数据不能和当前字符集里面的数据进行匹配,那么对于字符流来说
这是一个无效数据,会被扔掉,这就是为什么复制图片无法成功,一致缺少数据。
** 字节流基本上可以用在所有的文件操作中,字符流只能用到TXT文本可以打开的可视化文件中。**
public class copyImage {
public static void main(String[] args) throws IOException {
//1.找到源文件
File srcFile = new File("C:\\Users\\bitware13\\Desktop\\2.jpg");
if(!srcFile.exists() || !srcFile.isFile()) {
throw new FileNotFoundException();
}
//2.确定目标文件
File dstFile = new File("C:\\Users\\bitware13\\Desktop\\3.jpg");
//3.打开读取和写入通道
FileReader fileReader = new FileReader(srcFile);
FileWriter fileWriter = new FileWriter(dstFile);
//4.准备字符缓冲区
int length = -1;
char[] buffer = new char[1024];
while((length = fileReader.read(buffer)) != -1) {
fileWriter.write(buffer);
}
//5.关闭资源
fileWriter.close();
fileReader.close();
}
}