20175215 2018-2019-2 第六周java课程学习总结
第七章 内部类与异常类
1.内部类
- Java支持在一个类中定义另一个类,这样的类称作内部类,而包含内部类的类成为内部类的外嵌类
- 内部类和外嵌类之间重要关系如下
- 内部类的外嵌类的成员变量在内部类中仍然有效,内部类中的方法也可以调用外嵌类中的方法。
- 内部类的类体中不可以声明类变量和类方法。外嵌类的类体中可以用内部类声明对象,作为外嵌类的成员。
- 内部类仅供它的外嵌类使用,其他类不可以用某个类的内部类声明对象。
- 非内部类不可以是
static
类
2.匿名类
(1)和子类有关的匿名类
特点:
- 匿名类可以继承父类的方法也可以重写父类的方法。
- 使用匿名类时,必然是在某个类中直接用匿名类创建对象,因此匿名类一定是内部类。
- 匿名类可以访问外嵌类中的成员变量和方法,匿名类的类体中不可以声明
static
成员变量和static
方法。 - 由于匿名类是一个子类,但没有类名,所以在用匿名类创建对象时,要直接使用父类的构造方法。
(2)和接口有关的匿名类
- 如果某个方法的参数是接口类型,那么可以使用接口名和类体组合创建一个匿名对象传递给方法的参数,类体必须要重写接口中的全部方法。
- 例如,对于
void f(Computable x)
,其中参数x
是接口,那么在调用f
时,可以向f
的参数x
传递一个匿名对象,如:f(new Computable(){实现接口的匿名类的类体})
。
3.异常类
异常对象可以调用如下方法得到或输出有关异常的信息
public String getMessage();
public void printStackTrace();
public String toString();
(1)try-catch
语句
public class Example7_4 {
public static void main(String args[ ]) {
int n = 0,m = 0,t = 1000;
try{ m = Integer.parseInt("8888");
n = Integer.parseInt("ab89"); //发生异常,转向catch
t = 7777; //t没有机会被赋值
}
catch(NumberFormatException e) {
System.out.println("发生异常:"+e.getMessage());
}
System.out.println("n="+n+",m="+m+",t="+t);
try{ System.out.println("故意抛出I/O异常!");
throw new java.io.IOException("我是故意的");
//System.out.println("这个输出语句肯定没有机会执行,所以必须注释掉,否则编译出错");
}
catch(java.io.IOException e) {
System.out.println("发生异常:"+e.getMessage());
}
}
}
运行结果
带finally
子语句的try-catch
语句,语法格式如下:
try{}
catch{ExceptionSubClass e){}
finally{}
其执行机制是:在执行try-catch
语句后,执行finally
子语句,也就是说,无论在try
部分是否发生过异常,fianlly
子语句都会被执行
- 如果在
try-catch
雨中执行了return
语句,那么finally
子语句仍然会被执行。 try-catch
语句中执行了程序退出代码,即执行System.exit(0);
,则不执行finally
子语句(当然包括其后的所有语句)。
(2)自定义异常类
在编写程序时可以扩展Exception类定义自己的异常类,然后根据程序的需要来规定这些方法产生这样的异常。一个方法在声明时可以使用throws
关键字声明要产生的若干个异常,并在该方法的方法体中具体给出产生异常的操作,即用相应的异常类创建对象,并使用throw
关键字抛出该异常对象,导致该方法结束执行。程序必须在try-catch
块语句中调用可能发生异常的方法,其中catch
的作用就是捕获throw
关键字抛出的异常对象。
4.断言
(1)断言语句的语法格式
使用关键字assert
声明一条断言语句,断言语句有以下两种格式:
assert booleanExpression;
assert booleanExpression:messageException;
(2)启用与关闭断言语句
使用java -ea mainClass
启用断言语句(详细见下文)
第十章 输入、输出流
1.File类
创造一个File对象的构造方法有3个:
File(String filename);
File(String directoryPath , String filename);
File(File dir , String filename);
其中,filename
是文件名字,directoryPath
是文件的路径,dir
为一个目录。 使用File(String filename)
创建文件时,该文件被认为与当前应用程序在同一个目录中。
(1)文件的属性
public String getName()
获取文件的名字。public boolean canRead()
判断文件是否是可读的。public boolean canWrite()
判断文件是否可被写入。public boolean exits()
判断文件是否存在。public long length()
获取文件的长度(单位是字节)。public String getAbsolutePath()
获取文件的绝对路径。public String getParent()
获取文件的父目录。public boolean isFile()
判断文件是否是一个普通文件,而不是目录。public boolean isDirectroy()
判断文件是否是一个目录。public boolean isHidden()
判断文件是否是隐藏文件。public long lastModified()
获取文件最后修改的时间(时间是从1970年午夜至文件最后修改时刻的毫秒数)。
(2)目录
- 创建目录:File对象调用方法
public boolean mkdir()
创建一个目录,如果创建成功返回true
,否则返回false
(如果该目录已经存在将返回false
)。 - 列出目录中的文件
public String[] list()
用字符串形式返回目录下的全部文件。public File [] listFiles()
用File对象形式返回目录下的全部文件。public String[] list(FilenameFilter obj)
用字符串形式返回目录下的指定类型的所有文件。public File [] listFiles(FilenameFilter obj)
用File对象形式返回目录下的指定类型所有文件。
上述两方法的参数FilenameFilter是一个接口,该接口有一个方法:
public boolean accept(File dir,String name);
(3)文件的创建与删除
当使用File类创建一个文件对象后,例如
File file=new File("c:\\myletter","letter.txt");
如果c:\myletter目录中没有名字为letter.txt文件,文件对象file调用方法
public boolean createNewFile();
文件对象调用方法 public boolean delete()可以删除当前文件,例如:
file.delete();
(4)运行可执行文件
用Runtime 类声明一个对象( Runtime类在java.lang包)
Runtime ec;
然后使用该类的getRuntime()静态方法创建这个对象:ec=Runtime.getRuntime();
ec可以调用exec(String command)方法打开本地机的可执行文件或执行一个操作。
2.文件字节输入流
使用输入流通常包括4个基本步骤:
- 设定输入流的源
- 创建指向源的输入流
- 让输入流读取源中的数据
- 关闭输入流。
(1)构造方法
使用FileInputStream类的下列构造方法创建指向文件的输入流。
FileInputStream(String name);
FileInputStream(File file);
(2)使用输入流读取字节
int read()
读取单个字节的数据,返回字节值(0~255整数),如果未读出字节就返回-1。int read(byte b[])
读取b.length个字节到字节数组b中,返回实际读取的字节数。如果到达文件的末尾,则返回-1。int read(byte b[], int off, int len)
读取len个字节到字节数组b中,并返回实际读取的字节数目。如果到达文件的末尾,则返回-1,参数off指定从字节数组的某个位置开始存放读取的数据。
(3)关闭流
3.文件字节输出流
使用输出流通常包括4个基本步骤:
- 给出输出流的目的地
- 创建指向目的地的输出流
- 让输出流把数据写入到目的地
- 关闭输出流。
(1)构造方法
使用FileOutputStream
类的下列具有刷新功能的构造方法创建指向文件的输出流。
FileOutputStream(String name);
FileOutputStream(File file);
可以使用FileOutputStream
类的下列能选择是否具有刷新功能的构造方法创建指向文件的输出流
FileOutputStream(String name, boolean append);
FileOutputStream(File file, boolean append);
(2)使用输出流写字节
字节输出流的write方法以字节单位向目的地写数据。
void write(int n)
向目的地写入单个字节。void write(byte b[])
向目的地写入一个字节数组。void write(byte b[],int off,int len)
从字节数组中偏移量off处取len个字节写到目的地。void close()
关闭输出流
(3)关闭流
通过调用close()方法,可以保证操作系统把流缓冲区的内容写到它的目的地,即关闭输出流可以把该流所用的缓冲区的内容冲洗掉(通常冲洗到磁盘文件上)。
4.文件字符输入、输出流
- Reader类提供的read方法以字符为单位顺序地读取源中的数据。
int read():
int read(char b[]):
int read(char b[], int off, int len):
void close():
long skip(long numBytes):
- Writer流以字符为单位顺序地写文件,每次调用write方法就顺序地向目的地写入内容。 Writer类有如下常用的方法。
void write(int n): 向输出流写入一个字符。
void write(byte b[]): 向输出流写入一个字符数组。
void write(byte b[],int off,int length): 从给定字符数组中起始于偏移量off处取len个字符写到输出流。
void close(): 关闭输出流。
- 与FileInputStream、FileOutputStream字节流相对应的是FileReader、FileWriter字符流(文件字符输入、输出流),FileReader和FileWriter分别是Reader和Writer的子类,其构造方法分别是:
FileReader(String filename);
FileReader(File filename);
FileWriter(String filename);
FileWriter(File filename);
FileWriter(String filename, boolean append);
FileWriter(File filename, boolean append);
5.缓冲流
BufferedReader和BufferedWriter类创建的对象称作缓冲输入、输出流。二者的源和目的地必须是字符输入流和字符输出流。 构造方法:
BufferedReader(Reader in);
BufferedWriter (Writer out);
通过向BufferedReader传递一个Reader子类的对象(如FileReader的实例),来创建一个BufferedReader对象,如:
FileReader inOne = new FileReader("Student.txt");
BufferedReader inTwo = BufferedReader(inOne);
然后inTwo流调用readLine()
方法中读取Student.txt,例如:
String strLine = inTwo.readLine();
类似地,可以将BufferedWriter流和FileWriter流连接在一起,然后使用BufferedWriter流将数据写到目的地,例如
FileWriter tofile = new FileWriter("hello.txt");
BufferedWriter out = BufferedWriter(tofile);
然后out
使用BufferedReader类的方法write(String s , int off, int len)
把字符串s
写到hello.txt
中,参数off
是s
开始处的偏移量,len
是写入的字符数量。
另外,BufferedWriter流有一个独特的向文件写入一个回行符的方法:newLine();
6.随机流
使用RandomAccessFile类来创建一个随机访问文件流。RandomAccessFile类创建的流的指向既可以作为源也可以作为目的地。
构造方法:
RandomAccessFile(String name,String mode) ;
参数name
用来确定一个文件名,给出创建的流的源,也是流目的地。参数mode
取r(只读)或rw(可读写),决定创建的流对文件的访问权利。RandomAccessFile(File file,String mode) ;
参数file
是一个File对象,给出创建的流的源,也是流目的地。参数mode
取r(只读)或rw(可读写),决定创建的流对文件的访问权利。readLine()
方法在读取含有非ASCII字符的文件时出现“乱码”现象的解决方法:- 读取
String str=in.readLine();
- 用
iso-8859-1
重新编码byte b[]=str.getBytes("iso-8859-1");
- 使用当前机器的默认编码将字节数组转化为字符串
String content = new String(b);
- 如果机器的默认编码是“GB2312”,那么上一行代码等同于
String content = new String(b, "BG2312");
- 读取
7.数组流
(1)字节数组流
字节数组输入流ByteArrayInputStream和字节数组输出流ByteArrayOutputStream分别使用字节数组作为流的源和目标。
- ByteArrayInputStream构造方法及常用方法
ByteArrayInputStream(byte[] buf);
ByteArrayInputStream(byte[] buf,int offset,int length);
public int read();
顺序地从源中读出一个字节public int read(byte[] b,int off,int len);
顺序地从源中读出参数len指定的字节数
- ByteArrayOutputStream流构造方法及常用方法
ByteArrayOutputStream();
ByteArrayOutputStream(int size);
public void write(int b);
顺序地向缓冲区写入一个字节public void write(byte[] b,int off,int len);
将参数b中指定的len个字节顺序地写入缓冲区public byte[] toByteArray();
返回输出流写入到缓冲区的全部字节
(2)字符数组流
CharArrayReader和CharArrayWriter类是字符数组流,使用字符数组作为流的源和目标。
8.数据流
DataInputStream和DataOutputStream类创建的对象称为数据输入流和数据输出流。 构造方法:
DataInputStream(InputStream in)
创建的数据输入流指向一个由参数in指定的底层输入流DataOutputStream(OutnputStream out)
创建的数据输出流指向一个由参数out指定的底层输出流
9.对象流
ObjectInputStream和ObjectOutputStream类创建的对象称为对象输入流和对象输出流。 它的构造方法是:
ObjectInputStream(InputStream in)
ObjectOutputStream(OutputStream out)
- 相关方法:
writeObject(Object obj)
将一个对象obj写入到一个文件readObject()
读取一个对象到程序中
所谓序列化:一个类如果实现了Serializable接口,那么这个类创建的对象就是所谓序列化的对象。
10.序列化与对象克隆
如果一个“复制品”实体的变化不会引起原对象实体发生变化,反之亦然。这样的复制品称为原对象的一个克隆对象或简称克隆。
一个对象调用clone()
方法就可以获取该对象的克隆对象。
对象输入流通过对象的序列化信息来得到当前对象的一个克隆。
11.使用Scanner解析文件
使用Scanner类和正则表达式来解析文件。
- 使用默认分隔标记解析文件
- 创建Scanner对象,并指向要解析的文件,例如:
File file = new File("hello.java");
Scanner sc = new Scanner(file); //sc将空白作为分隔标记
- 相关方法
- next()依次返回file中的单词
- hasNext()判断file最后一个单词是否已被next()方法返回.
- 使用正则表达式作为分隔标记解析文件
- 创建Scanner对象,指向要解析的文件,并使用useDelimiter方法指定正则表达式作为分隔标记,例如:
File file = new File("hello.java");
Scanner sc = new Scanner(file);
sc.useDelimiter(正则表达式); //sc将正则表达式作为分隔标记
- 相关方法
- next() 依次返回file中的单词
- hasNext() 判断file最后一个单词是否已被next()方法返回
12.文件对话框
构造方法JFileChooser()创建初始不可见的有模式的文件对话框。然后文件对话框调用下述2个方法:
showSaveDialog(Component a);
showOpenDialog(Component a);
都可以使得对话框可见,只是呈现的外观有所不同,showSaveDialog
方法提供保存文件的界面,showOpenDialog
方法提供打开文件的界面。上述两个方法中的参数a指定对话框可见时的位置,当a
是null
时,文件对话框出现在屏幕的中央;如果组件a
不空,文件对话框在组件a
的正前面居中显示。
13.带进度条的输入流
如果读取文件时希望看见文件的读取进度可以使用javax.swing包提供的输入流类:ProgressMonitorInputStream
。
它的构造方法是:ProgressMonitorInputStream(Conmponent c,String s,InputStream);
14.文件锁
FileLock、FileChannel类处理Java提供的文件锁功能。它们分别在java.nio和java.nio.channels包中。
输入、输出流读写文件时可以使用文件锁。
RondomAccessFile创建的流在读写文件时使用文件锁的步骤如下:
- 先使用RondomAccessFile流建立指向文件的流对象,该对象的读写属性必须是rw,
例如:RandomAccessFile input=new RandomAccessFile("Example.java","rw");
- input流调用方法getChannel()获得一个连接到地层文件的FileChannel对象(信道),
例如:FileChannel channel=input.getChannel();
- 信道调用tryLock()或lock()方法获得一个FileLock(文件锁)对象,这一过程也称作对文件加锁.
例如:FileLock lock=channel.tryLock();
SP.第六周学习中碰到的问题
(1)IDEA中开启assert
断言
在使用Linux Bash或者cmd中运行程序时,通常可以使用java -ea mainClass
中的-ea
启用断言语句,但在IDEA中,没有这一个命令可以执行,因此,我们需要使用别的方法来启用断言语句
点击run按钮,如图所示
打开下图中的对话框后,在VM options中输入-ea
或者-enableassertions
就可以了
下面我们来调试一下教材P170的内容(Example7_6)
源代码如下:
import java.util.Scanner;
public class Example7_6 {
public static void main (String args[ ]) {
int [] score={-120,98,89,120,99};
int sum=0;
for(int number:score) {
assert number>0:"负数不能是成绩";
sum=sum+number;
}
System.out.println("总成绩:"+sum);
}
}
- 未启用
assert
断言语句的运行结果
- 启用
assert
断言语句的运行结果
(2)文件路径设置导致的问题
由于我在windows系统中进行java调试,使用IDEA调试的时候,工作路径不能很好的判断,我直接原封不动的使用了书上Example10_1的代码,导致程序运行结果如下图
文件不可读,长度为0,我寻找出问题症结所在,发现要把这段代码:File f = new File("C:\\ch10","Example10_1.java");
改为File f = new File("E:\\files of ding\\2019 java\\4.6\\src","Example10_1.java");
,就可显示出文件可读性和长度了,如下图
而相应的目录中也成功创建了new.txt
(3)部分程序代码的含义
inAndOut.seek(i*4);
:将随机访问文件定位到指定的位置,由于int为4字节,所以分别定位到0,4。然后读取数据
参考资料
1.Idea中开启assert断言