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

时间:2009-04-04 23:04:05

标签: java

您总是在课程中实施哪些方法和界面?

你总是重写equals()吗?如果你这样做,你也做hashcode()吗?的toString()?您是否习惯于实施Comparable接口?

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

你们都在想什么?

14 个答案:

答案 0 :(得分:13)

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

如果我的类包含数据成员并且我打算将其存储在某个地方,我通常会实现equals,hashCode和可比较的。

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

不要实现你不需要的东西,但要始终确保是否需要它们,因为Java通常不会警告你。

此外,请确保使用您的IDE或Apache commons之类的东西来生成这些功能。很少需要手动编码。

至于toString,我很少实现它,直到我发现自己调试并需要在Eclipse调试器中更好的表示(例如,而不是对象ID)。我害怕隐式转换,在生成输出时从不使用toString。

答案 1 :(得分:8)

(差不多)始终toString()

这通常有助于调试目的。

答案 2 :(得分:4)

如果您覆盖equals,则您(几乎总是)必须覆盖hashCodehashCode的契约是两个等于的对象必须具有相同的哈希码。如果重写equals使得相等性基于系统身份哈希码之外的某些东西,那么两个对象可能彼此相等但具有不同的哈希码。

答案 3 :(得分:3)

我认为你永远不应该实施你不需要的东西,或者不确定你是否会需要它们。如果它没有为你的代码增加价值,就不要把它放进去。如果你想让你的(单元)测试与你的代码保持同步,并用它们来显示代码的用例,那你就不应该有任何未被这些测试覆盖的东西。这包括equals(),hashCode(),compareTo()等。

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

所以我说只有在你真正需要它们时才实现它们。因此,我不能说我总是实现这个和那个方法。也许toString()将是我写得最多的方法,因为它在调试中显得很有用。

答案 4 :(得分:2)

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

在需要时使用equals()和hashCode(),但总是两者兼而有之。

Iterable接口在类似集合的类上很有用,通常只返回类似innerCollection.iterator()的东西。可比较也很有用。

另外,我们公司创建了一些我经常使用的接口,比如Displayable(比如toString,但提供更多或其他类型的信息,比如日志记录)和ParseLocatable(对于来自我们解析的文件的东西,我们想要的查看哪个文件以及哪一行例如定义了特定规则(有点像堆栈跟踪)

答案 5 :(得分:2)

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

答案 6 :(得分:0)

当您懒得编写单元测试时,

toString()有时对测试目的非常有帮助,在调试时对观察也很方便。

但是我不建议在每个对象中实现Comparable,有时它很好,但是明智地使用它或者你最终会得到大量你实际上并不需要的代码。

答案 7 :(得分:0)

同上toString()及其在不同语言和运行时的变体,但我也想指出Ned Batchelder关于stringification的文章,这是一本很好的阅读,并且接近我的推理这样做。

答案 8 :(得分:0)

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

答案 9 :(得分:0)

我通常会实施compareTo方法以及toString方法。通常很好知道类的一个实例如何与另一个实例进行排序和搜索。另外一个重写的toString方法非常适合调试。您可以以对您所编写的类有意义的方式查看类的内容(而不仅仅是内存位置)。

答案 10 :(得分:0)

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

答案 11 :(得分:0)

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

我为所有数据值对象扩展了这个类,所以每次都不实现它。

答案 12 :(得分:0)

我没有覆盖ToString,但我有时会应用DebuggerDisplay属性,它为调试目的执行相同操作,并且不会在发布版本上增加开销。

答案 13 :(得分:0)

我也发现自己重写了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() Method