【Java高级】反射(上)

1.反射机制的作用

通过java语言中的反射机制可以操作(读或者修改)字节码文件。
通过反射机制可以操作代码片段(class文件)。

2.反射机制的相关类

(1)所在包:java.lang.reflect
(2)相关类:

  • java.lang.Class: 代表整个字节码,代表一个类型。代表一个类型。
  • java.lang.reflect.Method: 代表字节码中的方法字节码。代表类中的方法。
  • java.lang.reflect.Constructor: 代表字节码中的构造方法字节码。代表类中的构造方法
  • java.lang.reflect.Field: 代表字节码中的属性字节码。代表类中的成员变量。

3.获取Class的三种方式

(1)Class.forName(“完整类名”)

  • 该方法是一个静态方法。
  • 该方法的参数是一个字符串
  • 字符串需要完整的类名(完整类名,java.lang不能省略)。
package com.sdnu;

public class ClassDemo1 {
    public static void main(String[] args) {
        try {
            Class t1 = Class.forName("java.lang.String");  //t1代表String.class,或者说代表String类型
            Class t2 = Class.forName("java.util.Date");  //t2代表Date类型
            Class t3 = Class.forName("java.lang.Integer");  //t3代表Integer类型
            Class t4 = Class.forName("java.lang.System");  //t4代表System类型
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

(2)对象.getClass()

package com.sdnu;

public class ClassDemo2 {
    public static void main(String[] args) {
        String s1 = "Hello World";
        Class c1 = s1.getClass();
    }
}

(3) java语言中任何一种类型:包括基本数据类型,都有class属性。

package com.sdnu;

public class ClassDemo3 {
    public static void main(String[] args) {
        Class c1 = String.class;
        Class c2 = Integer.class;
        Class c3 = int.class;
    }
}

4.通过反射实例化对象

ReflectDemo1.java

package com.sdnu;

public class ReflectDemo1 {
    public static void main(String[] args) {
        try {
            Class c = Class.forName("com.sdnu.bean.User");
            Object object = c.newInstance();
            System.out.println(object);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}

User.java

package com.sdnu.bean;

public class User {
    public User() {
        System.out.println("无参构造方法");
    }
}

在这里插入图片描述

通过反射机制获取class,然后通过class来实例化对象。

newInstance这个方法会调用User这个类的无参构造方法去创建实例对象。

5.通过读属性文件实例化对象

ReflectDemo2.java

package com.sdnu;

import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

public class ReflectDemo2 {
    public static void main(String[] args) {
        try {
            //通过IO流读取classinfo.properties文件
            FileReader reader = new FileReader("javareflect/src/classinfo.properties");
            //创建属性类对象
            Properties pro = new Properties();
            //加载
            pro.load(reader);
            //关闭流
            reader.close();
            String className = pro.getProperty("className");
            Class c = Class.forName(className);
            Object object = c.newInstance();
            System.out.println(object);
        } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

clasinfo.properties

className=com.sdnu.bean.User

(使用的是上一节的User.java)
在这里插入图片描述
使用上面的反射机制可以使得程序变得灵活,当我们创造另一个对象的时候,我们只需要修改配置文件即可。配置文件修改如下:

className=java.util.Date

则程序运行结果为如下:
在这里插入图片描述

6.使用forName只让静态代码块执行

ReflectDemo3.java

package com.sdnu;

public class ReflectDemo3 {
    public static void main(String[] args) {
        try {
            Class.forName("com.sdnu.MyClass");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

MyClass.java

package com.sdnu;

public class MyClass {
    static {
        System.out.println("静态代码块执行了!");
    }
}

在这里插入图片描述

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

我们先来看一下之前写的代码:

FileReader reader = new FileReader("javareflect/src/classinfo.properties");

这段代码并没有什么错误,但是可移植性较差,因为在idea中默认的当前路径是project。假如代码离开idea,换到了其他地方,不一定默认路径为project。

接下来我们介绍一种新的方法来获取当前路径。(注意,这种方法值适用于类路径下,也就是idea的src下。)

Thread.currentThread():获取当前线程对象

getContextClassLoader(): 当前线程对象的方法,获取当前线程对象的类加载器对象

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

PathDemo.java

package com.sdnu;

public class PathDemo {
    public static void main(String[] args) {
        String path = Thread.currentThread().getContextClassLoader().
                getResource("classinfo.properties").getPath();
        System.out.println(path);
    }
}

在这里插入图片描述

8.以流的形式直接返回

package com.sdnu;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class PathDemo2 {
    public static void main(String[] args) {
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("classinfo.properties");
        Properties pro = new Properties();
        try {
            pro.load(in);
            in.close();
            String className = pro.getProperty("className");
            System.out.println(className);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

9.资源绑定器

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

package com.sdnu;

import java.util.ResourceBundle;

public class ResourceBundleDemo {
    public static void main(String[] args) {
        ResourceBundle bundle = ResourceBundle.getBundle("classinfo");
        String className = bundle.getString("className");
        System.out.println(className);
    }
}

10.类加载器

(1)什么是类加载器: 专门负责加载类的命令/工具(ClassLoader)。

(2)JDK 中自带的三个类加载器:

  • 启动类加载器
  • 扩展类加载器
  • 应用类加载器

(3)示例

有这样一段代码:String s = "Hello World"。在开始执行代码之前,会将所需要的类加载到JVM中,也就是将 String 类加载到JVM中。

(4)加载的顺序

  • 首先通过“启动类加载器”加载

启动类加载器加载的类在JDK的路径如下:

D:\JAVA-JDK\jre\lib\rt.jar

这里面的类都是java中最核心的类,比如String类
在这里插入图片描述

  • 启动类加载器找不到的时候,通过扩展类加载器进行加载

扩展类加载器加载的类在JDK的路径如下:

D:\JAVA-JDK\jre\lib\ext\*.jar
  • 扩展类加载器找不到的时候,通过应用类加载器进行加载

应用类加载器加载的类在 classpath (系统变量)中的jar包。

(5)双亲委派机制

首先从启动类加载器加载,这个称为“父”,加载不到再从扩展类加载器加载,这个称为“母”,如果都加载不到,再考虑从应用类加载器加载。

在这里插入图片描述

作者:Beyong    
出处:Beyong博客
github地址:https://github.com/beyong2019

本博客中未标明转载的文章归作者Beyong有,欢迎转载,但未经作者同意必须保留此段声明,且在文章明显位置给出原文连接,否则保留追究法律责任的权利。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值