Java >> Java tutorial >  >> Tag >> private

Påkaldelse af en privat metode i Java

1. Oversigt

Mens metoder er gjort private i Java for at forhindre dem i at blive kaldt uden for ejerklassen, skal vi muligvis stadig kalde dem af en eller anden grund.

For at opnå dette skal vi omgå Javas adgangskontrol. Dette kan hjælpe os med at nå et hjørne af et bibliotek eller give os mulighed for at teste noget kode, der normalt skal forblive privat.

I denne korte vejledning vil vi se på, hvordan vi kan verificere funktionaliteten af ​​en metode uanset dens synlighed. Vi vil overveje to forskellige tilgange:Java Reflection API og Springs ReflectionTestUtils .

2. Synlighed uden for vores kontrol

For vores eksempel, lad os bruge en hjælpeklasse LongArrayUtil der fungerer lang arrays. Vores klasse har to indexOf metoder:

public static int indexOf(long[] array, long target) {
    return indexOf(array, target, 0, array.length);
}

private static int indexOf(long[] array, long target, int start, int end) {
    for (int i = start; i < end; i++) {
        if (array[i] == target) {
            return i;
        }
    }
    return -1;
}

Lad os antage, at synligheden af ​​disse metoder ikke kan ændres, og alligevel vil vi kalde det private indexOf metode.

3. Java Reflection API

3.1. Find metoden med refleksion

Mens compileren forhindrer os i at kalde en funktion, der ikke er synlig for vores klasse, kan vi påkalde funktioner via refleksion. Først skal vi have adgang til metoden objekt, der beskriver den funktion, vi vil kalde:

Method indexOfMethod = LongArrayUtil.class.getDeclaredMethod(
  "indexOf", long[].class, long.class, int.class, int.class);

Vi skal bruge getDeclaredMethod for at få adgang til ikke-private metoder. Vi kalder det på typen, der har funktionen, i dette tilfælde LongArrayUtil , og vi videregiver typerne af parametrene for at identificere den korrekte metode.

Funktionen kan fejle og give en undtagelse, hvis metoden ikke eksisterer.

3.2. Tillad adgang til metoden

Nu skal vi hæve metodens synlighed midlertidigt:

indexOfMethod.setAccessible(true);

Denne ændring vil vare indtil JVM stopper, eller den tilgængelige egenskaben er sat tilbage til false.

3.3. Påberåb metoden med refleksion

Til sidst kalder vi invokemetoden objekt:

int value = (int) indexOfMethod.invoke(
  LongArrayUtil.class, someLongArray, 2L, 0, someLongArray.length);

Vi har nu adgang til en privat metode.

Det første argument at påkalde er målobjektet, og de resterende argumenter skal matche vores metodes signatur. Som i dette tilfælde er vores metode statisk , og målobjektet er den overordnede klasse – LongArrayUtil . For at kalde instansmetoder vil vi videregive det objekt, hvis metode vi kalder.

Vi skal også bemærke, at påkald returnerer Objekt , som er null for ugyldigt funktioner, og som skal castes til den rigtige type for at kunne bruge den.

4. Spring ReflectionTestUtils

At nå internt i klasser er et almindeligt problem i test. Springs testbibliotek giver nogle genveje til at hjælpe enhedstests med at nå klasser. Dette løser ofte problemer, der er specifikke for enhedstest, hvor en test skal have adgang til et privat felt, som Spring kan instansiere under kørsel.

Først skal vi tilføje forårstesten afhængighed i vores pom.xml:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.3.4</version>
    <scope>test</scope>
</dependency>

Nu kan vi bruge invokeMethod funktion i ReflectionTestUtils , som bruger samme algoritme som ovenfor, og sparer os for at skrive så meget kode:

int value = ReflectionTestUtils.invokeMethod(
  LongArrayUtil.class, "indexOf", someLongArray, 1L, 1, someLongArray.length);

Da dette er et testbibliotek, ville vi ikke forvente at bruge dette uden for testkoden.

5. Overvejelser

Brug af refleksion til at omgå funktionssynlighed er forbundet med nogle risici og er måske ikke engang muligt. Vi bør overveje:

  • Om Java Security Manager tillader dette i vores runtime
  • Om den funktion, vi ringer til, uden kontrol af kompileringstid, vil fortsætte med at eksistere, så vi kan kalde det i fremtiden
  • Omstrukturering af vores egen kode for at gøre tingene mere synlige og tilgængelige

6. Konklusion

I denne artikel så vi på, hvordan man får adgang til private metoder ved hjælp af Java Reflection API og ved hjælp af Springs ReflectionTestUtils .

Som altid kan eksempelkoden til denne artikel findes på GitHub.


Java tag