理想的书籍是智慧的钥匙。——列夫·托尔斯泰
非常棒的学习网站:How2J
一、File文件对象
文件和文件夹都是用File代表
绝对路径:从磁盘读取的路径或者网站目录的路径
相对路径:指目标相对于当前文件的路径
实践代码,搓搓小手动起来(=!=):
一些File类常用的方法:
//文件对象
import java.io.File;
import java.io.IOException;
import java.util.Date;
/*
文件和文件夹都是用File代表
绝对路径:从磁盘读取的路径或者网站目录的路径
相对路径:指目标相对于当前文件的路径
*/
public class FileDemo {
public static void main(String[] args) throws IOException {
//使用绝对路径或者相对路径创建File对象
//绝对路径
File f1 = new File("D:/JavaTest");
System.out.println("f1的绝对路径:" + f1.getAbsolutePath());
//相对路径,这里相对于项目目录
File f2 = new File("hello.tex");
System.out.println("f2的绝对路径:" + f2.getAbsolutePath());
//把f1作为父目录创建文件对象
File f3 = new File(f1,"text1.tex");
System.out.println("f3的绝对路径:" + f1.getAbsolutePath());
//文件常用方法
String path = new String("D:/JavaTest/java/hello");
File f4 = new File(path);
//创建文件夹,如果父文件夹不存在,也会创建父文件夹
f4.mkdirs();
//创建一个空文件,如果父文件夹不存在,就会抛出异常
File f5 = new File(f4,"text.txt");
f5.createNewFile();
//判断文件是否存在
System.out.println("判断是否存在:"+f4.exists());
System.out.println("判断是否存在:"+f5.exists());
//是否是文件夹
System.out.println("判断是否是文件夹:"+f4.isDirectory());
System.out.println("判断是否是文件夹:"+f5.isDirectory());
//是否是文件(非文件夹)
System.out.println("判断是否是文件:"+f4.isFile());
System.out.println("判断是否是文件:"+f5.isFile());
//文件长度
System.out.println("获取文件的长度:"+f4.length());
//文件最后修改时间
long time = f4.lastModified();
Date d = new Date(time);
System.out.println("获取文件的最后修改时间:"+d);
//设置文件修改时间为1970.1.1 08:00:00
f4.setLastModified(0);
//文件重命名
File f6 =new File("D:/JavaTest/java/hello/1.txt");
f5.renameTo(f6);
// 以字符串数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
f4.list();
// 以文件数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
File[]fs= f5.listFiles();
// 以字符串形式返回获取所在文件夹
System.out.println("f5所在文件夹:" + f5.getParent());
// 以文件形式返回获取所在文件夹
f5.getParentFile();
// 列出所有的盘符c: d: e: 等等
f5.listRoots();
// 刪除文件
f5.delete();
// JVM结束的时候,刪除文件,常用于临时文件的删除
f5.deleteOnExit();
}
}
2道题目:
import java.io.File;
public class FileTest {
/*
一般说来操作系统都会安装在C盘,所以会有一个 C:\WINDOWS目录。
遍历这个目录下所有的文件(不用遍历子目录)
找出这些文件里,最大的和最小(非0)的那个文件,打印出他们的文件名
*/
static long min = Long.MAX_VALUE;
static long max = 0;
static String fileMax = "";
static String fileMin = "";
public static void main(String[] args) {
//实现第一题
System.out.println("第一题:");
File f = new File("C:/WINDOWS");
fileMaxMin(f);
//实现第二题
System.out.println("第二题:");
chirdFileMaxMin(f.listFiles());
System.out.println("最小文件是:"+fileMin+",其大小是"+min+"字节");
System.out.println("最大文件是:"+fileMax+",其大小是"+max+"字节");
}
//第一题的方法
public static void fileMaxMin(File f){
File[] fs = f.listFiles();
for (File ff:fs) {
if (ff.isFile()) {//路径名表示的文件是否是一个标准文件
//if (ff.length()==0) continue;//continue结束本次循环,继续下次循环
if (ff.length()>max) {
max=ff.length();
fileMax = ff.toString();
}
else if (ff.length()>0 && ff.length()<min) {
min=ff.length();
fileMin = ff.toString();
}
}
}
System.out.println("最小文件是:"+fileMin+",其大小是"+min+"字节");
System.out.println("最大文件是:"+fileMax+",其大小是"+max+"字节");
}
//第二题的方法
public static void chirdFileMaxMin(File[] fs){
if(fs != null){
for (File ff:fs) {
if (ff.isDirectory()) {//是否文件夹
chirdFileMaxMin(ff.listFiles());//是文件夹,就继续遍历
}
else if (ff.length()>max) {
max=ff.length();
fileMax = ff.toString();
}else if (ff.length()>0 && ff.length()<min) {
min=ff.length();
fileMin = ff.toString();
}
}
}
}
}
二、字节流
什么是流(Stream),流就是一系列的数据
输入流表示从一个源读取数据,输出流表示向一个目标写数据。
字节输入流: InputStream
字节输出流:OutputStream
用于以字节的形式读取和写入数据
InputStream是字节输入流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileInputStream 是InputStream子类,用于从文件读取数据
OutputStream是字节输出流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileOutputStream 是OutputStream子类,用于向文件输入数据
实践代码,搓搓小手动起来(=!=):
import java.io.*;
//建立了一个文件输入流,这个流可以用来把数据从硬盘的文件,读取到JVM(内存)
public class StreamClass {
public static void main(String[] args) throws IOException {
File f = new File("D:/JavaTest/java/hello/1.txt");
//读取文件数据
// 通过这个输入流,就可以把数据从硬盘,读取到Java的虚拟机中来,也就是读取到内存中
FileInputStream fis = new FileInputStream(f);
//创建字节数组,其长度就是文件的长度
byte[] all =new byte[(int) f.length()];
//以字节流的形式读取文件所有内容
fis.read(all);
for (byte b : all) {
System.out.println(b);
}
//每次使用完流,都应该进行关闭
fis.close();
//把数据输入文件,2.txt还没被创建
byte data[] = { 88, 89};//被输入的数据
// 创建基于文件的输出流
File f1 = new File("D:/JavaTest/java/hello/java/2.txt");
File f2 = f1.getParentFile();
if(f2.exists()){//文件夹路径是否存在
//f1.createNewFile();
FileOutputStream fos = new FileOutputStream(f1);
// 把数据写入到输出流
fos.write(data);
// 关闭输出流
fos.close();
System.out.println("完成写入数据");
}else {
f2.mkdirs();
//f1.createNewFile();
FileOutputStream fos = new FileOutputStream(f1);
fos.write(data);
fos.close();
System.out.println("完成写入数据");
}
}
}
package priv.study.io;
/*
第一题:拆分文件
找到一个大于100k的文件,按照200k为单位,拆分成多个子文件,并且以编号作为文件名结束。
比如文件 yyyy.exe,大小是753k。
拆分之后,成为
eclipse.exe-0
eclipse.exe-1
eclipse.exe-2
eclipse.exe-3
第二题:合并文件
把上述拆分出来的文件,合并成一个原文件。
*/
import java.io.*;
public class StreamTest {
public static void main(String[] args) throws IOException {
String path = "D:/JavaTest/java/hello/3.ppt";
//实现第一题
split(path);
System.out.println(split(path));
//实现第二题
//merge(path);
//System.out.println(merge(path));
}
//拆分方法
/*
思路:
1.判断是否存在
2.获取文件大小,打算拆分为几段(这里200K一段)
3.读取这个文件数据
4.循环写入拆分的子文件
*/
public static Boolean split(String path) {
File f = new File(path);
//文件是否存在
if (f.exists()) {
int longf = (int) f.length();//文件长度
int num = 0;
int duan = 200*1024;
//分段,200K一段
if (longf % duan == 0) {
num = (int) longf / duan;
} else {
num = (int) (longf / duan)+1;
}
byte[] all = new byte[longf];
//把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
//读取文件
try(FileInputStream fis = new FileInputStream(f)){
fis.read(all);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//写入子文件
for (int i = 0; i < num; i++) {
File fs = new File(path + "-" + i);
//把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
try(FileOutputStream fos = new FileOutputStream(fs)){
if (i < num - 1) {
fos.write(all, duan * i, duan);//从duan*i起,偏移量为duan
System.out.println("子文件" + (i + 1) + ":" + path + "-" + i + ",其大小为" + longf + "字节");
}
if (i == num - 1) {
fos.write(all, duan * i, longf % duan);
System.out.println("子文件" + (i + 1) + ":" + path + "-" + i + ",其大小为" + longf % duan + "字节");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
System.out.println("文件不存在");
}
return true;
}
//合并方法
/*
原文件存在先删除
循环读取并写入新的文件
*/
public static Boolean merge(String path) {
File f = new File(path);
if (f.exists()) {
f.delete();
}
byte[] all=null;
for (int i=0;i<6;i++) {
File newFile = new File(path+"-"+i);
//把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
try (FileInputStream fis= new FileInputStream(newFile)){
all = new byte[(int)newFile.length()];
fis.read(all);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
try(FileOutputStream fos =new FileOutputStream(f,true)) {
//true:不覆盖写入
fos.write(all);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
}
三、关闭流的方式
所有的流,无论是输入流还是输出流,使用完毕之后,都应该关闭。
如果不关闭,会产生对资源占用的浪费。 当量比较大的时候,会影响到业务的正常开展。
-
在try中关闭:
在try的作用域里关闭文件输入流。
弊端:如果文件不存在,或者读取的时候出现问题而抛出异常,
那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。
不推荐使用 -
在finally中关闭:
这是标准的关闭流的方式
1. 首先把流的引用声明在try的外面,如果声明在try里面,其作用域无法抵达finally.
2. 在finally关闭之前,要先判断该引用是否为空
3. 关闭的时候,需要再一次进行try catch处理 -
在try()关闭:
把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术
所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。
并且在try, catch, finally结束的时候自动关闭,回收相关资源。
四、字符流
Reader字符输入流
Writer字符输出流
专门用于字符的形式读取和写入数据
FileReader 是Reader子类
FileWriter 是Writer子类
实践代码,搓搓小手动起来(=!=):
package priv.study.io;
import java.io.*;
public class ReaderWriter {
public static void main(String[] args) {
//读取文件字符数据
//FileReader 是Reader子类
//2.txt文件里字符是XY,如果字节流读取就是相应的ASCII码88,89
//如果字符流读取就是字符XY本身
File f = new File("D:/JavaTest/java/hello/java/2.txt");
char[] all = new char[(int) f.length()];
try (FileReader fr = new FileReader(f)){
// 创建字符数组,其长度就是文件的长度
fr.read(all);
for (char b : all) {
// 打印出来是XY
System.out.println(b);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//使用字符流把字符串写入到文件
try (FileWriter fw = new FileWriter(f)) {
String a = "zxcvbnasdfg";
char[] c = a.toCharArray();
fw.write(c);
for (char cc : c) {
System.out.println(cc);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
五、缓存流
以介质是硬盘为例,字节流和字符流的弊端:
在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。
为了解决以上弊端,采用缓存流。
缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,
直到缓存中的数据读取完毕,再到硬盘中读取。
就好比吃饭,不用缓存就是每吃一口都到锅里去铲。用缓存就是先把饭盛到碗里,碗里的吃完了,再到锅里去铲
缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,
一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,
从而减少了IO操作
使用缓存流读取数据:
缓存字符输入流 BufferedReader 可以一次读取一行数据
PrintWriter 缓存字符输出流, 可以一次写出一行数据
有的时候,需要立即把数据写入到硬盘,而不是等缓存满了才写出去。 这时候就需要用到flush
实践代码,搓搓小手动起来(=!=):
package priv.study.io;
import java.io.*;
import java.util.ArrayList;
public class BufferedReadWrite {
public static void main(String[] args) {
String path = new String("D:/JavaTest/java/hello/java/3.txt");
File f = new File(path);
//BufferedReaderClass(f);
//PrintWriterClass(f);
//FlushClass(f);
String path1 = new String("D:/JavaTest/java/hello/java/4.txt");
File f1 = new File(path1);
RemoveZhuShi(f1);
}
//使用缓存流读取数据BufferedReader
public static boolean BufferedReaderClass(File f){
// 创建文件字符流
// 缓存流必须建立在一个存在的流的基础上
try (FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);)
{
while (true) {
// 一次读一行
String line = br.readLine();
if (null == line)
break;//结束,并跳出循环
System.out.println(line);
}
} catch (IOException ex) {
ex.printStackTrace();
}
return true;
}
//PrintWriter 缓存字符输出流
public static boolean PrintWriterClass(File f){
try(FileWriter fw = new FileWriter(f);//有true不会覆盖原内容,反之覆盖
PrintWriter pw = new PrintWriter(fw);
){
String s1="123";
String s2="456";
String s3="789";
pw.println(s1);
pw.println(s2);
pw.println(s3);
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
//有的时候,需要立即把数据写入到硬盘,而不是等缓存满了才写出去。 这时候就需要用到flush
public static boolean FlushClass(File f){
try(FileWriter fw = new FileWriter(f,true);//有true不会覆盖原内容,反之覆盖
PrintWriter pw = new PrintWriter(fw);
){
String s1="flush";
String s2="flush";
String s3="flush";
pw.println(s1);
//强制把缓存中的数据写入硬盘,无论缓存是否已满
pw.flush();
pw.println(s2);
pw.flush();
pw.println(s3);
pw.flush();
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
//设计一个方法,用于移除Java文件中的注释
//移出以//开头的注释行
//如果注释在后面,或者是/**/风格的注释,暂不用处理
/*
思路:判断读取的每一行(去空白)开头是否是“//”,否:就add进ArrayList中,再遍历写入
*/
public static boolean RemoveZhuShi(File f){
// 创建文件字符流
// 缓存流必须建立在一个存在的流的基础上
ArrayList<String> list = new ArrayList<String>();//也可以用StreamBuffer动态字符串append()逐一加上去,当然要分行-
try (FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
FileWriter fw = new FileWriter(f);
PrintWriter pw = new PrintWriter(fw);
)
{
while (true) {
// 一次读一行
String line = br.readLine();
if (null == line)
break;//结束,并跳出循环
//startsWith()如果字符串以指定的前缀开始,则返回 true;否则返回 false。
//trim() 方法用于删除字符串的头尾空白符
if(!line.trim().startsWith("//")){
list.add(line);
// System.out.println(line);
}else {
System.out.println("注释的语句:"+line.trim());
}
}
for (String l:list
) {
pw.println(l);
System.out.println("写入的语句:"+l.trim());
pw.flush();
}
} catch (IOException ex) {
ex.printStackTrace();
}
return true;
}
}
六、数据流
DataInputStream 数据输入流
DataOutputStream 数据输出流
使用数据流的writeUTF()和readUTF() 可以进行数据的格式化顺序读写
通过DataOutputStream 向文件顺序写出 布尔值,整数和字符串等等,然后再通过DataInputStream 顺序读入这些数据。
注: 要用DataInputStream 读取一个文件,这个文件必须是由DataOutputStream 写出的,否则会出现EOFException,
因为DataOutputStream 在写出的时候会做一些特殊标记,只有DataInputStream 才能成功的读取。
实践代码,搓搓小手动起来(=!=):
package priv.study.io;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataStream {
public static void main(String[] args) {
//直接进行字符串的读写
write();
read();
}
private static void read() {
File f =new File("D:/JavaTest/java/hello/java/5.txt");
try (
FileInputStream fis = new FileInputStream(f);
DataInputStream dis =new DataInputStream(fis);
){
boolean b= dis.readBoolean();
int i = dis.readInt();
String str = dis.readUTF();
System.out.println("读取到布尔值:"+b);
System.out.println("读取到整数:"+i);
System.out.println("读取到字符串:"+str);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void write() {
File f =new File("D:/JavaTest/java/hello/java/5.txt");
try (
FileOutputStream fos = new FileOutputStream(f);
DataOutputStream dos =new DataOutputStream(fos);
){
dos.writeBoolean(true);
dos.writeInt(100);
dos.writeUTF("hello hello hello");
} catch (IOException e) {
e.printStackTrace();
}
}
}
七、对象流
对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘
一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现Serializable接口
实践代码,搓搓小手动起来(=!=):
import java.io.Serializable;
public class Hero implements Serializable {
//表示这个类当前的版本,如果有了变化,比如新设计了属性,就应该修改这个版本号
private static final long serialVersionUID = 1L;
public String name;
public float hp;
}
package priv.study.io;
import java.io.*;
//序列化对象
/*
创建一个Hero对象,设置其名称为garen。
把该对象序列化到一个文件garen.lol。
然后再通过序列化把该文件转换为一个Hero对象
*/
public class ObjectStream {
public static void main(String[] args) {
//创建一个Hero garen
//要把Hero对象直接保存在文件上,务必让Hero类实现Serializable接口
Hero h = new Hero();
h.name = "garen";
h.hp = 600;
//准备一个文件用于保存该对象
File f =new File("d:/garen.lol");
//创建对象输出流
try(FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos =new ObjectOutputStream(fos);
//创建对象输入流
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois =new ObjectInputStream(fis);
){
oos.writeObject(h);
Hero h1 = (Hero) ois.readObject();
System.out.println(h1.name);
System.out.println(h1.hp);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
package priv.study.io;
import java.io.*;
//准备一个长度是10,类型是Hero的数组,使用10个Hero对象初始化该数组
//然后把该数组序列化到一个文件heros.lol
//接着使用ObjectInputStream 读取该文件,并转换为Hero数组,验证该数组中的内容,是否和序列化之前一样
public class HeroTest {
public static void main(String[] args) {
String path= "D:/JavaTest/java/hello/java/6.lol";
xuLieHua(path);
}
public static void xuLieHua(String path){
//创建长度为10的Hero类型数组
Hero[] heros = new Hero[10];
for (int i=0;i<10;i++) {
heros[i] = new Hero();
heros[i].name="lol"+i;
heros[i].hp=650;
}
File f = new File(path);
try(FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fos);
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois =new ObjectInputStream(fis);
){
oos.writeObject(heros);
Hero[] heross = (Hero[]) ois.readObject();
for (Hero h:heross
) {
System.out.println(h.name);
System.out.println(h.hp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
八、System.in
System.out 是常用的在控制台输出数据的
System.in 可以从控制台输入数据
使用System.in.read虽然可以读取数据,但是很不方便
使用Scanner就可以逐行读取了
实践代码,搓搓小手动起来(=!=):
自动创建有一个属性的类文件。
通过控制台,获取类名,属性名称,属性类型,根据一个模板文件,自动创建这个类文件,并且为属性提供setter和getter
模板:
public class @class@ {
public @type@ @property@;
public @class@() {
}
public void set@Uproperty@(@type@ @property@){
this.@property@ = @property@;
}
public @type@ get@Uproperty@(){
return this.@property@;
}
}
package priv.study.io;
import java.io.*;
import java.util.*;
public class HeroTest1 {
static String className;
static String attributeByte;
static String attributeName;
public static void main(String[] args) {
//仅限于一个属性,多个属性还没有实现
automatic();
}
public static void automatic() {
//控制台输入
Scanner sc =new Scanner(System.in);
System.out.println("请输入类名:");
className = sc.next();//从控制台获得类名
HashMap<String,String> attribute= new HashMap<String,String>();//用来存放属性名和值
while (true) {
System.out.println("请输入属性类型:"+"需要退出程序,输入exit即可");
attributeByte = sc.next();//从控制台获得属性类型
if (attributeByte.equals("exit")) {
break;
}
System.out.println("请输入属性名:");
attributeName = sc.next();
attribute.put(attributeByte,attributeName);//属性名和类型放到HashMap里
}
//读取和写入
automatic1(className,attribute);
}
public static void automatic1(String className,HashMap<String,String> attribute ) {
File newFile = new File("D:/JavaTest/java/hello/java/8.txt");//创建新文件对象
File templateFile = new File("D:/JavaTest/java/hello/java/7.txt");//创建模板文件对象
List<String> list=new ArrayList<>(attribute.keySet());//把属性的全部键值取出,用键可以获得对应的值
StringBuffer[] sbs = new StringBuffer[list.size()];//用于存放首字母大写的属性名(get/set方法要使用)
for (int i=0;i<list.size();i++) {
//首字母大写
String str =attribute.get(list.get(i));
StringBuffer sb = new StringBuffer(String.valueOf(Character.toUpperCase(str.charAt(0))));
sb.append(str.substring(1));
sbs[i] = sb;
}
//缓存流读取模板数据
ArrayList<String> listRead = new ArrayList<String>();//存放读取的字符串
try(FileReader fr = new FileReader(templateFile);
BufferedReader br = new BufferedReader(fr);
//写入新文件
FileWriter fw = new FileWriter(newFile);
PrintWriter pw = new PrintWriter(fw);
)
{
while (true) {
String line = br.readLine(); //一行一行读取
if (line==null) {
break;
}
if (line.indexOf("@class@")!=-1||line.indexOf("@type@")!=-1||
line.indexOf("@property@")!=-1||line.indexOf("@Uproperty@")!=-1
) {
line=line.replace("@class@",className);
line=line.replace("@type@",list.get(0));
line=line.replace("@property@",attribute.get(list.get(0)));
line=line.replace("@Uproperty@",sbs[0]);
}
listRead.add(line);
System.out.println(line);
}
for (String l:listRead
) {
pw.println(l);
System.out.println("写入的语句:"+l.trim());
pw.flush();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
今天学习分享的内容到此为止了,本是想要激励自己学下去,但发现快乐更是知识在于分享!
作为初学者对于Java的理解实在浅薄,如有错误请指正,万分感谢!