什么是反射机制?
Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。
Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。
换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。
简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。
JAVA反射机制提供了什么功能?
提供如下功能:
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判段任意一个类所具有的成员变量和方法
在运行时调用任一个对象的方法
在运行时创建新类对象
在使用Java的反射功能时,基本首先都要获取类的Class对象,再通过Class对象获取其他的对象。
反射机制的优点与缺点:
为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念,
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发。
它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
Java程序中的各个Java类属于同一类事物,描述这类事物的Java类就是Class类。
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的;
获得Class对象
每个类被加载后,系统会为该类生成对应的Class对象,通过Class对象可以访问到JVM中的这个类,
3种方式:
1、调用某个类的class属性获取Class对象,如Date.class会返回Date类对应的Class对象(其实就是得到一个类的一份字节码文件);
2、使用Class类的forName(String className)静态方法,className表示全限定名;如String的全限定名:java.lang.String;
3、调用某个对象的getClass()方法。该方法属于Object类;
Class<?> clz = new Date().getClass();
public class Demo{
public static void main(String[] args) throws Exception {
//获得Class对象的方法(三种)
method_1();
}
//一:调用属性
public static void method_1(){
Class<String> c = String.class;
System.out.println(c);
Class<String> c2 = String.class;
System.out.println(c == c2);
}
//二:使用forName()方法
public static void method_2() throws Exception{
Class<String> c = String.class;
//Class cla = Class.forName("String");//ERROR,
Class<String> cla =(Class<String>)Class.forName("java.lang.String");
System.out.println(c == cla);//true
}
//三:利用对象调用Object的getClass方法;
public static void method_3(){
Class<String> c = String.class;
Class c3 = new String().getClass();
System.out.println(c == c3);
}
}
method_1()运行结果:
class java.lang.String true |
method_2()运行结果:
true |
method_3()运行结果:
true |
九个预定义Class对象
基本的 Java 类型(boolean、byte、char、short、int、long、float和 double)和关键字void通过class属性也表示为Class 对象;
Class类中boolean isPrimitive() :判定指定的Class 对象是否表示一个基本类型。
包装类和Void类的静态TYPE字段;
Integer.TYPE == int.class ;
Integer.class == int.class;
数组类型的Class实例对象:
Class<String[]> clz = String[].class;
数组的Class对象如何比较是否相等?数组的维数和数组的类型;
Class类中 boolean isArray():判定此 Class对象是否表示一个数组类型。
Class中得到构造方法Constructor、方法Method、字段Field
常用方法:
Constructor类用于描述类中的构造方法:
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回该Class对象表示类的指定的public构造方法;
Constructor<?>[] getConstructors()
返回该Class对象表示类的所有public构造方法;
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回该Class对象表示类的指定的构造方法,和访问权限无关;
Constructor<?>[] getDeclaredConstructors()
返回该Class对象表示类的所有构造方法,和访问权限无关;
Method类用于描述类中的方法:
Method getMethod(String name, Class<?> ... parameterTypes)
返回该Class对象表示类和其父类的指定的public方法;
Method[] getMethods():
返回该Class对象表示类和其父类的所有public方法;
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回该Class对象表示类的指定的方法。和访问权限无关,但不包括继承的方法;
Method[] getDeclaredMethods(): 获得类所有的方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法;
利用反射创建对象
创建对象:
1、使用Class对象的newInstance()方法创建该Class对象的实例,此时该Class对象必须要有无参数的构造方法。
2、使用Class对象获取指定的Constructor对象,再调用Constructor的newInstance()方法创建对象类的实例,此时可以选择使用某个构造方法。如果这个构造方法被私有化起来,那么必须先申请访问,将可以访问设置为true;
使用反射调用方法
每个Method的对象对应一个具体的底层方法。获得Method对象后,程序可以使用Method里面的invoke方法来执行该底层方法。
Object invoke(Object obj,Object ... args):obj表示调用底层方法的对象,后面的args表示传递的实际参数。
如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为null,想想为什么?
如果底层方法所需的形参个数为 0,则所提供的args 数组长度可以为0 或null。
不写,null,或new Object[]{}
若底层方法返回的是数组类型,invoke方法返回的不是底层方法的值,而是底层方法的返回类型;
------- android培训、java培训、期待与您交流! --------