本文会介绍反射相关的知识,为了不和泛型类的方法混在一起,本文集中介绍基本类的反射知识。主要内容包括: 类从被加载到虚拟机内存中开始,直到被卸载出内存为止,它的整个生命周期包括:加载,验证,准备,解析,初始化,使用和卸载这 7 个阶段。其中,验证,准备和解析这三个部分统称为连接(linking)。 加载阶段既可以使用系统提供的类加载器,也可以使用用户自定义的类加载器。加载阶段与连接阶段的部分内容(如一部分字节码文件格式验证动作)是交叉进行的,因此加载阶段尚未完成,连接阶段可能已经开始。 需要注意的是,同一个类只会被类加载器加载一次。 验证(Verification):这是连接阶段的第一步,验证是为了确保 Class 文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。验证包括:文件格式验证,元数据验证,字节码验证和符号引用验证。 准备(Preparation):这个阶段为类的静态变量分配内存并将其初始化为默认值,这些内存都将在方法区中进行分配。 需要注意的是,准备阶段不分配类中的实例变量的内存,因为实例变量将会在对象实例化时随着对象一起分配在 Java 堆中。 例如, 解析(Resolution):这个阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。 初始化(Initialization):这是类加载过程的最后一步。 前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的 Java 程序代码。 初始化阶段是执行类构造器 这里有一个 我们可以通过四种方式获取 第一种方式:通过类对象获取 打印信息: 第二种方式:通过类的 打印信息: 第三种方式:通过 打印信息: 第四种方式:通过 从上面的打印信息,可以看到:这四种方式的打印信息是一样的,但是这四种方式获取到的类对象是否相等呢? 我们通过代码验证一下: 打印结果: 它们是一模一样的,这是因为类只会被加载一次。 到这里,我们知道了获取类对象有 4 种方式,那么这 4 种方式之间有什么区别呢? 前两种方式:通过类对象获取和通过类的 通过 先看 从 调用 关键的就是第二个参数: 结论: 再看 结论: 如果加载的类依赖于初始化值的话,就需要采用 查看文档,获取类名的方法有: 这 4 个方法的区别是什么?它们分别适用于什么场合呢? 为了方便测试,这里写了一个泛型的打印方法: 我们先通过简单的 打印信息: 可以看到除了 但是,它们是有区别的。 下面展示会出现区别的场景: 嵌套类场景: 嵌套类就是静态内部类,大家不要把它和成员内部类混淆在一起了。 测试代码: 打印结果: 可以看到, 数组场景: 分别对一维和二维的字符串数组,打印相关信息: 打印结果: 可以看到, 匿名内部类场景: 打印结果: 可以看到,匿名内部类通过 到这里,对这 4 种获取名字的方法做一下总结: 查看 下面通过例子说明 需要注意的是,不能把这里的调用者 这里我们定义一个 测试代码如下: 打印信息: 如果是类,就返回超类; 查看文档,相关的函数有: 下面通过例子说明 需要注意的是,不能把这里的调用者 还有一点需要注意的是, 为了演示这个函数的使用,我们首先需要准备一些接口和类,并且为了便于理解类的关系,会提供一个类图出来。 类图如下: 测试代码: 对于 打印结果: 关于打印结果,需要做一下说明:打印的顺序就是 所以,我们可以根据索引来获取对应的接口: 打印信息: 对于 打印信息: 对于基本类型及 打印结果: 对于数组类型: 打印结果: 总结一下: 对于实现了接口的类,会返回所实现接口的数组,数组中元素顺序和实现顺序一致; 我们会遇到这样的需求,判断一个类是不是 这就需要获取类修饰符。这需要进行两步操作。 第一步要调用 这个函数返回i一个 第二步要调用 需要说明的一点是, 下面我们看代码演示: 测试类是 测试代码: 打印结果: 第二步,调用 打印结果: 我们再看一个接口的例子: 获取打包了所有修师符的 解析 打印结果: 这些方法比较容易掌握,这里只是把演示代码放出来: 但是,下面的这两个方法需要仔细区分一下,在实际开发中特别容易搞不清楚: 这里我们还是以 测试代码: 运行结果: 其实, 打印结果: 接着, 测试代码: 运行结果: 本文介绍了基本类的周边信息获取,希望能够帮助到大家。巩固好反射知识,对于阅读框架源码是很有帮助的。目录
1. 前言
2. 正文
2.1 类的生命周期
加载(Loading): 这是类加载过程的第一个阶段,在这个阶段,虚拟机需要完成三件事情:通过一个类的全限定名来获取定义这个类的二进制字节流;将这个二进制字节流所代表的静态存储结构转化为方法区的运行时数据结构;在 Java 堆中生成一个代表这个类的 java.lang.Class
对象,作为方法区里数据的访问入口。public static int value = 18;//在准备阶段value初始值为0 。在初始化阶段才会变为18 。
<clinit>()
方法的过程。<clinit>()
方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}
块)中的语句合并产生的。2.2 获取类类型
Fruit
类:package com.java.advanced.features.reflect; public class Fruit { public String taste; public Fruit() { } }
Fruit
类的类类型:Fruit fruit = new Fruit(); Class fruitClass1 = fruit.getClass(); System.out.println("fruitClass1 = " + fruitClass1);
fruitClass1 = class com.java.advanced.features.reflect.Fruit
class
对象获取Class fruitClass2 = Fruit.class; System.out.println("fruitClass2 = " + fruitClass2);
fruitClass2 = class com.java.advanced.features.reflect.Fruit
Class.forName(fullClassName)
获取Class fruitClass3 = null; try { fruitClass3 = Class.forName("com.java.advanced.feat } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println("fruitClass3 = " + fruitClass3);
fruitClass3 = class com.java.advanced.features.reflect.Fruit
Classloader.loadClass(fullClassName)
获取Class fruitClass4 = null; try { fruitClass4 = _01_GetClassTest.class.getClassLoader().loadClass("com.java.advanced.features.reflect.Fruit"); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println("fruitClass4 = " + fruitClass4);
System.out.println("result = " + (fruitClass1 == fruitClass2 && fruitClass2 == fruitClass3 && fruitClass3 == fruitClass4));
result = true
class
对象获取,不会抛出异常;后两种方式:通过Class.forName(fullClassName)
获取和通过 Classloader.loadClass(fullClassName)
获取,可能会抛出 ClassNotFoundException
异常。Class.forName(fullClassName)
获取的 Class 是已经完成初始化的,通过 Classloader.loadClass(fullClassName)
获取的 Class 是还没有连接的。为什么有这样的区别,我们需要去看一下源码:Class.forName()
:public static Class<?> forName(String className) throws ClassNotFoundException { Class<?> caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); } public static Class<?> forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException { Class<?> caller = null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { // Reflective call to get caller class is only needed if a security manager // is present. Avoid the overhead of making this call otherwise. caller = Reflection.getCallerClass(); if (sun.misc.VM.isSystemDomainLoader(loader)) { ClassLoader ccl = ClassLoader.getClassLoader(caller); if (!sun.misc.VM.isSystemDomainLoader(ccl)) { sm.checkPermission( SecurityConstants.GET_CLASSLOADER_PERMISSION); } } } return forName0(name, initialize, loader, caller); }
forName(String name, boolean initialize, ClassLoader loader)
的方法文档注释里,可以看到:Class.forName("Foo")
等价于调用 Class.forName("Foo", true, this.getClass().getClassLoader())
。boolean initialize
,表示这个类是否要被初始化。Class.forName(fullClassName)
方式表示类是被初始化的。ClassLoader
类的 loadClass()
方法:public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); } protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c;
loadClass(String name)
调用的是 loadClass(String name, boolean resolve)
方法,第二个参数的值是 false
。boolean resolve
的意思是是否连接该类(Links the specified class)。Classloader.loadClass(fullClassName)
不会链接类。Class.forName(fullClassName)
的方式,而不能采用Classloader.loadClass(fullClassName)
方式。2.3 获取类名
public String getName() public String getSimpleName() public String getCanonicalName() public String getTypeName()
private static <T> void print(Class<T> clazz, String label) { System.out.println(label + ".getName() = " + clazz.getName()); System.out.println(label + ".getSimpleName() = " + clazz.getSimpleName()); System.out.println(label + ".getCanonicalName() = " + clazz.getCanonicalName()) System.out.println(label + ".getTypeName() = " + clazz.getTypeName()); System.out.println(); }
Fruit
类来说明:print(Fruit.class, "simpleClass");
simpleClass.getName() = com.java.advanced.features.reflect.Fruit simpleClass.getSimpleName() = Fruit simpleClass.getCanonicalName() = com.java.advanced.features.reflect.Fruit simpleClass.getTypeName() = com.java.advanced.features.reflect.Fruit
getSimpleName()
外,其他三个打印信息是一样的。package com.java.advanced.features.reflect.basicclass; public class OuterClass { public static final class StaticInnerClass { } }
print(OuterClass.StaticInnerClass.class, "staticInnerClassClass");
staticInnerClassClass.getName() = com.java.advanced.features.reflect.basicclass.OuterClass$StaticInnerClass staticInnerClassClass.getSimpleName() = StaticInnerClass staticInnerClassClass.getCanonicalName() = com.java.advanced.features.reflect.basicclass.OuterClass.StaticInnerClass staticInnerClassClass.getTypeName() = com.java.advanced.features.reflect.basicclass.OuterClass$StaticInnerClass
getCanonicalName()
获取到的名字和 getName()
以及 getTypeName()
就不一样了。print(String[].class, "1-arrayClass"); print(String[][].class, "2-arrayClass");
1-arrayClass.getName() = [Ljava.lang.String; 1-arrayClass.getSimpleName() = String[] 1-arrayClass.getCanonicalName() = java.lang.String[] 1-arrayClass.getTypeName() = java.lang.String[] 2-arrayClass.getName() = [[Ljava.lang.String; 2-arrayClass.getSimpleName() = String[][] 2-arrayClass.getCanonicalName() = java.lang.String[][] 2-arrayClass.getTypeName() = java.lang.String[][]
getName()
获取的名字和 getCanonicalName()
以及 getTypeName()
不同。print(new Serializable() { }.getClass(), "anonymousInnerClass");
anonymousInnerClass.getName() = com.java.advanced.features.reflect.basicclass._02_GetClassNamePackageNameTest$1 anonymousInnerClass.getSimpleName() = anonymousInnerClass.getCanonicalName() = null anonymousInnerClass.getTypeName() = com.java.advanced.features.reflect.basicclass._02_GetClassNamePackageNameTest$1
getSimpleName()
获取到的是空字符串,通过 getCanonicalName()
获取到的是 null
。getName()
:返回的是虚拟机里面的 class 的表示,是动态加载类所需要的,例如用于Class.forName(String name)
;
getCanonicalName()
:返回的是更容易理解的表示 用于获取 import
的名字;
getSimpleName()
:获取类名的标识符;
getTypeName()
: 如果不是数组,就调用 getName()
;是数组,就是类名后面跟维数([]),几维就跟几个[]。2.4 获取超类的
Class
对象Class
类的文档有两个函数:// 获取 Class 对象的普通类型父类 public native Class<? super T> getSuperclass(); // 获取 Class 对象的泛型类型父类 public Type getGenericSuperclass()
getSuperclass()
的使用。至于 getGenericSuperclass()
后面会介绍。Class
对象局限为类对应的 Class
对象,还应该包括接口,基本类型以及 void
对应的 Class
对象。Apple
类,它继承 Fruit
类:public class Fruit { public String taste; } public class Apple extends Fruit { }
System.out.println("Apple.class.getSuperclass() = " + Apple.class.getSuperclass()); System.out.println("Collection.class.getSuperclass() = " + Collection.class.getSuperclass()); System.out.println("int.class.getSuperclass() = " + int.class.getSuperclass()); System.out.println("void.class.getSuperclass() = " + void.class.getSuperclass()); System.out.println("stringArray.getClass().getSuperclass() = " + String[].class.getSuperclass()); System.out.println("integerArray.getClass().getSuperclass() = " + Integer[].class.getSuperclass());
Apple.class.getSuperclass() = class com.java.advanced.features.reflect.Fruit Collection.class.getSuperclass() = null int.class.getSuperclass() = null void.class.getSuperclass() = null stringArray.getClass().getSuperclass() = class java.lang.Object integerArray.getClass().getSuperclass() = class java.lang.Object
如果是接口,基本类型或 void
,就返回 null
;
如果是数组,就返回 Object
。2.5 获取直接继承或实现的接口的
Class
对象列表// 获取 Class 对象的直接继承或实现的接口 Class 对象列表 public Class<?>[] getInterfaces() // 获取 Class 对象的直接继承或实现的泛型接口 Class 对象列表 public Type[] getGenericInterfaces()
getInterfaces()
的使用。至于 getGenericInterfaces()
后面会介绍。Class
对象局限为类对应的 Class
对象,还应该包括接口,基本类型以及 void
对应的 Class
对象。getInterfaces()
方法返回的是 Class<?>[]
,这是一个数组。这是因为在 Java 中,一个类可以实现多个接口,一个接口可以继承于多个接口。public interface SuperPower { } public interface XRayVision extends SuperPower { void seeThroughWalls(); } public interface SuperHearing extends SuperPower { void hearSubtleNoises(); } public interface SuperSmell extends SuperPower { void trackBySmell(); } public interface SuperHearSmell extends SuperHearing, SuperSmell { } public interface Workable { void work(); } public class Man implements Workable { @Override public void work() {} } public class SuperHero extends Man implements XRayVision, SuperHearing, SuperSmell { @Override public void hearSubtleNoises() {} @Override public void trackBySmell() {} @Override public void seeThroughWalls() {} }
还需要封装一个打印方法:private static <T> void printGetInterfaces(Class<T> clazz) { Class<?>[] interfaces = clazz.getInterfaces(); if (interfaces.length == 0) { System.out.println("返回数组长度为 0。"); System.out.println(); return; } for (Class<?> element : interfaces) { System.out.println(element.getName()); } System.out.println();
SuperHero
,这是一个继承于 Man
类,并且实现了多个接口的类:printGetInterfaces(SuperHero.class);
com.java.advanced.features.reflect.basicclass.XRayVision com.java.advanced.features.reflect.basicclass.SuperHearing com.java.advanced.features.reflect.basicclass.SuperSmell
SuperHero
实现接口的顺序:public class SuperHero extends Man implements XRayVision, SuperHearing, SuperSmell
Class<?>[] interfaces = SuperHero.class.getInterfaces(); System.out.println("interfaces[0] = " + interfaces[0]); System.out.println("interfaces[1] = " + interfaces[1]); System.out.println("interfaces[2] = " + interfaces[2]);
interfaces[0] = interface com.java.advanced.features.reflect.basicclass.XRayVision interfaces[1] = interface com.java.advanced.features.reflect.basicclass.SuperHearing interfaces[2] = interface com.java.advanced.features.reflect.basicclass.SuperSmell
SuperHearSmell
接口,它继承了多个接口:printGetInterfaces(SuperHearSmell.class);
com.java.advanced.features.reflect.basicclass.SuperHearin com.java.advanced.features.reflect.basicclass.SuperSmell
void
:printGetInterfaces(int.class); printGetInterfaces(void.class);
返回数组长度为 0。 返回数组长度为 0。
printGetInterfaces(String[].class);
java.lang.Cloneable java.io.Serializable
对于继承了接口的接口,会返回所直接继承的接口数组,数组中元素顺序和继承顺序一致;
对于没有实现接口的类或没有继承接口的接口,会返回长度为 0 的数组;
对于基本类型或 void
类型,会返回长度为 0 的数组;
对于数组类型,会返回由 java.lang.Cloneable
和 java.io.Serializable
组成的数组。2.6 获取类修饰符
pulibc
的?是不是 static
的?是不是 final
的?Class
类的 getModifiers()
方法,返回 Class
对象以整数编码的 Java 语言修饰符。public native int getModifiers();
int
值,Class
对象包含的所有修饰符都打包在这个 int
值里面了。Modifier
类的相关静态函数,来解析上面得到的 int
值,或者判断 int
值里面是否有某个修饰符。// 是否包含 public 修饰符 public static boolean isPublic(int mod) // 是否包含 private 修饰符 public static boolean isPrivate(int mod) // 是否包含 protected 修饰符 public static boolean isProtected(int mod) // 是否包含 static 修饰符 public static boolean isStatic(int mod) // 是否包含 final 修饰符 public static boolean isFinal(int mod) // 是否包含 synchronized 修饰符 public static boolean isSynchronized(int mod) // 是否包含 volatile 修饰符 public static boolean isVolatile(int mod) // 是否包含 transient 修饰符 public static boolean isTransient(int mod) // 是否包含 native 修饰符 public static boolean isNative(int mod) // 是否包含 interface 修饰符 public static boolean isInterface(int mod) // 是否包含 abstract 修饰符 public static boolean isAbstract(int mod) // 是否包含 strictfp 修饰符 public static boolean isStrict(int mod) // 解析参数 mod 对应的修饰符 public static String toString(int mod)
Modifier
类不仅仅是应用于解析或判断类修饰符,也包括接口修饰符,变量修饰符,方法修饰符。StaticInnerClass
:public class OuterClass { public static final class StaticInnerClass { } }
StaticInnerClass
包含 3 个修饰符:public
,static
和 final
。
第一步:获取打包所有修饰符的 int
值:Class<OuterClass.StaticInnerClass> clazz = OuterClass.StaticInnerClass.class; int modifiers = clazz.getModifiers(); System.out.println("modifiers = " + modifiers);
modifiers = 25
Modifier
类的相关函数来解析上一步得到的 int
值或判断是否包含某个修饰符。System.out.println("Modifier.toString(modifiers) = " + Modifier.toString(modifiers)); System.out.println("Modifier.isPublic(modifiers) = " + Modifier.isPublic(modifiers)); System.out.println("Modifier.isStatic(modifiers) = " + Modifier.isStatic(modifiers)); System.out.println("Modifier.isFinal(modifiers) = " + Modifier.isFinal(modifiers));
Modifier.toString(modifiers) = public static final Modifier.isPublic(modifiers) = true Modifier.isStatic(modifiers) = true Modifier.isFinal(modifiers) = true
public interface OuterInterface { public static interface InnerInterface { } }
int
值:int modifiers3 = OuterInterface.InnerInterface.class.getModifiers(); System.out.println("modifiers3 = " + modifiers3); // 打印:1545
int
值或判断是否包含某修饰符:System.out.println("Modifier.toString(modifiers3) = " + Modifier.toString(modifiers3)); System.out.println("Modifier.isPublic(modifiers3) = " + Modifier.isPublic(modifiers3)); System.out.println("Modifier.isAbstract(modifiers3) = " + Modifier.isAbstract(modifiers3)); System.out.println("Modifier.isStatic(modifiers3) = " + Modifier.isStatic(modifiers3)); System.out.println("Modifier.isInterface(modifiers3) = " + Modifier.isInterface(modifiers3));
Modifier.toString(modifiers3) = public abstract static interface Modifier.isPublic(modifiers3) = true Modifier.isAbstract(modifiers3) = true Modifier.isStatic(modifiers3) = true Modifier.isInterface(modifiers3) = true
2.7
Class
对象的 isXXX()
@Deprecated public class _09_ClassIsXXXMethodTest { public static void main(String[] args) { // isAnnotation() 是不是注解类型 System.out.println("Override.class.isAnnotation() = " + Override.class.isAnnotation()); // isAnnotationPresent(Class<? extends Annotation> annotationClass) boolean annotationPresent = _09_ClassIsXXXMethodTest.class.isAnnotationPresent(Deprecated.class); System.out.println("annotationPresent = " + annotationPresent); // isAnonymousClass() 是不是匿名类 System.out.println("new Serializable(){}.getClass().isAnonymousClass() = " + new Serializable() { }.getClass().isAnonymousClass()); // isArray() 是不是数组 System.out.println("String[].class.isArray() = " + String[].class.isArray()); // isAssignableFrom(Class<?> cls) System.out.println("Collection.class.isAssignableFrom(List.class) = " + Collection.class.isAssignableFrom(List.class)); // isEnum() System.out.println("Color.class.isEnum() = " + Color.class.isEnum()); // isInstance(Object obj) List<String> list = new ArrayList<>(); System.out.println("Collection.class.isInstance(list) = " + Collection.class.isInstance(list)); // isInterface() 是不是接口 System.out.println("Serializable.class.isInterface() = " + Serializable.class.isInterface()); class A { } // isLocalClass() 是不是局部类,定义在方法内部的类 System.out.println("A.class.isLocalClass() = " + A.class.isLocalClass()); // 是不是成员类 System.out.println("B.class.isMemberClass() = " + B.class.isMemberClass()); // isPrimitive() 是不是原生类型 System.out.println("int.class.isPrimitive() = " + int.class.isPrimitive()); } class B { } }
public native boolean isInstance(Object obj); public native boolean isAssignableFrom(Class<?> cls);
isInstance(Object obj)
方法:判断参数指定的对象是否是调用者 Class
对象所表示的类及其子类的实例。Apple
类来说明,它继承 Fruit
类:public class Fruit { public String taste; } public class Apple extends Fruit { }
Apple apple = new Apple(); Fruit fruit = new Fruit(); System.out.println("Fruit.class.isInstance(apple) = " + Fruit.class.isInstance(apple)); System.out.println("Fruit.class.isInstance(fruit) = " + Fruit.class.isInstance(fruit));
Fruit.class.isInstance(apple) = true Fruit.class.isInstance(fruit) = true
isInstance()
方法和 instanceof
关键字作用是一样的,我们来看一下使用 instanceof
关键字的写法:System.out.println("apple instanceof Fruit = " + (apple instanceof Fruit)); System.out.println("fruit instanceof Fruit = " + (fruit instanceof Fruit));
apple instanceof Fruit = true fruit instanceof Fruit = true
isAssignableFrom(Class<?> cls)
方法:它的参数是一个 Class
对象,用于判断调用者Class
对象是否和参数Class
对象为同一类型或者是参数 Class
对象的超类或超接口。boolean assignableFrom = Fruit.class.isAssignableFrom(Apple.class); System.out.println("assignableFrom = " + assignableFrom);
assignableFrom = true
3. 最后
参考
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算