/*******************************************************************************
* Companion code for the book "Introduction to Software Design with Java",
* 2nd edition by Martin P. Robillard.
*
* Copyright (C) 2022 by Martin P. Robillard
*
* This code is licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* See http://creativecommons.org/licenses/by-nc-nd/4.0/
*
*******************************************************************************/
package e2.chapter5;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class MetaprogrammingSamples {
public static void main(String[] args) {
introspection();
manipulation1();
manipulation2();
}
/**
* Demonstrates basic introspection features
*/
private static void introspection() {
try {
String fullyQualifiedName = "e2.chapter5.Card";
<?> cardClass1 = Class.forName(fullyQualifiedName);
System.out.println(cardClass1.getName());
Class<Card> cardClass2 = ;
Card card = Card.get(Rank.ACE, Suit.CLUBS);
<?> cardClass3 = card.getClass();
System.out.println();
for( Method method : String.class.getDeclaredMethods() ) {
System.out.println(method.getName());
}
}
catch( ClassNotFoundException e ) {
e.printStackTrace();
}
}
/**
* Illustrates how to use metaprogramming to create an instance
* of an object with a private constructor.
*/
private static void manipulation1() {
try {
Card card1 = Card.get(Rank.ACE, Suit.CLUBS);
Constructor<Card> cardConstructor = Card.class.getDeclaredConstructor(Rank.class, Suit.class);
cardConstructor.setAccessible(true);
Card card2 = cardConstructor.newInstance(Rank.ACE, Suit.CLUBS);
System.out.println(card1 == card2);
}
catch( ReflectiveOperationException e ) {
e.printStackTrace();
}
}
/**
* Illustrates how to use metaprogramming to change the value of a private
* field of an instance.
*/
private static void manipulation2() {
try {
Card card = Card.get(Rank.TWO, Suit.CLUBS);
Field rankField = Card.class.getDeclaredField("aRank");
rankField.setAccessible(true);
rankField.(card, Rank.ACE);
System.out.println(card);
} catch( ReflectiveOperationException e ) {
e.printStackTrace();
}
}
}
Field object that reflects the specified declared
field of the class or interface represented by this Class
object. The name parameter is a String that specifies
the simple name of the desired field.
Field object that reflects the specified declared
field of the class or interface represented by this Class
object. The name parameter is a String that specifies
the simple name of the desired field.
If this Class object represents an array type, then this
method does not find the length field of the array type.
name - the name of the fieldField object for the specified field in this
classNoSuchFieldException - if a field with the specified name is
not found.NullPointerException - if name is nullSecurityException - If a security manager, s, is present and any of the
following conditions is met:
s.checkPermission method with
RuntimePermission("accessDeclaredMembers")
denies access to the declared field
s.checkPackageAccess() denies access to the package
of this class
Constructor object to
create and initialize a new instance of the constructor's
declaring class, with the specified initialization parameters.
Individual parameters are automatically unwrapped to match
primitive formal parameters, and both primitive and reference
parameters are subject to method invocation conversions as necessary.
Constructor object to
create and initialize a new instance of the constructor's
declaring class, with the specified initialization parameters.
Individual parameters are automatically unwrapped to match
primitive formal parameters, and both primitive and reference
parameters are subject to method invocation conversions as necessary.
If the number of formal parameters required by the underlying constructor
is 0, the supplied initargs array may be of length 0 or null.
If the constructor's declaring class is an inner class in a non-static context, the first argument to the constructor needs to be the enclosing instance; see section 15.9.3 of The Java Language Specification.
If the required access and argument checks succeed and the instantiation will proceed, the constructor's declaring class is initialized if it has not already been initialized.
If the constructor completes normally, returns the newly created and initialized instance.
initargs - array of objects to be passed as arguments to
the constructor call; values of primitive types are wrapped in
a wrapper object of the appropriate type (e.g. a float
in a Float)IllegalAccessException - if this Constructor object
is enforcing Java language access control and the underlying
constructor is inaccessible.IllegalArgumentException - if the number of actual
and formal parameters differ; if an unwrapping
conversion for primitive arguments fails; or if,
after possible unwrapping, a parameter value
cannot be converted to the corresponding formal
parameter type by a method invocation conversion; if
this constructor pertains to an enum class.InstantiationException - if the class that declares the
underlying constructor represents an abstract class.InvocationTargetException - if the underlying constructor
throws an exception.ExceptionInInitializerError - if the initialization provoked
by this method fails.accessible flag for this reflected object to
the indicated boolean value. A value of true indicates that
the reflected object should suppress checks for Java language access
control when it is used. A value of false indicates that
the reflected object should enforce checks for Java language access
control when it is used, with the variation noted in the class description.
accessible flag for this reflected object to
the indicated boolean value. A value of true indicates that
the reflected object should suppress checks for Java language access
control when it is used. A value of false indicates that
the reflected object should enforce checks for Java language access
control when it is used, with the variation noted in the class description.
This method may be used by a caller in class C to enable
access to a member of declaring class D if any of the following hold:
C and D are in the same module. public and D is public in
a package that the module containing D exports to at least the module
containing C. protected static, D is
public in a package that the module containing D
exports to at least the module containing C, and C
is a subclass of D. D is in a package that the module containing D
opens to at least the module
containing C.
All packages in unnamed and open modules are open to all modules and
so this method always succeeds when D is in an unnamed or
open module. This method may be used by JNI code
with no caller class on the stack to enable access to a member
of declaring class D if and only if:
public and D is public in
a package that the module containing D exports unconditionally. This method cannot be used to enable access to private members, members with default (package) access, protected instance members, or protected constructors when the declaring class is in a different module to the caller and the package containing the declaring class is not open to the caller's module.
This method cannot be used to enable write access to a non-modifiable final field. The following fields are non-modifiable:
The accessible flag when true suppresses Java language access
control checks to only enable read access to
these non-modifiable final fields.
If there is a security manager, its
checkPermission method is first called with a
ReflectPermission("suppressAccessChecks") permission.
A SecurityException is also thrown if this object is a
Constructor object for the class Class and flag
is true.
setAccessible in class AccessibleObjectflag - the new value for the accessible flagInaccessibleObjectException - if access cannot be enabledSecurityException - if the request is denied by the security manager
or this is a constructor for java.lang.ClassConstructor provides information about, and access to, a single
constructor for a class.
Constructor provides information about, and access to, a single
constructor for a class.
Constructor permits widening conversions to occur when matching the
actual parameters to newInstance() with the underlying
constructor's formal parameters, but throws an
IllegalArgumentException if a narrowing conversion would occur.
Constructor object that reflects the specified
constructor of the class represented by this
Class object. The parameterTypes parameter is
an array of Class objects that identify the constructor's
formal parameter types, in declared order.
If this Class object represents an inner class
declared in a non-static context, the formal parameter types
include the explicit enclosing instance as the first parameter.Constructor object that reflects the specified
constructor of the class represented by this
Class object. The parameterTypes parameter is
an array of Class objects that identify the constructor's
formal parameter types, in declared order.
If this Class object represents an inner class
declared in a non-static context, the formal parameter types
include the explicit enclosing instance as the first parameter.parameterTypes - the parameter arrayConstructor object for the constructor with the
specified parameter listNoSuchMethodException - if a matching constructor is not found,
including when this Class object represents
an interface, a primitive type, an array class, or void.SecurityException - If a security manager, s, is present and any of the
following conditions is met:
s.checkPermission method with
RuntimePermission("accessDeclaredMembers")
denies access to the declared constructor
s.checkPackageAccess() denies access to the package
of this class
String class represents character strings. All
string literals in Java programs, such as "abc", are
implemented as instances of this class.
String class represents character strings. All
string literals in Java programs, such as "abc", are
implemented as instances of this class.
Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared. For example:
String str = "abc";
is equivalent to:
char data[] = {'a', 'b', 'c'};
String str = new String(data);
Here are some more examples of how strings can be used:
System.out.println("abc");
String cde = "cde";
System.out.println("abc" + cde);
String c = "abc".substring(2, 3);
String d = cde.substring(1, 2);
The class String includes methods for examining
individual characters of the sequence, for comparing strings, for
searching strings, for extracting substrings, and for creating a
copy of a string with all characters translated to uppercase or to
lowercase. Case mapping is based on the Unicode Standard version
specified by the Character class.
The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings. For additional information on string concatenation and conversion, see The Java Language Specification.
Unless otherwise noted, passing a null argument to a constructor
or method in this class will cause a NullPointerException to be
thrown.
A String represents a string in the UTF-16 format
in which supplementary characters are represented by surrogate
pairs (see the section Unicode
Character Representations in the Character class for
more information).
Index values refer to char code units, so a supplementary
character uses two positions in a String.
The String class provides methods for dealing with
Unicode code points (i.e., characters), in addition to those for
dealing with Unicode code units (i.e., char values).
Unless otherwise noted, methods for comparing Strings do not take locale
into account. The Collator class provides methods for
finer-grain, locale-sensitive String comparison.
javac compiler
may implement the operator with StringBuffer, StringBuilder,
or java.lang.invoke.StringConcatFactory depending on the JDK version. The
implementation of string conversion is typically through the method toString,
defined by Object and inherited by all classes in Java.Method provides information about, and access to, a single method
on a class or interface. The reflected method may be a class method
or an instance method (including an abstract method).
Method provides information about, and access to, a single method
on a class or interface. The reflected method may be a class method
or an instance method (including an abstract method).
A Method permits widening conversions to occur when matching the
actual parameters to invoke with the underlying method's formal
parameters, but it throws an IllegalArgumentException if a
narrowing conversion would occur.
Method objects reflecting all the
declared methods of the class or interface represented by this
Class object, including public, protected, default (package)
access, and private methods, but excluding inherited methods.
The declared methods may include methods not in the
source of the class or interface, including bridge methods and other synthetic methods added by compilers.
Method objects reflecting all the
declared methods of the class or interface represented by this
Class object, including public, protected, default (package)
access, and private methods, but excluding inherited methods.
The declared methods may include methods not in the
source of the class or interface, including bridge methods and other synthetic methods added by compilers.
If this Class object represents a class or interface that
has multiple declared methods with the same name and parameter types,
but different return types, then the returned array has a Method
object for each such method.
If this Class object represents a class or interface that
has a class initialization method <clinit>, then the returned
array does not have a corresponding Method object.
If this Class object represents a class or interface with no
declared methods, then the returned array has length 0.
If this Class object represents an array type, a primitive
type, or void, then the returned array has length 0.
The elements in the returned array are not sorted and are not in any particular order.
Method objects representing all the
declared methods of this classSecurityException - If a security manager, s, is present and any of the
following conditions is met:
s.checkPermission method with
RuntimePermission("accessDeclaredMembers")
denies access to the declared methods within this class
s.checkPackageAccess() denies access to the package
of this class
Method
object, as a String.Method
object, as a String.getName in interface MembergetName in class Executableprint(boolean) and then
println().print(boolean) and then
println().x - The boolean to be printedObjects of class Class are unique.
Objects of class Class are unique.
Object. The returned
Class object is the object that is locked by
static synchronized methods of the represented class.
Object. The returned
Class object is the object that is locked by
static synchronized methods of the represented class.
The actual result type is Class<? extends |X|>
where |X| is the erasure of the static type of the
expression on which getClass is called. For
example, no cast is required in this code fragment:
Number n = 0;
Class<? extends Number> c = n.getClass();
Class object that represents the runtime
class of this object.This is a class literal. It's a kind of literal value formed by taking a type name and appending .class to it.
A class literal refers to the object of type Class that represents the type. Because there is no ambiguity about
the value referred to by a class literal, use of the type wildcard is not necessary.
This is a class literal. It's a kind of literal value formed by taking a type name and appending .class to it.
A class literal refers to the object of type Class that represents the type. Because there is no ambiguity about
the value referred to by a class literal, use of the type wildcard is not necessary.
print(String) and then
println().print(String) and then
println().x - The String to be printed.Console.charset() if the Console exists,
stdout.encoding otherwise.
Console.charset() if the Console exists,
stdout.encoding otherwise.
For simple stand-alone Java applications, a typical way to write a line of output data is:
System.out.println(data)
See the println methods in class PrintStream.
System class contains several useful class fields
and methods. It cannot be instantiated.
Among the facilities provided by the System class
are standard input, standard output, and error output streams;
access to externally defined properties and environment
variables; a means of loading files and libraries; and a utility
method for quickly copying a portion of an array.System class contains several useful class fields
and methods. It cannot be instantiated.
Among the facilities provided by the System class
are standard input, standard output, and error output streams;
access to externally defined properties and environment
variables; a means of loading files and libraries; and a utility
method for quickly copying a portion of an array.Class object.
Class object.
If this Class object represents a class or interface,
not an array class, then:
N + '/' + <suffix>
where N is the binary name
indicated by the class file passed to
Lookup::defineHiddenClass, and <suffix> is an unqualified name.
If this Class object represents an array class, then
the result is a string consisting of one or more '[' characters
representing the depth of the array nesting, followed by the element
type as encoded using the following table:
Element Type Encoding booleanZbyteBcharCclass or interface with binary name N LN;doubleDfloatFintIlongJshortS
If this Class object represents a primitive type or void,
then the result is a string with the same spelling as the Java language
keyword which corresponds to the primitive type or void.
Examples:
String.class.getName()
returns "java.lang.String"
byte.class.getName()
returns "byte"
(new Object[3]).getClass().getName()
returns "[Ljava.lang.Object;"
(new int[3][4][5][6][7][8][9]).getClass().getName()
returns "[[[[[[[I"
Class object.Class object associated with the class or
interface with the given string name. Invoking this method is
equivalent to:
Class object associated with the class or
interface with the given string name. Invoking this method is
equivalent to:
Class.forName(className, true, currentLoader)
where currentLoader denotes the defining class loader of
the current class.
For example, the following code fragment returns the
runtime Class descriptor for the class named
java.lang.Thread:
Class t = Class.forName("java.lang.Thread")
A call to forName("X") causes the class named
X to be initialized.
In cases where this method is called from a context where there is no caller frame on the stack (e.g. when called directly from a JNI attached thread), the system class loader is used.
className - the fully qualified name of the desired class.Class object for the class with the
specified name.LinkageError - if the linkage failsExceptionInInitializerError - if the initialization provoked
by this method failsClassNotFoundException - if the class cannot be locatedClass represent classes and
interfaces in a running Java application. An enum class and a record
class are kinds of class; an annotation interface is a kind of
interface. Every array also belongs to a class that is reflected as
a Class object that is shared by all arrays with the same
element type and number of dimensions. The primitive Java types
(boolean, byte, char, short,
int, long, float, and double), and the
keyword void are also represented as Class objects.
Class represent classes and
interfaces in a running Java application. An enum class and a record
class are kinds of class; an annotation interface is a kind of
interface. Every array also belongs to a class that is reflected as
a Class object that is shared by all arrays with the same
element type and number of dimensions. The primitive Java types
(boolean, byte, char, short,
int, long, float, and double), and the
keyword void are also represented as Class objects.
Class has no public constructor. Instead a Class
object is constructed automatically by the Java Virtual Machine when
a class is derived from the bytes of a class file through
the invocation of one of the following methods:
ClassLoader::defineClass
java.lang.invoke.MethodHandles.Lookup::defineClass
java.lang.invoke.MethodHandles.Lookup::defineHiddenClass
The methods of class Class expose many characteristics of a
class or interface. Most characteristics are derived from the class
file that the class loader passed to the Java Virtual Machine or
from the class file passed to Lookup::defineClass
or Lookup::defineHiddenClass.
A few characteristics are determined by the class loading environment
at run time, such as the module returned by getModule().
The following example uses a Class object to print the
class name of an object:
void printClassName(Object obj) {
System.out.println("The class of " + obj +
" is " + obj.getClass().getName());
}
It is also possible to get the Class object for a named
class or interface (or for void) using a class literal.
For example:
System.out.println("The name of class Foo is: "+Foo.class.getName());
Some methods of class Class expose whether the declaration of
a class or interface in Java source code was enclosed within
another declaration. Other methods describe how a class or interface
is situated in a nest. A nest is a set of
classes and interfaces, in the same run-time package, that
allow mutual access to their private members.
The classes and interfaces are known as nestmates.
One nestmate acts as the
nest host, and enumerates the other nestmates which
belong to the nest; each of them in turn records it as the nest host.
The classes and interfaces which belong to a nest, including its host, are
determined when
class files are generated, for example, a Java compiler
will typically record a top-level class as the host of a nest where the
other members are the classes and interfaces whose declarations are
enclosed within the top-level class declaration.
A class or interface created by the invocation of
Lookup::defineHiddenClass is a hidden
class or interface.
All kinds of class, including enum classes and record classes, may be
hidden classes; all kinds of interface, including annotation interfaces,
may be hidden interfaces.
The name of a hidden class or interface is
not a binary name,
which means the following:
Class::describeConstable,
ClassDesc::of, or
ClassDesc::ofDescriptor.
Class::forName
or ClassLoader::loadClass.
Class.forName method in class Class.
findSystemClass method in class
ClassLoader .
loadClass method in class ClassLoader.
but no definition for the class with the specified name could be found.
Throwable object on the error output stream that is
the value of the field System.err. The first line of
output contains the result of the toString() method for
this object. Remaining lines represent data previously recorded by
the method fillInStackTrace(). The format of this
information depends on the implementation, but the following
example may be regarded as typical:
Throwable object on the error output stream that is
the value of the field System.err. The first line of
output contains the result of the toString() method for
this object. Remaining lines represent data previously recorded by
the method fillInStackTrace(). The format of this
information depends on the implementation, but the following
example may be regarded as typical:
java.lang.NullPointerException
at MyClass.mash(MyClass.java:9)
at MyClass.crunch(MyClass.java:6)
at MyClass.main(MyClass.java:3)
This example was produced by running the program:
class MyClass {
public static void main(String[] args) {
crunch(null);
}
static void crunch(int[] a) {
mash(a);
}
static void mash(int[] b) {
System.out.println(b[0]);
}
}
The backtrace for a throwable with an initialized, non-null cause
should generally include the backtrace for the cause. The format
of this information depends on the implementation, but the following
example may be regarded as typical:
HighLevelException: MidLevelException: LowLevelException
at Junk.a(Junk.java:13)
at Junk.main(Junk.java:4)
Caused by: MidLevelException: LowLevelException
at Junk.c(Junk.java:23)
at Junk.b(Junk.java:17)
at Junk.a(Junk.java:11)
... 1 more
Caused by: LowLevelException
at Junk.e(Junk.java:30)
at Junk.d(Junk.java:27)
at Junk.c(Junk.java:21)
... 3 more
Note the presence of lines containing the characters "...".
These lines indicate that the remainder of the stack trace for this
exception matches the indicated number of frames from the bottom of the
stack trace of the exception that was caused by this exception (the
"enclosing" exception). This shorthand can greatly reduce the length
of the output in the common case where a wrapped exception is thrown
from the same method as the "causative exception" is caught. The above
example was produced by running the program:
public class Junk {
public static void main(String args[]) {
try {
a();
} catch(HighLevelException e) {
e.printStackTrace();
}
}
static void a() throws HighLevelException {
try {
b();
} catch(MidLevelException e) {
throw new HighLevelException(e);
}
}
static void b() throws MidLevelException {
c();
}
static void c() throws MidLevelException {
try {
d();
} catch(LowLevelException e) {
throw new MidLevelException(e);
}
}
static void d() throws LowLevelException {
e();
}
static void e() throws LowLevelException {
throw new LowLevelException();
}
}
class HighLevelException extends Exception {
HighLevelException(Throwable cause) { super(cause); }
}
class MidLevelException extends Exception {
MidLevelException(Throwable cause) { super(cause); }
}
class LowLevelException extends Exception {
}
As of release 7, the platform supports the notion of
suppressed exceptions (in conjunction with the
try-with-resources statement). Any exceptions that were
suppressed in order to deliver an exception are printed out
beneath the stack trace. The format of this information
depends on the implementation, but the following example may be
regarded as typical:
Exception in thread "main" java.lang.Exception: Something happened
at Foo.bar(Foo.java:10)
at Foo.main(Foo.java:5)
Suppressed: Resource$CloseFailException: Resource ID = 0
at Resource.close(Resource.java:26)
at Foo.bar(Foo.java:9)
... 1 more
Note that the "... n more" notation is used on suppressed exceptions
just as it is used on causes. Unlike causes, suppressed exceptions are
indented beyond their "containing exceptions."
An exception can have both a cause and one or more suppressed exceptions:
Exception in thread "main" java.lang.Exception: Main block
at Foo3.main(Foo3.java:7)
Suppressed: Resource$CloseFailException: Resource ID = 2
at Resource.close(Resource.java:26)
at Foo3.main(Foo3.java:5)
Suppressed: Resource$CloseFailException: Resource ID = 1
at Resource.close(Resource.java:26)
at Foo3.main(Foo3.java:5)
Caused by: java.lang.Exception: I did it
at Foo3.main(Foo3.java:8)
Likewise, a suppressed exception can have a cause:
Exception in thread "main" java.lang.Exception: Main block
at Foo4.main(Foo4.java:6)
Suppressed: Resource2$CloseFailException: Resource ID = 1
at Resource2.close(Resource2.java:20)
at Foo4.main(Foo4.java:5)
Caused by: java.lang.Exception: Rats, you caught me
at Resource2$CloseFailException.<init>(Resource2.java:45)
... 2 more
print(String) and then
println().print(String) and then
println().x - The Object to be printed.accessible flag for this reflected object to
the indicated boolean value. A value of true indicates that
the reflected object should suppress checks for Java language access
control when it is used. A value of false indicates that
the reflected object should enforce checks for Java language access
control when it is used, with the variation noted in the class description.
accessible flag for this reflected object to
the indicated boolean value. A value of true indicates that
the reflected object should suppress checks for Java language access
control when it is used. A value of false indicates that
the reflected object should enforce checks for Java language access
control when it is used, with the variation noted in the class description.
This method may be used by a caller in class C to enable
access to a member of declaring class D if any of the following hold:
C and D are in the same module. public and D is public in
a package that the module containing D exports to at least the module
containing C. protected static, D is
public in a package that the module containing D
exports to at least the module containing C, and C
is a subclass of D. D is in a package that the module containing D
opens to at least the module
containing C.
All packages in unnamed and open modules are open to all modules and
so this method always succeeds when D is in an unnamed or
open module. This method may be used by JNI code
with no caller class on the stack to enable access to a member
of declaring class D if and only if:
public and D is public in
a package that the module containing D exports unconditionally. This method cannot be used to enable access to private members, members with default (package) access, protected instance members, or protected constructors when the declaring class is in a different module to the caller and the package containing the declaring class is not open to the caller's module.
This method cannot be used to enable write access to a non-modifiable final field. The following fields are non-modifiable:
The accessible flag when true suppresses Java language access
control checks to only enable read access to
these non-modifiable final fields.
If there is a security manager, its
checkPermission method is first called with a
ReflectPermission("suppressAccessChecks") permission.
setAccessible in class AccessibleObjectflag - the new value for the accessible flagInaccessibleObjectException - if access cannot be enabledSecurityException - if the request is denied by the security managerField provides information about, and dynamic access to, a
single field of a class or an interface. The reflected field may
be a class (static) field or an instance field.
Field provides information about, and dynamic access to, a
single field of a class or an interface. The reflected field may
be a class (static) field or an instance field.
A Field permits widening conversions to occur during a get or
set access operation, but throws an IllegalArgumentException if a
narrowing conversion would occur.
Note how setting a field via reflection requires, as first argument,
the instance on which the field is set. This is because the rankField object
represents the field of a class, not the field of an instance.
Field object on the
specified object argument to the specified new value. The new
value is automatically unwrapped if the underlying field has a
primitive type.
Note how setting a field via reflection requires, as first argument,
the instance on which the field is set. This is because the rankField object
represents the field of a class, not the field of an instance.
Field object on the
specified object argument to the specified new value. The new
value is automatically unwrapped if the underlying field has a
primitive type.
The operation proceeds as follows:
If the underlying field is static, the obj argument is
ignored; it may be null.
Otherwise the underlying field is an instance field. If the
specified object argument is null, the method throws a
NullPointerException. If the specified object argument is not
an instance of the class or interface declaring the underlying
field, the method throws an IllegalArgumentException.
If this Field object is enforcing Java language access control, and
the underlying field is inaccessible, the method throws an
IllegalAccessException.
If the underlying field is final, this Field object has
write access if and only if the following conditions are met:
setAccessible(true) has succeeded for
this Field object;IllegalAccessException.
Setting a final field in this way is meaningful only during deserialization or reconstruction of instances of classes with blank final fields, before they are made available for access by other parts of a program. Use in any other context may have unpredictable effects, including cases in which other parts of a program continue to use the original value of this field.
If the underlying field is of a primitive type, an unwrapping
conversion is attempted to convert the new value to a value of
a primitive type. If this attempt fails, the method throws an
IllegalArgumentException.
If, after possible unwrapping, the new value cannot be
converted to the type of the underlying field by an identity or
widening conversion, the method throws an
IllegalArgumentException.
If the underlying field is static, the class that declared the field is initialized if it has not already been initialized.
The field is set to the possibly unwrapped and widened new value.
If the field is hidden in the type of obj,
the field's value is set according to the preceding rules.
obj - the object whose field should be modifiedvalue - the new value for the field of obj
being modifiedIllegalAccessException - if this Field object
is enforcing Java language access control and the underlying
field is inaccessible or final;
or if this Field object has no write access.IllegalArgumentException - if the specified object is not an
instance of the class or interface declaring the underlying
field (or a subclass or implementor thereof),
or if an unwrapping conversion fails.NullPointerException - if the specified object is null
and the field is an instance field.ExceptionInInitializerError - if the initialization provoked
by this method fails.With getClass, it is necessary to use a type wildcard becase of polymorphism.
A reference to an object stored in variable card could technically be of
a subtype of class Card (if one existed). To be more specific, it is also
possible to use a bounded wildcard here: Class<? extends Card>.
Class represent classes and
interfaces in a running Java application. An enum class and a record
class are kinds of class; an annotation interface is a kind of
interface. Every array also belongs to a class that is reflected as
a Class object that is shared by all arrays with the same
element type and number of dimensions. The primitive Java types
(boolean, byte, char, short,
int, long, float, and double), and the
keyword void are also represented as Class objects.
With getClass, it is necessary to use a type wildcard becase of polymorphism.
A reference to an object stored in variable card could technically be of
a subtype of class Card (if one existed). To be more specific, it is also
possible to use a bounded wildcard here: Class<? extends Card>.
Class represent classes and
interfaces in a running Java application. An enum class and a record
class are kinds of class; an annotation interface is a kind of
interface. Every array also belongs to a class that is reflected as
a Class object that is shared by all arrays with the same
element type and number of dimensions. The primitive Java types
(boolean, byte, char, short,
int, long, float, and double), and the
keyword void are also represented as Class objects.
Class has no public constructor. Instead a Class
object is constructed automatically by the Java Virtual Machine when
a class is derived from the bytes of a class file through
the invocation of one of the following methods:
ClassLoader::defineClass
java.lang.invoke.MethodHandles.Lookup::defineClass
java.lang.invoke.MethodHandles.Lookup::defineHiddenClass
The methods of class Class expose many characteristics of a
class or interface. Most characteristics are derived from the class
file that the class loader passed to the Java Virtual Machine or
from the class file passed to Lookup::defineClass
or Lookup::defineHiddenClass.
A few characteristics are determined by the class loading environment
at run time, such as the module returned by getModule().
The following example uses a Class object to print the
class name of an object:
void printClassName(Object obj) {
System.out.println("The class of " + obj +
" is " + obj.getClass().getName());
}
It is also possible to get the Class object for a named
class or interface (or for void) using a class literal.
For example:
System.out.println("The name of class Foo is: "+Foo.class.getName());
Some methods of class Class expose whether the declaration of
a class or interface in Java source code was enclosed within
another declaration. Other methods describe how a class or interface
is situated in a nest. A nest is a set of
classes and interfaces, in the same run-time package, that
allow mutual access to their private members.
The classes and interfaces are known as nestmates.
One nestmate acts as the
nest host, and enumerates the other nestmates which
belong to the nest; each of them in turn records it as the nest host.
The classes and interfaces which belong to a nest, including its host, are
determined when
class files are generated, for example, a Java compiler
will typically record a top-level class as the host of a nest where the
other members are the classes and interfaces whose declarations are
enclosed within the top-level class declaration.
A class or interface created by the invocation of
Lookup::defineHiddenClass is a hidden
class or interface.
All kinds of class, including enum classes and record classes, may be
hidden classes; all kinds of interface, including annotation interfaces,
may be hidden interfaces.
The name of a hidden class or interface is
not a binary name,
which means the following:
Class::describeConstable,
ClassDesc::of, or
ClassDesc::ofDescriptor.
Class::forName
or ClassLoader::loadClass.
Class.The ? character used in place of a type represents the type wildcard.
In practice, this means a specific, but unknown, type. Use of the type
wildcard is necessary with forName to avoid an unchecked cast warning,
because forName cannot guarantee that the resulting object will represent
a specific type parameter.
Class represent classes and
interfaces in a running Java application. An enum class and a record
class are kinds of class; an annotation interface is a kind of
interface. Every array also belongs to a class that is reflected as
a Class object that is shared by all arrays with the same
element type and number of dimensions. The primitive Java types
(boolean, byte, char, short,
int, long, float, and double), and the
keyword void are also represented as Class objects.
The ? character used in place of a type represents the type wildcard.
In practice, this means a specific, but unknown, type. Use of the type
wildcard is necessary with forName to avoid an unchecked cast warning,
because forName cannot guarantee that the resulting object will represent
a specific type parameter.
Class represent classes and
interfaces in a running Java application. An enum class and a record
class are kinds of class; an annotation interface is a kind of
interface. Every array also belongs to a class that is reflected as
a Class object that is shared by all arrays with the same
element type and number of dimensions. The primitive Java types
(boolean, byte, char, short,
int, long, float, and double), and the
keyword void are also represented as Class objects.
Class has no public constructor. Instead a Class
object is constructed automatically by the Java Virtual Machine when
a class is derived from the bytes of a class file through
the invocation of one of the following methods:
ClassLoader::defineClass
java.lang.invoke.MethodHandles.Lookup::defineClass
java.lang.invoke.MethodHandles.Lookup::defineHiddenClass
The methods of class Class expose many characteristics of a
class or interface. Most characteristics are derived from the class
file that the class loader passed to the Java Virtual Machine or
from the class file passed to Lookup::defineClass
or Lookup::defineHiddenClass.
A few characteristics are determined by the class loading environment
at run time, such as the module returned by getModule().
The following example uses a Class object to print the
class name of an object:
void printClassName(Object obj) {
System.out.println("The class of " + obj +
" is " + obj.getClass().getName());
}
It is also possible to get the Class object for a named
class or interface (or for void) using a class literal.
For example:
System.out.println("The name of class Foo is: "+Foo.class.getName());
Some methods of class Class expose whether the declaration of
a class or interface in Java source code was enclosed within
another declaration. Other methods describe how a class or interface
is situated in a nest. A nest is a set of
classes and interfaces, in the same run-time package, that
allow mutual access to their private members.
The classes and interfaces are known as nestmates.
One nestmate acts as the
nest host, and enumerates the other nestmates which
belong to the nest; each of them in turn records it as the nest host.
The classes and interfaces which belong to a nest, including its host, are
determined when
class files are generated, for example, a Java compiler
will typically record a top-level class as the host of a nest where the
other members are the classes and interfaces whose declarations are
enclosed within the top-level class declaration.
A class or interface created by the invocation of
Lookup::defineHiddenClass is a hidden
class or interface.
All kinds of class, including enum classes and record classes, may be
hidden classes; all kinds of interface, including annotation interfaces,
may be hidden interfaces.
The name of a hidden class or interface is
not a binary name,
which means the following:
Class::describeConstable,
ClassDesc::of, or
ClassDesc::ofDescriptor.
Class::forName
or ClassLoader::loadClass.
Class.Chapter 5, insight #6
Metaprogramming is a powerful language feature that allows you to write code to analyze other code. However, it must be used with care in production code, because it is prone to run-time errors
Chapter 5, insight #6
Metaprogramming is a powerful language feature that allows you to write code to analyze other code. However, it must be used with care in production code, because it is prone to run-time errors