java进阶学习——8 反射机制

11 篇文章 0 订阅


大数据学习路线,从零开始学大数据(点击跳转,学习不迷路)

Java最详细教程 (点击跳转,学习不迷路)

八、反射机制

1. 反射机制有什么用?

通过java语言中的反射机制可以操作字节码文件
优点类似于黑客。(可以读和修改字节码文件。)
通反射机制可以操作代码片段。(class文件。)

2. 反射机制的相关类在哪个包下?

java.lang.reflect.* ;

3. 反射机制相关的重要的类有哪些?

 java.lang.class:  代表整个字节码,代表一个类型,代表整个类。
 
 java.lang.reflect.Method: 代表字节码中的方法字节码。代表类中的方法。
 
 java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法。
 
 java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量(静态变量和实例变量)。

在这里插入图片描述

4. 获取Class的三种方式:

要操作一个类的字节码,需要首先获取到这个类的字节码,怎么获取java.lang.class实例?
三种方式
第一种:Class c = Class.forName(“完整类名带包名”);
第二种:Class c = 对象.getClass();
第三种: Class c = 任何类型.class;

在这里插入图片描述

public class ReflectTest01 {
    public static void main(String[] args) {

        /*  Class.forName()
                1. 静态方法
                2. 方法的参数是一个字符串
                3. 字符串需要的是一个完整类名.
                4. 完整类名必须带有包名. java.lang 包也不能省略

        * */
        Class c1 = null;
        Class c2 = null;

        try {
        // 第一种
            c1 = Class.forName("java.lang.String");  // c1 代表 String.class文件.或者说c1 代表String类型
            c2 = Class.forName("java.util.Date");    // c2 代表Date类型
            Class c3 = Class.forName("java.lang.Integer");  //c3  代表Integer类型
            Class c4 = Class.forName("java.lang.System");    //c4  代表System类型
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

		//第二种
        // java中任何一个对象都有一个方法:getClass()
        String s = "abc";
        Class x = s.getClass(); // x代表String.class字节码文件,x代表String类型
        System.out.println(c1 == x);    // true(== 判断的是对象的内存地址.)

        Date time = new Date();
        Class y = time.getClass();
        System.out.println(c2 == y); // true (c2和y两个变量中保存的内存地址是一样是,都指向方法区中的字节码文件)

        // 第三种方式: java语言中任何一种类型,包括基本数据类型,它都有.class属性
        Class z = String.class;   // z 代表String类型
        Class k = Date.class;   // k 代表Date类型
        Class f = int.class;   // f 代表int类型
        Class e = double.class;  // e 代表double类型

        System.out.println(x == z); //true
    }
}

5. 反射机制的灵活性

java代码写一遍,在不改变java源代码的基础之上,可以做到不同对象的实例化。
非常之灵活。(符合OCP开闭原则:对扩展开放,对修改关闭。)

代码例子:
先创建一个.properties 文件,将对象存放进去
在这里插入图片描述
java代码:

public class ReflectTest03 {
    public static void main(String[] args) {
        // 通过IO流读取Classinfo.properties文件
        try {
            FileReader reader = new FileReader("src\\main\\java\\Reflect\\classinfo.properties");
            // 创建属性类对象Map
            Properties pro = new Properties();  // key value 都是String
            // 加载
            pro.load(reader);
            // 关闭流
            reader.close();

            //通过key获取value
            String calssName = pro.getProperty("className");
//            System.out.println(calssName);

//            通过反射机制实例化对象
            Class c = Class.forName(calssName);
            Object obj = c.newInstance();
            System.out.println(obj);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}

运行结果:
在这里插入图片描述

在不改变源代码的情况下,改变classinfo.properties文件

在这里插入图片描述
运行结果:
源代码对象改成Date类
在这里插入图片描述

6. 只让静态代码块执行

研究一下 :class.forname()发生了什么?
记住,重点:
如果你只是希望一个类的静态代码块执行,其他代码一律不执行,
可以使用:
Class.forName(“完整类名”);
这个方法的执行对导致类加载,类加载时,静态代码块执行。

代码例子:

public class ReflectTest04 {
    public static void main(String[] args) {

        try {
//            class.forName()这个方法的执行会导致:类加载。
            Class.forName("Reflect.MyClass");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
class MyClass {
    //   静态代码块只在类加载的时候执行,并且执行一次
    static {
        System.out.println("MyClass类的静态代码执行了!");
    }
    //  普通方法 ,在加载类时,不调用的化不执行
    public void eat(){
        System.out.println("吃个早餐");
    }
}

运行结果:

在这里插入图片描述

7. 获取类路径下文件的绝对路径

怎么获取一个文件的绝对路径:

以下讲解的这种方式是通用的。但前提是:文件需要在类路径下,才能用这种方式。

在这里插入图片描述
获取文件的绝对路径:

Thread.currentThread()  : 当前线程对象
getContextClassLoader()  :  是线程对象的方法,可以获取当前线程的类加载器对象。
getResource() : 【获取资源】这是类加载器对象的方法,当前线程的类加载器默认从类的根路径下加载资源。

// 采用此代码可以拿到一个文件的绝对路径(前提是文件在类路径下)
// 这种方式获取文件绝对路径是通用的(任何操作系统)。
String path = Thread.currentThread().getContextClassLoader().getResource(name:" 文件名").getPath();

资源绑定器:

在这里插入图片描述

java.util 包下提供了一个资源绑定器,便于获取属性配置文件的内容。
使用以下的方式时,书信配置文件xxx.properties必须放到类路径下。

在这里插入图片描述

类加载器:

在这里插入图片描述

在这里插入图片描述

路径问题:
在这里插入图片描述

8. 获取Filed

Filed是翻译为字段,其实就是属性 / 成员 。

反射属性Filed
在这里插入图片描述

获取Filed:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
访问对象的属性:

在这里插入图片描述

使用反射机制访问对象的属性:

在这里插入图片描述

可变长度参数

int …args 这就是可变长度参数。
语法: 类型…args (注意:一定是3个点。)

  1. 可变长度参数要求的参数个数是0~N个。
  2. 可变长度参数在参数列表中必须在最后一个位置上,而且可变长度参数只能有一个。
  3. 可变长度参数可当作一个数组看待。
public class argsTest {
    public static void main(String[] args) {
        m();
        m(2);
        m(1,3,2);

        m2(10);
        m2(1,"我","是","中","国","人","!");

        m3("是不是中国人?");
//        传一个数组
        String [] str = {"我","是","中","国","人","!"};
        m3(str);
    }

    public static void m(int...args){
        System.out.println("m方法执行了!");
    }

    public static void m2(int i ,String...args){

    }

    public static void m3(String...args){
        for (int i = 0; i <args.length ; i++) {
            System.out.println(args[i]);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海码儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值