null对象打印为什么是null?

JAVA中有八种基本数据类型,他们在初始化的时候会被赋予初始值。

byte -> 0
short -> 0
int -> 0
long -> 0
char -> " "(看起来像是一个空格)
float -> 0.0
double -> 0.0
boolean -> false

引用类型对象初始化会被赋予初始值:null

String s = null;
try{
    s.toString();
} catch(NullPointerException e){
    e.printStackTrace();
}
System.out.println(s);

执行结果如下:

java.lang.NullPointerException
	at GjcTest.main(GjcTest.java:5)
null

问题1:String类型null对象为什么会被打印成null?

当我们调用null对象的方法时,会抛出异常。但是我们打印null对象却不会抛出异常,感觉是println方法对null对象做了什么处理。

println方法源码如下:

public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

嗯,答案可能在方法print中,我们打开print方法源码:

public void print(String s) {
    if (s == null) {
        s = "null";
    }
    write(s);
}

嗯,简单粗暴的处理方式,如果传入String对象是null,则直接打印字符串“null”。

那如果是引用类型呢?我们就以Integer类作为示例。

Integer i = null;
try{
    i.toString();
} catch(NullPointerException e){
    e.printStackTrace();
}
System.out.println(i);

 执行结果如下:

java.lang.NullPointerException
	at GjcTest.main(GjcTest.java:5)
null

问题2:非String类型null对象为什么会被打印成null?

我们先看一下println源码:

public void println(Object x) {
    String s = String.valueOf(x);
    synchronized (this) {
        print(s);
        newLine();
    }
}

 第一感觉是print方法应该是对null对象进行了处理的,我们直接打开print方法源码:

public void print(String s) {
    if (s == null) {
        s = "null";
    }
    write(s);
}

嗯?怎么调用的是参数类型是String类型的方法?哦,原来在println方法中,调用print方法参数类型是String类的,那么问题应该是在println源码中第2行valueOf方法中。valueOf方法源码如下:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

这个问题就解决了,如果传入的引用类型对象是null,那么返回字符串“null”,否则调用对象的toString方法。

总结

String类型null对象处理方式:判断对象是否是null,如果是null,打印字符串“null”;如果不是null,打印字符串。

非String类型null对象处理方式:判断对象是否是null,如果是null,打印字符串“null”;如果不是null,调用对象的toString方法,并打印字符串。

我的疑问

高敬超

 如图所示:println(Object o)处理逻辑是调用String.valueOf()方法,判断对象o是否为空并返回需要打印的字符串,然后调用print(String s)打印出来。为什么println(Object o)不直接调用print(Object o)呢,代码如下。是设计者就是这样设计的,还是有什么原因?

public void println(Object x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

 

<think>好的,我现在需要解决用户在使用Spring的BeanUtils.copyProperties方法时,复制后对象属性全为null的问题。首先,用户提到他们遇到了这个问题,而根据提供的引用内容,可能的原因有参数顺序错误、属性名称或类型不匹配、访问权限问题等。我需要逐步分析这些可能性,并给出相应的解决方案。 首先,参数顺序是否正确?根据引用[1],Spring的BeanUtils.copyProperties方法的参数顺序是源对象在前,目标对象在后,而Apache Commons的BeanUtils相反。如果用户混淆了这两个库的方法,参数顺序颠倒就会导致复制失败,目标对象属性为null。因此,我需要提醒用户检查是否使用了正确的方法,并确认参数的顺序是否正确。 接下来,属性名称和类型是否匹配。如果源对象和目标对象的属性名称不一致,或者类型无法转换,那么复制时这些属性会被忽略,导致目标属性为null。例如,源对象有属性userName,而目标对象是username,大小写不同会导致无法复制。用户需要检查两个类的属性是否一一对应,包括名称和类型。 然后,访问权限的问题。BeanUtils.copyProperties依赖于getter和setter方法。如果这些方法不是public的,或者不存在,那么复制过程无法访问属性,导致复制失败。需要检查源对象的getter方法和目标对象的setter方法是否存在,并且是public的。 另外,引用[3]提到,Spring的BeanUtils在复制时会忽略null值,而Apache Commons的BeanUtils不会。如果源对象的某些属性为null,使用Spring的方法时这些属性不会被复制到目标对象,可能导致目标对象原本有值的属性被覆盖为null。不过用户的问题是所有属性都为null,这可能更倾向于参数顺序或其他问题。但如果用户确实需要处理null值,可能需要使用Apache Commons的BeanUtils并配置选项,或者自定义处理。 还有可能是目标对象本身没有正确初始化。如果目标对象未被实例化,即还是null,那么调用copyProperties时会抛出异常,但用户的问题中是属性全为null,可能目标对象已经实例化,但属性未被正确复制。需要确认目标对象是否已经通过new创建。 此外,其他可能的原因包括静态或final修饰的属性,这些属性无法被复制,或者存在嵌套对象需要深拷贝,而BeanUtils默认是浅拷贝。不过这种情况通常导致部分属性为null,而不是全部。 解决方案方面,首先检查参数顺序是否正确,然后检查属性名称和类型是否匹配,确认getter和setter方法存在且可访问。如果使用Spring的BeanUtils并且希望忽略null值,可能需要切换到Apache Commons的BeanUtils,并配置相关选项。或者,可以手动复制属性,或使用其他工具如ModelMapper。 例如,引用[3]中的例子展示了如何使用Apache Commons的BeanUtils并设置不忽略null值,可能需要注册Converter来处理类型转换。另外,用户需要确保目标对象正确实例化,并且没有其他配置问题。 最后,生成相关问题需要考虑用户可能遇到的类似问题,比如不同工具库的区别、处理嵌套对象、深拷贝与浅拷贝等。</think>### Spring BeanUtils.copyProperties 复制后对象属性全为 null 的解决方案 #### 一、问题原因分析 1. **参数顺序错误** Spring 的 `BeanUtils.copyProperties` 方法参数顺序为**源对象在前,目标对象在后**,而 Apache Commons 的版本参数顺序相反。若混淆两者会导致复制失败[^1]。 ```java // Spring 正确用法 BeanUtils.copyProperties(sourceDemo, targetDemo); // Apache Commons 错误用法(会导致复制失败) BeanUtils.copyProperties(targetDemo, sourceDemo); ``` 2. **属性名称/类型不匹配** 若源对象与目标对象的属性**名称不同**,或**类型无法自动转换**(如 `Date` 转 `String`),属性会被忽略。例如源对象有 `createTime: Date`,而目标对象是 `createTime: String`。 3. **访问权限问题** `BeanUtils.copyProperties` 依赖目标对象的 `setter` 方法和源对象的 `getter` 方法。若方法非 `public` 或不存在,会导致复制失败。 4. **目标对象未初始化** 若目标对象未通过 `new` 实例化,直接调用会抛出空指针异常。例如: ```java TargetDemo target = null; // 错误 BeanUtils.copyProperties(source, target); ``` --- #### 二、解决方案 1. **检查参数顺序与库版本** 确认使用的是 `org.springframework.beans.BeanUtils`,并检查参数顺序是否为 `(源对象, 目标对象)`[^1]。 2. **核对属性映射关系** 通过反射工具检查属性名称和类型是否一致: ```java // 打印对象属性 Arrays.stream(source.getClass().getDeclaredFields()).forEach(f -> System.out.println(f.getName() + ": " + f.getType())); // 打印目标对象属性 Arrays.stream(target.getClass().getDeclaredFields()).forEach(f -> System.out.println(f.getName() + ": " + f.getType())); ``` 3. **显式声明 getter/setter 方法** 确保所有需要复制的属性都有 `public` 的访问方法: ```java // 源对象 public class SourceDemo { private String name; public String getName() { return name; } // 必须存在 } // 目标对象 public class TargetDemo { private String name; public void setName(String name) { this.name = name; } // 必须存在 } ``` 4. **处理 null 值问题** 若需要保留目标对象原有值(仅覆盖非 null 属性),使用 Apache Commons 的 `BeanUtils` 并配置忽略 null: ```java // 配置忽略 null 值 BeanUtilsBean utils = new BeanUtilsBean() { @Override public void copyProperty(Object dest, String name, Object value) throws IllegalAccessException, InvocationTargetException { if (value != null) { super.copyProperty(dest, name, value); } } }; utils.copyProperties(targetDemo, sourceDemo); // Apache Commons 参数顺序 ``` --- #### 三、替代方案 | 工具 | 特点 | 示例代码 | |---------------------|-----------------------------------|-----------------------------------| | **MapStruct** | 编译时生成代码,性能最佳 | `Mapper.INSTANCE.toDto(source)` | | **ModelMapper** | 支持复杂映射规则 | `modelMapper.map(source, Target.class)` | | **手动复制** | 完全可控,适合少量属性 | `target.setName(source.getName())` | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值