tifyty

pure Java, what else ?

String immutable reloaded

A korábbi A String immutable, vagy nem? cikk meglehetősen rövid volt. Nem titkolt (bár közzé sem tett) szándékom az volt, hogy az olvasókat gondolkodásra ösztönözzem, és azt hiszem, hogy a visszajelzések alapján (ami személyes levélben is jócskán jött) ez meg is történt. Azonban voltak olyan visszajelzések is, amelyek szememre vetették, hogy nem szabad ilyen hekkeléseket csinálni, holott a cikk nem akarta azt sugallni, hogy a String osztály a Java nyelvben ilyen módon is használandó lehet.

Ezért most “újra” megírom ezt a cikket. Először elmondom, hogy mit is csinál ez a program, majd pedig azt, hogy miért is érdemes ezt tudni, melyek azok az esetek, amikor szükségünk lehet erre az ismeretre. És akkor, mivel elég rövid, hogy ne kelljen lapozgatni, az eredeti cikk mégegyszer:


Mit ír ki a következő program?

package com.verhas.elrettentopelda;

import java.lang.reflect.Field;

public class Wtf {
	public static void main(String[] args) throws Exception {
		String alma = "alma";
		String korte = "alma";
		Field value = String.class.getDeclaredField("value");
		value.setAccessible(true);
		value.set(alma, new char[] { 'k', 'o', 'r', 't', 'e' });
		System.out.println(korte);
	}
}

Mit csinál ez a program

Először is tisztázzuk, hogy a program olyan dolgot követ el, ami ugyan a gyakorlatban működik, de semmi nem garantálja, hogy valóban működőképes mindig, minden Java környezetben. Ugyanis nem csak a String osztály definiált, és garantált működését használja ki, hanem reflection használatával olyan mezőkhöz nyúl, amelyek ugyan szerepelnek az implementációban, ám minden előzetes figyelmeztetés nélkül a fejlesztők megváltoztathatják ezeket. Nem azért vannak, hogy piszkáljuk, de senki nem akadályoz meg bennünket abban, hogy megtegyük.

UPDATE(2013-11-08): Java8-ban meg is tették a fejlesztők, a fenti példa nem működik 8-as Java alatt!

Tehát ha valaki ilyesmire vetemedik, akkor az megérdemli. Az nem Java-ban programoz, hanem csak kódot állít elő Java nyelven.

A program két String tíusú változót hoz létre. A Java fordító észreveszi, hogy ez a két string literál azonos, ezért a lefordított kódban valóban azonos lesz a két string, annyira, hogy csak egyszer fog szerepelni a string literálok között. Azaz alma==korte. Ezt követően reflection használatával elkérjük a String osztály value nevű mezőjét. Vigyázat, kezdők, és akik nem jártasak a reflection-ben: NEM a value mező értékét kérjük el, már csak azért sem, mert nem egy String típusú objektum value mezőjéről beszélünk, hanem az osztály value mezőjéről. Ez nem egy static mező, így értéke sincs, nem osztálypéldány. Ettől függetlenül még kaphatunk egy Field típusú objektumot, amelyik metódusai ezen a mezőn végeznek műveletet.

Amikor megvan ez az objektumunk, akkor a hozzáférést true értékre állítjuk. Ezzel elérjük, hogy azokat a mezőket is el tudjuk érni, amelyek private módosítóval rendelkeznek, vagy egyéb okok miatt nem férhetnénk hozzá a mezőhöz (pl. protected a mező, és nem azonos csomagban vagyunk, sem pedig leszármazottak nem vagyunk). Innen kezdve a field objektumon keresztül el tudjuk érni egy String objektum value mezőjét.

Ezt követően ezt a mezőt átállítjuk. Az értéke egy karakter tömb lesz, a k, o, r, t, e értékekkel, és a hossza 5. Ez azonban nem a string hossza, csak a string objektum value mezőjének a hossza. A String karakterei ugyanis csupán valahol ebben a tömbben vannak, nem feltétlenül az első elemnél kezdődik a string és nem feltétlenül tart a tömb végéig. A string objektum hosszát nem állítottuk át, az maradt továbbra is a "alma".length() értéke, ami 4.

Ennek folyományaként pedig a a string objektum értéke "kort", mert a hossz érték 4.

Érdekes, hogy a szavazás állása szerint jelen pillanatban (2012-07-26 11:30pm) a korte 12:8-ra vezet a helyes kort-tel szemben, de hát a tények makacs dolgok, ez nem demokrácia, hogy a szavazás döntsön.

Miért érdemes ezt tudni?

Például érdemes tudni, hogy a substring metódus nem fogja a karaktereket átmásolni, hanem az eredeti és a substring által visszaadott string ugyanazt a karakter tömböt fogja használni. Ezért nem különösebben nagy költség, még igen nagy string objektumoktól sem elkérni substring-et. (Stringet konkatenálni persze az már más.)

Azért is érdekes lehet a kérdés, hogy tisztában legyünk azzal, hogy ha kiadunk egy JAR fájlt a kezünkből, akár obfuscated lebutítva, hogy ne nagyon lehessen visszafejteni, és elektronikusan aláírva, hogy ha valaki belepiszkál, akkor a class loader már ne töltse be (melyik class loader?) azzal nagyon sokat nem növeltünk a biztonságon.

Készítettünk licence ellenőrző modult, most is elérhető LGPL License3j néven. Ez abban segíti a felhasználót, hogy ne használja véletlenül a szoftvert olyan esetben, amikor nincs rá joga. De arra izmozni, hogy ne is tudja, nem érdemes, mert azt még C-ben sem lehet. A natív gépi kódot is át lehet írni, a JVM byte kódba is bele lehet piszkálni, lehet class loadert írni, ami kikerüli a betöltési védelmeket, és végül, de nem utolsó sorban át lehet írni reflection-nel a futó Java-ban bármit.

De aki ilyet tesz, az hacker. Nem programozó.

One response to “String immutable reloaded

  1. Visszajelzés:final, fin ül « tifyty

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés / Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés / Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés / Módosítás )

Google+ kép

Hozzászólhat a Google+ felhasználói fiók használatával. Kilépés / Módosítás )

Kapcsolódás: %s

%d blogger ezt kedveli: