>  기사  >  Java  >  Java 리플렉션의 역할에 대한 자세한 설명

Java 리플렉션의 역할에 대한 자세한 설명

PHP中文网
PHP中文网원래의
2017-06-22 14:20:20989검색

Java의 반사 메커니즘은 Java의 기능 중 하나이며, 반사 메커니즘은 프레임워크 기술 구축의 기초입니다. Java Reflection 메커니즘을 유연하게 익히는 것은 앞으로 프레임워크 기술을 배우는 모든 사람에게 큰 도움이 될 것입니다.

그럼 Java에서 리플렉션이란 무엇인가요?

우리 모두는 Java 프로그램이 실행되기 위해서는 Java 클래스가 Java 가상 머신에 의해 로드되어야 한다는 것을 알고 있습니다. Java 클래스는 Java 가상 머신에 의해 로드되지 않으면 정상적으로 실행될 수 없습니다. 이제 우리가 실행하는 모든 프로그램은 컴파일 중에 필요한 클래스가 로드되었음을 알고 있습니다.

Java의 반사 메커니즘은 컴파일 중에 어떤 클래스가 로드되는지 결정하지 않고 프로그램이 실행될 때 로드, 감지 및 자체 검사만 한다는 것입니다. 컴파일 타임에 알려지지 않은 클래스를 사용하십시오. 이러한 기능은 반사입니다.

그럼 Java 리플렉션은 무엇을 합니까?

두 명의 프로그래머가 있다고 가정해 보겠습니다. 한 프로그래머가 프로그램을 작성할 때 두 번째 프로그래머가 작성한 클래스를 사용해야 하는데 두 번째 프로그래머가 자신이 작성한 클래스를 완료하지 못합니다. 그렇다면 첫 번째 프로그래머의 코드가 컴파일될 수 있을까요? 이는 컴파일할 수 없습니다. Java 리플렉션 메커니즘을 사용하면 첫 번째 프로그래머는 두 번째 프로그래머가 작성한 클래스를 가져오지 않고도 자신의 코드 컴파일을 완료할 수 있습니다.

Java의 반사 메커니즘은 클래스의 기본 구조를 알고 있습니다. Java의 클래스 구조를 감지하는 이러한 기능을 Java 클래스의 "자기 검토"라고 합니다. 모두가 Jcreator와 Eclipse를 사용해 왔습니다. 객체를 생성할 때 객체의 메서드와 속성을 호출합니다. 한 번의 클릭으로 컴파일 도구는 사용자가 선택할 수 있도록 개체에서 사용할 수 있는 모든 메서드와 속성을 자동으로 나열합니다. 이는 Java 리플렉션 원리를 사용하여 우리가 생성한 객체를 감지하고 자체 검사합니다.

클래스 클래스

java.lang.class 클래스를 사용하려면 java 반사 메커니즘을 올바르게 사용해야 합니다. Java의 반사 메커니즘의 기원입니다. 클래스가 로드되면 JVM(Java Virtual Machine)은 자동으로 Class 객체를 생성합니다. 이 Class 객체를 통해 가상 머신에 로드된 Class 객체에 해당하는 메소드, 멤버, 생성자의 선언 및 정의 등의 정보를 얻을 수 있습니다. 리플렉션 API는 현재 Java Virtual Machine의 클래스, 인터페이스 또는 객체 정보를 반영하는 데 사용됩니다. —객체의 하나의 클래스 정보를 가져옵니다.

- 액세스 수정자, 멤버, 메서드, 생성자 및 슈퍼클래스 정보를 얻습니다.

- 인터페이스에 속하는 상수 및 메서드 선언을 검색합니다. —프로그램이 실행될 때까지 이름을 알 수 없는 클래스의 인스턴스를 만듭니다.

—객체의 멤버를 가져오고 설정합니다. 멤버 이름이

인 경우에도 프로그램이 실행될 때까지 알 수 없습니다.
- 런타임 중에만 이름이 알려진 객체를 검색하는 방법

Java 리플렉션 메커니즘을 사용하면 Java 가상 머신에 로드된 클래스 정보를 유연하게 감지할 수 있습니다. 물론 이런 종류의 감지는 작업의 성능을 약화시키므로 반사를 언제 사용할지는 요구사항, 비즈니스 규모, 경험 축적에 따라 달라집니다.

그렇다면 런타임 시 클래스 정보를 알기 위해 리플렉션 API를 어떻게 사용합니까? 코드 예:

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.swing.JOptionPane;
/**
  *本类用于测试反射API,利用用户输入类的全路径,
*找到该类所有的成员方法和成员属性
  */
public class MyTest {
     /**
     *构造方法
     */
    public MyTest(){
       String classInfo=JOptionPane.showInputDialog(null,"输入类全路径");//要求用户输入类的全路径
       try {
           Class cla=Class.forName(classInfo);//根据类的全路径进行类加载,返回该类的Class对象
          
           Method[] method=cla.getDeclaredMethods();//利用得到的Class对象的自审,返回方法对象集合
          
           for(Method me:method){//遍历该类方法的集合
              System.out.println(me.toString());//打印方法信息
           }
          
           System.out.println("********");
          
           Field[] field=cla.getDeclaredFields();//利用得到的Class对象的自审,返回属性对象集合
           for(Field me:field){ //遍历该类属性的集合
              System.out.println(me.toString());//打印属性信息
           }
       } catch (ClassNotFoundException e) {
           e.printStackTrace();
       }
    }
    public static void main(String[] args) {
       new MyTest();
    }
}
실행할 때 javax.swing.JFrame을 입력하면 실행 결과는 다음과 같습니다.

public void javax.swing.JFrame.remove(java.awt.Component )
public void javax.swing.JFrame.update(java.awt.Graphics)

…………

********

public static final int javax.swing.JFrame.EXIT_ON_CLOSE

private int javax.swing.JFrame.defaultCloseOperation

…………

    大家可以发现,类的全路径是在程序运行的时候,由用户输入的。所以虚拟机事先并不知道所要加载类的信息,这就是利用反射机制来对用户输入的类全路径来对类自身的一个自审。从而探知该类所拥有的方法和属性。

通过上面代码,大家可以知道编译工具为什么能够一按点就能列出用户当前对象的属性和方法了。它是先获得用户输入对象的字符串,然后利用反射原理来对这样的类进行自审,从而列出该类的方法和属性。

使用反射机制的步骤:

u导入java.lang.relfect 包

u遵循三个步骤
第一步是获得你想操作的类的 java.lang.Class 对象
第二步是调用诸如 getDeclaredMethods 的方法
第三步使用 反射API 来操作这些信息

获得Class对象的方法

u如果一个类的实例已经得到,你可以使用

       【Class c = 对象名.getClass(); 

      例: TextField t = new TextField();

              Class c = t.getClass();

              Class s = c.getSuperclass();

u如果你在编译期知道类的名字,你可以使用如下的方法

Class c = java.awt.Button.class; 
或者

         Class c = Integer.TYPE;

u如果类名在编译期不知道, 但是在运行期可以获得, 你可以使用下面的方法

          Class c = Class.forName(strg);

   这样获得Class类对象的方法,其实是利用反射API把指定字符串的类加载到内存中,所以也叫类加载器加载方法。这样的话,它会把该类的静态方法和静态属性,以及静态代码全部加载到内存中。但这时候,对象还没有产生。所以为什么静态方法不能访问非静态属性和方法。因为静态方法和属性产生的时机在非静态属性和方法之前。

代码示例:

package  com;
 
public class MyTest {
    public static void main(String[] args) {
       TestOne  one=null;
       try{
       Class  cla=Class.forName("com.TestOne");//进行com.TestOne类加载,返回一个Class对象
       System.out.println("********");
       one=(TestOne)cla.newInstance();//产生这个Class类对象的一个实例,调用该类无参的构造方法,作用等同于new TestOne()
       }catch(Exception e){
           e.printStackTrace();
       }
       TestOne two=new TestOne();
  System.out.println(one.getClass() == two.getClass());//比较两个TestOne对象的Class对象是否是同一个对象,在这里结果是true。说明如果两个对象的类型相同,那么它们会有相同的Class对象
    }
}
 
class TestOne{
    static{
       System.out.println("静态代码块运行");
    }
    TestOne(){
       System.out.println("构造方法");
    }
}

  以上代码过行的结果是:

静态代码块运行

***********

构造方法

构造方法


代码分析:

在进行Class.forName("com.TestOne")的时候,实际上是对com.TestOne进行类加载,这时候,会把静态属性、方法以及静态代码块都加载到内存中。所以这时候会打印出"静态代码块运行"。但这时候,对象却还没有产生。所以"构造方法"这几个字不会打印。当执行cla.newInstance()的时候,就是利用反射机制将Class对象生成一个该类的一个实例。这时候对象就产生了。所以打印"构造方法"。当执行到TestOne two=new TestOne()语句时,又生成了一个对象。但这时候类已经加载完毕,静态的东西已经加载到内存中,而静态代码块只执行一次,所以不用再去加载类,所以只会打印"构造方法",而"静态代码块运行"不会打印。

反射机制不但可以例出该类对象所拥有的方法和属性,还可以获得该类的构造方法及通过构造方法获得实例。也可以动态的调用这个实例的成员方法。

代码示例:

package reflect;
 
import java.lang.reflect.Constructor;
 
 
/**
 *
 * 本类测试反射获得类的构造器对象,
 * 并通过类构造器对象生成该类的实例
 *
 */
public class ConstructorTest {
 
    public static void main(String[] args) {
       try {
           //获得指定字符串类对象
           Class cla=Class.forName("reflect.Tests");
           //设置Class对象数组,用于指定构造方法类型
           Class[] cl=new Class[]{int.class,int.class};
          
           //获得Constructor构造器对象。并指定构造方法类型
           Constructor con=cla.getConstructor(cl);
          
           //给传入参数赋初值
           Object[] x={new Integer(33),new Integer(67)};
          
           //得到实例
           Object obj=con.newInstance(x);
       } catch (Exception e) {
           e.printStackTrace();
       }
    }
 
}
 
class Tests{
    public Tests(int x,int y){
       System.out.println(x+"    "+y);
    }
}

运行的结果是” 33    67。说明我们已经生成了Tests这个类的一个对象。 

위 내용은 Java 리플렉션의 역할에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.