1.
package com.example.demo10;
public class Demo10Application {
public static void main(String[] args) {
Calculator calculator = new Calculator(6000);
double result = calculator.calculate();
System.out.println(result);
}
}
package com.example.demo10;
public class Calculator {
private int number;
private double multiple = 1.2;
public double calculate(){
return this.number * this.multiple;
}
public Calculator() {
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public Calculator(int number) {
this.number = number;
}
}
运行结果:
2.从classpath类路径外加载 Calculator 类
package com.example.demo10;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
public class Demo10Application {
public static void main(String[] args) throws Exception{
//创建URL对象
URL url = new URL("file:C:/Minecloud/IDEA_workspace/myapp.jar");
//创建一个URLClassLoader,负责加载的范围是 {url}
URLClassLoader urlClassLoader = new URLClassLoader(new URL[] {url});
// 到urlClassLoader所负责的范围 寻早并加载 指定的类
Class clazz = urlClassLoader.loadClass("com.example.Calculator");
//调用有参构造创建该类的对象,参数是有参构造的参数列表(区分重载)
Object obj = clazz.getConstructor(int.class).newInstance(20000);
//获取指定的方法
Method method = clazz.getMethod("calculate");
//调用该方法
double result = (double) method.invoke(obj);
System.out.println(result);
}
}
将Calculator打成jar包放到类路径外
package com.example;
public class Calculator {
private int number;
private double multiple = 1.2;
public double calculate(){
return this.number * this.multiple;
}
public Calculator() {
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public Calculator(int number) {
this.number = number;
}
}
运行程序
3.修改class文件,自定义类加载器
修改class文件
package com.example.demo10;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Demo {
public static void main(String[] args) throws Exception{
//原文件
File originalFile = new File("C:\Minecloud\IDEA_workspace\springboot02\myapp\target\classes\com\example\Calculator.class");
FileInputStream originalFis = new FileInputStream(originalFile);
//修改后的目标文件
File targetFile = new File("C:\Minecloud\IDEA_workspace\Calculator.class");
FileOutputStream targetFos = new FileOutputStream(targetFile);
//原文件头部添加一个字节(值为8),形成目标文件
int code = 8;
targetFos.write(code);
//fis.read() = -1 代表已经读到文件的末尾
while( (code=originalFis.read()) != -1 ){
targetFos.write(code);
}
originalFis.close();
targetFos.close();
}
}
将修改后的class文件打成jar包
自定义类加载器需要实现ClassLoader
SecureClassLoader 实现了ClassLoader
自定义类加载器 继承 SecureClassLoader
自定义类加载器从jar中读取修改后的class文件
package com.example.demo10;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.security.SecureClassLoader;
import java.util.ArrayList;
public class MyClassLoader extends SecureClassLoader {
private String jarFile;
//重写findClass 自定义如何加载类
@Override
protected Class> findClass(String name) {
//类名转换为路径
String classPath = name.replace(".","/").concat(".class");
int code;
byte[] b;
ByteArrayOutputStream bs = new ByteArrayOutputStream();
try{
//读取class文件 为 byte数组
URL url = new URL( "jar:file:\" + this.jarFile + "!/" + classPath);
InputStream is = url.openStream();
while ( (code=is.read()) != -1 ){
bs.write( (byte)code );
}
b = bs.toByteArray();
/*
defineClass将二进制字节流转换成 Class 对象实例
参数:
name:字符串类型,表示要装入作为类名的二进制名称。如 com.example.MyClass
b:byte 数组类型,表示要装入内存的二进制数据。
off:int 类型,表示数组起始位置的偏移量(offset)。(这里跳过一个字节才能正确解析,)
len:int 类型,表示要装入的数组长度。
*/
return this.defineClass(name,b,1,b.length-1);
}catch(Exception e){
e.printStackTrace();
return null;
}finally {
try {
bs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public MyClassLoader() {
}
public MyClassLoader(String jarFile) {
this.jarFile = jarFile;
}
public String getJarFile() {
return jarFile;
}
public void setJarFile(String jarFile) {
this.jarFile = jarFile;
}
}
package com.example.demo10;
import java.lang.reflect.Method;
public class Demo010 {
public static void main(String[] args) throws Exception{
//创建自定义的类加载器
MyClassLoader classLoader = new MyClassLoader("C:\Minecloud\IDEA_workspace\myapp.jar");
//加载指定类 (loadClass 中会调用 findClass )
Class clazz = classLoader.loadClass("com.example.Calculator");
//调用有参构造创建该类的对象,参数是有参构造的参数列表(区分重载)
Object obj = clazz.getConstructor(int.class).newInstance(20000);
//获取指定的方法
Method method = clazz.getMethod("calculate");
//调用该方法
double result = (double) method.invoke(obj);
System.out.println(result);
}
}
运行结果:
4.
打破双亲委派
ClassLoader中的 loadClass
1. findLoadedClass(name)从缓存中查找是否已经加载过该类
2.没有加载过 且 有父加载器,调用父加载器 loadClass,没有父加载器(即当前为Bootstrap类加载器),调用findBootstrapClassOrNull(name) 从Bootstrap类加载器负责的范围中加载所需的类。从父加载器中没有加载到需要的类,再调用 当前类加载器findClass(name) 去加载所需要的类。
protected Class> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
自定义类加载器中重写loadClass
package com.example.demo10;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.SecureClassLoader;
public class MyClassLoader extends SecureClassLoader {
private String jarFile;
//重写 loadClass 方法 ,打破双亲委派
@Override
protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException{
synchronized (getClassLoadingLock(name)){
// First, check if the class has already been loaded
Class> c = findLoadedClass(name);
if(c == null){
//优先调用当前类加载器的 findClass 加载所需要的类
c = this.findClass(name);
// 当前类加载器加载不到所需要的类,再让父加载器去加载
if( c == null ){
c = super.loadClass(name,resolve);
}
}
return c;
}
}
//重写findClass 自定义如何加载类
@Override
protected Class> findClass(String name) {
//类名转换为路径
String classPath = name.replace(".","/").concat(".class");
int code;
byte[] b;
ByteArrayOutputStream bs = new ByteArrayOutputStream();
try{
//读取class文件 为 byte数组
URL url = new URL( "jar:file:\" + this.jarFile + "!/" + classPath);
InputStream is = url.openStream();
while ( (code=is.read()) != -1 ){
bs.write( (byte)code );
}
b = bs.toByteArray();
/*
defineClass将二进制字节流转换成 Class 对象实例
参数:
name:字符串类型,表示要装入作为类名的二进制名称。如 com.example.MyClass
b:byte 数组类型,表示要装入内存的二进制数据。
off:int 类型,表示数组起始位置的偏移量(offset)。
len:int 类型,表示要装入的数组长度。
*/
return this.defineClass(name,b,0,b.length);
}catch(Exception e){
return null;
}finally {
try {
bs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public MyClassLoader() {
}
public MyClassLoader(String jarFile) {
this.jarFile = jarFile;
}
public String getJarFile() {
return jarFile;
}
public void setJarFile(String jarFile) {
this.jarFile = jarFile;
}
}
类路径下的 Calculator类
package com.example;
public class Calculator {
private int number;
private double multiple = 1;
public double calculate(){
return this.number * this.multiple;
}
public Calculator() {
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public Calculator(int number) {
this.number = number;
}
}
类路径外 jar 中的 Calculator 类
package com.example;
public class Calculator {
private int number;
private double multiple = 1.2;
public double calculate(){
return this.number * this.multiple;
}
public Calculator() {
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public Calculator(int number) {
this.number = number;
}
}
main方法
package com.example.demo10;
import java.lang.reflect.Method;
public class Demo010 {
public static void main(String[] args) throws Exception{
//创建自定义的类加载器
MyClassLoader classLoader = new MyClassLoader("C:\Minecloud\IDEA_workspace\myapp.jar");
//加载指定类 (loadClass 中会调用 findClass )
Class clazz = classLoader.loadClass("com.example.Calculator");
//调用有参构造创建该类的对象,参数是有参构造的参数列表(区分重载)
Object obj = clazz.getConstructor(int.class).newInstance(20000);
//获取指定的方法
Method method = clazz.getMethod("calculate");
//调用该方法
double result = (double) method.invoke(obj);
System.out.println(result);
}
}
结果:加载的是类路径外 jar 中的Calculator 类
如果不重写 loadClass
结果:加载的是类路径下 的Calculator 类
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net