Java类加载器除了根类加载器之外,其他类加载器都是使用Java语言编写的
System.exit()
或Runtime.getRuntime().exit()
代码处结束程序class
文件读入内存,并为之创建一个java.lang.Class
对象ClassLoader
基类来创建自己的类加载器java.lang.Object
new
创建、通过反射来创建、通过反序列化来创建java.lang.Class
对象final
类变量,如果在编译时值就可以确定,那么在编译时就定下来了,使用它不会导致类的初始化,如果值不能确定,将会导致类的初始化ClassLoader
类的loadClass()
方法来加载某个类时,该方法只是加载该类,并不会执行该类的初始化;使用Class
类的forName()
静态方法才会导致强制初始化该类类加载器负责将.class文件加载到内存中,并为之生成对应的java.lang.Class对象
在Java中,一个类使用其全限定类名(包括包名和类名)作为标识;但在JVM中,一个类使用其全限定类名和其类加载器作为其唯一标识
null
。 // 获取系统类加载器
ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
System.out.println("系统类加载器:" + systemLoader);
/*
获取系统类加载器的加载路径——通常由CLASSPATH环境变量指定
如果操作系统没有指定CLASSPATH环境变量,默认以当前路径作为
系统类加载器的加载路径
*/
Enumeration em1 = systemLoader.getResources("");
while(em1.hasMoreElements()){
System.out.println(em1.nextElement());
}
// 获取系统类加载器的父类加载器:得到扩展类加载器
ClassLoader extensionLader = systemLoader.getParent();
System.out.println("扩展类加载器:" + extensionLader);
System.out.println("扩展类加载器的加载路径:" + System.getProperty("java.ext.dirs"));
System.out.println("扩展类加载器的parent: " + extensionLader.getParent());
Class
的步骤: Class
是否载入过,如果有直接进入第8步,否则执行第2步;由于Java中的对象在运行时会出现两种类型:编译时类型和运行时类型,程序需要在运行时发现对象和类的真实信息,方式:
instanceof
运算符进行判断,再利用强制类型转换符将其转换成其运行时类型的变量即可能够分析类能力的程序称为反射(reflective),反射机制的功能极其强大,可以用来:
反射是一种功能强大且复杂的机制,使用它的主要人员是工具构造者。
在程序运行期间,JRE始终为所有的对象维护一个被称为运行时的类型标识,这个信息跟踪着每个对象所属的类,JVM利用运行时类型信息选择相应的方法执行,这些信息可以通过Class
类来访问。Object
类(所有类的父类)中的getClass()
方法将会返回一个Class
类型的实例,一个Class
对象将标识一个特定类的属性。虚拟机为每个类型管理一个Class
对象,因此,可以用==
运算符实现两个类对象比较的操作。在获取类名称的时候,可以利用forName
与newInstance
配合来创建一个对应对象,但是假如该类没有默认构造器(构造器参数为0)的话,就会抛出一个异常。
获得Class类对象的三种方式:
getClass()
方法:需要对应对象的一个实例forName()
方法:需要对应对象的完整类名称T.class
方法:需要对应对象的类型T
注意: Class
是一个类,而Class
对应的类型并不一定是类,例如:int.class
在java.lang.reflect
包中有三个类Field
、Method
、Constructor
,分别用于描述类的域、方法、构造器。这三个类都有一个叫做getName()
的方法,用来返回项目的名称。Field
类有一个getType
方法,用来返回描述域所属类型的Class
对象。Method
和Constructor
有能够报告参数类型的方法,Method
类还有一个可以报告返回类型的方法。这三个类还有一个叫做getModifiers
的方法,它将返回一个整型数值,用不同的位开关描述public
和static
这样的修饰符使用情况。另外,可以利用java.lang.reflect
包中的Modifier
类的静态方法分析getModifiers
返回的整型数值。
Class
类中的getFields
、getMethods
和getConstructors
方法将分别返回类提供的public
域、方法和构造函数,其中包括超类公有成员。Class
类的getDeclareFields
、getDeclaredMethods
、getDeclaredConstructors
方法将分别返回类中声明的全部域、方法和构造器,其中包括私有和受保护成员,但是不包括超类的成员。
Executable
抽象类,该对象代表可执行的类成员,该类派生出了Constructor
、Method
两个子类 程序可以通过Method
对象来执行对应的方法,通过Constructor
对象来调用对应的构造器创建实例,能通过Field
对象直接访问并修改对象的成员变量值
通过反射来生成对象的两种方式:
Class
对象的newInstance()
方法来创建该Class
对象对应类的实例,这种方式要求该Class
对象的对应类有默认构造器,而执行newInstance()
方法时实际上是利用默认构造器来创建该类的实例。Class
对象获取指定的Constructor
对象,再调用Constructor
对象的newInstance()
方法来创建该Class
对象对应类的实例。通过这种方式可以选择使用指定的构造器来创建实例。利用指定的构造器来创建Java对象的步骤:
Class
对象;Class
对象的getConstructor()
方法来获取指定的构造器;Constructor
的newInstance()
方法来创建Java对象。注意:通过反射创建对象时性能要稍低一些,实际上只有程序需要动态创建某个类的对象时才会考虑使用反射,通常在开发通用性比较广的框架、基础平台时可能会大量使用反射。
Class
对象后,就可以通过该Class
对象的getMethods()
方法或getMethod()
方法来获取方法了,每个Method
对象对应一个方法,可以通过该Method
对象来调用它对应的方法,在Method
里包含一个invoke()
方法,该方法签名:Object invoke(Object obj, Object... args);
该方法中的obj
是执行该方法的主调,后面的args
是执行该方法时传入该方法的实参。private
方法:setAccessible(boolean flag)
;将Method
对象的accessible
设置为指定的boolean
值,值为true
,指示该Method
在使用时应该取消Java语言的访问权限审查;值为false
,指示该Method
在使用时要实施Java语言的访问权限检查Class
对象的getFields()
或getField()
方法可以获取该类所包括的全部成员变量或指定成员变量,Field
提供了如下两组方法来读取或设置成员变量值。 obj
对象的该成员变量的值。此处的Xxx
对应8种基本类型,如果该成员变量的类型是引用型,则取消get
后面的Xxx
obj
对象的该成员变量设置成val
值。此处的Xxx对应8种基本类型,如果该成员变量的类型是引用型,则取消set
后面的Xxx
java.lang.reflect
包下还提供了一个Array
类,Array
对象可以代表所有的数组。程序可以通过使用Array
来动态地创建数组,操作数组元素等Array
提供了如下几类方法: 使用代理可以在运行时创建一个实现了一组给定接口的新类,这种功能只有在编译时无法确定需要实现哪个接口时才有必要使用,主要用于编写框架和底层基础代码
Object
类中的全部方法。InvocationHandler
接口的类对象,在这个接口中只有一个方法:Object invoke(Object proxy, Method method, Object[] args);
,无论何时调用代理对象的方法,调用处理器的invoke
方法都会被调用,并向其传递Method
对象和原始的调用参数)来实现。在Java的·java.lang.reflect·包下提供了一个·Proxy·类和一个·InvocationHandler·接口,通过使用这个类和接口可以生成动态代理类或动态代理对象。
Proxy
提供了用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类。如果在程序中为一个或多个接口动态地生成实现类,就可以使用Proxy
来创建动态代理类;如果需要为一个或多个接口动态地创建实例,也可以使用Proxy
来创建动态代理实例。
Proxy
提供了如下两个方法来创建动态代理类和动态代理实例: Class
对象,该代理类将实现interfaces
所指定的多个接口。第一个ClassLoader
参数指定生成动态代理类的类加载器。interfaces
指定的系列接口,执行代理对象的每个方法都会被替换执行InvocationHandler
对象的invoke
方法。InvocationHandler
这个接口,并且每个代理类的实例都关联到了一个handler
,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler
这个接口的invoke
方法来进行调用。Object invoke(Object proxy, Method method, Object[] args);
Method
对象Proxy
类的Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h);
方法创建一个代理对象,该方法有三个参数: null
(使用默认加载器);定义了由哪个ClassLoader对象来对生成的代理对象进行加载InvocationHandler
对象interface Person {
void walk();
void sayHello(String name);
}
class MyInvokationHandler implements InvocationHandler {
/*
执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法
其中:
proxy:代表动态代理对象
method:代表正在执行的方法
args:代表调用目标方法时传入的实参。
*/
public Object invoke(Object proxy, Method method, Object[] args) {
System.out.println("----正在执行的方法:" + method);
if (args != null) {
System.out.println("下面是执行该方法时传入的实参为:");
for (Object val : args) {
System.out.println(val);
}
}
else {
System.out.println("调用该方法没有实参!");
}
return null;
}
}
public class ProxyTest {
public static void main(String[] args) throws Exception {
// 创建一个InvocationHandler对象
InvocationHandler handler = new MyInvokationHandler();
// 使用指定的InvocationHandler来生成一个动态代理对象
Person p = (Person)Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class}, handler);
// 调用动态代理对象的walk()和sayHello()方法
p.walk();
p.sayHello("孙悟空");
}
}
Proxy.newProxyInstance
创建的代理对象是在JVM运行时动态生成的一个对象,它并不是我们的InvocationHandler
类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$
开头,proxy
为中,最后一个数字表示对象的标号。参考博客:java的动态代理机制详解
interface Dog {
// info方法声明
void info();
// run方法声明
void run();
}
class GunDog implements Dog {
// 实现info()方法,仅仅打印一个字符串
public void info() {
System.out.println("我是一只猎狗");
}
// 实现run()方法,仅仅打印一个字符串
public void run() {
System.out.println("我奔跑迅速");
}
}
class DogUtil {
// 第一个拦截器方法
public void method1() {
System.out.println("=====模拟第一个通用方法=====");
}
// 第二个拦截器方法
public void method2() {
System.out.println("=====模拟通用方法二=====");
}
}
class MyInvokationHandler implements InvocationHandler
{
// 需要被代理的对象
private Object target;
public void setTarget(Object target) {
this.target = target;
}
// 执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
DogUtil du = new DogUtil();
// 执行DogUtil对象中的method1。
du.method1();
// 以target作为主调来执行method方法
Object result = method.invoke(target , args);
// 执行DogUtil对象中的method2。
du.method2();
return result;
}
}
class MyProxyFactory {
// 为指定target生成动态代理对象
public static Object getProxy(Object target) throws Exception {
// 创建一个MyInvokationHandler对象
MyInvokationHandler handler = new MyInvokationHandler();
// 为MyInvokationHandler设置target对象
handler.setTarget(target);
// 创建、并返回一个动态代理
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces() , handler);
}
}
public class Test {
public static void main(String[] args) throws Exception {
// 创建一个原始的GunDog对象,作为target
Dog target = new GunDog();
// 以指定的target来创建动态代理
Dog dog = (Dog)MyProxyFactory.getProxy(target);
dog.info();
dog.run();
}
}