[Java] Waarom geen generics in Swing?

Pagina: 1
Acties:

  • Robtimus
  • Registratie: November 2002
  • Laatst online: 19:51

Robtimus

me Robtimus no like you

Topicstarter
Ik ben eindelijk eens echt begonnen met Java 5, en dus ook generics (op het werk zitten we nog op 1.4 en dat blijft ook nog wel even zo).

Nu heb ik generics al snel door gekregen, maar bij het omzetten van wat oude code merkte ik iets op: er zitten geen generics in Swing of AWT.

Ok, voor sommige components is het (vrijwel) onmogelijk, zoals een JTable waar elke kolom van een andere class kan zijn. Maar ik heb toch al snel wat components kunnen vinden die weinig problemen zouden mogen hebben als ze generics zouden gebruiken.

JList
Een JList kan bevat objecten, via zijn ListModel. Dit kan dus prima generic gemaakt worden:
JList<E>
ListModel<E> - het type moet exact gelijk zijn want de JList get en set waarden van zijn model. Voor get moet het model subclasses van E hebben, voor set superclasses.
ListCellRenderer<? extends E>

JComboBox
Een JComboBox lijkt heel veel op een JList (ComboBoxModel is zelfs een subinterface van ListModel), dus ook hier:
JComboBox<E>
ComboBoxModel<E>
ListCellRenderer<? extends E>


Verder kun je zoiets ook doen met een JTabbedPane<T extends Component>, en in een wat complexere manier met JTree. Maar nu vraag ik me af waarom Sun dit niet gedaan heeft? Ze hebben generics in het collection framework intensief doorgevoerd om invalide class casts op compile niveau af te vangen, en vervolgens laten ze in de user interface packages de gebruiker alsnog aan zijn lot over waar dit niet overal nodig zou zijn.

Iemand een idee?

More than meets the eye
There is no I in TEAM... but there is ME
system specs


  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Ik denk dat backwards-compatibility hier de reden voor is.

Nu met Land Rover Series 3 en Defender 90


  • Robtimus
  • Registratie: November 2002
  • Laatst online: 19:51

Robtimus

me Robtimus no like you

Topicstarter
Daar heb ik wel over gedacht, maar waarom is dat bij het collections framework geen probleem dan? Hoewel ik nu net even snel de belangrijkste packages heb doorgekeken, en generics worden eigenlijk (vrijwel) alleen maar gebruikt in java.lang en java.util.

Ik krijg bijna het idee dat ze er verder geen zin in hebben gehad, want er zijn volgens mij toch echt wel genoeg classes / methods die hiervoor in aanmerking komen.

More than meets the eye
There is no I in TEAM... but there is ME
system specs


Verwijderd

Mijns inziens omdat Swing daar weinig baat bij heeft. Generics lenen zich namelijk perfect voor maps, lists en dies meer om aan te duiden wat zo'n datastructuur nu precies bevat. 'List foo;' is onduidelijk, 'List<Integer> foo' dan weer niet. Echter, een 'JTextField bar' behoeft geen verdere uitleg, omdat deze een vaste property 'text' heeft met een String waarde. Je haalt zelf het voorbeeld van een JTable al aan; waar renderers geconfigureerd worden door de getColumnClass() van het backing TableModel. Idem zo met de renderer van een JList, dat is ook een standaard property ('cellRenderer') van JList sinds het begin van Swing. Bovendien kunnen deze properties eenvoudig at runtime aangepast worden (wel even op de EDT!) naar alles wat je hartje belieft.

Swing haalt zijn kracht uit generieke componenten die door een pluggable model en renderers en desnoods een overridden paintComponent() eender wat kunnen weergeven. Een JComboBox is een JComboBox met een redelijk rigide featureset. Met diezelfde JComboBox kan je echter een BookComboBoxModel, TorrentComboModel of wat dan ook modelleren in een drop-downlist. Elk van deze modellen kan ook een oneindig aantal bijpassende renderers hebben. De JComboBox blijft echter hetzelfde.

Nu kan je aanhalen: ja, maar dat is toch net zo met een List, een List is een List, en met generics geef je aan wat erin zit. Klopt, maar die generics hebben tot doel de inhoud te beperken tot een welbepaalde hiërachie van classes. Enkel Doubles, enkel AttributedStrings, etc. Dit gaat niet op voor een JComboBox. In de property van het model mag reeds énkel een object dat ComboBoxModel implementeert geset worden. Idem zo voor de renderer die de ListCellRenderer interface moet implementeren. Een JComboBox is dus met andere woorden reeds een soort JComboBox<ListCellRenderer R, ComboBoxModel M>.

Trouwens, als je al een JList<MyObject> zou kunnen definiëren, wat dus eigenlijk impliceert dat het model en/of de renderer iets met MyObject te maken moeten hebben, dan zou je de Swing API doorbreken. Zoals eerder aangehaald is het model een property van de JList die aangepast mag worden met eender welk object dat aan de interface van een ListModel voldoet. Wat denk je dat setModel() nu moet doen met een JList<MyObject> ? Een exception throwen ? Swing definiëert reeds de minimale set van methodes die gebruikt zullen worden in de interface van het model. Idem zo met een renderer. Een geldige renderer moet slechts aan één simpele methode voldoen: getCellRendererComponent(). Hoe die CellRenderer geïmplementeerd is doet er niet toe. Wat het kan weergeven ook niet. Het mag een object zijn dat door containment eender welk ander object mag doorsturen. Het mag ook een 'MyObjectJLabel' zijn dat zichzelf doorgeeft. Ok, de 'Object value' parameter zou misschien geparameteriseerd kunnen worden, maar dan zou héél veel kode breken. Ik heb al meer dan eens een generieke renderer geschreven die speciale dingen kan met objecten waar ie voor geschreven was, maar niet onder de indruk was van zaken die ie niet kende en desnoods met een toString() toch nog probeerde weer te geven.

De componenten van Swing zijn slechts dat: componenten. De echte waarde zit in het model en de renderer, die door het component reeds met een vaste interface worden gequeried/gestuurd. Complexe componenten als een JTable of een JTree bevatten op zich weinig logica, alles wordt naar een implementatie van hun respectievelijke interface gedelegeerd. De TableModel interface is op zich goed genoeg om gegevens uit een databank, xml file, of wat dan ook te halen, daar heeft de JTable op zich geen zaakjes mee, en een JTable<PostgreSQLBackedModelOpPoort9876> zou zondigen tegen het Model-Delegate principe van Swing.

Ik blijf er maar op hameren: de interfaces die door de Swing componenten worden gebruikt liggen al vast, en Generics introduceren zal reeds bestaande componenten niet magisch meer (user-defined) methodes laten aanroepen in de respectievelijke modellen en renderer, en dus ook niet zorgen voor meer type-safety, hét punt van generics bij Collections.

De opmerking over backwards compatiblity gaat trouwens niet op, door de beruchte type erasure die de JCP gekozen heeft voor de generics-implementatie van Java 5.