JavaSE IO,反射

IO

总共16个流

java.io.FileInputStream(掌握)
java.io.FileOutputStream(掌握)
java.io.FileReader
java.io.FileWriter

转换流(字节流->字符流)
java.io.InputStreamReader
java.io.OutputStreamWriter

缓冲流
java.io.BufferedInputStream
java.io.BufferedOutputStream
java.io.BufferedReader
java.io.BufferedWriter

数据流
java.io.DataInputStream
java.io.DataOutputStream

标准输出流
java.io.PrintWriter
java.io.PrintStream(掌握)

对象专属流
java.io.ObjectInputStream(掌握)
java.io.ObjectOutputStream

1、掌握

FileInputStream
FileOutputStream

应用

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
使用FileInputStream + FileoutputStream完成拷贝,一边读一边写
使用字节流拷贝的时候,文件类型不限
 */
public class CopyTest {
    public static void main(String[] args) {
        FileInputStream fis=null;
        FileOutputStream fos=null;
        try {
            //创建输入流
            fis=new FileInputStream("tempfile");
            //创建输出流
            fos=new FileOutputStream("C:\\Users\\Desktop\\java\\文件操作Test/tempfile");
            byte[] bytes=new byte[100*1024];
            int readCount=0;
            while((readCount= fis.read(bytes))!=-1){
                fos.write(bytes,0,readCount);
            }
            //输出流最后要刷新
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //分开try/catch相互不影响
            if(fos!=null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fis!=null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

ObjectInputStream

ObjectOutputStream

涉及序列化和反序列化
应用:
Student类

import java.io.Serializable;

public class Student implements Serializable {
    //Java虚拟机看到Serializable接口之后会自动生成一个序列化版本号
    //这里没有手动写出来,Java虚拟机会默认提供这个序列化版本号
    //序列化版本号
    private int no;
    private String name;

    public Student() {
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}

序列化
序列化也需刷新和关闭

import com.dhjavacode.java.Student;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

/*
Java对象从内存中放入硬盘中:序列化(Serialize)
    因为不能一次直接把整个对象放过去,所以会分块,也就有了序列
Java对象从硬盘恢复到内存中:反序列化
    因为内一块都有编号,能组装回去(DeSerialize)

ObjectOutputStream 负责序列化
ObjectInputStream 负责反序列化

参与序列化和反序列化的对象必须实现Serializable接口
public interface Serializable{
}
这个接口什么代码都没有,,其标识作用,Java虚拟机看到后会提供序列化版本号
 */
public class ObjectoutputStreamTest {
    public static void main(String[] args) throws Exception {
        Student stu1=new Student(1111,"zhangsan");
        //序列化,序列化到文件students
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("students"));
        //序列化对象
        //**参与序列化对象所属类必须实现Serializable接口
        oos.writeObject(stu1);

        //刷新
        oos.flush();
        //关闭
        oos.close();
    }
}

2、了解

FileReader

文件输入流,只能读普通文本,读取文本内容方便
用法和FileInputStream相似

FileWriter

文件输出流,只能写普通文本
用法和FileOutputStream相似
输出完成之后也需调用.flush()方法

PrintWriter
PrintStream

默认输出到控制台(再看视频)
----------------------------------------------------------------分割线----------------------------------------------------------

File

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class FileTest01 {
    public static void main(String[] args) throws IOException {
        File f1=new File("D:/javacode/file");
        System.out.println(f1.exists());//判断文件是否存在,当有file文件时返回true
        //如果不存在,则以文件的形式创建
        if(!f1.exists())f1.createNewFile();
        //如果不存在,则以目录的形式创建。若上一层目录也不存在,则不会创建。
        if(!f1.exists())f1.mkdir();
        //多重目录新建
        File f2=new File("D:/javacode/a/b/c");
        if(!f2.exists())f1.mkdirs();

        //常用方法
        File f3=new File("D:/javacode/a/b/c");
        //获取文件父路径
        String parentPath=f3.getParent();
        System.out.println(parentPath);
        //获取父文件
        File f4=f3.getParentFile();
        //获取绝对路径
        System.out.println(f4.getAbsoluteFile());
        File f5=new File("D:/javacode/file");
        //获取文件名
        System.out.println("文件名"+f5.getName());

        //判断是否是目录
        System.out.println(f5.isDirectory());
        //判断是否是文件
        System.out.println(f5.isFile());

        //最后一次修改时间
        long haoMiao=f5.lastModified();//获取毫秒是从1970.1.1到现在的总毫秒
        Date time = new Date(haoMiao);
        System.out.println(time);
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        String sdTime =sdf.format(time);
        System.out.println(sdTime);

        //获取文件字节大小
        System.out.println(f5.length());

        //listFiles返回当前目录下所有子目录,返回File[] listFiles()
        File f6=new File("D:/javacode");
        File[] files=f6.listFiles();
        for(File ff:files){
            System.out.println(ff.getName());
        }
    }
}
注:多重目录是在已有的最后一位文件里创建
若将多重目录写成.mkdir()则不会创建任何也不会报错

应用:带目录文件拷贝

import java.io.*;

public class CopyAll {
    public static void main(String[] args) {
        //拷贝源
        File srcFile=new File("C:\\Users\\代涵\\Desktop\\java");

        //拷贝目标
        File desFile=new File("D:\\javacode\\CopyTest");

        copyDir(srcFile,desFile);
    }
    /*
    srcFile 拷贝源
    desFile 拷贝目标
     */
    private static void copyDir(File srcFile, File desFile) {
        if(srcFile.isFile()) {
            //如果是文件,一边读一边写
            FileInputStream in = null;
            FileOutputStream out=null;
            try {
                //读文件
                in=new FileInputStream(srcFile);
                String path=desFile.getAbsolutePath().endsWith("\\")?desFile.getAbsolutePath()+srcFile.getAbsolutePath().substring(20):desFile.getAbsolutePath()+"\\"+srcFile.getAbsolutePath().substring(20);
                out=new FileOutputStream(path);
                byte[] bytes=new byte[1024*1024];
                int readCount=0;
                while((readCount=in.read(bytes))!=-1){
                    out.write(bytes,0,readCount);
                }
                out.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(out!=null) {
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(in!=null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            return;
        }
        //获取源下的子目录
        File[] files=srcFile.listFiles();
        for(File file:files){
            if(file.isDirectory()){
                //System.out.println(file.getAbsoluteFile());
                //源C:\Users\代涵\Desktop\java
                //目标D:\javacode\CopyTest
                String srcDir=file.getAbsolutePath();
                System.out.println(srcDir.substring(20));
                String desDir=desFile.getAbsolutePath().endsWith("\\")?desFile.getAbsolutePath()+srcDir.substring(20):desFile.getAbsolutePath()+"\\"+srcDir.substring(20);
                System.out.println(desDir);
                File newFile=new File(desDir);
                if(!newFile.exists()){
                    newFile.mkdirs();
                }
            }
            //递归
            copyDir(file,desFile);
        }
    }
}

反射机制

重点是通过反射机制获取并修改属性和调用方法

作用:

通过Java语言的反射机制可以操作字节码文件。可读可修改。操作代码片段
包:java.lang.reflect.*

反射机制相关重要类:

    java.lang.Class:代表这个字节码,代表一个类
    java.lang.reflect.Method:代表字节码中的方法字节码
    java.lang.reflect.Constructor:代表字节码中的构造方法字节码
    java.lang.reflect.Field:代表字节码中的属性字节码

获取类操作

要操作一个类的字节码,需要首先获取这个类的字节码。三种方式:

1、Class.forName(); 静态方法
2、实例.getClass()方法
3、实例.class属性
package com.javacode.reflect;
import java.util.Date;
public class ReflectTest1 {
    public static void main(String[] args) throws Exception {
        /*
        Class.forName()
            1、静态方法
            2、参数是字符串
            3、字符串需要是完整的类名
            4、完整类名必须带有包名,java.lang包也不能省略
         */
        Class c1=Class.forName("java.lang.String");
        Class c2=Class.forName("java.util.Date");
        Class c3=Class.forName("java.lang.Integer");
        Class c4=Class.forName("java.lang.System");


        //Java中任何一个对象都有一个方法叫做getClass()
        String s="asd";
        Class x=s.getClass();//x代表String.class字节码文件,x代表String类型
        System.out.println(c1==x);//true


        //Java中任何一种类型,包括基本数据类型,都是有.class属性的
        Class z=String.class;
        Class k= Date.class;
        
    }
}

反射机制实例化对象

通过反射机制可以更灵活的创建对象

package com.javacode.reflect;
/*
获取到Class能做什么:更灵活的创建对象。
 */
public class ReflectTest2 {
    public static void main(String[] args) throws ClassNotFoundException {
        //通过反射机制获取Class,通过Class实例化对象
        Class c=Class.forName("com.javacode.reflect.User");
        try {
            //返回对象,执行无参构造。** .newInstance()方法底层调用无参构造
            Object o=c.newInstance();
            System.out.println(o);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

灵活创建例子:
通过Properties配置文件创建实例

package com.javacode.reflect;

import java.io.FileReader;
import java.util.Properties;

public class ReflectTest3 {
    public static void main(String[] args) throws Exception {
        FileReader reader=new FileReader("src\\com\\javacode\\reflect\\classname.Properties");
        Properties pro=new Properties();

        pro.load(reader);
        //load()方法可以传入FileReader对象也可以FileInputStream对象
        reader.close();

        String classname= pro.getProperty("classname");

        Class c=Class.forName(classname);
        Object o=c.newInstance();
        System.out.println(o);
    }
}

获取Filed 属性

package com.javacode.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/*
Field
反射TStudent类中的Field
 */
public class ReflectTest5 {
    public static void main(String[] args) throws Exception {
        Class studentClass=Class.forName("com.javacode.bean.Student");
        String className=studentClass.getName();
        System.out.println(className);//com.javacode.bean.Student 完整类名(带包名)
        String classSimpleName=studentClass.getSimpleName();
        System.out.println(classSimpleName);//Student 简类名


        //获取类中所有Field
        Field[] fields=studentClass.getFields();
        System.out.println(fields.length);//1
        Field f=fields[0];
        System.out.println(f.getName());//age
        //注:.getFields()方法只能获取public修饰的属性

        System.out.println("===================================");
        Field[] fields2=studentClass.getDeclaredFields();
        System.out.println(fields2.length);//4
        for(Field ff:fields2){
            //获取修饰符
            int i=ff.getModifiers();//返回一个数字,这个数组是修饰符代号
            System.out.println(i);
            //将代号数字转换成字符串
            String modifier=Modifier.toString(i);
            System.out.println(modifier);

            //获取属性类名
            System.out.println(ff.getType().getName());
            //获取简单名
            System.out.println(ff.getType().getSimpleName());

            //获取属性名
            System.out.println(ff.getName());
        }
        //注:.getDeclaredFields()方法能获取全部属性
    }
}
反射机制中的Field

获取Field

package com.javacode.reflect;
//通过反射机制反编译一个类的属性Field

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class ReflectTest6 {
    public static void main(String[] args) throws Exception {
        StringBuffer s=new StringBuffer();

        Class studentClass=Class.forName("com.javacode.bean.Student");

        s.append(Modifier.toString(studentClass.getModifiers())+"class " +studentClass.getSimpleName()+"{\n");

        Field[] fields=studentClass.getDeclaredFields();

        for(Field ff:fields){
            s.append("\t");
            //修饰符
            s.append(Modifier.toString(ff.getModifiers()));
            s.append(" ");
            s.append(ff.getType().getSimpleName());
            s.append(" ");
            s.append(ff.getName()+";\n");

        }

        s.append("}");
        System.out.println(s);
    }
}

通过反射机制给属性赋值及获取属性值

package com.javacode.reflect;

import java.lang.reflect.Field;

/*
怎么通过反射机制
    给属性赋值
    获取属性值
 */
public class ReflectTest7 {
    public static void main(String[] args) throws Exception {
        //通过反射机制,访问一个对象的属性
        Class studentClass=Class.forName("com.javacode.bean.Student");
        //获取要操作的属性
        Object o=studentClass.newInstance();//Student对象,调无参构造
        //获取属性,获取属性靠属性名区分
        Field noField=studentClass.getDeclaredField("no");
        //给o对象的no属性赋值
        noField.set(o,2222);//给o对象的no属性赋值2222
        //获取o对象no的值
        System.out.println(noField.get(o));

        //访问私有属性
        //获取要操作的属性
        Field nameField=studentClass.getDeclaredField("name");
        nameField.set(o,"jack");
        System.out.println(nameField.get(o));//无法访问private修饰的
        
        //非得访问就需要打破封装,这样设置完,在外部可以访问private
        nameField.setAccessible(true);
        nameField.set(o,"jack");
        System.out.println(nameField.get(o));//无法访问private修饰的
    }
}

反射机制中的Method

获取method

package com.javacode.reflect;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/*
反射Method
 */
public class ReflectTest8 {
    public static void main(String[] args) throws Exception{
        //获取类
        Class userClass=Class.forName("com.javacode.service.UserService");
        //获取所有Method,包括私有
        Method[] methods=userClass.getDeclaredMethods();
        System.out.println(methods.length);//2

        for(Method m:methods){
            //获取修饰符列表
            System.out.println(Modifier.toString(m.getModifiers()));
            //获取返回值类型
            System.out.println(m.getReturnType().getSimpleName());
            //获取方法名
            System.out.println(m.getName());
            
            //获取参数列表
            Class[] parameterTypes=m.getParameterTypes();
            for(Class p:parameterTypes){
                System.out.println(p.getSimpleName());
            }
        }
    }
}

通过反射机制调对象方法

package com.javacode.reflect;
import com.javacode.service.UserService;
import java.lang.reflect.Method;
/*
重点,通过反射机制调对象方法
 */
public class ReflectTest10 {
    public static void main(String[] args) throws Exception {
        //不使用反射机制调方法
        UserService user=new UserService();
        boolean login=user.login("admin","123");
        System.out.println(login);

        //使用反射机制调用对象的方法
        Class userServiceClass=Class.forName("com.javacode.service.UserService");
        //创建对象
        Object o=userServiceClass.newInstance();
        //获取Method,不仅要方法名,还需要参数列表
        Method loginMethod=userServiceClass.getDeclaredMethod("login",String.class,String.class);


        //调用方法,4要素:userServiceClass的对象o、方法名login、实参列表、返回值
        /**最重要
         * loginMethod是方法名
         * o是对象
         * "admin","123"是实参
         * oback是返回值
         */
        Object oback=loginMethod.invoke(o,"admin","123");
        System.out.println(oback);
    }
}

获取构造函数

不太重要
注:不含方法体

package com.javacode.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;

/*
反编译一个类的Constructor方法
 */
public class ReflectTest11 {
    public static void main(String[] args) throws Exception{
        StringBuilder s=new StringBuilder();
        Class vipClass=Class.forName("com.javacode.bean.Vip");
        s.append(Modifier.toString(vipClass.getModifiers()));
        s.append(" class ");
        s.append(vipClass.getSimpleName());
        s.append("{\n");
        //拼接构造方法
        Constructor[] constructors=vipClass.getDeclaredConstructors();
        for(Constructor c:constructors){
            s.append("\t");
            s.append(Modifier.toString(c.getModifiers()));
            s.append(" ");
            s.append(vipClass.getSimpleName());
            s.append("(");
            //拼接参数
            Class[] parameterTypes=c.getParameterTypes();
            for(Class p:parameterTypes){
                s.append(p.getSimpleName());
                s.append(",");
            }
            //删除多余的逗号
            if(s.charAt(s.length()-1)==',')s.deleteCharAt(s.length()-1);
            s.append("){}");
            s.append("\n");
        }
        s.append("}");
        System.out.println(s);
    }
}

通过反射机制获取父类和实现的接口

package com.javacode.reflect;
/*
重点:给定一个类,怎么获取父类,以及实现了哪些接口
 */
public class ReflecTest14 {
    public static void main(String[] args) throws Exception{
        //String举例
        Class stringClass=Class.forName("java.lang.String");
        //获取父类
        Class superClass=stringClass.getSuperclass();
        System.out.println(superClass.getName());

        //获取String类实现的所有接口
        Class[] interfaces=stringClass.getInterfaces();
        for(Class i:interfaces){
            System.out.println(i.getSimpleName());
        }

    }
}

注:

1、Class.forName(“完整类名”)方法 会使这个类的静态代码块执行。如果只是希望一个类的静态代码块执行,可以使用这个方式。
---------------------------------------------------------------------分割线----------------------------------------------------------

路径

以下写法的code移植性差

FileReader reader=new FileReader(“src\com\javacode\reflect\classname.Properties”);

可移植路径:

关于类加载器:
定义:专门负责加载类的命令/工具
ClassLoader
JDK带有三个类加载器:
父:启动类加载器:加载jre\lib\rt.jar 最核心
母:扩展类加载器:加载jre\lib\ext*.jar
应用类加载器:加载classpath中的jar包

优先级(双亲委派机制):父、母、应用类

package com.javacode.reflect;
import java.io.InputStream;
import java.util.Properties;

/*
研究路径
 */
public class AboutPath {
    public static void main(String[] args) throws Exception {
        //这种路径移植性差,在IDEA中默认的路径是当前project的根
        //FileReader reader=new FileReader("src\\com\\javacode\\reflect\\classname.Properties");

        /*通用路径(前提是:文件必须在类路径下也就是在src下)
        Thread.currentThread()当前线程对象
        .getContextClassLoader()线程对象的方法,获取当前线程类加载器对象
        .getResource("") [获取资源] 类加载器对象方法,当前线程的类加载器默认从类的根路径下加载资源

        */
        String path =Thread.currentThread().getContextClassLoader()
                .getResource("classname2.Properties").getPath();
        System.out.println(path);
        //以上代码可以拿到文件的绝对路径

        //获取db.Properties绝对路径。从类的根路径下开始
        String path2=Thread.currentThread().getContextClassLoader()
                .getResource("com/javacode/reflect/db.PRoperties").getPath();
        System.out.println(path2);

        
        //也可以直接以流的形式返回
        InputStream reader=Thread.currentThread().getContextClassLoader()
                .getResourceAsStream("classname2.Properties");
        Properties pro=new Properties();
        pro.load(reader);
        String classname=pro.getProperty("classname");
        System.out.println(classname);
    }
}

更先进的路径获取:

(资源属性文件)

package com.javacode.reflect;
import java.util.ResourceBundle;
/*
java.util包下提供了资源绑定器,便于获取属性配置文件的内容
使用以下方式的时候,属性配置文件xxx.properties必须放到类路径下
 */
public class ResourceBundleTest {
    public static void main(String[] args) {
        //资源绑定器只能绑定xxx.properties文件。并且这个文件只能在src路径下。文件扩展名也必须是properties
        //在写路径时,扩展名不写
        ResourceBundle bundle=ResourceBundle.getBundle("classname2");
        String classname=bundle.getString("classname");
        System.out.println(classname);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值