原文链接:https://www.codemore.top/cates/Backend/post/2018-04-26/reflect-class

Java中每个类型要么是引用类型,要么是原生类型。类,枚举,数组(他们都继承于java.lang.Object)和接口都是引用类型。例如:java.lang.String,所有原生类型的包装类java.lang.Double,接口java.io.Serializable和枚举javax.swing.Sortorder,都是引用类型。原生类型的数量是固定的:boolean,byte,short,int,long,char,float,double。 对于每个对象类型,JVM都会为其初始化一个java.lang.Class的实例,可以检查包括属性和方法在内的对象运行时的属性。Class同样也可以创建一个新的类和对象。最重要的是,他是所有反射API的入口。

获取类对象

java.lang.Class是所有反射操作的的入口。java.lang.reflect中的所有类都没有公共的构造函数,所以为了实例化其中的类,需要通过调用合适的Class函数。

Object.getClass()

如果可以获取到一个类的实例,最简单获取Class的方法就是调用Object.getClass()。当然这个只适应于全部都继承与Object的引用类型。例如:返回StringClass

Class c = "foo".getClass();

System.console() 返回的是一个java.io.Console类,所以如下代码然会了ConsoleClass

Class c = System.console().getClass();

对于枚举类型,E,A是E的实例,所以A.getClass() 返回的是E的Class例如:

Enum E {A,B}
Class c = A.getClass();

因为数组也是对象,所以也可以通过调用其getClass()获取Class,返回的Class带有数组的类型信息。

byte[] bytes = new byte[1024];
Class c = bytes.getClass();

对于集合类,同样s.getClass() 返回的是与java.util.HashSet相关的Class

import java.util.Set
import java.util.HashSet Set<String> s = new HashSet<String>();
Class c = s.getClass();
.class 语法

如果类型可用,但是没有实例,可以通过.class获取Class。同样,也可以使用这个方法获取原生类型的Class

boolean b;
Class = b.getClass(); //编译错误 Class = boolean.class; //正确

注意直接使用boolean.getClass()会发生编译错误,因为boolean是一个原生类型,而且不可以被反引用。

Class c = java.io.PrintStream.class;

获取java.io.PrintStream相关的Class

Class c = int[][].class;

获取二位int数组相关的Class

Class.forName()

使用这个方法需要知道类的全限定名。只能应用于引用类型。数组类型的全限定名可以由Class.getName()获取。

Class c = Class.forName("com.duke.MyLocaleServiceProvider");

通过使用全限定名创建class

Class cDoubleArray = Class.forName("[D");

Class cStringArray = Class.forName("[[Ljava.lang.String;");

cDoubleArraydouble[]Classdouble[].class相同。cStringArray 则与String[][].class相同。

原生类型包装类的TYPE字段

获取原生类型的Class既可以通过.class方式,也可以通过原生类型的包装类的TYPE字段,对于void,java.lang.Void同样提供了这样的一个字段。

Class c = Double.TYPE;

Double.TYPE 就相当于double.class

Class c = Void.TYPE;

等同于void.class

返回Class的方法

如果已经得到了Class,那么可以使用Class中的API来获取其他的类 Class.getSuperClass() 返回指定类的父类

Class c = javax.swing.JButton.class.getSupperClass();

返回其父类javax.swing.AbstractButton Class.getClasses() 获取所有内部所有public类,接口,枚举,包括本身和继承的成员类。

Class<?>[] c = Character.class.getClasses();

返回Character的两个成员类Character.SubsetCharacter.UnicodeBlock Class.getDeclearedClasses()返回类中所有的类,接口,枚举。

Class<?>[] c Character.class.getDeclearedClasses();

返回Character的两个public类Character.SubsetCharacter.UnicodeBlock和一个private类Character.CharacterCache。 Class.getDeclearingClass(),java.lang.reflect.Field.getDeclearingClass(),java.lang.reflect.Method.getDeclearingClass(),java.lang.reflect.Constructor.getDeclaringClass()返回声明这些成员的类返回声明这些成员的类。匿名类不会有声明类,有一个外围类(enclosing class)。

import java.lang.reflect.Field;

Field f = System.class.getField("out");
Class c = f.getDeclaringClass();

out 是在System中声明的。

public class MyClass{
static Object o = new Object() {
public void m(){}
};
static Class<c> = o.getClass().getEnclosingClass();
}

Class.getEnclosingClass() 返回其外围类

Class c = Thread.State.class.getEnclosingClass();

Thread.State的外围类Thread

public class MyClass {
static Object o = new Object() {
public void m() {}
};
static Class<c> = o.getClass().getEnclosingClass();
}

匿名类的外围类是MyClass.

获取Class主要三种方法对比:

方式 使用范围
getClass() 需要获取对象实例,仅能用于引用类型
.class 无需获取对象实例,既可以是引用类型也可以是原生类型
forName() 只需要类的全限定名

检查类修饰符和类型

类声明时会包含一个或多能够影响他运行时行为的修饰符:

  • 访问修饰符:public,private,protected
  • 抽象修饰符:abstract
  • 静态修饰符:static
  • 不可变修饰符: final
  • 强制严格浮点修饰符: strictfp
  • 注解 不是所有的修饰符都可以应用到所有的类上,比如,interface不能使用final,enum不能使用abstract。java.lang.reflect.Modifier 包含了所有的修饰符声明。方法Class.getModifiers()可以返回所有的修饰符。 下面这个例子演示了如果获取一个类的修饰符,泛型参数,实现接口,和集成链。因为Class继承了java.lang.reflect.AnnotatedElement所以可以在运行时获取注解信息。
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);
}
}
}

运行:

$ 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的源码为:

public interface ConcurrentNavigableMap<K,V>
extends ConcurrentMap<K,V>, NavigableMap<K,V>

注意,以为他是接口,编译器默认对所有接口加abstract。有两个泛型K,V。 运行:

$ 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 --]
获取类成员

Class中有两种获取field,method,constructor的方式,一种是获取全部成员,一种是获取指定成员。同样获取成员是也分为从当前类查找和从继承链中查找。总结如下: Field 方法

API 列出所有成员 列出继承成员 私有成员
getDeclaredField() n n y
getField() n y n
getDeclaredFields() y n y
getFields() y y n

Method 方法

API 列出所有成员 列出继承成员 私有成员
getDeclaredMethod() n n y
getMethod() n y n
getDeclaredMethods() y n y
getMethods() y y n

constructor 方法:

API 列出所有成员 列出继承成员 私有成员
getDeclaredConstructor() n n y
getConstructor() n n n
getDeclaredConstructors() y n y
getConstructors() y n n

构造函数并不继承。

示例如下:

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");
}
}

使用如下:

 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()
故障排除

下面这些例子是在用注解是会遇到到的一些常见问题:

Compiler Warning: "Note: ... uses unchecked or unsafe operations"

调用方法的时候会检查参数类型比做类型转换,如下示例:

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();
}
}
}

运行 结果:

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

可以通过使用泛型或者使用注解@SuppressWarning("unchecked")解决:

Class<?> c = warn.getClass();
Class c = ClassWarning.class;
@SupressWarning("unchecked")
Method m = c.getMethod();
InstantiationException when the Constructor is Not Accessible

如果通过Class.newInstance()创建类,但是没有0参数的构造器,会抛出InstantiationException异常。例如:

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();
}
}
}

运行结果:

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)

反射获取 Class的更多相关文章

  1. Atitit利用反射获取子类 集合 以及继承树

    Atitit利用反射获取子类 集合 以及继承树 想从父类往下找子类的确是不可能的,要知道只要类不是final的话谁都有继承它的自由不需要事前通知父类. Eclipse实现不是重父类开始找而是重子类往回 ...

  2. java 通过反射获取调用类方法及属性

    首先说下反射是什么?反射是Sun公司推出的一组API,此组API位于Java.lang.reflect中 反射的作用是编写工具(例如eclipse),编写框架,当然对于一般的程序,我们不可能用反射来做 ...

  3. C#中使用反射获取结构体实例

    一般用反射获取类对象的实例比较简单,只要类有一个无参构造函数或没有显示声明带参的构造函数即可使用如下代码 static void Main(string[] args) { Type type = t ...

  4. java 27 - 4 反射之 通过反射获取成员变量并使用

    类Field: 提供有关类或接口的单个字段的信息,以及对它的动态访问权限. A:获得类的成员变量 数组: 1.getFields(公共类的) 2.getDeclaredFields(所有类型的) B: ...

  5. java 27 - 3 反射之 通过反射获取构造方法并使用

    类 Constructor<T>:提供关于类的单个构造方法的信息以及对它的访问权限. 通过反射的方法获取构造方法并使用  ps:先忽略泛型 A.1:获取构造方法的数组: public Co ...

  6. 通过反射获取SSM的controller层的注解以及注解中的value值

    package com.reflection.test; import java.lang.annotation.Annotation; import java.lang.reflect.Invoca ...

  7. java中的反射机制,以及如何通过反射获取一个类的构造方法 ,成员变量,方法,详细。。

    首先先说一下类的加载,流程.只有明确了类这个对象的存在才可以更好的理解反射的原因,以及反射的机制. 一.  类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三 ...

  8. c#反射机制学习和利用反射获取类型信息

    反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类.结构.委托.接口和枚举等)的成员,包括方法.属性.事件,以及构造函数等.还可以获得每个成员的 ...

  9. Android开发之通过反射获取到Android隐藏的方法

    在PackageManger中,有些方法被隐藏了,无法直接调用,需要使用反射来获取到该方法. 比如方法:getPackageSizeInfo(),通过这个方法可以获取到apk的CacheSize,Co ...

  10. Android(java)学习笔记109:通过反射获取成员变量和成员方法并且使用

    一.反射获取成员变量并且使用: 1.获取字节码文件对象:         Class c = Class.forName("cn.itcast_01.Person"); 2.使用无 ...

随机推荐

  1. javascript学习(2)修改html元素和提示对话框

    一.修改html元素 1.修改p元素 1.1.源代码 1.2.执行前 1.3.执行后 2.修改div元素的className 2.1.源代码 1.2.执行前 1.3.执行后 3.直接在当前位置输出内容 ...

  2. spring-oauth-server实践:授权方式四:client_credentials 模式下有效期内重复申请 access_token ?

    spring-oauth-server入门(1-12)授权方式四:client_credentials 模式下有效期内重复申请 access_token ? 一.失效重建邏輯 二.如果沒有失效,不会重 ...

  3. hadoop2.7.3+spark2.1.0+scala2.12.1环境搭建(2)安装hadoop

    一.依赖安装 安装JDK 二.文件准备 hadoop-2.7.3.tar.gz 2.2 下载地址 http://hadoop.apache.org/releases.html 三.工具准备 3.1 X ...

  4. Spring Security 入门(3-11)Spring Security 的使用-自定义登录验证和回调地址

    配置文件 security-ns.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmln ...

  5. JSON(五)——同步请求中使用JSON格式字符串进行交互(不太常见的用法)

    在同步请求中使用JSON格式进行数据交互的场景并不多,同步请求是浏览器直接与服务器进行数据交互的大多是用jsp的标签jstl和el表达式对请求中的数据进行数据的渲染.我也是在一次开发中要从其它服务器提 ...

  6. vscode调试适配器已意外终止

    出现这个错误了,找半天没找到办法.师兄支了一招: 把图中红圈部分删掉! 这是个旧的配置文件 ,你删掉它(反正一直报错误,也用不成了!).然后你调试一个文件,它会重新自动添加新的配置文件.

  7. IT技术有感

    今天看技术文章,spring相关的,某一个点以前每次看一直不理解, 可是不知道为什么隔了1年左右,中间什么都没做,现在却都懂了. 在看懂的那一刻,笼罩在我心上的躁动突然平静了许多,我的心这一年来前所未 ...

  8. python继承——封装

    python继承--封装 1 为什么要封装 封装数据的主要原因是:保护隐私 封装方法的主要原因是:隔离复杂度 2 封装分为两个层面 第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空 ...

  9. [Debug]测试环境Giraffe无法正确登录

    BUG描述: 在测试环境192.168.2.72上的giraffe无法正确登录,输入正确的用户名.密码,点击登录无反应,输入错误的用户名密码会报错 原因: 2.72安装giraffe的磁盘空间已满,导 ...

  10. 初试GH-OST

    最近老板让做一个gh-ost和pt-osc 的对比测试,本文将对两者做对比. 一.原理和所用说明   PT-OSC GH-OST 原理 1.创建一个和要执行 alter 操作的表一样的新的空表结构(是 ...