Java中的反射

java

Java反射指的是在运行状态时,能够获取类的属性和方法或者修改类运行时行为的过程。

java.lang.Class类提供了很多方法用于获取元数据、检查和改变类运行时的行为。

Java的反射主要涉及java.lang和java.lang.reflect包下的类。

反射应用场景举例

  1. IDE, 如Eclipse、MyEclipse、NetBeans等;
  2. 调试器;
  3. 测试工具等;
  4. 各大框架、spring、hibernate等;

java.lang.Class类

java.lang.Class主要提供了以下两个功能:

  1. 提供方法用于访问运行期间类的元数据;
  2. 提供方法用于检查和修改类的运行时行为;

java.lang.Class类常用方法

MethodDescription
1) public String getName()返回类名
2) public static Class forName(String className)throws ClassNotFoundException加载类并返回Class对象
3) public Object newInstance()throws InstantiationException,IllegalAccessException创建实例对象
4) public boolean isInterface()判断是否是接口
5) public boolean isArray()判断是否是数组
6) public boolean isPrimitive()判断是否是原始数据类型
7) public Class getSuperclass()返回父类Class引用
8) public Field[] getDeclaredFields()throws SecurityException返回类的成员属性字段数组
9) public Method[] getDeclaredMethods()throws SecurityException返回类的方法数组
10) public Constructor[] getDeclaredConstructors()throws SecurityException返回类的构造方法数组
11) public Method getDeclaredMethod(String name,Class[] parameterTypes)throws NoSuchMethodException,SecurityException返回类中指定参数类型的方法

怎样获取Class对象

有三种方式,如下:

  1. Class类的forName()方法,动态加载,运行时,开始装入类, 并做类的静态初始化
  2. 对象的getClass()方法,静态加载(编译时已加载)
  3. .class语法, 静态加载(编译时已加载)

forName()方法示例

可用于动态加载,当你知道类的全限定名时,可以使用该方式。注意原始数据类型不适用该方法;

package tmp;

class Simple

{

}

public class Test

{

public static void main(String args[]) throws ClassNotFoundException

{

Class<?> c = Class.forName("tmp.Simple");

System.out.println(c.getName());

System.out.println(c.getSimpleName());

}

}

tmp.Simple
Simple

getClass()方法示例:

从实例对象中获取Class对象

package tmp;

class Simple

{

}

public class Test

{

void printName(Object obj)

{

}

public static void main(String args[])

{

Simple s = new Simple();

Class<? extends Object> c = s.getClass();

System.out.println(c.getName());

System.out.println(c.getSimpleName());

}

}

tmp.Simple
Simple

.class语法示例

作用于类名上,也可应用于原始数据类型,如下所示:

package tmp;

public class Test

{

public static void main(String args[])

{

Class<Boolean> c = boolean.class;

System.out.println(c.getName());

Class<Test> c2 = Test.class;

System.out.println(c2.getName());

}

}

boolean
tmp.Test

判断Class对象对应的类型

以下方法可用于判断Class对象对应的类型:

1) public boolean isInterface(): 是否对应接口

2) public boolean isArray(): 是否对应数组

3) public boolean isPrimitive(): 是否对应原始数据类型

代码示例:

package tmp;

class Simple

{

}

interface My

{

}

public class Test

{

public static void main(String args[])

{

try

{

Class<?> c = Class.forName("tmp.Simple");

System.out.println(c.isInterface());

Class<?> c2 = Class.forName("tmp.My");

System.out.println(c2.isInterface());

}

catch (Exception e)

{

System.out.println(e);

}

}

}

false
true

通过反射创建实例对象

有两种方式,如下:

  1. 通过Class对象的newInstance()方法创建,这种方式只能调用无参构造方法;
  2. 通过Constructor对象的newInstance()方法创建,这种方式适用于有参构造方法,并且还可以破坏单例模式,调用私有构造方法;

所以,通常来讲,第二种方式比第一种使用范围更广。

Class对象调用newInstance()方法示例

package tmp;

class Simple

{

void message()

{

System.out.println("Hello Java");

}

}

public class Test

{

public static void main(String args[])

{

try

{

Class<?> c = Class.forName("tmp.Simple");

Simple s = (Simple) c.newInstance();

s.message();

}

catch (Exception e)

{

System.out.println(e);

}

}

}

Hello Java

Constructor对象调用newInstance()方法示例

注意这里可以根据传入参数的类型来得到指定的构造方法,还可以改变构造方法的访问权限限制。

package tmp;

import java.lang.reflect.Constructor;

class Simple

{

private String msg;

void message()

{

System.out.println("Hello Java," + msg);

}

private Simple(String s){

this.msg = s;

}

}

public class Test

{

public static void main(String args[])

{

try

{

Class<?> c = Class.forName("tmp.Simple");

Constructor<?> con = c.getDeclaredConstructor(String.class);

con.setAccessible(true);

Simple s = (Simple) con.newInstance("...");

s.message();

}

catch (Exception e)

{

System.out.println(e);

}

}

}

Hello Java,...

通过反射调用私有方法

通过反射,我们可以调用其它类的私有方法,主要涉及java.lang.Class和java.lang.reflect.Method类;

其中主要是用到了Method类的setAccessible方法和invoke方法,前者修改访问权限,后者调用方法。

通过调用有参私有方法示例:

package tmp;

import java.lang.reflect.Method;

class A

{

private void cube(int n)

{

System.out.println(n * n * n);

}

}

class Test

{

public static void main(String args[]) throws Exception

{

Class<A> c = A.class;

Object obj = c.newInstance();

Method m = c.getDeclaredMethod("cube", new Class[]{ int.class });

m.setAccessible(true);

m.invoke(obj, 4);

}

}

关于javap工具

使用javap命令可以反汇编java的字节码文件,展示class文件中的字段属性、构造方法、普通方法信息;

使用说明:

javap java.lang.Object示例

javap -c Test示例:

写个简单的Test类,如下:

package tmp;

class Simple

{

}

public class Test

{

public static void main(String args[])

{

System.out.println("Hello");

}

}

输入javap -c Test:

 参考资料

基本属于翻译,做了小部分修改

http://www.javatpoint.com/java-reflection

以上是 Java中的反射 的全部内容, 来源链接: utcz.com/z/391666.html

回到顶部