Java常用工具_IO流
异常概述
即非正常情况,通俗地说,异常就是程序出现的错误
异常的分类(Throwable)
异常(Exception)
合理的应用程序可能需要捕获的问题 举例:NullPointerException
错误(Error)
合理的应用程序不应该试图捕获的问题 举例:StackOverFlowError
异常的处理方式
异常的处理方式
JVM默认的异常处理方式:在控制台打印错误信息,并终止程序
开发中异常的处理方式
try…catch(finally):捕获,自己处理
try {
// 尝试执行的代码
} catch(Exception e) {
// 出现可能的异常之后的处理代码
} finally {
// 一定会执行的代码,如关闭资源
}
/* 方式一: 捕获, 自己处理. try..catch..finally
特点: 处理完异常之后, 程序会继续执行.
执行流程:
先执行try{}中的内容, 看是否有问题(异常)
没有: 直接执行finally语句中的内容.
有: 跳转到catch(){}语句中开始执行, 再执行finally{}语句中的内容.*/
throws:抛出,交给调用者处理
public void 方法名() throws Exceptoin {
}
/* 异常处理方式二: throws: 抛出异常, 交给调用者处理.
特点: 执行结束后, 程序不再继续执行.
*/
public class Test {
public static void main(String[] args) {
try { //尝试要执行的代码
int a = 10 / 0;
System.out.println(a);
} catch (Exception e) { //出现问题后的代码(解决方案)
System.out.println("被除数不能为0");
return;
} finally { //即使try, catch中有return, finally里边的代码也会执行.
System.out.println("看看我执行了吗?");
}
// System.out.println("看看我执行了吗?");
}
}
被除数不能为0
看看我执行了吗?
public class Test2 {
public static void main(String[] args) throws Exception { //方案一(异常处理方式二: throws)
// show(); //因为show()方法已经抛出了一个异常, 作为调用者(main函数)必须处理这个异常.
//方案一: 接着抛.
show(); //打印出异常,程序不往下进行
//方案二: 采用try.catch处理.
/*try{
show();
}catch (Exception e){
System.out.println("代码出问题了!");
}*/
System.out.println("看看我执行了吗?");
}
//定义一个方法
public static void show() throws Exception {
int a = 10 / 0;
System.out.println("a: " + a);
}
}
Exception in thread "main" java.lang.ArithmeticException: / by zero
at cn.itcast.demo7.Test2.show(Test2.java:27)
at cn.itcast.demo7.Test2.main(Test2.java:16)
多个异常分别处理:
try {
// 尝试执行的代码
} catch(异常A e) {
// 出现可能的异常之后的处理代码
} catch(异常B e) {
// 出现可能的异常之后的处理代码
} finally {
// 一定会执行的代码,如关闭资源
}
finally代码块:
可以省略(不能和catch部分同时省略) finally代码之前若有return语句,先执行return语句,再执行finally代码
块,最后返回return的结果
方法重写:
子类方法不能比父类方法抛出更大的异常
IO流概述
I/O,即输入(Input)输出(Output),是Java中用来传输数据的方式。IO流指的是数据像连绵的流体一样进行传输。
在本地磁盘或网络上传输(读/写)数据
按数据流向分:
输入流 输出流
按操作方式分:
字节流: InputStream OutputStream
字符流:Reader Writer
字节流: 以字节为单位来操作数据.
InputStream: 字节输入流的顶层抽象类.
FileInputStream: 普通的字节输入流.
BufferedInputStream: 高效的字节输入流(也叫: 字节缓冲输入流)
OutputStream: 字节输出流的顶层抽象类.
FileOutputStream: 普通的字节输出流.
BufferedOutputStream: 高效的字节输出流(也叫: 字节缓冲输出流).
字符流: 以字符为单位来操作数据.
Reader: 字符输入流的顶层抽象类.
FileReader: 普通的字符输入流.
BufferedReader: 高效的字符输入流(也叫: 字符缓冲输入流)
Writer: 字符输出流的顶层抽象类.
FileWriter: 普通的字符输出流.
BufferedWriter: 高效的字符输出流(也叫: 字符缓冲输出流)
File类
文件,文件夹,一个File对象代表磁盘上的某个文件或文件夹
构造方法:
File(String pathname)
File(String parent, String child)
File(File parent, String child)
成员方法:
createNewFile():创建文件
mkdir()和mkdirs():创建目录
isDirectory():判断File对象是否为目录
isFile():判断File对象是否为文件
exists():判断File对象是否存在
getAbsolutePath():获取绝对路径
从本地磁盘开始的路径
举例:C:\Users\itcast\Desktop
getPath():获取文件的相对路径
相对某一位置的路径
Java项目中,相对路径从项目名开始
getName():获取文件名
list():获取指定目录下所有文件(夹)名称数组
listFiles():获取指定目录下所有文件(夹)File数组
public class Test3 {
public static void main(String[] args) throws IOException {
// 构造方法:
//需求: 将 D:\abc\1.txt 封装成File对象.
//方式一: 根据字符串形式的路径获取File对象.
//File file1 = new File("D:\\abc\\1.txt");
File file1 = new File("D:/abc/1.txt");
System.out.println("file1: " + file1);
//方式二: 根据字符串形式的父目录以及子目录创建File对象.
File file2 = new File("D:/abc/", "1.txt");
System.out.println("file2: " + file2);
//方式三: 根据父目录对象, 以及字符串形式的子目录来获取File对象.
File file3 = new File("D:/abc/");
File file4 = new File(file3, "1.txt");
System.out.println("file4: " + file4);
// 测试创建功能(如果不存在就创建, 返回true, 否则就不创建, 返回false.)
//需求: 在d:盘下创建 2.txt文件
File file5 = new File("d:/2.txt");
boolean flag1 = file5.createNewFile();
System.out.println("flag1: " + flag1);
//需求: 在D:盘下创建 a文件夹
File file6 = new File("D:/a");
boolean flag2 = file6.mkdir(); //make directory, 创建单级目录
System.out.println("flag2: " + flag2);
//需求: 在D:盘下创建 a/b/c文件夹
File file7 = new File("D:/a/b/c");
boolean flag3 = file7.mkdirs(); //创建多级目录(也可以创建单级目录)
System.out.println("flag3: " + flag3);
//测试判断功能
File file8 = new File("D:/abc/11.txt");
/* boolean flag4 = file8.isDirectory();
System.out.println("测试file8是否是文件夹: " + flag4 );*/
System.out.println("测试file8是否是文件夹: " + file8.isDirectory());
System.out.println("测试file8是否是文件: " + file8.isFile());
System.out.println("测试file8是否存在: " + file8.exists());
}
}
public class Test4 {
public static void main(String[] args) {
File file1 = new File("lib/1.txt");
//获取file1的绝对路径
String path1 = file1.getAbsolutePath();
//获取file1的相对路径
String path2 = file1.getPath();
//获取文件名
String fileName = file1.getName();
//获取lib文件夹下所有的文件(夹)的: 名称数组String[]
File file2 = new File("lib");
String[] names = file2.list();
for (String name : names) {
System.out.println(name);
}
//获取lib文件夹下所有的文件(夹)的: File对象数组 File[]
File[] files = file2.listFiles();
for (File file : files) {
System.out.println(file);
}
}
}
字符流读写文件
字符流读数据 – 按单个字符读取
创建字符流读文件对象:
Reader reader = new FileReader("readme.txt");
调用方法读取数据:
int data = reader.read(); // 读取一个字符,返回该字符代表的整数,若到达流的末尾,返回-1
异常处理:
try {
// 尝试执行的代码
} catch(Exception e) {
// 出现异常后的处理代码
}
// 关闭资源:
finally {
reader.close();
}
public class ReaderDemo1 {
public static void main(String[] args) throws IOException {
//需求: 通过字符流读取数据.
//1. 创建字符输入流对象.
Reader reader = new FileReader("lib/1.txt");
//2. 读取数据.
/*int ch1 = reader.read();
System.out.println(ch1); //97
int ch2 = reader.read();
System.out.println(ch2); //98
int ch3 = reader.read();
System.out.println(ch3); //99
int ch4 = reader.read();
System.out.println(ch4); //-1*/
/*
优化上述的读法, 用循环改进.
又因为不知道循环次数, 所以用while循环.
*/
//定义变量, 用来接收读取到的字符.
int ch;
/*
(ch = reader.read()) != -1 做了三件事
1. 执行reader.read(), 去文件中读取一个字符.
2. 执行ch = reader.read(), 将读取到的字符赋值给变量.
3. (ch = reader.read()) != -1, 用读取到的字符(内容) 和 -1进行比较.
*/
while((ch = reader.read()) != -1){
//ch = reader.read();
System.out.println(ch);
}
//3. 释放资源.
reader.close();
}
}
字符流读数据 – 按字符数组读取
创建字符流读文件对象:
Reader reader = new FileReader("readme.txt");
调用方法读取数据:
// 读取字符到数组中,返回读取的字符数,若到达流的末尾,返回-1
char[] chs = new char[2048];
int len = reader.read(chs);
异常处理:
try {
// 尝试执行的代码
} catch(Exception e) {
// 出现异常后的处理代码
}
// 关闭资源:
finally {
reader.close();
}
public class ReaderDemo2 {
public static void main(String[] args) throws IOException {
//需求: 通过字符流读取数据, 一次读取一个字符数组.
//1. 创建字符输入流对象.
Reader reader = new FileReader("lib/2.txt");
//2. 读取数据.
/* char[] chs = new char[3]; // , ,
int len1 = reader.read(chs);
System.out.println(chs); //a,b,c
System.out.println(len1); //3
int len2 = reader.read(chs);
System.out.println(chs); //d,e,f
System.out.println(len2); //3
int len3 = reader.read(chs);
System.out.println(chs); //g,e,f
System.out.println(len3); //1
int len4 = reader.read(chs);
System.out.println(chs); //g,e,f
System.out.println(len4); //-1*/
/*
优化上述的代码, while循环
*/
//定义字符数组
char[] chs = new char[3];
//定义一个变量, 记录读取到的有效字符数.
int len;
while((len = reader.read(chs)) != -1) {
//将读取到的内容, 转换成字符串, 然后打印.
/*
chs: 表示要操作的数组.
0: 表示起始索引.
len: 表示要操作的字符的个数.
*/
String s = new String(chs,0,len); //[g,e,f], 0, 1
System.out.println(s);
}
//3. 释放资源.
reader.close();
}
}
字符流写数据 – 按单个字符写入
创建字符流写文件对象:
Writer writer = new FileWriter("dest.txt");
调用方法写入数据:
int x = '中';
writer.write(x); // 写一个字符
异常处理:
try {
// 尝试执行的代码
} catch(Exception e) {
// 出现异常后的处理代码
}
// 关闭资源:
finally {
writer.close();
}
字符流写数据 – 按字符数组写入
创建字符流写文件对象:
Writer writer = new FileWriter("dest.txt");
调用方法写入数据(写入字符数组):
char[] chs = {'橙', '心', '橙', '意'};
writer.write(chs); // 写一个字符数组
调用方法写入数据(写入字符串):
writer.write("小黑爱学习"); // 写入一个字符串
异常处理:
try {
// 尝试执行的代码
} catch(Exception e) {
// 出现异常后的处理代码
}
// 关闭资源:
finally {
writer.close();
}
public class WriterDemo {
public static void main(String[] args) throws IOException {
//需求: 通过字符流, 写数据.
//1. 创建字符输出流对象.
Writer writer = new FileWriter("lib/1.txt");
//2. 写数据.
//一次写一个字符
writer.write('好');
//一次写一个指定的字符数组
char[] chs = {'黑','马','程','序','员'};
writer.write(chs,2,3);
//一次写一个字符串
writer.write("好好学习, 知识改变命运!");
//3. 释放资源.
writer.close();
}
}
字符流读、写数据的常见操作到这里就介绍完了。接下来稍微提高一点难度:使用字符流拷贝文件。
字符流拷贝文件 – 按单个字符读写
创建字符流读文件对象:
Reader reader = new FileReader("readme.txt");
创建字符流写文件对象:
Writer writer = new FileWriter("dest.txt");
调用方法读取数据:
int data = reader.read();
调用方法写入数据:
writer.write(data);
异常处理:
throws IOException
关闭资源:
finally {
reader.close();
writer.close();
}
public class CopyFile1 {
public static void main(String[] args) throws IOException {
//需求: 通过字符流拷贝文件, 一次读写一个字符.
//例如: 将1.txt文件中的内容复制到2.txt文件中.
/*
IO流拷贝文件核心6步:
1.创建字符输入流对象, 关联数据源文件.
2.创建字符输出流对象, 关联目的地文件.
3.定义变量,记录读取到的内容.
4.循环读取,只要条件满足就一直读,并将读取到的内容赋值给变量.
5.将读取到的数据写入到 目的地文件中.
6.释放资源.
*/
//Reader reader = new FileReader("lib/1.txt");
FileReader fr = new FileReader("lib/1.txt");
FileWriter fw = new FileWriter("lib/3.txt"); //细节: 如果目的地文件不存在, 程序会自动创建
int len;
while((len = fr.read()) != -1) {
fw.write(len);
}
fr.close();
fw.close();
}
}
每次读取一个字符,效率太低,如果能一次性读取多个字符,效率是不是会提高呢?答案是肯定的。
字符流拷贝文件 – 按字符数组读写
创建字符流读文件对象:
Reader reader = new FileReader("readme.txt");
创建字符流写文件对象:
Writer writer = new FileWriter("dest.txt");
调用方法读取数据:
char[] chs = new char[2048];
int len= reader.read(chs);
调用方法写入数据:
writer.write(chs, 0, len);
异常处理:
throws IOException
关闭资源:
finally {
reader.close();
writer.close();
}
public class CopyFile2 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("lib/1.txt");
FileWriter fw = new FileWriter("lib/2.txt");
char[] chs = new char[1024]; //定义一个字符数组
int len; //用来记录读取到的有效字符数.
while((len = fr.read(chs)) != -1) {
fw.write(chs,0,len);
}
fr.close();
fw.close();
}
}
字符流操作数据的基本用法介绍完了。在实际生产环境中,流的操作非常的缓慢、耗时(打开资源、操作资源、关闭资源),所以,实际生产环境中的流操作对效率的要求很高。为此,Java的设计者们提供了高效的缓冲流供开发者使用。
字符缓冲流拷贝文件的标准代码
创建字符流读文件对象:
BufferedReader br = new BufferedReader(
new FileReader("readme.txt"));
创建字符流写文件对象:
BufferedWriter bw = new BufferedWriter(
new FileWriter("dest.txt"));
异常处理:
throws IOException
使用while循环读写数据:
char[] chs = new char[2048];
int len;
while((len = br.read(chs)) != -1) {
bw.write(chs, 0, len);
}
关闭资源:
br.close();
bw.close();
public class Test5 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("lib/1.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("lib/2.txt"));
int len;
while ((len = br.read()) != -1) {
bw.write(len);
}
br.close();
bw.close();
}
}
/*特点: 字符缓冲流自带有缓冲区, 大小为8192个字符, 也就是16KB.
注意: 字符流只能拷贝纯文本文件.*/
//一次拷贝一行
public class Test6 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("lib/1.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("lib/2.txt"));
String str;
while ((str= br.readLine()) != null) {
bw.write(str);
// bw.write("\r\n"); .window操作系统: \r\n mac操作系统:\r unix操作系统: \n
bw.newLine(); //换行(根据当前操作系统给出对应的换行符)
}
br.close();
bw.close();
}
}
字节流读写文件
字节流拷贝文件 – 按单个字节读写
public class Test7 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("lib/a.jpg");
FileOutputStream fos = new FileOutputStream("lib/b.jpg");
int len;
while ((len = fis.read()) != -1) {
fos.write(len);
}
fis.close();
fos.close();
}
}
字节流拷贝文件 – 按字节数组读写
public class Test7 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("lib/a.jpg");
FileOutputStream fos = new FileOutputStream("lib/b.jpg");
byte[] bys = new byte[1024];
int len;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
fis.close();
fos.close();
}
}
字节缓冲流拷贝文件的标准代码
拷贝纯文本文件用字符流,拷贝其他(图片,音频,视频等)用字节流。
public class Test8 {
public static void main(String[] args) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("lib/a.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("lib/b.jpg"));
int len;
while ((len = bis.read()) != -1) {
bos.write(len);
}
bis.close();
bos.close();
}
}
案例:模拟文件上传功能
需求:使用控制台模拟实际开发中上传用户头像的功能
分析:
- 在控制台录入用户头像的路径
- 解析路径字符串中文件名是否合法:
- 后缀名为:.jpg、.png、.bmp
- 判断该路径表示的File对象是否存在,是否为文件:file.exist();file.isFile()
- 读取该文件并写入到指定目录
- 提示头像上传成功 或 失败
public class Test9 {
public static void main(String[] args) throws IOException {
//获取路径
File path = getPath(); //d:\picture\1.png
//判断图片是否存在
boolean flag = isExists(path.getName()); //1.png
if (flag) {
System.out.println("头像已存在,上传失败");
} else {
upLoadFile(path);
}
}
public static File getPath() {
while (true) {
Scanner sc = new Scanner(System.in);
System.out.println("请录入头像路径:");
String path = sc.nextLine();
if (!path.endsWith(".jpg") && !path.endsWith(".png")) {
System.out.println("不是图片");
continue;
}
File file = new File(path);
if (file.exists() && file.isFile()) {
return file;
} else {
System.out.println("路径不合法");
}
}
}
public static boolean isExists(String path) {
File file = new File("lib");
String[] names = file.list();
for (String name : names) {
if (name.equals(path)) {
return true;
}
}
return false;
}
public static void upLoadFile(File path) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("lib" + path.getName()));
int len;
while ((len = bis.read()) != -1) {
bos.write(len);
}
bis.close();
bos.close();
System.out.println("上传成功");
}
}
Java高级_反射
反射概述
原来的开发流程:程序代码是固定的,方法的执行顺序也是固定的
源代码 -> 字节码 -> 运行
使用反射:在需要的时候执行对应对象的方法,更改了程序执行的顺序,大大提高了程序的灵活性
反射技术致力于构建通用的底层代码,让所有的模块调用,提高程序的扩展性。
什么是反射?
在程序运行过程中分析类的一种能力
反射能做什么?
分析类
- 加载并初始化一个类
- 查看类的所有属性和方法
查看并使用对象 - 查看一个对象的所有属性和方法
- 使用对象的任意属性和方法
反射的应用场景
构建通用的工具
搭建具有高度灵活性和扩展性的系统框架
类加载器(ClassLoader):负责将类的字节码文件(.class文件)加载到内存中,并生成对应的Class对象
Class对象:java.lang.Class类的对象,也叫字节码文件对象,每个Class对象对应一个字节码文件
类的加载时机
(第一次使用类中成员,但是这个类还没有在内存中存在时)
创建类的实例
Student stu = new Student();
访问类的静态成员
Calendar.getInstance();
初始化类的子类
class User extends Person {}
User user = new User(); // 先加载父类
反射方式创建类的Class对象
Class clazz = Class.forName(“类的正名”); //正名:包名+类名
获取Class对象的三种方式
Object类的getClass()方法
Class clazz = 对象名.getClass();
类的静态属性
Class clazz = 类名.class;
Class类的静态方法
Class clazz = Class.forName(“类的正名”); // 正名:包类路径名,如:cn.itcast.bean.Student
public class ReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
Student stu = new Student();
Class clazz1 = stu.getClass();
Class clazz2 = Student.class;
Class clazz3 = Class.forName("cn.itcast.demo8.Student"); //左边cope Refrence
}
}
反射方式获取构造方法并使用
Constructor对象
构造器对象,属于java.base模块,java.lang.reflect包
通过Class对象获取构造器对象
// Class<?>… :可变参数,代表Class类型的数组
// ? :通配符,代表不确定的任意类型
getConstructor(Class<?>… parameterTypes)// 返回一个Constructor对象,仅公共构造函数
getDeclaredConstructor(Class<?>… parameterTypes) // 返回一个Constructor对象,可获取私有构造函数
getConstructors() // 返回此类所有(不含私有)构造函数的数组
Constructor的常用方法
String getName() // 返回构造函数名
T newInstance(Object… initargs) // 使用此构造函数和指定参数创建并初始化对象
public class Student {
//公共的无参构造
public Student() {}
//公共的带参构造
public Student(String name) { System.out.println("您录入的name的值是: " + name); }
//私有的带参构造.
private Student(int age) { System.out.println("您录入的age的值是: " + age); }
}
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
//需求: 通过反射的方式创建: Student类型的对象.
//1. 获取Student类的字节码文件对象.
Class clazz = Class.forName("cn.itcast.demo8.Student");
//2. 根据第一步获取到的字节码文件对象, 获取指定的构造器对象.
/* //2.1 获取公共的无参构造
Constructor con1 = clazz.getConstructor();
System.out.println(con1); //public cn.itcast.demo8.Student()*/
//2.2 获取公共的有参构造
Constructor con2 = clazz.getConstructor(String.class);
System.out.println(con2); //public cn.itcast.demo8.Student(java.lang.String)
/* //2.3 获取私有的有参构造
Constructor con3 = clazz.getDeclaredConstructor(int.class);
System.out.println(con3); //private cn.itcast.demo8.Student(int)
//2.4 获取Student类的所有公共的构造函数
Constructor[] cons= clazz.getConstructors();
for (Constructor con : cons) {
System.out.println(con);
}*/
//获取构造器的名字, 看看他是哪个类的构造
String name = con2.getName();
System.out.println(name);
//3. 根据构造器对象和参数, 创建对应的Student对象.
Student stu = (Student) con2.newInstance("张三"); //Object向下转型
//4. 打印结果.
System.out.println(stu);
}
}
public cn.itcast.demo8.Student(java.lang.String)
cn.itcast.demo8.Student
您录入的name的值是: 张三
cn.itcast.demo8.Student@7530d0a
反射方式获取成员方法并使用
Method对象
方法对象,属于java.base模块,java.lang.reflect包
通过Class对象获取方法
// name :方法名 // parameterTypes :方法的参数列表
getMethod(String name, Class<?>… parameterTypes)// 返回一个Method对象,仅公共成员方法
getDeclaredMethod(String, Class<?>…) // 返回一个Method对象,可获取私有成员方法
getMethods() // 返回此类所有(不含私有)方法的数组
Method的常用方法
String getName() // 返回方法名
Object invoke(Object obj, Object… args) // 在指定对象上调用此方法,参数为args
public class Student {
//公共的空参方法
public void show1() { System.out.println("我是公共的空参方法"); }
//公共的带参方法
public void show2(int a) { System.out.println("我是公共的带参方法, 您传入的a的值是: " + a);}
//私有的带参方法
private int show3(int a, int b) {System.out.println("我是私有的带参方法"); return a + b; }
}
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
//需求: 通过反射获取Student类中的成员方法并调用.
//1. 获取Student类的字节码文件对象.
Class clazz = Class.forName("cn.itcast.demo8.Student");
//2. 获取该类的构造器对象, 然后创建Student类的对象.
Constructor con = clazz.getConstructor();
Student stu = (Student) con.newInstance();
//3. 获取该类的成员方法对象, 然后调用此方法.
//3.1 调用公共的空参方法
Method method1 = clazz.getMethod("show1");
System.out.println(method1); //打印方法对象
System.out.println(method1.getName()); //打印方法名
method1.invoke(stu); //调用此方法
//3.2 公共的带参方法
Method method2 = clazz.getMethod("show2", int.class);
method2.invoke(stu, 100);
//3.3 调用私有的带参方法
Method method3 = clazz.getDeclaredMethod("show3", int.class, int.class);
//开启暴力反射
method3.setAccessible(true);
int sum = (int) method3.invoke(stu, 10, 20);
System.out.println("您录入的两个数的和是: " + sum);
//3.4 获取Student类中所有的成员方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
案例:通过反射获取方法并使用
需求:通过反射获取类的setter方法,使用该方法为属性赋值
分析:
- setter方法的方法名由set和属性名(首字母大写)组成: 举例:setName, setAge
- setter方法有且只有一个参数,参数类型为属性的类型: 举例:setName(String name), setAge(int age)
- setter方法为public修饰的方法,反射获取该方法使用: getMethod(String , Class<?>… );
- 根据上述分析分别为属性name、age赋值并使用
public class Student { 成员变量name ,构造,get,set,toString() }
public class ReflectDemo1 {
public static void main(String[] args) throws Exception {
//需求: 通过反射获取类的setter方法,使用该方法为属性赋值
//1. 通过反射获取Student类的字节码文件对象.
Class clazz = Class.forName("cn.itcast.demo4.Student");
//2. 通过反射获取Student类的构造方法, 并创建该类的对象.
Constructor con = clazz.getConstructor();
Student stu = (Student)con.newInstance();
//3. 获取到指定的setName()方法, 给Student对象设置值.
Method method1 = clazz.getMethod("setName", String.class);
//调用此方法
method1.invoke(stu,"张无忌");
//4. 打印学生对象.
System.out.println(stu);
}
}
反射方式获取成员变量并使用
Field对象
域(属性、成员变量)对象,属于java.base模块,java.lang.reflect包
通过Class对象获取属性
getField(String name) // 返回一个Field对象,仅公共属性// name :属性名
getDeclaredField(String name) // 返回一个Field对象,可获取私有属性
getDeclaredFields() // 返回此类所有(含私有)属性的数组
Field的常用方法
String getName() // 返回方法名
boolean setAccessible(boolean flag) // 将此属性的可访问性设置为指定布尔值
public class Student {
public String name;
private int age;
....
}
public class ReflectDemo4 {
public static void main(String[] args) throws Exception {
//需求: 通过反射获取成员变量并使用.
//1. 获取Student类的字节码文件对象.
Class clazz = Class.forName("cn.itcast.demo8.Student");
//2. 通过字节码文件对象获取构造器对象, 然后创建学生类对象.
/* Constructor con= clazz.getConstructor();
Student stu =(Student) con.newInstance();*/
Student stu = (Student) clazz.getConstructor().newInstance();
//3. 设置学生对象的各个属性值.
//3.1 设置姓名
Field filed = clazz.getField("name");
filed.set(stu, "张无忌");
//3.2 设置年龄
Field filed2 = clazz.getDeclaredField("age");
//开启暴力反射
filed2.setAccessible(true);
filed2.set(stu, 30);
//4. 打印学生对象.
System.out.println(stu);
}
}