简体   繁体   中英

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()? If you do, do you also do hashcode()? toString()? Do you make it a habit to implement the Comparable interface?

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

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?

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.

Also, make sure to use your IDE or something like Apache commons to generate these functions. 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). I am afraid of implicit converts and never use toString when generating output.

(Almost) Always toString() .

It is usually helpful for debugging purposes.

If you override equals , you (almost always) have to override hashCode . hashCode 's contract is that two objects that are equals must have the same hash code. 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.

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.

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?"

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.

Almost always toString(), it's a pain to be debugging and read something about object Class@123456

equals() and hashCode() when needed, but always both or neither.

The Iterable interface is useful on collection-like classes, and will usually just return something like 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)

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

I also found myself overriding the ToString() method a lot. 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

Usage:

string testMember = "testing";

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

Writes ' string testMember="testing" ' to the Console. 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

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.

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.

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

For business CRUD applications, I always override ToString. This helps when binding a List(Of T) to a WinForm control. 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. Comes in handy.

I usually implement the compareTo method as well as the toString method. 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. 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. 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. 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. 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.

For data value classes I have an AbstractPojo class which uses reflection to implement equals, hashCode, toString and asMap()

I extend this class for all my data value objects so I don't implement this each time.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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