简体   繁体   English

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

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

Which methods and interfaces do you always implement in your classes? 您始终在类中实现哪些方法和接口?

Do you always override equals()? 您是否总是重写equals()? If you do, do you also do hashcode()? 如果这样做,您还会做hashcode()吗? toString()? toString()? Do you make it a habit to implement the Comparable interface? 您是否养成了实施Comparable接口的习惯?

I've just written some code where I needed to implement compareTo() and override equals() to get my program to work in a sane manner; 我刚刚编写了一些代码,在其中我需要实现compareTo()和重写equals(),以使我的程序以理智的方式工作; I now start seeing ways of using these everywhere... 我现在开始看到在任何地方使用这些方法的方式...

What do y'all think? 你们怎么想?

I usually don't implement things in advance unless I need them. 除非需要,否则我通常不会提前实施。

If my class contains data members and I plan to store it somewhere, I will usually implement equals, hashCode, and comparable. 如果我的类包含数据成员,并且我计划将其存储在某个位置,则通常将实现equals,hashCode和同类对象。

However, I found that most of my classes do not have this issue so there's no point to do it. 但是,我发现我的大多数班级都没有这个问题,因此没有必要这样做。 For example, if your class revolves around functionality on other objects rather than data, why bother? 例如,如果您的课程围绕其他对象而不是数据的功能展开,为什么要麻烦呢? If you have one instance or is organized hierarchically (eg, a GUI widget or window), why bother? 如果您有一个实例或按层次结构组织(例如,GUI小部件或窗口),为什么要打扰?

Don't implement things you don't need, but always make sure to check whether they are needed or not because Java will generally not warn you. 不要实现不需要的东西,但是请务必确保检查是否需要它们,因为Java通常不会警告您。

Also, make sure to use your IDE or something like Apache commons to generate these functions. 另外,请确保使用您的IDE或类似Apache commons的东西来生成这些功能。 There is rarely a need to hand-code them. 几乎不需要手动编码它们。

As for toString, I rarely implement it until I find myself debugging and needing a better presentation in the Eclipse debugger (eg, instead of object ID). 至于toString,我很少实现它,直到发现自己需要调试并且需要在Eclipse调试器中进行更好的展示(例如,代替对象ID)。 I am afraid of implicit converts and never use toString when generating output. 我担心隐式转换,并且在生成输出时从不使用toString。

(Almost) Always toString() . (几乎)总是toString()

It is usually helpful for debugging purposes. 通常对于调试目的很有帮助。

If you override equals , you (almost always) have to override hashCode . 如果重写equals ,则(几乎总是)必须重写hashCode hashCode 's contract is that two objects that are equals must have the same hash code. hashCode的约定是,两个相等的对象必须具有相同的哈希码。 If you override equals such that equality is based on something besides the system identity hash code, the it's possible for two objects to be equal to each other but have different hash code. 如果您覆盖equals,使得equals基于除系统标识哈希码之外的其他内容,则两个对象可能彼此相等,但具有不同的哈希码。

I think you should never implement things you don't need, or are not sure you are going to need them or not. 我认为您永远都不要实现不需要的东西,或者不确定是否需要它们。 If it doesn't add value to your code, don't put it in. If you like to keep your (unit) tests in synch with your code, and use them to show use cases of your code, then you shouldn't have anything that is not covered by those tests. 如果它不能为您的代码增加价值,请不要使用它。如果您想使您的(单元)测试与您的代码保持同步,并使用它们显示您的代码用例,那么您不应有那些测试未涵盖的内容。 This includes equals(), hashCode(), compareTo() etc. 这包括equals(),hashCode(),compareTo()等。

The problem I see, other than a possible waste of time, is that it would confuse someone who reads the code. 除了可能浪费时间外,我看到的问题是它会使读取代码的人感到困惑。 "Why does this class have equals implemented? Is it some data value? Can it be a part of a collection? Does it even make sense to compare instances of this class?" “为什么要实现该类的equals?它有一些数据值吗?可以作为集合的一部分吗?比较此类的实例是否有意义?”

So I'd say only implement these when you actually need them. 因此,我想说的是只有在您真正需要它们时才实施它们。 Therefore I can't say that I always implement this and that method. 因此,我不能说我总是实现这种方法。 Perhaps toString() would be the method that I write the most, because it's usefulness appears a lot in debugging. 也许toString()将是我编写最多的方法,因为它在调试中很有用。

Almost always toString(), it's a pain to be debugging and read something about object Class@123456 几乎总是toString(),调试和阅读有关对象Class @ 123456的内容很痛苦

equals() and hashCode() when needed, but always both or neither. 必要时可以返回equals()和hashCode(),但必须两者都选或都不选。

The Iterable interface is useful on collection-like classes, and will usually just return something like innerCollection.iterator(). Iterable接口在类似于集合的类上很有用,并且通常只会返回诸如innerCollection.iterator()之类的东西。 Comparable can be useful too. 可比性也可能有用。

also, our company created some interfaces I use a lot, like Displayable (like toString, but gives more or another type of info, like for logging) and ParseLocatable (for stuff that comes from a file we parse, and we want to see in which file and on which line where for example a specific rule was defined (a little like stacktraces) 此外,我们公司还创建了一些我经常使用的接口,例如Displayable(例如toString,但提供了更多或其他类型的信息,例如用于日志记录)和ParseLocatable(用于来自我们解析的文件的内容,我们希望在其中查看例如,哪个文件和哪一行定义了特定规则(有点类似于stacktraces)

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

I also found myself overriding the ToString() method a lot. 我还发现自己大量重写了ToString()方法。 Especially during development. 特别是在开发过程中。 Although code generators help, it becomes quite annoying to have to change it every time you rename a class member. 尽管代码生成器有帮助,但是每次重命名类成员时都必须更改它,这很烦人。 Actually I got so annoyed, I tried to find a remedy, This is what I came up with: 其实我很生气,我试图找到一种补救办法,这就是我想出的:

Creates a string of this format: MemberType MemberName=MemberValue 创建此格式的字符串:MemberType MemberName = MemberValue

Usage: 用法:

string testMember = "testing";

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

Writes ' string testMember="testing" ' to the Console. 将'string testMember =“ testing”'写入控制台。 Here it is: 这里是:

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;
    }
}

A more thorough explanation and how to use it can be found on my blog about the: Generic ToString() Method 在我的博客中可以找到关于以下内容的更全面的解释以及如何使用它: Generic ToString()方法

toString() is sometimes really helpful for testing purposes when you're too lazy to write Unit tests, also comes in handy for watches while debugging. 当您懒于编写单元测试时, toString()有时对于测试目的确实很有帮助,在调试时也很方便观察

But I wouldn't recommend to implement Comparable in every object, it's nice sometimes, but use it wise or you'll end up with loads of code that you don't actually need. 但是我不建议在每个对象中都实现Comparable ,有时候会很好,但是明智地使用它会导致您实际上并不需要很多代码。

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

For business CRUD applications, I always override ToString. 对于商业CRUD应用程序,我总是重写ToString。 This helps when binding a List(Of T) to a WinForm control. 这有助于将List(Of T)绑定到WinForm控件。 For example, overriding ToString in a Customer object to return _name will then automatically show the customer name value when binding a List(Of Customer) to a ListBox control. 例如,在将List(Of Customer)绑定到ListBox控件时,覆盖Customer对象中的ToString以返回_name会自动显示客户名称值。 Comes in handy. 派上用场。

I usually implement the compareTo method as well as the toString method. 我通常实现compareTo方法以及toString方法。 Its generally good to know how one instance of the class compares to another instance for sorts and searches. 通常,知道该类的一个实例与另一个实例进行排序和搜索的方式比较好。 Also an overrided toString method is great for debugging. 另外,重写的toString方法也非常适合调试。 You can see the content of the class (not just the memory location) presented in a way that makes sense for the class you have written. 您可以看到对您编写的类有意义的类内容(不仅仅是内存位置)。

On objects that are used primarily for holding data ("rocks"), I find toString and the equals/hashcode contract to be invaluable. 在主要用于保存数据的对象(“岩石”)上,我发现toString和equals / hashcode契约是无价的。 This is because rocks are typically passed into and extracted out of collections all the time, most notably the Hash(Set/Map) collections, which require the equals and hashcode contract, and it is very easy to see these objects in a debugger if toString is implemented. 这是因为岩石通常总是一直传递到集合中或从集合中提取出来,最显着的是Hash(Set / Map)集合,这需要使用equals和hashcode协定,并且如果toString,则很容易在调试器中看到这些对象被实施。 When implementing toString, I always use Apache Common's ToStringBuilder class to display all of my properties - that way it is very easy to read the output. 在实现toString时,我总是使用Apache Common的ToStringBuilder类来显示我的所有属性-这样,读取输出就非常容易。 I am never concerned about "implicit conversion" - toString is not meant to be used as anything but a human readable string, that the toString can be used on Number subclasses to convert to and from is really just a quirk, etc. Production code should never rely on the toString method to convert the object to a string representation, because that's not what it's for - it's for a human readable string representation, so a different method should be defined if a non-human, but computer code useable string representation is desired. 我从不担心“隐式转换”-toString并不用作人类可读的字符串,toString可以用于Number子类以进行来回转换,实际上只是一个怪癖,等等。生产代码应该永远不要依赖toString方法将对象转换为字符串表示形式,因为这不是它的用途-它是用于人类可读的字符串表示形式,因此,如果非人类的但计算机代码可用的字符串表示形式应定义为另一种方法想要的。

For data value classes I have an AbstractPojo class which uses reflection to implement equals, hashCode, toString and asMap() 对于数据值类,我有一个AbstractPojo类,该类使用反射来实现equals,hashCode,toString和asMap()

I extend this class for all my data value objects so I don't implement this each time. 我为所有我的数据值对象扩展了此类,因此不必每次都实现。

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

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

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