Wat is Reflectie?
Reflectie is een API die ondersteuning biedt voor het creëren van een instantie van de gewenste klasse via een object van het type Class dat is geladen in het heap-gebied, en voor het toegang krijgen tot de velden en methoden van de instantie, ongeacht de toegangsmodifier.
Hierbij verwijst 'geladen klasse' naar het feit dat de JVM Class Loader het laden van het klassebestand heeft voltooid en vervolgens een object van het type Classheeft aangemaakt dat de informatie van die klasse bevat en opgeslagen in het heap-gebied van het geheugen. Let op dat dit anders is dan het object dat wordt aangemaakt met het trefwoord new. Als u de informatie over het object van het type Class niet goed begrijpt, raadpleeg dan de JDK-documentatie van java.lang.class.
Gebruik
Voordat u reflectie kunt gebruiken, moet u het object van het type Class ophalen dat in het heap-gebied is geladen. Er zijn drie manieren om dit te doen.
- Ophalen via Klasse.class
- Ophalen via Instantie.getClass()
- Ophalen via Class.forName("Naam van de klasse")
U kunt zien dat de drie objecten van het type Class die met de drie methoden zijn opgehaald, allemaal hetzelfde zijn. Ongeacht welke methode u gebruikt, de hashwaarde is hetzelfde, dus u kunt deze naar behoefte gebruiken.
Nu we het object van het type Class hebben opgehaald, kunnen we een instantie van die klasse maken en toegang krijgen tot de velden en methoden van die instantie, ongeacht de toegangsmodifier. Laten we eerst een instantie van die klasse maken.
Met getConstructor() kunt u de constructor ophalen en met newInstance() kunt u dynamisch een Member-instantie maken.
Ten slotte zullen we toegang krijgen tot de velden en methoden van de instantie, ongeacht de toegangsmodifier, en deze gebruiken.
Met getDeclaredFileds() kunt u alle instantievariabele van de klasse ophalen, met get() kunt u de waarde van het veld teruggeven en met set() kunt u de waarde van het veld wijzigen. Let op dat wanneer u toegang krijgt tot een veld met de private toegangsmodifier, u setAccessible() met true moet doorgeven als argument.
U kunt ook methoden ophalen met getDeclaredMethod(). Hierbij moet u de naam van de methode en het type van de parameter als argumenten doorgeven. Ook hier moet u setAccessible() met true instellen als argument wanneer u toegang krijgt tot een methode met de private toegangsmodifier. Ten slotte kunt u de methode die u met de reflectie-API hebt opgehaald, aanroepen met de methode invoke().
Voor- en nadelen
- Voordelen
- Het biedt flexibiliteit om tijdens runtime een instantie van een klasse te maken en toegang te krijgen tot velden en methoden, ongeacht de toegangsmodifier, om de gewenste taken uit te voeren.
- Nadelen
- Het ondermijnt inkapseling.
- Omdat de instantie tijdens runtime wordt gemaakt, kan het type niet worden gecontroleerd tijdens compiletijd.
- Omdat de instantie tijdens runtime wordt gemaakt, is het moeilijk om de specifieke workflow te begrijpen.
- Het is langzamer om toegang te krijgen tot velden en methoden via reflectie dan rechtstreeks. (Dit geldt niet voor alle situaties.)
Redenen voor gebruik
Met behulp van de reflectie-API kunt u tijdens runtime toegang krijgen tot klasse-informatie en de klasse aanpassen zoals u wilt. U kunt zelfs velden en methoden die zijn gedeclareerd met de private toegangsmodifier manipuleren. Omdat inkapseling een belangrijk aspect is van objectgeoriënteerd ontwerp, lijkt het misschien alsof deze technologie niet mag worden gebruikt.
Bij kleine consoleprojecten kan de ontwikkelaar tijdens compiletijd alle objecten en afhankelijkheden die in het programma worden gebruikt, volledig identificeren. Maar bij grote projecten zoals frameworks is het moeilijk om een groot aantal objecten en afhankelijkheden te identificeren. Reflectie kan dan worden gebruikt om dynamisch klassen te maken en relaties tussen deze klassen te creëren.
Neem bijvoorbeeld de Bean Factory van Spring. Als u alleen maar annotaties zoals @Controller, @Service en @Repository gebruikt, kan de Bean Factory automatisch de klassen met die annotaties maken en beheren. Hoewel de ontwikkelaar de klasse nooit aan de Bean Factory heeft meegedeeld, is dit mogelijk dankzij reflectie. Tijdens runtime zoekt en vindt de Bean Factory de klassen met die annotaties. Vervolgens maakt de Bean Factory met behulp van reflectie een instantie van die klasse aan, voegt de benodigde velden toe en slaat deze op in de Bean Factory.
Natuurlijk, zoals hierboven vermeld, ondermijnt het inkapseling, dus het is het beste om het alleen te gebruiken wanneer het echt nodig is.
Reacties0