流与反射

from:流与反射


#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("吃橘子");
    }
}