如何反射出对象的所有属性?

本文对比了使用不同编程语言实现反射功能的方法,包括JavaScript、Swift3.0和Java。介绍了每种语言的具体实现细节,并讨论了它们之间的差异。

        用你现在用的语言写出这个反射功能可能too easy, 但如果让你用现在前端主流的Java、JavaScript、Object-C、Swift写呢?

       Object-C语言已经没落了,用Swift3.0语言更有前途, 看看最近苹果公司禁用JS Patch的事件就该明白,作为iOS开发者必须紧跟苹果的节奏。

      话说Swift和JS在有些地方很像,因为Swift借鉴了JS语言的特性。

先感受下JS的实现方式, 注意JS语法里一切都是对象, 下面所列了3中实例化对象的方法。 for in循环跟Swift类似,区别是for后面Swift不需要圆括号,但JS必须要圆括号。

PS:分号在JS语法里是可选的。

<script>
//声明类的第一种方式	
car = {color:"blue", length: 4, weight: "1000kg"}	
for (variable in car) {
	document.write(variable + ":" + car[variable] + "<br>")  //遍历对象属性
}
	
document.write("<br>")
	
//声明类的第二种方式	
function person(firstname,lastname,age,eyecolor){
	this.firstname=firstname;
	this.lastname=lastname;
	this.age=age;
    this.eyecolor=eyecolor;
}	
myFather=new person("John","Doe",50,"blue");
for (variable in myFather) {
	document.write(variable + ":" + myFather[variable] + "<br>")  //遍历对象属性
}	
document.write("<br>")

//第三种方式
var obj = new Object();
obj.myname = "张三"; //String类型
obj.age = 20;     //Number类型
obj.test = true;  //布尔类型
for (variable in obj) {
	document.write(variable + ":" + obj[variable] + "<br>")  //遍历对象属性
}	

document.write(myFather.firstname + " is " + myFather.age + " years old.");  //访问属性
document.write("<br>")  //换行
document.write(myFather["firstname"])  //访问属性
document.write("<br>")

</script>

Swift3.0实现方式:

struct Book {
    let name: String?
    let price: Int
    let test: Bool
}

let book = Book(name: nil, price: 10, test: true)
let mirror = Mirror(reflecting: book)
for case let (key?, value) in mirror.children {  //children是Array类型, for case表示参数不为nil
    print("key:\(key), value: \(value)")  
}

print(mirror.description)
输出:

key:name, value: nil
key:price, value: 10
key:test, value: true
Mirror for Book

Java版本:

   Person person = new Person();
        person.name = "zhangsan";
        person.age = 20;
        person.test = true;

        Class clz = person.getClass();
        Field[] fields = clz.getDeclaredFields();
        try {
            for (Field field : fields) {
                System.out.print(field.getName() + ":");
                Object value = field.get(person);
                if (value != null) {
                    System.out.print(String.valueOf(value));
                }
                System.out.println();
                //判断参数数据类型, 注意自动装箱和拆箱的语法特性
                /*
                if (value instanceof Double) {
                    System.out.print("double类型")
                } else if (value instanceof String) {
                    System.out.print("String类型")
                } else if (value instanceof Integer) {
                    System.out.println("int类型");
                }
                */
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
输出:

name:zhangsan
age:20
test:true

      通过对比可以看出, Java是最麻烦的,还要捕获异常;Swift3.0和JS的代码量较少,不需要捕获异常,而且代码很像。

    

      JSON序列化和反序列化用到反射语法,  比如Swift语言版本的SwiftyJSON、Java的fastjson/Gson。


PS: 用多种语言实现一个功能,可以更好的学习和掌握各个语言的区别。





<think> 我们正在讨论的是通过反射获取对象属性值的方法。根据用户提供的引用,这些引用都是关于Java反射的示例。因此,我将提供Java中的反射获取属性值的方法。 在Java中,通过反射获取对象属性值的基本步骤: 1. 获取对象的Class对象。 2. 通过Class对象获取指定字段(属性)的Field对象。如果是私有属性,需要设置可访问性。 3. 通过Field对象的get方法获取属性值。 引用[1]和[3]提供了具体的代码示例。 下面我将详细说明: ### 方法一:获取公共属性值 对于公共属性(public),可以直接获取: ```java Field field = obj.getClass().getField("fieldName"); // 获取公共属性 Object value = field.get(obj); ``` ### 方法二:获取任意属性(包括私有属性) 对于私有属性,需要使用`getDeclaredField`并设置可访问性: ```java Field field = obj.getClass().getDeclaredField("fieldName"); // 获取任何声明的属性(包括私有) field.setAccessible(true); // 设置可访问,即使是私有属性 Object value = field.get(obj); ``` ### 完整示例: ```java import java.lang.reflect.Field; public class ReflectionExample { public static void main(String[] args) throws Exception { // 创建一个对象 Student student = new Student(); student.setName("张三"); student.setAge(20); // 获取公共属性值 Field nameField = student.getClass().getDeclaredField("name"); // 因为name是私有属性,所以需要设置可访问 nameField.setAccessible(true); String nameValue = (String) nameField.get(student); System.out.println("name: " + nameValue); // 获取公共属性(age是public) Field ageField = student.getClass().getField("age"); int ageValue = (int) ageField.get(student); System.out.println("age: " + ageValue); } } class Student { private String name; public int age; public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } } ``` 注意: 1. 如果属性是基本类型(如int, double等),使用`Field.get`会返回对应的包装类型(如Integer, Double)。也可以直接使用Field对象提供的特定方法,如`getInt`、`getDouble`等,避免类型转换。 2. 获取属性值可能会抛异常,需要处理`IllegalAccessException`等。 ### 封装工具方法 我们可以封装一个工具方法来获取任意对象属性值(包括私有): ```java public static Object getFieldValue(Object obj, String fieldName) { try { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); return field.get(obj); } catch (NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException(e); } } ``` ### 遍历所有属性 引用[2]和[3]展示了如何遍历对象的所有属性并获取值: ```java public static void getAllFieldValues(Object obj) { Class<?> clazz = obj.getClass(); Field[] fields = clazz.getDeclaredFields(); // 获取所有声明的属性(不包括继承的父类属性) for (Field field : fields) { try { field.setAccessible(true); Object value = field.get(obj); System.out.println(field.getName() + ": " + value); } catch (IllegalAccessException e) { e.printStackTrace(); } } } ``` 注意:`getDeclaredFields()`只能获取当前类声明的所有字段(包括私有、保护、默认和公有),但不包括继承的字段。如果要获取包括父类的字段,需要递归向上查找。 ### 处理父类属性 如果需要获取包括父类的所有属性,可以递归: ```java public static List<Field> getAllFields(Class<?> clazz) { List<Field> fields = new ArrayList<>(); while (clazz != null) { fields.addAll(Arrays.asList(clazz.getDeclaredFields())); clazz = clazz.getSuperclass(); } return fields; } ``` 然后遍历这个列表获取属性值。 ### 注意事项 - 反射会破坏封装性,并且有性能开销,应谨慎使用。 - 对于私有成员,需要设置`setAccessible(true)`,但可能会受到安全管理器的限制。 §§相关问题§§ 1. 如何通过反射调用对象的私有方法? 2. 反射操作属性时如何处理值类型转换? 3. 如何通过反射获取属性的自定义特性(注解)? </think> ### 通过反射获取对象属性值的方法(Java 实现) #### 核心步骤 1. **获取 Class 对象** 通过对象实例或类名获取类的 Class 对象: ```java Class<?> clazz = obj.getClass(); // 或 Class<?> clazz = Class.forName("com.example.Student"); ``` 2. **获取属性字段** - 获取单个属性: ```java Field field = clazz.getDeclaredField("fieldName"); // 获取指定名称属性(包括私有) // 或 Field field = clazz.getField("fieldName"); // 仅获取公共属性 ``` - 获取所有属性: ```java Field[] fields = clazz.getDeclaredFields(); // 获取所有属性(包括私有) ``` 3. **设置访问权限**(针对私有属性) ```java field.setAccessible(true); // 解除私有属性访问限制 ``` 4. **获取属性值** ```java Object value = field.get(obj); // 从对象实例读取属性值 ``` #### 完整示例代码 ```java import java.lang.reflect.Field; class Student { private String name = "张三"; public int age = 20; } public class ReflectionDemo { public static void main(String[] args) throws Exception { Student student = new Student(); // 1. 获取Class对象 Class<?> clazz = student.getClass(); // 2. 获取私有属性值 Field nameField = clazz.getDeclaredField("name"); nameField.setAccessible(true); // 解除私有限制 String nameValue = (String) nameField.get(student); System.out.println("私有属性name值: " + nameValue); // 输: 张三 // 3. 获取公共属性值 Field ageField = clazz.getField("age"); int ageValue = ageField.getInt(student); // 直接获取基本类型值 System.out.println("公共属性age值: " + ageValue); // 输: 20 // 4. 遍历所有属性值 System.out.println("\n所有属性值:"); for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); Object value = field.get(student); System.out.println(field.getName() + " = " + value); } } } ``` #### 输结果: ``` 私有属性name值: 张三 公共属性age值: 20 所有属性值: name = 张三 age = 20 ``` ### 关键注意事项 1. **异常处理** 需处理以下异常: ```java try { // 反射操作代码 } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } ``` 2. **性能优化** - 缓存 `Field` 对象避免重复查找: ```java private static final Field NAME_FIELD = Student.class.getDeclaredField("name"); static { NAME_FIELD.setAccessible(true); } ``` 3. **类型安全处理** - 基本类型需使用专用方法: ```java int intValue = field.getInt(obj); double doubleValue = field.getDouble(obj); ``` - 对象类型需强制转换: ```java String strValue = (String) field.get(obj); ``` 4. **父类属性获取** 递归获取父类属性: ```java public static Object getSuperField(Object obj, String fieldName) throws Exception { Class<?> clazz = obj.getClass().getSuperclass(); Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); return field.get(obj); } ``` > 参考实现:[引用1][^1]展示了私有属性访问,[引用3][^3]演示了属性遍历方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值