Class是一个非常有用的类,在jvm底层很多功能都是通过这个类实现的;
Object是所有类的父类,所有类都是Class的实例:
public final class Class<T> implements java.io.Serializable, java.lang.reflect.GenericDeclaration, java.lang.reflect.Type, java.lang.reflect.AnnotatedElement {
private static final int ANNOTATION= 0x00002000; //8192 private static final int ENUM = 0x00004000; //16384 private static final int SYNTHETIC = 0x00001000; //4096
final声明的类,表明该类不能被继承,属性和方法不能被复写;
private static native void registerNatives(); static { registerNatives(); }
利用静态块调动静态方法,这个方法时native声明的,表明是调用系统方法; RegisterNatives将本地对象向VM进行登记,使得VM迅速找到;
执行顺序:是看该属性有没有分配到空间(载体);如果有空间就执行,没有空间的要创建空间后(实例化、初始化)才执行;方法有没有被调用,被调用后才被执行;
private Class() {}
构造方法私有化,外部不能创建实例,通过只有内部类创建和获得实例,或者通过A getA(){return new A();}方式获得;
public String toString() { return (isInterface() ? "interface " : (isPrimitive() ? "" : "class ")) + getName(); }
覆写toString()方法,返回接口名,基本数据类型,类名,比如:
Class clazz = int.class; System.out.println(clazz.toString()); //int
参考文档:http://msdn.microsoft.com/zh-cn/library/aa989577(v=vs.80).aspx ;
jdk api中文版
1、public static Class forName(java.lang.String className);
获得Class实例的4种方法: Class clazz = Class.forName("java.lang.String"); Class clazz = String.class; Class clazz = new String("").getClass(); Class clazz2 = Integer.Type; //这种获得Class实例的方法只适合包装类 System.out.println(clazz2.toString()); //返回的基本类 :int2、 public static Class forName(String className, boolean initialize, ClassLoader loader);
方法1调用方法2
ClassLoader:根据className来加载这个class类;3、public java.lang.Class[] getClasses() 得到当前类中定义的public内部类/接口:
public class Demo1 { private class Demo1a{} class Demo1b{} public class Demo1c{} public interface Demo1d{} public String str; }test:
public static void main(String[] args) { Class clazz = Demo1.class; Class[] claz = clazz.getClasses(); System.out.println(claz.length); for(int i= 0; i<claz.length;i++){ System.out.println(claz[i].getName()); } } 输出: 2 org.skx.test.Demo1$Demo1c org.skx.test.Demo1$Demo1d4、public java.lang.ClassLoader getClassLoader() ,获得类加载器:
Class clazz1 = String.class; Class clazz2 = Demo1.class; System.out.println(clazz1.getClassLoader()); System.out.println(clazz2.getClassLoader()); 输出: null sun.misc.Launcher$AppClassLoader@15253d5为什么第一个的类加载器为null ? 因为它是由启动类Bootstrap加载器完成加载的,启动类加载是所有类加载器的父类,返回值都为null, 类加载器将在以后章节详解;
5、public java.lang.Class getComponentType() ,获得一个数组的组件类型
Class clazz = new Demo1[4].getClass(); System.out.println(clazz.getComponentType()); 输出: class org.skx.test.Demo16、public java.lang.reflect.Constructor getConstructor(java.lang.Class[] parameterTypes) ,获得public,含参的 构造方法,唯一匹配;
Demo1(){} public Demo1(String str){System.out.println("ok");} public Demo1(String str,int x){System.out.println("ok");} private Demo1(String str,int x,String s){System.out.println("ok");} //非public的构造方法测试:
try{ Class clazz = Demo1.class; Class[] argss = new Class[3]; argss[0] = String.class; argss[1] = int.class; argss[2] = String.class; System.out.println(clazz.getConstructor(argss[0])); System.out.println(clazz.getConstructor(argss[0],argss[1])); System.out.println(clazz.getConstructor(argss[0],argss[1],argss[2])); //抛出异常 }catch (NoSuchMethodException e){ System.out.println("找不到这个构造方法"); } 输出: public org.skx.test.Demo1(java.lang.String) public org.skx.test.Demo1(java.lang.String,int) 找不到这个构造方法7、public java.lang.reflect.Constructor[] getConstructors() 获得public的构造方法,返回数组
Class clazz = Demo1.class; Constructor[] constructor = clazz.getConstructors(); System.out.println(constructor.length); for(int i=0; i<constructor.length;i++){ System.out.println(constructor[i]); } 输出: 2 public org.skx.test.Demo1(java.lang.String,int) public org.skx.test.Demo1(java.lang.String)8、public java.lang.reflect.Constructor getDeclaredConstructor(java.lang.Class[ ] parameterTypes) 唯一匹配,从所用声明过的构造方法中,不管是不是public的:
复制6的测试,改写为:
System.out.println(clazz.getDeclaredConstructor()); System.out.println(clazz.getDeclaredConstructor(argss[0])); System.out.println(clazz.getDeclaredConstructor(argss[0],argss[1])); System.out.println(clazz.getDeclaredConstructor(argss[0],argss[1],argss[2])) 输出: org.skx.test.Demo1() public org.skx.test.Demo1(java.lang.String) public org.skx.test.Demo1(java.lang.String,int) private org.skx.test.Demo1(java.lang.String,int,java.lang.String)9、public java.lang.reflect.Constructor[ ] getDeclaredConstructors() ,放回所有构造方法数组;
10、在方法3中,获取的是public的内部类,这里获取所有的内部类;public java.lang.Class[ ] getDeclaredClasses();
11、public java.lang.reflect.Field getField(java.lang.String fieldName) 获得public 配对的属性:
Class clazz = Demo1.class; try { System.out.println(clazz.getField("str")); } catch (NoSuchFieldException e) { System.out.println("没有找到这个属性"); }
12、public java.lang.reflect.Field[ ] getFields() 获得public声明的属性
13、public java.lang.reflect.Field getDeclaredField(java.lang.String fieldName)
14、public java.lang.reflect.Field[ ] getDeclaredFields()
15、public java.lang.reflect.Method getMethod(java.lang.String methodName, java.lang.Class[ ] parameterTypes) 获得public 匹配的方法:
Demo1: // public void say0(){System.out.println(str);} public void say0(String str){System.out.println(str);} private void say1(int a){System.out.println(a);} public void say(String str,int a){System.out.println("ok");}
test:
Class clazz = Demo1.class; try { System.out.println(clazz.getMethod("say0", null)); } catch (NoSuchMethodException e) { System.out.println("没有找到say0()方法"); } try { System.out.println(clazz.getMethod("say0", String.class)); } catch (NoSuchMethodException e) { System.out.println("没有找到say0(String str)方法"); } try { System.out.println(clazz.getMethod("say1",int.class)); } catch (NoSuchMethodException e) { System.out.println("没有找到say1(int a)方法"); } try { System.out.println(clazz.getMethod("say",String.class,int.class)); } catch (NoSuchMethodException e) { System.out.println("没有找到say(String str,int a)方法"); } 输出: 没有找到say0()方法 public void org.skx.test.Demo1.say0(java.lang.String) 没有找到say1(int a)方法 public void org.skx.test.Demo1.say(java.lang.String,int)
16、public java.lang.reflect.Method[ ] getMethods() ,获取public声明的所有方法
17、public java.lang.reflect.Method getDeclaredMethod(java.lang.String methodName, java.lang.Class[ ] parameterTypes)
18、public java.lang.reflect.Method[ ] getDeclaredMethods()
19、public java.lang.Class[ ] getInterfaces() 获得接口数组,如
Demo impliments INinterface{}
20、public int getModifiers(),获取修饰符,如public,abstract,private等的声明符,注意返回的是int型的;使用Modifier.toString(int a)进行转换
Class clazz = Demo1.class; int x=clazz.getModifiers(); System.out.println(x); System.out.println(Modifier.toString(x)); 输出: 1 public
Modifier.toString(int x)
public static String toString(int mod) { StringBuffer sb = new StringBuffer(); int len; if ((mod & PUBLIC) != 0) sb.append("public "); if ((mod & PROTECTED) != 0) sb.append("protected "); if ((mod & PRIVATE) != 0) sb.append("private "); if ((mod & ABSTRACT) != 0) sb.append("abstract "); if ((mod & STATIC) != 0) sb.append("static "); if ((mod & FINAL) != 0) sb.append("final "); if ((mod & TRANSIENT) != 0) sb.append("transient "); if ((mod & VOLATILE) != 0) sb.append("volatile "); if ((mod & SYNCHRONIZED) != 0) sb.append("synchronized "); if ((mod & NATIVE) != 0) sb.append("native "); if ((mod & STRICT) != 0) sb.append("strictfp "); if ((mod & INTERFACE) != 0) sb.append("interface "); if ((len = sb.length()) > 0) /* trim trailing space */ return sb.toString().substring(0, len-1); return ""; }
21、getName()
22、public java.lang.Class getSuperclass()
23、public Type getGenericSuperclass() //获得含泛型参数的父类
24、public Type[] getGenericInterfaces() { //获得带泛型参数的接口
25、public java.lang.Object newInstance() 创建实例
public T newInstance()throws InstantiationException, IllegalAccessException{ if (System.getSecurityManager() != null) { checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false); } return newInstance0(); }
这里对SecurityManager这个类说明一下,安全管理类java.lang.SecurityManager,通过抛出异常来提供阻止操作完成的机会。该类的方法以checkXXX命名,如果允许执行,安全管理器不做任何操作,但如果不允许执行该操作,抛出一个 SecurityException
,唯一例外是 checkTopLevelWindow
,它返回 boolean
值。通过System.getSecurityManager()获取一个实例(通过set设置一个实例,SecurityManager在System静态设置获取);checkMemberAccess表示:如果不允许调用线程访问程序,抛出 SecurityException
。
private volatile transient Constructor<T> cachedConstructor; private volatile transient Class<?> newInstanceCallerCache;
这里有两个关键字:volatile['v?l?ta?l]和transient['trænz??nt]以前没有接触过,他们是什么意思呢?字面意思易变的和短暂的,这里简单说明一下
volatile的适用:在多线程机制中,每个线程中有一块memory来保存资源的副本,方便自己访问以提高运行效率,使用synchronized声明一个方法,使得对象对资源的访问变为直接向主资源访问并在访问时进行加锁;volatile声明一个属性,VM限制其他对象拷贝这个成员变量,只能直接访问这个变量;
Java的serialization提供了一种持久化(串行化)对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。 transient是Java语言的关键字,用来表示一个域是不会被该对象 串行化。当一个对象被串行化的时候,transient型变量不会被串行化,然而非transient型的变量被序列化。
public native boolean isInstance(Object obj);
通过系统程序来判断一个对象是不是clazz所代表类的实例;
Class clazz = Arrays.class; String obj = "ok"; System.out.println(clazz.isInstance(obj)); //false 表示判断obj是否为clazz的实列
判断两个类是否相同,或判断是否为另一个类的父类/接口
public native boolean isAssignableFrom(Class<?> cls);
public class TestUtil extends FileUtil implements TestInt{ public static void main(String[] args) throws Exception { Class clazz = TestUtil.class; Class clazz2 = FileUtil.class; Class intE = TestInt.class; System.out.println(clazz.isAssignableFrom(clazz)); //true System.out.println(clazz2.isAssignableFrom(clazz)); //true注意是clazz是从clazz2派生而来的 System.out.println(intE.isAssignableFrom(clazz)); //true表示clazz AssignableFrom intE; }}
判断类是否为接口、数组、基本数据类型;
public native boolean isInterface(); public native boolean isArray(); public native boolean isPrimitive();
Class intE = TestInt.class; Class arr = Class.forName("java.util.Arrays"); Class arr2 = new int[4].getClass(); Class primi = int.class; System.out.println(intE.isInterface()+"||"+arr.isArray()+"||"+arr2.isArray()+"||"+primi.isPrimitive()); //true||false||true||true
为什么arr不是一个Array呢?因为Arrays只是一个普通类,就好比你顺便写了个类,你觉得那是数组,jvm不会执行你的类来判断是不是数组(jvm不会给类分配执行内存),所以jvm不是根据名字就判断出他是不是数组,应该是根据名字找到类所在的.class文件;而接口和基本类可以判断出来,可能是接口有interface关键字声明,基本数据类型用相应的关键字(就不用在内存中去查看,就能判断是不是接口和基本类了);如何判断是不是一个数组呢?先创建一个数组实列new int[4];添加getClass()就返回了一个Class实列,可以通过clazz.getName()查看到底返回了一个怎么样的类型:[I ,而不是想象的java.util.Arrays,这又是怎么回事呢?假如现在创建的是一个new long[4],返回了[J;double[4]返回[D;float[4] 返回[F;short[4]返回[S;byte[4]返回[B;char[4],返回[C;boolean[4]返回[Z,;new String[4]返回[Ljava.lang.String;Double[4]返回[Ljava.lang.Double;Arrays[4]返回[Ljava.util.Arrays;FileUtil[4]返回[Lorg.skx.api 发现了一个规律:基本类数组返回是[+“X”,而其他基本类返回的是一个[+“X”+包.类;还是因为jvm从头到尾都不知道Arrays是干什么的!所以只返回基本类型的数组表示如int型为[I;只有在new开辟了一个内存之后,jvm能通过内存得知这是一个对象数组的形式(数组都可以称为对象数组,有些是基本类型数组);并得到他的相关属性;
Class clazz = String.class; System.out.println(clazz.isArray()); //false clazz只能等到String的类名、包名、属性、方法、等等,但不能知道String在内存中是个什么形式; new int[3][4][5][6][7][8][9]).getClass().getName() returns "[[[[[[[I"
isInterface()和isPrimitive()在Class.toString()中被调用;
public boolean isAnnotation() { return (getModifiers() & ANNOTATION) != 0; }
判断该类是不是一个注解类,比如:
import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Annotation1 { //创建一个注解类 String value(); } Class anno = Annotation1.class; System.out.println(anno.isAnnotation());
判断一个类是不是复合类:内部类是复合类,但只会返回false;
public boolean isSynthetic() { return (getModifiers() & SYNTHETIC) != 0; }
查看资料:isSynthetic()是用来判断Class是不是“复合类”。这在java应用程序中只会返回false,不会返回true。因为,JVM中才会产生复合类,在java应用程序中不存在“复合类”!
获得类<变量>:获得泛型参数,不是一般的变量:
public TypeVariable<Class<T>>[] getTypeParameters()
public class Demo1<E,T> { private String str = "ok"; private int x = 32; private long[] l = {2,3,4,5,6}; } Class demo1 = Demo1.class; TypeVariable[] attr = demo1.getTypeParameters(); for(int i=0;i<attr.length;i++){ System.out.println(attr[i].toString()); //或者getName(); } //E,T
获得包名:
public Package getPackage() {
获得方法里面的 局部类(含匿名类),比如:
public Method getEnclosingMethod() {
public class Demo6 { Object say(){ class A{ A(){ System.out.println("hello"); } } return new A(); } }
Class clazz =new Demo6().say().getClass(); //得到A System.out.println(clazz.getEnclosingMethod()); //A是通过这个方法创建的 hello java.lang.Object org.skx.api.Demo6.say()public Constructor<?> getEnclosingConstructor()
如果该 Class 对象表示构造方法中的一个本地或匿名类,则返回 Constructor
对象,它表示底层类的立即封闭构造方法。否则返回 null。实现方法同上
其他的方法暂不再介绍,没有发现如何获取import字段的方法,
如何获取属性是什么类型和方法返回类型,查看Field和Method的相关方法;
这里讲解了如何获取:包名,声明符,类名,泛型参数,接口,父类名,构造方法,属性,一般方法,判断是否为接口、基本类、数组、注解等;
创建Class的4中方法,获取类加载器,获取数组组件类型;