java反射机制,流和注解

反射机制

java程序完整的跑出来有两个时期:编译期和运行期。

编译期就是把java文件编译为可执行代码,就是把java文件变为class文件。

运行期就是把编译后的文件交给计算机执行。

反射机制就是在运行期中,对于任意一个类或者任意一个对象,都能够知道它的属性和方法,这种动态获取信息及调用方法称为反射机制。

java反射机制在服务器程序和中间件程序有很多运用,在服务器端根据客户的请求动态的调用某个对象的放啊,在ORM中间件的实现中,运用java反射机制可以读取任意一个javaBean的所有属性,或者给这些属性赋值

反射可访问类或者对象的常用信息

 getPackage 获取类的路径

 getName 获取类的名称

 getSuperclass 获取该类的子类

 getInterface 获取该类实现的所有接口

 getConstructors 获取所有权限为public的构造方法

 getDerclaredContruectors 获取当前对象所有的构造方法

 getMethods 获取所有权限为public的方法

 getDeclaredMethods 获取当前对象的所有方法

 getFields 获取所有权限为public的成员变量

 getDeclareFields 获取当前对象的所有成员变量

 getClasses 获取所有权限为public的内部类

 getDeclaredClasses 获取所有内部类

 getDeclaringClass 如果该类为内部类,返回它的成员类

java反射机制能够在运行时动态的获取类的实例,有很大的灵活性,但是反射会消耗一定的系统资源,而且会忽略掉权限检查,获取这个类的私有方法和属性,影响封装性而导致的安全问题。

反射机制Api

java.lang.reflect和java.lang.Class这两个类,是反射机制的关键

### java.lang.class Class类是实现反射的关键,Class类的一个实例表示java的一种数据类型,包括,类,接口,枚举,注解,基本数据类型。Class没有公有的构造方法,Class的实例是jvm在类的加载时自动创建的。

java public class RefleCtion { public static void main(String [] args){ Class cle1=String.class; //获取类的class String cre2="str".getClass(); //获取对象的class System.out.println(cle1.getName()); //获取类名称 System.out.println(cle1.isPrimitive());//是否为基本类型 } }

java.lang.reflect

reflect提供了反射中要用到的类

Constructor 提供类的构造方法
Field 提供类或接口中成员变量信息
Method 提供类或接口成员方法信息
Array 提供了动态创建和访问java数组的方法
Modifier 提供类和成员访问修饰符信息

```java import java.lang.reflect.Modifier;

public class RefleCtion { public static void main(String [] args){ try{ Class c=Class.forName("java.lang.String"); Method[] methods=c.getDeclaredMethods();//获取成员方法 for(Method method:methods){ System.out.println(Modifier.toString(method.getModifiers())); System.out.println(method.getName()); } }catch (ClassNotFoundException e){ System.out.println(e); } } } ```

反射访问构造方法

为了能够动态获取对象构造方法的信息,我们需要创建一乐Constructor类型的对象或数组

class.

   getConstructors
   getConstructor
   getDeclaredConstructors
   getDeclaredConstructor 

   这些方法都可以创建Constructor的对象或数组

如果是访问指定的构造方法,需要根据该构造方法的入口参数的类型来访问,

```java // 访问构造方法 import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier;

public class RefleCtion { public static void main(String [] args){ Integer a=1123; Class c=a.getClass(); try { Constructor e=c.getDeclaredConstructor(int.class); System.out.println(e.isVarArgs()); //该构造方法是否允许带可变参数 System.out.println(e.getParameterAnnotations()); //按照声明顺序,返回一个Class数组,里边是参数的类型 System.out.println(e.getExceptionTypes()); System.out.println(e.newInstance(1)); System.out.println(e); } catch (NoSuchMethodException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } } ```

访问到构造方法之后,我们相当于获取到了一个Constructor类,

Constructor的常用方法 isVarArgs 查看该构造方法时候允许带可变数量的参数

getParameterTypes 按照声明顺序以Class数组的形式获取该构造方法各个参数的类型

getExceptionTypes 以Class数组的形式获取该构造方法可能抛出的异常类型

newInstance(params) 通过该构造方法利用指定的参数创建一个该类型的对象,如果未设置参数则表示采用默认无参的构造方法

setAccessiable 如果该构造方法的访问权限为private默认不允许通过反射利用newInstance方法创建对象,如果先执行该方法,并将入口参数设置为true则允许创建对象

getModifiers 获取可以解析出该构造方法所采用修饰符的整数

通过getModifires获取到modifier之后我们可以通过Modifier类的方法查看一些信息

isStatic 是否静态方法
isPublic 
isProtected
isPrivate
isFinal
toString

```java //访问构造方法实战 import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier;

public class RefleCtion { public static void main(String [] args) { Class book=Book.class; Constructor[] declaredConstructor=book.getDeclaredConstructors(); //获取到Constructor,获取到所有的构造方法 for(int i=0;i

try {
                    if(i ==1){
                        //这里因为构造方法是protected 会抛出异常到catch,通过执行setAccessible开通权限创建对象
                    books=(Book) con.newInstance("哈哈",1);
                    }else if(i == 2){
                      books=(Book) con.newInstance();
                    }else{
                        // 通过执行可变数量参数的构造方法实例化books
                        Object[] parameters = new Object[] { new String[] { "100", "200" } };
                        books = (Book) con.newInstance(parameters);
                    }
                } catch (Exception e) {
                    System.out.println("在创建对象时拋出异常,下面执行 setAccessible() 方法");
                    con.setAccessible(true);
                }

        }
        books.print();
    }
}

}

class Book{ private String name; private int id,price; private Book(){} protected Book(String name,int id){ this.name=name; this.id=id; } public Book(String ...strings) throws NumberFormatException{ if(strings.length<0){ id=Integer.valueOf(strings[0]); } if(strings.length<1){ price=Integer.valueOf(strings[1]); } } public void print() { System.out.println("name=" + name); System.out.println("id=" + id); System.out.println("price=" + price); } } ```

反射访问方法

要动态获取一个对象的方法,需要创建一个Method类型的对象或者数组

getMethods
  getMethods
  getDeclaredMethos
  getDeclaredMethods 

  这些方法可以获取到Method对象或者数组

Method的常用方法

 getName 方法名称

 getParameterType 按照声明顺序,以Class数组的形式返回当前方法的各个参数类型

 getReturnType 获取当前方法的返回值类型 ,(class对象形式)。

 getExceptionTypes  class数组形式返回该方法可能抛出的异常

 invoke(Object obj,Object...args) 利用args参数执行指定对象obj中的该方法,返回值为Object类型

 isVarArgs 查看该方法是否允许带有可变数量的参数
 getModifiers

```java import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier;

public class RefleCtion { public static void main(String [] args) { Book books=new Book(); Class class1=books.getClass();//获取到calss Method[] methods=class1.getDeclaredMethods();//获取到所有的方法 for(int i=0;i * * * * * ***方法名称是"+method.getName()); System.out.println("是否带有可变参数"+method.isVarArgs()); Class[] methodType = method.getParameterTypes();//获取到所有的参数类型 for (int j = 0; j < methodType.length; j++) { System.out.println(" " + methodType[j]); } System.out.println("该方法的返回值类型是"+method.getReturnType()); Class[] errors=method.getExceptionTypes();//获取到所有的异常 for(int j=0;j

class Book{ static void staticMethod(){ System.out.println("Static作用域方法"); } public int publicMethod(int i){ System.out.println("public作用域方法"); return i+1; } protected int proctedMethod(String s,int i)throws NumberFormatException{ System.out.println("protected作用域方法"); return Integer.valueOf(s)+i; } private String privateMethod(String ...strings){ System.out.println("private作用域方法"); StringBuffer s=new StringBuffer(); for(int i=0;i

反射访问成员变量

访问成员变量需要一个Field类型的对象或者数组

getFields
getField
getDeclaredFields
getDeclaredField

 通过这些方法可获取到Field类型的对象或数组


  常用方法

   getName

   getType 获取成员变量的Class对象

   get(obj) 获取去指定对象obj中成员变量的值

   set(obj,value) 将指定obj中成员变量的值修改为value

   getInt(obj) 获取指定对象obj中成员类型为int的成员变量的值

   setInt(obj,value) 将指定对象obj中成员变量的值设置为value

   setFloat(obj,value)

   getFloat(obj)

   getBoolean(obj)

   setBoolean(obj,value)

   setAccessible(true) 

   getModifiers

```java import java.lang.reflect.*;

public class RefleCtion { public static void main(String [] args) { Book book=new Book(); Class class1=book.getClass(); Field[] fields=class1.getDeclaredFields();//获取到所有的成员变量 for(int i=0;i< fields.length;i++){ Field field=fields[i]; System.out.println("**********成员名称"+field.getName()); Class filedType=field.getType(); System.out.println("成员类型"+filedType); boolean state=true; while(state == true){ try{ state=false; System.out.println("修改前成员的值为:" + field.get(book)); if(filedType.equals(int.class)){ System.out.println("利用setInt()方法修改成员的值"); field.setInt(book, 100); }else if(filedType.equals(String.class)){ System.out.println("利用set"); field.set(book,"哈哈"); }else if(filedType.equals(Boolean.class)){ System.out.println("利用boolean"); field.setBoolean(book,true); } System.out.println("修改后成员的值为"+field.get(book)); }catch (Exception e){ System.out.println("访问到了ptrivate权限的变量"); field.setAccessible(true); state=true; } } } } }

class Book{ public String name; private int age; protected boolean sex; } ```

反射操作数组

### 通过反射创建一个数组 ```java import java.lang.reflect.*; import java.util.Arrays;

public class RefleCtion { public static void main(String [] args) { String [] vals={"11","22","33"};//数组的值 String cName="java.math.BigInteger";//数组的类型 try { Class arrClass=Class.forName(cName); //创建数组的Class Object o=Array.newInstance(arrClass,vals.length);//初始化一个数组对象 //获取长整形的构造器 Constructor bigInt=arrClass.getConstructor(String.class); for(int i=0;i

class Book{ public String name; private int age; protected boolean sex; } ```

Io

Io就是java的输入输出流,因为变量集合等东西程序结束就会消失,为了能够永久的保存数据,将数据保存到磁盘里所以我们需要输入输出流。 ## java的流 在java中所有数据都是用流读写的,根据流向的不同可以分为input输入流和output输出流。 ## input输入流 java流相关的类都在java.io里,而且每个数据流都是一个对象。所有输入流都是InputStream(字节输入)抽象类和Reader(字符输入)抽象类的子类。

InputStream类中所有方法遇到错误时都会引发IoException异常

   InputStream的常用方法

   read 从输入流读入一个8字节的数据,将它转换为0-255的整数,返回一个整数,结束返回-1。

   read(byte[] b) 从输入流读取若干字节的数据保存到参数b指定的字节数组中,返回的字节数表示读取的字节数,结束返回-1

   read(byte[] b,int off,int len) 从输入流读取若干字节的数据保存到b指定的字节数组中,off是开始保存数据的下标,len是读取字节的位数,返回的是实际读取的字节数,结束返回-1。

   close 关闭数据流

   available 返回可以从数据源读取的数据流的位数

   skip(n) 从输入流跳过参数n指定的字节数目

   markSupported 判断输入流是否可以重复读取

   mark(limit) 如果可以重复读取,从流当前的位置开始标记,limit指定可以设置标记的字节数

   reset 使输入流重新定位到刚才标记的位置,这样可以读取标记过的数据

   最后三个方法一般会结合使用,先判断是否可以重复读取,然后使用mark进行标记,标记完后使用read读取,使用reset重新定位到标记,重复读取

InputStream是用来处理字节的,处理文本时可以使用Reader类。方法与InputStream类似

输出流

java的所有输出流都是OutputStream(字节)抽象类和Writer(字符)抽象类的子类

常用方法

   write 将指定字节的数据写入到输出流

   write(byte [] b) 将指定数组b写入到输出流

   writr(byte bn,start,end) 将字节数组b从start下标,到end下标的内容写入到输出流

   close 关闭输出流

   flush 刷新输出流,强行将缓冲区的内容写入输出流

系统流

每一个java程序运行的时候都有一个系统流,系统流对应的类是java.lang.System。System类对应三个流

System.in 输入流
System.out 输出流
System.error 错误流

```java //输入流 import java.io.IOException;

public class StreamDemo { public static void main(String [] args){ byte [] bytes=new byte[100]; System.out.println("请输入英"); try { System.in.read(bytes); } catch (IOException e) { e.printStackTrace(); } System.out.println("输入的内容如下"); for(int i=0;i

System.out和System.error是PrintStream的对象 */ ```

字符编码

计算机中任何文字都是以编码的形式存在的,java开发中最常见的是

ISO8859-1 单字节编码,最多只能表示0-255的字节范围

 GBK/GB2312 中文编码,属于双字节编码,GBK可以表示繁体中文/简体中文,GB2312只能表示简体中文


 Unicode  一种编码规范,Utf-8和Utf-16就是这种规范的一种实现,java内部使用的就是Unicode编码

 UTF  UTF编码兼容了ISO8859-1,同样也可以用来表示所有的语言字符。

在程序中,如果不处理好编码问题就容易出现乱码,

java public class StreamDemo { public static void main(String [] args){ System.out.println("系统默认的编码是"+System.getProperty("file.encoding")); } } //系统的默认编码

File类

File类是java.io包中唯一代表的磁盘对象,就是说操作文件都需要通过File类。但是File不能访问文件内容,文件内容还需要输入输出流。

File构造方法

  File(path); path是目录路径则File是目录,path是文件则File是文件

  File(path,name); 路径名,文件名,File是路径

  File(File dir,name) 
  路径对象,文件名


 File对象的方法

   canRead 判断程序是否能从指定的文件中读取内容。

   canWrite 判断当前文件是否能被程序写入内容

   delete 删除当前对象的文件

   exists 判断当前File是否存在

   getAbsoultePath 获取当前File的绝对路径

   getName 获取当前File的文件名或路径

   getParent 获取父目录

   isAbsoulte 判断当前File是否是一个绝对路径

   isDirectory 判断当前File是否是一个路径

   lastModified 获取当前File的最后修改时间

   length 获取当前File的长度

   list 获取指定路径的文件列表

   list(FilenameFilter) 返回满足过滤器的文件列表

   mkdir 创建一个文件夹,路径由当前的File决定

    renameTo(File) 修改文件的名称


   常量
      File.separator  一个路径的分隔符

      pathSeparator 多个路径的分隔符

```java import java.io.File; import java.io.IOException; //访问文件属性 public class StreamDemo { public static void main(String [] args){ String path="D:\index.txt"; // 路径 File indexTxt=new File(path);//创建File System.out.println(indexTxt.isAbsolute()); //是否是绝对路径 System.out.println("是否可读取:\t"+(indexTxt.canRead()?"是":"否")); System.out.println("是否可写入:\t"+(indexTxt.canWrite()?"是":"否")); System.out.println("文件是否存在\t"+(indexTxt.exists()?"是":"否")); System.out.println("文件名"+indexTxt.getName()); System.out.println("父级目录"+indexTxt.getParent()); indexTxt.delete(); } }

```

java //修改和删除文件 public class StreamDemo { public static void main(String [] args){ String path="D:"+File.separator+"index.txt"; // 路径 File indexTxt=new File(path);//创建File if(indexTxt.exists()){ indexTxt.delete(); } try { indexTxt.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } } /* 文件的路径的分隔符一定要使用常量, */ ```java //创建和删除目录 public class StreamDemo { public static void main(String [] args){ String path="D:"+File.separator+"config"+File.separator; // 路径 File indexTxt=new File(path);//创建File if(indexTxt.exists()){ indexTxt.delete(); //目录有则先删除 }else{ indexTxt.mkdir(); //创建新目录 System.out.println("config目录创建完成"); }

}

} ```

遍历目录

File类的list方法提供了遍历目录的方法。

```java //不设置过滤器的方法 public class StreamDemo { public static void main(String [] args){ String path="D:"+File.separator; // 路径 File Dp=new File(path); System.out.println("文件名称\t\t 文件类型\t\t文件字节\t\t"); String [] filelist=Dp.list(); for(int i=0;i

}
}

} java //设置过滤器的方法 public class StreamDemo { public static void main(String [] args){ String path="D:"+File.separator; // 路径 File Dp=new File(path); String [] fileList= Dp.list(new FileFilter()); for(int i=0;i

RandomAccessFile

RandomAccessFile类是用来动态读取文件的内容。动态读取是指从文件的任意位置访问文件,而不是必须从文件的开头读到结尾。

RandomAccessFile对象提供了一个记录指针,用来标识当前读写的位置,我们可以自由移动指针。

常用方法

readBoolean 从文件中读取一个boolean值

readByte 从文件中读取一个带符号位的字节

readChar 从文件中读取一个字符

readint 从文件中读取一个带符号位的整数

readLong 从文件中读取一个带符号位的long值

readLine 从文件中读取下一行文本

seek 指定从文件起始位置开始的指针偏移量

writeBoolean 以字节的形式向文件中写入一个Boolean值

writeByte 以单字节的形式向文件中写入一个byte值

writeChar 以双字节的形式向文件中写入一个char值

writeInt 以4字节的形式写入一个整数

writeBytes 以8字节的形式写入一个字符串

skipBytes 以当前文件指针为起始点,跳过n字节

RandomAccessFile的构造方法

RandomAccessFile(file,mode); mode一般是两个值'r' 只读 或者 'rw' 读写

```java //动态读写 public class StreamDemo { public static void main(String [] args) { String path="D:"+File.separator+"index.txt"; // 路径 File indexTxt=new File(path); if(indexTxt.exists()){ // 存在则先删除再创建 indexTxt.delete(); } String demo="刘能,王老七,王大拿,谢大脚,谢广坤,宋晓锋";//要写入的内容 RandomAccessFile raf=null; try {

indexTxt.createNewFile();
        raf=new RandomAccessFile(indexTxt,"rw");//读写文件
        String demo2=new String(demo.getBytes("GBK"),"ISO-8859-1");//因为是中文,编码转换
        raf.writeBytes(demo2); //写入文件
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    try {
        System.out.println("当前指针的位置\t\t"+raf.getFilePointer());
        //移动指针的位置
        raf.seek(6);
        byte[] buffer = new byte[2];
        int len = 0;
        while ((len = raf.read(buffer, 0, 2)) != -1) {
            System.out.print(new String(buffer, 0, len,"GB2312")); // 输出文件内容
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

} ```

字节流(InputStream)

InputStream是java所有字节输入流的父类,OutoutStream是java所有字节输出流的父类。 它们都是一个抽象类,所以继承他们的子类要重新定义父类中的抽象方法。

### 字节输入流

InputStream的子类

  ByteArrayInputStream  将字节数组转换为字节输入流,从中读取字节

  FileInputStream 从文件中读取数据

  PipedInputStream 连接到一个PipedOutputSream(管道输出流)

  SequenceInputStream 将多个字节输入流串联晨成一个字节输入流

  ObjectInputStream 将对象反序列化

使用InputStream类的方法可以从流中读取一个或者一批字节

常用方法


   read 从输入流中读取一个8位的字节,并把它转换为一个0-255的整数,最后返回整数,

   read(byte [] b) 从输入流中读取若干字节,并把它们保存到参数b指定的字节数组中,返回读取的字节数

   read(byte [] b,start,len) 读取若干字节,将他们保存在b字节数组中,start是开始保存位置的下标,len是指定读取的字节数

   close 关闭输入流

   avaliable 返回可以从输入流中读取的字节数

   skip(long n) 从输入流跳过指定n个字节,返回跳过的字节数

   mark 从输入流的当前位置开始设置标记

   markSupported 判断当前输入流是否允许设置标记

   reset 将输入流的指针返回到设置标记的起始处

   使用mark和reset方法时需要判断文件系统是否支持这两个方法

字节输出流

OutputStrem类及其子类的对象表示一个字节输出流

子类

    ByteArrayOutputStream 向内存缓冲去的字节数组中写数据

    FileOutputStream 向文件中写数据

    PipedOutputStreamj 连接到一个PipedIntputStream(管道输出流)

    ObjectOutputStream 将对象序列化

    常用方法

     write 向输出流中写入一个字节,

     write(byte [] b) 把参数b的字节数组写入到输出流中

     write(byte[] b,start,len) 把参数b的字节数组的若干字节写入到输出流中,start表示数组中的开始下标,len是元素个数

     close 关闭输出流,写操作完成之后应该关闭输出流,系统将会释放与这个输出流相关的资源

     flush 在向输出流写入数据时,数据一般会先保存到内存缓冲区中,只有当缓冲区的数据达到一定程度时,缓冲区的数据才会写入输出流中,使用flush会强制将缓冲区写入输出流,并清空缓冲区

字节数组输入流

ByteArrayStream可以从内存的字节数组中读取数据。

ByteArrayInputStream的输入流

  ByteArrayInput(byte [] b);

   创建一个字节字节数组输入流,其中字节字节数组类型的输入源有参数b指定

   ByteArrayInputStream(byte [] byf,start,len) 创建一个字节数组输入流,数据由参数b指定,start是从数组开始的位置,len是元素个数

```java public class StreamDemo { public static void main(String [] args) { byte [] b=new byte[]{1,-1,25,-22,-5,23}; ByteArrayInputStream arrStream=new ByteArrayInputStream(b); int i=arrStream.read(); //读取下一个字节 while(i != -1){ System.out.println("原值="+(byte) i +"int="+i); i=arrStream.read(); } } }

```

字节数组输出流

ByteArrayOutputStream可以向内存的字节数组中写入数据

构造方法

    ByteArrayOutputStream () ; 创建一个字节数组输出流,输出缓冲区的初始容量大小为32字节

    ByteArrayOutputStream(size) 创建一个字节数组输出流,缓冲区大小由size指定

java byte [] b=new byte[]{1,-1,25,-22,-5,23}; ByteArrayOutputStream bias=new ByteArrayOutputStream(); bias.write(b,2,3); System.out.println("写入到数组中共"+bias.size()+"个元素"); byte [] newbyteArr=bias.toByteArray();//转换为字节数组 System.out.println(Arrays.toString(newbyteArr));

文件输入流

FileInputStream是java流中比较常用的一种,表示从文件系统的某个文件中获取输入字节。创建FileInputStream要构造时,要用异常处理,因为可能找不到文件会爬出FileNotFoundExceprtion java //读取本地文件 public class StreamDemo { public static void main(String [] args) { String path="D:"+File.separator+"learnANDstudy"+File.separator+"JavaStudyInit"+File.separator+"bibao.java"; File file=new File(path); FileInputStream fis=null; try { fis =new FileInputStream(file); byte[] bytes=new byte[1024]; int n=0;//实际获取的字节数 while((n=fis.read(bytes)) != -1){ String s=new String(bytes,0,n); System.out.println(s); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { throw new RuntimeException(e); }finally{ try { fis.close();//关闭输入流 System.out.println("资源已经关闭"); } catch (IOException e) { e.printStackTrace(); } } } } /* FileInputStream 重写了父类InputStream的read方法,skip方法,available方法和close方法,不支持mark方法和reset方法 */

文件输出流

FileOutputStream继承自OutputStream类,重写了父类的所有方法,创建FileOutputStream对象时,如果指定的文件不存在,则会创建新文件,存在则清除文件的内容再重新写入。

构造方法

   FileOutputStream(file); 创建一个文件输出流,参数file指定目标文件

   FileOutputStream(file,boolean) 创建一个文件输出流,file是目标文件,boolean如果是true则将数据添加到文件内容的末尾,如果是false则清除原文件的内容

```java import java.io.*; import java.nio.charset.StandardCharsets; import java.util.Arrays;

public class StreamDemo { public static void main(String [] args) { String inputPath="D:"+File.separator+"learnANDstudy"+File.separator+"JavaStudyInit"+File.separator+"bibao.java"; String outputPath="D:"+File.separator+"index.txt"; File inputFile=new File(inputPath); File outputFile=new File(outputPath); FileInputStream fis=null; FileOutputStream fos=null; try { fis =new FileInputStream(inputFile); fos=new FileOutputStream(outputFile); byte[] bytes=new byte[1024]; int n= fis.read(bytes); while(n != -1){ fos.write(bytes,0,n); n=fis.read(bytes); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { throw new RuntimeException(e); }finally{ try { fis.close();//关闭输入流 fos.close();// 关闭输出流 System.out.println("资源已经关闭"); } catch (IOException e) { e.printStackTrace(); } } } }

```

字符流

尽管字节流的功能很强大,可以处理任何类型的io操作,但是却不能直接操作16位的Unicode字符,这旧需要用到字符流

字符输入流

Reader类是所有字符流输入类的父类

子类

  CharArrayReader 将字符数组转换为字符输入流,从中读取字符

  StringReader 将字符串转换为字符输入流,从中读取字符

  BufferedReader 为其他字符输入流提供读缓冲区

  PipedReader 连接到一个PipeWriter

  InputStreamReader 将字节输入流转换为字符输入流,可以指定字符编码

  常用方法

   Reader类里也有close,mark,skip,reset等方法。

   read() 读取一个字符并转换为0-65535的整数

   read(char [] b) 从输入流中读取若干个字符,并保存到b数组中

   read(char [] b,start,length) 从输入流中读取若干个字符保存到b数组中,start表示b数组的开始下标,length是元素个数

字符输出流

Writer是所有字符输出流的父类

子类

   CharArrayReader 将字符数组转换为字符输入流,从中读取字符

   StringReader 将字符串转换为字符输入流

   BufferedReader 为其他字符输入流提供读缓冲区

   PipedReader 连接到一个PipedReader

   OutputStreamReader 将字节输出流转换为字符输出流

   常用方法

    Write类也有close,flush等方法

    write() 向输出流中写入一个字符

    write(char [] b) 将字符数组b写入到输出流中

    write(char [] b,start,len) 把字符数组的若干字符写入到输出流中,start是字符数组的开始下标,len表示元素个数

    write(String str) 向输出流中写入一个字符串

    write(String str,start,len) 向输出流中写入字符串str的部分字符,start是开始下标,len是元素个数

    append(c) 将参数c指定的字符添加到输出流中

    append(charSequence esq) 将参数esq指定的字符序列添加到输出流中

    append(charSequence esq,start,end) 将参数esq指定的字符序列的从strat开始至end结束的子序列添加到输出流中


    Write的所有方法在出错的情况下都会引发IOException异常,关闭一个流后再对其进行任何操作都会产生错误

字符文件输入流

java给提供了,用来读取字符文件的类,FileReader类。

创建FileReader读取对象时,默认的字符编码以及字节缓冲区的大小都是系统设定的,要自己指定这些值,可以自己在FileInputStream上构造一个InputStreamReader

```java import java.io.*; import java.nio.charset.StandardCharsets; import java.util.Arrays;

public class StreamDemo { public static void main(String [] args) { String inputPath="D:"+File.separator+"learnANDstudy"+File.separator+"JavaStudyInit"+File.separator+"bibao.java"; File files=new File(inputPath); FileReader fileReader=null; int i=0; try { fileReader=new FileReader(files); while((i=fileReader.read()) != -1){ System.out.println((char) i); //转化为字符 } } catch (IOException e) { e.printStackTrace(); }finally { try { fileReader.close(); } catch (IOException e) { e.printStackTrace(); } } } }

```

字符文件输出流

字符文件输出流FileWrite类

构造方法

   FileWrite(file)

   FileWriter(file,append)  append如果为true则写入到文件末尾

```java import java.io.*; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Scanner;

public class StreamDemo { public static void main(String [] args) { String outputPath="D:"+File.separator+"index.txt"; File files=new File(outputPath); FileWriter fileWriter=null; Scanner input=new Scanner(System.in); try { fileWriter=new FileWriter(files); for(int i=0;i<5;i++){ System.out.println("请输入第"+(i+1)+"个字符串"); String str=input.next(); fileWriter.write(str); } } catch (IOException e) { e.printStackTrace(); }finally { try { fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } }

```

字符缓冲区输入流

BufferedReader 类主要用于辅助其他字符输入流,它可以将一批数据读到内存缓冲区,然后接下来旧可以从内存缓冲区获取数据,提高效率。

构造方法
 BufferedReader(Reader in) 创建一个Buffered来修饰in指定的字符输入流

 BufferedReader(Reader in,int size) 创建一个BufferReader来修饰参数in指定的字符输入流,参数size则用于指定缓冲区的大小

 readLine()方法,用于获取一行文本的内容。

```java public class StreamDemo { public static void main(String [] args) { String outputPath="D:"+File.separator+"index.txt"; File files=new File(outputPath); FileReader fileReader=null; BufferedReader bufferedReader=null; try { fileReader =new FileReader(files); bufferedReader=new BufferedReader(fileReader); String str=""; while( (str=bufferedReader.readLine()) != null){ System.out.println(str); } } catch (IOException e) { throw new RuntimeException(e); }finally {

try {
            bufferedReader.close();
            fileReader.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

} ```

字符缓冲区输出流

BufferWriter类主要用于辅助其他字符输出流,带有缓冲区,可以先将数据写入缓冲区,当缓冲区满了之后将数据一次性写入文件。

构造方法

    BufferedWriter(Writer out) 创建一个BufferWriter来修饰参数out指定的字符输出流

    BufferedWrite(Writer out ,int size) 创建一个BufferedWriter来修饰参数out指定的字符输出流,size用于指定缓冲区的大小

    newLine() 写入一个换行分割符

字节流和字符流的区别

字节流在操作时,没有用到内存缓冲区,直接就是对文件的读写操作。

字符流在操作时用到了内存缓冲区,通过内存缓冲区再操作文件。

转换流

使用字节流可以对所有的数据进行操作,但是操作,有些数据字符流比字节流要更方便,所有java提供了转换流

InputStreamReader用于将字节输入流转换为字符输入流。OutputStream用于将字节输出流转换为字符输入流

```java public class StreamDemo { public static void main(String [] args) { String outputPath="D:"+File.separator+"index.txt"; /* 因为index.txt文件全都是中文,所以使用字节读取的时候,可能会出现解码错误,所以要将字节流转换为字符流 */ File files=new File(outputPath); FileInputStream fileInputStream=null; InputStreamReader inputStreamReader=null; try{ fileInputStream=new FileInputStream(files); inputStreamReader =new InputStreamReader(fileInputStream,"UTF-8"); //将字节流转换为字符流,并设置编码 int b=0; while((b = inputStreamReader.read()) != -1){ System.out.println((char) b); } }catch (IOException e){ e.printStackTrace(); } } }

```

java public class StreamDemo { public static void main(String [] args) { String outputPath="D:"+File.separator+"index.txt"; File files=new File(outputPath); //将普通的键盘输入转换为,字符输入流,再将字符输入流,转换为缓冲区,最后整行输出 InputStreamReader inputStreamReader=new InputStreamReader(System.in); //转换为Buffer BufferedReader br=new BufferedReader(inputStreamReader); String line=null; try { while((line = br.readLine()) !=null){ if(line.equals("exit")){ //exit退出 System.exit(1); } System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }

利用对象序列化进行IO操作

序列化是指把java对象变成二进制内容,本质上就是一个byte [] 数组。为什么要把java对象序列化,因为序列化后可以把byte [] 数组保存到文件中,然后把byte数组通过网络传输到远程,这样旧相当于把java对象存储到文件里,或者通过网络传输过去了。

有了序列化,旧有了反序列化,可以把byte数组,再转换为java对象

序列化

把一个java对象转换为byte 数组,需要用到ObjectOutputStream

```java public class StreamDemo { public static void main(String [] args) { //创建一个字节数组输出流 Students s=new Students(); ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream=null; try{ objectOutputStream=new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(s); objectOutputStream.writeInt(1); } catch (IOException e) { e.printStackTrace(); }finally { try { objectOutputStream.close(); } catch (IOException e) { throw new RuntimeException(e); } } System.out.println(Arrays.toString(byteArrayOutputStream.toByteArray())); } }

class Students implements java.io.Serializable{ // 一个类的实例化对象要进行序列化

// 那么这个类一定要实现java.ioSerializable 这个接口
public String name;

} ```

反序列化

ObjectInputStream用于从一个字节流,读取java对象

```java ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(byteArrayOutputStream.toByteArray()) ;

//反序列化

    try {
        ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);
        try {
            Students a=(Students) objectInputStream.readObject();
            System.out.println(a.name);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }

```

java的序列化机制可以导致一个实例能直接从byte数组创建,而不经过构造方法,因此存在安全隐患,更好的序列化方法是通过json来实现。 可实现序列化的对象必须实现java.io.Serializable接口,反序列化时不调用构造方法。

```java //文件输入输出demo import java.io.*; import java.nio.charset.StandardCharsets; import java.sql.Struct; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Scanner;

public class StreamDemo { public static void main(String [] args) { List arrList=new ArrayList(); Book book1=new Book("小红帽",1,22.5); Book book2=new Book("托马斯",2,26.5); arrList.add(book1); arrList.add(book2); Book.write(arrList); Book.read(); } }

class Book{ public String name; public int id; public double price; public Book(String name,int id,double price){ this.name=name; this.id=id; this.price=price; }

@Override
public String toString() {
    return "图书编号:\t\t"+this.id+"\t\t图书名称:\t\t"+this.name+"\t\t图书单价:\t\t"+this.price+"\n";
}
//写入方法
public static void write(List list){
String  path = "D:"+File.separator+"index.txt";
File files=new File(path);
    FileOutputStream fileOutputStream=null;
    try {
        fileOutputStream=new FileOutputStream(path);
        for(int i=0;i< list.size();i++){
            fileOutputStream.write(list.get(i).toString().getBytes());
        }
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }finally {
        try {
            fileOutputStream.close();
            System.out.println("写入成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
public static void read(){
    String  path = "D:"+File.separator+"index.txt";
    File files=new File(path);
    FileReader fileReader=null;
    BufferedReader bufferedReader=null;
    try {
        fileReader=new FileReader(files);
        bufferedReader=new BufferedReader(fileReader);
        String str="";
        while((str = bufferedReader.readLine()) != null){
            System.out.println(str);
        }
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }finally{
        try {
            fileReader.close();
            bufferedReader.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

}

```

注解

注解并不是注释,注解是代码里的特殊标记,这些标记可以在编译,类加载和运行时被读取。 注解并不能改变程序的运行结果,也不会影响程序运行的性能。但是有些注解可以在编译时给用户提示/警告

基本注解: 
  @Overrride,@Deprecated,@SuppressWarnings,@SafeVarargs,@Functionallnterface

@Override

@Override注解是用来只当方法重写的,并且修饰方法之呢个用于方法重写

java class Demo { @Override public String toString(){return ""} } 这里是重写了Object类的toString方法,使用@Override注解。 @Override的作用是告诉编译器检查这个方法,保证父类要包含一个被该方法冲洗的方法。

@Deprecated

@Deprecated 用来注解类,接口,属性,方法等。表示某个方法已经被废弃。 当使用被废弃的元素时,编译器将会给出警告。 java @Deprecated class Demo{} //当我们去实例化Demo这个类的时候,将会出现删除线

@SuppressWarnings

@SuppressWarnings 注解表示,被该注解修饰的类及其子类,曲线显示的编译器警告。 @SuppressWarnings 主要用于取消一些编译器产生的警告对代码左侧的遮挡,影响我们打断点。

抑制单类型的警告

      @SuppressWarnings("关键字')

      多类型
     @SuppressWarnings("关键字","关键字")


    关键字    用途

    all  抑制所有警告

    boxing 抑制装箱,拆箱操作时候的警告

    cast 抑制映射相关的警告

    dep-ain 一直启用注释的警告

    deprecation 抑制被废弃方法使用的警告

    fallthrough 抑制在switch中缺少breaks的警告

    finally 抑制finally模块没有返回的警告

    hiding 抑制相对于隐藏变量的局部变量的警告

    incomplete-switch 忽略不完整的switch语句

    nls 忽略费nls格式的字符

    null 忽略对null的操作

    synthetic-access 抑制子类没有按最优方法访问内部类的警告

    unchecked 抑制没有进行过类型检查操作的警告

    unqualified-field-access 抑制没有权限访问的域的警告

    unused 抑制没被使用过的代码的警告

@FunctionalInterface

@FunctionalInterface用来表示一个接口是函数式接口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值