Programowane refleksyjne i serializacja 1 1. Programowanie refleksyjne: ● przegląd wybranych klas z pakietu java.lang i java.lang.reflect, ● dynamiczne obiekty proxy. 2. Serializacja ● interfejs Serializable, ● pełna kontrola nad serializacją, ● serializacja do plików XML.
28
Embed
Programowane refleksyjne i serializacjausers.uj.edu.pl/~ciesla/java/java_12.pdf · języka programowania, które nie musiały być zdeterminowane w momencie tworzenia oprogramowania.
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Programowane refleksyjne i serializacja
1
1. Programowanie refleksyjne:
● przegląd wybranych klas z pakietu java.lang i java.lang.reflect,
● dynamiczne obiekty proxy.
2. Serializacja
● interfejs Serializable,
● pełna kontrola nad serializacją,
● serializacja do plików XML.
Wprowadzenie
2
Programowanie refleksyjne polega na dynamicznym korzystaniu ze struktur, które
języka programowania, które nie musiały być zdeterminowane w momencie
tworzenia oprogramowania.
Najważniejsze klasy języka Java, które umożliwiają programowanie refleksyjne to
Class, Field, Method, Array, Constructor. Są one zgrupowane w pakietach
java.lang i java.lang.reflect.
Klasa Class
3
Class reprezentuje klasę. Każdy obiekt (java.lang.Obiect) w Javie zawiera
metodę getClass(), która zwraca instancję klasy Class.
Podstawowe metody Class:
static Class forName(String) – zwraca obiekt reprezentujący klasę
o podanej nazwie. Jeśli klasa nie była wcześniej używana jest wcześniej ładowana za
pomocą odpowiedniego ClassLoader'a.
Class.forName("com.mysql.jdbc.Driver");
Object newInstance()– tworzy nowy obiekt (instancję) danego typu
Metoda getClassLoader() wywołana na rzecz obiektu Class zwraca obiekt
odpowiedzialny za załadowanie zasobów związanych z daną klasą. Obiekty ClassLoader mogą być wykorzystane do dynamicznej zmiany miejsca z którego
zostaną załadowane zasoby.
class OwnClassLoader extends ClassLoader { public Class findClass(String name) { byte[] b = loadClassData(name); return defineClass(name, b, 0, b.length); }
Object invoke(Object obj, Object[] args) – wywołuje metodę na rzecz
obiektu obj. Argumenty wejściowe są przekazywane przez tablicę args. Wartością
zwracaną jest wartość zwrócona w wyniku działania metody.
Przykład:
...Method m = Class.forName("MyClass").getDeclaredMethod(
"example3", null);m.invoke(null, null);
...
metoda invoke może zwrócić kilka rodzajów wyjątków związanych z dostępem do
metody i zgodnością typów argumentów.
Klasa Method
14
Wady wynikające z urzywania invoke(Object obj, Object[] args):
● typy primitywne (int, float, ...) muszą zostać opakowane w odpowiednie klasy
(Integer, Float, ...) tak, aby można było je przekazać przez tablicę parametrów,
● brak kontroli (w trakcie kompilacji) typów przekazywanych parametrów,
● ograniczenie obsługi wyjątków do Throwable.
Rozwiązaniem tych problemów jest możliwe dzięki tzw. Dynamic Proxy Class.
Klasa Proxy
15
...m.invoke(obj);...
Program...public void metoda(){...}...
Obiekt (klasa)
...proxy.metoda();...
Program...public void metoda(){...}...
Obiekt (klasa)
...obj.metoda();...
Proxy
brak kontroli typów
proxy musi być tworzone dynamicznie!
Klasa Proxy
16
Klasa Proxy udostępnia metody statyczne służące do tworzenia tzw. dynamicznych
klas proxy oraz ich instancji:
Utworzenie proxy dla określonego interfejsu (np. MyInterface):
InvocationHandler handler = new MyInvocationHandler(...);Class proxyClass = Proxy.getProxyClass(
MyInterface.class.getClassLoader(), new Class[] { MyInterface.class });
MyInterface mi = (MyInterface) proxyClass.getConstructor(
new Class[] { InvocationHandler.class }).newInstance(new Object[] { handler });
Klasa Proxy
17
Alternatywne wywołanie:
MyInterface mi = (MyInterface) Proxy.newProxyInstance(MyInterface.class.getClassLoader(), // loader dla zasobównew Class[] { MyInterface.class }, // tablica interfejsówhandler); // obiekt do którego będą przekazywane
// wywołania
Stworzono obiekt mi, który „z zewnątrz” wygląda jak klasa implementująca
MyInterface, natomiast obsługa metod będzie w rzeczywistości realizowana przez
handler.
Klasa Proxy
18
Obiekt handler nie musi implementować MyInterface! Musi za to
implementować interfejs InvocationHandler, czyli metodę:
Wszystkie wywołania metod na obiekcie mi zostaną przekierowane do metody
invoke, przy czym pierwszym parametrem będzie obiekt proxy.
Klasa Proxy
19
...Pisarz obj = new PisarzImpl();Method m = obj.getClass().getMethod( "pisz", new Class[] {String.class});m.invoke(obj, new Object[]{"hello world"});...
class PisarzImpl implements Pisarz {...public void pisz(String s){
...}...
}interface Pisarz {
public void pisz(String s);}
Klasa Proxy
20
class MyHandler{ private Pisarz obj = new PisarzImpl(); public static Object invoke(Object proxy, Method m, Object[] args)){ return m.invoke(obj, args); }}
Aby zapisać lub odczytać klasę należy utworzyć obiekt ObjectOutputStream
a następnie skorzystać z metod:
void writeObject(Object)Object readObject()
w celu zapisania lub odczytania obiektu.
Serializacja - przykład
24
Zapisywanie:
...FileOutputStream out = new FileOutputStream("magazyn");ObjectOutputStream s = new ObjectOutputStream(out);s.writeObject("Hello World");s.writeObject(new Date());s.flush();...Odczytywanie:...FileInputStream in = new FileInputStream("magazyn");ObjectInputStream s = new ObjectInputStream(in);String today = (String)s.readObject();Date date = (Date)s.readObject();...
Pełna kontrola nad serializacją
25
● implementacja writeObject(ObjectOutputStream) oraz readObject():private void writeObject(ObjectOutputStream os) throws IOException{
os.defaultWriteObject();// własny kod
}private void readObject(ObjectInputStream s) throws IOException { s.defaultReadObject(); // własny kod, aktualizacja stanu obiektu}
● implementacja interfejsu Externalizable:
public interface Externalizable extends Serializable {
public void writeExternal(ObjectOutput out) throws IOException;
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
Serializacja a XML
26
Wraz z wersją 1.4 Javy udostępniona została możliwość serializacji obiektów typu
JavaBeans do plików tekstowych w formacie XML. Służą do tego klasy z pakietu
java.beans:
XMLEncoder:
XMLEncoder e = new XMLEncoder(new FileOutputStream("jbutton.xml")));e.writeObject(new JButton("Hello world"));e.close();
XMLDecoder:
XMLDecoder d = new XMLDecoder(new FileInputStream("jbutton.xml"));