Java反射机制总结

刚开始学习Java的时候,这部分的内容并没有引起我的重视,因为在平常的编程中很少用到。直到有一天,忘了是看什么来着,接触到这个知识点,搞得自己一脸懵逼,所以翻阅了网上的各种资料,简单总结一下。

什么是反射?

Java反射机制是指在程序运行时加载、探知、使用编译期间完全未知的类型。也就是说,Java可以加载一个在运行时才得知其类型的类,获悉其完整构造,并生成其对象实体、或对其fields设值、或调用其methods。

反射 的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁

反射能做什么?

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的方法
  • 生成动态代理

重点:是运行时而不是编译时

反射相关的API

先贴出来一个测试用的类Person
package com.cao.reflecttest;

public class Person {
	private int id;
	private String name;
	private int age;
	public Person()
	{
		id=0;
		name="zhang wei";
		age=18;
	}
	public Person(int id,String name,int age)
	{
		this.id=id;
		this.name=name;
		this.age=age;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	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 String toString()
	{
		return id+"\t"+name+"\t"+age;
	}
}

1 获取Class对象的三种方法


(1)使用Class类的forName()静态方法

public static Class<?> forName(String className)
//在JDBC开发中常用此方法加载数据库驱动:
Class.forName(driver);

(2)直接获取某一个类型的class

Class<?> klass = int.class;
Class<?> classInt = Integer.TYPE;

(3)调用某个对象的getClass()方法

StringBuilder str = new StringBuilder("123");
Class<?> class = str.getClass();

以上三种方法的综合测试用例如下所示,其结果是一样的。

package com.cao.reflecttest;

public class GetClassTest {

	public static void main(String[] args) throws ClassNotFoundException {
		//the first method
		Class<?> c1=Class.forName("com.cao.reflecttest.Person");
		System.out.println("The first method : "+c1.getCanonicalName());
		//the second method
		Class<?> c2=Person.class;
		System.out.println("The second method : "+c2.getCanonicalName());
		//the third method
		Class<?> c3=new Person().getClass();
		System.out.println("The third method : "+c3.getCanonicalName());
	}
}
运行结果为:

The first method : com.cao.reflecttest.Person
The second method : com.cao.reflecttest.Person
The third method : com.cao.reflecttest.Person
注意:这里打印的是全限定类名,如果只想打印类名的话,直接调用Class类的getName()方法就可以了。

2 判断是否为某个类的实例

一般地,我们用instanceof关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()方法来判断是否为某个类的实例,它是一个Native方法:

public native boolean isInstance(Object obj);

package com.cao.reflecttest;

public class InInstanceTest {

	public static void main(String[] args) throws ClassNotFoundException {
		
		Class<?> c=Class.forName("com.cao.reflecttest.Person");
		Person p=new Person();
		System.out.println(c.isInstance(p));
	}

}
运行结果为:

true

3 创建类的实例

通过反射生成类的实例主要有两种方法。

(1)调用Class对象的newInstance()方法

(2)先通过Class对象获得Constructor对象,再调用Constructor对象的newInstance()方法来创建实例,这种方法可以用指定的构造器创建类的实例

第一种方法要求类必须有一个默认的构造器,因为newInstance()方法中是没有任何参数的。

第二种方法通过获取类的Constructor对象来创建对象,包含类的所有构造器,所以不需要有(1)中的限制。

package com.cao.reflecttest;

import java.lang.reflect.Constructor;

public class ConstructObjects {

	public static void main(String[] args) throws Exception {
		
		Class<?> c=Class.forName("com.cao.reflecttest.Person");
		//the first method
		Object person=c.newInstance();
		System.out.println(person);
		//the second method:using default constructor
		Constructor<?> constructor=c.getConstructor(null);
		Object obj=constructor.newInstance(null);
		System.out.println(obj);
		//the second method:using the parameter constructor
		constructor=c.getConstructor(int.class,String.class,int.class);
		obj=constructor.newInstance(1,"sunhai",22);
		System.out.println(obj);
	}

}

输出结果为:

0	zhang wei	18
0	zhang wei	18
1	sunhai	22

从结果中可以看到,调用Class对象的newInstance()方法实际上跟使用类的默认构造器创建对象是一样的,而方法(2)更灵活,不仅可以调用默认构造器,还可以调用带有参数的构造器来创建对象。

4 获取方法

getDeclaredMethods()方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

public Method[] getDeclaredMethods() throws SecurityException
getMethods()方法返回某个类的所有公用(public)方法,包括其父类的公用方法。

public Method[] getMethods() throws SecurityException
getMethod()方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
	
public Method getMethod(String name, Class<?>... parameterTypes)
package com.cao.reflecttest;

import java.lang.reflect.Method;

public class GetMethodsTest {

	public static void main(String[] args) throws Exception {
		
		Class<?> c=Class.forName("com.cao.reflecttest.Person");
		Object obj=c.newInstance();
		Method[] methods=c.getMethods();
		// all public method, including the base class
		System.out.println("getMothods()");
		for (Method m:methods)
			System.out.println(m);
		System.out.println("getDeclaredMethods()");
		methods=c.getDeclaredMethods();
		for(Method m:methods)
			System.out.println(m);
		// getMethod()
		System.out.println("getMethod()");
		Method method=c.getMethod("setName", String.class);
		System.out.println(obj);
		method.invoke(obj, "zhao Zilong");
		System.out.println(obj);
	}

}
运行结果为:

getMothods()
public java.lang.String com.cao.reflecttest.Person.toString()
public java.lang.String com.cao.reflecttest.Person.getName()
public int com.cao.reflecttest.Person.getId()
public void com.cao.reflecttest.Person.setName(java.lang.String)
public void com.cao.reflecttest.Person.setId(int)
public int com.cao.reflecttest.Person.getAge()
public void com.cao.reflecttest.Person.setAge(int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
getDeclaredMethods()
public java.lang.String com.cao.reflecttest.Person.toString()
public java.lang.String com.cao.reflecttest.Person.getName()
public int com.cao.reflecttest.Person.getId()
public void com.cao.reflecttest.Person.setName(java.lang.String)
public void com.cao.reflecttest.Person.setId(int)
public int com.cao.reflecttest.Person.getAge()
public void com.cao.reflecttest.Person.setAge(int)
getMethod()
0	zhang wei	18
0	zhao Zilong	18

5 获取构造器

这个内容在3中已经有所体现,在那里,我们通过获取类的Constructor对象来创建类的实例。

通过Class类的getConstructor()方法得到Constructor类的一个实例,然后通过Constructor类的newInstance()方法创建一个对象实例。

public T newInstance(Object ... initargs)
getConstructor()方法的原型如下所示:


Parameters:
parameterTypes the parameter array:参数数组
Returns:
the Constructor object of the public constructor that matches the specified parameterTypes:与指定的参数相匹配的公共构造器的Constructor对象

package com.cao.reflecttest;

import java.lang.reflect.Constructor;

public class GetConstructorTest {

	public static void main(String[] args) throws Exception {
		
		Class<?> c=Class.forName("com.cao.reflecttest.Person");
		Constructor<?>[] constructors=c.getConstructors();
		for(Constructor constructor:constructors)
			System.out.println(constructor);
	}

}

运行结果如下所示:获取了两个构造器

public com.cao.reflecttest.Person()
public com.cao.reflecttest.Person(int,java.lang.String,int)

6 获取类的成员变量

getField(String):访问公有的成员变量,必须是公有的,否则将会报错,包含一个参数,用于指定field的名字

getDeclaredFileds():所有已声明的成员变量,但不包括其父类的成员变量,无论是public、private、protected、包访问权限的都将返回

getFields():包括接口或者父类的属性,但必须是public的才可以

package com.cao.reflecttest;

import java.lang.reflect.Field;

public class GetFieldTest {

	public static void main(String[] args) throws Exception {
		Class<?> c=Class.forName("com.cao.reflecttest.Person");
		System.out.println("getFields()");
		Field[] fields=c.getFields();
		for(Field field:fields)
			System.out.println(field);
		System.out.println("getDeclaredFields()");
		fields=c.getDeclaredFields();
		for(Field field:fields)
			System.out.println(field);
		
		
	}

}

运行结果为:

getFields()
getDeclaredFields()
private int com.cao.reflecttest.Person.id
private java.lang.String com.cao.reflecttest.Person.name
private int com.cao.reflecttest.Person.age

7 调用方法

invoke()方法原型为:

public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,InvocationTargetException

Parameters:
obj the object the underlying method is invoked from:方法所在的对象
args the arguments used for the method call:该方法的参数列表
Returns:
the result of dispatching the method represented by this object on obj with parameters args:调用方法的返回结果

8 综合案例

参考参考文献(3)实现一个利用反射实现类文件的反编译的例子。

package com.cao.reflecttest;

import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ReflectionSummary {

    public static void main(String[] args) {
        Class c=null;
        try{
            c=Class.forName("com.cao.reflecttest.Person");
            System.out.println("package "+c.getPackage().getName()+"\n");
            System.out.print(Modifier.toString(c.getModifiers()));
            System.out.print(" class "+c.getSimpleName());
            System.out.print(" extends "+c.getSuperclass().getSimpleName());
            Class[] iters=c.getInterfaces();
            if(iters.length>0)
            {
                System.out.print(" implements ");
                for(int i=0;i<iters.length;i++)
                {
                    System.out.print(iters[i].getSimpleName());
                    if(i<iters.length-1)
                        System.out.print(",");
                }
            }
            System.out.println("{");
            printFields(c);
            printConstructors(c);
            printMethods(c);
            System.out.println("}");

        }catch(Exception e)
        {
            e.printStackTrace();
        }

    }

    private static void printMethods(Class c) {
        Method[] methods=c.getMethods();
        for(int i=0;i<methods.length;i++)
        {
            System.out.print("\t");
            System.out.print(Modifier.toString(methods[i].getModifiers())+" ");
            System.out.print(methods[i].getGenericReturnType()+" ");
            System.out.print(methods[i].getName()+"(");
            Class[] params=methods[i].getParameterTypes();
            for(int j=0;j<params.length;j++)
            {
                System.out.print(params[j].getSimpleName()+" arg"+j);
                if(j<params.length-1)
                    System.out.print(",");
            }
            System.out.print(")");
            Class[] exceptions=methods[i].getExceptionTypes();
            if(exceptions.length>0)
            {
                System.out.print(" throws ");
                for(int j=0;j<exceptions.length;j++)
                {
                    System.out.print(exceptions[j].getSimpleName());
                    if(j<exceptions.length-1)
                        System.out.print(",");
                }
            }
            System.out.println("{");
            System.out.println("\t\t\\\\method body");
            System.out.println("\t}");
        }

    }

    private static void printConstructors(Class c) {
        Constructor[] constructors=c.getConstructors();
        for(int i=0;i<constructors.length;i++)
        {
            System.out.println();
            System.out.print("\t");
            System.out.print(Modifier.toString(constructors[i].getModifiers())+" ");
            System.out.print(constructors[i].getName()+"(");
            Class[] params=constructors[i].getParameterTypes();
            for(int j=0;j<params.length;j++)
            {
                System.out.print(params[j].getSimpleName()+" arg"+j);
                if(j<params.length-1)
                    System.out.print(",");
            }
            System.out.print(")");
            System.out.println("{");
            System.out.println("\t\t\\\\constructor body");
            System.out.println("\t}");
        }

    }

    private static void printFields(Class c) {
        Field[] fields=c.getDeclaredFields();
        for(int i=0;i<fields.length;i++)
        {
            System.out.print("\t");
            System.out.print(Modifier.toString(fields[i].getModifiers())+" ");
            System.out.print(fields[i].getType().getSimpleName()+" ");
            System.out.println(fields[i].getName()+";");
        }
    }

}

运行结果为:

package com.cao.reflecttest

public class Person extends Object{
	private int id;
	private String name;
	private int age;

	public com.cao.reflecttest.Person(){
		\\constructor body
	}

	public com.cao.reflecttest.Person(int arg0,String arg1,int arg2){
		\\constructor body
	}
	public class java.lang.String toString(){
		\\method body
	}
	public class java.lang.String getName(){
		\\method body
	}
	public int getId(){
		\\method body
	}
	public void setName(String arg0){
		\\method body
	}
	public void setId(int arg0){
		\\method body
	}
	public int getAge(){
		\\method body
	}
	public void setAge(int arg0){
		\\method body
	}
	public final void wait() throws InterruptedException{
		\\method body
	}
	public final void wait(long arg0,int arg1) throws InterruptedException{
		\\method body
	}
	public final native void wait(long arg0) throws InterruptedException{
		\\method body
	}
	public boolean equals(Object arg0){
		\\method body
	}
	public native int hashCode(){
		\\method body
	}
	public final native java.lang.Class<?> getClass(){
		\\method body
	}
	public final native void notify(){
		\\method body
	}
	public final native void notifyAll(){
		\\method body
	}
}


参考文献:

(1) 深入解析Java反射机制(1)-基础

(2) Java反射机制详解

(3) Java反射机制的原理与简单使用


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值