Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.
 
Inhaltsverzeichnis
Vorwort
1 Neues in Java 8 und Java 7
2 Fortgeschrittene String-Verarbeitung
3 Threads und nebenläufige Programmierung
4 Datenstrukturen und Algorithmen
5 Raum und Zeit
6 Dateien, Verzeichnisse und Dateizugriffe
7 Datenströme
8 Die eXtensible Markup Language (XML)
9 Dateiformate
10 Grafische Oberflächen mit Swing
11 Grafikprogrammierung
12 JavaFX
13 Netzwerkprogrammierung
14 Verteilte Programmierung mit RMI
15 RESTful und SOAP-Web-Services
16 Technologien für die Infrastruktur
17 Typen, Reflection und Annotationen
18 Dynamische Übersetzung und Skriptsprachen
19 Logging und Monitoring
20 Sicherheitskonzepte
21 Datenbankmanagement mit JDBC
22 Java Native Interface (JNI)
23 Dienstprogramme für die Java-Umgebung
Stichwortverzeichnis

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java SE 8 Standard-Bibliothek von Christian Ullenboom
Das Handbuch für Java-Entwickler
Buch: Java SE 8 Standard-Bibliothek

Java SE 8 Standard-Bibliothek
Pfeil 17 Typen, Reflection und Annotationen
Pfeil 17.1 Metadaten
Pfeil 17.1.1 Metadaten durch Javadoc-Tags
Pfeil 17.2 Metadaten der Typen mit dem Class-Objekt
Pfeil 17.2.1 An ein Class-Objekt kommen
Pfeil 17.2.2 Eine Class ist ein Type
Pfeil 17.3 Klassenlader
Pfeil 17.3.1 Das Verzeichnis jre/lib/endorsed *
Pfeil 17.3.2 Die Klasse java.lang.ClassLoader
Pfeil 17.3.3 Hot Deployment mit dem URL-Classloader *
Pfeil 17.4 Metadaten der Typen mit dem Class-Objekt
Pfeil 17.4.1 Der Name des Typs
Pfeil 17.4.2 Was das Class-Objekt beschreibt *
Pfeil 17.4.3 instanceof mit Class-Objekten *
Pfeil 17.4.4 Oberklassen finden *
Pfeil 17.4.5 Implementierte Interfaces einer Klasse oder eines Interfaces *
Pfeil 17.4.6 Modifizierer und die Klasse Modifier *
Pfeil 17.4.7 Die Arbeit auf dem Feld *
Pfeil 17.5 Attribute, Methoden und Konstruktoren
Pfeil 17.5.1 Reflections – Gespür für die Attribute einer Klasse
Pfeil 17.5.2 Schnittstelle Member für Eigenschaften
Pfeil 17.5.3 Field-Klasse
Pfeil 17.5.4 Methoden einer Klasse erfragen
Pfeil 17.5.5 Properties einer Bean erfragen
Pfeil 17.5.6 Konstruktoren einer Klasse
Pfeil 17.5.7 Annotationen
Pfeil 17.6 Objekte erzeugen und manipulieren
Pfeil 17.6.1 Objekte erzeugen
Pfeil 17.6.2 Die Belegung der Variablen erfragen
Pfeil 17.6.3 Eine generische eigene toString()-Methode *
Pfeil 17.6.4 Variablen setzen
Pfeil 17.6.5 Bean-Zustände kopieren *
Pfeil 17.6.6 Private Attribute ändern
Pfeil 17.6.7 Methoden aufrufen
Pfeil 17.6.8 Statische Methoden aufrufen
Pfeil 17.6.9 Dynamische Methodenaufrufe bei festen Methoden beschleunigen *
Pfeil 17.6.10 java.lang.reflect.Parameter
Pfeil 17.7 Eigene Annotationstypen *
Pfeil 17.7.1 Annotationen zum Laden von Ressourcen
Pfeil 17.7.2 Neue Annotationen deklarieren
Pfeil 17.7.3 Annotationen mit genau einem Attribut
Pfeil 17.7.4 Element-Wert-Paare (Attribute) hinzufügen
Pfeil 17.7.5 Annotationsattribute vom Typ einer Aufzählung
Pfeil 17.7.6 Felder von Annotationsattributen
Pfeil 17.7.7 Vorbelegte Attribute
Pfeil 17.7.8 Annotieren von Annotationstypen
Pfeil 17.7.9 Deklarationen für unsere Ressourcen-Annotationen
Pfeil 17.7.10 Annotierte Elemente auslesen
Pfeil 17.7.11 Auf die Annotationsattribute zugreifen
Pfeil 17.7.12 Komplettbeispiel zum Initialisieren von Ressourcen
Pfeil 17.7.13 Mögliche Nachteile von Annotationen
Pfeil 17.8 Zum Weiterlesen
 
Zum Seitenanfang

17.4Metadaten der Typen mit dem Class-Objekt Zur vorigen ÜberschriftZur nächsten Überschrift

Ein Class-Objekt beschreibt eine Reihe von Eigenschaften, wie Namen, Beziehungen, Annotationen, die sich mit unterschiedlichen Methoden erfragen lassen.

 
Zum Seitenanfang

17.4.1Der Name des Typs Zur vorigen ÜberschriftZur nächsten Überschrift

Liegt zu einem Typ das Class-Objekt vor, so können wir zur Laufzeit ihren voll qualifizierten Namen über die Methode getName() ausgeben. Da jeder Typ über einen Namen verfügt, führt diese Methode also jedes Mal zum Ziel:

Anweisung

String-Rückgabe

java.util.Date().getClass().getName()

java.util.Date

java.util.RandomAccess.class.getName()

java.util.RandomAccess

Deprecated.class.getName()

java.lang.Deprecated

Thread.State.class.getName()

java.lang.Thread$State

Tabelle 17.2getName() liefert eine String-Repräsentation diverser Typen

Während getName() den voll qualifizierten Namen liefert, liefert getSimple() nur den Typnamen und keine Paketangabe.

toString(), toGenericString(), getCanonicalName()

Die Klasse Class überschreibt die Methode toString() und greift dabei auf getName() zurück. toString() fügt zusätzlich Informationen über die Art des repräsentierten Typs (normale Klasse, Schnittstelle oder primitiver Datentyp) ein. Neu in Java 8 ist toGenericString(), was auch noch in spitzen Klammern die Typvariablen anzeigt (natürlich nicht den Typparameter, da der zur Laufzeit wegen der Typlöschung nicht bekannt ist). Um die Typvariable zu erfragen, wird (ab Java 8) getTypeName() verwendet; die Methode ist eine Implementierung aus der Schnittstelle Type, die Class implementiert.

[zB]Beispiel

Teste für ein Class-Objekt die vier String-Repräsentationen:

Class<?> c = HashMap.class;
System.out.println( c.getName() ); // java.util.HashMap
System.out.println( c.getSimpleName() ); // HashMap
System.out.println( c.toString() ); // class java.util.HashMap
System.out.println( c.toGenericString() ); // public class java.util.HashMap<K,V>

Bei inneren Typen trennt ein $ bei der String-Repräsentation den äußeren und inneren Typ. Anders verhält sich getCanonicalName(), wie das Beispiel zeigt:

Anweisung

Rückgabe

Map.Entry.class.getName()

java.util.Map$Entry

Map.Entry.class.getCanonicalName()

java.util.Map.Entry

Map.Entry.class.toString()

interface java.util.Map$Entry

Map.Entry.class.toGenericString()

public abstract static interface java.util.Map$Entry<K,V>

Tabelle 17.3String-Repräsentation bei inneren Typen

Kodierung von Feldern *

Schwieriger ist die Kodierung bei Array-Typen, die ja eine besondere Form von Klassen sind. getName() kodiert sie mit einer führenden »[«. Jede Klammer steht dabei für eine Dimension des Array-Typs. Nach den Klammern folgt in einer kodierten Form der Typ der Array-Elemente. So liefert

System.out.println( int[][][].class.getName() ); // [[[I
System.out.println( (new int[2][3][4]).getClass().getName() ); // [[[I

den String »[[[I«, also einen dreidimensionalen Array-Typ mit Array-Elementen vom primitiven Typ int. Der Elementtyp ist wie folgt kodiert:

Kürzel

Datentyp

B

Byte

C

Char

D

Double

F

Float

I

Int

J

Long

LElementtyp;

Klasse oder Schnittstelle

S

Short

Z

Boolean

Tabelle 17.4Kodierung der Elementtypen

Nimmt das Array Objektreferenzen auf, wird deren Typ in der Form »LKlassenname;« kodiert. So liefert (new Object[3]).getClass().getName() den String [Ljava.lang.Object;. Der Klassen- bzw. Schnittstellenname ist wie üblich voll qualifiziert.

Der String ist auch für Class.forName(…) von Bedeutung. Im Fall von Arrays liefert die Methode ein Class-Objekt für den Elementtyp. Die ersten Versuche, ein Class-Objekt für Felder zu beziehen, scheitern an einer ClassNotFoundException:

Class.forName( "String[]" );
Class.forName( "java.lang.String[]" );

In der ersten Anweisung ist der Klassenname nicht voll qualifiziert, und auch in der zweiten Anweisung ist der String falsch aufgebaut.

out.println( Class.forName("[Ljava.lang.String;") ); // class [Ljava.lang.String;

Steht die Frage an, ob ein Class-Objekt für ein Feld von Objekten steht oder für ein primitives Feld, lässt sich das Ergebnis von getName() auswerten:

public static boolean isObjectArray( Class<?> clazz ) {
if ( clazz != null && clazz.isArray() )
return clazz.getName().startsWith( "[L" );
return false;
}

So liefert:

System.out.println( isObjectArray( Object[].class ) ); // true
System.out.println( isObjectArray( int[].class ) ); // false
System.out.println( isObjectArray( Object.class ) ); // false
final class java.lang.Class<T>
implements Serializable, GenericDeclaration, Type, AnnotatedElement
  • String getName()
    Liefert für ein Class-Exemplar als String den voll qualifizierten Namen der repräsentierten Klasse oder Schnittstelle bzw. des repräsentierten Array-Typs oder des primitiven Datentyps.

  • String toString()
    Liefert eine für Menschen lesbare String-Repräsentation des Class-Objekts.

 
Zum Seitenanfang

17.4.2Was das Class-Objekt beschreibt * Zur vorigen ÜberschriftZur nächsten Überschrift

Ein Class-Exemplar kann eine Schnittstelle, eine Klasse, einen primitiven Datentyp oder auch einen Array-Typ beschreiben. Dies lässt sich durch die drei Class-Methoden isInterface(), isPrimitive() und isArray() herausfinden. Wenn keine der drei Methoden für ein Class-Exemplar true liefert, repräsentiert das Objekt eine gewöhnliche Klasse.

Dass es auch Class-Exemplare gibt, die die primitiven Datentypen von Java beschreiben, erstaunt zunächst. Damit ist es jedoch möglich, die Parameter- und Ergebnistypen beliebiger Java-Methoden einheitlich durch Class-Exemplare zu beschreiben. Dazu kodiert jede der acht Wrapper-Klassen, die zu den Datentypen boolean, byte, char, short, int, long, float und double gehören, eine Konstante TYPE. Zusätzlich gib es eine spezielle Klasse Void für den »Typ« void mit genau einer Konstanten TYPE. Benötigen wir ein Class-Objekt für den primitiven Typ int, so greifen wir mit Integer.TYPE (oder alternativ mit int.class) darauf zu. Alle Class-Exemplare für primitive Datentypen werden automatisch von der JVM erzeugt. Die Methode isPrimitive() gibt genau für diese neun besonderen Class-Exemplare true zurück, sodass sie von Repräsentanten für echte Klassen unterschieden werden können.

[»]Hinweis

Obwohl void kein Typ ist, meldet isPrimitive() dies:

System.out.println( void.class.isPrimitive() ); // true

Das folgende Programmstück testet die Attribute von Class-Objekten systematisch durch. Wir benutzen die Class-Methode getName(), um den Namen des Class-Objekts auszugeben. Im nächsten Abschnitt mehr dazu. Das Class-Objekt für Felder setzt sich aus dem Basistyp und Paaren von eckigen Klammern zusammen, etwa double[][].class.

Listing 17.4com/tutego/insel/meta/CheckClassType.java, CheckClassType

class CheckClassType {
public static void main( String[] args ) {
checkClassType( Observer.class );
checkClassType( Observable.class );
checkClassType( (new int[2][3][4]).getClass() );
checkClassType( Integer.TYPE );
}

static void checkClassType( Class<?> c ) {
if ( c.isArray() )
System.out.println( c.getName() + " ist ein Feld." );
else if ( c.isPrimitive() )
System.out.println( c + " ist ein primitiver Typ.");
else if ( c.isInterface() )
System.out.println( c.getName() + " ist ein Interface." );
else
System.out.println( c.getName() + " ist eine Klasse." );
}
}

Die Ausgabe des Programms ist nun:

java.util.Observer ist ein Interface.
java.util.Observable ist eine Klasse.
[[[I ist ein Feld.
int ist ein primitiver Typ.
final class java.lang.Class<T>
implements Serializable, GenericDeclaration, Type, AnnotatedElement
  • boolean isInterface()
    Liefert true, wenn das Class-Objekt eine Schnittstelle beschreibt.

  • boolean isArray()
    Liefert true, wenn das Class-Objekt einen Array-Typ beschreibt.

  • boolean isPrimitive()
    Testet, ob das Class-Objekt einen primitiven Datentyp beschreibt.

Komponententyp bei Feldern

Die Methode getComponentType() liefert bei Feldern den Typ der Elemente als Class-Objekt. Steht das Class-Objekt für kein Feld, ist die Methodenrückgabe null:

System.out.println( double[].class.getComponentType() ); // double
System.out.println( double[][].class.getComponentType() ); // class [D
System.out.println( double.class.getComponentType() ); // null
 
Zum Seitenanfang

17.4.3instanceof mit Class-Objekten * Zur vorigen ÜberschriftZur nächsten Überschrift

Der binäre Operator instanceof testet, ob ein Objekt Exemplar einer Klasse oder der Oberklasse ist. Wenn das Ergebnis wahr ist, lässt sich das Objekt unter dem gegebenen Typ ansprechen, ist also zuweisungskompatibel. Der rechte Operator bei instanceof, der Typname, muss jedoch immer zur Übersetzungszeit bekannt sein und kann nicht dynamisch, etwa durch einen String, festgelegt werden.

Ist der Typname zur Compilezeit vielleicht unbekannt, kann das Class-Objekt helfen. Die Methode isInstance(Object) ist sozusagen ein dynamisches instanceof. Gilt mit dem Operator

object instanceof ReferenceType

so heißt das mit der Methode:

ReferenceType-Class-Objekt.isInstance( object )

Gewöhnungsbedürftig ist sicherlich die Tatsache, dass bei der Class-Methode isInstance(Object) die beiden Operanden umgedreht sind. Dazu ein paar Beispiele:

Listing 17.5com/tutego/insel/meta/IsAssignableFrom.java, main()

Component b = new JLabel();
out.println( b instanceof JLabel ); // true
out.println( JLabel.class.isInstance( b ) ); // true
out.println( Object.class.isInstance( b ) ); // true
out.println( Class.forName("java.awt.Component").isInstance( b ) ); // true
out.println( String.class.isInstance( b ) ); // false

Die Methode isInstance(object) ist natürlich ein wenig dadurch eingeschränkt, dass es immer ein Test-Objekt geben muss. Die Frage etwa, ob das Class-Objekt der Schnittstelle PublicKey eine »Ist-eine-Art-von-Serializable« ist, kann isInstance(object) nicht beantworten, denn dann müsste es vorher ein Objekt geben. Für diesen Fall bietet das Class-Objekt noch eine zweite Methode, isAssignableFrom(Class):

Class<?> clazz = Serializable.class;
out.println( clazz.isAssignableFrom( String.class ) ); // true
out.println( clazz.isAssignableFrom( Thread.class ) ); // false
out.println( clazz.isAssignableFrom( PublicKey.class ) ); // true

Solange der Typname zur Übersetzungszeit bekannt ist, ist instanceof immer noch die beste Lösung. Doch wenn die Klasse nur durch ein Class-Objekt gegeben ist, bleibt immer noch isAssignableFrom(Class<?> cls). Die Methode clazz.isInstance(obj) ist sozusagen eine Kurzform von clazz.isAssignableFrom(obj.getClass()).

 
Zum Seitenanfang

17.4.4Oberklassen finden * Zur vorigen ÜberschriftZur nächsten Überschrift

Das Class-Exemplar für eine Klasse gibt Zugriff auf die Oberklasse, die Sichtbarkeitsstufe und weitere Informationen. Die Oberklasse ermittelt getSuperclass(). Die Methode gibt null zurück, falls das Class-Objekt eine Schnittstelle repräsentiert oder wir schon am oberen Ende der Hierarchie sind, also bei dem Class-Objekt für die Wurzelklasse Object. Das folgende Programm findet alle Oberklassen einer Klasse durch den wiederholten Aufruf der Methode getSuperclass():

Listing 17.6com/tutego/insel/meta/ShowSuperclasses.java

Class<?> subclass = javax.swing.JButton.class;
Class<?> superclass = subclass.getSuperclass();

while ( superclass != null ) {
String className = superclass.getName();
System.out.println( className );
subclass = superclass;
superclass = subclass.getSuperclass();
}

Wahrscheinlich wäre eine rekursive Variante noch eleganter, aber darauf kommt es jetzt nicht an.

javax.swing.AbstractButton
javax.swing.JComponent
java.awt.Container
java.awt.Component
java.lang.Object
final class java.lang.Class<T>
implements Serializable, GenericDeclaration, Type, AnnotatedElement
  • Class<? super T> getSuperclass()
    Liefert ein Class-Exemplar für die Oberklasse der Klasse, die durch das aufrufende Class-Objekt repräsentiert wird. Falls wir schon oben auf der Vererbungshierarchie bei Object sind oder nach der Oberklasse einer Schnittstelle fragen, liefert die Methode null.

 
Zum Seitenanfang

17.4.5Implementierte Interfaces einer Klasse oder eines Interfaces * Zur vorigen ÜberschriftZur nächsten Überschrift

Klassen stehen zum einen in einer Vererbungsbeziehung zu einer Oberklasse und können zum anderen mehrere Schnittstellen implementieren. Schnittstellen können ihrerseits wiederum andere Schnittstellen erweitern. Bei einer Klassendeklaration folgt direkt hinter dem Schlüsselwort implements eine Auflistung der implementierten Schnittstellen. So implementiert die Klasse RandomAccessFile die Schnittstellen DataOutput, DataInput und Closeable:

public class RandomAccessFile implements DataOutput, DataInput, Closeable

Um zu einem vorhandenen Class-Objekt die Schnittstellen aufzulisten, rufen wir getInterfaces() auf, die uns ein Array von Class-Objekten liefert. Von hier aus kennen wir den Weg zum Namen: Der Aufruf von getName() liefert den String für den Namen der Schnittstelle.

[zB]Beispiel

Gib die implementierten Schnittstellen von RandomAccessFile aus:

Listing 17.7com/tutego/insel/meta/ShowInterfaces.java, main()

for ( Class<?> theInterface: java.io.RandomAccessFile.class.getInterfaces() )
System.out.println( theInterface.getName() );

Die Ausgabe ist:

java.io.DataOutput
java.io.DataInput
java.io.Closeable
 
Zum Seitenanfang

17.4.6Modifizierer und die Klasse Modifier * Zur vorigen ÜberschriftZur nächsten Überschrift

Eine Klassendeklaration kann Modifizierer enthalten, also Schlüsselwörter, die zum Beispiel die Sichtbarkeit bestimmen. Unter anderem sind dies public, protected, private und final. Sie stehen etwa in der Klassendeklaration vor dem Schlüsselwort class oder auch vor Methoden. Die Modifizierer können auch kombiniert werden: So ist die Klasse Class selbst public final. Die Methode getModifiers() liefert im Rückgabewert die Modifizierer, verschlüsselt als Ganzzahl:

System.out.println( Modifier.class.getModifiers() ); // 1
System.out.println( Modifier.toString(Modifier.class.getModifiers()) ); // public
final class java.lang.Class<T>
implements Serializable, GenericDeclaration, Type, AnnotatedElement
  • int getModifiers()
    Liefert die Modifizierer für eine Klasse oder eine Schnittstelle.

Dekodieren der Zahlrepräsentationen durch die Klasse Modifier

Damit wir uns bei der Entschlüsselung nicht mit magischen Zahlenwerten der JVM herumschlagen müssen, gibt es in der Klasse java.lang.reflect.Modifier einige statische Methoden, die diese Ganzzahl testen und aufbauen. Zudem werden Konstanten deklariert (wie Modifier.PUBLIC), mit denen dieser Ganzzahlwert verglichen werden kann. Da die Ganzzahl potenziell eine Kombination mehrerer Modifizierer kodiert, ist die gezielte Abfrage allerdings mit den statischen isXXX(…)-Methoden einfacher. Obwohl eine Klasse nicht transient, synchronized, nativ sein kann, listen wir hier alle statischen Methoden auf, da wir diese Modifizierer später auch für die Untersuchung von Methoden und Objekt- bzw. Klassenvariablen per Reflection einsetzen. Jede dieser Testmethoden liefert true, wenn der gefragte Modifizierer in dem kodierten Ganzzahlwert enthalten ist. Alle Methoden sind static und liefern ein boolean-Ergebnis, außer toString().

class java.lang.reflect.Modifier
  • static boolean isAbstract(int mod)

  • static boolean isFinal(int mod)

  • static boolean isInterface(int mod)

  • static boolean isNative(int mod)

  • static boolean isPrivate(int mod)

  • static boolean isProtected(int mod)

  • static boolean isPublic(int mod)

  • static boolean isStatic(int mod)

  • static boolean isSynchronized(int mod)

  • static boolean isTransient(int mod)

  • static boolean isVolatile(int mod)

  • static boolean isDefault(int mod) (seit Java 8)

Des Weiteren gibt es xxxModifier()-Methoden, die über ein int aussagen, welche Modifizierer an einem bestimmten Element erlaubt sind:

class java.lang.reflect.Modifier
  • static int classModifiers()

  • static int constructorModifiers()

  • static int fieldModifiers()

  • static int interfaceModifiers()

  • static int methodModifiers()

  • static int parameterModifiers()
    Liefert ein int, das alle Modifizierer kodiert, die an Klassen/Konstruktoren/Feldern/Schnittstellen/Methoden/Methodenparametern erlaubt sind. So liefert constructorModifiers() zum Beispiel Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE.

[»]Hinweis

Schnittstellen, wie java.io.Serializable, tragen den Modifier abstract:

int mod = Serializable.class.getModifiers();
System.out.println( mod ); // 1537
System.out.println( (mod & Modifier.PUBLIC) != 0); // true
System.out.println( (mod & Modifier.ABSTRACT) != 0); // true
System.out.println( Modifier.toString(mod) ); // public abstract interface
 
Zum Seitenanfang

17.4.7Die Arbeit auf dem Feld * Zur vorigen ÜberschriftZur nächsten Überschrift

Die Utility-Klasse java.lang.reflect.Array stellt statische Methoden bereit, um auf Array-Objekten generisch zu arbeiten. Elemente lassen sich erfragen und setzen und auch Arrays mit einem gewünschten Typ anlegen:

Object array = Array.newInstance( int.class, 20 );
System.out.println( Array.getLength(array) ); // 20
Array.setInt( array, 0, –1 );
System.out.println( Array.getInt(array, 0) ); // –1

Bei newInstance(…) ist der Typ int.class und nicht int[].class!

Eine allgemeine statische Array-Methode set(…) und auch get(…) arbeiten für Objekte, wobei auch Wrapper für primitive Felder verwendet werden können:

Array.set( array, 0, Integer.valueOf(-1) );
System.out.println( Array.get(array, 0) ); // –1

Für mehrdimensionale Felder lässt sich bei newInstance(…) ein Feld von Größen angeben:

Object array = Array.newInstance( int.class, new int[]{ 2, 2 } );
((int[][])array)[0][0] = 1;
((int[][])array)[1][1] = 1;
System.out.println( Arrays.deepToString( (int[][])array ) ); // [[1, 0], [0, 1]]

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java SE 8 Standard-Bibliothek Java SE 8 Standard-Bibliothek
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Java ist auch eine Insel
Java ist auch eine Insel


Zum Rheinwerk-Shop: Professionell entwickeln mit Java EE 8
Professionell entwickeln mit Java EE 8


Zum Rheinwerk-Shop: Besser coden
Besser coden


Zum Rheinwerk-Shop: Entwurfsmuster
Entwurfsmuster


Zum Rheinwerk-Shop: IT-Projektmanagement
IT-Projektmanagement


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2018
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 
Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern