如何为类重载输出函数?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何为类重载输出函数?相关的知识,希望对你有一定的参考价值。

比如说有这样一个类
class A

public:
private:
int data;

int main()

A Temp;
cout<<Temp.data<<endl;
return 0;


显然这样是不行的,如果要重载<<的话应该怎么写,才能输出任意一个数据成员?

参考技术A 这样是可以的。本回答被提问者采纳

如何为不可变类创建默认构造函数

【中文标题】如何为不可变类创建默认构造函数【英文标题】: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 内容的例子吗?

以上是关于如何为类重载输出函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何为自定义类重载`float()`?

本周学习小结

运算符重载

如何为从C++中的模板继承的类重载赋值运算符

如何为派生类创建构造函数? [复制]

如何为朋友函数中定义的类授予友谊?