关于java-Class类的简单分析
java有个Class的基类,高级编程的时候,务必要理解这个。
粗略看下,可以明白了解Class这个类对于了解和掌握java非常重要。
Class这个类的包路径是:java.lang.Class<T>
可以看出来这是一个非常基础,非常核心的类,因为它的包路径位于java.lang,即java的语言包下面,可谓核心的核心。
一、开个好头
a.先看引入部分
import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; import java.lang.reflect.GenericDeclaration; import java.lang.reflect.Member; import java.lang.reflect.Field; import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.AnnotatedType; import java.lang.ref.SoftReference; import java.io.InputStream; import java.io.ObjectStreamField; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Set; import java.util.Map; import java.util.HashMap; import java.util.Objects; import sun.misc.Unsafe; import sun.reflect.CallerSensitive; import sun.reflect.ConstantPool; import sun.reflect.Reflection; import sun.reflect.ReflectionFactory; import sun.reflect.generics.factory.CoreReflectionFactory; import sun.reflect.generics.factory.GenericsFactory; import sun.reflect.generics.repository.ClassRepository; import sun.reflect.generics.repository.MethodRepository; import sun.reflect.generics.repository.ConstructorRepository; import sun.reflect.generics.scope.ClassScope; import sun.security.util.SecurityConstants; import java.lang.annotation.Annotation; import java.lang.reflect.Proxy; import sun.reflect.annotation.*; import sun.reflect.misc.ReflectUtil;
为了简化,我们把sun.refect.annotation.*算作一个,共有import语句45个,其中:27个和reflect(反射)有关,10个和java.util明显有关,3个和security(安全)有关,2个和io有关,余者3个。
所以这个Class类,可以大体理解为和反射,工具,安全,io有关的工具类。依赖那么多反射是因为必须通过反射来解析目标类或者对象。
如果可以,也大体可以这么认为:Class类大体就是通过反射功能分析和处理类的工具类。虽然它不仅仅是这样。
b.看下这个类的头部注释
头部的注释可谓是本类意图的较好表达。
为了便于大家查看,这里只列出JavaDoc显示的结果:
java.lang.Class<T> Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind ofclass and an annotation is a kind of interface.
Every array also belongs to a class that is reflected as a Class objectthat is shared by all arrays with the same element type and number of dimensions.
The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects. Class has no public constructor. Instead Classobjects are constructed automatically by the Java Virtual Machine as classesare loaded and by calls to the defineClass method in the classloader. The following example uses a Class object to print theclass name of an object: void printClassName(Object obj) { System.out.println("The class of " + obj + " is " + obj.getClass().getName()); } It is also possible to get the Class object for a namedtype (or for void) using a class literal. See Section 15.8.2 of The Java™ Language Specification.For example: System.out.println("The name of class Foo is: "+Foo.class.getName());
Type Parameters:<T> the type of the class modeled by this Classobject. For example, the type of String.class is Class<String>.
Use Class<?> if the class being modeled isunknown.
Since:JDK1.0
Author:unascribed
See Also:java.lang.ClassLoader.defineClass(byte [], int, int)
当然,也不仅仅是这个注释重要,整个类文件有3639行(rt.jar中,版本1.8.0_301),还有许多的属性和方法都具有较长的注释。
后面的注释后面说,开头这里先说说这一段话什么意思:
原文:
Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions. The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects. Class has no public constructor. Instead Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the classloader.
译文:
类Class的实例描绘了正在jvm中运行的类的接口。一个enum(枚举)是一种类,一个annotation(注解)是一种接口。
每个array也归属于一个类,这个类表示一个Class对象,这个对象被具有同个元素类型和维度的所有数组共享。
原始的java类型(boolean,byte,char,short,int,long,float和double),以及关键字void也被表示为一个Class对象。
Class没有公共的构造函数。但是Class对象可以被jvm自动构造,具体的方式是当类被加载,并由classloader执行defineClass方法。
c.历史
看一个图片:
注:
a.以上统计仅仅基于@since关键字,但还有许多方法是没有@since的,这些就是1.0就提供的。since1.0是放在Class定义头之上。
b.原来since后面跟的不都是 数字,例如1.0,1.8,而是有的 以JDK开头,有的直接就是一个数字。 从1.2(包含1.2)之后就不再带有JDK字眼,而是形如 @since 1.5
有意思吧,这个统计充分表明了几个信息:
1.从1.0开始java就构思这个基类,这个@since JDK1.0是放在类头,原文“ * @since JDK1.0”
2.版本 1.1,1.5,1.8引入了最多的,大体占据了89%
针对每个版本引入的新特性,对照每个发行申明中的新特性,就可以发现二者之间的紧密关系,而这种关联是想当然的。
二、定义
a. 定义
public final class Class<T> implements java.io.Serializable, GenericDeclaration, Type, AnnotatedElement
关键点:泛型、可序列化、通用定义、类型、注解
说明Class可以处理各种类的定义,类型和注解。
b.罕见关键字列表
这个罕见,是说在一般的应用编程中。
先理解这个词语,方能继续分析。
- primitive -- 发音 英 [ˈprɪmətɪv] 。含义:原始,本类用于表达一个类型是否原始类型
- volatile --
- 发音和原意思见百度翻译-200种语言互译、沟通全世界! (baidu.com),大意是五常性
- 具体用法见 (37条消息) Java volatile关键字最全总结:原理剖析与实例讲解(简单易懂)_老鼠只爱大米的博客-CSDN博客_java volatile
- 小结:java用这个修饰变量或者方法,目的是为了在多线程下共享变量或者方法块
- transient
- 发音和原来意思见 https://fanyi.baidu.com/?aldtype=85#en/zh/transient,大概意思是 转瞬即逝
- 具体用法见 java transient初探 - 袁立 - 博客园 (cnblogs.com)
- 小结: 这个是用于修饰对象属性,主要是控制是否序列化,这个容易让人想起JackSon或者fastJson的JsonIgnore
- native
- 发音和含义见 百度翻译-200种语言互译、沟通全世界! (baidu.com) ,大意是出生地的。
- 具体用法见 java中native的用法 - 不止吧 - 博客园 (cnblogs.com)
- 小结:主要修饰非java api方法
- SYNTHETIC
- 发音:[sɪnˈθetɪk] 。含义:合成的(形容词);合成物(名词)
- 具体用法:
- Java synthetic - -CoderLi - 博客园 (cnblogs.com)
- Synthetic Class in Java - Stack Overflow Java has the ability to create classes at runtime. These classes are known as Synthetic Classes or Dynamic Proxies
-
http://www.javaworld.com/article/2073578/java-s-synthetic-methods.html
-
http://javapapers.com/core-java/java-synthetic-class-method-field/
- http://java.sun.com/j2se/1.5.0/docs/guide/reflection/proxy.html
- 小结:这个东西常见于编译后的修饰说明,一般我们不会在代码中使用这个关键字。这是编译器编译java文件后的class文件中的关键字。所以这个词语理解为编译器合成/动态合成,也许更加贴切一些。
- 但也不仅仅是这样,还可能是动态代理的时候使用。
- Package
- 含义:包,即java中的包
- @CallerSensitive
- 含义:主调者敏感,大意是根据不同的主调者而有所不同
- 具体定义见 @CallerSensitive一些理解 - 追求极致 - 博客园 (cnblogs.com)
- 小结:大体可以理解为是一种安全机制,保证安全调用。
- ConstantPool
- 含义:常量池,是太阳公司反射包中一个类,用于获取jvm常量有关信息
三、构成
内容太多,没有必要一一罗列,只列出自己关注的部分。
函数和方法
- forName
- newInstance
- getGenericSuperclass
- getDeclaredFields
- getDeclaredMethods
- getResource
- getAnnotations
- getAnnotatedInterfaces
四、主要功能
- 获取类或者接口信息
- 反射,一遍动态编程
五、Object和getClass
为了配合反射,java的祖类Object,增加了一些重要的内容:
public final native Class<?> getClass();
这是一个泛型的native方法,且是final,即由jvm native块执行。
该方法的注释:
* @return The {@code Class} object that represents the runtime
* class of this object.
有了这个方法,反射就变得很容易了。
除了通过getClass获取Class,也可以直接在类名后跟上class获取,例如:
Class<ChineseMan> cc= ChineseMan.class;
直接看Object本身的定义并没有这个属性,但确可以使用,这是因为编译器自动做了这个活。
六、JVM
Class类的大量功能和内容和JVM是绑定在一起的。 贴几个JVM结构图:(注下图直接bing获取的,没有注意来源)
再来一个更加清楚的:
关于jvm,非长篇大论不足以详知,非本文内容,有关内容自行搜索,或者查看以下内容:
本文列出jvm内容,是为了说明native这个东西。native是jvm活着的主要目的,当然jvm不仅仅是native还有Excecution Engine(执行引擎)。因为这个,java其实够慢的。
七、示例
package study.base.reflect; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import study.base.classes.ChineseMan; public class ReflectTest { public static void printClassTree(Class<?> c) { List<String> classNameList=new ArrayList<String>(); getClassTree(c,classNameList); int lvl=classNameList.size(); for(int i=lvl-1;i>=0;i--) { int paddingQty=lvl-i; String paddingString=StringUtils.leftPad("", paddingQty,"-"); System.out.println(paddingString+classNameList.get(i)); } } public static void getClassTree(Class<?> c,List<String> result){ result.add(c.getName()); if (c.getSuperclass()!=null) { getClassTree(c.getSuperclass(),result); } } public static void printMethod(Method[] methods) { if (methods.length==0) { System.out.println("没有任何方法!"); } for (Method item:methods) { System.out.println(item.getDeclaringClass().getName()+":"+item.getName()); Parameter[] params=item.getParameters(); if (params.length>0) { for(Parameter p:params) { System.out.println( " "+p.getParameterizedType().getTypeName()+" "+p.getName() ); } } } } public static void printFileds(Field[] fields) { for(Field item:fields) { System.out.println(item.getName()+":"+item.getType().isPrimitive()); } } @SuppressWarnings({ "rawtypes", "unchecked" }) public static void main(String[] args) { ChineseMan cm=new ChineseMan("lzf"); cm.setLeftPadding(" --"); Class<ChineseMan> cc=ChineseMan.class; printClassTree(cc); System.out.println("-------------------------------------------------------"); System.out.println("获取类ChineseMan特有方法"); Method[] methods=cc.getDeclaredMethods(); printMethod(methods); System.out.println("-------------------------------------------------------"); System.out.println("获取类ChineseMan的所有属性"); printFileds(cc.getDeclaredFields()); System.out.println("-------------------------------------------------------"); System.out.println("执行cm的当前类方法--具有返回结果"); Class voidClass=Void.class; String voidClassName=voidClass.getSimpleName().toLowerCase(); for (Method item:methods) { Class returnType=item.getReturnType(); String returnTypeClassName=returnType.getSimpleName().toLowerCase(); if (!returnTypeClassName.equals(voidClassName)) { try { Object result=item.invoke(cm); System.out.println(item.getName()+":"+result.toString()); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } System.out.println("-------------------------------------------------------"); System.out.println("获取ChineseMan所有方法(含祖先)"); methods=cc.getMethods(); printMethod(methods); System.out.println("-------------------------------------------------------"); System.out.println("执行ChineseMan的父亲类"+cc.getSuperclass().getName()+"方法"); System.out.println("-------------------------------------------------------"); methods=cc.getSuperclass().getDeclaredMethods(); for (Method item:methods) { //System.out.println(item.getName()); if (item.getParameters().length==0) { try { System.out.print(" "+item.getName()+":"); if (!item.getReturnType().getSimpleName().toLowerCase().equals(voidClassName)) { Object result=item.invoke(cm); System.out.println(result.toString()); } else { item.invoke(cm); } } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } else { System.out.println(" "+item.getName()+"(...)"); } } } }
直接结果如下:
-java.lang.Object --study.base.classes.Organisms ---study.base.classes.Animal ----study.base.classes.Human -----study.base.classes.Man ------study.base.classes.ChineseMan ------------------------------------------------------- 获取类ChineseMan特有方法 study.base.classes.ChineseMan:set斗志 java.lang.String 斗志 study.base.classes.ChineseMan:get斗志 study.base.classes.ChineseMan:set力量 java.lang.String 力量 study.base.classes.ChineseMan:get力量 study.base.classes.ChineseMan:setSoldier boolean isSoldier study.base.classes.ChineseMan:isSoldier study.base.classes.ChineseMan:toString ------------------------------------------------------- 获取类ChineseMan的所有属性 isSoldier:true 斗志:false 力量:false ------------------------------------------------------- 执行cm的当前类方法--具有返回结果 get斗志:100 get力量:100 isSoldier:true toString:ChineseMan{ 姓名:lzf, 力量:100, 斗志:100 } ------------------------------------------------------- 获取ChineseMan所有方法(含祖先) study.base.classes.ChineseMan:set斗志 java.lang.String 斗志 study.base.classes.ChineseMan:get斗志 study.base.classes.ChineseMan:set力量 java.lang.String 力量 study.base.classes.ChineseMan:get力量 study.base.classes.ChineseMan:setSoldier boolean isSoldier study.base.classes.ChineseMan:isSoldier study.base.classes.ChineseMan:toString study.base.classes.Man:born study.base.classes.Man:work study.base.classes.Man:eat study.base.classes.Man:getLeftPadding study.base.classes.Man:familywork study.base.classes.Man:growOld study.base.classes.Man:disappear study.base.classes.Man:fallSick study.base.classes.Man:fight study.base.classes.Man:die study.base.classes.Man:bear study.base.classes.Man:teach study.base.classes.Man:setLeftPadding java.lang.String leftPadding study.base.classes.Man:run study.base.classes.Human:setGender java.lang.String gender study.base.classes.Human:getGender study.base.classes.Human:sleep study.base.classes.Animal:getEatable study.base.classes.Animal:setEatable java.lang.Boolean eatable study.base.classes.Organisms:setLocation java.lang.String location study.base.classes.Organisms:setType java.lang.String type study.base.classes.Organisms:getName study.base.classes.Organisms:getLocation study.base.classes.Organisms:setName java.lang.String name study.base.classes.Organisms:getType java.lang.Object:wait java.lang.Object:wait long arg0 int arg1 java.lang.Object:wait long arg0 java.lang.Object:equals java.lang.Object arg0 java.lang.Object:hashCode java.lang.Object:getClass java.lang.Object:notify java.lang.Object:notifyAll ------------------------------------------------------- 执行ChineseMan的父亲类study.base.classes.Man方法 ------------------------------------------------------- born: --生当作人杰,死亦为鬼雄! work: --锄禾日当午,汗滴禾下土! 以天为盖,以地为舆 eat: --但使残年饱吃饭,只愿无事常相见 getLeftPadding: -- familywork: --子不教,父之过! growOld: --儿童相见不相识,笑问客从何处来! disappear: --神龟虽寿,犹有竞时;腾蛇乘雾,终成土灰 fallSick: --僵卧孤村不自哀,尚思为国戍轮台 fight: --黄沙百战穿金甲,不破楼兰终不还 die: --人生自古谁无死,留取丹心照汗青 bear: --男人不能生孩子 teach: --师者,所以传道授业解惑者也! setLeftPadding(...) run: --醉里挑灯看剑,梦回吹角连营!
八、参考资料
参考内容太多,不一一列出,有的已经在前文列出。
Java发行历史(截止1.8) https://blog.csdn.net/wq6ylg08/article/details/91351603