如何为类重载输出函数?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何为类重载输出函数?相关的知识,希望对你有一定的参考价值。
比如说有这样一个类
class A
public:
private:
int data;
int main()
A Temp;
cout<<Temp.data<<endl;
return 0;
显然这样是不行的,如果要重载<<的话应该怎么写,才能输出任意一个数据成员?
如何为不可变类创建默认构造函数
【中文标题】如何为不可变类创建默认构造函数【英文标题】:How to create default constructor for immutable class 【发布时间】:2019-02-25 11:39:00 【问题描述】:我喜欢基于this article (Why objects must be immutable) 使我的对象不可变。
但是,我正在尝试使用 Jackson Object Mapper 解析对象。我最初收到的是JsonMappingException: No suitable constructor found for type [simple type, class ]: cannot instantiate from JSON object.
我可以像here 中提到的那样修复它,方法是提供一个默认构造函数并使我的字段不是最终的。
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@AllArgsConstructor
// @NoArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
@Data
public class School
@NonNull
private final String schoolId;
@NonNull
private final String schoolName;
我应该遵循什么好的编程风格来克服这个问题?唯一的办法是让我的对象可变吗?
我可以使用不使用默认构造函数的不同映射器吗?
【问题讨论】:
为您的不可变对象创建对 Jackson 友好的工厂怎么样? github.com/rzwitserloot/lombok/issues/816 【参考方案1】:TL;DR:使用 lombok 并避免使用默认构造函数
使用@Value
制作不可变数据类
用@JsonProperty("name-of-property")
注释所有字段
将 lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty
添加到您的 lombok.config
以将其复制到生成的构造函数中
创建一个带有@JsonCreator
注释的全参数构造函数
示例:
@Value
@AllArgsConstructor(onConstructor_ = @JsonCreator)
class School
@JsonProperty("schoolId")
String schoolId;
@JsonProperty("schoolName")
String schoolName;
长答案
对于使用@JsonCreator
注释的静态工厂方法,imo 有一个更好的替代方法,那就是为所有元素提供一个构造函数(无论如何都是不可变类所必需的)。用@JsonCreator
注释那个 并用@JsonProperty
注释所有参数,如下所示:
class School
//fields
@JsonCreator
public School(
@JsonProperty("id") String id,
@JsonProperty("name") String name)
this.schoolId = id;
this.schoolName = name;
//getters
这些是@JsonCreator
注释为您提供的选项。它在其文档中这样描述它们:
单参数构造函数/工厂方法,没有参数的 JsonProperty 注释:如果是这样,这就是所谓的“委托创建者”,在这种情况下,杰克逊首先将 JSON 绑定到参数类型,然后调用创建者。这通常与 JsonValue 结合使用(用于序列化)。 构造函数/工厂方法,其中每个参数都使用 JsonProperty 或 JacksonInject 进行注释,以指示要绑定到的属性名称
在某些情况下,您甚至可能不需要显式指定参数名称。有关@JsonCreator
的文档进一步指出:
还请注意,所有 JsonProperty 注释必须指定实际名称(“默认”不是空字符串),除非您使用可以检测参数名称的扩展模块之一;这是因为 8 之前的默认 JDK 版本无法从字节码存储和/或检索参数名称。但是对于 JDK 8(或使用辅助库,如 Paranamer,或其他 JVM 语言,如 Scala 或 Kotlin),指定名称是可选的。
另外,这也可以很好地与 lombok 版本 1.18.3
或更高版本一起使用,您可以将 lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty
添加到您的 lombok.config
并因此让它将 JsonProperty
注释复制到构造函数,因为您确实注释了所有带有它的字段(海事组织无论如何都应该这样做)。要将@JsonCreator
-annotation 放在构造函数上,您可以使用实验性的onX feature。将 lombok 的 @Value
用于不可变数据类,您的 DTO 可能看起来像这样(未经测试):
@Value
//@AllArgsConstructor(onConstructor = @__(@JsonCreator)) // JDK7 or below
@AllArgsConstructor(onConstructor_ = @JsonCreator) // starting from JDK8
class School
@JsonProperty("schoolId")
String schoolId;
@JsonProperty("schoolName")
String schoolName;
【讨论】:
【参考方案2】:您可以使用 Jackson 工厂(使用 @JsonCreator 注释的方法)从地图中读取字段并调用您的非默认构造函数:
class School
//fields
public School(String id, String name)
this.schoolId = id;
this.schoolName = name;
@JsonCreator
public static School create(Map<String, Object> object)
return new School((String) object.get("schoolId"),
(String) object.get("schoolName"));
//getters
Jackson 将使用 Map
版本的 json 调用 create
方法。这有效地解决了问题。
我相信您的问题是在寻找杰克逊的解决方案,而不是新的模式/风格。
【讨论】:
感谢您的建议!但是,由于@NonNull,这不起作用。我得到NPE。 "java.lang.NullPointerException: schoolId 被标记为@NonNull 但为空 @SyncMaster 那一定是因为你的 JSON。schoolId
在您的 json 中是 null 还是缺失(或具有不同的字段名称)?你能展示一个你的 json 内容的例子吗?以上是关于如何为类重载输出函数?的主要内容,如果未能解决你的问题,请参考以下文章