Java反射机制

  Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在。灵活掌握Java反射机制,对大家以后学习框架技术有很大的帮助。
那么什么是Java的反射呢?

  大家都知道,要让Java程序能够运行,那么就得让Java类要被Java虚拟机加载。Java类如果不被Java虚拟机加载,是不能正常运行的。现在我们运行的所有的程序都是在编译期的时候就已经知道了你所需要的那个类的已经被加载了。

  Java的反射机制是在编译并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知、自审。使用在编译期并不知道的类。这样的特点就是反射。
那么Java反射有什么作用呢?
     假如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?这是不能通过编译的。利用Java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。

  Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。大家都用过Jcreator和eclipse。当我们构建出一个对象的时候,去调用该对象的方法和属性的时候。一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利用了Java反射的原理,是对我们创建对象的探知、自审。

    Class类

       要正确使用Java反射机制就得使用java.lang.Class这个类。它是Java反射机制的起源。当一个类被加载以后,Java虚拟机就会自动产生一个Class对象。通过这个Class对象我们就能获得加载到虚拟机当中这个Class对象对应的方法、成员以及构造方法的声明和定义等信息,jvm使用ClassLoader将字节码文件(class文件)加载到方法区内存中。

Class clazz = ClassLoader.getSystemClassLoader().loadClass("com.mypackage.MyClass");

 可见ClassLoader根据类的完全限定名加载类并返回了一个Class对象,而java反射的所有起源都是从这个class类开始的。

反射API
       反射API用于反应在当前Java虚拟机中的类、接口或者对象信息
    功能
        —获取一个对象的类信息.
       —获取一个类的访问修饰符、成员、方法、构造方法以及超类的信息.
       —检获属于一个接口的常量和方法声明.
       —创建一个直到程序运行期间才知道名字的类的实例.
       —获取并设置一个对象的成员,甚至这个成员的名字是
   在程序运行期间才知道.

       —检测一个在运行期间才知道名字的对象的方法

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

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

 使用反射机制的步骤:

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

代码示例:

public class Person implements China{
      private String name;
      private int age ;
      private char sex ;

      public Person() {
           super ();
     }

      public Person(String name, int age, char sex) {
           super ();
           this .name = name;
           this .age = age;
           this .sex = sex;
     }

      public String getName() {
           return name ;
     }

      public void setName(String name) {
           this .name = name;
     }

      public int getAge() {
           return age ;
     }

      public void setAge(int age) {
           this .age = age;
     }

      public char getSex() {
           return sex ;
     }

      public void setSex(char sex) {
           this .sex = sex;
     }
      public void eat()
     {
          System. out .println("吃了" );
     }

      @Override
      public String toString() {
           return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]" ;
     }

      @Override
      public void sayChina() {
           // TODO Auto-generated method stub
          System. out .println("作者:" + AUTHOR + "国籍:"+ NATIONAL );
     }

      @Override
      public String sayHello(String name, int age, char sex) {
           // TODO Auto-generated method stub
           return "姓名:" + name + "年龄:"+ age + "性别:" + sex;
     }

}
public class ClassDemo02 {

     public static void main(String[] args) {
          Person p1 = new Person("小明" ,20,'男' );
          Person p2 = new Person("小红" ,23,'女' );

           //创建Class对象的方式一:(对象.getClass()),获取person类中的字节码文件
          Class class1 = p1.getClass();
          System. out.println(p1.getClass().getName());
          Class class2 = p2.getClass();
          System. out.println(class1 == class2 );

          System. out.println("==============================" );
           //创建Class对象的方式二:(类.class:需要输入一个明确的类,任意一个类型都有一个静态的class属性)
          Class class3 = Person.class;
          System. out.println(class1 == class2);

          System. out.println("==============================" );
           //创建Class对象的方式三:(forName():传入时只需要以字符串的方式传入即可)
           //通过Class类的一个forName(String className)静态方法返回一个Class对象,className必须是全路径名称;
           //Class.forName()有异常:ClassNotFoundException

          Class class4 = null;
          try {
              class4 = Class.forName("cn.itcast.Person");
          } catch (ClassNotFoundException e) {
               // TODO Auto-generated catch block
              e.printStackTrace();
          }
          System. out.println(class4 == class3);
     }
}

注意:在开发中一般使用第三种方法,因为第三种接收的是一个字符串路径,将来可以通过配置文件获取,通用性好;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值