mboost-dp1
Java: Constrained Generics?
- Forside
- ⟨
- Forum
- ⟨
- Programmering
Jeg har et spørgsmål som jeg håber arne eller andre herinde har et kvalificeret syn på:
Lad os lege at jeg har en superklasse og en håndfuld interfaces.
Eksempel:
Abstrakt superklasse: Citizen
Der vil opstå en masse subklasser der vil extende Citizen og implementerer forskellige interfaces.
Eksempler på interfaces:
Handy
Sporty
Emotional
Philosophical
Athletic
Lazy
Scientific
Organic
Political
(find selv på flere adjektiver der beskriver personlige egenskaber)
Ovenstående interfaces kan indeholde metoder, det kunne også være marker interfaces. That's besides the point. Dette er her ikke en diskussion om hvorvidt de skal være fields i en generel klasse.
Her kommer spørgsmålet. Så vidt jeg kan se kan jeg kun lave instanser af generiske klasser med faktiske eksisterende klasser eller interfaces.
Eksempelvis:
List<Lazy>
En liste med dovne personer. Hvis jeg forsøger at tilføje en politisk person, så vil compileren klage. Hvis ikke compileren fanger det, så vil jeg få en ClassCastException ved runtime.
Anyway:
Hvis jeg nu vil lave en liste med fokl som er følsomme, økologiske og politiske, så er jeg nødt til at lave et interface. Eksempelvis:
public interface Hippie implements emotional, organic, political
Så kan jeg skrive List<Hippie> og få en liste som kun tillader subklasser af Object som implementerer disse tre interfaces. Det er dog ikke nok at de implementerer dem, de skal også eksplicit implementerer Hippie interfacet.
Det vil sige at:
public class someKindOfPerson extends Citizen implements emotional, organic, political, andAnotherInterface ikke vil passe i listen - og ikke vil overleve en eksplicit cast.
Frem til spørgsmålet:
Jeg kunne godt tænke mig hvis sproget gav mig lov at skrive:
List<Citizen implements Scientific>
Med andre ord: Listen er åben for enhver subklasse af citizen som implementerer scientific, uanset hvem det måtte være. Og jeg vil have adgang til at kalde metoder som er defineret i Citizen og i Scientific.
Nogle der kan bidrage med noget perspektiv på:
1) Hvorfor dette ikke kan lade sig gøre?
- logisk begrænsning?
- sproglig begrænsning?
2) Hvorfor jeg får ClassCastException når jeg forsøger eksplicit at caste en klasse som implementerer alle nødvendige superinterfaces for at kvalificere sig til et subinterface (dog uden eksplicit at erklære dette subinterface i koden) til dette subinterface - eksempel: En klasse som har alt hvad en Hippie kræver, men alligevel ikke kan castes til Hippie fordi den ikke eksplicit implementerer Hippie ?
Lad os lege at jeg har en superklasse og en håndfuld interfaces.
Eksempel:
Abstrakt superklasse: Citizen
Der vil opstå en masse subklasser der vil extende Citizen og implementerer forskellige interfaces.
Eksempler på interfaces:
Handy
Sporty
Emotional
Philosophical
Athletic
Lazy
Scientific
Organic
Political
(find selv på flere adjektiver der beskriver personlige egenskaber)
Ovenstående interfaces kan indeholde metoder, det kunne også være marker interfaces. That's besides the point. Dette er her ikke en diskussion om hvorvidt de skal være fields i en generel klasse.
Her kommer spørgsmålet. Så vidt jeg kan se kan jeg kun lave instanser af generiske klasser med faktiske eksisterende klasser eller interfaces.
Eksempelvis:
List<Lazy>
En liste med dovne personer. Hvis jeg forsøger at tilføje en politisk person, så vil compileren klage. Hvis ikke compileren fanger det, så vil jeg få en ClassCastException ved runtime.
Anyway:
Hvis jeg nu vil lave en liste med fokl som er følsomme, økologiske og politiske, så er jeg nødt til at lave et interface. Eksempelvis:
public interface Hippie implements emotional, organic, political
Så kan jeg skrive List<Hippie> og få en liste som kun tillader subklasser af Object som implementerer disse tre interfaces. Det er dog ikke nok at de implementerer dem, de skal også eksplicit implementerer Hippie interfacet.
Det vil sige at:
public class someKindOfPerson extends Citizen implements emotional, organic, political, andAnotherInterface ikke vil passe i listen - og ikke vil overleve en eksplicit cast.
Frem til spørgsmålet:
Jeg kunne godt tænke mig hvis sproget gav mig lov at skrive:
List<Citizen implements Scientific>
Med andre ord: Listen er åben for enhver subklasse af citizen som implementerer scientific, uanset hvem det måtte være. Og jeg vil have adgang til at kalde metoder som er defineret i Citizen og i Scientific.
Nogle der kan bidrage med noget perspektiv på:
1) Hvorfor dette ikke kan lade sig gøre?
- logisk begrænsning?
- sproglig begrænsning?
2) Hvorfor jeg får ClassCastException når jeg forsøger eksplicit at caste en klasse som implementerer alle nødvendige superinterfaces for at kvalificere sig til et subinterface (dog uden eksplicit at erklære dette subinterface i koden) til dette subinterface - eksempel: En klasse som har alt hvad en Hippie kræver, men alligevel ikke kan castes til Hippie fordi den ikke eksplicit implementerer Hippie ?
1) Lav din egen liste, måske noget ala:
2) Hvis jeg forstår spørgsmålet korrekt, og i øvrigt husker korrekt:
Fordi tanken bag interfaces er at sikre kontrakterne. Du kan ikke caste på tværs af interfaces, bare fordi du ved at kontrakterne bliver overholdt. Så skulle alle (udviklere) hele tiden holde øje med om kontrakterne nu også blev overholdt, når de lavede noget. Interfaces er netop en garanti, programmørens øjne != en garanti :)
public abstract class ScientificList<C extends Scientific> implements List<C>
2) Hvis jeg forstår spørgsmålet korrekt, og i øvrigt husker korrekt:
Fordi tanken bag interfaces er at sikre kontrakterne. Du kan ikke caste på tværs af interfaces, bare fordi du ved at kontrakterne bliver overholdt. Så skulle alle (udviklere) hele tiden holde øje med om kontrakterne nu også blev overholdt, når de lavede noget. Interfaces er netop en garanti, programmørens øjne != en garanti :)
ISCS, burde compileren ikke kunne lægge to og to sammen?
Hvis:
A = B+C
D = B+C
A = D
No?
Og hvorfor er det at du forslår jeg skriver min egen abstrakte!?! ADT List implementation? Det er ikke et spørgsmål møntet specifikt på List interfacet, men på hvordan generiske typer instantieres. Det jeg kan konstatere er at man kun kan anvende typer der også eksisterer i form af klasser/interfaces.
Man kan, så vidt jeg kan se, ikke blot instantiere en liste som en begrænsning, altså én type + 1 eller flere interfaces.
Hvis:
A = B+C
D = B+C
A = D
No?
Og hvorfor er det at du forslår jeg skriver min egen abstrakte!?! ADT List implementation? Det er ikke et spørgsmål møntet specifikt på List interfacet, men på hvordan generiske typer instantieres. Det jeg kan konstatere er at man kun kan anvende typer der også eksisterer i form af klasser/interfaces.
Man kan, så vidt jeg kan se, ikke blot instantiere en liste som en begrænsning, altså én type + 1 eller flere interfaces.
MadiZone (3) skrev:der også eksisterer i form af klasser/interfaces
Altså der er jo wildcardet også. List<? extends Scientific> list;
MadiZone (3) skrev:ISCS, burde compileren ikke kunne lægge to og to sammen?
Jo. Men et interface er en garanti. Hvad nu hvis D var defineret på et andet host, på tværs af RMI fx?
Wildcardet begrænser kun hvilke generiske typer som listen kan instantieres med. Jeg vil stadigvæk kun have mulighed for at instantiere den som en CitizenList<Scientific> og få scientific referencer ud - det betyder at jeg ikke kan køre nogle af citizenmetoderne på de objekter der er gemt i listen med mindre jeg eksplicit caster dem til Citizen (hvorefter mine Scientific-metoder forsvinder).
Igen: Det jeg efterlyser er ikke en måde at begrænse hvad en generisk klasse kan instantieres med, men en måde at instantiere en generisk klasse med et udtryk som begrænser listen til de typer som opfylder kriterierne.
Eksempel:
List<Bil implements AirCondition, SpeedPilot, Sunroof>
Denne liste vil således kun tage imod subklasser til biler som implementerer disse tre interfaces. Hvis jeg således forsøger at tilføje en instans af SuzukiAlto (som extender Bil), så vil det fejle, fordi den ikke har soltag.
Igen: Det jeg efterlyser er ikke en måde at begrænse hvad en generisk klasse kan instantieres med, men en måde at instantiere en generisk klasse med et udtryk som begrænser listen til de typer som opfylder kriterierne.
Eksempel:
List<Bil implements AirCondition, SpeedPilot, Sunroof>
Denne liste vil således kun tage imod subklasser til biler som implementerer disse tre interfaces. Hvis jeg således forsøger at tilføje en instans af SuzukiAlto (som extender Bil), så vil det fejle, fordi den ikke har soltag.
MadiZone (6) skrev:
Eksempel:
List<Bil implements AirCondition, SpeedPilot, Sunroof>
Nu fandt jeg lige Eclipse frem. - Og løb ind i samme frustration som dig, med at A+B = C != C ...
Men hvad med at lave din egen liste således:
public class MinListe<B extends Sunroof & SpeedPilot & AirCondition> extends List
Jeg kan se to grunde til at det ikke virker.
1) Praktisk.
Det vil være lidt besværligt for compileren at checke kombination interfacet for om det indeholder ekstra metoder.
2) Principielt.
Generelt er typer i Java ikke ens selvom de indeholder det sammen.
To beans osm indeholder de samme properties er forskellige typer.
To interfaces som indeholder de samme metoder er forskellige typer.
1) Praktisk.
Det vil være lidt besværligt for compileren at checke kombination interfacet for om det indeholder ekstra metoder.
2) Principielt.
Generelt er typer i Java ikke ens selvom de indeholder det sammen.
To beans osm indeholder de samme properties er forskellige typer.
To interfaces som indeholder de samme metoder er forskellige typer.
Gå til top
Opret dig som bruger i dag
Det er gratis, og du binder dig ikke til noget.
Når du er oprettet som bruger, får du adgang til en lang række af sidens andre muligheder, såsom at udforme siden efter eget ønske og deltage i diskussionerne.