Какие методы и интерфейсы вы (почти) всегда используете в классах? - PullRequest
7 голосов
/ 05 апреля 2009

Какие методы и интерфейсы вы всегда используете в своих классах?

Вы всегда переопределяете equals ()? Если вы делаете, вы также делаете хэш-код ()? нанизывать()? У вас есть привычка внедрять Comparable интерфейс?

Я только что написал некоторый код, в котором мне нужно было реализовать compareTo () и переопределить equals (), чтобы заставить мою программу работать в здравом уме; Теперь я начинаю видеть способы их использования везде ...

Что вы думаете?

Ответы [ 14 ]

13 голосов
/ 05 апреля 2009

Обычно я не реализую вещи заранее, если они мне не нужны.

Если в моем классе содержатся члены с данными, и я планирую где-то их хранить, я обычно использую equals, hashCode и сопоставимые.

Однако я обнаружил, что большинство моих классов не имеют этой проблемы, поэтому нет смысла это делать. Например, если ваш класс вращается вокруг функциональности других объектов, а не данных, зачем беспокоиться? Если у вас есть один экземпляр или он организован иерархически (например, графический виджет или окно), зачем беспокоиться?

Не реализуйте вещи, которые вам не нужны, но всегда проверяйте, нужны ли они или нет, потому что Java обычно не предупредит вас.

Кроме того, обязательно используйте вашу IDE или что-то вроде Apache Commons для генерации этих функций. Редко возникает необходимость кодировать их вручную.

Что касается toString, я редко реализую его, пока не обнаружу, что отлаживаю и нуждаюсь в лучшей презентации в отладчике Eclipse (например, вместо ID объекта). Я боюсь неявных преобразований и никогда не использую toString при генерации вывода.

8 голосов
/ 05 апреля 2009

(Почти) Всегда toString().

Обычно это полезно для отладки.

4 голосов
/ 05 апреля 2009

Если вы переопределите equals, вам (почти всегда) придется переопределить hashCode. Контракт hashCode заключается в том, что два равных объекта должны иметь одинаковый хэш-код. Если вы переопределяете equals таким образом, чтобы равенство основывалось на чем-то, кроме хеш-кода системной идентификации, два объекта могут быть равны друг другу, но иметь разные хеш-коды.

3 голосов
/ 05 апреля 2009

Я думаю, что вы никогда не должны реализовывать вещи, которые вам не нужны, или не уверены, что они вам понадобятся или нет. Если это не добавляет ценности вашему коду, не вставляйте его. Если вы хотите синхронизировать свои (модульные) тесты с вашим кодом и использовать их для отображения вариантов использования вашего кода, то вам не следует есть что-нибудь, что не подпадает под эти тесты. Это включает в себя equals (), hashCode (), compareTo () и т. Д.

Проблема, которую я вижу, кроме возможной траты времени, состоит в том, что это может запутать человека, который читает код. «Почему в этом классе реализованы равные? Это какое-то значение данных? Может ли оно быть частью коллекции? Имеет ли смысл сравнивать экземпляры этого класса?»

Так что я бы сказал, реализуйте их только тогда, когда они вам действительно нужны. Поэтому я не могу сказать, что я всегда реализую тот или иной метод. Возможно, метод toString (), который я пишу чаще всего, потому что он очень полезен при отладке.

2 голосов
/ 05 апреля 2009

Эффективная Java содержит главу о том, как и когда реализовывать toString, равно, hashCode, Comparable и т. Д. Настоятельно рекомендуется читать.

2 голосов
/ 05 апреля 2009

Почти всегда toString (), отладка и чтение чего-либо об объекте Class @ 123456

- боль

равно () и hashCode () при необходимости, но всегда оба или ни одного.

Интерфейс Iterable полезен для классов, подобных коллекциям, и обычно просто возвращает что-то вроде innerCollection.iterator (). Сопоставимый может быть полезным.

также наша компания создала несколько интерфейсов, которые я часто использую, например Displayable (например, toString, но предоставляет больше или другой тип информации, например, для ведения журнала) и ParseLocatable (для материала, который получается из файла, который мы анализируем, и мы чтобы увидеть, в каком файле и в какой строке, например, определено определенное правило (немного похоже на трассировку стека)

0 голосов
/ 03 июля 2009

Я также обнаружил, что слишком много переопределяю метод 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;
    }
}

Более подробное объяснение и способы его использования можно найти в моем блоге о: Общий метод ToString ()

0 голосов
/ 06 апреля 2009

Я не переопределяю ToString, но иногда применяю атрибут DebuggerDisplay, который делает то же самое для целей отладки и не накладывает накладных расходов на версию выпуска.

0 голосов
/ 05 апреля 2009

Для классов значений данных у меня есть класс AbstractPojo, который использует отражение для реализации equals, hashCode, toString и asMap ()

Я расширяю этот класс для всех своих объектов значений данных, поэтому я не реализую это каждый раз.

0 голосов
/ 05 апреля 2009

На объектах, которые используются главным образом для хранения данных («камни»), я считаю, что toString и контракт equals / hashcode неоценимы. Это связано с тем, что породы обычно передаются в коллекции и извлекаются из них все время, особенно это касается коллекций Hash (Set / Map), для которых требуется контракт equals и hashcode, и эти объекты очень легко увидеть в отладчике, если toString реализовано. При реализации toString я всегда использую класс ToStringBuilder Apache Common для отображения всех моих свойств - таким образом, очень легко прочитать вывод. Меня никогда не беспокоило «неявное преобразование» - toString не предназначен для использования в качестве чего-либо, кроме удобочитаемой строки, что toString можно использовать на подклассах Number для преобразования в и из, это на самом деле просто причуды и т. Д. Рабочий код должен никогда не полагайтесь на метод toString для преобразования объекта в строковое представление, потому что это не то, для чего он предназначен - он предназначен для удобочитаемого для человека строкового представления, поэтому должен быть определен другой метод, если не человек, но желательно использовать в компьютерном коде строковое представление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...