繁体   English   中英

您(几乎)总是在类中实现哪些方法和接口?

[英]What methods and interfaces do you (almost) always implement in classes?

您始终在类中实现哪些方法和接口?

您是否总是重写equals()? 如果这样做,您还会做hashcode()吗? toString()? 您是否养成了实施Comparable接口的习惯?

我刚刚编写了一些代码,在其中我需要实现compareTo()和重写equals(),以使我的程序以理智的方式工作; 我现在开始看到在任何地方使用这些方法的方式...

你们怎么想?

除非需要,否则我通常不会提前实施。

如果我的类包含数据成员,并且我计划将其存储在某个位置,则通常将实现equals,hashCode和同类对象。

但是,我发现我的大多数班级都没有这个问题,因此没有必要这样做。 例如,如果您的课程围绕其他对象而不是数据的功能展开,为什么要麻烦呢? 如果您有一个实例或按层次结构组织(例如,GUI小部件或窗口),为什么要打扰?

不要实现不需要的东西,但是请务必确保检查是否需要它们,因为Java通常不会警告您。

另外,请确保使用您的IDE或类似Apache commons的东西来生成这些功能。 几乎不需要手动编码它们。

至于toString,我很少实现它,直到发现自己需要调试并且需要在Eclipse调试器中进行更好的展示(例如,代替对象ID)。 我担心隐式转换,并且在生成输出时从不使用toString。

(几乎)总是toString()

通常对于调试目的很有帮助。

如果重写equals ,则(几乎总是)必须重写hashCode hashCode的约定是,两个相等的对象必须具有相同的哈希码。 如果您覆盖equals,使得equals基于除系统标识哈希码之外的其他内容,则两个对象可能彼此相等,但具有不同的哈希码。

我认为您永远都不要实现不需要的东西,或者不确定是否需要它们。 如果它不能为您的代码增加价值,请不要使用它。如果您想使您的(单元)测试与您的代码保持同步,并使用它们显示您的代码用例,那么您不应有那些测试未涵盖的内容。 这包括equals(),hashCode(),compareTo()等。

除了可能浪费时间外,我看到的问题是它会使读取代码的人感到困惑。 “为什么要实现该类的equals?它有一些数据值吗?可以作为集合的一部分吗?比较此类的实例是否有意义?”

因此,我想说的是只有在您真正需要它们时才实施它们。 因此,我不能说我总是实现这种方法。 也许toString()将是我编写最多的方法,因为它在调试中很有用。

几乎总是toString(),调试和阅读有关对象Class @ 123456的内容很痛苦

必要时可以返回equals()和hashCode(),但必须两者都选或都不选。

Iterable接口在类似于集合的类上很有用,并且通常只会返回诸如innerCollection.iterator()之类的东西。 可比性也可能有用。

此外,我们公司还创建了一些我经常使用的接口,例如Displayable(例如toString,但提供了更多或其他类型的信息,例如用于日志记录)和ParseLocatable(用于来自我们解析的文件的内容,我们希望在其中查看例如,哪个文件和哪一行定义了特定规则(有点类似于stacktraces)

有效的Java一章介绍了如何以及何时实现toString,equals,hashCode,Comparable等。强烈建议阅读。

我还发现自己大量重写了ToString()方法。 特别是在开发过程中。 尽管代码生成器有帮助,但是每次重命名类成员时都必须更改它,这很烦人。 其实我很生气,我试图找到一种补救办法,这就是我想出的:

创建此格式的字符串:MemberType MemberName = MemberValue

用法:

string testMember = "testing";

Console.WriteLine(Member.State(() => testMember));

将'string testMember =“ testing”'写入控制台。 这里是:

public static class Member
{
    public static string State<T>(Func<T> expr)
    {
        var member = ExtractMemberFromLambdaExpression(expr);

        Type memberType = GetTypeOfMember(member);

        string contents = ExtractContentsFromLambdaExpression(expr);

        return string.Format("{0} {1}={2}",memberType.Name,  member.Name, contents);
    }

    static string ExtractContentsFromLambdaExpression<T>(Func<T> expr)
    {
        if (expr() == null) {
            return "NULL";
        }

        string contents = string.Empty;
        if (expr().GetType().IsArray) {
            foreach (var item in (expr() as Array)) {
                contents += item.ToStringNullSafe() + ", ";
            }
            contents = contents.Trim().TrimEnd(',');
        } else {
            contents = expr().ToString();
        }

        return contents;
    }

    static MemberInfo ExtractMemberFromLambdaExpression<T>(Func<T> expr)
    {
        // get IL code behind the delegate
        var il = expr.Method.GetMethodBody().GetILAsByteArray();
        // bytes 2-6 represent the member handle
        var memberHandle = BitConverter.ToInt32(il, 2);
        // resolve the handle
        return expr.Target.GetType().Module.ResolveMember(memberHandle);
    }


    static Type GetTypeOfMember(MemberInfo member)
    {
        Type memberType;
        if (member.MemberType == MemberTypes.Field) {
            memberType = GetFieldType(member as FieldInfo);
        }
        else if (member.MemberType == MemberTypes.Property) {
            memberType = GetPropertyType(member as PropertyInfo);
        }
        else {
            memberType = typeof(object);
        }
        return memberType;
    }

    static Type GetFieldType(FieldInfo fieldInfo)
    {
        return fieldInfo.FieldType;
    }

    static Type GetPropertyType(PropertyInfo propertyInfo)
    {
        return propertyInfo.PropertyType;
    }
}

在我的博客中可以找到关于以下内容的更全面的解释以及如何使用它: Generic ToString()方法

当您懒于编写单元测试时, toString()有时对于测试目的确实很有帮助,在调试时也很方便观察

但是我不建议在每个对象中都实现Comparable ,有时候会很好,但是明智地使用它会导致您实际上并不需要很多代码。

同理toString()及其在不同语言和运行时中的变体,但我也想向您介绍Ned Batchelder的有关字符串化的文章,该文章不错,很接近我的推理。

对于商业CRUD应用程序,我总是重写ToString。 这有助于将List(Of T)绑定到WinForm控件。 例如,在将List(Of Customer)绑定到ListBox控件时,覆盖Customer对象中的ToString以返回_name会自动显示客户名称值。 派上用场。

我通常实现compareTo方法以及toString方法。 通常,知道该类的一个实例与另一个实例进行排序和搜索的方式比较好。 另外,重写的toString方法也非常适合调试。 您可以看到对您编写的类有意义的类内容(不仅仅是内存位置)。

在主要用于保存数据的对象(“岩石”)上,我发现toString和equals / hashcode契约是无价的。 这是因为岩石通常总是一直传递到集合中或从集合中提取出来,最显着的是Hash(Set / Map)集合,这需要使用equals和hashcode协定,并且如果toString,则很容易在调试器中看到这些对象被实施。 在实现toString时,我总是使用Apache Common的ToStringBuilder类来显示我的所有属性-这样,读取输出就非常容易。 我从不担心“隐式转换”-toString并不用作人类可读的字符串,toString可以用于Number子类以进行来回转换,实际上只是一个怪癖,等等。生产代码应该永远不要依赖toString方法将对象转换为字符串表示形式,因为这不是它的用途-它是用于人类可读的字符串表示形式,因此,如果非人类的但计算机代码可用的字符串表示形式应定义为另一种方法想要的。

对于数据值类,我有一个AbstractPojo类,该类使用反射来实现equals,hashCode,toString和asMap()

我为所有我的数据值对象扩展了此类,因此不必每次都实现。

我没有覆盖ToString,但是有时我会应用DebuggerDisplay属性,该属性出于调试目的而相同,并且不会在发行版上增加开销。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM