Original link: https://www.codemore.top/cates/Backend/post/2018-04-26/reflect-class
kind
Every type in Java is either a reference type or a primitive type. Classes, enums, arrays (which they all inherit from java.lang.Object
) and interfaces are all reference types. For example: java.lang.String
, wrapper classes java.lang.Double
, interfaces java.io.Serializable
and enumerations javax.swing.Sortorder
of all primitive types are reference types. The number of primitive types is fixed: boolean
, byte
, short
, int
, long
, char
, float
, double
. For each object type, the JVM initializes an java.lang.Class
instance of it and can inspect the properties of the object at runtime, including properties and methods. Class
It is also possible to create a new class and object. Most importantly, it is the entry point for all reflection APIs.
get class object
java.lang.Class
It is the entry point for all reflection operations. java.lang.reflect
None of the classes in . have a public constructor, so in order to instantiate one of them, you need to call the appropriate Class
function.
Object.getClass()
If you can get an instance of a class, the easiest way to get Class
it is to call Object.getClass()
. Object
Of course this only applies to reference types that all inherit from . String
For example: returnedClass
Class c = "foo".getClass();
System.console()
The return is a class, so the java.io.Console
following code will knowConsole
Class
Class c = System.console().getClass();
For enumeration types, E, A is an instance of E, so what is A.getClass()
returned is E. Class
For example:
Enum E {A,B}
Class c = A.getClass();
getClass()
Because the array is also an object, it can also be obtained by calling it Class
, and the returned Class
type information with the array.
byte[] bytes = new byte[1024];
Class c = bytes.getClass();
For collection classes, the same s.getClass()
return is java.util.HashSet
related toClass
import java.util.Set
import java.util.HashSet
Set<String> s = new HashSet<String>();
Class c = s.getClass();
.class
grammar
If the type is available, but there is no instance, it can be obtained .class
by Class
. Similarly, you can also use this method to get primitive types Class
.
boolean b;
Class = b.getClass(); //编译错误
Class = boolean.class; //正确
Note that boolean.getClass()
a compilation error will occur when using it directly, because it boolean
is a primitive type and cannot be dereferenced.
Class c = java.io.PrintStream.class;
get java.io.PrintStream
relatedClass
Class c = int[][].class;
Get the associated two-digit int arrayClass
Class.forName()
Using this method requires knowing the fully qualified name of the class. Can only be applied to reference types. The fully qualified name of the array type can be Class.getName()
obtained by .
Class c = Class.forName("com.duke.MyLocaleServiceProvider");
Create a class by using the fully qualified name
Class cDoubleArray = Class.forName("[D");
Class cStringArray = Class.forName("[[Ljava.lang.String;");
cDoubleArray
Yes double[]
the Class
same double[].class
. cStringArray is the String[][].class
same.
The TYPE field of the native type wrapper class
The native type Class
can be obtained either by .class
means or through the TYPE field of the wrapper class of the native type. For void, java.lang.Void
such a field is also provided.
Class c = Double.TYPE;
Double.TYPE is equivalent todouble.class
Class c = Void.TYPE;
Equivalent tovoid.class
Methods that return Class
If it has been obtained Class
, then you can use the API in Class to get other classes and Class.getSuperClass()
return the parent class of the specified class
Class c = javax.swing.JButton.class.getSupperClass();
Return to its parent class javax.swing.AbstractButton
Class.getClasses()
to get all internal public classes, interfaces, enumerations, including itself and inherited member classes.
Class<?>[] c = Character.class.getClasses();
Returns Character
two member classes Character.Subset
and Character.UnicodeBlock
Class.getDeclearedClasses()
returns all classes, interfaces, and enumerations in the class.
Class<?>[] c Character.class.getDeclearedClasses();
Character
Two public classes Character.Subset
and Character.UnicodeBlock
one private class are returned Character.CharacterCache
. Class.getDeclearingClass()
, java.lang.reflect.Field.getDeclearingClass()
, java.lang.reflect.Method.getDeclearingClass()
, java.lang.reflect.Constructor.getDeclaringClass()
returns the class that declares these members Returns the class that declares these members. An anonymous class does not have a declaring class, it has an enclosing class.
import java.lang.reflect.Field;
Field f = System.class.getField("out");
Class c = f.getDeclaringClass();
out is declared in System.
public class MyClass{
static Object o = new Object() { public void m(){} }; static Class<c> = o.getClass().getEnclosingClass(); }
Class.getEnclosingClass()
return its enclosing class
Class c = Thread.State.class.getEnclosingClass();
The outer class Thread of Thread.State
public class MyClass {
static Object o = new Object() { public void m() {} }; static Class<c> = o.getClass().getEnclosingClass(); }
The enclosing class of the anonymous class is MyClass.
There are three main methods for obtaining Class:
Way | Scope of use |
---|---|
getClass() | Need to get an object instance, can only be used for reference types |
.class | No need to get an instance of the object, either a reference type or a primitive type |
forName () | Only the fully qualified name of the class is required |
Check for class modifiers and types
A class is declared with one or more modifiers that affect its runtime behavior:
- Access modifiers: public, private, protected
- Abstract modifier: abstract
- static modifier: static
- Immutable Modifier: final
- Force strict floating point modifier: strictfp
- Not all modifiers of annotations can be applied to all classes. For example, interface cannot use final, and enum cannot use abstract.
java.lang.reflect.Modifier
All modifier declarations are included. The methodClass.getModifiers()
can return all modifiers. The following example demonstrates how to obtain a class's modifiers, generic parameters, implementing interfaces, and integration chains. BecauseClass
of inheritancejava.lang.reflect.AnnotatedElement
, annotation information can be obtained at runtime.
import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.List; import static java.lang.System.out; public class ClassDeclarationSpy { public static void main(String[] args) { try{ Class<?> c = Class.forName(args[0]); out.format("Class:%n %s%n%n", c.getCanonicalName()); out.format("Modifier: %n %s%n%n", Modifier.toString(c.getModifiers())); out.format("Type Parameters:%n"); TypeVariable[] tv = c.getTypeParameters(); if (tv.length != 0){ out.format(" "); for (TypeVariable t : tv) out.format("%s ", t.getName()); out.format("%n%n"); }else{ out.format("-- No TypeParameter --%n%n"); } out.format("Inheritance Path:%n"); List<Class> l = new ArrayList<>(); printAncestor(c, l); if (l.size() != 0) { for (Class<?> cl : l) out.format(" %s%n", cl.getCanonicalName()); out.format("%n"); } else { out.format(" -- No Super Classes --%n%n"); } out.format("Annotations:%n"); Annotation[] ann = c.getAnnotations(); if (ann.length != 0) { for (Annotation a : ann) out.format(" %s%n", a.toString()); out.format("%n"); } else { out.format(" -- No Annotations --%n%n"); } }catch (Exception e){ e.printStackTrace(); } } private static void printAncestor(Class<?> c, List<Class> l){ Class<?> ancestor =c.getSuperclass(); if (ancestor != null){ l.add(ancestor); printAncestor(ancestor, l); } } }
run:
$ java ClassDeclarationSpy java.util.concurrent.ConcurrentNavigableMap
Class:
java.util.concurrent.ConcurrentNavigableMap
Modifiers:
public abstract interface
Type Parameters: K V Implemented Interfaces: java.util.concurrent.ConcurrentMap<K, V> java.util.NavigableMap<K, V> Inheritance Path: -- No Super Classes -- Annotations: -- No Annotations --
java.util.concrrent.ConcurrentNavigableMap
The source code is:
public interface ConcurrentNavigableMap<K,V> extends ConcurrentMap<K,V>, NavigableMap<K,V>
Note that, thinking that he is an interface, the compiler adds abstract to all interfaces by default. There are two generic types K, V. run:
$ java ClassDeclarationSpy "[Ljava.lang.String;"
Class:
java.lang.String[]
Modifiers:
public abstract final
Type Parameters:
-- No Type Parameters --
Implemented Interfaces:
interface java.lang.Cloneable interface java.io.Serializable Inheritance Path: java.lang.Object Annotations: -- No Annotations --]
get class members
There are two ways to get fields, methods, and constructors in Class, one is to get all members, and the other is to get specified members. The same way to get members is also divided into lookup from the current class and lookup from the inheritance chain. Summarized as follows: Field method
API | list all members | List inherited members | private member |
---|---|---|---|
getDeclaredField() | n | n | and |
getField() | n | and | n |
getDeclaredFields() | and | n | and |
getFields() | and | and | n |
Method method
API | list all members | List inherited members | private member |
---|---|---|---|
getDeclaredMethod() | n | n | and |
getMethod() | n | and | n |
getDeclaredMethods() | and | n | and |
getMethods() | and | and | n |
constructor method:
API | list all members | List inherited members | private member |
---|---|---|---|
getDeclaredConstructor() | n | n | and |
getConstructor() | n | n | n |
getDeclaredConstructors() | and | n | and |
getConstructors() | and | n | n |
Constructors do not inherit.
An example is as follows:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Member;
import static java.lang.System.out; enum ClassMember { CONSTRUCTOR, FIELD, METHOD, CLASS, ALL } public class ClassSpy { public static void main(String... args) { try { Class<?> c = Class.forName(args[0]); out.format("Class:%n %s%n%n", c.getCanonicalName()); Package p = c.getPackage(); out.format("Package:%n %s%n%n", (p != null ? p.getName() : "-- No Package --")); for (int i = 1; i < args.length; i++) { switch (ClassMember.valueOf(args[i])) { case CONSTRUCTOR: printMembers(c.getConstructors(), "Constructor"); break; case FIELD: printMembers(c.getFields(), "Fields"); break; case METHOD: printMembers(c.getMethods(), "Methods"); break; case CLASS: printClasses(c); break; case ALL: printMembers(c.getConstructors(), "Constuctors"); printMembers(c.getFields(), "Fields"); printMembers(c.getMethods(), "Methods"); printClasses(c); break; default: assert false; } } // production code should handle these exceptions more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } } private static void printMembers(Member[] mbrs, String s) { out.format("%s:%n", s); for (Member mbr : mbrs) { if (mbr instanceof Field) out.format(" %s%n", ((Field)mbr).toGenericString()); else if (mbr instanceof Constructor) out.format(" %s%n", ((Constructor)mbr).toGenericString()); else if (mbr instanceof Method) out.format(" %s%n", ((Method)mbr).toGenericString()); } if (mbrs.length == 0) out.format(" -- No %s --%n", s); out.format("%n"); } private static void printClasses(Class<?> c) { out.format("Classes:%n"); Class<?>[] clss = c.getClasses(); for (Class<?> cls : clss) out.format(" %s%n", cls.getCanonicalName()); if (clss.length == 0) out.format(" -- No member interfaces, classes, or enums --%n"); out.format("%n"); } }
Use as follows:
java ClassSpy ClassMember FIELD METHOD
Class:
ClassMember
Package:
-- No Package --
Fields:
public static final ClassMember ClassMember.CONSTRUCTOR
public static final ClassMember ClassMember.FIELD public static final ClassMember ClassMember.METHOD public static final ClassMember ClassMember.CLASS public static final ClassMember ClassMember.ALL Methods: public static ClassMember ClassMember.valueOf(java.lang.String) public static ClassMember[] ClassMember.values() public final int java.lang.Enum.hashCode() public final int java.lang.Enum.compareTo(E) public int java.lang.Enum.compareTo(java.lang.Object) public final java.lang.String java.lang.Enum.name() public final boolean java.lang.Enum.equals(java.lang.Object) public java.lang.String java.lang.Enum.toString() public static <T> T java.lang.Enum.valueOf (java.lang.Class<T>,java.lang.String) public final java.lang.Class<E> java.lang.Enum.getDeclaringClass() public final int java.lang.Enum.ordinal() public final native java.lang.Class<?> java.lang.Object.getClass() public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final void java.lang.Object.wait() hrows java.lang.InterruptedException public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll()
Troubleshooting
The following examples are some common problems encountered when using annotations:
Compiler Warning: "Note: ... uses unchecked or unsafe operations"
When calling a method, the parameter type is checked rather than type conversion, as in the following example:
import java.lang.reflect.Method;
public class ClassWarning { void m() { try { Class c = ClassWarning.class; Method m = c.getMethod("m"); // warning // production code should handle this exception more gracefully } catch (NoSuchMethodException x) { x.printStackTrace(); } } }
operation result:
javac ClassWarning.java
Note: ClassWarning.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
$ javac -Xlint:unchecked ClassWarning.java
ClassWarning.java:6: warning: [unchecked] unchecked call to getMethod
(String,Class<?>...) as a member of the raw type Class Method m = c.getMethod("m"); // warning ^ 1 warning
It can be solved by using generics or using annotations @SuppressWarning("unchecked")
:
Class<?> c = warn.getClass();
Class c = ClassWarning.class;
@SupressWarning("unchecked")
Method m = c.getMethod();
InstantiationException when the Constructor is Not Accessible
If a class is created through Class.newInstance(), but there is no constructor with 0 parameters, an InstantiationException will be thrown. E.g:
class Cls {
private Cls() {} } public class ClassTrouble { public static void main(String... args) { try { Class<?> c = Class.forName("Cls"); c.newInstance(); // InstantiationException // production code should handle these exceptions more gracefully } catch (InstantiationException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } catch (ClassNotFoundException x) { x.printStackTrace(); } } }
operation result:
java ClassTrouble
java.lang.IllegalAccessException: Class ClassTrouble can not access a member of
class Cls with modifiers "private" at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65) at java.lang.Class.newInstance0(Class.java:349) at java.lang.Class.newInstance(Class.java:308) at ClassTrouble.main(ClassTrouble.java:9)