Class类简述
class
类和 java.lang.String
, java.lang.Integer
或是我们自定义的类一样,都是java中的类,都继承自 java.lang.Object
, 只不过名字比较特殊。
对于我们自己定义的类,我们用类来抽象现实中的某些事物,比如我们定义一个名称为 Car
的类来抽象现实生活中的车,然后可以实例化这个类,用这些实例来表示我的车、你的车、黄的车、红的车等等。
我们通过 Car
类创建出对象实例,这些对象实例是 Car
这个类所抽象的事物的具体实现。 同时我们可以创建出名为 Class
的类的对象实例,这些通过 Class
类创建出的对象代表的是Java中运行着的各个类。
Car
这个类中可能有 代表车尺寸的 length
、Height
等属性, 同样的 Class
这个类中也有表示各个类名称的 name
属性等。
一句话: 类是对事物的抽象, Class
又是对这些类的一个抽象。
我们编写一个没有任何自定义方法和属性的类 ClassTest
来说明 Class
类的相关使用。
package cn.wang.myclasses;
/**
* cn.wang.myclasses.ClassTest
*
* @author Yang
* @date 2018/5/9
*/
public class ClassTest {
public static void main(String args[]) {
ClassTest myClass = new ClassTest();
...
}
}
获取Class类
Class
类只有一个私有的构造方法
private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
}
因此只有java虚拟机能调用该方法创建该类的对象,所以我们不能像其他类一样用 new
关键字获取对象。但有下面几种方法可以获取到具体 Class
对象
1. 通过类的静态成员获取。每个类都有一个表示其 Class
对象的静态成员
Class clazz1 = ClassTest.class;
2. 通过对象的 getClass()
方法获取。不难猜出此方法是继承自 java.lang.Object
类的方法。
Class clazz2 = myClass.getClass();
3. 通过 Class
类的静态方法 forName()
方法获取 Class
的对象,该方法可以帮助我们实现在程序运行时类的动态加载
try {
clazz3 = Class.forName("cn.wang.myclasses.ClassTest");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Class类相关方法
newInstance 方法
我们可以通过 MyClass
对象获取其对应的 Class
类的对象, 也可以通过 Class
类对象获取普通类的对象
ClassTest myClass2 = (ClassTest) clazz1.newInstance();
用 newInstance()
获取类对象时要求类必须有无参构造方法,否则会抛出 InstantiationException
异常:
Exception in thread "main" java.lang.InstantiationException: cn.wang.myclasses.NoNoneParaConstructor
at java.lang.Class.newInstance(Class.java:427)
at cn.wang.myclasses.ClassTest.main(ClassTest.java:40)
Caused by: java.lang.NoSuchMethodException: cn.wang.myclasses.NoNoneParaConstructor.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
... 1 more
forName(String name) 方法
此方法的作用前面已经提到,就是根据类的全限定名 className
查找 对应的 Class
实例,然后返回此实例的引用。
我们看到,此方法最终是调用一个名为 forName0
的方法,而 forName0
是一个本地方法。
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
/** Called after security check for system loader access checks have been made. */
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
getName() 方法
此方法返回该 Class
对象所对应的类的全限定名:
System.out.println("clazz1: " + clazz1.getName());
System.out.println("clazz1.getClass(): " + clazz1.getClass().getName());
//输出:
// clazz1: cn.wang.myclasses.ClassTest
// clazz1.getClass(): java.lang.Class
clazz1
是 ClassTest
类对应的 Class
对象, 因此其调用 getName()
输出的是 ClassTest
的全限定名
clazz1.getClass()
是 Class
类的 Class
对象, 因此对应输出是 java.lang.Class
public String getName() {
String name = this.name;
if (name == null)
this.name = name = getName0();
return name;
}
// cache the name to reduce the number of calls into the VM
private transient String name;
private native String getName0();
我们看到, getName()
方法在第一次调用时会调用另一个本地方法 getName0()
, 然后把得到的 name
缓存起来
getClassLoader() 方法
此方法返回加载调用此方法类的类加载器
Class clazz1 = ClassTest.class;
ClassLoader cl = clazz1.getClassLoader();
System.out.println("clazz1 classLoader: " + cl.toString());
Class stringClazz = String.class;
System.out.println("stringClazz classLoader: " + stringClazz.getClassLoader());
//输出:
// clazz1 classLoader: sun.misc.Launcher$AppClassLoader@18b4aac2
// stringClazz classLoader: null
我们看到,ClassTest
对应的类加载器是:应用程序类加载器 sun.misc.Launcher$AppClassLoader
;String
的类加载器返回 null
, 说明其加载器是启动类加载器。
getSuperClass() 方法
此方法返回调用者对应的类的父类的 Class
对象
Class parentClazz = clazz1.getSuperclass();
System.out.println("parentClazz: " + parentClazz.getName());
//输出:
//parentClazz: java.lang.Object
ClassTest
的父类是 Object
。
此方法也是一个本地方法。
public native Class<? super T> getSuperclass();