java反射的基本使用
java反射机制的使用是相当广泛,以前掌握的不是太好,趁最近有时间来复习一番。
百度百科中对于反射机制是这么介绍的:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;
一般我们都是通过new关键字来创建对象的,这个反射到底是何方婶婶?怎么那么牛?
不要急,我们先来看一下下面的示意图:
每一个.class文件加载到内存的时候都是一个Class类的对象!把Demo.class加载到内存的时候,他就是一个Class
Class,Field,Method,Constructor,分别表示:类,成员变量,方法,和构造器。
获取Class通常有一下的3种方法:
1.通过类名称.class,对基本类型也支持;
Class c = int.class;
Class c = int[].class;
Class c = String.class
2.通过对象.getClass()方法
Class c = obj.getClass();
3.Class.forName()通过类名称加载类,这种方法只要有类名称就可以得到Class;
Class c = Class.forName(“类名”);(不要忘记包名)
********************************************************************************************
Class类的常用方法
String getName():获取类名称,包含包名;
String getSimpleName():获取类名称,不包含包名;
Class getSupperClass():获取父类的Class,
例如:new Integer(100).getClass().getSupperClass()返回的是Class
但new Object().getSupperClass()返回的是null,因为Object没有父类;
T newInstance():使用本类无参构造器来创建本类对象;
boolean isArray():是否为数组类型;
boolean isAnnotation():是否为注解类型;
boolean isAnnotationPresent(Class annotationClass):当前类是否被annotationClass注解了;
boolean isEnum():是否为枚举类型;
boolean isInterface():是否为接口类型;
boolean isPrimitive():是否为基本类型;
boolean isSynthetic():是否为引用类型;
下面举个例子来总结一下:
package lsj.pc;
public class Test {
@org.junit.Test
public void fun1() throws Exception {
Class<?> clazz = Class.forName("lsj.pc.User");
User user = (User)clazz.newInstance();
user.setPassword("1234567");
user.setUsername("TOM");
System.out.println(user);
}
}
class User {
private String username;
private String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
public User() {
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "用户名:"+ username + ", 密码:" + password ;
}
}
执行的结果如下:
User [username=TOM, password=1234567]
上面的例子中,通过反射获取了User类的Class对象,然后通过Class对象的newInstance()方法创建了一个user对象的实例。
2)获取玩Class对象,接下来获取构造器Constructor对象。
获取的方式有以下4种:
Constructor getConstructor(Class… parameterTypes):通过指定的参数类型获取公有构造器反射对象;
Constructor[] getConstructors():获取所有公有构造器对象;
Constructor getDeclaredConstructor(Class… parameterTypes):通过指定参数类型获取构造器反射对象。可以是私有构造器对象;
Constructor[] getDeclaredConstructors():获取所有构造器对象。包含私有构造器;
Construcator类常用方法
String getName():获取构造器名;
Class getDeclaringClass():获取构造器所属的类型;
Class[] getParameterTypes():获取构造器的所有参数的类型;
Class[] getExceptionTypes():获取构造器上声明的所有异常类型;
T newInstance(Object… initargs):通过构造器反射对象调用构造器。
下面举个例子:
public class Test {
@org.junit.Test
public void fun1() throws Exception {
Class<?> clazz = Class.forName("lsj.pc.User");
Constructor<?> c=clazz.getConstructor(String.class,String.class);
User user=(User) c.newInstance("TOM","1234567");
/*User user = (User)clazz.newInstance();
user.setPassword("1234567");
user.setUsername("TOM");*/
System.out.println(user);
}
3)获取方法
Method getMethod(String name, Class… parameterTypes):
通过方法名和方法参数类型获取方法反射对象,包含父类中声明的公有方法,但不包含所有私有方法;
Method[] getMethods():
获取所有公有方法,包含父类中的公有方法,但不包含任何私有方法;
Method getDeclaredMethod(String name, Class… parameterTypes):
通过方法名和方法参数类型获取本类中声明的方法的反射对象,包含本类中的私有方法,但不包含父类中的任何方法;
Method[] getDeclaredMethods():
获取本类中所有方法,包含本类中的私有方法,但不包含父类中的任何方法。
下面是一些常用的方法:
String getName():获取方法名;
Class getDeclaringClass():获取方法所属的类型;
Class[] getParameterTypes():获取方法的所有参数的类型;
Class[] getExceptionTypes():获取方法上声明的所有异常类型;
Class getReturnType():获取方法的返回值类型;
Object invode(Object obj, Object… args):
通过方法反射对象调用方法,如果当前方法是实例方法,那么当前对象就是obj,如果当前方法是static方法,那么可以给obj传递null。args表示是方法的参数;
现在我们试着获取User的toString方法。
<span style="color:#000000;">public class Test {
@org.junit.Test
public void fun1() throws Exception {
Class<?> clazz = Class.forName("lsj.pc.User");
Constructor<?> c=clazz.getConstructor(String.class,String.class);
User user=(User) c.newInstance("TOM","1234567");
Method method=clazz.getMethod("toString");
String result =(String) method.invoke(user);
/*User user = (User)clazz.newInstance();
user.setPassword("1234567");
user.setUsername("TOM");*/
System.out.println(result);
}
}</span>
结果 :用户名:TOM, 密码:1234567
4)获取类的成员变量
Field getField(String name):通过名字获取公有成员变量的反射对象,包含父类中声明的公有成员变量;
Field[] getFields():获取所有公有成员变量反射对象,包含父类中声明的公有成员变量;
Field getDeclaredField(String name):通过名字获取本类中某个成员变量,包含本类的private成员变量,但父类中声明的任何成员变量都不包含;
Field[] getDeclaredFields():获取本类中声明的所有成员变量,包含private成员变量,但不包含父类中声明的任何成员变量;
Fileld类有以下的一些常用的方法:
String getName():获取成员变量名;
Class getDeclaringClass():获取成员变量的类型;
Class getType():获取当前成员变量的类型;
Object get(Object obj):获取obj对象的成员变量的值;
void set(Object obj, Object value):设置obj对象的成员变量值为value;
下面举一个例子:
import java.lang.reflect.Field;
public class Test {
@org.junit.Test
public void fun1() throws Exception {
Class<?> clazz = Class.forName("lsj.pc.User");
User user=new User("老王","123");
Field field1=clazz.getDeclaredField("username");
Field field2=clazz.getDeclaredField("password");
String username=(String) field1.get(user);
String password=(String) field2.get(user);
System.out.println(username+","+password);
field1.set(user,"lisi");
field2.set(user,"456");
System.out.println(user);
}
}
class User {
public String username;
public String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
public User() {
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "用户名:"+ username + ", 密码:" + password ;
}
}
输出结果:
老王,123
用户名:lisi, 密码:456
5)获取AccessibleObject
AccessibleObject类是Constructor、Method、Field三个类的父类。AccessibleObject最为重要的方法如下:
boolean isAccessible():判断当前成员是否可访问;
void setAccessible(boolean flag):设置当前成员是否可访问。
当Constructor、Method、Field为私有时,如果我们想反射操作,那么就必须先调用反射对象的setAccessible(true)方法,然后才能操作。
把刚才的User类中的两个属性改成private类型。
public void fun1() throws Exception {
Class<? > clazz = Class.forName("lsj.pc.User");
User user=new User("老王","123");
Field field1=clazz.getDeclaredField("username");
Field field2=clazz.getDeclaredField("password");
field1.setAccessible(true);
field2.setAccessible(true);
String username=(String) field1.get(user);
String password=(String) field2.get(user);
System.out.println(username+","+password);
field1.set(user,"lisi");
field2.set(user,"456");
System.out.println(user);
}
这样就可以访问私有的成员变量了。
还没有评论,来说两句吧...