Try using it in your preferred language.

English

  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar
translation

Dit is een door AI vertaalde post.

제이온

[Java] Reflectie concept en gebruik

Selecteer taal

  • Nederlands
  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • हिन्दी
  • Magyar

Samengevat door durumis AI

  • Reflectie is een API die toegang tot klasse-informatie tijdens runtime mogelijk maakt, zodat klassen naar wens kunnen worden gemanipuleerd.
  • Met reflectie kunnen instanties van klassen worden gemaakt en velden en methoden worden gebruikt, ongeacht toegangsbeheerders, en het is met name nuttig in grote ontwikkelingsfasen, zoals frameworks, om afhankelijkheden dynamisch te beheren.
  • Het is echter raadzaam om reflectie alleen te gebruiken wanneer dat noodzakelijk is, omdat het inbreuk kan maken op inkapseling en prestatieverlies kan veroorzaken.

Reflectie?

Reflectie is een API die ondersteuning biedt voor het maken van instanties van een gewenste klasse via het Class-type-object dat in de heap-ruimte is geladen, en voor toegang tot de velden en methoden van de instantie, ongeacht de toegangsbeheerders.



Een geladen klasse betekent hier dat de klasselader van de JVM het laden van het klassebestand heeft voltooid en een Class-type-objectheeft gemaakt dat de informatie van die klasse bevat en in de heap-ruimte van het geheugen heeft opgeslagen. Merk op dat dit anders is dan de objecten die worden gemaakt met het nieuwe trefwoord. Als je niet goed begrijpt wat een Class-type-object is, raadpleeg dan de JDK-documentatie voor het java.lang.class-object.


Gebruik

Voordat je reflectie kunt gebruiken, moet je het Class-type-object ophalen dat is geladen in de heap-ruimte. Er zijn in totaal drie manieren.


  • Ophalen met klasse.klasse
  • Ophalen met instantie.getClass()
  • Ophalen met Class.forName("klasse-naam")


public class Member {

    private String name;

    protected int age;

    public String hobby;

    public Member() {
    }

    public Member(String name, int age, String hobby) {
        this.name = name;
        this.age = age;
        this.hobby = hobby;
    }

    public void speak(String message) {
        System.out.println(message);
    }

    private void secret() {
        System.out.println("Het wachtwoord is 1234.");
    }

    @Override
    public String toString() {
        return "Member{" +
            "name='" + name + '\'' +
            ", age=" + age +
            ", hobby='" + hobby + '\'' +
            '}';
    }
}

public class Main {

    public static void main(String[] args) throws ClassNotFoundException {
        Class memberClass = Member.class;
        System.out.println(System.identityHashCode(memberClass));

        Member member = new Member("Jayon", 23, "Dara쓰 development");
        Class memberClass2 = member.getClass();
        System.out.println(System.identityHashCode(memberClass2));

        Class memberClass3 = Class.forName("{package name}.Member");
        System.out.println(System.identityHashCode(memberClass3));
    }
}

// Uitvoer
1740000325
1740000325

Je kunt zien dat de Class-type-instanties die met de drie methoden zijn opgehaald, allemaal hetzelfde zijn. Ongeacht welke methode je gebruikt, de hash-waarde is hetzelfde, dus je kunt deze naar behoefte gebruiken.


Nu kun je met het opgehaalde Class-type instanties van die klasse maken, en kun je toegang krijgen tot de velden en methoden van de instantie, ongeacht de toegangsbeheerders. Laten we eerst instanties van die klasse maken.


public class Main {

    public static void main(String[] args) throws Exception {
        // Alle constructoren van Member afdrukken
        Member member = new Member();
        Class memberClass = member.getClass();
        Arrays.stream(memberClass.getConstructors()).forEach(System.out::println);

        // Instantie maken via de standaardconstructor van Member
        Constructor constructor = memberClass.getConstructor();
        Member member2 = constructor.newInstance();
        System.out.println("member2 = " + member2);

        // Instantie maken via een andere constructor van Member
        Constructor fullConstructor =
            memberClass.getConstructor(String.class, int.class, String.class);
        Member member3 = fullConstructor.newInstance("Jayon", 23, "Dara쓰 development");
        System.out.println("member3 = " + member3);
    }
}

// Uitvoer
public Member()
public Member(java.lang.String,int,java.lang.String)
member2 = Member{name='null', age=0, hobby='null'}

Met getConstructor() kun je de constructor ophalen, en met newInstance() kun je dynamisch Member-instanties maken.

Laten we ten slotte de velden en methoden van de instantie benaderen, ongeacht de toegangsbeheerders.

public class Main {

    public static void main(String[] args) throws Exception {
        Member member = new Member("Jayon", 23, "Dara쓰 development");
        Class memberClass = member.getClass();

        // Toegang tot velden
        Field[] fields = memberClass.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            System.out.println(field.get(member));
        }
        fields[0].set(member, "Jayon2");
        System.out.println(member);

        // Toegang tot methoden
        Method speakMethod = memberClass.getDeclaredMethod("speak", String.class);
        speakMethod.invoke(member, "Reflectie test");

        Method secretMethod = memberClass.getDeclaredMethod("secret");
        secretMethod.setAccessible(true);
        secretMethod.invoke(member);
    }
}

// Uitvoer
Jayon
23
Dara쓰 development
Member{name='Jayon2', age=23, hobby='Dara쓰 development'}
Reflectie test

Met getDeclaredFileds() kun je alle instantie-variabelen van de klasse ophalen, met get() kun je de veldwaarde terugkrijgen, en met set() kun je de veldwaarde wijzigen. Let erop dat wanneer je toegang hebt tot velden met een private toegangsbeheerder, je setAccessible() met true als argument moet doorgeven.


Methoden kunnen ook worden opgehaald met getDeclaredMethod(). In dat geval moet je de naam van de methode en het type van de parameter samen als argument doorgeven. Op dezelfde manier, wanneer je toegang hebt tot methoden met een private toegangsbeheerder, moet je setAccessible() met true als argument instellen. Ten slotte kun je de methode die is opgehaald met de reflectie-API aanroepen met de methode invoke().


Voor- en nadelen

  • Voordelen
    • Het heeft de flexibiliteit om instanties van klassen te maken tijdens runtime, en om toegang te krijgen tot velden en methoden ongeacht de toegangsbeheerders, om de benodigde taken uit te voeren.
  • Nadelen
    • Het ondermijnt inkapseling.
    • Omdat instanties tijdens runtime worden gemaakt, kan het type niet op compileertijd worden gecontroleerd.
    • Omdat instanties tijdens runtime worden gemaakt, is het moeilijk om de specifieke workflow te begrijpen.
    • Het is langzamer om toegang te krijgen via reflectie dan om rechtstreeks toegang te krijgen tot velden en methoden. (Niet alle situaties zijn langzamer.)


Redenen voor gebruik

Via de reflectie-API kun je tijdens runtime toegang krijgen tot klasse-informatie en klassen naar wens manipuleren. Zelfs velden en methoden die zijn verklaard met een private toegangsbeheerder kunnen worden gemanipuleerd. Het lijkt misschien een technologie die niet mag worden gebruikt, omdat het de inkapseling, die belangrijk is in objectgeoriënteerd ontwerp, ondermijnt.


In kleine console-omgevingen kan een ontwikkelaar alle objecten en afhankelijkheden die in het programma worden gebruikt, op compileertijd identificeren. In grote ontwikkelingsprojecten zoals frameworks is het echter moeilijk om een groot aantal objecten en afhankelijkheden te identificeren. In dat geval kan reflectie worden gebruikt om dynamisch klassen te maken en afhankelijkheden tot stand te brengen.


Bijvoorbeeld, als je naar de Bean Factory van Spring kijkt, zie je dat Bean Factory automatisch de klassen met de annotaties @Controller, @Service en @Repository maakt en beheert, zolang je deze annotaties maar aan de klassen toevoegt. De ontwikkelaar heeft Bean Factory nooit deze klassen laten weten, maar dit is mogelijk dankzij reflectie. Als een klasse met de bijbehorende annotatie tijdens runtime wordt gevonden, wordt deze via reflectie gebruikt om een instantie van die klasse te maken, de benodigde velden te injecteren en op te slaan in Bean Factory.


Natuurlijk is het vanwege de inkapseling die het ondermijnt, het beste om het alleen te gebruiken wanneer dat echt nodig is.


Bron

제이온
제이온
제이온
제이온
[Effectieve Java] Item 6. Vermijd onnodige objectcreatie Een gids over het verminderen van onnodige objectcreatie in Java. Voor onveranderlijke objecten zoals String en Boolean is het beter om literals te gebruiken, en voor reguliere expressies is het beter om Pattern-instanties te cachen. Autoboxing kan ook le

28 april 2024

[Effectieve Java] Item 4. Gebruik een private constructor om instantiatie te voorkomen Voor utility-klassen die alleen statische methoden en velden bevatten, is het een goed idee om de toegangsmodifier van de constructor op 'private' te zetten om instantiatie te voorkomen. Dit voorkomt dat gebruikers de constructor verwarren met een automat

28 april 2024

[Effectieve Java] Item 2. Overweeg een bouwer als je constructor veel parameters heeft Het gebruik van het builder-patroon bij het maken van objecten met veel parameters maakt de code duidelijker en gemakkelijker leesbaar. Creëer een builder-object met vereiste parameters en stel optionele parameters in met setter-methoden, en roep de build

27 april 2024

[Javascript] Object-structuur (V8) Het JavaScript Object wordt in de V8-engine geoptimaliseerd als een structuur afhankelijk van de toestand en werkt als een Fast-modus en een Dictionary-modus die als een hashmap werkt. De Fast-modus is snel met keys en waarden in een bijna vaste vorm, maa
곽경직
곽경직
곽경직
곽경직
곽경직

18 maart 2024

[Concurrency] Atomaire bewerking: Memory Fence en Memory Ordering Deze blogpost bespreekt hoe geheugensorde te overwegen in atomaire bewerkingen en het belang van de Ordering-opties. We bespreken verschillende Ordering-opties zoals Relaxed, Acquire, Release, AcqRel, SecCst, inclusief een beschrijving van de voor- en nad
곽경직
곽경직
곽경직
곽경직
곽경직

12 april 2024

[React Hook] useState Deze blogpost beschrijft in detail waarom de useState-hook in React de volledige component opnieuw rendert bij het opnieuw renderen, hoe waarden worden behouden en hoe de interne implementatiestructuur werkt. Door de analyse van de ReactFiberHooks.js-code
Sunrabbit
Sunrabbit
Sunrabbit
Sunrabbit

14 maart 2024

Voor mij die goede feedback wil geven Wil je effectieve feedbackmethoden leren om de groei van je teamleden te bevorderen? In dit artikel wordt de belangrijkheid benadrukt van 'feedforward', waarbij de sterke punten van teamleden worden ontdekt en geprezen, en er wordt een methode geschetst o
울림
울림
울림
울림

18 maart 2024

Logisch gegevensmodelleren Logisch gegevensmodelleren is het proces van het transformeren van een conceptueel gegevensmodel naar het relationele databaseparadigma, waarbij 1:1, 1:N en N:M relaties worden verwerkt en normalisatie wordt gebruikt om gegevensintegriteit te waarborgen.
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그

9 april 2024

Hoe Rust concurrency-fouten voorkomt Rust is een krachtige taal die de uitdagingen van concurrency-programmeren aanpakt. Door het type-systeem en eigendomsmodel is het veilig om gegevens tussen threads te verzenden en te delen. Met behulp van interne veranderlijkheidspatronen zoals Mutex, Ch
곽경직
곽경직
곽경직
곽경직
곽경직

28 maart 2024