前年写过一篇关于java“反射”的博客,现在看来不够深入。如今在原来的基础上再加一些东西。主要细化一下反射中主要用到的方法。还是在原来代码的基础上进行测试。
1. 获取反射class对象
在原来的博客中介绍过反射获取class对象的三种方式。如下:
//第一种方式获取Class对象
User user1 = new User();//这一new 产生一个user对象,一个Class对象。
Class userClass = user1.getClass();
System.out.println("方式一获取的class: "+ userClass);
//第二种方式获取Class对象
Class userClass2 = User.class;
//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
System.out.println("方式二获取的class: "+ userClass2);
System.out.println("方式一和方式二获取结果比较:"+ (userClass == userClass2));
//第三种方式获取Class对象
//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
Class userClass3 = Class.forName("reflect.entity.User");
System.out.println("方式三获取的class: "+ userClass3);
System.out.println("方式二和方式三获取结果比较:"+ (userClass2 == userClass3));
打印结果为:
方式一获取的class: class reflect.entity.User
方式二获取的class: class reflect.entity.User
方式一和方式二获取结果比较:true
方式三获取的class: class reflect.entity.User
方式二和方式三获取结果比较:true
class对象内容:
区别:
三种方式常用第三种,
第一种:对象都有了还要反射干什么。可以通过一些放射方法来操作这个对象。
第二种:需要导入类的包,依赖太强,不导包就抛编译错误。
第三种:一个字符串可以传入也可写在配置文件中等多种方法。
2. 属性Field
2.1 获取属性
方法 | 功能 |
getFields() | 获取所有public字段,包括父类字段 |
getDeclaredFields() | 获取所有字段,public和protected和private,但是不包括父类字段 |
public Field getField(String name) | 根据字段名称获取public字段 |
public Field getDeclaredField(String name) | 根据字段名称获取自身的单个字段 |
代码dome
/**
* 获取属性
*/
Class userClass3 = Class.forName("reflect.entity.User");
Field[] publicFields = userClass3.getFields();
Field[] allSelfFields = userClass3.getDeclaredFields();
System.out.println("获取所有public字段,包括父类字段");
for (Field f:publicFields) {
System.out.println("getFields---"+f.getName());
}
System.out.println("获取所有字段,public和protected和private,但是不包括父类字段");
for (Field f:allSelfFields) {
System.out.println("getDeclaredFields---"+f.getName());
}
System.out.println();
System.out.println("根据名称获取单个public字段,包括父类字段");
Field publicFieldByName = userClass3.getField("name");
System.out.println("getField by name---"+publicFieldByName.getName());
System.out.println();
System.out.println("根据名称获取自身单个字段,public和protected和private,但是不包括父类字段");
Field selfFieldByName = userClass3.getDeclaredField("passWord");
System.out.println("getDeclaredField by name---"+selfFieldByName.getName());
结果打印
:可见getFields可以获取到父类中的public字段,getDeclaredFields可以获取自身的所有字段。
获取所有public字段,包括父类字段
getFields---userId
getFields---name
获取所有字段,public和protected和private,但是不包括父类字段
getDeclaredFields---userName
getDeclaredFields---passWord
getDeclaredFields---userId
getDeclaredFields---phone
getDeclaredFields---ipAddress
根据名称获取单个public字段,包括父类字段
getField by name---name
根据名称获取自身单个字段,public和protected和private,但是不包括父类字段
getDeclaredField by name---passWord
2.2 属性(Field)相关方法
方法名 | 作用 |
public int getModifiers() | 得到属性的修饰符(0:没有修饰符(default);1:public;2:private;4:protected) |
public String getName() | 得到属性的名称。 |
public boolean isAccessible() | 判断此属性是否被外部访问 |
public void setAccessible(Boolean flag) | 设置一个属性是否可被外部访问。 |
public String toString() | 返回此Field类的信息 |
public Object get(Object obj) | 得到一个对象中属性的具体内容,必须要声明一个对象 |
public void set(Object obj,Object value)t | 设置指定对象中属性的具体内容,必须要声明一个对象 |
代码demo
/**
* 属性赋值
*/
Class userClass3 = Class.forName("reflect.entity.User");
Field[] allSelfFields = userClass3.getDeclaredFields();
User setUser = new User();
System.out.println("获取所有public字段,包括父类字段");
int i =1;
for (Field f:allSelfFields) {
System.out.println("属性名称为: "+f.getName()+";是否可被访问:"+f.isAccessible()+";修饰符为: "+f.getModifiers());
// 设为可访问
f.setAccessible(true);
// 赋值
f.set(setUser,"a"+Integer.toString(i));
// 获取属性的值
System.out.println("属性名称为:"+f.getName()+",属性值为: "+f.get(setUser));
++i;
}
System.out.println(setUser.toString());
结果打印
name, age, sex字段为父类非public字段,所以没有被访问的,也就没被赋值。
获取所有public字段,包括父类字段
属性名称为: userName;是否可被访问:false;修饰符为: 2
属性名称为:userName,属性值为: a1
属性名称为: passWord;是否可被访问:false;修饰符为: 2
属性名称为:passWord,属性值为: a2
属性名称为: userId;是否可被访问:false;修饰符为: 1
属性名称为:userId,属性值为: a3
属性名称为: phone;是否可被访问:false;修饰符为: 4
属性名称为:phone,属性值为: a4
属性名称为: ipAddress;是否可被访问:false;修饰符为: 0
属性名称为:ipAddress,属性值为: a5
User{userName='a1', passWord='a2', userId='a3', phone='a4', ipAddress='a5', name='null', age=null, sex=}
3. 方法
3.1 获取方法
方法名 | 作用 |
Method[] getMethods() | 获取所有public方法,包括父类public方法 |
Method[] getDeclaredMethods() | 获取自身声明的方法,包括私有方法但不包括父类字段 |
Constructor<?>[] getConstructors() | 获取构造函数 |
Method getMethod(String name, Class<?>... parameterTypes) | 根据方法名称获取所有public方法,包括父类public方法 |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 根据方法名称获取自身声明的方法,包括私有方法但不包括父类字段 |
代码dome
Class userClass3 = Class.forName("reflect.entity.User");
System.out.println("获取所有public方法,包括父类public方法");
Method[] methods = userClass3.getMethods();
for (Method m:methods) {
System.out.println(m.getName());
}
System.out.println("获取类中声明public方法,但是不包括父类字段");
Method[] declaredMethods = userClass3.getDeclaredMethods();
for (Method m:declaredMethods) {
System.out.println(m.getName());
}
System.out.println("获取构造函数");
Constructor[] declaredConstructors = userClass3.getConstructors();
for (Constructor m:declaredConstructors) {
System.out.println(m.getName());
}
System.out.println("根据方法名称获取单个方法");
Method getUserPublicMethod = userClass3.getMethod("getUserPublicMethod", String.class);
System.out.println("getMethod---"+getUserPublicMethod.getName());
Method getUserPrivateMethod = userClass3.getDeclaredMethod("getUserPrivateMethod", String.class);
System.out.println("getDeclaredMethod---"+getUserPrivateMethod.getName());
结果打印
获取所有public方法,包括父类public方法
getUserPublicMethod
toString
getPersonPublicMethod
wait
wait
wait
equals
hashCode
getClass
notify
notifyAll
获取public方法,但是不包括父类字段
getUserPublicMethod
getUserPrivateMethod
toString
获取构造函数
reflect.entity.User
reflect.entity.User
根据方法名称获取单个方法
getMethod---getUserPublicMethod
getDeclaredMethod---getUserPrivateMethod
3.2 调用方法
通过调用public Object invoke(Object obj, Object... args)来实现反射调用方法,但对于私有方法需要将私有方法访问性进行修改;
代码demo
Class userClass3 = Class.forName("reflect.entity.User");
Method getUserPublicMethod = userClass3.getDeclaredMethod("getUserPublicMethod", String.class);
System.out.print("调用方法为: "+getUserPublicMethod.getName());
getUserPublicMethod.invoke(userClass3.newInstance(), "调用公有方法");
Method getUserPrivateMethod = userClass3.getDeclaredMethod("getUserPrivateMethod", String.class);
System.out.print("调用方法为: "+getUserPrivateMethod.getName());
getUserPrivateMethod.setAccessible(true);
getUserPrivateMethod.invoke(userClass3.newInstance(), "调用私有方法");
结果打印
getDeclaredMethod---getUserPublicMethod
子类公有方法调用,参数为: 调用公有方法
getDeclaredMethod---getUserPrivateMethod
子类私有方法调用,参数为: 调用私有方法
4. 其他操作
方法名 | 作用 |
Class<? super T> getSuperclass() | 获取父类 |
5. 反射的原理
6. 代码结构
Person
package reflect.entity;
public class Person {
public String name;
protected Integer age;
char sex;
private String address;
public void getPersonPublicMethod(String param){
System.out.println("父类共有方法,参数为:"+param);
}
private void getPersonPrivateMethod(String param){
System.out.println("父类私有方法,参数为:"+param);
}
}
User
package reflect.entity;
public class User extends Person{
private String userName;
private String passWord;
public String userId;
protected String phone;
String ipAddress;
public User() {}
public User(String userName, String passWord) {
this.userName = userName;
this.passWord = passWord;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", passWord='" + passWord + '\'' +
", userId='" + userId + '\'' +
", phone='" + phone + '\'' +
", ipAddress='" + ipAddress + '\'' +
", name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
public void getUserPublicMethod(String param){
System.out.println("子类公有方法调用,参数为: "+param);
}
private void getUserPrivateMethod(String param){
System.out.println("子类私有方法调用,参数为: "+param);
}
}