流与反射

来源:互联网 发布:php就业方向 编辑:程序博客网 时间:2024/06/07 00:53
#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("吃橘子");
    }
}
```
1 0
原创粉丝点击