/*******************************************************************************
* 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 null
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 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 AccessibleObject
flag
- 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.Class
Constructor
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 Member
getName
in class Executable
print(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 boolean
Z
byte
B
char
C
class or interface with binary name N L
N;
double
D
float
F
int
I
long
J
short
S
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:
It is also possible to get thevoid printClassName(Object obj) { System.out.println("The class of " + obj + " is " + obj.getClass().getName()); }
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:
This example was produced by running the program:java.lang.NullPointerException at MyClass.mash(MyClass.java:9) at MyClass.crunch(MyClass.java:6) at MyClass.main(MyClass.java:3)
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 moreNote 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 moreNote 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 AccessibleObject
flag
- 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:
It is also possible to get thevoid printClassName(Object obj) { System.out.println("The class of " + obj + " is " + obj.getClass().getName()); }
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:
It is also possible to get thevoid printClassName(Object obj) { System.out.println("The class of " + obj + " is " + obj.getClass().getName()); }
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