package com.scott.classloader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class MyClassLoader extends ClassLoader{
private String name;
private String path;
private final String fileType=".class";
public MyClassLoader(String name){
super();
this.name = name;
}
public MyClassLoader(String name, String path, ClassLoader parent){
super(parent);
this.name = name;
this.path = path;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String filePath = name.replace(".", "\\");
filePath = path+filePath+fileType;
System.out.println("file path is : "+filePath);
byte[] b = loadClassData(filePath);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String fileName) {
byte[] result = null;
ByteArrayOutputStream baos = null;
//FileInputStream fis = null;
InputStream inputStream = null;
try{
// //错误的实现方式导致了class文件和byte数组不一致,JVM检查不过
// baos = new ByteArrayOutputStream();
// inputStream = new FileInputStream(new File(fileName));
// //特别注意 !!!!!!!!!!!!!!!!!!!!!!!!!
// byte[] byteBuffer = new byte[1];//需要一个一个字节的读取,当是1024时,报错Exception in thread "main" java.lang.ClassFormatError: Extra bytes at the end of class file Parent
// while(-1 != inputStream.read(byteBuffer)){
// baos.write(byteBuffer);
// }
// result = baos.toByteArray();
baos = new ByteArrayOutputStream();
inputStream = new FileInputStream(new File(fileName));
int length = 0;
//特别注意 !!!!!!!!!!!!!!!!!!!!!!!!!
byte[] byteBuffer = new byte[1024];//
while(-1 != (length=inputStream.read(byteBuffer))){
baos.write(byteBuffer,0,length);
}
result = baos.toByteArray();
}catch(Exception e){
e.printStackTrace();
}finally{
if(null!=baos){
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(null!=inputStream){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
@Override
public String toString() {
return this.name;
}
public static void main(String[] args) throws Exception {
System.out.println("Hello MyClassLoader!");
//MyClassLoader loaderOne = new MyClassLoader("loader111", "e:/myapp/",ClassLoader.getSystemClassLoader());
MyClassLoader loaderOne = new MyClassLoader("loader111", "e:\\myapp\\",null);
System.out.println("start loade class");
Class<?> loadClass = loaderOne.loadClass("Parent");
System.out.println("the class is : "+loadClass);
Object newInstance = loadClass.newInstance();
}
}
//java.lang.ClassFormatError: Extra bytes at the end of class file
这个报错在网上查资料,说是JDK运行版本与编译版本不符合
我机器的情况是这样的:
C:\Users\Administrator>java -version
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b18)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
C:\Users\Administrator>javac -version
javac 1.8.0
网上说报错的其中一种情况是编译版本低于运行版本
但是我在eclipse中通过系统类加载器加载类对象的方式没有任何问题,但是通过自定义类加载器加载就报错了,我也查看了eclipse的编译环境和运行环境JDK版本都是一致的。
所以我判定是读取class文件有问题,经过文件复制的查看,发现确实在读取文件的时候,需要一个字节一个字节的读取,这样才能保证*.class文件与原文件保持内容一致。才能符合jdk对java文件的文件结构检查,语意检查,操作码与操作数检查,二进制兼容性检查等。我想这里应该是二进制兼容性检查出问题了。
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class MyClassLoader extends ClassLoader{
private String name;
private String path;
private final String fileType=".class";
public MyClassLoader(String name){
super();
this.name = name;
}
public MyClassLoader(String name, String path, ClassLoader parent){
super(parent);
this.name = name;
this.path = path;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String filePath = name.replace(".", "\\");
filePath = path+filePath+fileType;
System.out.println("file path is : "+filePath);
byte[] b = loadClassData(filePath);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String fileName) {
byte[] result = null;
ByteArrayOutputStream baos = null;
//FileInputStream fis = null;
InputStream inputStream = null;
try{
// //错误的实现方式导致了class文件和byte数组不一致,JVM检查不过
// baos = new ByteArrayOutputStream();
// inputStream = new FileInputStream(new File(fileName));
// //特别注意 !!!!!!!!!!!!!!!!!!!!!!!!!
// byte[] byteBuffer = new byte[1];//需要一个一个字节的读取,当是1024时,报错Exception in thread "main" java.lang.ClassFormatError: Extra bytes at the end of class file Parent
// while(-1 != inputStream.read(byteBuffer)){
// baos.write(byteBuffer);
// }
// result = baos.toByteArray();
baos = new ByteArrayOutputStream();
inputStream = new FileInputStream(new File(fileName));
int length = 0;
//特别注意 !!!!!!!!!!!!!!!!!!!!!!!!!
byte[] byteBuffer = new byte[1024];//
while(-1 != (length=inputStream.read(byteBuffer))){
baos.write(byteBuffer,0,length);
}
result = baos.toByteArray();
}catch(Exception e){
e.printStackTrace();
}finally{
if(null!=baos){
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(null!=inputStream){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
@Override
public String toString() {
return this.name;
}
public static void main(String[] args) throws Exception {
System.out.println("Hello MyClassLoader!");
//MyClassLoader loaderOne = new MyClassLoader("loader111", "e:/myapp/",ClassLoader.getSystemClassLoader());
MyClassLoader loaderOne = new MyClassLoader("loader111", "e:\\myapp\\",null);
System.out.println("start loade class");
Class<?> loadClass = loaderOne.loadClass("Parent");
System.out.println("the class is : "+loadClass);
Object newInstance = loadClass.newInstance();
}
}
//java.lang.ClassFormatError: Extra bytes at the end of class file
这个报错在网上查资料,说是JDK运行版本与编译版本不符合
我机器的情况是这样的:
C:\Users\Administrator>java -version
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b18)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
C:\Users\Administrator>javac -version
javac 1.8.0
网上说报错的其中一种情况是编译版本低于运行版本
但是我在eclipse中通过系统类加载器加载类对象的方式没有任何问题,但是通过自定义类加载器加载就报错了,我也查看了eclipse的编译环境和运行环境JDK版本都是一致的。
所以我判定是读取class文件有问题,经过文件复制的查看,发现确实在读取文件的时候,需要一个字节一个字节的读取,这样才能保证*.class文件与原文件保持内容一致。才能符合jdk对java文件的文件结构检查,语意检查,操作码与操作数检查,二进制兼容性检查等。我想这里应该是二进制兼容性检查出问题了。