反射的基本使用

发布时间:2019-11-19 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了反射的基本使用脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

大家好,我是IT修真院深圳分院第6期的学员,一枚正直纯洁善良的java程序员

今天给大家分享一下,修真院官网Java任务一,深度思考中的知识点——反射的基本使用

1.背景介绍

反射的概述

反射是框架设计的灵魂

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取信息以及动态调用对象的方法的特性称为java语言的反射机制。

要想获得类的各种信息,必须先要获取到该类的字节码文件对象。该对象也就是java.lang.Class类,Class类用于表示java程序编译后得到的.class文件。

Class类的理解

Java程序在运行时,系统会对所有的对象进行所谓的运行时类型标识(RTTI,Run-time TyPE Identification),其作用是在运行时识别一个对象的类型和类的信息。

传统的”RRTI”,它假定我们在编译期已知道了所有类型(在没有反射机制时,一般都是编译期已确定其类型,如new对象时该类必须已定义好);另外一种是反射机制,它允许我们在运行时发现和使用类型的信息。

在Java中用来表示运行时类型信息的对应类就是Class类,Class类也是一个实实在在的类,存在于JDK的java.lang包中。

Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。

JVM为每种类型管理一个独一无二的Class对象。也就是说,无论创建多少个实例对象,在内存中每个类有且只有一个相对应的Class对象,并且基本的java类型和关键字void也都对应一个Class对象。运行程序时,JVM首先检查所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入

2.知识剖析

在这里先看一下java为我们提供了哪些反射机制中的类:

java.lang.Class;

java.lang.reflect.Constructor;

java.lang.reflect.Field; 

java.lang.reflect.Method;

java.lang.reflect.Modifier;

反射的基本运用:Class对象获取方式

之前说了,Class对象是jvm用来保存对应实例对象的相关信息的,除此之外,我们完全可以把Class对象看成一般的实例对象。得到一个实例对象对应的Class对象有以下三种方式:

1.通过实例变量的getClass()方法

[java] view plain copy
test3 test3 =new Test3();  
  
Class c3 =test3.getClass();  

根据已经实例化的对象,利用getClass方法

2.通过类Class的静态方法forName()

[java] view plain copy
Classc2 =Class.forName("com.getClassObject.@R_126_1222@");  

传入的参数是对应类的全限定名

3.直接给出对象类文件的.class

[java] view plain copy
Class c1 =test1.class;  

反射的基本运用:判断是否为某个类的实例

一般地,我们用instanceof关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()方法来判断是否为某个类的实例,它是一个Native方法

[java] view plain copy
Class cls =Class.forName("com.isInstance.Demo"); //创建了一个Demo类的Class对象  
  
boolean b1 =cls.isInstance(new Integer(37));  

反射的基本运用:创建实例

通过反射来生成对象主要有两种方式:

(1)使用Class对象的newInstance()方法来创建Class对象对应类的实例。

//获取class对象

[java] view plain copy
Class c1 =Class.forName("com.createinstance.Instance1");  

//第一种方式:根据class对象,创建对应的实例

//调用无参数的构造函数,直接调用Class类中的newInstance

[java] view plain copy
Instance1 instance1 = (Instance1)c1.newInstance();  

(2)先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。

//获取Instance1所对应的Class对象

[java] view plain copy
Class c2 =Instance1.class;  

//获取Instance1类带一个int参数的构造器

//若想调用有参构造函数,则需要调用Constructor类中newInstance()方法

[java] view plain copy
Constructor constructor =c2.getConstructor(int.class);  

//根据构造器创建实例

[htML] view plain copy
Object obj =constructor.newInstance(3213);  

反射的基本运用:获取方法

获取某个Class对象的方法集合,主要有以下几个方法:

(1) getDeclaredMethods() 方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

(2) getMethods() 方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。

(3) getMethod("add", int.class, int.class) 方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。

[java] view plain copy
Class c =Class.forName("com.getMethod.methodClass");  

//获取methodClass类的所有公有方法(可获取到父类的方法)

[java] view plain copy
Method[]methods =c.getMethods();  

//获取methodClass类的所有的方法

[java] view plain copy
Method[]declaredMethods =c.getDeclaredMethods();  
//获取指定方法,methodClass类的add方法

[java] view plain copy
Method publicMethod =c.getMethod("add", int.class, int.class);  
//获取指定私有方法,div方法

[java] view plain copy
Method privateMethod =c.getDeclaredMethod("div", int.class, int.class);  

反射的基本运用:获取构造器信息

获取类构造器的用法与上述获取方法的用法类似。主要是通过Class类的getConstructor方法得到Constructor类的一个实例,而Constructor类有一个newInstance方法可以创建一个对象实例。

[java] view plain copy
public T newInstance(Object ... initargs)  

具体方法同获取对应类方法

反射的基本运用:获取类的成员变量(字段)信息

主要是这几个方法:

getFiled: 访问公有的成员变量

getDeclareDField:所有已声明的成员变量。但不能得到其父类的成员变量。

getFileds和getDeclaredFields用法同上(参照Method)

反射的基本运用:反射用于工厂模式

先看看传统的工厂模式

主类如下

[java] view plain copy
interface Fruit {  
  
void eat();  
  
}  

[java] view plain copy
class Apple implements Fruit {  
    public void eat(){  
        System.out.PRintln("Eat Apple");  
    }  
}  

[html] view plain copy
class Orange implements Fruit {  
    public void eat(){  
        System.out.println("Eat Orange");  
    }  
}  

工厂类

[java] view plain copy
public class Factory {  
  
public static Fruit getInstance(String fruitName){  
  
Fruit f=null;  
  
        if("Apple".equals(fruitName)){  
  
        f=new Apple();  
  
        }  
  
if("Orange".equals(fruitName)){  
  
f=new Orange();  
  
        }  
  
return f;  
  
    }  
  
}  
可以看到如果我要新增一个实现类,就要在工厂类中改代码,耦合度较高。

利用反射实现工厂

[java] view plain copy
public class ReflexFactory {  
  
public static Fruit2 getInstances(String classname) {  
  
Fruit2 f2 =null;  
  
        try {  
  
            //利用反射  
  
            f2 = (Fruit2)Class.forName(className).newInstance();  
  
        }catch (Exception e) {  
  
e.printStackTrace();  
  
        }  
  
return f2;  
  
    }  
  
}  
当如果要新增实现类的话,只要将传入的参数改变就好,无需更改工厂内的代码。

3.常见问题

4.解决方案

5.编码实战

6.扩展思考

理解泛化的Class对象引用

由于Class的引用总是指向某个类的Class对象,利用Class对象可以创建实例,这也就说明Class对象的引用指向的是对象确切的类型。在Java SE5引入泛型后,使我们可以利用泛型来表示Class对象更具体的类型,即使在运行期间会被擦除,但编译期足以确保我们使用正确的对象类型。

7.参考文献

链接:https://blog.csdn.net/javazej...

作者:zejian_

链接:https://blog.csdn.net/sinat_3...

作者:敬业的小码哥

8.更多讨论

反射机制的作用?

1,反编译:.class-->.java

2,通过反射机制访问java对象的属性,方法,构造方法等;

暴力反射?

获取类的私有成员。通过setAccessible(true)方法,设置成可访问。

类加载的过程?

加载:通过一个类的完全限定查找此类字节码文件,并利用字节码文件创建一个Class对象。

链接:验证字节码的安全性和完整性,准备阶段正式为静态域分配存储空间,注意此时只是分配静态成员变量的存储空间,不包含实例成员变量,如果必要的话,解析这个类创建的对其他类的所有引用。

初始化:类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量。

反射的应用场景?

Java的反射特性一般结合注解和配置文件(如:XML)来使用,这也是大部分框架(Spring等)支持两种配置方式的原因。还有著名的junit测试框架也是利用反射方法名和参数名来进行测试的。

今天的分享就到这里啦,欢迎大家点赞、转发、留言、拍砖~

脚本宝典总结

以上是脚本宝典为你收集整理的反射的基本使用全部内容,希望文章能够帮你解决反射的基本使用所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。