A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 思维 于 2014-8-12 23:02 编辑

这两天学了下类加载器,使用EditPlus写了自定义类加载器进行加密与解密的代码,出现了各种问题,郁闷的不行,谁来解决下啊?问题一:运行MyClassLoader类后将加密的ClassLoaderAttachment覆盖原来的.class文件,解密时产生ClassFormortError   (注意:所有的类均在D:\JavaDemo\下)
  1. import java.io.*;
  2. import java.util.*;
  3. class MyClassLoader extends ClassLoader{
  4.         //编译:java MyClassLoader D:\JavaDemo\ClassLoaderAttachment.class D:\
  5.         public static void main(String[] args)throws Exception{
  6.                 //参数中传入加密前的目标文件和路径
  7.                 String srcPath = args[0];
  8.                 //参数中传入完成后的加密文件的路径
  9.                 String destDir = args[1];
  10.                 //创建目标文件的文件输入流对象
  11.                 FileInputStream fis = new FileInputStream(srcPath);
  12.                 //获取目标文件的文件名
  13.                 String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1);
  14.                 //完成后返回加密文件和路径
  15.                 String destPath = destDir+"\\"+destFileName;
  16.                 //创建加密文件的文件输出流对象
  17.                 FileOutputStream fos = new FileOutputStream(destPath);
  18.                 //对数据进行加密
  19.                 cypher(fis,fos);
  20.                 fis.close();
  21.                 fos.close();
  22.         }
  23.         //创建对数据流进行加密的方法
  24.         private static void cypher(InputStream ips,OutputStream ops)throws Exception{
  25.                 int b = -1;
  26.                 while((b = ips.read())!=-1){
  27.                         ops.write(b^0xff);
  28.                 }
  29.         }
  30.         //自定义类加载器
  31.         @Override
  32.         protected Class<?> findClass(String name)throws ClassNotFoundException{
  33.                 //获得加密文件和路径
  34.                 String classFileName = name.substring(name.lastIndexOf('.')+1)+".class";
  35.                 try{
  36.                         //创建加密文件的文件输入流对象
  37.                         FileInputStream fis = new FileInputStream(classFileName);
  38.                         //创建解密文件的字节数组输出流对象
  39.                         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  40.                         //对加密数据进行解密
  41.                         cypher(fis,bos);
  42.                         fis.close();
  43.                         byte[] bytes = bos.toByteArray();
  44.                         return defineClass(null,bytes,0,bytes.length);
  45.                 }catch(Exception e){
  46.                         e.printStackTrace();
  47.                 }
  48.                 return null;
  49.         }
  50. }
  51. //创建一个需要被加密的类
  52. class ClassLoaderAttachment extends Date{
  53.         public String toString(){
  54.                 return "你好,黑马训练营!";
  55.         }
  56. }
复制代码
测试代码:
  1. import java.util.*;
  2. //对类的加密结果进行测试
  3. public class ClassLoaderTest{
  4.         public static void main(String[] args)throws Exception{
  5.                 //System.out.println(new ClassLoaderAttachment().toString());
  6.                 Class clazz =
  7.                                 new MyClassLoader().loadClass("ClassLoaderAttachment");
  8.                 Date cla1 = (Date)clazz.newInstance();
  9.                 System.out.println(cla1);
  10.                 //ClassLoaderAttachment cla1 = clazz.newInstance();
  11.                 //ClassLoaderAttchment已经被加密,无法被编译器识别,因此需要继承Date类
  12.         }
  13. }
复制代码
问题二:运行MyClassLoader类后将加密的ClassLoaderAttachment存入My目录下,同时删除D:\JavaDemo下的ClassLoaderAttachment,解密时产生IllegalAccessException
  1. import java.io.*;
  2. import java.util.*;
  3. class MyClassLoader extends ClassLoader{
  4.         //编译:java MyClassLoader D:\JavaDemo\ClassLoaderAttachment.class D:\
  5.         public static void main(String[] args)throws Exception{
  6.                 //参数中传入加密前的目标文件和路径
  7.                 String srcPath = args[0];
  8.                 //参数中传入完成后的加密文件的路径
  9.                 String destDir = args[1];
  10.                 //创建目标文件的文件输入流对象
  11.                 FileInputStream fis = new FileInputStream(srcPath);
  12.                 //获取目标文件的文件名
  13.                 String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1);
  14.                 //完成后返回加密文件和路径
  15.                 String destPath = destDir+"\\"+destFileName;
  16.                 //创建加密文件的文件输出流对象
  17.                 FileOutputStream fos = new FileOutputStream(destPath);
  18.                 //对数据进行加密
  19.                 cypher(fis,fos);
  20.                 fis.close();
  21.                 fos.close();
  22.         }
  23.         //创建对数据流进行加密的方法
  24.         private static void cypher(InputStream ips,OutputStream ops)throws Exception{
  25.                 int b = -1;
  26.                 while((b = ips.read())!=-1){
  27.                         ops.write(b^0xff);
  28.                 }
  29.         }
  30.         private String classDir;
  31.         public MyClassLoader(){
  32.                
  33.         }        
  34.         public MyClassLoader(String classDir){
  35.                 this.classDir = classDir;
  36.         }        
  37.         //自定义类加载器
  38.         @Override
  39.         protected Class<?> findClass(String name)throws ClassNotFoundException{
  40.                 //获得加密文件和路径
  41.                 String classFileName =
  42.                         classDir + "\\"  + name.substring(name.lastIndexOf('.')+1) + ".class";
  43.                 try{
  44.                         //创建加密文件的文件输入流对象
  45.                         FileInputStream fis = new FileInputStream(classFileName);
  46.                         //创建解密文件的字节数组输出流对象
  47.                         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  48.                         //对加密数据进行解密
  49.                         cypher(fis,bos);
  50.                         fis.close();
  51.                         byte[] bytes = bos.toByteArray();
  52.                         return defineClass(null,bytes,0,bytes.length);
  53.                 }catch(Exception e){
  54.                         e.printStackTrace();
  55.                 }
  56.                 return null;
  57.         }
  58. }
  59. //创建一个需要被加密的类
  60. class ClassLoaderAttachment extends Date{
  61.         public String toString(){
  62.                 return "你好,黑马训练营!";
  63.         }
  64. }
复制代码
测试代码
import java.util.*;
//对类的加密结果进行测试
public class ClassLoaderTest{
        public static void main(String[] args)throws Exception{
                //System.out.println(new ClassLoaderAttachment().toString());
                Class clazz =
                                new MyClassLoader("D:\\JavaDemo\\My").loadClass("ClassLoaderAttachment");
                Date cla1 = (Date)clazz.newInstance();
                System.out.println(cla1);
                //ClassLoaderAttachment cla1 = clazz.newInstance();
                //ClassLoaderAttchment已经被加密,无法被编译器识别,因此需要继承Date类
        }
}





捕获.JPG (179.99 KB, 下载次数: 24)

捕获.JPG

捕获1.JPG (49.35 KB, 下载次数: 26)

捕获1.JPG

评分

参与人数 1技术分 +1 收起 理由
格子、 + 1 神马都是浮云

查看全部评分

21 个回复

倒序浏览
楼主高大上,领教了
回复 使用道具 举报
.................................
回复 使用道具 举报
楼主加油
回复 使用道具 举报
楼主很给力啊!虽然看过视频,但还是不是很清楚。
回复 使用道具 举报

回帖奖励 +2

赞一个~~
回复 使用道具 举报
思维 高级黑马 2014-8-11 21:49:35
7#
求高手帮忙解决啊!:'(
回复 使用道具 举报
More 中级黑马 2014-8-11 21:49:41
8#
我还没看   不过你可以根据异常去进行调试   一个是非法访问异常还有一个是类格式错误  你可以先排查排查
回复 使用道具 举报
思维 高级黑马 2014-8-11 21:51:38
9#
More 发表于 2014-8-11 21:49
我还没看   不过你可以根据异常去进行调试   一个是非法访问异常还有一个是类格式错误  你可以先排查排查 ...

类格式错误,说明解密失败了!非法访问异常,目测是路径上出问题了!就是不知道怎么解决啊?:'(
回复 使用道具 举报
More 中级黑马 2014-8-11 23:13:46
10#
思维 发表于 2014-8-11 21:51
类格式错误,说明解密失败了!非法访问异常,目测是路径上出问题了!就是不知道怎么解决啊? ...

是高新技术上讲的吗  等我看过视频一起探讨探讨
回复 使用道具 举报

回帖奖励 +1

试试   args[1] 输入改成  D:\JavaDemo  
回复 使用道具 举报

回帖奖励 +1

过来学习一下,对类加载不是很熟~~~
回复 使用道具 举报
本帖最后由 a6511631 于 2014-8-12 10:21 编辑

首先classPath下不要放ClassLoaderAttachment.class,不然类加载器会先去加载它,而不会去自定义加载,
你如果放了的话就会报你说的那个ClassFormatError。
我估计你后来没有放了,接下来就报了IllegalAccessException是不是?
解决方法:给ClassLoaderAttachment类加上修饰符public。这个异常代表非法访问,就是因为权限不够。一个类文件不能有多个public修饰的类,你把它另外做一个.java类文件吧。
建议:
你仔细看MyClassLoader的构造方法,这里loadClass()需要用到MyClassLoader其中的findClass()
而findClass()方法中需要一个参数classDir,这个参数哪里定义的?就是在构造时定义,你这里没有给它传参数,最好加上路径。
顺便一提的是,loadClass()方法的参数,这个类名ClassLoaderAttachment应该要加上包名,但是你写这个程序的时候没有建包,就不用写了。建议以后写上报名
PS:我才不会告诉你我又去复习类加载器捣鼓了半个小时。

点评

真是牛逼的一塌糊涂啊!  发表于 2014-8-12 10:33

评分

参与人数 2技术分 +1 黑马币 +2 收起 理由
格子、 + 1 赞一个!
思维 + 2 很给力!

查看全部评分

回复 使用道具 举报 1 0
我表示这部分还没看到。。。
回复 使用道具 举报
本帖最后由 思维 于 2014-8-12 10:45 编辑
a6511631 发表于 2014-8-12 10:17
首先classPath下不要放ClassLoaderAttachment.class,不然类加载器会先去加载它,而不会去自定义加载,
你 ...

还有一点问题就是:自定义类加载器加载的类必须是public的,缺省的都不行?
回复 使用道具 举报
思维 发表于 2014-8-12 10:35
还有一点问题就是:自定义类加载器加载的类必须是public的吗?

你去测试一下吧,我说了你也记不住
回复 使用道具 举报
a6511631 发表于 2014-8-12 10:17
首先classPath下不要放ClassLoaderAttachment.class,不然类加载器会先去加载它,而不会去自定义加载,
你 ...

classPath下存放ClassLoaderAttachment,AppClassLoader作为发起者,委托给父类加载器进行加载,当加载到AppClassLoader时均无法加载ClassLoaderAttachment,不会再向下由自定义加载器去加载,目测这是张孝祥老师关于MySrvlet的那个知识点啊!:D
回复 使用道具 举报
a6511631 发表于 2014-8-12 10:43
你去测试一下吧,我说了你也记不住

说说呗!看看我哪些东西还没学到!:D
回复 使用道具 举报
alee 中级黑马 2014-8-12 10:58:46
19#
这部分内容却是有点恶心,楼主多看看吧
回复 使用道具 举报
思维 发表于 2014-8-12 10:46
说说呗!看看我哪些东西还没学到!

外部类的访问修饰符只有public、default(不写即默认为default)。自定义的类加载器在加载类字节码的时候,它们在同一个包中吗?众所周知,不在同一个包就只能访问public修饰的类。通常情况下,不在。因为自定义加载时这个包下的classPath中不会放那个类字节码文件。

点评

精辟!  发表于 2014-8-12 12:33
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马