Java Reflection深入理解Class对象
2018-02-22 18:18
363 查看
使用Java反射机制可以在运行时期检查Java类的信息,检查Java类的信息往往是你在使用Java反射机制的时候所做的第一件事情,
通过获取类的信息你可以获取以下相关的内容:
.Class对象
.类名
.修饰符
.包信息
.父类
.实现的接口
.构造器
.方法
.变量
.注解
除了上述这些内容,还有很多的信息你可以通过反射机制获得。
Class对象
在你想检查一个类的信息之前,你首先需要获取类的Class对象。Java中的所有类型包括基本类型(int, long, float等等),
即使是数组都有与之关联的Class类的对象。有如下三种方式获取Class对象:
以下知识点实例涉及共有代码:
MyObject.java
package com.lanhuigu.reflect.cls;
import com.lanhuigu.reflect.annotations.MyAnnotation;
@MyAnnotation(name = "testAnnoation", value = "hello world")
public class MyObject {
/** 公有变量*/
public static final String testFieldName = "test-field-name";
/** 私有变量 */
private String username;
private int age;
public MyObject () {
username = "Test1-Class";
age = 27;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}MyAnnotation.java
package com.lanhuigu.reflect.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
public String name();
public String value();
}
(1) 如果能够new某个对象,可以通过如下方式获取Class对象:
MyObject myObject = new MyObject();
Class myObjectClass = myObject.getClass();
eg:
(2) 如果你在编译期知道一个类的名字的话,那么你可以使用如下的方式获取一个类的Class对象:
Class myObjectClass = MyObject.class;
eg:
(3) 如果你在编译期不知道类的名字,但是你可以在运行期获得到类名的字符串,那么你则可以这么做来获取Class对象
String className = ... ; //在运行期获取的类名字符串
Class class = Class.forName(className);
在使用Class.forName()方法时,你必须提供一个类的全名,这个全名包括类所在的包的名字。
例如MyObject类位于com.lanhuigu.reflect.cls包,那么他的全名就是com.lanhuigu.reflect.cls.MyObject。
如果在调用Class.forName()方法时,没有在编译路径下(classpath)找到对应的类,那么将会抛出ClassNotFoundException。
eg:
类名
你可以从Class对象中获取两个版本的类名。
通过getName()方法返回类的全限定类名(包含包名):
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
String className = myClass.getName();
eg:
package com.lanhuigu.reflect.classname;
import com.lanhuigu.reflect.cls.MyObject;
/**
* 通过getName()方法返回类的全限定类名(包含包名):
* Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
* String className = myClass.getName();
*/
public class Test1 {
public static void main(String[] args) {
Class myClass = MyObject.class;
String className = myClass.getName();
System.out.println("className:" + className);
}
}
如果你仅仅只是想获取类的名字(不包含包名),那么你可以使用getSimpleName()方法:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
String simpleClassName = myClass.getSimpleName();
eg:
package com.lanhuigu.reflect.classname;
import com.lanhuigu.reflect.cls.MyObject;
/**
* 如果你仅仅只是想获取类的名字(不包含包名),那么你可以使用getSimpleName()方法:
* Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
* String simpleClassName = myClass.getSimpleName();
*/
public class Test2 {
public static void main(String[] args) {
Class myClass = MyObject.class;
String simpleClassName = myClass.getSimpleName();
System.out.println("simpleClassName:" + simpleClassName);
}
}
修饰符
可以通过Class对象来访问一个类的修饰符,即public,private,static等等的关键字,你可以使用如下方法来获取类的修饰符:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
int modifiers = myClass.getModifiers();
修饰符都被包装成一个int类型的数字,这样每个修饰符都是一个位标识(flag bit),这个位标识可以设置和清除修饰符的类型。
可以使用java.lang.reflect.Modifier类中的方法来检查修饰符的类型:
Modifier.isAbstract(int modifiers);
Modifier.isFinal(int modifiers);
Modifier.isInterface(int modifiers);
Modifier.isNative(int modifiers);
Modifier.isPrivate(int modifiers);
Modifier.isProtected(int modifiers);
Modifier.isPublic(int modifiers);
Modifier.isStatic(int modifiers);
Modifier.isStrict(int modifiers);
Modifier.isSynchronized(int modifiers);
Modifier.isTransient(int modifiers);
Modifier.isVolatile(int modifiers);
eg:
包信息
可以使用Class对象通过如下的方式获取包信息:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
Package package = myClass.getPackage();
通过Package对象你可以获取包的相关信息,比如包名,你也可以通过Manifest文件访问位于编译路径下jar包的指定信息,
比如你可以在Manifest文件中指定包的版本编号。
eg:
父类
通过Class对象你可以访问类的父类,如下例:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
Class superclass = myClass.getSuperclass();
可以看到superclass对象其实就是一个Class类的实例,所以你可以继续在这个对象上进行反射操作。
eg:
package com.lanhuigu.reflect.parent;
import com.lanhuigu.reflect.cls.MyObject;
public class Test1 {
public static void main(String[] args) {
Class myClass = MyObject.class;
Class superClass = myClass.getSuperclass();
System.out.println("superClass name:" + superClass.getName());
}
}
实现的接口
可以通过如下方式获取指定类所实现的接口集合:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
Class[] interfaces = myClass.getInterfaces();
由于一个类可以实现多个接口,因此getInterfaces();方法返回一个Class数组,在Java中接口同样有对应的Class对象。
注意:
getInterfaces()方法仅仅只返回当前类所实现的接口。当前类的父类如果实现了接口,
这些接口是不会在返回的Class集合中的,尽管实际上当前类其实已经实现了父类接口。
eg:
package com.lanhuigu.reflect.interfaces;
import com.lanhuigu.reflect.cls.MyObject;
public class Test1 {
public static void main(String[] args) {
Class myClass = MyObject.class;
Class[] interfaces = myClass.getInterfaces();
for (Class c : interfaces) {
System.out.println("interfaces name:" + c.getName());
}
}
}
构造器
你可以通过如下方式访问一个类的构造方法:
Constructor[] constructors = myClass.getConstructors();
eg:
方法
你可以通过如下方式访问一个类的所有方法:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
Method[] method = myClass.getMethods();
eg:
变量
你可以通过如下方式访问一个类的成员变量:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
Field[] method = myClass.getFields();
eg:
注解
你可以通过如下方式访问一个类的注解:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
Annotation[] annotations = myClass.getAnnotations();
eg:
package com.lanhuigu.reflect.annotations;
import com.lanhuigu.reflect.cls.MyObject;
import java.lang.annotation.Annotation;
public class Test1 {
public static void main(String[] args) {
Class myClass = MyObject.class;
Annotation[] annotations = myClass.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof MyAnnotation) {
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("myAnnotation name:" + myAnnotation.name());
}
}
}
}
通过获取类的信息你可以获取以下相关的内容:
.Class对象
.类名
.修饰符
.包信息
.父类
.实现的接口
.构造器
.方法
.变量
.注解
除了上述这些内容,还有很多的信息你可以通过反射机制获得。
Class对象
在你想检查一个类的信息之前,你首先需要获取类的Class对象。Java中的所有类型包括基本类型(int, long, float等等),
即使是数组都有与之关联的Class类的对象。有如下三种方式获取Class对象:
以下知识点实例涉及共有代码:
MyObject.java
package com.lanhuigu.reflect.cls;
import com.lanhuigu.reflect.annotations.MyAnnotation;
@MyAnnotation(name = "testAnnoation", value = "hello world")
public class MyObject {
/** 公有变量*/
public static final String testFieldName = "test-field-name";
/** 私有变量 */
private String username;
private int age;
public MyObject () {
username = "Test1-Class";
age = 27;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}MyAnnotation.java
package com.lanhuigu.reflect.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
public String name();
public String value();
}
(1) 如果能够new某个对象,可以通过如下方式获取Class对象:
MyObject myObject = new MyObject();
Class myObjectClass = myObject.getClass();
eg:
package com.lanhuigu.reflect.cls; import java.lang.reflect.Method; /** * 如果能够new某个对象,可以通过如下方式获取Class对象: * MyObject myObject = new MyObject(); * Class myObjectClass = myObject.getClass(); */ public class Test1 { public static void main(String[] args) { /** 获取Class对象 */ MyObject myObject = new MyObject(); Class myObjectClass = myObject.getClass(); /** 获取Method */ Method[] methods = myObjectClass.getMethods(); /** 打印Method名称 */ for (Method myMethod : methods) { System.out.println("MyObject中的方法名:" + myMethod.getName()); } } }
(2) 如果你在编译期知道一个类的名字的话,那么你可以使用如下的方式获取一个类的Class对象:
Class myObjectClass = MyObject.class;
eg:
package com.lanhuigu.reflect.cls; import java.lang.reflect.Method; /** * 如果你在编译期知道一个类的名字的话,那么你可以使用如下的方式获取一个类的Class对象: * Class myObjectClass = MyObject.class; */ public class Test2 { public static void main(String[] args) { /** 获取Class对象 */ Class myObjectClass = MyObject.class; /** 获取Method */ Method[] methods = myObjectClass.getMethods(); /** 打印Method名称 */ for (Method myMethod : methods) { System.out.println("MyObject中的方法名:" + myMethod.getName()); } } }
(3) 如果你在编译期不知道类的名字,但是你可以在运行期获得到类名的字符串,那么你则可以这么做来获取Class对象
String className = ... ; //在运行期获取的类名字符串
Class class = Class.forName(className);
在使用Class.forName()方法时,你必须提供一个类的全名,这个全名包括类所在的包的名字。
例如MyObject类位于com.lanhuigu.reflect.cls包,那么他的全名就是com.lanhuigu.reflect.cls.MyObject。
如果在调用Class.forName()方法时,没有在编译路径下(classpath)找到对应的类,那么将会抛出ClassNotFoundException。
eg:
package com.lanhuigu.reflect.cls; import java.lang.reflect.Method; /** * 如果你在编译期不知道类的名字,但是你可以在运行期获得到类名的字符串,那么你则可以这么做来获取Class对象: * String className = ... ; //在运行期获取的类名字符串 * Class class = Class.forName(className); * * 在使用Class.forName()方法时,你必须提供一个类的全名,这个全名包括类所在的包的名字。 * 例如MyObject类位于com.lanhuigu.reflect.cls包,那么他的全名就是com.lanhuigu.reflect.cls.MyObject。 * 如果在调用Class.forName()方法时,没有在编译路径下(classpath)找到对应的类,那么将会抛出ClassNotFoundException。 */ public class Test3 { public static void main(String[] args) { try { /** 获取Class对象 */ String className = "com.lanhuigu.reflect.cls.MyObject"; Class myObjectClass = Class.forName(className); /** 获取Method */ Method[] methods = myObjectClass.getMethods(); /** 打印Method名称 */ for (Method myMethod : methods) { System.out.println("MyObject中的方法名:" + myMethod.getName()); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
类名
你可以从Class对象中获取两个版本的类名。
通过getName()方法返回类的全限定类名(包含包名):
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
String className = myClass.getName();
eg:
package com.lanhuigu.reflect.classname;
import com.lanhuigu.reflect.cls.MyObject;
/**
* 通过getName()方法返回类的全限定类名(包含包名):
* Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
* String className = myClass.getName();
*/
public class Test1 {
public static void main(String[] args) {
Class myClass = MyObject.class;
String className = myClass.getName();
System.out.println("className:" + className);
}
}
如果你仅仅只是想获取类的名字(不包含包名),那么你可以使用getSimpleName()方法:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
String simpleClassName = myClass.getSimpleName();
eg:
package com.lanhuigu.reflect.classname;
import com.lanhuigu.reflect.cls.MyObject;
/**
* 如果你仅仅只是想获取类的名字(不包含包名),那么你可以使用getSimpleName()方法:
* Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
* String simpleClassName = myClass.getSimpleName();
*/
public class Test2 {
public static void main(String[] args) {
Class myClass = MyObject.class;
String simpleClassName = myClass.getSimpleName();
System.out.println("simpleClassName:" + simpleClassName);
}
}
修饰符
可以通过Class对象来访问一个类的修饰符,即public,private,static等等的关键字,你可以使用如下方法来获取类的修饰符:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
int modifiers = myClass.getModifiers();
修饰符都被包装成一个int类型的数字,这样每个修饰符都是一个位标识(flag bit),这个位标识可以设置和清除修饰符的类型。
可以使用java.lang.reflect.Modifier类中的方法来检查修饰符的类型:
Modifier.isAbstract(int modifiers);
Modifier.isFinal(int modifiers);
Modifier.isInterface(int modifiers);
Modifier.isNative(int modifiers);
Modifier.isPrivate(int modifiers);
Modifier.isProtected(int modifiers);
Modifier.isPublic(int modifiers);
Modifier.isStatic(int modifiers);
Modifier.isStrict(int modifiers);
Modifier.isSynchronized(int modifiers);
Modifier.isTransient(int modifiers);
Modifier.isVolatile(int modifiers);
eg:
package com.lanhuigu.reflect.modifier; import java.lang.reflect.Modifier; public class Test1 { public static void main(String[] args) { try { Class myClass = Class.forName("com.lanhuigu.reflect.cls.MyObject"); int modifiers = myClass.getModifiers(); System.out.println("isPrivate:" + Modifier.isPrivate(modifiers)); System.out.println("isPublic:" + Modifier.isPublic(modifiers)); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
包信息
可以使用Class对象通过如下的方式获取包信息:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
Package package = myClass.getPackage();
通过Package对象你可以获取包的相关信息,比如包名,你也可以通过Manifest文件访问位于编译路径下jar包的指定信息,
比如你可以在Manifest文件中指定包的版本编号。
eg:
package com.lanhuigu.reflect.packages; import com.lanhuigu.reflect.cls.MyObject; public class Test1 { public static void main(String[] args) { Class myClass = MyObject.class; Package packages = myClass.getPackage(); System.out.println("packages.name:" + packages.getName()); } }
父类
通过Class对象你可以访问类的父类,如下例:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
Class superclass = myClass.getSuperclass();
可以看到superclass对象其实就是一个Class类的实例,所以你可以继续在这个对象上进行反射操作。
eg:
package com.lanhuigu.reflect.parent;
import com.lanhuigu.reflect.cls.MyObject;
public class Test1 {
public static void main(String[] args) {
Class myClass = MyObject.class;
Class superClass = myClass.getSuperclass();
System.out.println("superClass name:" + superClass.getName());
}
}
实现的接口
可以通过如下方式获取指定类所实现的接口集合:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
Class[] interfaces = myClass.getInterfaces();
由于一个类可以实现多个接口,因此getInterfaces();方法返回一个Class数组,在Java中接口同样有对应的Class对象。
注意:
getInterfaces()方法仅仅只返回当前类所实现的接口。当前类的父类如果实现了接口,
这些接口是不会在返回的Class集合中的,尽管实际上当前类其实已经实现了父类接口。
eg:
package com.lanhuigu.reflect.interfaces;
import com.lanhuigu.reflect.cls.MyObject;
public class Test1 {
public static void main(String[] args) {
Class myClass = MyObject.class;
Class[] interfaces = myClass.getInterfaces();
for (Class c : interfaces) {
System.out.println("interfaces name:" + c.getName());
}
}
}
构造器
你可以通过如下方式访问一个类的构造方法:
Constructor[] constructors = myClass.getConstructors();
eg:
package com.lanhuigu.reflect.constructors; import com.lanhuigu.reflect.cls.MyObject; import java.lang.reflect.Constructor; public class Test1 { public static void main(String[] args) { Class myClass = MyObject.class; Constructor[] constructors = myClass.getConstructors(); for (Constructor constructor : constructors) { System.out.println("constructor name:" + constructor.getName()); } } }
方法
你可以通过如下方式访问一个类的所有方法:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
Method[] method = myClass.getMethods();
eg:
package com.lanhuigu.reflect.methods; import com.lanhuigu.reflect.cls.MyObject; import java.lang.reflect.Method; public class Test1 { public static void main(String[] args) { Class myClass = MyObject.class; Method[] methods = myClass.getMethods(); for (Method method : methods) { System.out.println("method name:" + method.getName()); } } }
变量
你可以通过如下方式访问一个类的成员变量:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
Field[] method = myClass.getFields();
eg:
package com.lanhuigu.reflect.fields; import com.lanhuigu.reflect.cls.MyObject; import java.lang.reflect.Field; public class Test1 { public static void main(String[] args) { Class myClass = MyObject.class; /** 返回公有变量集合 */ Field[] fields = myClass.getFields(); for (Field field : fields) { System.out.println("field name:" + field.getName()); } } }
注解
你可以通过如下方式访问一个类的注解:
Class myClass = ... //获取Class对象,参考上面的Class对象获取的三种方法
Annotation[] annotations = myClass.getAnnotations();
eg:
package com.lanhuigu.reflect.annotations;
import com.lanhuigu.reflect.cls.MyObject;
import java.lang.annotation.Annotation;
public class Test1 {
public static void main(String[] args) {
Class myClass = MyObject.class;
Annotation[] annotations = myClass.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof MyAnnotation) {
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("myAnnotation name:" + myAnnotation.name());
}
}
}
}
相关文章推荐
- Java Reflection深入理解构造器(Constructor)
- Java Reflection深入理解方法(Method)
- Java Reflection深入理解动态代理(Proxy)
- Java Reflection深入理解变量(Field)
- Java Reflection深入理解数组(Array)
- Java Reflection深入理解私有变量和私有方法
- Java Reflection深入理解泛型(generics)
- Java中HashMap和TreeMap的区别深入理解(转载)
- Java 集合深入理解(15):AbstractMap
- 深入理解为什么Java中方法内定义的内部类可以访问方法中的局部变量
- Java中HashMap和TreeMap的区别深入理解
- 深入理解Java:注解(Annotation)自定义注解入门
- java面试-深入理解JVM(八)——类加载的时机
- 深入理解Java中的容器
- 深入理解Java中为什么内部类可以访问外部类的成员
- 深入理解Java虚拟机重点
- 深入理解Java8 lambda表达式
- Java 集合深入理解(13):Stack 栈
- 深入理解java异常处理机制
- 深入理解Java对象序列化