#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("吃橘子");
}
}
```