这个程序为什么输出的是null
有人可以帮忙解释一下这个代码吗
非常感谢!
public class Base {
private String baseName = "base";
public Base() {
m();
}
public void m() {
System.out.println(baseName);
}
static class Sub extends Base {
private String baseName = "sub";
public void m() {
System.out.println(baseName);
}
}
public static void main(String[] args) {
Base b = new Sub();
}
}
在执行构造函数时,m() 方法被调用。因为此时正在创建 Sub 对象,所以我们期望输出的是 "sub" 而不是 "base"。 但是在 Sub 中有一个域名与基类中的 baseName 相同。在 Java 中,实例变量会遮蔽掉同名的基类变量,因此用 baseName 屏蔽基类中的 baseName。
然而,由于在调用 m() 方法时正在构造 Sub 对象,并且在 Sub 构造函数之前必须完成 Base 的构造函数(因为子类需要依赖父类进行初始化),因此此时 baseName 实例变量仍然未初始化(即 null)。因此,打印出的是 null。
这个问题可以通过将 Base 类中的构造函数声明为 private 或 final 来解决。这样,在 Sub 中无法覆盖基类的 m() 方法并且您将得到所需的输出(e.g. "sub")。
public interface UserSearchService{
/**
* 根据用户id获取用户信息
* @param id 用户id
* @return 用户实体,此实体有可能是缺省值
*/
Optional<User> getOptional(Integer id);
}
仅看接口文档,不能确定入参是否为必填项,同样存在 NullPointerException的风险。如何约束入参呢?其实和返回值处理方式基本相同
强制约束
文档性约束(弱提示)
强制约束,利用jsr 303进行严格的约束声明
public interface UserSearchService{
/**
* 根据用户id获取用户信息
* @param id 用户id
* @return 用户实体,此实体有可能是缺省值
*/
Optional<User> getOptional(@NotNull Integer id);
}
文档性约束
在很多时候,我们会遇到遗留代码,对于遗留代码,整体性改造的可能性很小。
我们更希望通过阅读接口的实现,来进行接口的说明。
jsr 305规范,给了我们一个描述接口入参的一个方式(需要引入库 com.google.code.findbugs:jsr305):
可以使用注解: @Nullable @Nonnull @CheckForNull 进行接口说明
public interface UserSearchService{
/**
* 根据用户id获取用户信息
* @param id 用户id
* @return 用户实体
* @exception UserNotFoundException
*/
@CheckForNull
User get(@NonNull Integer id);
/**
* 根据用户id获取用户信息
* @param id 用户id
* @return 用户实体,此实体有可能是缺省值
*/
Optional<User> getOptional(@NonNull Integer id);
}
针对问题的解决方案: 1. 可能的原因: - 在程序设计中,没有对可能为空的数据进行判断。 - 接口定义中,对入参和返回值没有进行约束说明,导致出现null。 2. 解决方案: - 对程序中可能为空的数据进行判断,可以使用类似if(obj != null)这样的语句来判断。 - 在接口定义中,对入参和返回值进行严格的约束声明。可以使用@NotNull、@NonNull、@CheckForNull等注解进行约束说明,使用jsr 303进行严格的约束。如果是遗留代码,可以采用文档性约束的方式,在接口的实现中进行说明。 - 对于返回值为集合的情况,建议即使查询内容为null,也要分组成空集合返回,以避免空指针异常的发生。而对于查询结果为单个实体对象的情况,可以在逻辑中进行特判,返回null或者采用一些特殊的返回值代表该实体不存在。