IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> java31-类加载-JVM的类加载机制-反射-获取Class类的对象-反射获取构造方法/成员变量/成员方法 -> 正文阅读

[Java知识库]java31-类加载-JVM的类加载机制-反射-获取Class类的对象-反射获取构造方法/成员变量/成员方法

类加载

类加载概述

概念:

  • 当程序要使用某个类时,如果该类未被加载到内存中,则系统会通过类的加载、类的连接、类的初始化三个步骤对类进行初始化。
  • JVM会将类加载、连接、初始化连续完成,这三个步骤被称为类加载或类初始化。
  • 类的加载
  • 指将.class文件读入内存,并为之创建一个java.lang.Class对象类加载器的作用
  • 任何类被使用的时候,系统都会为之创建一个java.lang.Class对象
  • 类的连接
  • 验证阶段:用于检验被加载的类是否有正确的内部结构,并与其他类协调一致
  • 准备阶段:负责为类的类变量分配内存,并设置默认初始化值
  • 解析阶段:将类的二进制数据中的符号引用替换为直接引用
  • 类的初始化
  • 主要对类变量进行初始化
    类的初始化步骤:
  • 假如类还未被加载和连接,则程序先加载并连接该类
  • 假如该类的直接父类还未被初始化,则先初始化被直接父类
  • 假如类中有初始化语句,则系统依次执行这些初始化语句
    注意:
    在执行第二个步骤的时候,系统对直接父类的初始化步骤也遵循初始化步骤1-3
    一个类被载入java虚拟机的时候,同一个类就不会再次被载入了。
    类的初始化时机: 强调首次
  • 创建类的实例
  • 调用类的类方法(静态方法)
  • 访问类或者接口的类变量,或者为该类变量赋值
  • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  • 初始化某个类的子类(初始化子类首先就会初始化父类)
  • 直接使用java.exe命令来运行某个主类

JVM的类加载机制

JVM的类加载机制有三种:全盘负责、父类委托、缓存机制。

  • 全盘负责:当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也由该类加载器负责载入,除非显示使用另外一个类加载器载入;
  • 父类委托:当一个类加载器负责加载某个Class时,先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类;
  • 缓存机制:保证所有被加载的Class都会被缓存,当程序需要使用某个Class对象时,类加载器先从缓存区中搜索该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存储在缓存区。

ClassLoader: 负责加载类的对象
java运行时具有一下内置类加载器

类名说明
Bootstrap class loader它是虚拟机的内置类加载器,通常表示null,并且没有父null
也就是这个类是类加载器的祖宗
Platform class loader平台类加载器可以看到所有平台类,平台类包括由平台类加载器或其祖先定义的java SE平台API,其实现类和JDK特定的运行时类
System class loader它也被称为应用程序类加载器,与平台类加载器不同。系统类加载器通常用于定义应用程序类路径、模块路径和JDK特定工具上的类

类加载器的继承关系:System的父加载器为Platform(java9)Ext(java8),Platform的父加载器为Bootstrap。
ClassLoader中的两个方法:

方法名说明
static ClassLoader getSystemClassLoader()返回用于委派的系统类加载器
ClassLoader getParent()返回父类加载器进行委派

案例:

public class ClassLoaderDemo {
    public static void main(String[] args) {
        // 系统类加载器
        ClassLoader c = ClassLoader.getSystemClassLoader();
        System.out.println(c);//AppClassLoader(应用程序类加载器)

        // 父类加载器
        ClassLoader c2 = c.getParent();
        System.out.println(c2);//ExtClassLoader(扩展类加载器) 视频中是 PlatformClassLoader 
        // java8 的ExtClassLoader = java9 的 PlatformClassLoader 
        ClassLoader c3 = c2.getParent();
        System.out.println(c3);// null
    }
}

反射

概念:

  • java反射机制:运行时去获取一个类的变量和方法信息,通过获取到的信息创建对象,调用方法的一种机制;
  • 动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展;

理解xhj:

  • 自己定义类要想使用–》类加载器加载对应的.class文件–》每一个.class文件都会包含成员变量、构造方法、成员方法…信息
  • Class类就是所有.class文件对应的类型、躯体。
  • 不再通过自己定义类的去使用成员变量、构造方法、成员方法,而是用Class类去使用成员变量、构造方法、成员方法,这就是反射。
  • 反射就是把java类中的各种成分映射成相应的java类。

获取Class类的对象 Class.forName

原因: 通过反射去使用一个类。首先获取该类的 字节码文件对象=类型为Class类型的对象。
获取Class类型对象的方法:

方法说明
使用类的class属性来获取该类对应的Class对象Student.class将会返回Student类对应的Class对象
调用对象的getClass()方法,返回该对象所属类对应的Class对象该方法是Object类中的方法,所有的Java对象都可以调用该方法
使用Class类中的静态方法forName(String className)该方法需要出入 字符串参数 = 某个类的全路径=完整包名的路径

案例:

public class ReflectDemo {
    public static void main(String[] args) {
        //使用**类的class属性**来获取该类对应的Class对象
        Class<Student> c1 = Student.class;
        System.out.println(c1);
        // 输出内容是:class itiheima315.test2.Student
        // 一个类在内存中只有一个字节码文件
        Class<Student> c2 = Student.class;
        System.out.println(c1 == c2);
        // 输出:true
        System.out.println("------");
        // 调用**对象的getClass()方法**
        Student s = new Student();
        Class<? extends Student> c3 = s.getClass();
        System.out.println(c1 == c3);
        // 使用Class类中的静态方法forName(String className)
        Class<?> c4 = null;
        try {
            c4 = Class.forName("itiheima315.test2.Student");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(c1 == c4);

    }
}

反射获取构造方法并使用 Constructor

Class类

  • 在java.lang包下,使用需要导包;Class Class< T >
  • public final class Class< T > extends Object implements …是最终类,说明不能被继承
  • Class类的实例表示正在运行的java应用程序的类和接口
  • 通过Class对象获取Constructor对象的数据
所属类方法名说明
Class类Constructor< ? >[] getConstructors()返回所有公共构造方法对象的数组
Class类Constructor<?>[] getDeclaredConstructors()返回所有构造方法对象的数组
Class类Constructor< T> getConstructor(Class<?>…parameterType)返回单个公共构造方法对象
要获取的构造方法的参数的个数和数据类型对应的字节码文件对象
使用的是:String类型,则用String.class;int类型,则用的是int.class
Class类Constructor< T> getDeclaredConstructor(Class<?>…parameterType)返回单个构造方法对象
要获取的构造方法的参数的个数和数据类型对应的字节码文件对象

Constructor类

  • 在java.lang.reflect包下,使用需要导包
  • public final class Constructor< T> extends Executable 是最终类
  • 提供了一个类的单个构造函数的信息和访问权限
  • 通过Constructor类中的newInstance方法创建对象:
方法名说明
T newInstance(Object…initargs使用由此Constructor对象表示的构造函数,使用指定的初始化参数创建和初始化构造函数的声明类的新实例

理解xhj:

  • 在反射中,实际上是将类中的成员变量、构造方法、成员方法,看成一个个对象;
  • 通过反射创建类的对象:
1 通过Class.forName方法得到 类的字节码文件对象
	Class<?> c = Class.forName("类的路径")
	抛出异常 ClassNotFoundException
2 通过字节码文件对象的getConstructor方法得到单个构造函数
	Constructor<?> con = c.getConstructor();
	抛出异常 NoSuchMethodException
3 通过Constructor对象的newInstance方法创建对象
	Object obj = con.newInstance();
	抛出异常 IllegalAccessException, InvocationTargetException, InstantiationException

案例:

public class ReflectDemo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 获取Class对象,也就是类的字节码对象
        Class<?> c = Class.forName("itiheima315.test2.Student");
        // 得到Student类的字节码文件对象

        // 要想获取构造方法,要在Class类中找方法获取构造方法。

        //  Constructor< ? >[] getConstructors() |返回一个包含Constructor对象的数组
//        Constructor<?>[] arrayC = c.getConstructors();
//        for(Constructor con:arrayC){
//            System.out.println(con);
//        }
        // 结果:
        // public itiheima315.test2.Student(java.lang.String,int,java.lang.String)
        //public itiheima315.test2.Student()

        // Constructor<?>[] getDeclaredConstructors()|返回反映该Class对象的类声明的所有构造函数的Constructor对象的数组
//        Constructor<?>[] conS = c.getDeclaredConstructors();
//        for (Constructor con : conS) {
//            System.out.println(con);
//        }
        // 结果
        /*
        public itiheima315.test2.Student(java.lang.String,int,java.lang.String)
        itiheima315.test2.Student(java.lang.String,int)
        private itiheima315.test2.Student(java.lang.String)
        public itiheima315.test2.Student()*/

        //Constructor< T> getConstructor(Class<?>.....parameterType)|返回一个Constructor对象,该对象反映该Class对象表示的类的指定公共构造函数|
        Constructor<?> c0 = c.getConstructor();//拿public的无参构造方法
//        System.out.println(c0);
        // 使用Constructor对象来实现通过类创建对象。
        Object obj = c0.newInstance();
        System.out.println(obj);
// 输出Student{name='null', age=0, address='null'}

        // Constructor< T> getDeclaredConstructor(Class<?>...parameterType)|返回一个Constructor对象,该对象反映由此Class对象表示的类或接口的指定构造函数|
    }
}

案例:反射

案例1

需求:
通过反射实现以下操作:
Student s = new Student(“林俊杰”,30,“西安”);
System.out.println(s);
基本数据类型可以通过.class得到对应的Class类型

public class ReflectTest1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    /*    Student s = new Student("林俊杰",30,"西安");
        System.out.println(s);*/

        Class<?> c = Class.forName("itiheima315.test2.Student");
        // 获取Class对象
        Constructor<?> con = c.getDeclaredConstructor(String.class,int.class,String.class);
        Object obj = con.newInstance("林俊杰", 30, "西安");
        System.out.println(obj);
    }
}
案例2

需求:
通过反射实现以下操作:
Student s = new Student(“林俊杰”);
System.out.println(s);
public void setAccessible(boolean flag):值为true,取消访问检查

public class ReflectTest2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        /*Student s = new Student("林俊杰");
        System.out.println(s);*/
        Class<?> c = Class.forName("itiheima315.test2.Student");

        Constructor<?> con = c.getDeclaredConstructor(String.class);

        // 暴力反射
        // public void setAccessible(boolean flag):值为true,取消访问检查
        con.setAccessible(true);

        Object obj = con.newInstance("林俊杰");
        System.out.println(obj);

        // 获取到的私有构造方法不能创建对象 会报错 IllegalAccessException
        // 加了setAccessible方法 可以实现私有方法创建对象

        // 输出:Student{name='林俊杰', age=0, address='null'}
    }
}

反射获取成员变量并使用 Field

获取成员变量的方法

方法名说明
Field[] getFields()返回类或接口的所有可访问的公共字段组成的数组
Field[] getDeclaredFields()返回类或接口声明的所有字段组成的数组
Field getField(String name)返回类或接口的指定公共成员变量
Field getDeclaredField(String name)返回类或接口的指定声明成员变量

Field类

  • Field提供有关类或接口的单个字段的信息和动态访问
  • 所给成员变量赋值的方法:
方法名说明
void set(Object obj,Object value)将指定的对象参数,设置为由Field对象表示的字段
成员变量名.set(对象,“具体值”) # 给对象的成员变量赋值为具体值

反射获取成员变量具体的代码过程:

1 获取Class对象
	Class<?> c = Class.forName("类的路径");
2 获取Class对象的无参构造方法
	Constructor<?> con = c.getConstructor();
3 获取Class对象的成员变量
	Field fName = c.getField("成员变量名");
4 通过无参构造方法创建对象
	Object obj = con.newInstance();
5 给对象的成员变量赋值
	fName.set(obj,"设置的值");

需求:反射获取成员变量并使用

public class ReflectDemo3 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException
            , IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> c = Class.forName("itiheima315.test2.Student");

//        Field[] fields = c.getFields();//获取公共的成员变量
        Field[] fields = c.getDeclaredFields();//获取所有成员变量
        for(Field f:fields){
            System.out.println(f);
        }
        System.out.println("-------");
        Field addressField = c.getField("address");
        //获取无参构造方法创建对象
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

        addressField.set(obj,"西安");
        System.out.println(obj);
    }
}

练习:
需求:
通过反射实现:
Student s = new Student();
s.name = “汪苏泷”;
s.age = 30;
s.address = “阳泉”;
System.out.println(s);

public class ReflectTest3 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        // 通过反射实现
  /*      Student s = new Student();
        s.name = "汪苏泷";
        s.age = 30;
        s.address = "阳泉";
        System.out.println(s);*/

  // 获取Class对象
        Class<?> c = Class.forName("itiheima315.test2.Student");
        // 获取无参构造方法
        Constructor<?> con = c.getConstructor();
        // 创建对象
        Object obj = con.newInstance();
        // 获取成员变量
//        Field fname = c.getField("name");
        Field fname = c.getDeclaredField("name");
        // 暴力反射
        fname.setAccessible(true);
        Field fage = c.getDeclaredField("age");
        fage.setAccessible(true);
        Field faddress = c.getField("address");
        // 给对象的成员变量赋值
        fname.set(obj, "汪苏泷");
        fage.set(obj, 30);
        faddress.set(obj,"北京");

        System.out.println(obj);

    }
}

注意:
当想使用私有的成员变量的时候,需要进行如下操作:

 Field f = conStructor对象.getDeclaredField("成员变量名");
 f.setAccessible(ture)// 取消访问检查

反射获取成员方法并使用 Method

获取成员方法的方法:

方法名说明
Method[] getMethods()返回类或接口的所有公共方法
包括类或接口声明的对象以及从超类和超级接口继承的类
Method[] getDeclaredMethods()返回类或接口声明的所有方法
包括public、protected、default和private,不包括继承方法
Method[] getMethod(String name,Class<?> … parametreTyoes)返回类或接口的指定公共成员方法
Method[] getDeclaredMethod(String name,Class<?> … parametreTyoes)返回类或接口的指定声明的方法

Method方法

  • 在类或接口上提供有关单一方法的信息和访问权限
  • 实现对象调用方法
方法名说明
Object invoke(Object obj,Object …args)在具有指定参数的指定对象上调用此方法表示的基础方法
Object返回值类型;obj调用方法的对象;args方法需要的参数

反射获取成员方法的具体代码实现:

1 获取Class对象
	Class<?> c = Class.forName("类的路径");
2 获取无参构造方法
	Constructor con = c.getConstructor();
3 无参构造方法创建对象
	Object obj = con.newInstance();
4 获取成员方法
	Method m = c.getMethod("成员方法名");
5 对象使用成员方法对象
	m.invoke(obj,"成员方法所需参数");

代码:

public class ReflectDemo4 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException,
            IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> c = Class.forName("itiheima315.test2.Student");

//        Method[] methods = c.getMethods();//本类的 以及 继承的公共方法
//        Method[] methods = c.getDeclaredMethods();// 本类所有的方法
//        for(Method method:methods){
//            System.out.println(method);
//        }
//    }
        Method m1 = c.getMethod("method1");

        // 获取无参构造方法
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();
        m1.invoke(obj);
    }
}

练习

练习1

通过反射完成:
Student s = new Student();
s.method1();
s.method2(“汪苏泷”);
String ss = s.method3(“许嵩”,32);
System.out.println(ss);
s.function();
代码:

public class ReflectTest4 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//         //使用反射实现如下操作:
//        Student s = new Student();
//        s.method1();
//        s.method2("汪苏泷");
//        String ss = s.method3("许嵩",32);
//        System.out.println(ss);
//        s.function();

        Class<?> c = Class.forName("itiheima315.test2.Student");

        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

// s.method1();
        Method method1 = c.getDeclaredMethod("method1");
        method1.invoke(obj );
// s.method2("汪苏泷");
        Method method2 = c.getDeclaredMethod("method2", String.class);
        method2.invoke(obj,"汪苏泷");
//String ss = s.method3("许嵩",32);
        Method method3 = c.getDeclaredMethod("method3", String.class, int.class);
        Object ss = method3.invoke(obj, "许嵩", 30);
//  System.out.println(ss);
        String st = (String)ss;
        System.out.println(ss);
// s.function();
        Method function1 = c.getDeclaredMethod("function");
        // 由于function是私有成员,所以需要暴力反射
        function1.setAccessible(true);
        function1.invoke(obj);
    }
}
练习2

有一个ArrayList< Integer>集合,在这个集合中添加一个字符串数据,如何实现?
反射可以完成一些正常情况下无法完成的事情
反射可以越过泛型检查的,获取到原始的方法所需要的参数类型
代码:

public class ReflectTes5 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException,
            IllegalAccessException {
        ArrayList<Integer> array = new ArrayList<Integer>();

//        array.add(10);
//        array.add(20);
        // 获取Class对象,使用对象.getClass方法实现。
        Class<? extends ArrayList> c = array.getClass();
        Method madd = c.getMethod("add",Object.class);

        madd.invoke(array, "pretty");
        madd.invoke(array,"sunshine");

        System.out.println(array);

    }
}
练习3

通过配置文件运行类中的方法
代码:

public class ReflectDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException,
            IllegalAccessException, InvocationTargetException, InstantiationException {
//        Student s = new Student();
//        s.study();
//
//        Teacher t = new Teacher();
//        t.teach();
        // 为了方便使用Student和Teacher两个类,可以使用配置文件完成 而不用每次修改main方法

        // 加载数据
        Properties prop = new Properties();
        FileReader fr = new FileReader(".\\class.txt");
//        char[] chs = new char[1024];
//        int len;
//        while((len = fr.read(chs)) != -1){
//            System.out.println(new String(chs,0,len));
//        }
        // 输出结果是:className=itiheima315.test3.Student
        //MethodName=study
        // 说明 内容已被读入
        prop.load(fr);
        fr.close();

        // 数据文件加载成功

        String className = prop.getProperty("className");
        String methodName = prop.getProperty("MethodName");
        // 使用不使用 类以及其成员方法 在class.txt文件中修改

        // 通过反射来使用
        Class<?> c = Class.forName(className);//得到的是itiheima315.test3.Student
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();


        Method m = c.getMethod(methodName);
        // System.out.println(m);
        m.invoke(obj);
        
    }
}

模块化

概念

  • 随着java语言的发展,逐渐成为一个“臃肿”的语言,无论是大系统还是小软件,JVM都需要加载整个JRE环境;
  • java9实现了模块化,成功给java实现了瘦身,允许java程序可以根据需求选择要加载的模块;
  • 整体的项目project,下面依次是:模块、包、类或者接口;
  • 模块与模块之间是独立的,也可以作为访问权限的界定边界,可以通过模块的描述文件设置包是否被暴露处理、隐藏处理,对于隐藏的包即使它所包含的java类型使用了public修饰,别的模块仍旧不能访问这些类型。

模块基本使用

基本使用步骤:

  • 创建模块 …包、类、定义方法
    定义两个模块,myOne和MyTwo
  • 在模块的src目录下新建一个名为module-info.java的描述性文件,该文件专门定义模块名、访问权限、模块依赖等信息,描述性文件中使用模块导出模块依赖进行配置并使用。
    所要使用的和被使用的两个模块都创建module-info.java文件
  • 模块中所有未导出的包都是模块私有的,他们不能在模块之外被访问
    模块导出格式:exports 包名;
  • 一个模块要访问其他模块,必须明确指定依赖那些模块,未明确指定依赖的模块不能访问
    模块依赖格式:requires 模块名;
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-16 22:07:36  更:2022-03-16 22:10:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:39:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码