关于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.罕见关键字列表

这个罕见,是说在一般的应用编程中。

先理解这个词语,方能继续分析。

 

  • 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

 

posted @ 2022-03-27 17:12  正在战斗中  阅读(158)  评论(0编辑  收藏  举报