什么叫JAVA反射技术(Reflection)?
谈到反射,我们首先了解下动态语言。
“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。
从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。
尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。
这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。
换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),
并生成其对象实体、或对其fields设值、或唤起其methods。
这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。
Reflection和introspection是常被并提的两个术语。
那在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?
答案是肯定的。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。
JAVA反射提供了那些功能
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时调用任意一个对象的方法。
Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其
modifiers(诸如public, static 等等)、
superclass(例如Object)、实现之
interfaces(例如Serializable),也包括fields和methods的所有信息,并可于运行时改变fields内容或调用methods。
JAVA反射会用到哪些类
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中:
- Class类:代表一个类。
- Field 类:代表类的成员变量(成员变量也称为类的属性)。
- Method类:代表类的方法。
- Constructor 类:代表类的构造方法。
- Array类:提供了动态创建数组,以及访问数组的元素的静态方法
JAVA反射我们怎么用
Class是Reflection起源,针对任何你想探勘的class,唯有先为它产生一个Class Object,接下来才能经由后者唤醒
为数十多个的Reflection APIs
1、如何获得获得一个类以及类的相关信息
-
-
-
-
- public static void main(String[] args) {
- Demo demo=new Demo();
-
- System.out.println(demo.getClass().getName());
-
- System.out.println(Demo.class.getName());
-
- System.out.println(Demo.class.getSimpleName());
- }
打印结果:
com.reflect.Demo
com.reflect.Demo
Demo
这个例子告诉我们既可以通过对象调用getClass方法获取类的信息,也可以直接类.class的形式。
2、我们所常见的Class.forName(" ");
- public static void main(String[] args) {
- Class<?> demo1=null;
- Class<?> demo2=null;
- Class<?> demo3=null;
- try
- {
- demo1=Class.forName("com.reflect.Demo");
- }
- catch (ClassNotFoundException e)
- {
- e.printStackTrace();
- }
- demo2=new Demo().getClass();
- demo3=Demo.class;
- System.out.println("类名称"+demo1.getName());
- System.out.println("类名称"+demo2.getName());
- System.out.println("类名称"+demo3.getName());
- }
打印结果:
类名称com.reflect.Demo
类名称com.reflect.Demo
类名称com.reflect.Demo
记住这是第三种获得类的方式,给定完整的字符串名的类或接口,返回一个类对象。
3、通过一个类去实例化它的对象,不采取new的方式
- public static void main(String[] args) {
- Class<?> demo = null;
- try
- {
- demo = Class.forName("com.reflect.Person");
- }
- catch (ClassNotFoundException e)
- {
- e.printStackTrace();
- }
-
- Person person = null;
- try
- {
- person = (Person)demo.newInstance();
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- person.setName("jay");
- person.setAge(11);
- System.out.println(person);
- }
打印结果:
[jay||11]
这里我们应该看到了newInstance方法,调用它就能返回一个类的实例对象,注意的是,定义的类必须提供一个无参的构造方法才能通过此方法去实例化。
如果没有提供呢,我们是不是就没法通过反射的方式实例化了呢,当然不会,请看下一个示例。
4、实例化一个无参构造方法的类
- public static void main(String[] args) {
- Class<?> demo = null;
- try
- {
- demo = Class.forName("com.reflect.Person");
- }
- catch (ClassNotFoundException e)
- {
- e.printStackTrace();
- }
-
- try
- {
- Person person = (Person)demo.getConstructor(new Class[]{String.class}).newInstance(new Object[]{"Rollen"});
- System.out.println(person);
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
- }
打印结果:
[Rollen||0]
因为构造方法的参数个数及类型都是未知的,所以这里用到的是传数组的方式。
5、得到一个类的所有接口
- public static void main(String[] args) {
- Class<?> demo=null;
- try
- {
- demo=Class.forName("com.reflect.People");
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
-
- Class<?> intes[]=demo.getInterfaces();
-
- for (int i = 0; i < intes.length; i++)
- {
- System.out.println("实现的接口 "+intes[i].getName());
- }
- }
打印结果:
实现的接口 com.reflect.China
6、得到一个类的父类
- public static void main(String[] args) {
- Class<?> demo=null;
- try
- {
- demo=Class.forName("com.reflect.People");
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
-
- Class<?> temp=demo.getSuperclass();
- System.out.println("继承的父类为: "+temp.getName());
- }
打印结果:
继承的父类为: java.lang.Object
7、得到一个类的所有构造方法
- public static void main(String[] args) {
- Class<?> demo = null;
- try
- {
- demo = Class.forName("com.reflect.People");
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- Constructor<?>cons[]=demo.getConstructors();
- for (int i = 0; i < cons.length; i++)
- {
- System.out.println("构造方法: "+cons[i]);
- }
- }
打印结果:
构造方法: public com.reflect.People(java.lang.String)
构造方法: public com.reflect.People()
8、得到所有构造方法的修饰类型及参数类型
- public static void main(String[] args){
- Class<?> demo = null;
- try
- {
- demo = Class.forName("com.reflect.People");
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- Constructor<?> cons[] = demo.getConstructors();
- for (int i = 0; i < cons.length; i++)
- {
- Class<?> p[] = cons[i].getParameterTypes();
- System.out.print("构造方法: ");
-
- int mo = cons[i].getModifiers();
- System.out.print(Modifier.toString(mo) + " ");
-
- String consName=cons[i].getName();
- System.out.print(consName+"(");
- for (int j = 0; j < p.length; ++j)
- {
-
- String typeName=p[j].getName();
- System.out.print(typeName + " arg" + i);
- if (j < p.length - 1)
- {
- System.out.print(",");
- }
- }
- System.out.println("){}");
- }
- }
打印结果:
构造方法: public com.reflect.People(java.lang.String arg0){}
构造方法: public com.reflect.People(){}
9、得到属性的修饰符,及类型和名字
- public static void main(String[] args) {
- Class<?> demo = null;
- try
- {
- demo = Class.forName("com.reflect.People");
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- System.out.println("===============本类属性========================");
-
- Field[] field = demo.getDeclaredFields();
- for (int i = 0; i < field.length; i++)
- {
-
- int mo = field[i].getModifiers();
- String priv = Modifier.toString(mo);
-
- Class<?> type = field[i].getType();
-
- String name=field[i].getName();
- System.out.println(priv + " " + type.getName() + " "+ name + ";");
- }
- System.out.println("===============实现的接口或者父类的属性========================");
-
- Field[] filed1 = demo.getFields();
- for (int j = 0; j < filed1.length; j++)
- {
-
- int mo = filed1[j].getModifiers();
- String priv = Modifier.toString(mo);
-
- Class<?> type = filed1[j].getType();
-
- String name=filed1[j].getName();
- System.out.println(priv + " " + type.getName() + " "+ name + ";");
- }
- }
打印结果:
===============本类属性========================
private java.lang.String sex;
===============实现的接口或者父类的属性========================
public static final java.lang.String name;
public static final int age;
10、通过反射的方式调用某个对象的方法
- public static void main(String[] args) {
- Class<?> demo = null;
- try
- {
- demo = Class.forName("com.reflect.People");
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- try
- {
-
- Method method = demo.getMethod("sayChina");
- method.invoke(demo.newInstance());
-
- method = demo.getMethod("sayHello", new Class[]{String.class, int.class});
- method.invoke(demo.newInstance(), new Object[]{"Rollen", 20} );
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- }
打印结果:
hello ,china
Rollen 20
11、通过反射操作属性
正常情况下,我们是不可以直接操作其它某个对象的私有属性,但是反射可以做到
- public static void main(String[] args) throws Exception {
- Class<?> demo = null;
-
- Object obj = null;
-
- demo = Class.forName("com.reflect.People");
-
- obj = demo.newInstance();
-
- Field field = demo.getDeclaredField("sex");
-
- field.setAccessible(true);
-
- field.set(obj, "男");
-
- System.out.println(field.get(obj));
- }
打印结果:
男
12、通过反射取得并修改数组的信息
- public static void main(String[] args) {
- int[] temp={1,2,3,4,5};
-
- Class<?>demo=temp.getClass().getComponentType();
-
- System.out.println("数组类型: "+demo.getName());
-
- System.out.println("数组长度 "+Array.getLength(temp));
-
- System.out.println("数组的第一个元素: "+Array.get(temp, 0));
-
- Array.set(temp, 0, 100);
-
- System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0));
-
- }
打印结果:
数组类型: int
数组长度 5
数组的第一个元素: 1
修改之后数组第一个元素为: 100