流与反射

#File
```java
public class IO1 {
    public static void main(String[] args) {
          String path = "e:" + File.separator +"testJava"; //File.separator是根据系统产生相应的斜杠(为了跨平台),设置文件夹路径和名字
          File f = new File(path);  
          f.mkdir();           //创建一个文件夹
          String path1 = "e:" + File.separator + "testJava" + File.separator + "123.text"; //设置文件路径和格式
          File f1 = new File(path1);
          try {
                 f1.createNewFile();   //创建一个文件
               //f1.delete();   //删除文件
          } catch (IOException e) {
               e.printStackTrace();
          }
          /*if (f.exists()){  //判断文件是否存在
               f.delete();  //删除文件夹,只能删除空文件夹
          }*/
          String[] s = f.list();  //列出文件夹的内容,只列出名字,返回字符串数组
          for (int i=0; i<s.length; i++){
               System.out.println(s[i]);
          }
          File[] fl = f.listFiles();  //列出文件夹内容的完整路径,返回"File"文件数组
          for (int i=0; i<fl.length; i++){  
               System.out.println(fl[i]);
          }
          if (f.isDirectory()){  //判断若为文件夹就调用IoUtil类的ioUtil方法
               new IoUtil().ioUtil(f);
          }
    }
}
class IoUtil{
    public void ioUtil(File f){        //创建一个递归方法
          File[] fl1 = f.listFiles();    //列出文件夹内容路径
          for (int i=0; i<fl1.length; i++){ 
               if (fl1[i].isDirectory()){  //判断若为文件夹就继续调用该方法,遍历文件夹里面的内容
               ioUtil(fl1[i]);
               System.out.println(fl1[i]);
                }
               else{
                    System.out.println(fl1[i]);
               }
          }
    }
}
```
#字节输出流
```java
String path = "e:" + File.separator + "test" + File.separator + "123.txt";  //指定文件路径
OutputStream out = null;  //声明输出流
String s = "\r\n我是好人!";  //要输出内容
out = new FileOutputStream(path,true); //创建输出流并指定文件,加true可以重复输出,不加就只输出一次且会覆盖原来的内容
byte[] b = s.getBytes();  //将字符串转换成字节
out.write(b);  //将字节输出
out.close();   //关流,否则会造成内存浪费
```
#字节输入流
```java
String path = "e:" + File.separator + "test" + File.separator + "123.txt";
InputStream in = null; 
//byte[] b = new byte[(int)new File(path).length()]; //定义一个接收文件的字节数组,file.length确定文件大小,可以给确定的数值,只是会造成浪费
byte[] b = new byte[1024];  //指定byte数组大小
int l = 0;
in = new FileInputStream(path); //创建一个输入流
l = in.read(b);  //记录长度
in.close(); //关流
System.out.println(new String(b));    //所有内容(包括空格),String在构造函数中可以将字节转换成字符串
System.out.println(new String(b,0,l));  //指定输出范围,若有多余内存会直接截取掉,但还是存在的,只是没有输出来而已(障眼法)
```
#字符输出输入流
```java
String path = "e:" + File.separator + "test" + File.separator + "123.txt";
Writer w = null;  //声明一个字符输出流
Reader r = null;  //声明一个字符输入流
//char[] c = new char[1024];  //创建一个字符数组
char[] c = new char[(int)new File(path).length()]; //new File(path).length()接收文件长度
String s = "wo shi huairen"; //输出内容
/*try {
    w = new FileWriter(path,true); //创建一个输出流,输出到指定文件
    r = new FileReader(path);  //创建一个输入流,输入指定文件内容
    w.write(s);  //输出流输出内容
    r.read(c);   //输入流输入内容,将内容放入字符数组内
    } catch (Exception e){
          e.printStackTrace();
    }
    finally{
          try {
          w.close();  //关流
          r.close();  //关流
    } catch (IOException e) {
          e.printStackTrace();
     }
}
System.out.println(new String(c));
```
    注意:字节流使用了缓冲区(即内存中的一块区域),可以用不关闭流,看是否会写到文件中为例来证明;out.flush():强制清空缓冲区,这样在不关闭字符流的情况下也可以将数据写入到文件中;在开发中字节流使用较多;
#内存操作流
* 直接操作内存
```java
String s = "wo shi haoren";
ByteArrayInputStream bis = new ByteArrayInputStream(s.getBytes()); //通过ByteArrayInputStream构造方法向内存写入数据
ByteArrayOutputStream bos = new ByteArrayOutputStream(); //创建读取内存流
int l = 0;
while((l=bis.read())!=-1){  //当这里面没有参数时,说明"l"是存入的此节点值数据,当这里面有参数时,说明"l"是存入的整个节点值数据,没有参数就是一个字节一个字节的传输
char c = (char)l;
bos.write(Character.toUpperCase(c));  //调用char方法将内容变为大写
}
try {
    bis.close(); //关流
    bos.close();
} catch (IOException e) {
    e.printStackTrace();
}
System.out.println(bos.toString()); //取出插入流中的数据
```
#转换流
* 字符流内包字节流
```java
String path = "e:" + File.separator + "test" + File.separator +"123.txt";
OutputStreamWriter osw = null;
InputStreamReader isr = null;
int l = 0;
char[] c = new char[(int)new File(path).length()]; //创建一个字符数组
try {
    osw = new OutputStreamWriter(new FileOutputStream(path,true)); //创建一个输出字符流,实际上是输出的字节流,外表是字符输出,本质却是字节输出(不用转字节)
    isr = new InputStreamReader(new FileInputStream(path)); //创建一个输入字节流,实际上是输入的字符流
    osw.write("我是坏人"); //输出字符内容
    l = isr.read(c);
} catch (Exception e) {
    e.printStackTrace();
}
finally{
    try {
          osw.close();//关流
          isr.close();
     } catch (IOException e) {
          e.printStackTrace();
    }
}
System.out.println(new String(c,0,l));
```
#管道流
* 将两个线程联系起来
```java
public class IO7 {
    public static void main(String[] args) {
          Send s = new Send();
          Receive r = new Receive();
          try {
               s.getPos().connect(r.getPis());  //用输出线程来连接输入线程
          } catch (IOException e) {
               e.printStackTrace();
          }
          new Thread(s).start();  //开始线程
          new Thread(r).start();
    }
}
//创建一个发送类,实现Runnable接口,在此线程中创建输出流
class Send implements Runnable{  
    private PipedOutputStream pos = null; //声明一个输出流
    public Send(){
          this.pos = new PipedOutputStream(); //通过构造函数创建一个输出流
    }
    public void run(){
          String s = "我是好人";
          try {
               pos.write(s.getBytes());  //输出被转换成字节的字符串
          } catch (IOException e) {
               e.printStackTrace();
          }
          finally {
               try {
                    pos.close();  //关流
               } catch (IOException e) {
                    e.printStackTrace();
               }
          }
    }
    public PipedOutputStream getPos(){ //获取输出流
          return this.pos;
    }
}
//创建一个输入流,并实现Runnable接口,该线程创建输入流
class Receive implements Runnable{
    private PipedInputStream pis = null;
    public Receive(){
           this.pis = new PipedInputStream();
    }
    public void run(){
          byte[] b = new byte[1024];  //这时无法确定文件大小,因此只能给个估算值来存入接收数据
          int l = 0;
          try {
               l = pis.read(b);  //保存字节大小
          } catch (IOException e) {
               e.printStackTrace();
          }
          finally {
               try {
                    pis.close(); //关流
               } catch (IOException e) {
                    e.printStackTrace();
               }
          }
          System.out.println(new String(b,0,l)); 
    }
    public PipedInputStream getPis(){  //获取输入流
          return this.pis;
    }
}
```
#打印流
```java
String path = "e:" + File.separator + "test" + File.separator + "123.txt";
PrintStream ps = new PrintStream(new FileOutputStream(f));  //字节打印流,
ps.print("我是好人");
PrintWriter pw = new PrintWriter(new FileWriter(f));  //字符打印流
pw.print("我是坏人");
ps.close();
pw.close();
```
#打印流格式化输出
* 装饰设计模式:让格式也保持输出
```java
String path = "e:" + File.separator + "test" + File.separator + "123.txt";
PrintStream ps = new PrintStream(new FileOutputStream(path));
PrintWriter pw = new PrintWriter(new FileWriter(path));
ps.printf("name:%s, age:%d, score:%f, sex:%c","小明",18,79.5,'F'); //%s表示字符串型,%d表示整型,%f表示浮点型,%c表示字符型
pw.printf("name:%s, age:%d, score:%f, sex:%c","小明",18,79.5,'F'); //%s表示字符串型,%d表示整型,%f表示浮点型,%c表示字符型
ps.close();
pw.close();
```
#标准输出流
```java
OutputStream os = System.out;
os.writer("我们是好人"); //向显示器输出
System.err.print("我错了"); //专门用来输出错误信息
```
#标准输入流
* 方式一:只接受限制个数的输入
```java
InputStream in = System.in;
byte[] b = new byte[100];
int l = in.read(b);
System.out.println(new String(b,0,l));
in.close();
```
* 方式二:不接受汉字,因为其是一个字节一个字节的输入
```java
InputStream in = System.in;
StringBuffer sb = new StringBuffer();
int t = 0;
while((t=in.read()) != -1){  
    char c = (char)t;
    if (c == '\n')  //若换行表示输入结束
          break;
    sb.append(c); //没有换行则追加
}
System.out.println(sb);
in.close();
```
* 方式三:标准输入
```java
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //从键盘输入
//BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path))); //从指定文件输入
String s = br.readLine();
System.out.print(s);
br.close();
```
#输入输出重写向
```java
String path = "e:" + File.separator + "test" + File.separator + "321.txt";
try {
    System.setOut(new PrintStream(new FileOutputStream(path,true))); //输出重定向,输出到指定文件
    System.setIn(new FileInputStream(path)); //输入重定向,输入到指定文件
    System.setErr(new PrintStream(new FileOutputStream(path))); //错误重定向
    InputStream is = System.in;
    byte[] b = new byte[100];
    int l = is.read(b);
    System.out.println(new String(b,0,l));
    int c = 1/0;  //这里会出异常,错误信息会被发送到指定文件去
} catch (Exception e) {
    System.err.print(e);
}
System.out.println("我来了o");
```
#Scanner
```java
Scanner s = new Scanner(new FileInputStream(path1)); //从指定文件输入
s.useDelimiter("\n");   //改成以换行为分隔符,不改则遇到空格就结束
String s1 = s.next();
System.out.println(s1);
s.close();
```
#读写基本数据类型流
```java
DataOutputStream dos = new DataOutputStream(new FileOutputStream(path1));//向指定文件写入基本数据类型流,写入后只能通过下面方法读取
DataInputStream dis = new DataInputStream(new FileInputStream(path1)); //向指定文件读取基本数据类型流
char sex = 'F';  
int age = 18;
dos.writeChar(sex);  //写入时要加上基本数据类型
dos.writeChar('\t'); //写入一个制表符
dos.writeInt(age);
dos.close();
System.out.print(dis.readChar()); //读取时一定要按写入顺序,不然会出错
System.out.print(dis.readChar());
System.out.print(dis.readInt());
dis.close();
```
#合并与分割
```java
public class IOdemo {
    public static void main(String[] args) {
          String path1 = "e:" + File.separator + "test" + File.separator + "123.txt";
          String path2 = "e:" + File.separator + "test" + File.separator + "321.txt";
          String path3 = "e:" + File.separator + "test" + File.separator + "31.txt";
          String path4 = "e:" + File.separator + "test" + File.separator + "text.txt";
          String path5 = "e:" + File.separator + "test" + File.separator + "split";
          String path6 = "e:" + File.separator + "test" + File.separator + "11.mp3";
          String path7 = "e:" + File.separator + "test" + File.separator + "split" + File.separator + "5.mp3";
          try {
               Sequence.sequence1(path1,path2,path3);
          } catch (IOException e) {
               e.printStackTrace();
          }
          List<FileInputStream> list = new ArrayList<FileInputStream>(); //创建合并文件集合,以输出流为类型
          try {
               list.add(new FileInputStream(new File(path1)));  //添加文件
               list.add(new FileInputStream(new File(path2)));
               list.add(new FileInputStream(new File(path3)));
               Sequence.sequence2(list, path4);
          } catch (Exception e) {
                    e.printStackTrace();
          }
          try {
               Sequence.split(path6, path5, 1024*1024);//每次传输1024*1024B=1M;
          } catch (IOException e) {
               e.printStackTrace();
          }
          List<FileInputStream> list1 = new ArrayList<FileInputStream>(); 
          try {
               for (int i=0; i < 4; i++){ //将合并文件按循环加入到集合中
                    list1.add(new FileInputStream(new File(path5,(i+1)+".mp3")));
               }
               Sequence.sequence2(list1, path7);
          } catch (Exception e) {
               e.printStackTrace();
          }
    }
}
// 创建一个合并工具类
class Sequence{
    //合并两个文件,需要三个参数:要合并的两个文件路径及目的文件路径;重点:使用SequenceInputStream的构造方法合并两个输入流
    public static void sequence1(String path1,String path2,String path3) throws IOException{ 
          InputStream is1 = new FileInputStream(new File(path1));  //创建一个输入流,从指定文件输入
          InputStream is2 = new FileInputStream(new File(path2));
          OutputStream os = new FileOutputStream(new File(path3)); //创建一个输出流,输出到指定文件
          SequenceInputStream sis = new SequenceInputStream(is1,is2); //合并两个文件(也就是将两个管道的数据汇合到一个管道)
          int t = 0;
          byte[] b = new byte[1024];  //每次传输1024
          while((t=sis.read(b))!=-1){
               os.write(b,0,t); //输出到指定文件
          }
          sis.close();
          os.close();
    }
    //合并多个文件,需要两个参数:要合并文件集合及目的文件路径;重点:将合并文件弄成一个集合,并且通过Collections的enumeration方法转换成Enumeration集合
    public static void sequence2(List list,String path4) throws IOException{
          Enumeration<FileInputStream> e = Collections.enumeration(list); //通过Collections的enumeration方法生成Enumeration集合
          SequenceInputStream sis = new SequenceInputStream(e);  //因为SequenceInputStream类出现时间太早,只支持Enumeration集合
          OutputStream os = new FileOutputStream(new File(path4));
          int t = 0;
          byte[] b = new byte[1024];  //每次传输1024B=1KB
          while ((t=sis.read(b)) != -1){
               os.write(b,0,t);
          }
          sis.close();
          os.close();
    }
    //分割器(分割文件),需要三个参数:分割文件路径、目的文件夹路径及分割文件的大小;重点:传输一次就创建一个文件夹
    public static void split(String path1,String path2,int size) throws IOException{
          InputStream is = new FileInputStream(new File(path1)); //创建一个输入流,插入要分割文件
          byte[] b = new byte[size]; 
          OutputStream os = null;
          File f = new File(path2); 
          int t = 0;
          int count = 1;
          if (!f.exists()){ //判断文件夹是否存在,不存在就创建
               f.mkdir();
          }
          while((t=is.read(b)) != -1){
               os = new FileOutputStream(new File(f,(count++)+".mp3")); //File的另一个构造方法,两个参数:文件夹路径、文件名,传输一次就创建一个文件
               os.write(b,0,t);//向文件输出数据
          }
          is.close();
          os.close();
    }
}
```
#Properties集合类配置文件
```java
class MyUtil{
    //创建一个查询配置文件方法,用户可以通过输入来查询想要的信息;重点:创建一个Properties属性列表
    public static void proper(String path) throws IOException{
          BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //创建一个标准输入流
          InputStream is = new FileInputStream(path); //创建一个读取指定文件数据输入流
          Properties p = new Properties();  //创建一个空属性列表
          p.setProperty("name", "小红");  //向列表中写入信息,没有写入文件
          p.load(is);   //从输入流中读取属性列表
          p.list(System.out);  //将属性列表输出到指定输出流
          String key = br.readLine();  //让用户输入要查询属性值
          System.out.println(p.getProperty(key)); //获取属性值
          br.close();
    }
//主函数
String path = "e:" + File.separator + "test" + File.separator + "user.txt";
try {
    MyUtil.proper(path);
} catch (IOException e) {
    e.printStackTrace();
}
```
#压缩与解压
```java
public class IOdemo1 {
    public static void main(String[] args) {
          //压缩一个文件
          String path1 = "e:" + File.separator + "test" + File.separator + "11.mp3";
          String path2 = "e:" + File.separator + "test" + File.separator + "111.zip";
          try {
               MyUtil.zip1(path1, path2);
          } catch (IOException e) {
               e.printStackTrace();
          }
          //压缩一个文件夹
          String path3 = "e:" + File.separator + "test" + File.separator + "split";
          String path4 = "e:" + File.separator + "test" + File.separator + "split.zip";
          try {
               MyUtil.zip2(path3, path4);
          } catch (IOException e) {
               e.printStackTrace();
          }
          //压缩与解压多级目录
          try {
               MyUtil.Zip();
          } catch (IOException e) {
               e.printStackTrace();
          }
    }
}
class MyUtil{
    //压缩文件方法,需要两个参数:被压缩文件路径及压缩文件路径;重点:创建一个压缩输出流嵌套一个输出流
    public static void zip1(String path1,String path2) throws IOException{
          File f = new File(path1); //创建一个文件
          InputStream is = new FileInputStream(f); //创建一个输入流
          ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(path2)); //创建一个压缩输出流,需要一个输出流参数
          zos.putNextEntry(new ZipEntry(f.getName()));  //putNextEntry设置压缩名字(需要一个zipEntry参数,ZipEntry表示压缩文件名字
          zos.setComment("这是一首mp3");  //注释
          int t = 0;
          byte[] b = new byte[1024*1024]; //缓冲区
          while ((t=is.read(b))!=-1){
                zos.write(b,0,t);  //开始压缩
          }
          is.close();
          zos.close();
    }
    //压缩文件夹方法,需要两个参数:被压缩文件夹路径及压缩文件路径;重点:让输入流通过循环指向不同文件来实现压缩多个文件,通过listFiles获取所有文件路径方便压缩文件命名
    public static void zip2(String path1,String path2) throws IOException{
          File f = new File(path1);  //创建一个文件
          InputStream is = null;  //声明一个输入流
          ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(path2));//创建一个压缩输出流
          int t = 0;
          byte[] b = new byte[1024*1024]; //缓冲区,临时保存输入流数据
          if (f.isDirectory()){  //判断若是否为文件夹
               File[] ff = f.listFiles();  //列出文件夹下所有文件路径
                for (int i=0; i<ff.length; i++){
                     is = new FileInputStream(ff[i]); //创建一个输入流指向指定文件
                     zos.putNextEntry(new ZipEntry(ff[i].getName())); //为压缩文件命名
                     while ((t=is.read(b)) != -1){
                         zos.write(b,0,t); //开始压缩
                     }
                }
           }
           is.close();
          zos.close();
    }
    //压缩多级文件夹方法,无参
    public static void Zip() throws IOException{
          BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //创建一个标准输入流
          System.out.print("请输入要压缩的文件夹路径:");  
          String path1 = br.readLine();  //由用户输入路径
          path1.replaceAll("\\*", File.separator); //找到路径符并替换,让其能在各个平台使用,增强通用性
          System.out.print("请输入压缩后文件所放路径(.压缩格式):");
          String path2 = br.readLine();
          path2.replaceAll("\\*", File.separator);
          ZipOutputStream zos = null; 
          File f = new File(path1); //创建一个被压缩文件
          zos = new ZipOutputStream(new FileOutputStream(path2)); //创建一个压缩输出流
          System.out.print("请为压缩后的文件夹命名:");
          String str = br.readLine(); //由用户为压缩文件命名
          Zip(f,str,zos); //调用压缩多级文件夹重载方法
          zos.close(); //关流
          System.out.println("*****************压缩成功*********************");
          System.out.print("是否需要解压(yes/no):");
          String ss = br.readLine();
          if (ss.equals("yes")){
               System.out.print("请输入压缩的文件夹路径:");  
                String p1 = br.readLine();  //由用户输入路径
               path1.replaceAll("\\*", File.separator); //找到路径符并替换,让其能在各个平台使用,增强通用性
               System.out.print("请输入解压文件夹所放路径:");
               String p2 = br.readLine();
               path2.replaceAll("\\*", File.separator);
               UnZip(p1,p2);
               System.out.println("*****************解压成功*********************");
          }
          br.close();
    }
    //压缩多级文件夹重载方法,有三个参数:被压缩文件、压缩文件名及压缩输出流 ;重点:用递归遍历文件夹
    public static void Zip(File f,String str,ZipOutputStream zos) throws IOException{
          if (f.isDirectory()){  //判断是否为文件夹
               str = (str.length()==0 ? "1/": str+"/"); //判断用户是否为压缩文件命名,若没就以1命名
               File[] ff = f.listFiles(); //列出文件夹内的所有文件
               zos.putNextEntry(new ZipEntry(str));  //为压缩文件命名
               for (File fff:ff){  //遍历文件夹内所有文件
                    Zip(fff,str+fff.getName(),zos); //递归,压缩文件名要加上文件名
               }
          }
          else {
               InputStream is = new FileInputStream(f); //创建一个输入流,读取被压缩文件数据
               zos.putNextEntry(new ZipEntry(str)); //为压缩文件命名
               byte[] b = new byte[1024*1024]; //缓冲区
               int t = 0;
               while ((t=is.read(b)) != -1){  //开始读取数据
                    zos.write(b,0,t);  //开始压缩
               }
               is.close(); //关流
          }
    }
    //解压方法,需要两个参数:压缩文件路径及解压文件路径;重点:调用getNextEntry方法来获取压缩文件头目数据
    public static void UnZip(String s,String ss) throws IOException{
          ZipInputStream zs = new ZipInputStream(new FileInputStream(s)); //创建一个解压输入流
          ZipEntry ze = zs.getNextEntry(); //获取输入流里面的下一个压缩文件头
          File f = new File(ss);  //创建一个文件
          f.mkdirs(); //创建根文件夹
          while (ze != null){ //判断是否还有压缩文件
                if (ze.isDirectory()){ //判断该压缩文件是否为压缩文件夹
                    String name = ze.getName(); //获取该压缩文件名
                    f = new File(ss+File.separator+name); //创建文件
                    f.mkdirs(); //创建一个文件夹
               }
               else {
                    f = new File(ss+File.separator+ze.getName());
                    f.createNewFile(); //创建一个文件
                    OutputStream os = new FileOutputStream(f);
                    byte[] b = new byte[1024*1024];
                    int t = 0;
                    while ((t = zs.read(b)) != -1){ //开始读取压缩文件
                         os.write(b,0,t); //开始压缩
                    }
                    os.close(); //关流
               }
               ze = zs.getNextEntry(); //获取下一个数据
          }
          zs.close();
    }
}
```
#序列化
* 将对象做为一个整体进行传输和存储(只针对属性)
```java
public class IOdemo2 {
    public static void main(String[] args) {
          //序列化:将对象进行整体存储与读取,被transient修饰的属性没会被存储与读取,因此为默认值
          try { 
               //单个对象存储与读取
               Ser.ser("e:" + File.separator + "test" + File.separator + "ser.text");
          } catch (Exception e) {
               e.printStackTrace();
          }
          //多个对象存储与读取
          Person[] p = {new Person("小红",19,77.7),new Person("小中",41,47.7),new Person("小天",29,7.7)};
          try {
               Ser.ser(p,"e:" + File.separator + "test" + File.separator + "ser.text");
          } catch (Exception e) {
               e.printStackTrace();
          }
    }
}
//创建一个人类,用来存储人类一些属性
class Person implements Serializable{ //序列化必须继承Serializable接口
    private String name;
    private transient int age;  //transient表示反序列化,用此关键字修饰的属性不会被整体存储与读取
    private double score;
    public Person(String name, int age, double score) {
          this.name = name;
          this.age = age;
          this.score = score;
    }
    public Person() {
    }
     public String getName() {
          return name;
    }
    public void setName(String name) {
          this.name = name;
    }
    public int getAge() {
          return age;
    }
    public void setAge(int age) {
          this.age = age;
    }
    public double getScore() {
          return score;
    }
     public void setScore(double score) {
          this.score = score;
    }
}
//创建一个序列化类
class Ser{
    //单个对象的存储与读取,需要一个参数:存储文件路径;重点:创建对象输出/输入流嵌套输出/输入流,调用write与read方法时要加Object
    public static void ser(String path) throws Exception{
          OutputStream os = new FileOutputStream(path); //创建输出流
          InputStream is = new FileInputStream(path);  //创建输入流
          ObjectOutputStream oos = new ObjectOutputStream(os); //创建对象输出流
          oos.writeObject(new Person("小明",18,89.8)); //开始存储,需要一个对象参数,存储文件内是乱码,只能通过对象输入流读取
          oos.close();//关流
          ObjectInputStream ois = new ObjectInputStream(is); //创建对象输入流
          Person p = (Person)ois.readObject(); //开始读取,返回的是对象,若要用子类接收要强转
          System.out.println(p.getName()+","+p.getAge()+","+p.getScore()); //输出读取内容
          ois.close(); //关流
    }
    //多个对象的存储与读取(重载),需要两个参数:对象数组及存储文件路径;重点:与单个存储相差不大,区别就在与读取时要用数组接收
     public static void ser(Person[] p,String path) throws Exception{
          OutputStream os = new FileOutputStream(path);
          InputStream is = new FileInputStream(path);
          ObjectOutputStream oos = new ObjectOutputStream(os);
          ObjectInputStream ois = new ObjectInputStream(is);
          oos.writeObject(p);
          oos.close();
          Person[] pp = (Person[])ois.readObject(); //返回对象数组
          for (Person ppp:pp){ //遍历数组
               System.out.println(ppp.getName()+","+ppp.getAge()+","+ppp.getScore());
          }
          ois.close();
    }
}
```
#获取类结构
```java
public class Reflect1 {
    public static void main(String[] args) {
          //通过Class获取类名,三种方式
          Class c1 = Person1.class; //方式一:通过类来获取  
          System.out.println(c1.getName());
          Class c2 = new Person1().getClass(); //方式二:通过实例来获取
          System.out.println(c2.getName());
          Class c3 = null;
          try {
               c3 = Class.forName("com.java.IO.Person1"); //方式三:通过全限定名(包名加类名)获取,此方法常用
               System.out.println(c3.getName());
               Person1 p = (Person1)c3.newInstance(); //通过Class类来创建对象(这里是无参构造),newInstance返回的是Object需要强转
               p.setAge(7);
               p.setName("掌上电脑");
               System.out.println(p.getName()+","+p.getAge());
               Constructor[] c = c3.getConstructors();  //获取构造函数,返回的是Constructor数组,顺序不确定,因此我们可以获取指定的构造函数
               Constructor c1 = c3.getConstructor(String.class,int.class); //获取两个参的构造函数
               System.out.println(c1);
               for (Constructor b : c){  //查看数组
                    System.out.println(b);
               }
               Person1 p1 = (Person1)c[1].newInstance("小明",25); //这里是有参构造
               System.out.println(p1.getName()+","+p1.getAge());
                Class[] c = c3.getInterfaces(); //获取其继承的所有接口,返回Class数组
               for (Class cc:c){
                    System.out.println(cc);
               }
               Class c = c3.getSuperclass(); //获取其父类
               System.out.println(c);
               Constructor[] cs = c3.getConstructors();
               for (int i = 0; i < cs.length; i++) {
                    Class[] c = cs[i].getParameterTypes();  //获取其构造函数的形参,返回Class数组
                    int i1 = cs[i].getModifiers();  //获取其构造函数的权限,返回整型,1代表public
                    System.out.println(Modifier.toString(i1)); //用Modifier的toString方法来还原权限
                    System.out.println(cs[i].getName()); //获取其构造函数名
                    for (Class cc:c){
                         System.out.println(cc);
                    }
               }
               Method[] m = c3.getMethods();  //获取其所有方法(包括其父类),返回Method数组
               System.out.println(c3.getMethod("setName",String.class)); //获取指定方法,若是此方法有重载就要指定形参了
               Method mm = c3.getDeclaredMethod("setName", String.class); //用反射调用方法
               Person1 p = (Person1)c3.newInstance();
               mm.invoke(p,"小明");  //mm.invoke()相当于p.setName()
               System.out.println(p.getName());
               for (Method mm:m){
                    System.out.println(mm); //输出方法名
                    System.out.println(mm.getName()); //输出方法名
                    Class[] c = mm.getParameterTypes(); //获取其方法的形参
                     for (Class cc:c){
                          System.out.println(cc);
                    }
               }
               Field[] f = c3.getDeclaredFields(); //获取其所有属性,返回Field数组
               for (Field ff:f){
                    System.out.println(ff.getName()); //获取属性名
               }
               Constructor cs = c3.getConstructor(String.class,int.class); //获取两个参的构造函数
               Person1 ps = (Person1)cs.newInstance("小明",18);
               Field f = c3.getDeclaredField("name"); //获取指定属性
               f.setAccessible(true);  //此方法参数为true时说明可以修改
     f.set(ps,"大明"); //修改ps的name属性
               System.out.println(ps.getName());
          } catch (Exception e) {
                    e.printStackTrace();
          }
    }
}
class A{}
class Person1 extends A implements Serializable,Cloneable{
    private String name;
    private int age;
    public String getName() {
         return name;
     }
    public void setName(String name) {
          this.name = name;
    }
    public int getAge() {
          return age;
    }
    public void setAge(int age) {
          this.age = age;
    }
    public Person1(String name){
          this.name = name;
    }
    public Person1(String name, int age) {
          this.name = name;
          this.age = age;
    }
    public Person1() {
    }
}
```
#反射的应用
* 完整的工厂设计模式
```java
public class Reflect2 {
    public static void main(String[] args) {
          try {
               Factory.produc("com.java.IO.Banana").eat();;
          } catch (Exception e) {
               e.printStackTrace();
          }
     }
}
//创建一个生产水果工厂,作用是可以生产各种水果
class Factory{
    public static Fruit produc(String name) throws Exception{
           return (Fruit)Class.forName(name).newInstance(); //根据传入的全限定名,用Class类创建对象,这么 做的好处是不用判断用户输入的什么水果
    }
}
//创建一个水果接口
interface Fruit{  
    void eat(); //抽象吃方法
}
//创建一个香蕉类继承水果接口并实现吃方法
class Banana implements Fruit{
    public void eat(){
          System.out.println("吃香蕉");
    }
}
//创建一个苹果类继承水果接口并实现吃方法
class Apple implements Fruit{
    public void eat(){
          System.out.println("吃苹果");
    }
}
//创建一个橘子类继承水果接口并实现吃方法
class Orange implements Fruit{
    public void eat(){
          System.out.println("吃橘子");
    }
}
```

你可能感兴趣的:(集合,流,序列化,工厂)