一、简介

工作中经常会遇到动态处理类及属性的场景,在此处记录下常用方法。

1、依赖的jar

部分样例方法依赖的jar有:

  • Apache Commons BeanUtils

下载

或使用Maven:

<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.9.3</version>
</dependency>
  • Apache Commons Logging

下载

2、模型类

样例使用到的模型相关类有:

Animal:

public class Animal {

	private String id;
	private String name;
	private List<Animal> children = new ArrayList<>();
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public List<Animal> getChildren() {
		return children;
	}
	public void setChildren(List<Animal> children) {
		this.children = children;
	}
	
}

Mammal:

public class Mammal extends Animal{

	private Nest nest;
	private boolean male;
	
	public Nest getNest() {
		return nest;
	}
	public void setNest(Nest nest) {
		this.nest = nest;
	}
	public boolean isMale() {
		return male;
	}
	public void setMale(boolean male) {
		this.male = male;
	}
	
}

Nest:

public class Nest {

	private int size;
	private String color;
	
	public int getSize() {
		return size;
	}
	public void setSize(int size) {
		this.size = size;
	}
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	
}

Dog:

public class Dog extends Mammal{

	private Map<String, Animal> friends = new HashMap<>();

	public Map<String, Animal> getFriends() {
		return friends;
	}

	public void setFriends(Map<String, Animal> friends) {
		this.friends = friends;
	}
	
}

二、常用方法

1、判断对象是否可读写某个属性

  • 方法定义:
PropertyUtils.isReadable(Object bean, String name)

PropertyUtils.isWriteable(Object bean, String name)
  • 样例:
public static void main(String[] args) {
	Dog dog = new Dog();
	System.out.println(PropertyUtils.isReadable(dog, "id"));
	System.out.println(PropertyUtils.isWriteable(dog, "name"));
}
  • 输出:
true
true

2、对象普通属性的赋值与取值

  • 方法定义:

设置指定bean的某个属性的值:

PropertyUtils.setProperty(Object bean, String name, Object value)

设置指定bean的某个(可能是嵌套的)属性的值:

PropertyUtils.setNestedProperty(Object bean, String name, Object value)

返回指定bean的某个属性的值:

PropertyUtils.getProperty(Object bean, String name)

返回指定bean的某个(可能是嵌套的)属性的值:

PropertyUtils.getNestedProperty(Object bean, String name)
  • 样例:
public static void main(String[] args) {
	try {
		Dog dog = new Dog();
		Nest nest = new Nest();
		dog.setNest(nest);
		
		PropertyUtils.setProperty(dog, "id", "007");
		PropertyUtils.setNestedProperty(dog, "nest.color", "pink");
		PropertyUtils.setProperty(dog, "name", "super dog");
		
		System.out.println(PropertyUtils.getProperty(dog, "id"));
		System.out.println(PropertyUtils.getNestedProperty(dog, "nest.color"));
		System.out.println(PropertyUtils.getNestedProperty(dog, "name"));
	} catch (Exception e) {
		e.printStackTrace();
	}
}
  • 输出:
007
pink
super dog

3、对象集合属性的赋值与取值

  • 方法定义:

获取指定bean的Map属性某个key的值:

PropertyUtils.getMappedProperty(Object bean, String name, String key)

设置指定bean的Map属性某个key的值:

PropertyUtils.setMappedProperty(Object bean, String name, String key, Object value)

获取指定bean的List属性指定索引位置元素的值:

PropertyUtils.getIndexedProperty(Object bean, String name, int index)

设置指定bean的List属性指定索引位置元素的值:

PropertyUtils.setIndexedProperty(Object bean, String name, int index, Object value)
  • Map样例
public static void main(String[] args) {
	try{
		String field = "friends";
		Dog dog = new Dog();
		dog.setName("Tom");
		
		Dog abel = new Dog();
		abel.setName("Abel");
		dog.getFriends().put(abel.getName(), abel);
		
		Dog ben = new Dog();
		ben.setName("Ben");
		PropertyUtils.setMappedProperty(dog, field, "AAA", ben);
		
		Dog friend = (Dog) PropertyUtils.getMappedProperty(dog, field, "Abel");
		System.out.println(friend.getName());
		
		friend = (Dog) PropertyUtils.getMappedProperty(dog, field, "AAA");
		System.out.println(friend.getName());
	}catch(Exception e){
		e.printStackTrace();
	}
}

输出:

Abel
Ben
  • List样例
public static void main(String[] args) {
	try{
		String field = "children";
		Dog dog = new Dog();
		dog.setName("Tom");
		dog.getChildren().add(null);
		dog.getChildren().add(null);
	
		Dog one = new Dog();
		one.setName("a child");
		
		Dog another = new Dog();
		another.setName("another child");
		
		PropertyUtils.setIndexedProperty(dog, field, 0, one);
		PropertyUtils.setIndexedProperty(dog, field, 1, another);
		
		Dog child = (Dog) PropertyUtils.getIndexedProperty(dog, field, 0);
		System.out.println(child.getName());
		child = (Dog) PropertyUtils.getIndexedProperty(dog, field, 1);
		System.out.println(child.getName());
	}catch(Exception e){
		e.printStackTrace();
	}
}

输出:

a child
another child

4、获取某个类或对象的属性描述符

  • 方法定义:
PropertyUtils.getPropertyDescriptors(Class<?> beanClass)

PropertyUtils.getPropertyDescriptors(Object bean)
  • 样例:
public static void main(String[] args) {
	PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(Dog.class);
	for(PropertyDescriptor descriptor : descriptors){
		System.out.println(String.format("%s\t%s", descriptor.getName(), descriptor.getPropertyType()));
	}
}
  • 输出:
children	interface java.util.List
name	class java.lang.String
id	class java.lang.String
nest	class com.bean.model.Nest
class	class java.lang.Class
friends	interface java.util.Map
male	boolean

5、获取某个类的所有字段

与上面类似,下面的方法也支持获取继承的属性:

public static List<Field> getFields(Class<?> clazz){
	List<Field> fields = new ArrayList<>();
	while(clazz != null){
		Field[] declaredFields = clazz.getDeclaredFields();
		for(Field field : declaredFields){
			//过滤掉static属性
			if(Modifier.isStatic(field.getModifiers())){
				continue;
			}
			fields.add(field);
		}
		clazz = clazz.getSuperclass();
	}
	return fields;
}
  • 测试方法:
public static void main(String[] args) {
	List<Field> fields = getFields(Dog.class);
	for(Field field : fields){
		System.out.println(String.format("%s\t%s", field.getName(), field.getType()));
	}
}
  • 输出:
friends	interface java.util.Map
nest	class com.bean.model.Nest
male	boolean
id	class java.lang.String
name	class java.lang.String
children	interface java.util.List

6、获取集合元素的类型

public static Class<?> getListItemClass(Class<?> clazz, String property) {
	try {
		Field field = clazz.getDeclaredField(property);
		Type genericType = field.getGenericType();
		if(genericType instanceof ParameterizedType){
			ParameterizedType itemType = (ParameterizedType) genericType;
			Class<?> itemClass = (Class<?>) itemType.getActualTypeArguments()[0];
			return itemClass;
		}
	}catch (Exception e) {
		e.printStackTrace();
	}
	return null;
}
  • 测试方法:
private static void test03() {
	Class<?> itemClass = getListItemClass(Animal.class, "children");
	System.out.println(itemClass);
}
  • 输出:
class com.bean.model.Animal

7、动态创建集合及元素

  • 样例
public static void main(String[] args) {
	 try {
		//动态创建对象
		Animal animal = Animal.class.newInstance();
		PropertyUtils.setProperty(animal, "id", "001");
		PropertyUtils.setProperty(animal, "name", "Tom");
		//动态创建集合
		List<Object> children = ArrayList.class.newInstance();
		PropertyUtils.setProperty(animal, "children", children);
		Class<?> itemType = getListItemClass(Animal.class, "children");
		//创建集合元素
		Object child = itemType.newInstance();
		PropertyUtils.setProperty(child, "name", "Tom's baby");
		children.add(child);
		
		System.out.println(String.format("ID: %s, Name: %s", animal.getId(), animal.getName()));
		for(Animal item : animal.getChildren()){
			System.out.println("Child Name: " + item.getName());
		}
	} catch (Exception e) {
		e.printStackTrace();
	}
}
  • 输出:
ID: 001, Name: Tom
Child Name: Tom's baby
参考资料: