java中的反射机制使用,java类反射

  java中的反射机制使用,java类反射

  本文给大家带来一些java的知识,包括反射机制的原理,类获取的几种方法以及应用场景。希望对你有帮助。

  如何解决写爬虫IP受阻的问题?立即使用。

  学Java的小伙伴可能听说过Java反射机制,熟悉但有点不熟悉。本文主要针对面试中经常被问到的几个关于Java反射机制的问题,再结合理论知识结合代码实例和应用场景进行讲解,加深自己对Java反射机制的认知和理解,希望对有需要的小伙伴有所帮助~

  

一、Java反射机制是什么?

  

1.1 反射原理

   (1)Java反射机制(Java Reflection)是一种在Java语言中访问、检测和修改自身的动态(运行时)能力。它的主要功能是动态(运行时)获取一个类的完整结构信息,调用一个对象的方法~

  更简单地说,Java程序在运行时(动态地)创建一个类的反射对象,然后对该类执行相关操作,比如:

  获取对象的成员变量赋值,调用对象的方法(包括构造方法,有无参数)判断对象所属的类(2)一般情况下,我们使用某个类,都会知道这个类,以及要用它来做什么,可以直接通过new实例化创建对象,然后使用这个对象对类进行操作,这个就属于正射~

  (3)而反射则是一开始并不知道要初始化的是什么类,无法使用new来实例化创建对象,主要是通过JDK提供的反射API来实现,在运行时才知道要操作的是什么类,并且可以获取到类的完整构造以及调用对应的方法,这就是反射~

  

1.2 反射例子

  代码如下:

  包com . Justin . Java . lang;导入Java . lang . reflect . constructor;导入Java . lang . reflect . method;/**

  * @程序:Jdk1.8测试

  * @description:正字法和反射法的简单调用示例

  * @作者:贾丝汀琴

  * @create: 2021/8/22 13:23

  * @版本:v1.0.0

  * */公共课学生{

  private int id

  public void setId(int id) {

  this.id=id

  }

  public int getId() {

  返回id;

  }

  公共静态void main(String[] args)引发异常{

  //首先,正字法调用过程

  学生学生=新生();

  student . setid(1);

  System.out.println(正交调用过程学号: Student . getid()));

  //第二,反映调用过程

  class clz=class . forname( com . Justin . Java . lang . student );

  constructor student constructor=clz . get constructor();

  object studentObj=student constructor . new instance();

  方法setId method=clz . get method( setId ,int . class);

  setIdMethod.invoke(studentObj,2);

  method getId method=clz . get method( getId );

  System.out.println(正交调用过程StudentID: getid method . invoke(Studentobj));

  }}输出结果:

  正交调用程序学号:1反射调用程序学号:2上述例子反射的调用过程,可以看到获取一个类的反射对象,主要过程为:

  获取类的类实例对象,根据类实例对象获取构造函数对象,然后根据构造函数对象的newInstance方法获取类的反射对象获取到类的反射对象后,就可以对类进行操作了~ 例如,上述示例中对类的方法进行调用过程为:

  根据类实例对象获取类的方法对象,然后根据方法对象的invoke方法调用特定类的方法前面一点也提到了获取到类的Class实例对象,上面示例反向调用过程中我们是通过Class.forName("类的全局定名")这种方式来获取到类的Class实例对象,除了这种,常用的还有其他两种,往下讲解~

  

二、Java反射机制中获取Class的三种方式及区别?

  

2.1 Class的几种获取方式

  (1)获取类的java.lang.Class实例对象,常见的三种方式分别为:

  由MyClass.class获取,其中MyClass是指由Class.forName(类的全局命名)获取的具体类~ ~,包名全局命名的类名由new MyClass()获取。getClass(),其中MyClass是指具体的类~(2)通过MyClass.class获取,JVM会使用ClassLoader类加载器将类加载到内存中,但并不会做任何类的初始化工作,返回java.lang.Class对象

  (3)通过Class.forName("类的全局定名")获取,同样,类会被JVM加载到内存中,并且会进行类的静态初始化工作,返回java.lang.Class对象

  (4)通过new MyClass().getClass()获取,这种方式使用了new进行实例化操作,因此静态初始化和非静态初始化工作都会进行,getClass方法属于顶级Object类中的方法,任何子类对象都可以调用,哪个子类调用,就返回那个子类的java.lang.Class对象

  

2.2 代码演示几种方式的区别

  创建一个实体类,分别在实体类中创建类的静态代码块、动态代码块、有参构造方法、无参构造方法,方便测试几种方式的区别及内存地址是否相同~

  (1)实体类:

  公共类MyClass {

  私有静态最终字符串staticStr= Hi

  private static int static int=2021;

  私有字符串id;

  静态{

  System.out.println(静态代码块:staticstr= staticstr ,static int= static int );

  }

  {

  System.out.println(动态代码块~ );

  }

  公共MyClass() {

  System.out.println(无参数构造方法~ );

  }

  公共MyClass(字符串id) {

  System.out.println(带参数的构造方法~ );

  this.id=id

  }

  公共字符串getId() {

  返回id;

  }

  公共void setId(字符串id) {

  this.id=id

  }

  @覆盖

  公共字符串toString() {

  返回“MyClass{”

  id= id \

  };

  }}(2)单元测试类:

  通过@Test标注对三种方法进行单元测试,然后对这三种方法的组合进行单元测试~

  包com . Justin . Java . lang;导入org . JUnit . test;/**

  * @程序:Jdk1.8Test

  * @描述:Java反射机制中获取类的班级实例对象的常见三种方式及区别对比

  * @作者:贾丝汀琴

  * @create: 2021/8/22 15:04

  * @版本:1.0.0版

  * */公共类MyClassTest {

  @测试

  公共void test1() {

  System.out.println(一我的班级方式=========);

  班级?1班=我的班。类;

  }

  @测试

  公共void test2()抛出ClassNotFoundException {

  System.out.println(二、Class.forName方式=========);

  class class 2=class。forname( com。贾斯汀。Java。郎。我的班级’);

  }

  @测试

  公共void test3() {

  System.out.println(三、新的MyClass().对象名方式=========);

  类别class3=新的MyClass().getClass();

  }

  @测试

  公共void测试12()抛出ClassNotFoundException {

  System.out.println(一我的班级方式=========);

  班级?1班=我的班。类;

  System.out.println(二、Class.forName方式=========);

  class class 2=class。forname( com。贾斯汀。Java。郎。我的班级’);

  }

  @测试

  公共void test13() {

  System.out.println(一我的班级方式=========);

  班级?1班=我的班。类;

  System.out.println(三、新的MyClass().对象名方式=========);

  类别class3=新的MyClass().getClass();

  }

  @测试

  公共void测试23()抛出ClassNotFoundException {

  System.out.println(二、Class.forName方式=========);

  class class 2=class。forname( com。贾斯汀。Java。郎。我的班级’);

  System.out.println(三、新的MyClass().对象名方式=========);

  类别class3=新的MyClass().getClass();

  }

  @测试

  公共无效测试()引发了ClassNotFoundException {

  System.out.println(四、三种方式内存地址比较=========);

  班级?1班=我的班。类;

  class class 2=class。forname( com。贾斯汀。Java。郎。我的班级’);

  类别class3=新的MyClass().getClass();

  System.out.println(比较结果=========);

  系统。出去。println(我的班级。班级和Class.forName内存地址比较是否相同:(class 1==class 2));

  系统。出去。println(我的班级。班级和新的MyClass().对象名内存地址比较是否相同:(class 1==class 3));

  系统。出去。println( class。对于名称和新的MyClass().对象名内存地址比较是否相同:(class 2==class 3));

  }}逐个执行单元,得出测试结果为:

  *测试1()方法

  一我的班级方式=========* test2()方法

  二、Class.forName方式=========静态代码块:staticStr=Hi,staticInt=2021* test3()方法

  三、新的MyClass().对象名方式=========静态代码块:staticStr=Hi,staticInt=2021动态代码块~无参构造方法~*测试12()方法

  一我的班级方式=========二、Class.forName方式=========静态代码块:staticStr=Hi,staticInt=2021* test13()方法

  一我的班级方式=========三、新的MyClass().对象名方式=========静态代码块:staticStr=Hi,staticInt=2021动态代码块~无参构造方法~*测试23()方法

  二、Class.forName方式=========静态代码块:staticStr=Hi,staticInt=2021三、新的MyClass().对象名方式=========动态代码块~无参构造方法~*测试()方法

  四、三种方式内存地址比较=========静态代码块:staticStr=Hi,staticInt=2021动态代码块~无参构造方法~比较结果=========MyClass.class和Class.forName内存地址比较是否相同:trueMyClass.class和新的MyClass().对象名内存地址比较是否相同:trueClass.forName和新的MyClass().对象名内存地址比较是否相同:真通过test1、test2、test3的测试结果验证了2.1 三种方式及区别中黄色标记部分的区别说明,即:

  MyClass.class不会做任何类的初始化工作Class.forName会进行类的静态初始化工作新的MyClass().对象名静态初始化和非静态初始化工作都会进行使用这三种方式任意一种最终在虚拟机(Java虚拟机的缩写)加载到内存中都会是内存地址相同的而test23组合得到的测试结果,说明静态代码块只会被加载一次~

  讲了这么多,除了知道基本原理和基本使用之外,更重要的还是要知道它的一些比较实际的应用场景,往下介绍~

  

三、Java反射机制的应用场景有哪些?

  

3.1 应用场景

   工厂模式中的简单工厂模式优化代理模式中的动态代理方式实现爪哇数据库编程数据库操作

3.2 简单工厂模式优化

  

3.2.1 什么是简单工厂模式?

  

3.2.2 简单工厂模式有什么用?

  

3.2.3 如何实现简单工程模式?

  实现例子:

  步骤1:创建抽象产品类

  公共接口产品{

  公共抽象void show();}步骤2:创建具体产品类:

  公共类尾叶鹅掌柴实现产品{

  @覆盖

  公共void show() {

  System.out.println(生产了产品a’);

  } }公共类产品b实现产品{

  @覆盖

  公共void show() {

  System.out.println(生产了产品b’);

  } }公共类产品c实现产品{

  @覆盖

  公共void show() {

  System.out.println(生产了产品c’);

  }}步骤3:创建简单工厂类

  公共类简单工厂{

  /**

  * 实现简单工厂模式

  * @参数商品名称产品标识

  * @返回返回具体的产品

  */

  公共静态产品创建产品(字符串pName){

  开关(pName){

  案例“答”:

  返回新的ProductA();

  案例“乙”:

  返回新的ProductB();

  案例“C”:

  返回新的产品c();

  默认值:

  返回空

  }

  }}步骤4:调用简单工厂类

  公共类简单工厂测试{

  公共静态void main(String[] args) {

  尝试{

  SimpleFactory.createProduct(A )。show();

  } catch (NullPointerException e) {

  System.out.println(没有A这款产品,无法生产~);

  }

  尝试{

  SimpleFactory.createProduct(B )。show();

  } catch (NullPointerException e) {

  System.out.println(没有B这款产品,无法生产~);

  }

  尝试{

  SimpleFactory.createProduct(C )。show();

  } catch (NullPointerException e) {

  System.out.println(没有C这款产品,无法生产~);

  }

  尝试{

  SimpleFactory.createProduct(D ).show();

  } catch (NullPointerException e) {

  System.out.println(没有D这款产品,无法生产~);

  }

  }}

3.2.4 简单工厂模式优化

  (1)简单工厂模式弊端

  操作成本高:每增加一个接口的子类,必须修改工厂类的逻辑系统复杂性提高:每增加一个接口的子类,都必须向工厂类添加逻辑这两点弊端从前面的例子简单工厂工厂类的实现,可以看出简单工厂模式中对工厂类简单工厂的维护成本有点大,因为实际中可能会很频繁的去更新具体产品类,每一次变更都需要去修改工厂类,此时就可以利用爪哇反射机制对简单工厂模式进行优化~

  (2)简单工厂模式的优化思路

  采用爪哇反射机制,通过传入子类全局定名(包名类名)动态的创建不同的子类对象实例,从而使得在不增加产品接口子类和修改工厂类的逻辑的情况下还能实现了工厂类对子类实例对象的统一创建~

  (3)简单工厂模式的优化步骤步骤1:创建工厂类

  采用爪哇反射机制对工厂类进行优化,主要是将类名即子类全局定名(包名类名)作为入参,通过Class.forName方式获取类的java.lang.Class实例对象,再通过班级实例对象的getInstance方法获取到具体子类的实例对象~

  公共类工厂{

  公共静态产品getInstance(字符串类名){

  产品实际产品=空

  尝试{

  class pClass=class。forname(类名);

  实积=(积)pclass。新实例();

  } catch(异常e) {

  e。printstacktrace();

  }

  返回真实产品

  }}步骤2:调用工厂类

  公共类工厂测试{

  公共静态void main(String[] args) {

  尝试{

  产品productA=工厂。getinstance( com。贾斯汀。Java。郎。productA’);

  producta。show();

  } catch (NullPointerException e) {

  System.out.println(没有A这款产品,无法生产~);

  }

  尝试{

  产品产品b=工厂。getinstance( com。贾斯汀。Java。郎。productB’);

  产品b。show();

  } catch (NullPointerException e) {

  System.out.println(没有B这款产品,无法生产~);

  }

  尝试{

  产品产品c=工厂。getinstance( com。贾斯汀。Java。郎。产品c’);

  产品c。show();

  } catch (NullPointerException e) {

  System.out.println(没有C这款产品,无法生产~);

  }

  尝试{

  产品productD=工厂。getinstance( com。贾斯汀。Java。郎。productD’);

  productd。show();

  } catch(异常e) {

  System.out.println(没有D这款产品,无法生产~);

  }

  }}优化结果:

  

3.2.5 简单工厂模式再次优化

  (1)再次优化背景

  (2)再次优化实现思路

  (3)再次优化实现步骤

  再次优化步骤1:相关优化与第一次优化保持不变~

  再次优化步骤2:配置类名对应全局定名(包名+类名)

  创建属性配置文件产品。属性

  //产品抽象类产品相关子类的全局定名(包名类名)定义ProductA=com。贾斯汀。Java。郎。productaproductb=com。贾斯汀。Java。郎。productbproductc=com。贾斯汀。Java。郎。产品c注意:将产品。属性需要存放在资源中心/主要/资源资源目录下,若资源目录不存在则需要手动创建~

  再次优化步骤3:修改调用工厂类

  公共类工厂测试{

  @测试

  公共空的测试()引发IOException {

  类加载器类加载器=this。获取类().获取类加载器();

  Properties prop=new Properties();

  道具。load(类加载器。getresourceasstream( product。属性’));

  字符串类名=" ";

  尝试{

  类名=prop。getproperty( ProductA );

  产品productA=工厂。getinstance(类名);

  producta。show();

  } catch (NullPointerException e) {

  System.out.println(没有A这款产品,无法生产~);

  }

  尝试{

  类名=prop。getproperty( ProductB );

  产品productA=工厂。getinstance(类名);

  producta。show();

  } catch (NullPointerException e) {

  System.out.println(没有B这款产品,无法生产~);

  }

  尝试{

  类名=prop。getproperty(产品c );

  产品productA=工厂。getinstance(类名);

  producta。show();

  } catch (NullPointerException e) {

  System.out.println(没有C这款产品,无法生产~);

  }

  }}运行结果:

  生产了产品A生产了产品B生产了产品丙

3.3 代理模式中的动态代理实现

  

3.3.1 什么是代理模式?

  什么?还是不太理解?

  代理模式又分为静态代理、动态代理,往下介绍~

  

3.3.2 什么是静态代理?

  

3.3.2 什么是动态代理?

  动态代理

  动态代理最常用的是爪哇岛开发工具包原生动态代理和字节码生成动态代理,往下介绍~

  JDK 原生动态代理

  爪哇岛开发工具包原生动态代理,主要利用了文档的java.lang.reflect。代理和Java。郎。重新生效。innvocationhandler这两个类来实现~

  通过java.lang.reflect。代理代理类的newProxyInstance方法,传递3个参数,分别是:目标对象的加载器通过MyClass.getClass().getClassLoader方式获取目标对象的实现接口类型通过Object.getClass().getInterfaces()方式获取InnvocationHandler事件处理器通过新的实例化对象并重写引起方法方式获取

  例子:

  用户接口类IUserDao

  公共接口IUserDao

  //添加数据

  public void insert();}目标对象类UserDao

  /**

  * @程序:数据结构

  * @描述:

  * @作者:贾丝汀琴

  * @create: 2021/8/23 23:32

  * @版本:1.0.0版

  * */公共类数据层实现IUserDao

  @覆盖

  public void insert() {

  System.out.println(添加数据);

  }}动态代理类UserProxy

  /**

  * @程序:JDK 1.8测试

  * @描述:动态代理类

  * @作者:贾丝汀琴

  * @create: 2021/8/23 23:31

  * @版本:1.0.0版

  * */公共类用户代理{

  私有对象目标;//目标对象

  公共用户代理(对象目标){

  目标=目标

  }

  /**

  * 利用文档获取到代理对象

  * @返回

  */

  公共对象getProxyInstance() {

  //目标对象的加载器

  类别载入器loader=target。getclass().获取类加载器();

  //目标对象的实现接口类型

  班级?[] interfaces=target.getClass().获取接口();

  //InnvocationHandler事件处理器实例对象

  调用处理程序h=新调用处理程序(){

  @覆盖

  公共对象调用(对象代理、方法方法、对象[]参数)抛出可投掷的

  System.out.println(添加数据前:手动开启事务);

  //执行目标对象方法

  对象值=方法。invoke(target,args);

  System.out.println(添加数据后:手动提交事务);

  返回空

  }

  };

  //传入3个参数,创建代理类的实例对象,并返回

  返回代理。newproxyinstance(loader,interfaces,h);

  }}动态代理单元测试类

  /**

  * @程序:动态代理单元测试类

  * @描述:

  * @作者:贾丝汀琴

  * @create: 2021/8/23 23:42

  * @版本:1.0.0版

  * */公共类UserProxyTest {

  @测试

  公共无效测试(){

  IUserDao target=new UserDao();

  System.out.println(目标对象信息:目标。getclass());

  //获取代理类实例对象

  IUserDao proxy=(IUserDao)新用户代理(目标).getProxyInstance();

  System.out.println(代理对象信息:代理。getclass());

  //执行代理方法

  代理。insert();

  }}单元测试执行结果

  目标对象信息:class com。贾斯汀。Java。反思。数据层代理对象信息:class com.sun.proxy.$Proxy2添加数据前:手动开启事务

  添加数据

  添加数据后:手动提交事务cglib动态代理

  面向方面编程结合了字节码生成动态代理和爪哇岛开发工具包原生动态代理来实现,这里不过多介绍,有兴趣小伙伴可以查阅资料学习下~

  

3.3.3 动态代理中如何利用Java反射机制?

  

3.4 Java JDBC数据库操作实现

  

3.4.1 利用反射加载JDBC驱动

   相信很多小伙伴都知道爪哇数据库编程连接数据库主要分为七大步骤,其中第一步加载数据库编程驱动,利用爪哇反射机制通过传入不同的驱动名称,加载不同数据库的驱动~

  班级。forname( com。MySQL。JDBC。司机’);

  //加载关系型数据库驱动班级。forname(甲骨文。JDBC。司机。Oracle驱动程序’);

  //加载神谕驱动

3.4.2 Java JDBC连接示例

  创建测试库表及数据

  创建数据库测试;-如果存在测试用户,则删除表;创建表测试。user(id int(7)主键非空auto _ increment,name varchar(255),sex char(1),age int(3))ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8 _ general _ ci;插入到测试中。用户(姓名、性别、年龄)值(张一,男,21);插入到测试中。用户(姓名、性别、年龄)值(张二,女,22);插入到测试中。用户(姓名、性别、年龄)值(张三,男,23);Java MySQL JDBC连接七大步骤~

  公共静态void main(String[] args)抛出ClassNotFoundException,SQLException {

  //1.加载数据库编程驱动

  班级。forname( com。MySQL。JDBC。司机’);

  //2.获取数据库的连接(连接)对象

  连接连接=驱动程序管理器。获取连接(

  jdbc:mysql://localhost/test ,//mysql连接url,测试表示你要连接的数据库名

  根,//数据库用户名

  ABC @ 123456’);//密码

  //3.获取数据库的操作(准备报表)对象

  准备语句准备语句=连接。prepare语句( select * from test。id=?的用户);

  //4.设置传入参数

  prepareStatement.setInt(1,1);

  //5.上传结构化查询语言语句到服务器执行(excute),并返回结果集(结果集)

  结果集结果=准备语句。执行查询();

  //6.处理返回的结果集结果集

  while (result.next()) {

  系统。出去。打印(结果。getint( id ),);

  系统。出去。打印(结果。getstring( name ),);

  系统。出去。打印(结果。getstring( sex ),);

  系统。出去。打印(结果。getint( age );

  系统。出去。打印( \ n );

  }

  //7.释放相关资源:连接对象、准备报表对象、结果集对象。

  联系。close();

  准备陈述。close();

  结果。close();

  }执行结果:

  1,张一,男,21Java Oracle JDBC连接七大步骤~

  公共类JdbcOracleTest {

  公共静态void main(String[] args)抛出ClassNotFoundException,SQLException {

  //1.加载数据库编程驱动

  班级。forname(甲骨文。JDBC。司机。Oracle驱动程序’);

  //2.获取数据库的连接(连接)对象

  连接连接=驱动程序管理器。获取连接(

  JDBC:甲骨文:瘦:@ 127。0 .0 .1:1521:orcl ,//oracle连接全球资源定位器(统一资源定位器)

  根,//数据库用户名

  ABC @ 123456’);//密码

  //3.获取数据库的操作(准备报表)对象

  准备语句准备语句=连接。prepare语句( select * from test。id=?的用户);

  //4.设置传入参数

  prepareStatement.setInt(1,1);

  //5.上传结构化查询语言语句到服务器执行(excute),并返回结果集(结果集)

  结果集结果=准备语句。执行查询();

  //6.处理返回的结果集结果集

  while (result.next()) {

  系统。出去。打印(结果。getint( id ),);

  系统。出去。打印(结果。getstring( name ),);

  系统。出去。打印(结果。getstring( sex ),);

  系统。出去。打印(结果。getint( age );

  系统。出去。打印( \ n );

  }

  //7.释放相关资源:连接对象、准备报表对象、结果集对象。

  联系。close();

  准备陈述。close();

  结果。close();

  }}数据库连接池配置spring-mybatis.xml

  !-基于tomcat jdbc连接池的数据源-

  bean id= data source class= com。贾斯汀。数据来源。Tomcat数据源 init-method=创建池

  !-基于数据库连接池连接池的数据源

  bean id= data source class= com。贾斯汀。数据来源。dbcp数据源 destroy-method= close -

  !-基于阿里德鲁伊连接池的数据源

  bean id= data source class= com。贾斯汀。数据来源。德鲁伊数据源 destroy-method= close -

  属性名称=driverClassName 值= $ { app-data-source。驱动程序类名} /

  属性名称=url 值=${app-data-source.url} /

  属性名称=用户名值= $ { app-data-source。用户名} /

  属性名称=密码值= $ { app-data-source。密码} /

  & ampl

  t;!-- 初始化连接大小 -->

   <property name="initialSize" value="${app-data-source.initialSize}" />

   <!-- 连接池最大数量 -->

   <property name="maxActive" value="${app-data-source.maxActive}" />

   <!-- 连接池最大空闲 -->

   <property name="maxIdle" value="${app-data-source.maxIdle}" />

   <!-- 连接池最小空闲 -->

   <property name="minIdle" value="${app-data-source.minIdle}" />

   <!-- 获取连接最大等待时间 -->

   <property name="maxWait" value="${app-data-source.maxWait}" />

   </bean>数据库配置信息jdbc.propertis

  #数据库连接驱动

  app-data-source.driverClassName=com.mysql.jdbc.Driver#数据库连接url

  app-data-source.url=jdbc:mysql://localhost:3306/test?useSSL=false&characterEncoding=UTF-8#数据库用户

  app-data-source.username=root

  #数据库用户密码(加密)app-data-source.password=abc@123456#连接池初始化大小

  app-data-source.initialSize=10#连接池最大数量

  app-data-source.maxActive=50#连接池最大空闲

  app-data-source.maxIdle=20#连接池最小空闲

  app-data-source.minIdle=5#获取连接最大等待时间

  app-data-source.maxWait=30000

面试总结

一、Java反射机制是什么?

  1、Java反射机制(Java Reflection)是Java语言中一种动态(运行时)访问、检测 & 修改它本身的能力,主要作用是动态(运行时)获取类的完整结构信息 & 调用对象的方法~

   更简单点的说就是Java程序在运行时(动态)通过创建一个类的反射对象,再对类进行相关操作,比如:

  获取该对象的成员变量 & 赋值调用该对象的方法(含构造方法,有参/无参)判断该对象所属的类2、更通俗点的说,我们使用某个类,都会知道这个类,以及要用它来做什么,可以直接通过new实例化创建对象,然后使用这个对象对类进行操作,这个就属于正射~

  3、而反射则是一开始并不知道要初始化的是什么类,无法使用new来实例化创建对象,主要是通过JDK提供的反射API来实现,在运行时才知道要操作的是什么类,并且可以获取到类的完整构造以及调用对应的方法,这就是反射~

  二、Java反射机制中获取Class的三种方式及区别?

  1、获取类的java.lang.Class实例对象,常见的三种方式分别为:

  通过MyClass.class获取通过Class.forName("类的全局定名")获取通过new MyClass().getClass()获取2、通过MyClass.class获取,JVM会使用ClassLoader类加载器将类加载到内存中,但并不会做任何类的初始化工作,返回java.lang.Class对象

  3、通过Class.forName("类的全局定名")获取,同样,类会被JVM加载到内存中,并且会进行类的静态初始化工作,返回java.lang.Class对象

  4、通过new MyClass().getClass()获取,这种方式使用了new进行实例化操作,因此== 静态初始化和非静态初始化工作都会进行 == ,getClass方法属于顶级Object类中的方法,任何子类对象都可以调用,哪个子类调用,就返回那个子类的java.lang.Class对象

  5、这3种方式,最终在JVM堆区对应类的java.lang.Class对象都属于同一个,也就是内存地址相同,进行==双等号比较结果为true,原因是JVM类加载过程中使用的是同一个ClassLoader类加载器加载某个类,不论加载多少次,生成到堆区的java.lang.Class对象始终只有一个,除非自定义类加载器,破坏JVM的双亲委派机制,使得同一个类被不同类加载器加载,JVM才会把它当做两个不同的java.lang.Class对象

  三、Java反射机制的应用场景有哪些?

  工厂模式中的简单工厂模式优化代理模式中的动态代理方式实现Java JDBC数据库操作推荐学习:《java教程》

  以上就是详细解析Java反射机制原理和几种Class获取方式的详细内容,更多请关注我们其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: