JAVA4

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方法,使用该方法为属性赋值
分析:

  1. setter方法的方法名由set和属性名(首字母大写)组成: 举例:setName, setAge
  2. setter方法有且只有一个参数,参数类型为属性的类型: 举例:setName(String name), setAge(int age)
  3. setter方法为public修饰的方法,反射获取该方法使用: getMethod(String , Class<?>… );
  4. 根据上述分析分别为属性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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值