Java IO和反射机制

本文详细介绍了Java的I/O操作,包括File类、字节流、字符流、重定向标准I/O,以及序列化和反序列化。此外,深入探讨了反射机制,包括获取类信息、创建对象、访问属性和方法,以及动态创建和访问数组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java I/O和反射机制

一、操作文件或目录属性

1、File

File类构造方法

方法说明
File(String pathname)用指定的文件路径构造文件
File(String dir,String subpath)在指定的目录下创建指定文件名的文件
File(File parent,String subpath)根据一个文件对象和一个字文件构造文件对象

File类常用方法

方法说明
file.exists()判断文件是否存在
file.createNewFile()创建文件
file.delete()删除此对象指定的对象
file.getName()返回此对象表示的文件名
file.mkdir()创建目录(文件夹)
file.isFile()判断此对象是否是文件
file.isDirectory()判断此对象是否是目录
file.length()获取文件或目录的大小
file.getPath()获取文件或目录的路径
file.getAbsolutePath()获取文件或目录的绝对路径
file.getParent()返回此File对象的路径名的上一级,若无上一级则返回null

2、例

import java.io.File;
import java.io.IOException;

public class Demo01 {
	public static void main(String[] args) {
		//可以代表已有文件,也可以代表不存在的文件
		File file=new File("d:/abc");
		//创建此文件
		try {
			file.mkdirs();//创建目录
			file.createNewFile();//创建文件
		} catch (IOException e) {
			e.printStackTrace();
		}
		//删除此文件(彻底删除不过回收站)
		file.delete();
		//判断是否存在此文件
		boolean flag=file.exists();
		System.out.println(flag);	
	}
}

二、Java流

  • 读文件是指把文件中的数据读取到内存中。写文件是把内存中的数据写到文件中。

  • 通过流读写文件,流是一串流动的字符,是以先进先出的方式发送和接受数据的通道。

  • 流分为输入流和输出流,所谓的输入和输出是相对内存来说的。

  • 按照处理数据单元划分,流分为字节流和字符流。

  • 字符流在操作时使用了缓冲区,字节流在操作时直接操作文件,不使用缓冲区。

1、字节流:

  • 字节流是8位通用字节流,其基本单位是字节。
  • 字节流的基类是InputStream类和OutputStream类,他们都是抽象类。
  • 输入:InputStream,从文件中读取文字,多用其子类FileInputStream(文件输入流)。
  • 输出:OutputStream,向文件写数据,多用其子类FileOutStream(文件输出流)。

InputStream类的常用方法

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

OutputStream类的常用方法

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

2、字符流

  • 字符流是16位的Unicode字符流,基本单位是Unicode字符。
  • 字符流最适合用来处理字符串和文本,因为他们支持国际上大多数的字符集和语言。
  • 字符的的基类是Reader类和Writer类,他们都是抽象类。
  • 输入:Reader,常用子类BufferedReader,接受Reader对象作为参数,并对其添加字符缓冲器。
  • 输出:Writer,常用子类BufferedWriter,用于将数据缓冲到字符输出流。

Reader类的常用方法

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

Writer类的常用方法

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

3、读写文件

1)读写文本文件
①使用字节流读写文件
package section1;
/**
 * 使用字节流读取文本文件
 */
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

public class Demo02 {
	public static void main(String[] args) throws IOException {
		InputStream one=new FileInputStream("D:\\操作\\hello.txt");//创建流对象
		System.out.println("可读取的字节数:"+one.available());//获取对象字节数
		int date;//创建接受对象读取返回值的变量
		while((date=one.read())!=-1) {//循环读取流对象所关联的文本文件
			System.out.print((char)date+" ");//read()方法返回整数型,强制类型转换为字符型
		}
		one.close();//关闭流对象		
	}
}
  • **read()**方法返回整数,如果读取的是字符串,需进行强制类型转换。
  • 流对象使用完毕后需要关闭
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
 * 使用字节流向文本文件中写入数据
 *
 */
public class Demo03 {
	public static void main(String[] args) throws IOException {
		//创建对象流,以追加方式写入文件
		OutputStream two=new FileOutputStream("D:\\操作\\hello.txt",true);
		//创建要写入的字符串
		String str="好好学习,天天向上!";
		//将字符串加入缓冲区
		byte[] words=str.getBytes();
		//将缓冲区里的数据通过流写入文本文件
		two.write(words);
		//关闭流
		two.close();
	}
}
  • 在创建FileOutputStream实例时,如果相应文件并不存在,就会自动创建一个空的文件。
  • 如果对象表示的文件路径存在,但是代表一个文件目录,则会抛出FileNotFoundException类型异常。
  • 默认情况下,向文件写数据时将覆盖文件中原有的内容。
  • 若创建流对象的第二个参数为true,表示在文件末尾添加数据。
②使用字符流读写文件
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
 * 使用字符流读取文件内容
 *
 */
public class Demo04 {
	public static void main(String[] args) throws IOException {
		//创建流对象
		FileReader fr=new FileReader("D:\\操作\\hello.txt");
		BufferedReader br=new BufferedReader(fr);
		//读取一行数据,返回字符串
		String line=br.readLine();
		//输出读取的内容
		while (line!=null) {
			System.out.println(line);
			line=br.readLine();
		}
		//关闭流
		br.close();
		fr.close();
	}
}
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
/**
 * 使用字符流写入文件
 *
 */
public class Demo05 {
	public static void main(String[] args) throws IOException {
		//创建FileWirte对象,创建BufferedWirte对象
		FileWriter fw=new FileWriter("D:\\操作\\hello.txt",true);
		BufferedWriter bw=new BufferedWriter(fw);
		//写入内容
		bw.write("hello world!");
		bw.write("nonono");
		//换行
		bw.newLine();
		//写入内容
		bw.write("666");
		//换行
		bw.newLine();
		//写入内容
		bw.write("沙袋");
		//刷新缓冲区
		bw.flush();
		//关闭流
		bw.close();
		fw.close();
	}
}
2)读写二进制文件
  • 常见的文件读写中还有一种二进制文件读写。
  • 读写二进制文件的常用类有DataInputStreamDateOutputStream
①使用字节流读写文件
  • 利用DataInputStream读二进制文件与利用FileInputStream类读文件极其相似,也要用到FileInputStream类关联二进制文件。
②使用字符流读写文件

利用DataOutputStream读二进制文件与利用FileOutputStream类读文件极其相似,也要用到FileOutputStream类关联二进制文件。

例:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 读二进制文件
 * @author Administrator
 *
 */
public class Demo06 {
	public static void main(String[] args) throws IOException {
		//创建流对象
		FileInputStream fis=new FileInputStream("D:\\操作\\one.class");
		DataInputStream dis=new DataInputStream(fis);
		FileOutputStream fos=new FileOutputStream("D:\\操作\\two.class");
		DataOutputStream dos=new DataOutputStream(fos);
		int two;
		while ((two=dis.read())!=-1) {//读数据
			dos.write(two);//把读取的数据写入到two.class文件中
		}
		//关闭流
		fis.close();
		dos.close();
	}
}

三、重定向标准I/O

1、标准I/O

System.inSystem.out,他们是Java提供的两个标准输入/输出流,主要用于从键盘接受数据和向屏幕输出数据。

1)System.in常用方法:

int read():此方法从键盘接收一个字节的数据,返回值是该字符的ASCII码。

int read(byte []buf):此方法从键盘接收多个字节的数据,保存至buf中,返回值是接收字节数据的个数。

2)System.out常用方法:

print():向屏幕输出数据,不换行,参数可以是Java的任意数据类型。

println():向屏幕输出数据,换行,参数可以是Java的任意数据类型。

2、重定向

使用标准I/O对文件进行读写很方便,如果想要使用标准I/O对文件进行读写就需要重定向标准I/O,也就是说将标准I/O重定向到其他I/O的设备。

1)重定向标准I/O方法
方法说明
static void setErr(PrintStream err)重定向标准错误输出流
static void setIn(InputStream in)重定向标准输入流
static void setOut(PrintStream out)重定向标准输出流
2)例
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

/**
 * 重定向标准I/O
 * @author Administrator
 *
 */
public class Demo07 {
	public static void main(String[] args) throws FileNotFoundException {
		//创建PrintStream输出流
		PrintStream ps=new PrintStream(new FileOutputStream("D:\\操作\\hello.txt",true));
		//将标准输出流重定向到文件
		System.setOut(ps);
		//向文件中输出内容
		System.out.print("我的测试,重定向到文件666!");
	}
}

四、序列化

1、认识序列化

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

  • 序列化后可以将Java对象转化为字节流,再把字节流写入数据流,存储到存储介质(文件)中。

  • 序列化后的对象保存的是二进制状态,可以借助网络进行传输,在不同平台间进行传输,通过反序列化得到相同对象,无须担心数据因平台问题显示异常,实现了平台的无关性。

2、序列化保存对象信息

  • Java中只有实现了java.io.Serializable接口的类的对象才能被序列化。
  • Serializable表示可串行、可序列化的,序列化又称串行化。
  • String类、包装类、Data类都实现了Serializable接口。

例:

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

/**
 * 使用序列化将学生对象保存到文件中
 * @author Administrator
 *
 */
public class Demo08 {
	public static void main(String[] args) throws IOException {
		//创建对象输出流,包装了文件输出流	
		ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:\\操作\\hello.txt"));
		//创建对象
		Student stu=new Student("小明",18,"男");
		
//		//如要序列化多个对象,如下
//		Student stu1=new Student("小红",18,"女");
//		ArrayList<Student> list=new ArrayList<Student>();
//		list.add(stu);
//		list.add(stu1);
//		oos.writeObject(list);
		
		//对象序列化,写入输出流
		oos.writeObject(stu);
		oos.close();
	}
}

3、反序列化获取对象信息

  • 对象状态读取出来称为反序列化。
  • 反序列化是从特定存储介质中读取数据并重构对象的过程。
  • 如果向文件中使用序列化机制写入多个对象,那么反序列化恢复对象时,必须按照写入的顺序读取。
  • 如果一个可序列化的类,有多个父类(直接或间接),则这些父类要么是可序列化的,要么有无参数的构造器,否则会抛出异常。

例:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;

public class Demo09 {
	public static void main(String[] args) throws IOException, ClassNotFoundException {
		//创建ObjectInputStream输入流,包装文件输入流
		ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:\\操作\\hello.txt")); 
		
//		//如要将写入文件的集合反序列化,如下
//		//反序列化,强制类型转换
//		ArrayList<Student> list=(ArrayList<Student>)ois.readObject();
//		//输出集合中对象的信息
//		for (Student stu : list) {
//			System.out.println("姓名为:"+stu.getName());
//			System.out.println("年龄为:"+stu.getAge());
//			System.out.println("性别为:"+stu.getSex());
//		}
		
		//反序列化,进行强制类型转换
		Student stu=(Student)ois.readObject();
		//输出生成后的对象信息
		System.out.println("姓名为:"+stu.getName());
		System.out.println("年龄为:"+stu.getAge());
		System.out.println("性别为:"+stu.getSex());
		ois.close();	
	}
}

五、反射

1、认识反射

①Java反射机制是指在运行状态中,动态获取信息以及动态调用对象方法的功能。

②Java反射有3个动态性质:运行时生成对象实例、运行期间调用方法、运行时更改属性。

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

  • 在运行时判断任意一个对象所属的类。
  • 在运行时构造任意一个类的对象。
  • 在运行时判断任意一个类所具有的方法和属性。
  • 在运行时调用任意一个对象的方法。

④Java反射技术常用的类如下:

  • Class类:反射的核心类。
  • Field类:表示类的属性。
  • Method类:表示类的方法。
  • Constructor类:表示类的构造方法。

⑤在Java程序中使用反射的基本步骤:

  • 导入java.lang.reflect.*。
  • 获得需要操作的类的java.lang.Class对象
  • 调用Class的方法获取Field、Method等对象
  • 使用反射API进行操作

2、反射的应用

1)获取类的信息

①第一步,获取Class对象

  • 通过getClass()方法,得到该对象所属类的Class对象。

    (Class cla=stu.getClass()😉

  • 调用某个类的class属性得到该类对应的Class对象。*此方法最优

    (Class cla=Student.class;)

  • 使用Class类的forName()静态方法获取,该方法需传入字符串参数,该字符串参数是某个类的全名。

    (Class cla=Class.forName(“com.pd.jadv.reflection.Student”)😉

②第二部,从Class对象获取该类信息

  • 访问Class对象所对应类的构造方法的常用方法:
方法说明
Constructor getConstructor(Class[] params)返回此Class对象所包含的类的指定的public构造方法
Constructor[] getConstructor()返回此Class对象所包含的类的所有public构造方法
Constructor getDeclaredConstructor(Class[] params)返回此Class对象所包含的类的指定构造方法,与构造方法的访问级别无关
Constructor[] getDeclaredConstructor()返回此Class对象所包含的类的所有构造方法,与构造方法的访问级别无关
  • 访问Class对象所对应类的方法的常用方法:
方法说明
Method getMethod(String name,Class[] params)返回此Class对象所包含的类的指定的public方法
Method[] getMethods()返回此Class对象所包含的类的所有public方法
Method getDeclaredMethod(String name,Class[] params)返回此Class对象所包含的类的指定方法,与方法的访问级别无关
Method[] getDeclaredMethods()返回此Class对象所包含的类的全部方法,与方法的访问级别无关
  • 访问Class对象所对应类的属性的常用方法:
方法说明
Field getField(String name)返回此Class对象所包含的类的指定的public属性
Field[] getField()返回此Class对象所包含的类的所有public属性
Field getDeclaredField(String name)返回此Class对象所包含的类的指定属性,与方法的访问级别无关
Field[] getDeclaredField()返回此Class对象所包含的类的全部属性,与方法的访问级别无关
  • 访问Class对象所对应类的注解的常用方法:
方法说明
A getAnnotation(ClassannotationClass)试图获取该Class对象所表示类上指定类型的注解,如果该类型的注解不存在则返回null。
Annotation[] getAnnotations()返回此类上存在的所有注解
Annotation[] getDeclaredAnnotations()返回直接存在于此类上的所有注解
  • 访问Class对象所对应类的构其他信息的常用方法:
方法说明
Class[] getDeclaredClasses()返回该Class对象所对应类里包含的全部内部类
Class[] getDeclaringClass()访问Class对应的类所在的外部类
Class[] getInterfaces()返回该Class对象对应类所实现的全部接口
int getModifers()返回此类或接口的所有修饰符
Package getPackage()获取此类的包
String getName()以字符串形式返回此Class对象所表示的类的名称
String getSimpleName以字符串形式返回此Class对象所表示的类的简称
Class getSuperclass返回该Class所表示的类的超类对应的Class对象
2)创建对象

通过反射创建对象又两种方式:

①使用Class对象的newInstance()方法创建对象。

​ 此方法要求该Class对象的对应类有默认构造方法。

例:

package section1;

import java.util.Date;

import javax.xml.crypto.Data;

/**
 * 通过Class对象的newInstance()方法创建对象
 * @author Administrator
 *
 */
public class Demo10 {
	public static void main(String[] args) throws Exception{
		Class cla=Date.class;
		Date d=(Date)cla.newInstance();
		System.out.println(d.toString());	
	}
}
②使用Constructor对象创建对象。

​ 此方法要使用Class对象获取指定的Constructor对象,

​ 再调用Constructor对象的newInstance()方法创建该Class对象对应类的实例。

​ 此方式可以选择使用某个类的指定构造方法来创建实例。

例:

package section1;

import java.lang.reflect.Constructor;
import java.sql.Date;

/**
 * 利用Constructor对象指定的构造方法创建对象
 * @author Administrator
 *
 */
public class Demo11 {
	public static void main(String[] args) throws Exception{
		Class cla=Date.class;
		Constructor cu=cla.getConstructor(long.class);
		Date d=(Date)cu.newInstance(1987);
		System.out.println(d.toString());
	}
}
3)访问类的属性

通过Field对象可以对属性进行取值或赋值操作,方法如下:

方法说明
Xxx getXxx(Object obj)该方法中Xxx对应8个基本数据类型。obj为该属性所在的对象。
Object get(Object obj)得到引用类型属性值。
void setXxx(Object obj,Xxx val)将obj对象的该属性设置成val值。针对8个基本数据类型
void set(Object obj,object val)将obj对象的该属性设置成val值。针对引用类型赋值
void setAccessible(bool flag)对获取到的属性设置访问权限。参数为true,可对私有属性进行取值和赋值

例:

class Student{
	private String name;
    private int age;
    public String toString() {
		return "name is "+name +",age is "+age;
	}
}

import java.lang.reflect.Field;

public class Demo12 {
	public static void main(String[] args) throws Exception{
		//创建一个Student对象
		Student p=new Student();
		//获取Student对应的Class对象
		Class cla=Student.class;
		
		//获取Student类的name属性,使用getDeclaredField()方法可获取各种访问级别的属性
		Field nameField=cla.getDeclaredField("name");
		//设置通过反射访问该Field时取消权限检查
		nameField.setAccessible(true);
		//调用set()方法为p对象的制定Field设置值
		nameField.set(p, "Jack");
		
		//获取Student类的age属性,使用getDeclaredField()方法可获取各种访问级别的属性
		Field ageField=cla.getDeclaredField("age");
		//设置通过反射访问该Field时取消权限检查
		ageField.setAccessible(true);
		//调用setInt()方法为p对象的指定Field设置值
		ageField.setInt(p, 20);
		System.out.println(p);
	}
}
4)访问类的方法
  • 使用Method对象可以调用对象的方法。

  • 在Method类中包含一个invoke()方法,方法定义如下:

    Object invoke(Object obj,Object args)

    其中,obj是执行该方法的对象,args是执行该方法时传入该方法的参数。

例:

package section1;

import java.lang.reflect.Method;

public class Demo13 {
	public static void main(String[] args) throws Exception{
		//获取Student对应的Class对象
		Class cla=Student.class;
		//创建Student对象
		Student p=new Student();
		//得到setName方法
		Method met1=cla.getMethod("setName", String.class);
		//调用setName,为name赋值
		met1.invoke(p, "jack");
		
		//得到getName方法
		Method met=cla.getMethod("getName", null);
		//调用getName,获取name的值
		Object o=met.invoke(p, null);
		System.out.println(o);
 	}
}
5)使用Array类动态创建和访问数组

在java.lang.reflect包下还提供了一个Array类,此Array类的对象可以代表所有的数组。

程序可以通过使用Array类来动态的创建数组、操作数组元素等。

例:

package section1;
/**
 * 使用Array类动态操作数组
 */
import java.lang.reflect.Array;

public class Demo14 {
	public static void main(String[] args) {
		//创建一个元素类型为String,长度为10的数组
		Object arr=Array.newInstance(String.class,10);
		//依次为arr数组中index为5、6的元素赋值
		Array.set(arr, 5, "jack");
		Array.set(arr, 6, "john");
		//依次取出arr数组中index为5、6的元素的值
		Object o1=Array.get(arr,5);
		Object o2=Array.get(arr,6);
		//输出o1,o2的值
		System.out.println(o1.toString()+o2.toString());
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值