文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何改变jar包某个类的运行方式

2023-06-17 13:52

关注

这篇文章主要介绍“如何改变jar包某个类的运行方式”,在日常操作中,相信很多人在如何改变jar包某个类的运行方式问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何改变jar包某个类的运行方式”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

例如:

有类 Feature

Java代码

public class Feature {             private String content;             public void show() {             System.out.println(this.content);         }     }

及类 Function

Java代码

public class Function {             private Feature f;             public void show() {             this.f.show();         }              }

测试类 Test,运行结果为 null . 而你想让他输出hello kitty

Java代码

public class Test {                     public static void main(String[] args) {             Function function = new Function();             function.show();         }         }

***想到的方法是就是直接建一个同包同名类,在你的eclipse或者其它编译环境下;然后把相关方法,改成自己想要的方法;如下:

Java代码

public class Feature {             private String content;             public Feature(){             this.content = "hello kitty";         }             public void show() {             System.out.println(this.content);         }     }

然后,你会发现,使用的是你的class吖,而不是jar包里的吖.

但是,如果你的程序也打成jar包,和原jar一起运跑,会是什么情况呢;

你可能发现,会输出 空,如果运气好,也可能 输出 hello kitty ;

为啥呢? 因为当有同包同名类时,classLoader总会尝试先加载到一个,而且加载到这个class文件后,后面就不会再加载;这个先加载到的类一般和classpath设置的先后有关;

在eclipse环境下,会先加载编辑器下的类,然后优先加载,先导入的类库;

如果先加载到你的类,那么就会输出 "hellokitty".

假如需要在生产环境指定加载你的类,

而且,

你无法预知客户如何设置classPath的先后顺序,那么,要怎么办呢?

可否自己写一个classLoader只加载目标类,而让你的调用程序在此classLoader环境下运行?

Let us try try : 先写出这个特别的classLoader

Java代码

public class HoneyLoader extends URLClassLoader {             public HoneyLoader(URL[] urls, ClassLoader parent){             super(urls, parent);         }             public synchronized Class loadClass(String name) throws ClassNotFoundException {             Class c = findLoadedClass(name);             if (c != null) {                 return c;             }     //先自己在指定位置(通过urls指定)找,找不到交给父类             try {                 c = this.findClass(name);             } catch (Exception e) {                 c = super.loadClass(name);             }             return c;         }     }

回到我们的测试类,修改如下

Java代码

public class Test {             public static void main(String[] args) throws Exception {             // 根据jar包名称,获取我们需要的jar包的名称的url             String jarName = "feature2.jar";             URL url = null;                 ClassLoader loader = Thread.currentThread().getContextClassLoader();             Enumeration urls = loader.getResources("Feature.class");             int i = 0;             while (urls.hasMoreElements()) {                 url = urls.nextElement();                 i = url.getPath().indexOf(jarName);                 if (i > -1) {                     break;                 }             }                 // 用honeyLoader启动我们的运行环境             ClassLoader myLoader = new HoneyLoader(new URL[] { new URL(url.getPath().substring(0, i) + jarName) }, loader);             Object object = myLoader.loadClass("Feature").newInstance();             object.getClass().getMethod("show").invoke(object);             }

运行结果:

Java代码

hello kitty

用classLoader的方法,将建立一个小的运行机制,和业务代码的相关性很低,冗余代码多;

而且,新建的和原类相同的包名和类不便于维护;

有什么更好的方法么?

对于(一)中描述的需求,其实,我们只需改变下Feature的私有属性content,是否可以通过反射来实现呢?

尝试以下代码:

Java代码

public class Test {             // 获取object 的属性 fieldName         public static Field getField(Object object, String fieldName) throws Exception {             Field field = object.getClass().getDeclaredField(fieldName);             return field;         }             public static void main(String[] args) throws Exception {             Function function = new Function();             // 获取function的feature             Field f_feature = getField(function, "f");                 // 通过feature 获取 其属性 content             f_feature.setAccessible(true);             Field f_function = getField(f_feature.get(function), "content");                 // 改变content的内容             f_function.setAccessible(true);             f_function.set(f_feature.get(function), "hello kitty");                 function.show();         }     }

执行,得到结果

Java代码

hello kitty

冗余代码减少,目的更加明确了,但对于改变的业务代码,任然不清晰;不容易维护;

通常,如果我们要得到有我们的特性的类,通常用继承的方法,但是有时候,会发现,如果是你要调用的调用的调用的类,要改变一点动作,那你为了改调用的调用的调用,不得不继承调用和调用的调用;

假如我们只改变目标类,只继承目标类,结合反射的方式,改调用,是否可行呢?

例如,继承Feature创建类MyFeature

Java代码

public class MyFeature extends Feature {             private String mycontent;             public MyFeature(){             this.mycontent = "hello kitty";         }             public void show() {             System.out.println(this.mycontent);         }     }

这样我们改变的逻辑清晰很多,容易维护,我们再来修改下Test类

Java代码

public class Test {             // 获取object 的属性 fieldName         public static Field getField(Object object, String fieldName) throws Exception {             Field field = object.getClass().getDeclaredField(fieldName);             return field;         }             public static void main(String[] args) throws Exception {             Function function = new Function();             // 获取function的feature             Field f_feature = getField(function, "f");                 // 改变feature的内容             f_feature.setAccessible(true);             f_feature.set(function, new MyFeature());                 function.show();         }     }

此时,Test的逻辑也清晰很多,我们可以清楚的看到,我们需要改变哪个类

运行一下,看下结果

Java代码

hello kitty

到此,关于“如何改变jar包某个类的运行方式”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯