欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

java基础知识—Java中的反射机制,

来源: javaer 分享于  点击 47118 次 点评:102

java基础知识—Java中的反射机制,


1.java反射机制的定义

     首先,让我们来看看度娘是怎么定义反射机制的:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

2.java反射机制的优点和缺点

为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念

静态编译:在编译时确定类型,绑定对象,即通过。

动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。

一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。

它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。  1,丧失了编译时类型检查的好处 2,执行反射访问所需代码笨拙冗长 3,性能损失

 对于特定的复杂的系统编程任务,反射很有必要,如果编写的程序必须要与编译时未知的类一起工作,就可以用反射仅仅来实例化对象,但不应该通过反射来访问对象,应该通过被实例化对象的接口或者父类来访问对象的方法,这就是接口优先于反射机制的含义。


3.java中的Class类

在讲反射机制之前,我们不得不先了解一下Class类。

在程序运行期间,Java运行时系统始终未所有对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。这些信息可以通过专门的Java类来访问,而保存这些信息的类被称为Class类。(Class类是封装类型信息的类,每个类都有一个Class对象(保存在一个同名的.class文件中),每个java类运行时都在JVM里表现为一个class对象,当装载类时,Class类型的对象自动创建。某个类的Class对象被载入内存,它就用来创建这个类的所有对象。

Class类不是我们人为创建的,是由java虚拟机在我们生成.class文件的时候创建的,我们可以通过几种方法,获得这个Class类实例。下面介绍一下这几种方法:
  (1)利用对象调用getClass()方法获取该对象的Class实例;

(2)使用Class类的静态方法forName(),用类的名字获取一个Class实例;

       例如我们在连接Mysql数据时,就会用到:

Class.forName("com.mysql.jdbc.Driver");//加载Mysql驱动器</span>

面试题:Class.forName的作用:
     forName也是返回这个类(java.lang.String)的字节码,返回的方式分为两种情况:
     1.这个类的字节码已经加载到内存中,此时想要得到它的字节码,不需要再加载,而是找到这个字节码,将字节码返回。
     2.这个类的字节码还没有加载到内存中,首先用类加载器加载,加载进来以后将就字节码在虚拟机中缓存起来,同时forName方法返回刚才加载进来的字节码。 

 (3)运用.class的方式来获取Class实例,对于基本数据类型的封装类,还可以采用.TYPE来获取相对应的基本数据类型的Class实例。

public class Test {
	public static void main(String[] args){
		Date date=new Date();
		Class cl=date.getClass();//(1)调用.getClass()方法
		System.out.println(cl.getName());//output:java.util.Date
		Class c1=Integer.TYPE;//(3)调用.TYPE
		System.out.println(c1.getName());//output:int
		Class cl1=int.class;//(3)调用.class
		System.out.println(cl1.getName());//output:int
	}
}

4.获取反射类的实例

Class类中有一个方法叫做newInstance(),它可以用来创建一个Class类对象的新实例。Class对象包含的内容就是反射好的那个类,我们要构造那个类的新实例(新对象)。

4.1Class类的无参构造对象

public class Demo {
    public static void main(String[] args) {
        //实例化Class对象,forName()方法会抛异常
        Class<?> c = null;
        try {
            //这里需要完整的包名和类名
            c = Class.forName("java.lang.String");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
         
        //生成一个字符串的引用
        String s = null;
        try {
            //将构造好的对象向下转型为String类
            //newInstance()方法会抛异常
            s = (String) c.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        System.out.println("字符串长度: " + s.length());
    }
}
注意:因Class的newInstance是不接受参数的,只能利用默认构造函数。

4.2Class类的有参构造对象

import java.lang.reflect.Constructor;
 
public class Demo {
    //下面的几个方法抛出来的异常太多,为了代码的紧凑性,这里就直接抛给虚拟机了
    public static void main(String[] args) throws Exception {
        Class<?> c = null;
        try {
            c = Class.forName("java.lang.String");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        char[] ch = {'h','e','l','l','o'};
        String s = null;
        //获得Class类对象的有参构造方法,括号里面参数的写法是:类型.class
        Constructor<?> con = c.getConstructor(char[].class);
        //用此构造方法构造一个新的字符串对象,参数为一个char数组
        s = (String) con.newInstance(ch);
        System.out.println("构造的字符串:" + s);//output:hello
    }
}

5.获取类的构造器

 首先介绍一下Constructor类,这个类用来封装反射得到的构造器,Class有四个方法来获得Constructor对象

  • public Constructor<?>[] getConstructors()      返回类中所有的public构造器集合,默认构造器的下标为0
  • public Constructor<T> getConstructor(Class<?>... parameterTypes)   返回指定public构造器,参数为构造器参数类型集合
  • public Constructor<?>[] getDeclaredConstructors()  返回类中所有的构造器,包括私有
  • public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回任意指定的构造器
 从名字来看,还是很好懂的,带上Declared的都是获得所有的构造方法,包括私有,哈,这下我们就可以调用原本不允许调用的私有构造器了,看代码
/**
         * 获取构造方法Constructor
         * getConstructor()  only for public 
         * getDeclaredConstructor()  global access all 
         * 
         * */
        
        //指定参数列表获取特定的方法
        Constructor con = cls1.getDeclaredConstructor(new Class[]{String.class});
        con.setAccessible(true); //设置可访问的权限
        Object obj = con.newInstance(new Object[]{"liyang"});
        System.out.println(obj);  //打印一下这个对象的信息
        
//获取所有的构造方法集合
        Constructor con1[] = cls1.getDeclaredConstructors();
        con1[1].setAccessible(true);
        Object obj1 = con1[1].newInstance(new Object[]{"tom"});
        System.out.println(obj1);
解释一下:第一个是获得一个指定的方法,我们指定了参数是一个String类型,第二段我们获得了所有的构造方法集合,并选取了其中一个创建了新的对象。
注意,以上的四个方法全部需要抛出异常,当我们获得私有的方法的时候,要用setAccessible设置一下可访问的权限,例子中没有演示获取共有方法,那个比较简单,就不做介绍了,其实掌握了上面两个,其他就好理解了。

6.获取类的方法

 我觉得你已经可以帮我写这一段了,封装类的方法的类是Method.获取method也有四个方法,猜到了没??
  • public Method[] getMethods()    获取所有的共有方法的集合
  • public Method getMethod(String name,Class<?>... parameterTypes) 获取指定公有方法 参数1:方法名 参数2:参数类型集合  
  • public Method[] getDeclaredMethods()  获取所有的方法
  • public Method getDeclaredMethod(String name,Class<?>... parameterTypes) 获取任意指定方法
    看下面的例子吧
import java.lang.reflect.Method;
 
class Person {
    public void print(int i) {
        System.out.println("我在写数字: " + i);
    }
     
    public static void say(String str) {
        System.out.println("我在说: " + str);
    }
}
 
public class Demo {
    public static void main(String[] args) throws Exception {
        Person p = new Person();
        Class<?> c = p.getClass();
     
        //getMethod()方法需要传入方法名,和参数类型
        Method m1 = c.getMethod("print", int.class);
        //invoke()表示调用的意思,需要传入对象和参数
        m1.invoke(p, 10);
         
        Method m2 = c.getMethod("say", String.class);
        //这里的null表示不由对象调用,也就是静态方法
        m2.invoke(null, "你妹");
    }
}

7.获取类的成员变量

 了解了构造器,其实你可以猜到成员变量的获取方法了,成员变量用Field类进行封装。        主要的方法非常的类似:
  • public Field getDeclaredField(String name)  获取任意指定名字的成员
  • public Field[] getDeclaredFields()             获取所有的成员变量
  • public Field getField(String name)           获取任意public成员变量
  • public Field[] getFields()                          获取所有的public成员变量
    可以看出这些方法都是异曲同工的,好了直接看一下例子吧
import java.lang.reflect.Field;
 
class Person {
    public String name;
    private int age;
     
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
 
public class Demo {
    public static void main(String[] args) throws Exception {
        Person p = new Person("zhangsan",12);
 
        Class<?> c = p.getClass();
         
        //获取公共属性的值
        Field f1 = c.getField("name");
        //get(p)表明要获取是哪个对象的值
        String str = (String) f1.get(p);
        System.out.println("姓名: " + str);
         
        //获取私有属性的值
        Field f2 = c.getDeclaredField("age");
        //age是私有属性,所以要设置安全检查为true
        f2.setAccessible(true);
        int age = (int) f2.get(p);
        System.out.println("年龄: " + age);
    }
}

 



相关文章

    暂无相关文章
相关栏目:

用户点评