1. Java / Говнокод #8015

    +73

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    static class CheckBoxCellRenderer extends JCheckBox implements ListCellRenderer {
    
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            if (value instanceof CheckBoxListElement) {
                CheckBoxListElement cblel = (CheckBoxListElement) value;
                if (isSelected) {
                    setBackground(list.getSelectionBackground());
                    setForeground(list.getSelectionForeground());
                }
                else {
                    setBackground(list.getBackground());
                    setForeground(list.getForeground());
                }
                setSelected(cblel.isSelected());
                setText(cblel.getText());
                return this;
            }
            else {
                throw new RuntimeException();
            }
        }
            
    }

    Модель просто не должна быть другой...

    Запостил: dwinner, 28 Сентября 2011

    Комментарии (43) RSS

    • > setBackground(list.getSelectionBackgroun d());
      >setForeground(list.getSelectionForegrou nd());
      Всё это решается путём вызова нативного метода setBackgroundToBackgroundFromColorToSame Color(list);
      Ответить
    • > static class
      он еще и вложенный
      Ответить
      • Я твой класс вкладывал!
        Ответить
      • Разве "static class" говорит о том, что класс вложенный?
        Ответить
        • угу, этот модификатор допустим только для вложенных классов.
          Ответить
    • не считаю это ГК. Как верно было подмечено, класс вложенный да еще и не публичный. Скорее всего все это используется в одном месте с определенными входными параметрами и не расчитано на работу с чем либо еще. И что тут плохого?

      Я бы даже instanceof в такой ситуации не делал, сразу бы кастил.
      Ответить
      • Я так подозреваю, что это что-то из SWing... Но была ли причина по которой нальзя было, чтобы getListCellRendererComponent сразу устанавливала тип параметра как CheckBoxListElement? Зачем исключения во врема выполнения, если таким образом их можно было бы найти во время компиляции?

        Еще интересно было бы увидеть как Java компилятор разобрался бы с неожиданным return.
        Ответить
        • > чтобы getListCellRendererComponent сразу устанавливала тип параметра как CheckBoxListElement
          Если там написать другой тип, то код не скомпилится, т.к. класс не будет реализовывать интерфейс ListCellRenderer, метод интерфейса будет перегружен, но не определён.

          > как Java компилятор разобрался бы с неожиданным return
          и что в нём такого неожиданного? вы вздрогнули?
          Ответить
          • А разве более узкоспециальный метод не считается реализацией? Я не знаю, поэтому спрашиваю, но как на мой взгляд, это глупо, если не считается... опять получили статическую типизацию, которая ничего не типизирует :)

            Неожиданный потому, что функция формально должна вернуть значение в конце. Но если ее дословно переписать в байткод, то в конце получется недосягаемый участок с return <и тут не понятно что>. Т.е. компилятору нужно будет сообразить, что return, который написал программист не нужен, и его нужно выбросить, и точно такой же вставить вместо мертвого кода вконце.
            Ответить
            • > более узкоспециальный метод не считается реализацией
              нет, очень многие наступают на грабли, реализуя equals(MyClass) вместо equals(Object)

              > функция формально должна вернуть значение в конце
              функция может вернуть значение когда угодно. Никаких недосягаемых участков кода я не вижу.
              Ответить
            • > более узкоспециальный метод не считается реализацией
              Попробуйте оценить сами абсурдность обратного поведения. Тот, кто вызывает метод интерфейса, ожидает, что интерфейс будет работать с каким-то более общим типом к примеру, Object. Узкоспециализированный метод не может служить реализацией, ибо он нарушает контракт.
              Ответить
          • Т.е. даже если все так плохо, как вы говорите, ну можно ж было наверное сделать JCheckBox<T>, и когда нужно какой-то конкретный тип чекбокса, то и <T>getListCellRendererComponent(JList list, T value, ...).
            Ответить
            • Эта библиотека появилась ещё в java 1.2, тогда о дженериках и речи не было. Переписывать почему-то не стали.
              Ответить
              • Недосягаемый участок получится потому что после if должен быть jump куда-то дальше, а перед jump будет return. Т.о. это проблема для валидатора байткода, конечно она разрешима, но зачем ее создавать, если можно было не создавать? Компилятор, наверное поменяет ветки местами в итоге, хотя это не оптимально... Если уж следовать логике автора, то if не нужен вообще, нужно было просто каст, и продолжать, та же ошибка была бы.

                А перегружать методы с какой версии можно было?
                public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { throw Whatever(); }
                public Component getListCellRendererComponent(JList list, CheckBoxListElement value, int index, boolean isSelected, boolean cellHasFocus) { . . . }

                все-таки лучше было бы.
                Ответить
                • Выбор наиболее подходящей функции среди перегруженных происходит на этапе компиляции. Поскольку это некий callback, вызывающая сторона будет обращаться к первому методу. С печальными последствиями.
                  Ответить
                  • А что, компилятор не будет искать вариант с наиболее подходящими параметрами? Смысл тогда в такой перегрузке? Даже не знаю, не испытывая никаких особых сентиментов к C# - там это тривиальная задача...
                    Ответить
                    • Я же написал, что будет. Проблема в том, что вызывать этот код будет стандартный компонент Swing и вызывать он будет полиморфный метод
                      public Component getListCellRendererComponent(JList list, Object value...
                      , а не его перегруженную версию.
                      Ответить
                      • Вы только что сказали "или да или нет или одно из двух". Так будет искать или не будет?
                        getListCellRendererComponent(someList, new CheckBoxListElement(), ...);
                        Компилятор сгенерирует код, который вызовет
                        getListCellRendererComponent(JList list, Object value, ...);
                        Если да, то в чем смысл перегрузки?
                        Ответить
                        • Фуф... Спокойствие...
                          Идея в том, что CheckBoxCellRenderer будет передаваться в качестве отрисовщика элементов списка стандартному компоненту Swing. При этом для стандартного компонента Swing этот отрисовщик будет представляться как реализация интерфейса ListCellRenderer, у которого есть только один полиморфный метод getListCellRendererComponent(JList, Object...). Поэтому о поиске наиболее подходящей функции речь тут даже не идёт. Перегрузка в Java работает примерно так же, как она работает в C# и С++.
                          Ответить
                          • Очевидно, что не так же работает... В C# если объект типа A, при том, что A наследует B и реализует C, сколько угодно раз назовите его B или C, при наличии метода принимающего A, даже если будут соответствующие для B и C, будет вызван именно тот, который для А. А то, как вы описываете это в Java - это просто бесполезно... Это не полиморфизм никакой, и сколько функцию полиморфной не называйте, во рту слаще не станет :)
                            Ответить
                            • > A наследует B и реализует C
                              > при наличии метода принимающего A
                              в том то и суть, что метод принимает не A, а интерфейс С. Об A он и знать не знает. И вызываться будут методы C, а не перегруженные методы A.
                              Ответить
                              • В C# какой метод вызывать определяется исходя из RTTI и такой ситуации как ту, что вы описываете быть не может. Т.е. в любом случае будет вызван самый специфичный метод - абсолютно не важно какие другие методы у каких его прарадителей или интерфейсов имелись и в какой последовательности объявлялись. Последовательность будет только важна если есть несколько методов одинаково подходящих (например вызов, когда все аргументы - null). Но это не принципиально сейчас. С другой стороны в C# можно просто переписать у наследника метод родителя, так что даже потребности решать такую задачу не бозникло бы.
                                Ответить
                                • Не знаю как в C#, но во многих языках со статической типизацией есть разница между overload и override.
                                  Ответить
                                  • По поводу override vs overload:
                                    http://pastebin.com/zB4HjmkT
                                    Мне такой подход видится логичным. Если в Java это не так... то можно только руками развести.
                                    Ответить
                                    • Use online compillers, Luke!
                                      http://ideone.com/TbuuO
                                      Ответить
                                    • Какое отношение эта простыня вообще имеет к теме разговора? У методов даже параметров нет!
                                      Ответить
                              • Кажется мне, или это тот самый рецезент?
                                Наверное, он не понимает зачем и как были придуманы интерфейсы
                                Ответить
                            • Какой-то бред несёте.
                              Ответить
                              • положите бред где взяли, не несите его больше
                                Ответить
                        • Никто не вызывает getListCellRendererComponent(someList, new CheckBoxListElement(), ...), вызывается getListCellRendererComponent(someList, someValue, ...) у интерфейса. Просто мы уверены, что в этом случае someValue будет CheckBoxListElement (потому, что мы сами его так установили чуть раньше).
                          Ответить
                          • Не вызываются методы у интерфейсов, вы о чем вообще, где вы такое видели? Их как бы и нет у интерфейсов, только объявления... Даже в Java так плохо быть не может. Методы вызываются у объекта, те, которые имеются. Если есть больше одного, то вызывается самый подходящий. В этом и назначение перегрузки. А вот то, как вы это описываете - это да, идиотизм. Но я не удивлюсь, если оно в Java именно так, как вы описываете. Там обычно круглое носят, а квадратное катают.
                            Ответить
                            • Вы, похоже, не понимаете, как устроено ООП в статически-типизированных языках.
                              Ответить
                              • У меня тоже возникло такое ощущение. Наверное, ECMAScript всё же неотвратимо травмирует мозг...
                                Ответить
                              • При чем здесь ООП? Вы элементарно не понимаете, что у интефейса нет методов, и несете чушь про то, как эти несуществующие методы кто-то вызывает.
                                Ответить
                                • Этарак
                                  Ответить
                                • А что, по-вашему, есть у интерфейсов? Зачем они вообще нужны?
                                  Ответить
                                  • Задница универсальный интерфейс. Через неё можно делать множество вещей.
                                    Ответить
    • Не, ну явно перемудрили в комментах... А если вспомнить KISS?! ХЗ, я бы так сделал вообще:
      CheckBoxListElement - явно какой-то user class, что-то там инкапсулирует и используется тут как модель.
      RuntimeException "бросать" - явно плохой стиль, лучше убрать extends JCheckBox и сделать JToggleButton в виде
      композитного объекта, а экстендить DefaultListCellRenderer, тогда логично в else-ветке просто написать:
      return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus) и голову себе не ломать...
      Ответить
      • Зачем, если в ветку else просто никогда не попадём? В принципе, там достаточно было бы даже assert-а.

        Если JCheckBox не наследовать в этом классе, всё равно скорее всего придётся наследовать в ещё одном внутреннем, чтобы переопределить некоторые методы. И ничему это не поможет, класс и так внутренний и скрытый.
        Ответить
    • показать все, что скрытоvanished
      Ответить

    Добавить комментарий