Introduction
内容源自对慕课网视频Java反射教程的笔记
慕课网教程-反射——Java高级开发必须懂的
Class类的使用
- 类是对象,类是java.lang.Class的对象
- 如何表示这个对象
public class ClassDemo1 {
// Foo的实例对象的表示
Foo foo = new Foo();
// 万事万物皆对象,那么Foo这个类怎么作为对象表示出来
}
class Foo {}
我们进入Class的源代码,可以看到一个私有的构造函数(这个构造函数可能因为JDK的版本不同而不同)
/*
* Private constructor. Only the Java Virtual Machine creates Class objects.
* This constructor is not used and prevents the default constructor being
* generated.
*/
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;
}
说得很明确了只有JVM才能访问。
要想把Foo这个类作为对象表示出来有三种方式,内容基本都在注释里面了
package com.nevercome;
/**
* @author: sun
* @date: 2019/4/6
*/
public class ClassDemo1 {
public static void main(String[] args) {
// Foo的实例对象的表示
// Foo foo = new Foo("1");
Foo foo = new Foo();
// 万事万物皆对象,Foo这个类怎么作为对象表示出来
// 任何一个类都是Class的实例对象,但是我我们无法用构造函数的方式
// 但其实有三种方式
// 1. .class
Class c1 = Foo.class; // 这说明所有的类,都有一个为class的静态变量
// 2. 已知该类的对象 getClass()
Class c2 = foo.getClass();
// 来梳理一下概念
// 根据官网的定义: c1,c2 表示了Foo类的类类型(class type)
// 类类型指的就是类自己,它是Class类的一个实例,如Foo类的类类型就是c1
// c1是它作为Class类的实例(对象),我们称之为该类(这里是Foo)的类类型
// c1 和 c2都是Foo的类类型,一个类作为Class类的实例只可能有一个实例对象
System.out.println(c1 == c2); // true
Class c3 = null;
try {
c3 = Class.forName("com.nevercome.Foo");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c2 == c3); // true
// 我们还可以通过类的类类型来创建该类的对象
// 这要求该类必须有无参的构造函数(隐式和显示皆可)
// 不然会抛出NoSuchMethodException
try {
Foo foo1 = (Foo)c1.newInstance();
Foo foo2 = (Foo)c2.newInstance();
foo.print();
foo1.print();
foo2.print();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
class Foo {
// public Foo(String name) {
//
// }
public void print() {
System.out.println("foo");
}
}
动态加载类 类的反射
上述说的第三种方式Class.forName(“类的权限定名”),不仅代表了类的类类型,还代表了动态加载类。编译时刻加载类是静态加载类,运行时刻加载类是动态加载类。
看一下下面这个Office类:
public class Office {
public static void mian(String[] args) {
if("Word".equals(args[0])) {
Word w = new Word();
w.start();
}
if("Excel".equals(args[0])) {
Excel e = new Excel();
e.start();
}
}
}
使用javac命令编译这个Office类,毫无疑问,它会报错。因为我们没有Word和Excel类。那么如果你有了Word类呢,当然还是会报错,因为你没有Excel。仔细想一下这个问题,这是否和你的真实需求相背离了呢?我们希望有Word类,Word的功能就可以使用,而不是因为Excel缺失了而所有的Office全家桶都无法使用了。这就是静态加载类(new 都是静态加载),编译时刻要求加载所需的全部类的缺陷。我们希望只有在我们需要使用他们的时候,他们才被加载,Class.forName()可以完成这个任务。
public class OfficeBetter {
public static void main(String[] args) {
try {
// 动态加载类 运行时加载
Class c = Class.forName(args[0]);
// 通过类类型创建对象
// 强制类型转换&#