该复习笔记是基于传智播客的Java基础视频-深入简出精华版,链接: https://pan.baidu.com/s/1bp7NuOJ,建议刚刚入门的小白不要看,因为涉及太多的细节了,看多了反而让你容易放弃Java之路,刚刚入门的小白推荐下面这一套视频-链接:https://pan.baidu.com/s/1pLuAj5x
博主声明一下:我不是传智播客的什么托,只是一个菜鸟,现在在补着Java基础,搞了一套传智播客的Java视频以及Android视频,所以笔记可能会常出现这些字眼,请言语讽刺我是托的麻烦你闭嘴哈
A:JVM默认是如何处理异常的
B:异常处理的两种方式
a:try…catch…finally
try:用来检测异常的
catch:用来捕获异常的
finally:释放资源
当通过trycatch将问题处理了,程序会继续执行
特别强调:JDK7处理多个异常
int a = 10;
int b = 0;
int[] arr = {11,22,33,44,55};
//JDK7如何处理多个异常
try {
System.out.println(a / b);
System.out.println(arr[10]);
} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
System.out.println("出错了");
} catch (Exception e) {
// TODO: handle exception
System.out.println("我都可以接收到你的错误");
}
A:编译期异常和运行期异常的区别
所有的RuntimeException类及其子类的实例被称为运行时异常,其他的异常就是编译时异常
编译时异常
A:面试题1
B:面试题2
public class Test1 {
public static void main(String[] args) {
Demo d = new Demo();
System.out.println(d.method());//30,最新解释:return语
//句在返回时候不是直接返回变量的值,而是复制一份,然后返回.在finally
//块中改变return的值对返回值没有任何影响,而对引用数据类型的数据会有影响
}
}
//return语句相当于是方法的最后一口气,那么在他将死之前会看一看有没有finally帮其完成遗愿,
//如果有就将finally执行后在彻底返回
class Demo {
public int method() {
int x = 10;
try {
x = 20;
System.out.println(1 / 0);
return x;
} catch (Exception e) {
x = 30;// 出现异常到这里
return x;// 这个x已经被装入返回的箱子了,接着在执行return的时候就去执行finally方法,
// 此时不是装入retrun语句箱子里面的x变为40,但装在x语句中的return的值依然为30,
// finally执行完毕之后,return就会完全执行,退出方法
} finally {
x = 40;
System.out.println("finally的x:" + x);//40
// 千万不要在finally里面写返回语句,因为finally的作用是为了释放资源,是肯定会执行的
// return x; // 如果在这里面写返回语句,那么try和catch的结果都会被改变,所以这么写就是犯罪
}
}
}
B:如何使用异常处理
区别:
如果JDK没有提供对应的异常,需要自定义异常。
//第2种构造方法
String parent = "F:\\双元课堂\\day19\\video";
String child = "001_今日内容.avi";
File file = new File(parent,child);
System.out.println(file.exists());
//第3种构造方法
File parent = new File("F:\\双元课堂\\day19\\video");
String child = "001_今日内容.avi";
File file = new File(parent, child);
System.out.println(file.exists());
System.out.println(parent.exists());
A:创建功能
B:重命名和删除功能
public boolean delete():删除文件或者文件夹
C:获取功能
D:判断功能
File file = new File("zzz");
//windows系统认为所有的文件都是可读的
file.setReadable(false);
System.out.println(file.canRead()); //true
//windows系统可以设置为不可写
file.setWritable(true);
System.out.println(file.canWrite()); //true
File file2 = new File("aaa.txt");//在系统中设置其为隐藏文件
//判断是否是隐藏文件
System.out.println(file2.isHidden());//true
System.out.println(file.isHidden());//false
思考题: read()方法读取的是一个字节,为什么返回是int,而不是byt
因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111
那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上
24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型
/**
* read()方法读取的是一个字节,为什么返回是int,而不是byte
*
* 文件存储的二进制形式:
* 00010100 00100100 01000001 11111111 0000000
*
* 假设是byte类型(占1个字节)读取,当到了11111111的时候是byte类型的-1,读取停止
* 10000001 byte类型-1的原码
* 11111110 -1的反码
* 11111111 -1的补码
*
* 假设是int类型读取,那么11111111就自动变成下面这个(int占4个字节)
* 00000000 00000000 00000000 11111111
*PS:上面文件存储的二进制都会自动转为int类型(以0补够)
*
* 放心,write会自动把前三补的0自动砍掉(到时我们写回去硬盘的时候)
* fos.write(97)虽然写出的是一个int数,但是到文件上的是一个字节,会自动去除前三个8位
*/
FileInputStream fis = new FileInputStream("致青春.mp3");
FileOutputStream fos = new FileOutputStream("copy.mp3");
byte[] arr = new byte[1024 * 8];
int len;
// 如果忘记加arr,返回的就不是读取的字节个数,而是字节的码表值
// fis.read(arr)返回的是读取的字节个数
// fis.read()返回的是字节的码表值
while ((len = fis.read(arr)) != -1) {
fos.write(arr, 0, len);////写出字节数组有效个数
}
fis.close();
fos.close();
// 创建输入流对象,关联致青春.mp3
FileInputStream fis = new FileInputStream("致青春.mp3");
// 创建输出流对象,关联copy.mp3
FileOutputStream fos = new FileOutputStream("copy.mp3");
// 创建缓冲区对象,对输入流进行包装让其变得更加强大
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int b;
//bis以及bos类内置byte buf[]=new byte[8192];
while ((b = bis.read()) != -1) {
bos.write(b);
}
bis.close();//关闭流释放资源
bos.close();//关闭流释放资源
思考题:小数组的读写和带Buffered的读取哪个更快?
1. 定义小数组如果是8192个字节大小和Buffered比较的话
2. 定义小数组会略胜一筹,因为读和写操作的是同一个数组,而Buffered操作的是两个数组
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("xxx.txt");
fos = new FileOutputStream("yyy.txt");
int b;
while((b = fis.read()) != -1) {
fos.write(b);
}
}finally {
//try fianlly的嵌套目的是能关一个尽量关一个
try{
if(fis != null)
fis.close();
}finally {
if(fos != null)
fos.close();
}
}
}
try(
FileInputStream fis = new FileInputStream("xxx.txt");
FileOutputStream fos = new FileOutputStream("yyy.txt");
){
int b;
while((b = fis.read()) != -1) {
fos.write(b);
}
//当执行完毕{}里面的代码,fis跟fos自动关闭(JDK1.7新特性之一)
//InputStream跟OutputStream都继承AutoCloseable接口
//写在()里面的代码都必须具备自动关闭功能,否则编译不可以通过
}
原理:在try()中创建的流对象必须实现了AutoCloseable这个接口,如果实现了,在try后面的{}(读写代码)执行后就会自动调用,流对象的close方法将流关掉
/**
* @param args
* @throws IOException
* 将写出的字节异或上一个数,这个数就是密钥,解密的时候再次异或就可以了
*/
public static void main(String[] args) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("copy.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy2.jpg"));
int b;
while((b = bis.read()) != -1) {
bos.write(b ^ 123);//^一个数字偶数次变回自己
}
bis.close();
bos.close();
}
2.在控制台录入文件的路径,将文件拷贝到当前项目下
/**
* 在控制台录入文件的路径,将文件拷贝到当前项目下
*
* 分析:
*
* 1,定义方法对键盘录入的路径进行判断,如果是文件就返回
* 2,在主方法中接收该文件
* 3,读和写该文件
* @throws IOException
*/
public static void main(String[] args) throws IOException {
File file = getFile(); //获取文件
//File file1 = new File("F:\\xin.mp3");这里的文件路径必须\\((否则编译不通过)),第一个\是转义的意思
//String path="F:\\xin.mp3";//这里必须是\\(否则编译不通过),第一个\是转义的意思
//File file2 = new File(path);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file.getName()));
int b;
while((b = bis.read()) != -1) {
bos.write(b);
}
bis.close();
bos.close();
}
/*
* 定义一个方法获取键盘录入的文件路径,并封装成File对象返回
* 1,返回值类型File
* 2,参数列表无
*/
public static File getFile() {
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个文件的路径:");
while(true) {
//接收键盘录入的路径,这个nextLine()对路径有优化的作用
//当你写\的时候,它会自动帮你转为\\,当你写\\的时候它就不处理了
String line = sc.nextLine();
//封装成File对象,并对其进行判断
File file = new File(line);
if(!file.exists()) {
System.out.println("您录入的文件路径不存在,请重新录入:");
}else if(file.isDirectory()) {
System.out.println("您录入的是文件夹路径,请重新录入:");
}else {
return file;
}
}
}
1.字符流是什么
2.FileWriter继承的Writer类中有一个2k的小缓冲区,如果不关流,就会将内容写到缓冲区里,关流会将缓冲区内容刷新,再关闭
BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("aaa.txt"));
String line;
while((line = br.readLine()) != null) {
bw.write(line);
//bw.newLine();//写出回车换行符,跨平台,无论lunix还是Windows系统
//bw.write("\r\n");//Windows系统可以识别,但lunix系统不识别
}
br.close();//流对象尽量晚开早关
bw.close();
LineNumberReader lnr = new LineNumberReader(new FileReader("zzz.txt"));
String line;
lnr.setLineNumber(100);//设置从100行开始
while((line = lnr.readLine()) != null) {
//lnr.readLine()使用一次,lineNumber变回自从加1,所以显示的时候是从101行开始的
System.out.println(lnr.getLineNumber() + ":" + line);
}
lnr.close();
}
装饰设计模式个人小理解:
* 当Student刚刚毕业走出社会的时候,只会Javase以及Javaweb,工资不高,接着黑马学校可以把你的技能进行升级,让你拥有数据库,大数据等更多的技能,工资便会更高
* HeiMaStudent为什么不直接继承Student重写方法呢?这样耦合性太高了,假如Student改一改,接着HeiMaStudent也要跟着改变
public class Demo6_Wrap {
/**
* @param args
* 装饰设计模式的好处是:
* 耦合性不强,被装饰的类的变化与装饰类的变化无关
*/
public static void main(String[] args) {
HeiMaStudent hms = new HeiMaStudent(new Student());
hms.code();
}
}
interface Coder {
public void code();
}
class Student implements Coder {
@Override
public void code() {
System.out.println("javase");
System.out.println("javaweb");
}
}
class HeiMaStudent implements Coder {
//1,获取被装饰类的引用
private Student s; //获取学生引用
//2,在构造方法中传入被装饰类的对象
public HeiMaStudent(Student s) {
this.s = s;
}
//3,对原有的功能进行升级
@Override
public void code() {
s.code();
System.out.println("ssh");
System.out.println("数据库");
System.out.println("大数据");
System.out.println("...");
}
}
其中:
FileInputStream跟FileOutputStream无论是构造方法还是方法里面都没有指定码表的办法,但FileOutputStream可以根据方法write的时候让字符转为其他码表,fos.write(“str”.getBytes(“utf-8”));
InputStreamReader isr = new InputStreamReader(
new FileInputStream("utf-8.txt"), "uTf-8"); //指定码表读字符
OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("gbk.txt"), "gbk"); //指定码表写字符
int c;
while((c = isr.read()) != -1) {
osw.write(c);
}
isr.close();
osw.close();
面试题:
当我们下载一个试用版软件,没有购买正版的时候,每执行一次就会提醒我们还有多少次使用机会用学过的IO流知识,模拟试用版软件,试用10次机会,执行一次就提示一次您还有几次机会,如果次数到了提示请购买正版
//1,创建带缓冲的输入流对象,因为要使用readLine方法,可以保证数据的原样性
BufferedReader br = new BufferedReader(new FileReader("config.txt"));//config.txt中只有10数字
//2,将读到的字符串转换为int数
String line = br.readLine();
int times = Integer.parseInt(line); //将数字字符串转换为数字
//3,对int数进行判断,如果大于0,就将其--写回去,如果不大于0,就提示请购买正版
if(times > 0) {
//4,在if判断中要将--的结果打印,并将结果通过输出流写到文件上
System.out.println("您还有" + times-- + "次机会");
FileWriter fw = new FileWriter("config.txt");
fw.write(times + "");
fw.close();
/*FileOutputStream fos = new FileOutputStream("config.txt");
fos.write((times + "").getBytes());
fos.close();*/
}else {
System.out.println("您的试用次数已到,请购买正版");
}
//关闭流
br.close();
上题不可以使用FileInputStream(字节流)或者FileReader(字符流)读config.txt文件的时候,输出的结果是49以及48(根据ASCII码表)
FileReader fr = new FileReader("config.txt");
//FileInputStream fis = new FileInputStream("config.txt");
int c;
//while ((c=fis.read())!=-1) {
while ((c=fr.read())!=-1) {
System.out.print(c+" ");//输出49 48
}
fr.close();
//fis.close();
使用递归求5的阶乘
public class Demo8_Digui {
/**
* @param args
* 递归:方法自己调用自己
* 5!
* 5 * 4 * 3 * 2 * 1
*
* 5 * fun(4)(代表4!)
* 4 * fun(3)(代表3!)
* 3 * fun(2)(代表2!)
* 2 * fun(1)(代表1!)
*/
public static void main(String[] args) {
System.out.println(fun(5));//120
}
public static int fun(int num) {
if(num == 1) {
return 1;
}else {
return num * fun(num - 1);
}
}
}
面试题:从键盘输入接收一个文件夹路径,打印出该文件夹下所有的.java文件名
public class Test5 {
/**
* 需求:从键盘输入接收一个文件夹路径,打印出该文件夹下所有的.java文件名
*
* 分析:
* 从键盘接收一个文件夹路径
* 1,如果录入的是不存在,给与提示
* 2,如果录入的是文件路径,给与提示
* 3,如果是文件夹路径,直接返回
*
* 打印出该文件夹下所有的.java文件名
* 1,获取到该文件夹路径下的所有的文件和文件夹,存储在File数组中
* 2,遍历数组,对每一个文件或文件夹做判断
* 3,如果是文件,并且后缀是.java的,就打印
* 4,如果是文件夹,就递归调用
*/
public static void main(String[] args) {
File dir = getDir();
printJavaFile(dir);
}
/*
* 获取键盘录入的文件夹路径
* 1,返回值类型File
* 2,不需要有参数
*/
public static File getDir() {
Scanner sc = new Scanner(System.in); //创建键盘录入对象
System.out.println("请输入一个文件夹路径");
while(true) {
String line = sc.nextLine(); //将键盘录入的文件夹路径存储
File dir = new File(line); //封装成File对象
if(!dir.exists()) {
System.out.println("您录入的文件夹路径不存在,请重新录入");
}else if(dir.isFile()) {
System.out.println("您录入的是文件路径,请重新录入文件夹路径");
}else {
return dir;
}
}
}
/*
* 获取文件夹路径下的所.java文件
* 1,返回值类型 void
* 2,参数列表File dir
*/
public static void printJavaFile(File dir) {
//1,获取到该文件夹路径下的所有的文件和文件夹,存储在File数组中
File[] subFiles = dir.listFiles();
//2,遍历数组,对每一个文件或文件夹做判断
for (File subFile : subFiles) {
//3,如果是文件,并且后缀是.java的,就打印
if(subFile.isFile() && subFile.getName().endsWith(".java")) {
System.out.println(subFile);
//4,如果是文件夹,就递归调用
}else if (subFile.isDirectory()){
printJavaFile(subFile);
}
}
}
}
FileInputStream fis1 = new FileInputStream("a.txt");
FileInputStream fis2 = new FileInputStream("b.txt");
FileInputStream fis3 = new FileInputStream("c.txt");
//将流对象存储进来
Vector v = new Vector<>();
//创建集合对象
v.add(fis1);
v.add(fis2);
v.add(fis3);
Enumeration en = v.elements();
//将枚举中的输入流整合成一个
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("d.txt");
int b;
while((b = sis.read()) != -1) {
fos.write(b);
}
sis.close();//sis在关闭的时候,会将构造方法中传入的流对象也都关闭
fos.close();
FileInputStream fis = new FileInputStream("yyy.txt");
//在内存中创建了可以增长的内存数组
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b;
while((b = fis.read()) != -1) {
baos.write(b); //将读取到的数据逐个写到内存中
}
//将缓冲区的数据全部获取出来,并赋值给arr数组
byte[] arr = baos.toByteArray();
System.out.println(new String(arr,"utf-16"));//可以指定编码码表来转换
//将缓冲区的内容转换为了字符串,在输出语句中可以省略调用toString方法
System.out.println(baos.toString());//通过平台默认的码表转为String类
fis.close();
//baos.close();//因为需要关闭的流在内存以及硬盘之间创建通道的,但baos没创建这个通道不需要关闭
面试题:定义一个文件输入流,调用read(byte[] b)方法,将a.txt文件中的内容打印出来(byte数组大小限制为5)
// 创建字节输入流,关联yyy.txt
FileInputStream fis = new FileInputStream("yyy.txt");
// 创建内存输出流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] arr = new byte[5]; // 创建字节数组,大小为5
int len;
// 将文件上的数据读到字节数组中
while ((len = fis.read(arr)) != -1) {
// 将字节数组的数据写到内存缓冲区中
baos.write(arr, 0, len);
}
// 将内存缓冲区的内容转换为字符串打印
System.out.println(baos);
fis.close();
// Person必须要要序列化才可以存储implements Serializable
Person p1 = new Person("张三", 23);//Person已经重写toString()方法
Person p2 = new Person("李四", 24);
Person p3 = new Person("王五", 25);
Person p4 = new Person("赵六", 26);
ArrayList list = new ArrayList<>();
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("e.txt"));
oos.writeObject(list);//把整个集合对象一次写出
oos.close();
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("e.txt"));
ArrayList list = (ArrayList)
ois.readObject();//将集合对象一次读取
for (Person person : list) {
System.out.println(person);
}
ois.close();
PrintStream ps = System.out;
ps.println(97); //其实底层用的是Integer.toString(x),将x转换为数字字符串打印
ps.println("xxx");
ps.println(new Person("张三", 23));
Person p = null;
ps.println(p);//如果是null,就返回null,如果不是null,就调用对象的toString()
PrintWriter pw = new PrintWriter(new FileOutputStream("g.txt"), true);
pw.write(97);
pw.print("大家好");
pw.println("你好"); //自动刷出,只针对的是println方法
pw.close();
//改变标准输入流
System.setIn(new FileInputStream("a.txt"));
//改变标注输出流
System.setOut(new PrintStream("b.txt"));
//获取标准的键盘输入流,默认指向键盘,改变后指向文件
InputStream is = System.in;
//获取标准输出流,默认指向的是控制台,改变后就指向文件
PrintStream ps = System.out;
int b;
while((b = is.read()) != -1) {
ps.write(b);
}
//System.out.println();//也是一个输出流,不用关,因为没有和硬盘上的文件产生关联的管道
is.close();//需要关闭的流是与硬盘上建立联系的流,因为不关会耗费内存
ps.close();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = br.readLine();
System.out.println(line);//br不用关闭,因为这个流现在没有操作文件
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
System.out.println(line);//sc不用关闭,因为它现在没有操作文件
在实际开发中,需要用到的话首推Scanner这种,因为它功能更为强大(String,int等),BufferedReader只有读字符串的方法
A:随机访问流概述
B:read(),write(),seek()
System.out.println("使用FileOutputStream字节输出流写会大的基本类型数据有问题:");
FileOutputStream fos = new FileOutputStream("h.txt");
//00000000 00000000 00000011 11100101 int类型997
//但写的之后自动砍掉前面的三个8位,导致写进去的是11100101
fos.write(997);//真正写进去的是其二进制的最后8位
fos.close();
System.out.println("使用DataOutputStream输出流来写:");
DataOutputStream dos = new DataOutputStream(
new FileOutputStream("h.txt"));
dos.writeInt(997);
dos.writeInt(998);
dos.writeInt(999);
dos.close();
System.out.println("使用DataInputStream输入流来写:");
FileInputStream fis = new FileInputStream("h.txt");
int x = fis.read();
int y = fis.read();
int z = fis.read();
System.out.println(x+" "+y+" "+z);
fis.close();
A:Properties的概述
B:Properties的特殊功能
Properties prop = new Properties();
prop.setProperty("name", "张三");
prop.setProperty("tel", "18912345678");
//System.out.println(prop);
//获得存储中的所有key值
Enumeration<String> en = (Enumeration<String>) prop.propertyNames();
while(en.hasMoreElements()) {
String key = en.nextElement(); //获取Properties中的每一个键
String value = prop.getProperty(key); //根据键获取值
System.out.println(key + "="+ value);
}
Properties prop = new Properties();
//将文件上的键值对读取到集合中
prop.load(new FileInputStream("config.properties"));
prop.setProperty("tel", "18912345678");
//第二个参数是对列表参数的描述,可以给值,也可以给null
prop.store(new FileOutputStream("config.properties"), null);
System.out.println(prop);//打印看看里面的配置信息
第二篇复习连接:
Java基础复习(二) - it菜鸟的飞行梦 - 博客频道 - CSDN.NET
第四篇复习连接:
Java基础复习(四) - it菜鸟的飞行梦 - 博客频道 - CSDN.NET