概述
文章目录
- 1. 概念
- 2. 获取 Class 对象的四种方式
- 3. Class 对象能什么呢
- 4. Class 对象的唯一性
- 5. 创建 Class 对象的过程
- 6. 部分方法介绍
- 1. 生成对象实例的方法
- 1. 直接使用 Class 对象的 newInstance() 方法
- 2. 使用 Class 对象获取的构造器对象的 newInstance 方法
- 2. 获取类的构造器
- 3. 获取类中的方法
- 4. 获取类中的字段
1. 概念
在 java 世界里,一切皆对象。从某种意义上来说,java 有两种对象:实例对象和 Class 对象。每个类在运行时的类型信息就是用 Class 对象表示的,它包含了与类有关的信息,并且实例对象就是通过 Class 对象来创建的。Java 使用 Class 对象执行其 RTTI (运行时类型识别,Run-Time Type Identification),多态就是基于 RTTI 实现的。
每一个类都有一个 Class 对象,每当编译一个新类就产生一个 Class 对象,基本类型 (boolean, byte, char, short, int, long, float, double)有 Class 对象,就连关键字 void 也有 Class 对象(void.class)。Class 对象对应着 java.lang.Class 类,如果说类是对象的抽象和集合,那么 Class 类就是对类的抽象和集合。
Class 类只有一个私有的构造方法,所以 Class 对象不能通过 new 关键字来创建,而是在类加载的时候由 Java 虚拟机以及类加载器来自动构造的。
所有的类都是在第一次被使用时,动态加载到 JVM 中的(懒加载)。当程序创建第一个对类的静态成员的引用时,就会加载这个类。使用 new 创建类对象的时候也会被当作对类的静态成员的引用。因此 java 程序在它开始运行之前并非被完全加载,其各个类都是在必需时才加载的。
在类加载阶段,类加载器首先检查这个类的 Class 对象是否已经被加载。如果尚未加载,默认的类加载器就会根据类的全限定名查找 .class文件。在这个类的字节码被加载时,它们会接受验证,以确保其没有被破坏,并且不包含不良 java 代码。一旦某个类的 Class 对象被载入内存,我们就可以用它来创建这个类的所有对象。
下面涉及的源码都是 JDK 1.8 的
2. 获取 Class 对象的四种方式
//1.使用 .class 字面量
//使用这种办法生成 Class 对象时,不会使 JVM 自动加载该类(如String类)。而其他办法会使 JVM 初始化该类
Class<Person> clazz1 = Person.class;
//2.通过运行时类的对象获取
Person p = new Person();
Class clazz2 = p.getClass();
//3.通过Class类的静态方法获取
String className = "com.java.Person"; //全限定类名
Class clazz3 = Class.forName(className);
//4.通过类的加载器获取
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(className);//该方法会调用defineClass方法
注意:
- 包装类中有额外一种获取 Class 对象的方式:如
Integer.TYPE
,但是Integer.class
与Integer.TYPE
不同,Integer.TYPE
等价于int.class
;Integer 是 Object Type 对象类型,int 是 Primitive Type 原始类型//但以下这种情况是成立的 Class<Integer> obj2=int.class; //类型限制 Class<Integer> obj2=Integer.class; obj2=double.class; //会报错,obj2不能改指向别的类型 //若要obj2可以指向其他的数据类型,可以如下,指定类型上限 Class<? extends Number> obj=int.class; obj=Number.class; obj=double.class;//可以指向其他数据类型
- Number 类是 java.lang 包下的一个抽象类,提供了将包装类拆箱成基本类型的方法,所有基本类型的包装类都继承了该抽象类,并且用 final 声明为不可继承类
package java.lang; public abstract class Number implements java.io.Serializable { public abstract int intValue(); public abstract long longValue(); public abstract float floatValue(); public abstract double doubleValue(); public byte byteValue() { return (byte)intValue(); } public short shortValue() { return (short)intValue(); } private static final long serialVersionUID = -8742448824652078965L; }
- 一个 Class 对象实际上表示的是一个类型,而这个类型未必一定是一种类。例如 int 不是类,但 int.class 是一个 Class 对象。
- 调用 Class 类的 newInstance() 方法动态创建类对象时,需要对应类中有空参的构造器。
- Class 对象由 Java 虚拟机自动创建,或通过类加载器的 defineClass 方法生成
//通过该方法可以动态地将 .class 文件转为一个Class类对象 protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError{ return defineClass(name, b, off, len, null); }
- 当你使用泛型语法来构建一个 Class 类的基类对象时,必须采用以下的特殊语法
public class shapes{} class round extends shapes{} Class<round> rclass=round.class; Class<shapes> sclass=rclass.getSuperClass();//直接使用这种方式会报错 Class<? super round> sclass= rclass.getSuperClass();//使用类型下限就不会报错了
3. Class 对象能什么呢
获取到运行时类的 Class 实例后,通过 Class 类的实例可以:
- 通过 newInstance() 方法创建对应类的对象。
- 获取其对应类的完整结构,如构造器、属性、方法、内部类、父类、所在的包、异常和注解等。
- 调用对应的运行时类的指定结构,如属性、方法和构造器。
- 反射的应用,如 动态代理等等,Class 对象是反射的源头。
4. Class 对象的唯一性
每个通过关键字 class 标识的类,在内存中有且只有一个与之对应的 Class 对象来描述其类型信息,不论通过哪种方式获得该类的 Class 对象,它们返回的都是指向同一个 java 堆地址上的 Class 引用,JVM 不会创建两个相同类型的 Class 对象。也就是说,无论创建多少个实例对象,其依据的都是同一个 Class 对象。java 虚拟机中使用双亲委派模型来组织类加载器之间的关系,来保证 Class 对象的唯一性。
验证代码如下:
Class dog = Dog.class;
Class dog2 = Class.forName("fanda.zeng.reflect.Dog");
Class dog3 = new Dog().getClass();
Class dog4 = new Dog().getClass() ;
if (dog == dog2 && dog2 == dog3 && dog3 == dog4) {
System.out.println(true);
} else {
System.out.println(false);
}
//打印结果:
true
5. 创建 Class 对象的过程
虽然 Class 类是所有类的抽象,但是它依旧是与其它类一样具有共同性,创建一个自定义 Test 类,经过编译会产生一个 Test.class 字节码文件,该字节码文件保存着 Test 类的抽象,也就是保存着 Test 类的各种类型与方法等,JVM 会通过它来创建 Test 类对应的 Class 对象,JVM 再通过该 Class 对象来创建 Test 实例。不管创建多少个实例,字节码文件始终只有一个,且所有的实例都依赖于该 Class 对象。这也是所有类的 hashcode 都有唯一性的一个原因。
在实际中,Class 对象是不能被外部创建的,它只能在 JVM 中被创建,因为 Class 类只有私有的构造方法,所以不会存在 Class.class 文件
当我们 new 一个新对象或者引用静态成员变量时,JVM 中的类加载器子系统会将对应 Class 对象加载到 JVM 中,这个过程也就是通过类加载器将字节码文件转化为 Class 对象,然后 JVM 再根据这个 Class 对象创建我们需要的实例对象或者提供静态变量的引用值。
private Class(ClassLoader loader) {
classLoader = loader;
}
那么如何来加载一个 Class 对象或者获取一个 Class 对象的引用呢?在其内部提供了 forName 方法:
@CallerSensitive
public static Class<?> forName(String className) throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
该方法通过反射类 Reflection 的 getCallerClass 本地方法来获取当前类的 Class 对象的引用,但这个 Class 对象是只有标明是属于哪一个类的,里面并没有加载进对应类的信息。随后调用 forName0 本地方法来对 Class 对象进行初始化,加载对应类的静态部分,然后再加载对应类的非静态部分,当然,如果调用 froName 方法前该 Class 对象就已经存在了,那么就不会再执行初始化操作了,也就是不会再加载这个类了,因为已经加载过了
//是一个本地方法
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
另外一个 forName 方法里面加入了 java 的安全管理器,如果是系统级别的加载器则不需要验证权限,否则就需要验证加载器是否有加载该字节码文件的权限:
/**
* @param name 类的完全限定名
* @param initialize 是否加载
* @param loader 类加载器
* @return 一个Class对象
* @throws ClassNotFoundException
*/
@CallerSensitive
public static Class<?> forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException {
// 如果传入的类加载器为null,则获取调用类的类加载器
if (loader == null) {
// 获取安全管理器
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// 获取调用类的类加载器
ClassLoader ccl = ClassLoader.getCallerClassLoader();
if (ccl != null) {
// 使用安全管理器检查是否有获取类加载器的权限
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}
return forName0(name, initialize, loader)
}
这里的 SecurityManager 类是 JVM 提供的在应用层进行安全检查的机制,应用程序可以根据策略文件被赋予一定的权限,例如是否可以读写文件,是否可以读写网络端口,是否可以读写内存,是否可以获取类加载器等等。在进行特殊操作时,需要进行安全检查,从而给程序的安全运行提供一定保障。
6. 部分方法介绍
1. 生成对象实例的方法
1. 直接使用 Class 对象的 newInstance() 方法
前提:要求对应类中有相应的无参构造器
作用:创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new 表达式实例化该类。如果该类尚未初始化,则初始化这个类。
// 获取类的实例
public T newInstance() throws InstantiationException, IllegalAccessException {
// 进行安全检查
if (System.getSecurityManager() != null) {
checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false);
}
return newInstance0();
}
/**
* 检查客户端是否有成员的访问权限
* @param which 权限识别码,整数类型
* @param ccl 类加载器
* @param checkProxyInterfaces
*/
private void checkMemberAccess(int which, ClassLoader ccl, boolean checkProxyInterfaces) {
SecurityManager s = System.getSecurityManager();
if (s != null) {
// 检查客户端能否有权限访问该类
s.checkMemberAccess(this, which);
ClassLoader cl = getClassLoader0();
if (ReflectUtil.needsPackageAccessCheck(ccl, cl)) {
// 获取类的完全限定名
String name = this.getName();
int i = name.lastIndexOf('.');
// 类的完全限定名中含有.(例如com.Test)
if (i != -1) {
// 获取包名
String pkg = name.substring(0, i);
// 如果该类是com.sun.proxy包下的代理类,则不需要进行包访问权限验证,否则需要验证
// 代理类指使用Proxy.getProxyClass或Proxy.newProxyInstance动态生成的类
if (!Proxy.isProxyClass(this) || !pkg.equals(ReflectUtil.PROXY_PACKAGE)) {
s.checkPackageAccess(pkg);
}
}
}
// 如果该类是代理类,并且需要检查代理类的接口,则检查接口的访问权限
if (checkProxyInterfaces && Proxy.isProxyClass(this)) {
ReflectUtil.checkProxyPackageAccess(ccl, this.getInterfaces());
}
}
}
private T newInstance0() throws InstantiationException, IllegalAccessException {
// 每次先检查是否有已经缓存过的构造器,如果没有,则重新获取
if (cachedConstructor == null) {
// 如果该类是Class类,则直接抛出异常,意思是,我们不能利用此方法生成Class类的实例
if (this == Class.class) {
throw new IllegalAccessException(
"Can not call newInstance() on the Class for java.lang.Class"
);
}
try {
Class[] empty = {};
// 获取该类已经声明的的无参构造方法
final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
// 此处是为了使无参构造方法可以被访问,因为有时,构造方法被声明为private的
java.security.AccessController.doPrivileged
(new java.security.PrivilegedAction() {
public Object run() {
c.setAccessible(true);
return null;
}
});
// 将获取的无参构造方法缓存
cachedConstructor = c;
} catch (NoSuchMethodException e) {
throw new InstantiationException(getName());
}
}
Constructor<T> tmpConstructor = cachedConstructor;
// 获取构造方法的语言修饰符,诸如public,private,static,final等
int modifiers = tmpConstructor.getModifiers();
// 根据已经获取的语言修饰符判断是否具有访问权限,如果没有,则执行以下操作
if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
// 获取调用者的类
Class caller = Reflection.getCallerClass(3);
// 与之前缓存的调用者类进行对比,如果不是之前的,则需重新确保调用者类可以访问无参构造方法
if (newInstanceCallerCache != caller) {
Reflection.ensureMemberAccess(caller, this, null, modifiers);
newInstanceCallerCache = caller;
}
}
try {
// 整个方法的核心,使用类的构造方法来生成实例
return tmpConstructor.newInstance((Object[]) null);
} catch (InvocationTargetException e) {
Unsafe.getUnsafe().throwException(e.getTargetException());
return null;
}
}
案例:
Class c = Class.forName("jichu.ClassA");
ClassA o1 = (ClassA) c.newInstance();
ClassA o2 = (ClassA) c.newInstance();
System.out.println(o1.method1());// this is method1 in ClassA
System.out.println(o1 == o2);// false
2. 使用 Class 对象获取的构造器对象的 newInstance 方法
注意:JDK 1.9 的时候,第一种方式已经被弃用了,第二种方式不需要强制要求类中得有无参构造器
作用:通过类中对应的构造器创建一个该类的新实例,如果该类尚未初始化,则初始化这个类。
案例:
Class<?> c = String.class;
Constructor constructor = c.getConstructor(String.class);
Object obj = constructor.newInstance("23333");
2. 获取类的构造器
// 1.
@CallerSensitive
public Constructor<T> getConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
return getConstructor0(parameterTypes, Member.PUBLIC);
}
//2.
private Constructor<T> getConstructor0(Class<?>[] parameterTypes, int which) throws NoSuchMethodException {
Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
for (Constructor<T> constructor : constructors) {
if (arrayContentsEq(parameterTypes, constructor.getParameterTypes())) {
return getReflectionFactory().copyConstructor(constructor);
}
}
throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
}
//3.
private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) {
checkInitted();
Constructor<T>[] res;
ReflectionData<T> rd = reflectionData();
if (rd != null) {
res = publicOnly ? rd.publicConstructors : rd.declaredConstructors;
if (res != null) return res;
}
// No cached value available; request value from VM
if (isInterface()) {
@SuppressWarnings("unchecked")
Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0];
res = temporaryRes;
} else {
res = getDeclaredConstructors0(publicOnly);
}
if (rd != null) {
if (publicOnly) {
rd.publicConstructors = res;
} else {
rd.declaredConstructors = res;
}
}
return res;
}
//1.
@CallerSensitive
public Constructor<?>[] getConstructors() throws SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
return copyConstructors(privateGetDeclaredConstructors(true));
}
//2.
private static Method[] copyMethods(Method[] arg) {
Method[] out = new Method[arg.length];
ReflectionFactory fact = getReflectionFactory();
for (int i = 0; i < arg.length; i++) {
out[i] = fact.copyMethod(arg[i]);
}
return out;
}
//1.
@CallerSensitive
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
return getConstructor0(parameterTypes, Member.DECLARED);
}
//1.
@CallerSensitive
public Constructor<?>[] getDeclaredConstructors() throws SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
return copyConstructors(privateGetDeclaredConstructors(false));
}
用于测试的代码:
class Animal {
public Animal(){}
public Animal(int i){}
public Animal(int i,int j){}
protected Animal(double i){}
private Animal(long i){}
Animal (String str){}
}
class Cat extends Animal {
public Cat(){}
public Cat(String str){}
public Cat(String str, int i){}
private Cat(double i,double j){}
protected Cat(long i){}
Cat(HashMap a){}
}
获取构造器的四个方法分别是:
- Constructor<?>[] getConstructors():返回一个包含了本类所有 public 构造函数的 Constructor 类型数组,如果数组长度为 0,则说明该类是一个数组或者基本类型或者 void
Class<Cat> aClass = Cat.class; Constructor<?>[] constructors = aClass.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println(constructor.toString()); } //结果: public Cat(java.lang.String,int) public Cat(java.lang.String) public Cat()
- Constructor getConstructor(Class<?>… parameterTypes):返回一个指定参数的 public 构造函数对象,参数是一个 Class 类型的数组
Class<Cat> aClass = Cat.class; Class[] cls1 = new Class[]{String.class}; Constructor<Cat> constructor1 = aClass.getConstructor(cls1); System.out.println(constructor1.toString()); //public Cat(java.lang.String) Class[] cls2 = new Class[]{String.class,int.class}; Constructor<Cat> constructor2 = aClass.getConstructor(cls2); System.out.println(constructor2.toString()); //public Cat(java.lang.String,int)
- Constructor<?>[] getDeclaredConstructors():返回一个包含了本类所有构造函数的 Constructor 类型数组,如果数组长度为 0,则说明该类是一个数组或者基本类型或者 void
Class<Cat> aClass = Cat.class; Constructor<?>[] constructors = aClass.getDeclaredConstructors(); for (Constructor<?> constructor : constructors) { System.out.println(constructor.toString()); } //结果: Cat(java.util.HashMap) protected Cat(long) private Cat(double,double) public Cat(java.lang.String,int) public Cat(java.lang.String) public Cat()
- Constructor getDeclaredConstructor(Class<?>… parameterTypes):返回一个指定参数的构造函数对象,参数是一个 Class 类型的数组,他与 getConstructor 的区别就在于他不受访问权限修饰符的限制
Class<Cat> aClass = Cat.class; Class[] cls1 = new Class[]{String.class}; Constructor<Cat> constructor1 = aClass.getDeclaredConstructor(cls1); System.out.println(constructor1.toString()); //public Cat(java.lang.String) Class[] cls2 = new Class[]{String.class,int.class}; Constructor<Cat> constructor2 = aClass.getDeclaredConstructor(cls2); System.out.println(constructor2.toString()); //public Cat(java.lang.String,int) Class[] cls3 = new Class[]{long.class}; Constructor<Cat> constructor3 = aClass.getDeclaredConstructor(cls3); System.out.println(constructor3.toString()); //protected Cat(long)
3. 获取类中的方法
案例代码如下:
//父接口
interface AnimalInterface {
void testInterfacePublic();
int testInterfacePublic(int i);
int testInterfacePublic(int i, String str);
default void testInterfaceDefault() {
System.out.println("Interface:" + 1);
}
}
//子接口
interface CatInterface extends AnimalInterface {
void testSonInterfacePublic();
int testSonInterfacePublic(int i);
int testSonInterfacePublic(int i, String str);
default void testSonInterfaceDefault() {
System.out.println("SonInterface:" + 1);
}
}
//父类
class AnimalClass {
public void testFatherPublic() {
System.out.println("testFatherPublic");
}
public int testFatherPublic(int i) {
System.out.println("testFatherPublic:" + i);
return 0;
}
public int testFatherPublic(int i, String str) {
System.out.println("testFatherPublic:" + i + str);
return 0;
}
void testFatherDefault() {
System.out.println("testFatherDefault");
}
protected void testFatherProtected() {
System.out.println("testFatherProtected");
}
private void testFatherPrivate() {
System.out.println("testFatherPrivate");
}
}
/子类
class Cat extends AnimalClass {
public void testSonPublic() {
System.out.println("testSonPublic");
}
public int testSonPublic(int i) {
System.out.println("testSonPublic:" + i);
return 0;
}
public int testSonPublic(int i, String str) {
System.out.println("testSonPublic:" + i + str);
return 0;
}
void testSonDefault() {
System.out.println("testSonDefault");
}
protected void testSonProtected() {
System.out.println("testSonProtected");
}
private void testSonPrivate() {
System.out.println("testSonPrivate");
}
}
获取方法的四种方式:
-
Method[] getMethods():返回一个包含类或接口所有 public 方法的 Method 类型数组,包括他们的父类的所有 public 方法,注意,如果子类实现了某个接口,getMehtods 也无法获取到接口中的方法,他只能获取到父类中的方法,这里指的父类不仅仅是子类 Cat 的直接父类 AnimalClass,还递归地包含了父类的父类、父类的父类的父类等等,下面讲到的父类、父接口也是同理
Class<Cat> aClass = Cat.class; Method[] methods = aClass.getMethods(); System.out.println(methods.length); for (Method method : methods) { System.out.println(method.toString()); }
结果如下:
接口的测试代码:Class<CatInterface> aClass = CatInterface.class; Method[] methods = aClass.getMethods(); System.out.println(methods.length); for (Method method : methods) { System.out.println(method.toString()); }
结果如下:
-
Method getMethod(String name, Class<?>… parameterTypes):返回一个指定方法名称和参数类型(是一个 Class 数组)的 public 方法的 Method 对象,子类的 Class 对象可以通过这个方法来获取到父类中指定名称和参数的 public 方法,同理,这个方法也不能获取到父接口中的方法
Class<Cat> aClass = Cat.class; Class[] cls = new Class[]{}; Method method1 = aClass.getMethod("testFatherPublic",cls); //获取父类中的方法 Method method2 = aClass.getMethod("testSonPublic",cls); //获取子类自己的方法 Method method3 = aClass.getMethod("testFatherPrivate",cls); //编译通过,但运行出错,无法获取非public方法 System.out.println(method1.toString()); //public void AnimalClass.testFatherPublic() System.out.println(method2.toString()); //public void Cat.testSonPublic()
-
Method[] getDeclaredMethods():返回一个包含本类或本接口所有方法的 Method 类型数组
Class<Cat> aClass = Cat.class; Method[] methods = aClass.getDeclaredMethods(); System.out.println(methods.length); for (Method method : methods) { System.out.println(method.toString()); }
结果如下:
接口测试代码:Class<CatInterface> aClass = CatInterface.class; Method[] methods = aClass.getDeclaredMethods(); System.out.println(methods.length); for (Method method : methods) { System.out.println(method.toString()); }
结果如下:
-
Method getDeclaredMethod(String name, Class<?>… parameterTypes):返回一个本类或本接口中指定名称和参数类型的 Method 对象
Class<Cat> aClass = Cat.class; Class[] cls1 = new Class[]{int.class}; Class[] cls2 = new Class[]{}; Method method1 = aClass.getDeclaredMethod("testFatherPublic",cls2); //编译通过,但运行出错 Method method2 = aClass.getDeclaredMethod("testSonPublic",cls1); //获取子类自己的 public 方法 Method method3 = aClass.getDeclaredMethod("testSonProtected",cls2); //获取子类自己的 protected 方法 Method method4 = aClass.getDeclaredMethod("testSonDefault",cls2); //获取子类自己的 default 方法 Method method5 = aClass.getDeclaredMethod("testSonPrivate",cls2); //获取子类自己的 private 方法 System.out.println(method2.toString()); //public int Cat.testSonPublic(int) System.out.println(method3.toString()); //protected void Cat.testSonProtected() System.out.println(method4.toString()); //void Cat.testSonDefault() System.out.println(method5.toString()); //private void Cat.testSonPrivate()
4. 获取类中的字段
案例代码:
interface AnimalInterface {
void testFatherInterface();
int i = 1;
}
interface CatInterface extends AnimalInterface {
void testSonInterface();
long l = 1L;
}
class AnimalClass {
public int aFather;
protected double bFather;
long cFather;
private char dFather;
}
class Cat extends AnimalClass implements CatInterface{
public int aSon;
protected double bSon;
long cSon;
private char dSon;
@Override
public void testFatherInterface() {
}
@Override
public void testSonInterface() {
}
}
获取字段的方法有四个:
-
Field[] getFields():返回一个类或接口中所有的 public 字段的 Field 对象,包括父类和父接口中的所有 public 字段
Class<Cat> aClass = Cat.class; Field[] fields = aClass.getFields(); System.out.println(fields.length); for (Field field : fields) { System.out.println(field); }
结果如下:
-
Field getField(String name):返回一个指定名称的 public 字段的 Field 对象,通过子类的 Class 对象可以获取父类或父接口中指定名称的字段
Class<Cat> aClass = Cat.class; System.out.println(aClass.getField("i")); //获取间接父接口的 public 字段,public static final int AnimalInterface.i System.out.println(aClass.getField("l")); //获取直接父接口的 public 字段,public static final long CatInterface.l System.out.println(aClass.getField("aFather"));//获取父类的 public 字段,public int AnimalClass.aFather System.out.println(aClass.getField("bFather")); //获取父类的非 public 字段,编译通过,运行出错 System.out.println(aClass.getField("aSon")); //获取子类自己的 public 字段,public int Cat.aSon System.out.println(aClass.getField("bSon")); //获取子类自己的非 public 字段,编译通过,运行出错
-
Field[] getDeclaredFields():返回一个包含本类或本接口中所有字段的 Field 类型数组
Class<Cat> aClass = Cat.class; Field[] fields = aClass.getDeclaredFields(); System.out.println(fields.length); for (Field field : fields) { System.out.println(field); } //结果: 4 public int Cat.aSon protected double Cat.bSon long Cat.cSon private char Cat.dSon
接口测试代码:
Class<CatInterface> aClass = CatInterface.class; Field[] fields = aClass.getDeclaredFields(); System.out.println(fields.length); for (Field field : fields) { System.out.println(field); } //结果: 1 public static final long CatInterface.l
-
Field getDeclaredField(String name):返回一个本类或本接口中指定名称的 Field 对象
Class<Cat> aClass = Cat.class; Field field1 = aClass.getDeclaredField("aSon");//子类自己的 public 字段 Field field2 = aClass.getDeclaredField("bSon");//子类自己的 非public 字段 Field field3 = aClass.getDeclaredField("aFather");//父类的 public 字段,编译通过,运行出错 System.out.println(field1); //public int Cat.aSon System.out.println(field2); //protected double Cat.bSon
注意:静态部分的获取也是按照上面获取方法、字段的方式来获取,没有额外的特殊操作
具体的 java.lang.reflect 包中类的使用,在反射章节讲!
最后
以上就是飞快眼睛为你收集整理的Java 基础 (6) -- Class 类的全部内容,希望文章能够帮你解决Java 基础 (6) -- Class 类所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复