JAVA之反射
2017-04-09 00:18
411 查看
Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时通过反射机制取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现于interfaces(例如Cloneable),也包括fields和methods的所有信息,并可在运行时改变fields内容或调用methods。
Java反射机制允许程序在运行时加载、探知、使用编译期间完全未知的classes。换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。
一、相关API:
在java.lang.reflect包中可以找到相关的API,常用的类和接口有:
1、Member接口:获取类相关的成员信息,包括成员所在类的class对象,变量或方法的修饰符和名称等信息;
2、AccessibleObject类:是域(field)对象、方法(method)对象、构造函数(constructor)对象的基类。它提供了将反射的对象标记为在使用时取消默认Java 语言访问控制检查的能力。
3、Array类:提供动态创建和访问Java数组的方法。
4、Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。
5、Field类:提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)变量或实例变量。
6、Method类:提供关于类或接口的单个方法,以及对它的动态访问权限。反射的方法可能是类方法或实例方法(包括抽象方法)。
7、Modifier类:提供了对类、变量、方法的访问修饰符进行解码。
8、Proxy类:提供创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
二、应用:
1、获取类的class对象:
①可以调用对象的.getClass()方法,但原生类的变量不能调用此方法,比如int、boolean等:
②可以调用类的.class()方法,原生类也可以调用此方法,比如int、boolean等:
public class Test{
public static void main(String args[]){
System.out.println(String.class);
}
} ③可以调用Class类的静态方法.forName()
④原始包装类可以使用字段.Type
如果要获取布尔型的Class对象,可以使用如下方法,区别如下:
2、创建对象:
①使用Class对象的newInstance()方法,此方法只适用于无参数的构造方法:
②使用Constructor对象的newInstance()方法:
1>如果是无参的构造方法:
3、获取类的Fields(变量):
①public Field[] getFields():返回对应类/接口以及其所有父类/父接口的所有的公共变量;
②public Field getField(String name):返回对应类/接口以及其所有父类/父接口中指定名称的公共变量;
③public Field[] getDeclaredFields():返回对应类/接口中定义的所有的变量,但不包括继承来的变量;
④public Field getDeclaredField(String name):返回对应类/接口中定义过的指定名称的变量,但不包括继承来的变量;
假如有两个类有继承关系:
Test1:
Test2:
public class Test2 extends Test1 {
private String c;
public String d;
}通过反射获取变量时:
由此可见getFields和getDeclaredFields区别:
①getFields():返回对应类/接口以及其所有父类/父接口的所有的public变量;
②getDeclaredFields():返回类/接口中定义的所有变量,不包括父类中的。
4、设置和获取类的Fields(变量)的值:获取Class对象的Field对象后调用Field类中类似set(Object o,Object value)方法。
import java.lang.reflect.*;
public class Test{
public int a;
public String b;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public static void main(String args[]){
Class<?> clazz = Test.class;
try {
Object t = clazz.newInstance();
try {
Field f1 = clazz.getField("a");
Field f2 = clazz.getField("b");
try {
f1.setInt(t, 100);
f2.set(t, "Hello World");
int a = f1.getInt(t);
System.out.println(a);
String b = f2.get(t).toString();
System.out.println(b);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
}
} 5、获取类的Methods(方法):
①public Method[] getMethods():返回对应类/接口以及其所有父类/父接口的所有的公共方法;
②public Method getMethod(String name,Class<?>... parameterTypes):返回对应类/接口以及其所有父类/父接口中指定名称和参数类型的公共方法;
③public Method[] getDeclaredMethods():返回对应类/接口中定义的所有方法,但不包括继承来的方法;
④public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
:返回对应类/接口中定义过的指定名称的方法,但不包括继承来的方法;
假如有两个类有继承关系:
Test1:
Test2:
通过反射获取方法时:
6、获取类的Constructors(构造方法):
①public Constructor<?>[] getConstructors():返回对应类的公共构造方法,但不包括父类的构造方法;
②public Constructor<T> getConstructor(Class<?>... parameterTypes):返回对应类但不包括其父类的指定相同参数类型的公共构造方法;
③public Constructor<?>[] getDeclaredConstructors():返回对应类中定义的所有的构造方法,但不包括继承来的构造方法;
④public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回对应类中定义的指定参数类型的构造方法,但不包括继承来的构造方法;
假如有两个类有继承关系:
Test1:
Test2:
通过反射获取方法时:
import java.lang.reflect.Constructor;
public class Test{
public static void main(String args[]){
Class<?> clazz = Test2.class;
Constructor<?>[] constructors1 = clazz.getConstructors();
for(Constructor<?> c:constructors1){
System.out.println(c);
}
try {
System.out.println(clazz.getConstructor(String.class,String.class));
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
}
Constructor<?>[] constructors2 = clazz.getDeclaredConstructors();
for(Constructor<?> c:constructors2){
System.out.println(c);
}
try {
System.out.println(clazz.getDeclaredConstructor(String.class,String.class,String.class));
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
由此可见,获取构造方法与获取变量和方法的方法不同,它不能获取到其父类的构造方法。
7、调用方法:获取Class对象的Method对象后调用Method类中invoke(Object o, Object... args)方法。
import java.lang.reflect.*;
public class Test{
public void testMethod(int a){
System.out.println("testMethod:"+a);
}
public static void main(String args[]){
Class<?> clazz = Test.class;
try {
Object t = clazz.newInstance();
try {
Method m = clazz.getMethod("testMethod", int.class);
try {
m.invoke(t, 3);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
}
}
8、动态代理:动态代理即代理是在运行期发生的,而不是在编译上其发生的。
接口或抽象类:
实际作用类:
代理类:
主入口:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
RealPart real = new RealPart();
InvocationHandler handler = new ProxyPart(real);
Class<?> clazz = handler.getClass();
ProxyInterface proxy = (ProxyInterface)Proxy.newProxyInstance(clazz.getClassLoader(),real.getClass().getInterfaces(),handler);
System.out.println(proxy.getClass());
proxy.say();
}
}
参考:http://www.cnblogs.com/Quincy/archive/2011/06/19/2084557.html#
Java反射机制允许程序在运行时加载、探知、使用编译期间完全未知的classes。换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。
一、相关API:
在java.lang.reflect包中可以找到相关的API,常用的类和接口有:
1、Member接口:获取类相关的成员信息,包括成员所在类的class对象,变量或方法的修饰符和名称等信息;
2、AccessibleObject类:是域(field)对象、方法(method)对象、构造函数(constructor)对象的基类。它提供了将反射的对象标记为在使用时取消默认Java 语言访问控制检查的能力。
3、Array类:提供动态创建和访问Java数组的方法。
4、Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。
5、Field类:提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)变量或实例变量。
6、Method类:提供关于类或接口的单个方法,以及对它的动态访问权限。反射的方法可能是类方法或实例方法(包括抽象方法)。
7、Modifier类:提供了对类、变量、方法的访问修饰符进行解码。
8、Proxy类:提供创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
二、应用:
1、获取类的class对象:
①可以调用对象的.getClass()方法,但原生类的变量不能调用此方法,比如int、boolean等:
public class Test{ public static void main(String args[]){ String str = new String(); System.out.println(str.getClass()); } }
②可以调用类的.class()方法,原生类也可以调用此方法,比如int、boolean等:
public class Test{
public static void main(String args[]){
System.out.println(String.class);
}
} ③可以调用Class类的静态方法.forName()
public class Test{ public static void main(String args[]){ try { System.out.println(Class.forName("java.lang.String")); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
④原始包装类可以使用字段.Type
public class Test{ public static void main(String args[]){ System.out.println(Integer.TYPE); } }
如果要获取布尔型的Class对象,可以使用如下方法,区别如下:
public class Test{ public static void main(String args[]){ //boolean b = true; //System.out.println(b.getClass()); 原始类的变量不能调用.getClass()方法 Class<?> c1=Boolean.TYPE; //返回原始类型boolean System.out.println(c1); Class<?> c2=boolean.class; //返回原始类型boolean System.out.println(c2); Class<?> c3=Boolean.class; //返回class java.lang.Boolean System.out.println(c3); } }
2、创建对象:
①使用Class对象的newInstance()方法,此方法只适用于无参数的构造方法:
public class Test{ public static void main(String args[]){ Class<?> clazz = String.class; try { Object str = clazz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
②使用Constructor对象的newInstance()方法:
1>如果是无参的构造方法:
import java.lang.reflect.*; public class Test{ public static void main(String args[]){ Class<?> clazz = String.class; try { Constructor<?> c = clazz.getConstructor(); try { Object str = c.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } } }2>如果是有参的构造方法:
import java.lang.reflect.*; public class Test{ public static void main(String args[]){ Class<?> clazz = String.class; try { Constructor<?> c = clazz.getConstructor(String.class); try { Object str = c.newInstance("Hello World"); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } } }
3、获取类的Fields(变量):
①public Field[] getFields():返回对应类/接口以及其所有父类/父接口的所有的公共变量;
②public Field getField(String name):返回对应类/接口以及其所有父类/父接口中指定名称的公共变量;
③public Field[] getDeclaredFields():返回对应类/接口中定义的所有的变量,但不包括继承来的变量;
④public Field getDeclaredField(String name):返回对应类/接口中定义过的指定名称的变量,但不包括继承来的变量;
假如有两个类有继承关系:
Test1:
public class Test1 { private String a; public String b; }
Test2:
public class Test2 extends Test1 {
private String c;
public String d;
}通过反射获取变量时:
import java.lang.reflect.Field; public class Test{ public static void main(String args[]){ Test2 t = new Test2(); Class<?> clazz = t.getClass(); Field[] fields1 = clazz.getFields(); for(Field f:fields1){ System.out.println(f.getName()); //取到b,d,无序 } try { System.out.println(clazz.getField("b")); //public java.lang.String Test1.b(能取到b,d,但取不到a,c) } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } Field[] fields2 = clazz.getDeclaredFields(); for(Field f:fields2){ System.out.println(f.getName()); //取到c,d,无序 } try { System.out.println(clazz.getDeclaredField("d")); //public java.lang.String Test2.d(能取到c,d,取不到a,b) } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } } }
由此可见getFields和getDeclaredFields区别:
①getFields():返回对应类/接口以及其所有父类/父接口的所有的public变量;
②getDeclaredFields():返回类/接口中定义的所有变量,不包括父类中的。
4、设置和获取类的Fields(变量)的值:获取Class对象的Field对象后调用Field类中类似set(Object o,Object value)方法。
import java.lang.reflect.*;
public class Test{
public int a;
public String b;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public static void main(String args[]){
Class<?> clazz = Test.class;
try {
Object t = clazz.newInstance();
try {
Field f1 = clazz.getField("a");
Field f2 = clazz.getField("b");
try {
f1.setInt(t, 100);
f2.set(t, "Hello World");
int a = f1.getInt(t);
System.out.println(a);
String b = f2.get(t).toString();
System.out.println(b);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
}
} 5、获取类的Methods(方法):
①public Method[] getMethods():返回对应类/接口以及其所有父类/父接口的所有的公共方法;
②public Method getMethod(String name,Class<?>... parameterTypes):返回对应类/接口以及其所有父类/父接口中指定名称和参数类型的公共方法;
③public Method[] getDeclaredMethods():返回对应类/接口中定义的所有方法,但不包括继承来的方法;
④public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
:返回对应类/接口中定义过的指定名称的方法,但不包括继承来的方法;
假如有两个类有继承关系:
Test1:
public class Test1 { private void a(){ } private void a(int m,int n){ } public void b(){ } public void b(int m,int n){ } }
Test2:
public class Test2 extends Test1 { private void c(){ } private void c(int m,int n){ } public void d(){ } private void d(int m,int n){ } }
通过反射获取方法时:
import java.lang.reflect.Method; public class Test{ public static void main(String args[]){ Test2 t = new Test2(); Class<?> clazz = t.getClass(); Method[] Method1 = clazz.getMethods(); for(Method m:Method1){ System.out.println(m); //取到b,d,无序 } try { System.out.println(clazz.getMethod("b", int.class,int.class)); //public void Test1.b(int,int)(能取到b,d,但取不到a,c) } catch (NoSuchMethodException e1) { e1.printStackTrace(); } catch (SecurityException e1) { e1.printStackTrace(); } Method[] Method2 = clazz.getDeclaredMethods(); for(Method m:Method2){ System.out.println(m); //取到c,d,无序 } try { System.out.println(clazz.getDeclaredMethod("d")); //public void Test2.d() )(能取到c,d,但取不到a,b) } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } } }
6、获取类的Constructors(构造方法):
①public Constructor<?>[] getConstructors():返回对应类的公共构造方法,但不包括父类的构造方法;
②public Constructor<T> getConstructor(Class<?>... parameterTypes):返回对应类但不包括其父类的指定相同参数类型的公共构造方法;
③public Constructor<?>[] getDeclaredConstructors():返回对应类中定义的所有的构造方法,但不包括继承来的构造方法;
④public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回对应类中定义的指定参数类型的构造方法,但不包括继承来的构造方法;
假如有两个类有继承关系:
Test1:
public class Test1 { public Test1(){ } public Test1(int m){ } public Test1(int m,int n){ } private Test1(int m,int n,int x){ } }
Test2:
public class Test2 extends Test1 { public Test2(){ } public Test2(String str){ } public Test2(String str1,String str2){ } private Test2(String str1,String str2,String str3){ } }
通过反射获取方法时:
import java.lang.reflect.Constructor;
public class Test{
public static void main(String args[]){
Class<?> clazz = Test2.class;
Constructor<?>[] constructors1 = clazz.getConstructors();
for(Constructor<?> c:constructors1){
System.out.println(c);
}
try {
System.out.println(clazz.getConstructor(String.class,String.class));
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
}
Constructor<?>[] constructors2 = clazz.getDeclaredConstructors();
for(Constructor<?> c:constructors2){
System.out.println(c);
}
try {
System.out.println(clazz.getDeclaredConstructor(String.class,String.class,String.class));
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
由此可见,获取构造方法与获取变量和方法的方法不同,它不能获取到其父类的构造方法。
7、调用方法:获取Class对象的Method对象后调用Method类中invoke(Object o, Object... args)方法。
import java.lang.reflect.*;
public class Test{
public void testMethod(int a){
System.out.println("testMethod:"+a);
}
public static void main(String args[]){
Class<?> clazz = Test.class;
try {
Object t = clazz.newInstance();
try {
Method m = clazz.getMethod("testMethod", int.class);
try {
m.invoke(t, 3);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
}
}
8、动态代理:动态代理即代理是在运行期发生的,而不是在编译上其发生的。
接口或抽象类:
public interface ProxyInterface { public void say(); }
实际作用类:
public class RealPart implements ProxyInterface{ public void say() { System.out.println("RealPart"); } }
代理类:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class ProxyPart implements InvocationHandler { private Object obj; public ProxyPart(Object obj){ this.obj = obj; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { method.invoke(obj, args); return null; } }
主入口:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
RealPart real = new RealPart();
InvocationHandler handler = new ProxyPart(real);
Class<?> clazz = handler.getClass();
ProxyInterface proxy = (ProxyInterface)Proxy.newProxyInstance(clazz.getClassLoader(),real.getClass().getInterfaces(),handler);
System.out.println(proxy.getClass());
proxy.say();
}
}
参考:http://www.cnblogs.com/Quincy/archive/2011/06/19/2084557.html#
相关文章推荐
- [原创]JAVA反射技术(二)
- Java Reflection (JAVA反射)
- Java Reflection (JAVA反射)
- Java的反射机制
- Java动态程序设计:反射介绍(zz from jr)
- 如何利用Java的反射的机制来简化Structs应用程序的开发
- Java Reflection (JAVA反射)
- Java Reflection (JAVA反射)
- [学习小记]Java的反射机制
- Java Reflection (JAVA反射) (作者: corlin)
- Java Reflection (JAVA反射)
- Java Reflection (JAVA反射)
- Java中的类反射机制
- Java Reflection (JAVA反射)
- 在Java中使用反射分析类结构
- 在Java中使用反射分析类结构
- (Java)利用反射动态调用类成员
- Java Reflection (JAVA反射)
- Java Reflection (JAVA反射)
- 学习心得:Java为什么支持反射机制?