黑马程序员——IO流
2015-08-20 22:49
597 查看
——- android培训、java培训、期待与您交流! ———-
黑马程序员IO流
IO流常用基类
字符流
字符流创建文件
字符流读取文件
字符流继承体系简图
字符流的缓冲区
装饰设计模式
字节流
字节流继承体系简图
字符流的缓冲区
转换流
IO流的操作规律总结
IO包中的其他类
IO流体系
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流与字符流。
流按流向分为:输入流,输出流。
InputStream, OutputStream。
字符流的抽象基类:
Reader, Writer。
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
其实这些对象的内部使用的还是字节流(因为文字最终也是字节数据)
只不过,通过字节流读取了相对应的字节数,没有对这些字节直接操作。
而是去查了指定的(本机默认的)编码表,获取到了对应的文字。
简单说:字符流就是 : 字节流+编码表。
调用流对象的写入方法,将数据写入流
关闭流资源,并将流中的数据清空到文件中。
代码:
创建一个临时存放数据的数组。
调用流对象的读取方法将流中的数据读入到数组中。
代码:
缓冲技术原理:此对象中封装了数组,将数据存入,再一次性取出。
对应类
BufferedWriter
BufferedReader
缓冲区要结合流才可以使用。
在流的基础上对流的功能进行了增强。
当想对已有对象进行功能增强时,可定义类:将已有对象传入,基于已有对象的功能,并提供加强功能,那么自定义的该类称之为装饰类。
特点
装饰类通常都会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
装饰和继承的区别:
装饰模式比继承要灵活。避免了继承体系的臃肿,且降低了类与类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰的类通常都是属于一个体系。
从继承结构转为组合结构。
注:在定义类的时候,不要以继承为主;可通过装饰设计模式进行增强类功能。灵活性较强,当装饰类中的功能不适合,可再使用被装饰类的功能。
BufferedReader的原理。
使用流的read方法从源中读取一批数据存储到缓冲区的数组中。
通过计数器记录住存储的元素个数。
通过数组的角标来获取数组中的元素(从缓冲区中取数据).
指针会不断的自增,当增到数组长度,会归0.计数器会自减,当减到0时,就在从源拿一批数据进缓冲区。
自定义BufferedReader:
但它不仅可以操作字符,还可以操作其他媒体文件
读写特点:
read():会将字节byte型值提升为int型值
write():会将int型强转为byte型,即保留二进制数的最后八位。
转换流的由来
字符流与字节流之间的桥梁
方便了字符流与字节流之间的操作
转换流的应用
字节流中的数据都是字符时,转成字符流操作更高效。
标准输入输出流
System类中的字段:in,out。
它们各代表了系统标准的输入和输出设备。
默认输入设备是键盘,输出设备是显示器。
System.in的类型是InputStream.
System.out的类型是PrintStream是OutputStream的子类FilterOutputStream的子类.
示例
InputStreamReader将字节流通向字符流
获取键盘录入对象。
将字节流对象转成字符流对象,使用转换流。
为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
//键盘录入最常见写法
OutputStreamWriter字符流通向字节流
字符通向字节:录入的是字符,存到硬盘上的是字节。步骤和InputStreamReader转换流一样。
数据源:InputStream ,Reader
数据汇:OutputStream,Writer
明确数据:因为数据分两种:字节,字符。
数据源:是否是纯文本数据呢?
是:Reader
否:InputStream
数据汇:
是:Writer
否:OutputStream
明确设备:
数据源:
键盘:System.in
硬盘:FileXXX
内存:数组。
网络:socket socket.getInputStream();
数据汇:
控制台:System.out
硬盘:FileXXX
内存:数组
网络:socket socket.getOutputStream();
明确额外功能:
需要转换?是,使用转换流。InputStreamReader OutputStreamWriter
需要高效?是,使用缓冲区。Buffered
需要其他?
示例:
复制一个文本文件。
明确体系:
源:InputStream ,Reader
目的:OutputStream ,Writer
明确数据:
源:是纯文本吗?是 Reader
目的;是纯文本吗?是 Writer
明确设备:
源:硬盘上的一个文件。 FileReader
目的:硬盘上的一个文件。FileWriter
FileReader fr = new FileReader(“a.txt”);
FileWriter fw = new FileWriter(“b.txt”);
需要额外功能吗?
需要,高效,使用buffer
BufferedReader bufr = new BufferedReader(new FileReader(“a.txt”));
BufferedWriter bufw = new BufferedWriter(new FileWriter(“b.txt”));
读取键盘录入,将数据存储到一个文件中。
明确体系:
源:InputStream ,Reader
目的:OutputStream ,Writer
明确数据:
源:是纯文本吗?是 Reader
目的;是纯文本吗?是 Writer
明确设备:
源:键盘,System.in
目的:硬盘,FileWriter
InputStream in = System.in;
FileWriter fw = new FileWriter(“a.txt”);
需要额外功能吗?
需要,因为源明确的体系时Reader。可是源的设备是System.in。
所以为了方便于操作文本数据,将源转成字符流。需要转换流。InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
FileWriter fw = new FileWriter(“a.txt”);
需要高效不?需要。Buffer
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new FileWriter(“a.txt”));
读取一个文本文件,将数据展现在控制台上。
明确体系:
源:InputStream ,Reader
目的:OutputStream ,Writer
明确数据:
源:是纯文本吗?是 Reader
目的;是纯文本吗?是 Writer
明确设备:
源:硬盘文件,FileReader。
目的:控制台:System.out。
FileReader fr = new FileReader(“a.txt”);
OutputStream out = System.out;
需要额外功能?
因为源是文本数据,确定是Writer体系。所以为了方便操作字符数据,
需要使用字符流,但是目的又是一个字节输出流。
需要一个转换流,OutputStreamWriter
FileReader fr = new FileReader(“a.txt”);
OutputStreamWriter osw = new OutputStreamWriter(System.out);
需要高效吗?需要。
BufferedReader bufr = new BufferedReader(new FileReader(“a.txt”));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
读取键盘录入,将数据展现在控制台上。
明确体系:
源:InputStream ,Reader
目的:OutputStream ,Writer
明确数据:
源:是纯文本吗?是 Reader
目的;是纯文本吗?是 Writer
明确设备:
源:键盘:System.in
目的:控制台:System.out
InputStream in = System.in;
OutputStream out = System.out;
需要额外功能吗?
因为处理的数据是文本数据,同时确定是字符流体系。
为方便操作字符数据的可以将源和目的都转成字符流。使用转换流。
为了提高效率,使用Buffer
BufferedReader bufr =new BufferedReader(new InputStreamReader(Systme.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
读取一个文本文件,将文件按照指定的编码表UTF-8进行存储,保存到另一个文件中。
明确体系:
源:InputStream ,Reader
目的:OutputStream ,Writer
明确数据:
源:是纯文本吗?是 Reader
目的;是纯文本吗?是 Writer
明确设备:
源:硬盘:FileReader.
目的:硬盘:FileWriter
FileReader fr = new FileReader(“a.txt”);
FileWriter fw = new FileWriter(“b.txt”);
额外功能:
注意:目的中虽然是一个文件,但是需要指定编码表。
而直接操作文本文件的FileWriter本身内置的是本地默认码表。无法明确具体指定码表。
这时就需要转换功能。OutputStreamWriter,而这个转换流需要接受一个字节输出流,而且
对应的目的是一个文件。这时就使用字节输出流中的操作文件的流对象。FileOutputStream.
FileReader fr = new FileReader(“a.txt”);
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(“b.txt”),”UTF-8”);
需要高效吗?
BufferedReader bufr = new BufferedReader(new FileReader(“a.txt”));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(“b.txt”),”UTF-8”));
随机访问文件,自身具备读写的方法。
通过skipBytes(int x),seek(int x)来达到随机访问。
管道流
PipedInputStream和PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用。
打印流
PrintWriter与PrintStream
可以直接操作输入流和文件。
序列流
SequenceInputStream
对多个流进行合并。
操作对象
ObjectInputStream与ObjectOutputStream
被操作的对象需要实现Serializable (标记接口);
操作基本数据类型
DataInputStream与DataOutputStream
操作字节数组
ByteArrayInputStream与ByteArrayOutputStream
操作字符数组
CharArrayReader与CharArrayWrite
操作字符串
StringReader 与 StringWriter
黑马程序员IO流
IO流常用基类
字符流
字符流创建文件
字符流读取文件
字符流继承体系简图
字符流的缓冲区
装饰设计模式
字节流
字节流继承体系简图
字符流的缓冲区
转换流
IO流的操作规律总结
IO包中的其他类
IO流体系
黑马程序员——IO流
IO流用来处理设备之间的数据传输Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流与字符流。
流按流向分为:输入流,输出流。
IO流常用基类
字节流的抽象基类:InputStream, OutputStream。
字符流的抽象基类:
Reader, Writer。
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
字符流
字符流:为了处理文字数据方便而出现的对象。其实这些对象的内部使用的还是字节流(因为文字最终也是字节数据)
只不过,通过字节流读取了相对应的字节数,没有对这些字节直接操作。
而是去查了指定的(本机默认的)编码表,获取到了对应的文字。
简单说:字符流就是 : 字节流+编码表。
字符流——创建文件
创建流对象,建立数据存放文件FileWriter fw = new FileWriter("Test.txt");
调用流对象的写入方法,将数据写入流
fw.write("text");
关闭流资源,并将流中的数据清空到文件中。
fw.close();
代码:
FileWriter fw = null; try { fw = new FileWriter("Test.txt"); fw.write("text"); } catch (IOException e) { System.out.println(e.toString()); } finally { if (fw != null) { try{ fw.close(); } catch (IOException e) { System.out.println(e.toString()); } } }
字符流——读取文件
建立一个流对象,将已存在的一个文件加载进流。FileReader fr = new FileReader("Test.txt");
创建一个临时存放数据的数组。
char[] ch = new char[1024];
调用流对象的读取方法将流中的数据读入到数组中。
fr.read(ch);
代码:
FileReader fr = null; try { fr = new FileReader("c:\\test.txt"); char[] buf = new char[1024]; int len = 0; while ((len = fr.read(buf)) != -1) { System.out.println(new String(buf, 0, len)); } } catch (IOException e) { System.out.println("read-Exception :" + e.toString()); } finally { if (fr != null) { try { fr.close(); } catch (IOException e) { System.out.println("close-Exception :" + e.toString()); } } }
字符流继承体系简图
字符流的缓冲区
缓冲区的出现提高了对数据的读写效率。缓冲技术原理:此对象中封装了数组,将数据存入,再一次性取出。
对应类
BufferedWriter
BufferedReader
缓冲区要结合流才可以使用。
在流的基础上对流的功能进行了增强。
装饰设计模式
简述当想对已有对象进行功能增强时,可定义类:将已有对象传入,基于已有对象的功能,并提供加强功能,那么自定义的该类称之为装饰类。
特点
装饰类通常都会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
装饰和继承的区别:
装饰模式比继承要灵活。避免了继承体系的臃肿,且降低了类与类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰的类通常都是属于一个体系。
从继承结构转为组合结构。
注:在定义类的时候,不要以继承为主;可通过装饰设计模式进行增强类功能。灵活性较强,当装饰类中的功能不适合,可再使用被装饰类的功能。
BufferedReader的原理。
使用流的read方法从源中读取一批数据存储到缓冲区的数组中。
通过计数器记录住存储的元素个数。
通过数组的角标来获取数组中的元素(从缓冲区中取数据).
指针会不断的自增,当增到数组长度,会归0.计数器会自减,当减到0时,就在从源拿一批数据进缓冲区。
自定义BufferedReader:
import java.io.FileReader; import java.io.IOException; import java.io.Reader; /** * 自定义的读取缓冲区。其实就是模拟一个BufferedReader. * * 分析: 缓冲区中无非就是封装了一个数组, 并对外提供了更多的方法对数组进行访问。 其实这些方法最终操作的都是数组的角标。 * * 缓冲的原理: 其实就是从源中获取一批数据装进缓冲区中。 在从缓冲区中不断的取出一个一个数据。 * * 在此次取完后,在从源中继续取一批数据进缓冲区。 当源中的数据取光时,用-1作为结束标记。 * * * @author Administrator * */ public class MyBufferedReader extends Reader { private Reader r; // 定义一个数组作为缓冲区。 private char[] buf = new char[1024]; // 定义一个指针用于操作这个数组中的元素。当操作到最后一个元素后,指针应该归零。 private int pos = 0; // 定义一个计数器用于记录缓冲区中的数据个数。 当该数据减到0,就从源中继续获取数据到缓冲区中。 private int count = 0; MyBufferedReader(Reader r) { this.r = r; } /** * 该方法从缓冲区中一次取一个字符。 * * @return * @throws IOException */ public int myRead() throws IOException { // 从源中获取一批数据到缓冲区中。需要先做判断,只有计数器为0时,才需要从源中获取数据。 if (count == 0) { count = r.read(buf); pos = 0; // 每次获取数据到缓冲区后,角标归零. } if (count < 0) return -1; // 代表流读完了 char ch = buf[pos++]; count--; return ch; } public String myReadLine() throws IOException { StringBuilder sb = new StringBuilder(); int ch = 0; while ((ch = myRead()) != -1) { if (ch == '\r') continue; if (ch == '\n') return sb.toString(); // 将从缓冲区中读到的字符,存储到缓存行数据的缓冲区中。 sb.append((char) ch); } if (sb.length() != 0) return sb.toString(); return null; } public void myClose() throws IOException { r.close(); } @Override public int read(char[] cbuf, int off, int len) throws IOException { return 0; } @Override public void close() throws IOException { } }
字节流
基本操作与字符流类相同但它不仅可以操作字符,还可以操作其他媒体文件
字节流继承体系简图
字符流的缓冲区
同样是提高了字节流的读写效率。读写特点:
read():会将字节byte型值提升为int型值
write():会将int型强转为byte型,即保留二进制数的最后八位。
转换流
InputStreamReader, OutputStreamWriter转换流的由来
字符流与字节流之间的桥梁
方便了字符流与字节流之间的操作
转换流的应用
字节流中的数据都是字符时,转成字符流操作更高效。
标准输入输出流
System类中的字段:in,out。
它们各代表了系统标准的输入和输出设备。
默认输入设备是键盘,输出设备是显示器。
System.in的类型是InputStream.
System.out的类型是PrintStream是OutputStream的子类FilterOutputStream的子类.
示例
InputStreamReader将字节流通向字符流
获取键盘录入对象。
InputStream in=System.in;
将字节流对象转成字符流对象,使用转换流。
InputStreamReaderisr=new InputStreamReader(in);
为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
BufferedReaderbr=new BufferedReader(isr);
//键盘录入最常见写法
BufferedReaderin=new BufferedReader(new InputStreamReader(System.in));
OutputStreamWriter字符流通向字节流
字符通向字节:录入的是字符,存到硬盘上的是字节。步骤和InputStreamReader转换流一样。
/* 需求:将键盘录入的数据,显示在控制台,当输入over时,表示结束 源:键盘录入。 目的:控制台。 */ import java.io.*; class TransStreamDemo { public static void main(String[] args) throws IOException { // 获取键盘录入对象。 // InputStream in=System.in; // 将字节流对象转成字符流对象,使用转换流。 // InputStreamReader isr=new InputStreamReader(in); // 为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader // BufferedReader br=new BufferedReader(isr); // 键盘录入最常见写法 BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); // 字符流通向字节流 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter( System.out)); String s = null; while ((s = in.readLine()) != null) { if ("over".equals(s)) break; bw.write(s.toUpperCase());// 写入数据 bw.newLine();// 换行 bw.flush();// 刷新 } bw.close();// 关闭流资源 in.close(); } }
IO流的操作规律总结
明确体系:数据源:InputStream ,Reader
数据汇:OutputStream,Writer
明确数据:因为数据分两种:字节,字符。
数据源:是否是纯文本数据呢?
是:Reader
否:InputStream
数据汇:
是:Writer
否:OutputStream
明确设备:
数据源:
键盘:System.in
硬盘:FileXXX
内存:数组。
网络:socket socket.getInputStream();
数据汇:
控制台:System.out
硬盘:FileXXX
内存:数组
网络:socket socket.getOutputStream();
明确额外功能:
需要转换?是,使用转换流。InputStreamReader OutputStreamWriter
需要高效?是,使用缓冲区。Buffered
需要其他?
示例:
复制一个文本文件。
明确体系:
源:InputStream ,Reader
目的:OutputStream ,Writer
明确数据:
源:是纯文本吗?是 Reader
目的;是纯文本吗?是 Writer
明确设备:
源:硬盘上的一个文件。 FileReader
目的:硬盘上的一个文件。FileWriter
FileReader fr = new FileReader(“a.txt”);
FileWriter fw = new FileWriter(“b.txt”);
需要额外功能吗?
需要,高效,使用buffer
BufferedReader bufr = new BufferedReader(new FileReader(“a.txt”));
BufferedWriter bufw = new BufferedWriter(new FileWriter(“b.txt”));
读取键盘录入,将数据存储到一个文件中。
明确体系:
源:InputStream ,Reader
目的:OutputStream ,Writer
明确数据:
源:是纯文本吗?是 Reader
目的;是纯文本吗?是 Writer
明确设备:
源:键盘,System.in
目的:硬盘,FileWriter
InputStream in = System.in;
FileWriter fw = new FileWriter(“a.txt”);
需要额外功能吗?
需要,因为源明确的体系时Reader。可是源的设备是System.in。
所以为了方便于操作文本数据,将源转成字符流。需要转换流。InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
FileWriter fw = new FileWriter(“a.txt”);
需要高效不?需要。Buffer
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new FileWriter(“a.txt”));
读取一个文本文件,将数据展现在控制台上。
明确体系:
源:InputStream ,Reader
目的:OutputStream ,Writer
明确数据:
源:是纯文本吗?是 Reader
目的;是纯文本吗?是 Writer
明确设备:
源:硬盘文件,FileReader。
目的:控制台:System.out。
FileReader fr = new FileReader(“a.txt”);
OutputStream out = System.out;
需要额外功能?
因为源是文本数据,确定是Writer体系。所以为了方便操作字符数据,
需要使用字符流,但是目的又是一个字节输出流。
需要一个转换流,OutputStreamWriter
FileReader fr = new FileReader(“a.txt”);
OutputStreamWriter osw = new OutputStreamWriter(System.out);
需要高效吗?需要。
BufferedReader bufr = new BufferedReader(new FileReader(“a.txt”));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
读取键盘录入,将数据展现在控制台上。
明确体系:
源:InputStream ,Reader
目的:OutputStream ,Writer
明确数据:
源:是纯文本吗?是 Reader
目的;是纯文本吗?是 Writer
明确设备:
源:键盘:System.in
目的:控制台:System.out
InputStream in = System.in;
OutputStream out = System.out;
需要额外功能吗?
因为处理的数据是文本数据,同时确定是字符流体系。
为方便操作字符数据的可以将源和目的都转成字符流。使用转换流。
为了提高效率,使用Buffer
BufferedReader bufr =new BufferedReader(new InputStreamReader(Systme.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
读取一个文本文件,将文件按照指定的编码表UTF-8进行存储,保存到另一个文件中。
明确体系:
源:InputStream ,Reader
目的:OutputStream ,Writer
明确数据:
源:是纯文本吗?是 Reader
目的;是纯文本吗?是 Writer
明确设备:
源:硬盘:FileReader.
目的:硬盘:FileWriter
FileReader fr = new FileReader(“a.txt”);
FileWriter fw = new FileWriter(“b.txt”);
额外功能:
注意:目的中虽然是一个文件,但是需要指定编码表。
而直接操作文本文件的FileWriter本身内置的是本地默认码表。无法明确具体指定码表。
这时就需要转换功能。OutputStreamWriter,而这个转换流需要接受一个字节输出流,而且
对应的目的是一个文件。这时就使用字节输出流中的操作文件的流对象。FileOutputStream.
FileReader fr = new FileReader(“a.txt”);
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(“b.txt”),”UTF-8”);
需要高效吗?
BufferedReader bufr = new BufferedReader(new FileReader(“a.txt”));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(“b.txt”),”UTF-8”));
IO包中的其他类
RandomAccessFile随机访问文件,自身具备读写的方法。
通过skipBytes(int x),seek(int x)来达到随机访问。
管道流
PipedInputStream和PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用。
打印流
PrintWriter与PrintStream
可以直接操作输入流和文件。
序列流
SequenceInputStream
对多个流进行合并。
操作对象
ObjectInputStream与ObjectOutputStream
被操作的对象需要实现Serializable (标记接口);
操作基本数据类型
DataInputStream与DataOutputStream
操作字节数组
ByteArrayInputStream与ByteArrayOutputStream
操作字符数组
CharArrayReader与CharArrayWrite
操作字符串
StringReader 与 StringWriter
IO流体系
字符流: Reader |--BufferedReader |--LineNumberReader |--CharArrayReader |--StringReader |--InputStreamReaer |--FileReader Writer |--BufferedWriter |--CharArrayWriter |--StringWriter |--OutputStreamWriter |--FileWriter |--PrintWriter 字节流: InputStream |--FileInputStream |--FilterInputStream |--BufferedInputStream |--DataInputStream |--ByteArrayInputStream |--ObjectInputStream |--SequenceInputStream |--PipedInputStream OutputStream |--FileOutputStream |--FilterOutputStream |--BufferedOutputStream |--DataOutputStream |--ByteArrayOutputStream |--ObjectOutputStream |--PipedOutputStream |--PrintStream RandomAccessFile
相关文章推荐
- 黑马程序员-JAVA基础之单例设计模式
- 黑马程序员----关于string类的基本操作举例
- 黑马程序员——java泛型
- 聚龙股份有限公司-面试总结
- 写给java程序员的一封情书
- 海量数据处理:十道面试题与十个海量数据处理方法总结
- 黑马程序员----java基础之Map集合
- 黑马程序员——集合
- UC-Android逆向工程师 面试题1的分析
- 黑马程序员——正则与反射
- 程序员的生活充满压力,但你不能放弃!
- 黑马程序员——String类和基本数据类型包装类
- 115个Java面试题和答案——终极列表(下)
- 115个Java面试题和答案——终极列表(上)
- 15个顶级Java多线程面试题及回答
- 9个Java初始化和回收的面试题
- 黑马程序员——异常&IO、其他流&编码表、Properties
- 黑马程序员——多线程
- 黑马程序员-JAVA基础之面向对象
- 黑马程序员——Java基础---面向对象