目录
一、获取 Class 实例
1.1 、直接通过一个 class 的静态变量class获取
1.2、如果有一个实例变量,通过该实例变量提供的 getClasss() 方法获取
1.3、知道一个 class 的完整类名,通过Class.forName()获取
二、访问字段
三、调用方法
3.1、 普通方法调用
3.2、 静态方法调用
3.3、 非 public 方法调用
3.4、 多态方法调用
四、调用构造方法
通过 Class 实例获取 class 信息的方法称为反射(Reflection)。
由于 JVM 为每个加载的类创建了对应的类实例,并在实例中保存了该类的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等。因此,如果获得了某个类实例,就可以通过这个类实例取到实例对应的类的所有信息。
获取一个 class 的 Class 实例三种方法:
Class clazz = String.class;
如果有一个实例变量,可以通过该实例变量提供的 getClass() 方法获取
String str = "hello world";
Class clazz = str.getClass();
Class.forName()
获取 Class clazz = Class.forName("java.lang.String");
因为Class实例在JVM中是唯一的,所以,上述方法获取的Class实例是同一个实例。可以用==比较两个Class实例:
public class Main {public static void main(String[] args) throws Exception {Class clazz1 = String.class;String str = "Hello world";Class clazz2 = str.getClass();Class clazz3 = Class.forName("java.lang.String");System.out.println(clazz1 == clazz2); //trueSystem.out.println(clazz1 == clazz3); //trueSystem.out.println(clazz2 == clazz3);//true}}
class 实例比较和 instanceof 的差别:
public class Main {public static void main(String[] args) throws Exception {Integer n = new Integer(123);boolean b1 = n instanceof Integer; // true,因为n是Integer类型boolean b2 = n instanceof Number; // true,因为n是Number类型的子类boolean b3 = n.getClass() == Integer.class; // true,因为n.getClass()返回Integer.classboolean b4 = n.getClass() == Number.class; // false,因为Integer.class!=Number.class}}
用 instanceof 不但匹配指定类型,还匹配指定类型的子类,而用 == 判断class 实例可以精确地判断数据类型,但不能作为比较子类型比较。
通常情况,用 instanceof 判断数据类型,应为面向抽象编程地时候,不关心具体地子类型。只有在需要精确判断一个类型是不是某个 class 的时候,才使用 == 判断 class 实例。
反射的目的是为了获取某个实例的信息,因为当拿到某个 object 实例时,可以通过反射获取 object 的 class 信息。
例如获取到一个 Class 实例 ,就可以通过该 Class 实例来创建对应类型的实例:
public class Main {public static void main(String[] args) throws Exception{// 获取String的Class实例:Class cls = String.class;// 创建一个String实例:String s = (String) cls.newInstance();}
}
上述代码相当于 new String()。 通过 Class.newInstance 可以创建实例,它的局限性是只能调用 public 的无参构造方法。带参数的构造方法或者非 public 的构造方法都无法通过 Class.newInstance() 被调用。
动态加载
JVM 在执行 Java 程序的时候,并不是一次性把所有用到的 class 全部加载到内存,而是第一次需要用到 class 时才加载。例如:
// Main.java
public class Main {public static void main(String[] args) {if (args.length > 0) {create(args[0]);}}static void create(String name) {Person p = new Person(name);}
}
当执行Main.java 时,由于用到 Main, JVM会把 Main.class 加载到内存。然后,并不会加载 Person.class ,除非程序执行到 create() 方法, JVM 发现需要加载 Person 类时,才会首次加载 Person.class 。如果没有加载 create() 方法,那么 Person.class 就不会被加载。这就是 JVM 动态加载 class 的特性。
Class 类扩展方法
方法 | 描述 |
String toGenericString() | 返回一个描述这个类的字符串信息,包含修饰符和类型参数的信息 |
forName(String className) | 根据类的完整路径返回Class对象 |
forName(String name, boolean initialize,ClassLoader loader) | 根据类的完整路径返回Class对象 |
T newInstance() | 创建类的实例 |
boolean isInstance(Object obj) | 判断是否是类的实例 |
boolean isAssignableFrom(Class> cls) | 判断当前的Class对象所表示的类,是不是参数中传递的Class对象所表示的类的父类 |
boolean isInterface() | 判断是否接口 |
boolean isPrimitive() | 判断是否为原始基本类型(例如int、char、long..) |
boolean isAnnotation() | 判断是否注解类型 |
boolean isSynthetic() | 判断是的合成类 Java冷门基础知识isSynthetic方法的详细解析_看着不像程序猿的程序员_新浪博客 |
String getName() | 获取类名称 |
getClassLoader() | 获取加载器 |
Class super T> getSuperclass() | 获取父类 |
Type getGenericSuperclass() | 获取直接父类,并且父类的泛型类型也会返回 |
Package getPackage() | 获取包名 |
Class>[] getInterfaces() | 获得这个对象所实现的所有接口 |
Type[] getGenericInterfaces() | 获得这个对象所实现的所有接口并且返回接口泛型 |
Class> getComponentType() | 获取一个数组的Class对象 |
int getModifiers() | 获取修饰符 |
Object[] getSigners() | 返回类的签名者 |
Method getEnclosingMethod() | 当此Class对象表示方法内部的本地或匿名类时,使用getEnclosingMethod()方法返回基础类的最新封闭方法 |
Constructor> getEnclosingConstructor() | 如果此类是在该构造函数中声明的本地类或匿名类,则方法返回此类的封闭构造函数 |
Class> getDeclaringClass() | 返回表示在它被声明的类的Class对象,如果此Class对象所表示的类或接口是另一个类成员 |
Class> getEnclosingClass() | 返回底层的直接外围类。如果底层类是顶级类(Object)则返回null |
String getSimpleName() | 获取简单类名 |
String getCanonicalName() | 获取规范名称 |
boolean isAnonymousClass() | 判断是否匿名内部类 |
boolean isLocalClass() | 判断是否为本地类 |
boolean isMemberClass() | 判断是否成员类 |
Class>[] getClasses() | 返回Class 对象数组(不包含private修饰) |
Field[] getFields() | 返回公共字段(public 修饰) |
Method[] getMethods() | 返回公共方法(public 修饰) |
Constructor>[] getConstructors() | 获取构造方法(public 修饰) |
Field getField(String name) | 根据参数获取字段信息(public 修饰) |
Method getMethod(String name, Class>... parameterTypes) | 返回Method对象匹配指定名称和parameterTypes(public 修饰) |
Constructor | 返回一个 Constructor 对象,该对象反映了此 Class 对象表示的类的指定公共构造函数 |
Class>[] getDeclaredClasses() | 返回Class 对象数组 |
Field[] getDeclaredFields() | 获取类字段信息 |
Method[] getDeclaredMethods() | 获取类方法 |
Constructor>[] getDeclaredConstructors() | 获取构造方法 |
Field getDeclaredField(String name) | 根据参数获取字段信息 |
Method getDeclaredMethod(String name, Class>... parameterTypes) | 返回Method对象匹配指定名称和parameterTypes |
Constructor | 根据参数获取对应构造方法 |
InputStream getResourceAsStream(String name) | 查找具有给定名称的资源 |
java.net.URL getResource(String name) | 查找具有给定名称的资源,返回URL |
java.security.ProtectionDomain getProtectionDomain() | 返回类的 ProtectionDomain 对象 |
boolean desiredAssertionStatus() | 该方法以布尔值的形式返回该类的指定断言状态 |
boolean isEnum() | 判断是否枚举 |
T[] getEnumConstants() | 获取枚举元素 |
T cast(Object obj) | 将对象强制转换为所表示的类或接口 |
Class extends U> asSubclass(Class clazz) | 强制把Class对象转化成参数类的子类 |
AnnotatedType getAnnotatedSuperclass() | 获取当前类的父类,可以用 AnnotatedType 来描述,也就是说它们申明了泛型并且被注解标注 |
AnnotatedType[] getAnnotatedInterfaces() | 获取当前类的接口,可以用 AnnotatedType[] 来描述,也就是说它们申明了泛型并且被注解标 |
示例
import com.sun.javafx.geom.transform.Identity;import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.security.ProtectionDomain;
import java.util.HashMap;public class Main {public Integer age;private String userName;public Main() {}private Main(Integer age, String userName) {this.age = age;this.userName = userName;}public void showLong(Long l) {}private void say(Long l) {}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Main{" +"userName='" + userName + '\'' +'}';}public static void main(String[] args) {printClassInfo();}static void printClassInfo() {//返回一个描述这个类的字符串信息,包含修饰符和类型参数的信息toGenericString();//根据类的完整路径,加载类,返回Class对象clssForName();//创建类的实例newInstance();// 判断是否是类的实例isInstance();//判断当前的Class对象所表示的类,是不是参数中传递的Class对象所表示的类的父类isAssignableFrom();// 判断是否接口isInterface();// 判断是否数组isArray();//判断是否为原始基本类型(例如int、char、long..)isPrimitive();// 判断是否注解类型isAnnotation();/*** 判断是的合成类* https://blog.sina.com.cn/s/blog_1534f339a0102y88n.html**/// 获取类名称getName();// 获取加载器getClassLoader();// 获取父类(public 修饰)getSuperclass();// 获取直接父类,并且父类的泛型类型也会返回getGenericSuperclass();// 获取包名getPackage();// 获得这个对象所实现的所有接口getInterfaces();// 获得这个对象所实现的所有接口并且返回接口泛型getGenericInterfaces();// 获取一个数组的Class对象getComponentType();// 获取修饰符getModifiers();// 返回类的签名者getSigners();// 当此Class对象表示方法内部的本地或匿名类时,使用getEnclosingMethod()方法返回基础类的最新封闭方法getEnclosingMethod();// 如果此类是在该构造函数中声明的本地类或匿名类,则方法返回此类的封闭构造函数getEnclosingConstructor();//返回表示在它被声明的类的Class对象,如果此Class对象所表示的类或接口是另一个类成员getDeclaringClass();// 返回底层的直接外围类。如果底层类是顶级类(Object)则返回nullgetEnclosingClass();// 获取简单类名getSimpleName();// 获取规范名称getCanonicalName();// 判断是否匿名内部类isAnonymousClass();// 判断是否为本地类isLocalClass();// 判断是否成员类isMemberClass();// 返回Class 对象数组(不包含private修饰)getClasses();//返回公共字段(public 修饰)getFields();//返回公共方法(public 修饰)getMethods();// 获取构造方法(public 修饰)getConstructors();// 根据参数获取字段信息(public 修饰)getField();//返回Method对象匹配指定名称和parameterTypes(public 修饰)getMethod();//返回一个 Constructor 对象,该对象反映了此 Class 对象表示的类的指定公共构造函数getConstructor();//返回Class 对象数组getDeclaredClasses();// 获取类字段信息getDeclaredFields();//获取类方法getDeclaredMethods();// 获取构造方法getDeclaredConstructors();// 根据参数获取字段信息getDeclaredField();// 返回Method对象匹配指定名称和parameterTypesgetDeclaredMethod();// 根据参数获取对应构造方法getDeclaredConstructor();// 查找具有给定名称的资源getResourceAsStream();// 查找具有给定名称的资源,URLgetResource();//返回类的 ProtectionDomain 对象getProtectionDomain();//该方法以布尔值的形式返回该类的指定断言状态desiredAssertionStatus();// 判断是否枚举isEnum();// 获取枚举元素getEnumConstants();//将对象强制转换为所表示的类或接口cast();//强制把Class对象转化成参数类的子类asSubclass();// 获取当前类的父类,可以用 AnnotatedType 来描述,也就是说它们申明了泛型并且被注解标注getAnnotatedSuperclass();//获取当前类的接口,可以用 AnnotatedType[] 来描述,也就是说它们申明了泛型并且被注解标注getAnnotatedInterfaces();}//返回一个描述这个类的字符串信息,包含修饰符和类型参数的信息static void toGenericString() {Class clazz = Runnable.class;System.out.println("toGenericString: " + clazz);}// 根据类的完整路径返回与类或关联的Class对象static void clssForName() {try {// 参数:类的完整路Class clazz1 = Class.forName("Main");ClassLoader cLoader = clazz1.getClassLoader();/*** 参数一:类的完整路* 参数二 类是否初始化 true:初始化 false 不初始化* 参数三:加载器*/Class clazz2 = Class.forName("java.lang.String", true, cLoader);System.out.println("Class.forName():" + clazz1);System.out.println("Class.forName(...):" + clazz2);} catch (ClassNotFoundException e) {e.printStackTrace();}}// 创建类的实例static void newInstance() {try {Class clazz = Main.class;// 创建Main类的实例Main main = (Main) clazz.newInstance();main.setUserName("张三");System.out.println("newInstance: " + main.toString());} catch (Exception e) {}}// 判断是否属于类的实例static void isInstance() {try {Class clazz = Class.forName("Main");Class clazz1 = Class.forName("java.lang.String");// 创建Main类的实例Main main = (Main) clazz.newInstance();// 判断是否是类的实例boolean result = clazz.isInstance(main); // trueboolean result1 = clazz1.isInstance(main); // falseSystem.out.println("isInstance: result = " + result + " result1=" + result1);} catch (Exception e) {}}// 判断当前的Class对象所表示的类,是不是参数中传递的Class对象所表示的类的父类static void isAssignableFrom() {try {Class parent = Class.forName("Parent");Class Son = Class.forName("Son");//Boolean result = parent.isAssignableFrom(Son); // trueSystem.out.println("isAssignableFrom: result = " + result);} catch (Exception e) {}}// 判断是否接口static void isInterface() {try {Class demoService = Class.forName("DemoService");Boolean result = demoService.isInterface();System.out.println("isInterface: result = " + result);// true} catch (Exception e) {}}// 判断是否数组static void isArray() {Class clazz = String[].class;Boolean result = clazz.isArray();System.out.println("isInterface: result = " + result); // true}// 判断是否为原始基本类型(例如int、char、long..)static void isPrimitive() {String str = new String();Class cl1 = str.getClass();//创建并返回short-// short sh = 10;Class cl2 = short.class; // true// Class cl2 = Integer.class; // falseBoolean result = cl1.isPrimitive(); //falseBoolean result1 = cl2.isPrimitive(); //trueSystem.out.println("isPrimitive: result = " + result + " result1 = " + result1);}// 判断是否注解类型static void isAnnotation() {Class ann1 = Identity.class;Class ann2 = Deprecated.class;System.out.println("isAnnotation ann1= " + ann1.isAnnotation() + " ann2=" + ann2.isAnnotation());}//获取类名称static void getName() {Class clazz = Main.class;System.out.println("getName = " + clazz.getName());}// 获取类加载器static void getClassLoader() {Class clazz = Main.class;System.out.println("getClassLoader = " + clazz.getClassLoader());}// 获取父类static void getSuperclass() {Class clazz = Son.class;System.out.println("getSuperclass = " + clazz.getSuperclass());}// 获取直接父类static void getGenericSuperclass() {Class clazz = Son.class;System.out.println("getGenericSuperclass = " + clazz.getGenericSuperclass());}// 获取包名static void getPackage() {Class clazz = String.class;System.out.println("getPackage = " + clazz.getPackage());}// 获得这个对象所实现的所有接口static void getInterfaces() {Class clazz = DemoServiceImpl.class;Class[] arr = clazz.getInterfaces();if (null != arr && arr.length > 0) {System.out.println("getInterfaces arr = " + arr[0]);}}// 获得这个对象所实现的所有接口并且返回接口泛型static void getGenericInterfaces() {Class clazz = DemoServiceImpl.class;Type[] arr = clazz.getGenericInterfaces();if (null != arr && arr.length > 0) {System.out.println("getGenericInterfaces arr = " + arr[0]);}}// 获取一个数组的Class对象static void getComponentType() {Class clazz = String[].class;Class componentType = clazz.getComponentType();Class clazz1 = String.class;Class componentType1 = clazz1.getComponentType();System.out.println("getComponentType = " + componentType + " getComponentType=" + componentType1);}// 获取修饰符static void getModifiers() {Class clazz = Main.class;int modifiers = clazz.getModifiers();System.out.println("getModifiers = " + modifiers);}// 返回类的签名者static void getSigners() {try {Class cls = Main.class;Object[] obj = cls.getSigners();System.out.println("getSigners = " + obj);} catch (Exception ex) {System.out.println(ex.toString());}}// 当此Class对象表示方法内部的本地或匿名类时,使用getEnclosingMethod()方法返回基础类的最新封闭方法static void getEnclosingMethod() {try {Class c = (new Out()).ClassAObject().getClass();System.out.println("getEnclosingMethod() = " + c.getEnclosingMethod());} catch (Exception ex) {System.out.println(ex.toString());}}// 如果此类是在该构造函数中声明的本地类或匿名类,则方法返回此类的封闭构造函数static void getEnclosingConstructor() {try {Class c = (new Out()).c.getClass();System.out.println("getEnclosingConstructor() = " + c.getEnclosingConstructor());} catch (Exception ex) {System.out.println(ex.toString());}}// 返回这个类的声明类。static void getDeclaringClass() {Class cl = Integer.class;// It returns an array of Methods// that denotes the private, protected, public and default// Methods of the class IntegerMethod[] methods = cl.getMethods();// Traverse Integer class// for (int i = 0; i < methods.length; ++i) {Class declare_classes = methods[0].getDeclaringClass();System.out.println(" getDeclaringClass= " + declare_classes.toString());// }}/*** 返回底层直接外围类*/static void getEnclosingClass() {Class clazz = new Out().c.getClass();Class clazz1 = Object.class;System.out.println(" getEnclosingClass= " + clazz.getEnclosingClass());System.out.println(" getEnclosingClass= " + clazz1.getEnclosingClass());}// 获取简单类名static void getSimpleName() {Class clazz = String.class;System.out.println(" getSimpleName= " + clazz.getSimpleName());}// 获取规范名称static void getCanonicalName() {Class clazz = String.class;System.out.println(" getCanonicalName= " + clazz.getCanonicalName());}// 判断是否匿名类static void isAnonymousClass() {Class clazz = new HashMap() {// 匿名类}.getClass();System.out.println(" isAnonymousClass= " + clazz.isAnonymousClass());}// 判断是否为本地类static void isLocalClass() {class A {}Class clazz = A.class;Class clazz1 = Out.class;System.out.println(" isLocalClass= " + clazz.isLocalClass() + " isLocalClass=" + clazz1.isLocalClass());}// 判断是否成员类static void isMemberClass() {class A {}Class clazz = A.class;Class clazz1 = Out.class;System.out.println(" isMemberClass= " + clazz.isLocalClass() + " isMemberClass=" + clazz1.isLocalClass());}// 返回Class 对象数组static void getClasses() {Class clazz = Main.class;Class[] clazzArr = clazz.getClasses();for (int i = 0; i < clazzArr.length; i++) {System.out.println("getClasses = " + clazzArr[i].getName());}}// 返回公共字段(public 修饰)static void getFields() {Class clazz = Main.class;Field[] clazzArr = clazz.getFields();for (int i = 0; i < clazzArr.length; i++) {System.out.println("getFields = " + clazzArr[i]);}}// 返回公共方法(public 修饰)static void getMethods() {Class clazz = Main.class;Method[] clazzArr = clazz.getMethods();for (int i = 0; i < clazzArr.length; i++) {System.out.println("getMethods = " + clazzArr[i]);}}// 获取构造方法static void getConstructors() {Class clazz = Main.class;Constructor[] clazzArr = clazz.getConstructors();for (int i = 0; i < clazzArr.length; i++) {System.out.println("getConstructors = " + clazzArr[i]);}}// 根据参数获取字段信息,不包含(private 修饰)static void getField() {try {Class clazz = Main.class;Field field = clazz.getField("age");System.out.println("getField=" + field);} catch (Exception e) {}}// 返回Method对象匹配指定名称和parameterTypesstatic void getMethod() {try {Class clazz = Main.class;Class[] cArg = new Class[1];cArg[0] = Long.class;Method method = clazz.getMethod("showLong", cArg);System.out.println("getMethod=" + method.toString());} catch (Exception e) {e.printStackTrace();}}//返回一个 Constructor 对象,该对象反映了此 Class 对象表示的类的指定公共构造函数static void getConstructor() {try {Class cls[] = new Class[]{String.class};Constructor c = String.class.getConstructor(cls);System.out.println("getConstructor=" + c);} catch (Exception e) {e.printStackTrace();}}// 返回Class 对象数组static void getDeclaredClasses() {Class clazz = Main.class;Class[] clazzArr = clazz.getDeclaredClasses();for (int i = 0; i < clazzArr.length; i++) {System.out.println("getDeclaredClasses = " + clazzArr[i].getName());}}//获取类字段信息static void getDeclaredFields() {try {Class clazz = Main.class;Field[] fieldArr = clazz.getDeclaredFields();for(Field f : fieldArr){System.out.println("getDeclaredFields=" + f);}} catch (Exception e) {}}// 获取类方法static void getDeclaredMethods() {try {Class clazz = Main.class;Method[] methodArr = clazz.getDeclaredMethods();for(Method m : methodArr){System.out.println("getDeclaredMethods=" + m);}} catch (Exception e) {e.printStackTrace();}}// 获取构造方法static void getDeclaredConstructors() {try {Constructor[] cArr= Main.class.getDeclaredConstructors();for(Constructor c : cArr){System.out.println("getDeclaredConstructors=" + c);}} catch (Exception e) {e.printStackTrace();}}//根据参数获取字段信息static void getDeclaredField() {try {Class clazz = Main.class;Field field = clazz.getDeclaredField("userName");System.out.println("getDeclaredField=" + field);} catch (Exception e) {}}// 返回Method对象匹配指定名称和parameterTypesstatic void getDeclaredMethod() {try {Class clazz = Main.class;Class[] cArg = new Class[1];cArg[0] = Long.class;Method method = clazz.getDeclaredMethod("say", cArg);System.out.println("getDeclaredMethod=" + method.toString());} catch (Exception e) {e.printStackTrace();}}// 根据参数获取对应构造方法static void getDeclaredConstructor() {try {Class parameterTypes[] = {Integer.class,String.class};Constructor c = Main.class.getDeclaredConstructor(parameterTypes);System.out.println("getDeclaredConstructor=" + c);} catch (Exception e) {e.printStackTrace();}}// 查找具有给定名称的资源,返回InputStreamstatic void getResourceAsStream() {InputStream in = Main.class.getResourceAsStream("application.properties");byte[] buf = new byte[1024];int len;try {while ((len = in.read(buf)) != -1) {String s = new String(buf, 0,len,"GBK");System.out.println(s);}in.close();}catch (Exception E){}}// 查找具有给定名称的资源,返回URLstatic void getResource() {java.net.URL url = Main.class.getResource("application.properties");System.out.println("getResource = "+url);}// 返回类的 ProtectionDomain 对象static void getProtectionDomain() {ProtectionDomain protectionDomain = Main.class.getProtectionDomain();System.out.println("getProtectionDomain = "+protectionDomain);}// 该方法以布尔值的形式返回该类的指定断言状态static void desiredAssertionStatus() {boolean result = Main.class.desiredAssertionStatus();System.out.println("desiredAssertionStatus = "+result);}// 判断是否枚举static void isEnum() {boolean result = Main.class.isEnum();boolean result1 = EnumDemo.class.isEnum();System.out.println("isEnum = "+result +" isEnum="+result1);}// 获取枚举元素static void getEnumConstants() {EnumDemo[] enumDemoArr = EnumDemo.class.getEnumConstants();for(EnumDemo e:enumDemoArr){System.out.println("getEnumConstants = "+e );}}//将对象强制转换为所表示的类或接口static void cast() {Class clazz = Main.class;try {Object obj =new Main(23,"张三");if(obj instanceof Main){Main m = (Main) clazz.cast(obj);System.out.println("cast = "+m.toString() );}} catch (Exception e) {e.printStackTrace();}}// 强制把Class对象转化成参数类的子类static void asSubclass() {Class son = Son.class;Class parent = Parent.class;try {Class p = son.asSubclass(parent);System.out.println("asSubclass ="+p);} catch (Exception e) {e.printStackTrace();}}// 获取Class 类的父类注解static void getAnnotatedSuperclass() {try {Annotation[] anns = B.class.getAnnotatedSuperclass().getAnnotations();for (Annotation a : anns){System.out.println("getAnnotatedSuperclass = "+a.annotationType().getName());}}catch (Exception e) {e.printStackTrace();}}//返回一个AnnotatedType对象数组,表示使用类型来指定此Class对象表示的实体的超接口static void getAnnotatedInterfaces() {try {AnnotatedType[] anns = First.class.getAnnotatedInterfaces();for (AnnotatedType a : anns){System.out.println("getAnnotatedInterfaces = "+ a);}}catch (Exception e) {e.printStackTrace();}}public class a {}public class b {}private class c {}}class Out {public Object c;public Out() {class ClassA {};c = new ClassA();}public Object ClassAObject() {class ClassA {}return new ClassA();}
}enum EnumDemo {PAY_WX(),PAY_ALI();
}
class Grandfather {}class Parent extends Grandfather {}class Son extends Parent {}interface DemoService {}
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface First { }@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface Second { }class A { }class B extends @First @Second A { }class DemoServiceImpl implements DemoService {}
Class 类提供了以下几个方法获取字段:
示例
public class Main {public static void main(String[] args) throws Exception {Class stdClass = Student.class;// 获取public字段"score":System.out.println(stdClass.getField("score"));// 获取继承的public字段"name":System.out.println(stdClass.getField("name"));// 获取private字段"grade":System.out.println(stdClass.getDeclaredField("grade"));}
}class Student extends Person {public int score;private int grade;
}class Person {public String name;
}
控制台显示
public int Student.score
public java.lang.String Person.name
private int Student.grade
一个 Field 对象包含了一个字段的所有信息:
getName() : 返回字段名称 。例如 “name”。
getType(): 返回字段类型,也是一个 Class 示例。 例如 String.class。
getModifiers():返回字段修饰符,它是一个 int值,不同 bit 表示不同含义。
例如 String类的value字段为例,它的定义是:
public final class String {private final byte[] value;
}
用反射获取该字段的信息,代码如下:
import java.lang.reflect.Modifier;public class Main {public static void main(String[] args) throws Exception {java.lang.reflect.Field f = String.class.getDeclaredField("value");// private final char value[];f.getName(); // "value"f.getType(); // class [B 表示byte[]类型int m = f.getModifiers();Modifier.isFinal(m); // trueModifier.isPublic(m); // falseModifier.isProtected(m); // falseModifier.isPrivate(m); // trueModifier.isStatic(m); // false}
}
获取/设置字段值
import java.lang.reflect.Field;public class Main {public static void main(String[] args) throws Exception {Person p = new Person("Xiao Ming");Class c = p.getClass();Field f = c.getDeclaredField("name");f.setAccessible(true); // 别管这个字段是不是public,一律允许访问Object value = f.get(p); // 获取值System.out.println(value); // "Xiao Ming"'f.set(p, "Xiao Zhang"); // 设置值System.out.println(p.getName()); // "Xiao Hong"}
}class Person {private String name;public Person(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
setAccessible(true)可能会失败。如果JVM运行期存在SecurityManager,那么它会根据规则进行检查,有可能阻止setAccessible(true)。例如,某个SecurityManager可能不允许对java和javax开头的package的类调用setAccessible(true),这样可以保证JVM核心库的安全。
Field 类扩展方法
方法 | 描述 |
boolean isEnumConstant() | 判断是否枚举常量 |
Class> getType() | 获取字段类型,不包含泛型类型 |
Type getGenericType() | 获取字段类型 |
String toGenericString() | 返回描述这个字段的字符串 |
Object get(Object obj) | 获取字段值 |
boolean getBoolean(Object obj) | 获取 boolean 类型字段值 |
byte getByte(Object obj) | 获取 byte 类型字段值 |
char getChar(Object obj) | 获取 char 类型字段值 |
short getShort(Object obj) | 获取 short 类型字段值 |
int getInt(Object obj) | 获取 int类型字段值 |
long getLong(Object obj) | 获取 long类型字段值 |
float getFloat(Object obj) | 获取float类型字段值 |
double getDouble(Object obj) | 获取 double类型字段值 |
void set(Object obj, Object value) | 设置字段值 |
void setBoolean(Object obj, boolean z) | 设置boolean 类型字段值 |
void setByte(Object obj, byte b) | 设置 byte 类型字段值 |
void setChar(Object obj, char c) | 设置char 类型字段值 |
void setShort(Object obj, short s) | 设置short 类型字段值 |
void setInt(Object obj, int i) | 设置int类型字段值 |
void setLong(Object obj, long l) | 设置long类型字段值 |
void setFloat(Object obj, float f) | 设置float类型字段值 |
void setDouble(Object obj, double d) | 设置double类型字段值 |
AnnotatedType getAnnotatedType() | 返回一个AnnotatedType对象,该对象包含类型等信息 |
示例
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Field;
import java.lang.reflect.Type;public class Main {public static void main(String[] args) throws Exception {// 判断是否枚举常量isEnumConstant();// 获取字段类型,不包含泛型类型getType();// 获取字段类型getGenericType();// 返回描述这个字段的字符串toGenericString();// 获取/设置字段值get$set();// 获取/设置boolean 类型字段值getBoolean$setBoolean();// 获取/设置 byte 类型字段值getByte$setByte();// 获取/设置char 类型字段值getChar$setChar();// 获取/设置short 类型字段值getShort$setShort();// 获取/设置int类型字段值getInt$setInt();// 获取/设置long类型字段值getLong$setLong();// 获取/设置float类型字段值getFloat$setFloat();// 获取/设置double类型字段值getDouble$setDouble();//返回一个AnnotatedType对象,该对象包含类型等信息getAnnotatedType();}// 判断是否枚举常量static void isEnumConstant() {Class clazz = Pay.class;Field field = null;try {field = clazz.getDeclaredField("PAY");} catch (NoSuchFieldException e) {e.printStackTrace();}boolean isEnumConstant = field.isEnumConstant();System.out.println("isEnumConstant = " + isEnumConstant);}// 获取字段类型,不包含泛型类型static void getType() {Class clazz = Person.class;Field field = null;try {field = clazz.getDeclaredField("name");//field = clazz.getDeclaredField("address"); // 获取不到} catch (NoSuchFieldException e) {e.printStackTrace();}Class c = field.getType();System.out.println("getType = " + c);}static void getGenericType() {Class clazz = Person.class;Field field = null;try {field = clazz.getDeclaredField("address");} catch (NoSuchFieldException e) {e.printStackTrace();}Type c = field.getGenericType();System.out.println("getGenericType = " + c);}/*** *返回描述这个{@code字段}的字符串,包括* 其泛型类型。的访问修饰符* 字段(如果有的话),然后是泛型字段类型,然后是* 一个空格,后跟类的全限定名* 声明字段,后面跟着句号,后面跟着名称*/static void toGenericString() {Class clazz = Person.class;Field field = null;try {field = clazz.getDeclaredField("address");} catch (NoSuchFieldException e) {e.printStackTrace();}String str = field.toGenericString();System.out.println("toGenericString = " + str);}// 获取/设置 字段值static void get$set() {Person p = new Person();Class clazz = Person.class;Field field = null;try {field = clazz.getDeclaredField("name");field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问//设置字段的值field.set(p, "kevin");// 获取字段的值Object obj = field.get(p);System.out.println("get$set = " + obj);} catch (Exception e) {e.printStackTrace();}}// 获取/设置boolean 类型字段值static void getBoolean$setBoolean() {Person p = new Person();Class clazz = Person.class;Field field = null;try {field = clazz.getDeclaredField("deleteFlag");field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问// 设置字段的值field.setBoolean(p, Boolean.TRUE);// 获取字段的值boolean obj = field.getBoolean(p);System.out.println("getBoolean$setBoolean = " + obj);} catch (Exception e) {e.printStackTrace();}}// 获取/设置 byte 类型字段值static void getByte$setByte() {Person p = new Person();Class clazz = Person.class;Field field = null;try {field = clazz.getDeclaredField("byteField");field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问// 设置字段的值field.setByte(p, Byte.parseByte("3"));// 获取字段的值byte obj = field.getByte(p);System.out.println("getByte$setByte = " + obj);} catch (Exception e) {e.printStackTrace();}}//获取/设置char 类型字段值static void getChar$setChar() {Person p = new Person();Class clazz = Person.class;Field field = null;try {field = clazz.getDeclaredField("charField");field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问// 设置字段的值field.setChar(p, '2');// 获取字段的值char obj = field.getChar(p);System.out.println("getChar$setChar = " + obj);} catch (Exception e) {e.printStackTrace();}}// 获取/设置short 类型字段值static void getShort$setShort() {Person p = new Person();Class clazz = Person.class;Field field = null;try {field = clazz.getDeclaredField("shortField");field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问// 设置字段的值field.setShort(p, Short.parseShort("2"));// 获取字段的值short obj = field.getShort(p);System.out.println("getShort$setShort = " + obj);} catch (Exception e) {e.printStackTrace();}}// 获取/设置int 类型字段值static void getInt$setInt() {Person p = new Person();Class clazz = Person.class;Field field = null;try {field = clazz.getDeclaredField("intField");field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问// 设置字段的值field.setInt(p, 2);// 获取字段的值int obj = field.getInt(p);System.out.println("getInt$setInt = " + obj);} catch (Exception e) {e.printStackTrace();}}// 获取/设置 long 类型字段值static void getLong$setLong() {Person p = new Person();Class clazz = Person.class;Field field = null;try {field = clazz.getDeclaredField("longField");field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问// 设置字段值field.setLong(p, 4L);// 获取字段值long obj = field.getLong(p);System.out.println("getLong$setLong = " + obj);} catch (Exception e) {e.printStackTrace();}}// 获取/设置 float 类型字段值static void getFloat$setFloat() {Person p = new Person();Class clazz = Person.class;Field field = null;try {field = clazz.getDeclaredField("floatField");field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问// 设置字段的值field.setFloat(p, 3.0F);// 获取字段的值float obj = field.getFloat(p);System.out.println("getFloat$setFloat = " + obj);} catch (Exception e) {e.printStackTrace();}}// 获取/设置 double 类型字段值static void getDouble$setDouble() {Person p = new Person();Class clazz = Person.class;Field field = null;try {field = clazz.getDeclaredField("doubleField");field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问// 设置字段的值field.setDouble(p, 6.01);// 获取字段的值double obj = field.getDouble(p);System.out.println("getDouble$setDouble = " + obj);} catch (Exception e) {e.printStackTrace();}}// 返回一个AnnotatedType对象,该对象包含类型等信息static void getAnnotatedType() {Person p = new Person();Class clazz = Person.class;Field field = null;try {field = clazz.getDeclaredField("doubleField");field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问// 获取字段的值AnnotatedType obj = field.getAnnotatedType();System.out.println("getAnnotatedType = " + obj.getType());} catch (Exception e) {e.printStackTrace();}}}class Person {private Pay pay;private String name;private T address;private boolean deleteFlag;private byte byteField;private char charField;private short shortField;private int intField;private long longField;private float floatField;private double doubleField;public double getDoubleField() {return doubleField;}public void setDoubleField(double doubleField) {this.doubleField = doubleField;}public float getFloatField() {return floatField;}public void setFloatField(float floatField) {this.floatField = floatField;}public long getLongField() {return longField;}public void setLongField(long longField) {this.longField = longField;}public int getIntField() {return intField;}public void setIntField(int intField) {this.intField = intField;}public short getShortField() {return shortField;}public void setShortField(short shortField) {this.shortField = shortField;}public char getCharField() {return charField;}public void setCharField(char charField) {this.charField = charField;}public Person() {}public Person(String name) {this.name = name;}public Person(boolean deleteFlag) {this.deleteFlag = deleteFlag;}public String getName() {return name;}public void setName(String name) {this.name = name;}public byte getByteField() {return byteField;}public void setByteField(byte byteField) {this.byteField = byteField;}public Pay getPay() {return pay;}public void setPay(Pay pay) {this.pay = pay;}public T getAddress() {return address;}public void setAddress(T address) {this.address = address;}public boolean isDeleteFlag() {return deleteFlag;}public void setDeleteFlag(boolean deleteFlag) {this.deleteFlag = deleteFlag;}
}enum Pay {PAY
}
Class类提供了以下几个方法来获取Method
示例
public class Main {public static void main(String[] args) throws Exception {Class stdClass = Student.class;// 获取public方法getScore,参数为String:System.out.println(stdClass.getMethod("getScore", String.class));// 获取继承的public方法getName,无参数:System.out.println(stdClass.getMethod("getName"));// 获取private方法getGrade,参数为int:System.out.println(stdClass.getDeclaredMethod("getGrade", int.class));}
}class Student extends Person {public int getScore(String type) {return 99;}private int getGrade(int year) {return 1;}
}class Person {public String getName() {return "Person";}
}
控制台显示
public int Student.getScore(java.lang.String)
public java.lang.String Person.getName()
private int Student.getGrade(int)
一个 Method 对象包含一个方法的所有信息:
获取到一个Method对象时,就可以对它进行调用。代码为例:
String s = "Hello world";
String r = s.substring(6); // "world"
反射来调用substring方法,需要以下代码:
import java.lang.reflect.Method;public class Main {public static void main(String[] args) throws Exception {// String对象:String s = "Hello world";// 获取String substring(int)方法,参数为int:Method m = String.class.getMethod("substring", int.class);// 在s对象上调用该方法并获取结果:String r = (String) m.invoke(s, 6);// 打印调用结果:System.out.println(r);}
}
Method实例调用invoke就相当于调用该方法,invoke的第一个参数是对象实例,即在哪个实例上调用该方法,后面的可变参数要与方法参数一致,否则将报错。
获取到的Method表示一个静态方法,调用静态方法时,由于无需指定实例对象,所以invoke方法传入的第一个参数永远为null。以Integer.parseInt(String)为例:
import java.lang.reflect.Method;public class Main {public static void main(String[] args) throws Exception {// 获取Integer.parseInt(String)方法,参数为String:Method m = Integer.class.getMethod("parseInt", String.class);// 调用该静态方法并获取结果:Integer n = (Integer) m.invoke(null, "12345");// 打印调用结果:System.out.println(n);// 12345}
}
对于非public方法,虽然可以通过Class.getDeclaredMethod()获取该方法实例,但直接对其调用将得到一个IllegalAccessException。为了调用非public方法,我们通过Method.setAccessible(true)允许其调用:
import java.lang.reflect.Method;public class Main {public static void main(String[] args) throws Exception {Person p = new Person();Method m = p.getClass().getDeclaredMethod("setName", String.class);m.setAccessible(true);m.invoke(p, "Bob");System.out.println(p.name); // Bob}
}class Person {String name;private void setName(String name) {this.name = name;}
}
需要注意的话,setAccessible(true)可能会失败。如果JVM运行期存在SecurityManager,那么它会根据规则进行检查,有可能阻止setAccessible(true)。例如,某个SecurityManager可能不允许对java和javax开头的package的类调用setAccessible(true),这样可以保证JVM核心库的安全。
import java.lang.reflect.Method;public class Main {public static void main(String[] args) throws Exception {// 获取Person的hello方法:Method h = Person.class.getMethod("hello");// 对Student实例调用hello方法:h.invoke(new Student());}
}class Person {public void hello() {System.out.println("Person:hello");}
}class Student extends Person {public void hello() {System.out.println("Student:hello");}
}
控制台显示
Student:hello
使用反射调用方法时,仍然遵循多态原则:即总是调用实际类型的覆写方法(如果存在)。上述的反射代码:
Method m = Person.class.getMethod("hello");
m.invoke(new Student());
相当于:
Person p = new Student();
p.hello();
Method扩展方法
方法 | 描述 |
Class> getReturnType() | 获取方法返回类型 |
Type getGenericReturnType() | 获取方法返回类型,返回类型是参数化类型 |
Object invoke(Object obj, Object... args) | 调用该方法并获取结果 |
boolean isBridge() | 判断是否桥接方法 |
boolean isDefault() | 判断是否isDefault方法 |
Object getDefaultValue() | 获取默认值 |
示例
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Comparator;public class Main {public static void main(String[] args) throws Exception {// 获取方法返回类型getReturnType();// 获取方法返回类型,返回类型是参数化类型getGenericReturnType();//调用该方法并获取结果invoke();// 判断是否桥接方法isBridge();// 判断是否isDefault方法isDefault();// 获取默认值getDefaultValue();}// 获取方法返回类型static void getReturnType() {Person p = new Person();Method m = null;try {m = p.getClass().getDeclaredMethod("getName");m.setAccessible(true);Class clazz = m.getReturnType();System.out.println("getReturnType= " + clazz);} catch (NoSuchMethodException e) {e.printStackTrace();}}// 获取方法返回类型,返回类型是参数化类型static void getGenericReturnType() {Person p = new Person();Method m = null;try {m = p.getClass().getDeclaredMethod("say");m.setAccessible(true);Type clazz = m.getGenericReturnType();System.out.println("getGenericReturnType= " + clazz);} catch (NoSuchMethodException e) {e.printStackTrace();}}//调用该方法并获取结果:static void invoke() {Student p = new Student();Method m = null;try {m = p.getClass().getDeclaredMethod("setName", String.class);m.setAccessible(true);m.invoke(p, "Kevin");System.out.println("invoke= " + p.name);} catch (Exception e) {e.printStackTrace();}}// 判断是桥接方法static void isBridge() {Class classB = B.class;Method[] methods = classB.getDeclaredMethods();System.out.println("方法总数量:" + methods.length);for (Method method : methods) {System.out.println(method.getReturnType().getSimpleName() + " "+ method.getName() +"(" + method.getParameters()[0].getType().getSimpleName() + ")"+ " is " + (method.isBridge() ? "bridge" : "common") + " method");}}// 判断是否isDefault方法static void isDefault() {Class c = Comparator.class;Method[] methods = c.getMethods();for (Method method : methods) {// check whether method is Default Method or notif (method.isDefault()) {// print Method nameSystem.out.println("isDefault = " + method.getName() + " " + method.isDefault());}}}// 获取默认值static void getDefaultValue() {try {Method method = AnnotationDemo.class.getDeclaredMethod("fauvMovie");System.out.println("getDefaultValue =" + method.getDefaultValue());} catch (Exception e) {}}}@interface AnnotationDemo {public String fauvMovie() default "Inception";public double fauvMovieRating() default 9.6;public int fauvMovieReleaseYear();
}class Person {String name;private void setName(String name) {this.name = name;}public T say() {return null;}public String getName() {return name;}}class Student {String name;private void setName(String name) {this.name = name;}public String getName() {return name;}
}// 声明一个泛型接口
interface A {void test(T t);
}//泛型本身是语言级别的,经过编译后,泛型就会被擦除,所以接口 A 在编译后,test 方法的入参会被转换为 Object
//编译器编译
//public interface A {
// void test(Object t);
//}// 使用 String 类型实现一个具体的实现类
class B implements A {public void test(String s) {System.out.println(s);}
}//实现类 B 中的实现方法是 void test(String s),其实根本就没有实现 void test(Object t) 方法。但是这个代码是正确的,可以正常运行,因为 JVM 在编译过程中对我们的实现类做了一点手脚
//编译器编译
//public class B implements A {
// public void test(String s) {
// System.out.println(s);
// }
// public void test(Object s) {
// this.test((String) s);
// }
//}
通过创建对象实例:
Person p = new Person();
调用Class提供的newInstance()方法
Person p = Person.class.newInstance();
调用Class.newInstance()的局限是,它只能调用该类的public无参数构造方法。如果构造方法带有参数,或者不是public,就无法直接通过Class.newInstance()来调用。
为了调用任意的构造方法,Java的反射API提供了Constructor对象,它包含一个构造方法的所有信息,可以创建一个实例。Constructor对象和Method非常类似,不同之处仅在于它是一个构造方法,并且,调用结果总是返回实例:
import java.lang.reflect.Constructor;public class Main {public static void main(String[] args) throws Exception {// 获取构造方法Integer(int):Constructor cons1 = Integer.class.getConstructor(int.class);// 调用构造方法:Integer n1 = (Integer) cons1.newInstance(123);System.out.println(n1);// 获取构造方法Integer(String)Constructor cons2 = Integer.class.getConstructor(String.class);Integer n2 = (Integer) cons2.newInstance("456");System.out.println(n2);}
}
Class实例获取Constructor的方法如下
注意Constructor总是当前类定义的构造方法,和父类无关,因此不存在多态的问题。
调用非public的Constructor时,必须首先通过setAccessible(true)设置允许访问,setAccessible(true)可能会失败。
下一篇:GUESS验厂内容