Java基础-高级特性-简单总结(I/O和反射机制)

    Java中按照流向分,分为输入流和输出流,按照处理数据单元分,分为字符流和字节流。这个总结开始会简单写一点方法,然后会写一下常用模板,套用就好了。

File类的常用方法:

方法说明
boolean exists( )测试文件是否存在
String getAbsolutePath( )返回此对象表示的文件的绝对路径
String getName( )返回此对象表示的文件的名称
String getParent( )返回此File对象的路径名的上一级,如果路径名没有上一级,则返回null
boolean delete( )删除此对象指定的文件
boolean createNewFile( )创建空文件,不创建文件夹
boolean isSirectory( )测试此File对象表示的是否为目录
boolean mkdir( )创建一个目录,它的路径名由当前File对象指定
boolean mkdirs( )创建包括父目录的目录

Java中的输出流主要由OutputStream和Write组成,输入流主要由InputStream和Reader作为基类。都是抽象类。

InputStream常用的子类有FileInputStream,用于从文件中读取数据。常用方法:

方法说明
int read( )从输入流中读取下一个字节数据
int read(byte [ ] b)从输入流中读取数据,并将数据存储在缓冲区数组b中,返回实际读取的字节数
int read(byte [ ] b,int off,int len)从输入流中读取最多len长度的字节,保存到字节数组b中,保存的位置从off开始
void close()关闭输入流

Reader类的常用子类有BufferedReader,接受Reader对象作为参数,并对其添加字符缓冲器。常用方法:

方法说明
int read( )从输入流中读取单个字符,返回所读取的字符数据
int read(byte [ ] c)从输入流中最多读取c.length个字符,保存到字符数组c中,返回实际读取的字符数
int read(char [ ] c,int off.int len)从输入流中读取最多len个字符,保存到字符数组c中,保存的位置从off开始,返回实际读取的字符数
void close( )关闭流

OutputStream类的常用子类为FileOutputStream,用于向文件写数据。常用方法:

方法说明
void weite( int c)将指定的字节数据写入此输出流中
void weite( byte [ ] buf)将数组buf中的所有字节写入此输出流中
void write(byte [ ] b,int off.int len)将字节数组中从偏移量off开始的长度为len的字节数据输出到输出流中
void close( )关闭输出流

Write类的常用子类为BufferedWriter,用于将数据缓冲到字符输出流。常用方法:

方法说明
void write( String str)将str字符串里包含的字符输出到指定的输出流中
void write( String str,int off,int len)将str字符串从off位置开始,长度为len的多个字符串输出到输出流中
void close( )关闭输出流
void flush( )刷新输出流

读写二进制文件:

    利用DataInputStream类读二进制文件,利用DataOutputStream类写二进制文件。

    顺带一提,这两个类搭配使用,可以按照与平台无关的方式从流中读取基本数据类型的数据,如int、float、double和boolean等,此外,DataInputStream的readUTF()方法能读取采用UTF-8字符集编码的字符串。同样,在向外输出时也遵循此规则,但是,方法中并没有readString( )和writeString( )方法

序列化和反序列化:

    序列化就是将对象的状态存储到特定存储介质中的过程,也就是将对象状态转换为可保持或可传输格式的过程。序列化后的对象保存的是二进制状态。

    Java中只有实现了java.io.Serializable接口的类的对象才能被序列化。

    反序列化是从特定存储介质中读取数据并重新构建成对象的过程。反序列化要进行强制类型转换。(如果一个可序列化的类,有多个父类(包括直接父类或间接父类),则这些父类要么是可序列化的,要么有无参数的构造器,否则会抛出异常)。对于一些不想被序列化的敏感信息,可以用transient来修饰。

    当需要序列化某个特定对象时,它的各个成员对象也必须是可序列化的。所有保存到磁盘中的对象都有一个序列号,当程序试图序列化一个对象时,会检查是否已经被序列化,只有序列化后的对象才能被转换成字节序列输出。如果对象已经被序列化,则程序直接输出一个序列化编号。序列化编号也是一个序列化后的对象,在反序列化时也得到一个对象。

通常用到输入输出时的写法:

    字节流:

        (输入流)FileInputStream fis =new FileInputStream( 路径 );

                    BufferedInputStream bis =new BufferedInputStream( fis );

        (输出流)FileOutputStream fos =new FileOutputStream(路径);

                    BufferedOutputStream bos =new BufferedOutputStream (fos);

     字符流:

            (输入)FileReader fd =new FileReader (路径);

                        BufferedReader br =new BufferedReader (fd);

            (输出)FileWriter fw =new FileWriter (路径) ;

                        BufferedWriter bw=new BufferedWriter (fw) ;

    转换格式时:

            (输入)FileInputStream fis =new FileInputStream (路径) ;

                    InputStreamReader isr =new InputStreamReader (fis,"格式") ;

                    BufferedReader br =new  BufferedReader (isr);

            (输出)FileOutputStream fos =new FileOutputStream (路径);

                        OutputStreamWriter osw =new OutputStreamWriter (fos,"格式") ;

                        BufferedWriter bw =new BufferedWriter (osw) ;

    二进制文件:

            (输入)FileInputStream fis =new FileInputStream (路径);

                    DataInputStream dis =new DataInputStream (fis) ;

            (输出)FileOutputStream fos =new FileOutputStream (路径) ;

                    DataOutputStream dos =new DataOutputStream (fos) ;

    序列化和反序列化:

            (序列化)FileOutputStream fos =new FileOutputStream (路径) ;

                        ObjectOutputStream oos =new ObjectOutputStream (fos) ;

            (反序列化)FileInputStream fis =new FileOutputStream (路径) ;

                        ObjectInputStream ois =new ObjectInputStream (fis) ;

        基本格式差不多就是这样了,最后一个很重要的点,开了的流记得关,先开的后关,后开的先关。

反射:

    反射这方面我的理解也并不是太深,就简单讲讲表面。

    Java的反射机制是Java的特性之一,反射机制是构建框架技术的基础所在。Java反射机制是指在运行状态中,动态获取信息以及动态调用对象方法的功能。Java反射有三个动态性质,分别是运行时生成对象实例,运行期间调用方法,运行时更改属性。

    通过Java反射,可以实现以下功能:

        在运行时判断任意一个对象所属的类;

        在运行时构造任意一个类的对象;

        在运行时判断任意一个类所具有的方法和属性;

        在运行时调用任意一个对象的方法;

    Java反射常用API:Class类,反射的核心类。Filed类,表示类的属性。Method类,表示类的方法。Constructor类,表示类的构造方法。

    Java程序中获得Class对象通常有如下三种方法:

        第一种:调用对象的getClass( )方法

       Student stu=new Student();
       Class cla=stu.getClass();
        第二种:调用类的class属性
       Class cla1=Student.class;
        第三种:使用Class类的forName( )静态方法
       Class cla2=Class.forName("某个类的全名");

        相比之下调用某个类的class属性来获取该类对应的Class对象这种方式更有优势。因为代码更安全,程序在编译阶段就可以检查需要访问的Class对象是否存在。而且程序性能更高,因为这种方式无需调用方法,所以性能更好。

    获得Class对象后,可以用Class对象获得该类里的成员,包括方法,构造方法以及属性,方法由Method表示,构造方法由Constructor表示,属性由Field表示。这个方法太繁杂了,我就不手打了,可以自己去看看API。

    结合两个例子来看看怎么用。

这是随手写的一个学生类。

public class Student{
    private String name;
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Student() {
    }
    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

使用Class对象创建一个该Class对象对应的对象,并直接获取name属性,然后修改name属性

try {
            Student stu=new Student();
            Class cla=stu.getClass();
            Field nameFiele=cla.getDeclaredField("name");
            nameFiele.setAccessible(true);
            nameFiele.set(stu,"熊大");
            System.out.println(stu.getName());
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

提一句,getField( )方法只能获取public访问权限的属性,而使用getDeclaredField( )方法则可以获取所有访问权限的属性。

使用Class对象创建一个该Class对象对应的对象,并操作对象里面设置姓名的方法,更改对象的姓名

       Student stu=new Student();
        Class cla=stu.getClass();
        try {
            Method nameMethod=cla.getMethod("setName",String.class);
            nameMethod.invoke(stu,"熊二");
            System.out.println(stu.getName());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

通过Method的invoke( )方法调用方法时,Java会要求程序必须有调用该方法的权限,如果程序确实需要调用某个对象的private方法,可以先调用setAccessible( )方法,将Method对象的accessible标志设置为指定的布尔值,值为true则代表该Method在使用时应该取消Java语言访问权限检查,值为false则表示该Method在使用时应该进行Java语言访问权限检查。

差不多就是这个样子吧,动态操作嘛~

关于反射的详细说明建议看看别的博客,我这里写的比较粗浅。

练习:

1.编写一个程序将file1.txt文件中的内容复制到file2.txt文件中。

        FileReader fd=null;
        BufferedReader br=null;
        FileWriter fw=null;
        BufferedWriter bw=null;
        try {
            fd=new FileReader("file1.txt");
            br=new BufferedReader(fd);
            fw=new FileWriter("file2.txt");
            bw=new BufferedWriter(fw);
            String s=null;
            while((s=br.readLine())!=null){
                bw.write(s);
                bw.newLine();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                bw.close();
                fw.close();
                br.close();
                fd.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

2.编写一个Java程序读取Windows目录下的win.ini文件,并输出内容。

FileReader fd=null;
        BufferedReader br=null;
        try {
            fd=new FileReader("c:\\Windows\\win.ini");
            br=new BufferedReader(fd);
            String line=br.readLine();
            while(line!=null){
                System.out.println(line);
                line=br.readLine();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                br.close();
                fd.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

3.编写一个程序,运行Java控制台程序,检测本地是否存在学生对象(反序列化),如果保存,则输出学生信息,如果没有保存,则通过学生类Student创建一个学生对象,将学生信息输出并保存到本地文件(序列化)中。

        FileInputStream fis=null;
        ObjectInputStream ois=null;
        FileOutputStream fos=null;
        ObjectOutputStream oos=null;
        Student stu=new Student();
        try {
            fis=new FileInputStream("d:\\stu.txt");
            if (fis.available()>0){
                ois=new ObjectInputStream(fis);
                stu=(Student)ois.readObject();
                System.out.println("本地有学生信息,学生信息为:");
                System.out.println("姓名:"+stu.getName());
                System.out.println("年龄:"+stu.getAge());
                System.out.println("性别:"+stu.getSex());
            }else{
                System.out.println("本地没有学生信息,自动添加一位学员信息");
                fos=new FileOutputStream("d:\\stu.txt");
                oos=new ObjectOutputStream(fos);
                stu=new Student(18,"张三",'男');
                oos.writeObject(stu);
                System.out.println("添加学员信息为:");
                System.out.println("姓名:"+stu.getName());
                System.out.println("年龄:"+stu.getAge());
                System.out.println("性别:"+stu.getSex());
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                if(null!=oos){
                oos.close();
                }
                if(null!=fos){
                    fos.close();
                }
                if(null!=ois){
                    ois.close();
                }
                if(null!=fis){
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
这个题的finally如果不判断是否开启了对应的流,会边运行边报错,虽然结果是对的,但是看起来不舒服,所以所有关闭流的时候建议都判断一下。




    
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值