阅读更多

23顶
29踩

编程语言

原创新闻 四个有害的java习惯

2008-07-29 10:11 by 见习记者 jolestar 评论(76) 有38827人浏览

John O'Hanley 的这篇文章列举了四个有害的java编码习惯,并提出了改正方案。

这四个习惯普遍存在于java程序员中,并且已经被广泛接受,大家都习以为常,流毒甚远。

 

1.对局部变量(local variables),字段(fields),参数(method arguments)这三种变量的命名没有区分,造成了代码的阅读困难,增加了代码的维护成本。

 

作者举了个例子:

public boolean equals (Object arg) {
  if (! (arg instanceof Range)) return false;
  Range other = (Range) arg;
  return start.equals(other.start) && end.equals(other.end);
}

 

在这个方法中,arg直接用argument的缩写,虽然大家一看就知道这是参数了,但这种命名方式却丢失了参数代表的对象本身的含义。大家知道这是参数,却不知道这是什么参数。如果方法的参数多一点,都按照arg1,arg2这样的方式命名,阅读代码的时候很头疼。另外两个字段变量,start和end,突然凭空而出,想一下才知道这应该是字段。当然,这个方法很短,造成的困难还不大,如果这个方法比较长的话,突然看到start和end两个变量,一般会先在前面找一下是不是局部变量,然后才能确定是类的字段变量。

 

这个问题貌似微不足道,但为什么要让代码阅读者花费额外时间在这些琐碎的问题上呢?如果有个方案能让代码阅读者一目了然的明白变量是那种变量,为什么不采用呢?就如同Steve McConnell在 《代码大全》中说的:"让人费神去琢磨神秘杀人凶手这没有问题,但你不需要琢磨程序代码,代码是用来阅读的。"


作者提出了解决方案:

  • 方法参数用前缀a开始
  • 类字段变量用前缀f开始
  • 局部变量不用前缀

修正后的代码样式应该是:

public boolean equals (Object aOther) {
  if (! (aOther instanceof Range)) return false;
  Range other = (Range) aOther;
  return fStart.equals(other.fStart) && fEnd.equals(other.fEnd);
}

 

这样的代码看起来一目了然,如果你没有一目了然,说明还是习惯问题,习惯养成了就好了。

 

不过作者的方案里,给类字段变量前面加 f 前缀,如果用代码生成工具生成get,set方法是会比较麻烦。get,set方法中我们不希望出现个f。不过这个问题可以用修改代码生成工具的方式解决。如果这个习惯普遍被java界接受,这些应该都不成问题了。

 

作者引用了一句名言:

 

"By relieving the brain of all unnecessary work, a good notation sets it free to concentrate on more advanced problems, and in effect increases the mental power of the race. Before the introduction of the Arabic notation, multiplication was difficult, and the division even of integers called into play the highest mathematical faculties. Probably nothing in the modern world would have more astonished a Greek mathematician than to learn that ... a large proportion of the population of Western Europe could perform the operation of division for the largest numbers. This fact would have seemed to him a sheer impossibility ... Our modern power of easy reckoning with decimal fractions is the almost miraculous result of the gradual discovery of a perfect notation."
-- Alfred North Whitehead, An Introduction To Mathematics

 

个人理解大意为:

把大脑从不必需的工作中解放出来,一个好的记号法可以让大脑去关注更高级的问题,提升民族的整体智力。在阿拉伯数字记号法被介绍进来以前,乘法是非常困难的,计算整除也需要非常高的数学才能。一个古希腊的数学家可能非常诧异于西欧的大多数人口可以计算很大数字的除法。这个事实对他来说似乎是不可能的。我们现代人很容易用小数算帐的能力几乎可以说是由逐渐探索出的一套完美的计数法而造成的奇迹。

 

2.包(package)的命名和划分按照行为和层次划分(package-by-layer)而不是根据特征和功能划分(package-by-feature)

 

这个问题在我刚学java的时候就遇到了,在看了众多的网上开源程序后,我也慢慢习惯了按层次命名包。

作者举了个例子:

 
  • com.blah.action
  • com.blah.dao
  • com.blah.model
  • com.blah.util

我们已经习惯了按照层次分类或者叫按照行为分类,model一个包,dao一个包,service一个包,action一个包。这样就把具有同样特征或者功能的类划分到了不同的包里。这样的习惯,把java的包内私有(package-private)这个作用域给完全扔掉了,而包内私有是java的默认作用域。(ps:我学java来好像很少用过java的包内私有这个作用域,汗一个)

这中包的划分习惯也违反了面向对象编程的核心原则之--尽量保持私有以减少影响,因为这种习惯强迫你必须扩大类的作用域.

 

下面的包命名方式是按照特征划分命名:

  • com.blah.painting
  • com.blah.buyer
  • com.blah.seller
  • com.blah.auction
  • com.blah.webmaster
  • com.blah.useraccess
  • com.blah.util

举个例子,在一个web应用中,com.blah.painting包可能包含下面的成员:

  • Painting.java: model对象
  • PaintingDAO.java: dao对对象
  • PaintingAction.java:controller or action 对象
  • statements.sql: SQL文件
  • view.jsp: JSP文件

 

值得注意的是这种情况下,包里包含的不仅仅是java源码文件,同时也包含其他与该特征相关的文件。这点上好像违反大多数java程序员的习惯,并且如果要打包为jar好像也不方便,真实环境中如何应用,有没有别的麻烦,还要待实践一下。

 

作者列举了这种包划分方式的优点:

  • 包是高内聚的,并且模块化,包与包之间的耦合性被降到最低。

  • 代码的自文档性(或自描述性 self-documenting)增强. 读者只需看包的名字就对程序有些什么功能或特征有了大概的印象。在《代码大全》中, Steve McConnell 将自文档化(self-documenting)的代码比作 "the Holy Grail of legibility."(不知道怎么翻译)

  • 把类按照每个特征和功能区分开可以很容易实现分层设计。

  • 相关的成员在同一个位置。不需要为了编辑一个相关的成员而去浏览整个源码树。

  • 成员的作用域默认是包内私有。只有当另外的包需要访问某个成员的时候,才把它修改为public. (需要注意的是修改一个类为public,并不意味着它的所有类成员都应该改为public。public成员和包内私有(package-private)成员是可以在同一个类里共存的。)

  • 删除一个功能或特征只需要简单的删除一个文件夹。
  • 每个包内一般只有很少的成员,这样包可以很自然的按照进化式发展。如果包慢慢变的太大,就可以再进行细分,把它重构为两个或者更多新的包,类似于物种进化。而按照层次划分的方式,就没办法进化式发展,重构也不容易。

作者引用了一句Effective Java中的名言:

"The single most important factor that distinguishes a well-designed module from a poorly designed one is the degree to which the module hides its internal data and other implementation details from other modules."
-- Joshua Bloch, Effective Java

 

 

3.习惯用JavaBeans而不是不可变对象

 

按照javabeans的说明书(JavaBeans specification ),javabeans是用来解决特殊领域的问题:在图形界面程序的设计中充当小部件。但现在通常用javabean来做数据库记录的映射。作者反对javabean的这种用法。他提出了一个问题:

假如你要从数据库记录集映射一行为对象,不考虑现有的持久化方案和框架,你会将这个对象设计成什么样子?跟javabean相似呢还是完全不一样?

 

作者倾向于设计一个完全不一样的,他列举他的设计的几个特点:

 

  • 它不包含一个无参数构造方法(这一特征是javabean必备的。)。作者认为一个数据库记录的对象如果不包含任何数据是没有意义的。一个数据库表的所有字段都是可选的情况有多少?
  • It would likely not have anything to say about events and listeners.(不太明白作者的意思)

  • 它不强迫你用可变的对象。
  • 它内部有一个数据验证机制。这样一个验证机制对大多数数据库应用非常重要。(记住对象的第一原则:一个对象应该同时封装数据和对数据的操作。在这种情况下,操作就是验证数据。)

  • 数据验证机制可以给最终用户(end user)报错。

 

作者不满于现有的数据库持久化框架滥用javabean,提出了几个观点,但没有具体的代码演示。据我的理解,作者的意思和前一段时间javaeye上争论的充血模型和贫血模型有点类似。

 

4.类成员的排序没有按照成员的作用域(scope) 的大小从大到小排列,而是喜欢把private放在前面。

 

作者举了一个常见的类样式:

public class OilWell implements EnergySource {
   private Long id;
   private String name;
   private String location;
   private Date discoveryDate;
   private Long totalReserves;
   private Long productionToDate;
   
   public Long getId() {
      return id;
   }
   public void setId(Long id) {
      this.id = id;
   }
   
  //..elided
}

 这种方式将private变量放在最前面。作者认为应该倒过来,把private变量的申明放在最后面。

 

因为人们认识一个事物的通常过程都是从一般到特殊,从抽象层次来说,是从高到底的认识过程。如果你倒过来的话,就不能从整体上把握事物,也不能抓住事物的本质,只能在一堆具体的片段事实中迷失。

 

整体的抽象允许你忽略细节。抽象的层次越高,你可以忽略越多的细节。读者阅读一个类时可以忽略的细节越多他会越高兴。脑袋里填充太多的细节是痛苦的,所以细节越少越好。因此,将private成员方在最后会显得更富有同情心,因为这样阻止了不必要的细节显露给读者。

 

原来C++程序的习惯也是把private成员放在最开始。然而,C++社区迅速的认识到这是一个有害的规范,这个规范现在已经被修正。(参看 a typical C++ style guide )

注意:public 接口应该放在class的最开始,其次是protected成员,最后是private成员。原因是:

  • 程序员应该更关心接口而不是具体实现。
  • 当程序员需要用一个类的时候,他们需要的是接口而不是实现。

把接口放在开始是非常有意义的。把实现部分,private 片段,放在开始是一个历史遗留问题。最后还是要反复强调一下,一个类的接口的重要性超过实现细节。

 

将私有成员放在类的开始是一个等待打破的怀习惯,它似乎是sun早期的编码规范造成的。

 

将代码按照javadoc的顺序编排是非常好的:首先是构造方法,然后是非私有方法,最后是私有字段和方法。这样读者阅读的时候很自然的从抽象层次的高向低运动。

 

作者的这个观点确实很有道理,以前也没仔细思考过。可以考虑给IDE做个重构插件,专门按照这种排序格式化代码。

 

 

本文不算严格意义上的翻译,算是该文章的摘要以及读后感。

 

文章原始地址:http://www.javaworld.com/javaworld/jw-07-2008/jw-07-harmful-idioms.html

 

作者介绍:

John O'Hanleyjavapractices.com 的专栏作者, 同时也是 WEB4J framework  的创建者。他拥有10年编程经验,现在居住于Prince Edward Island, Canada.

 

参考资料:

23
29
评论 共 76 条 请登录后发表评论
56 楼 clarkcc1988 2008-10-27 10:27
只有第一条游泳 !
55 楼 flykete 2008-09-09 23:11
第一条基本上从不犯。
后面几条,纯属吃饱撑着的。尤其第二条,当业务量大时,用navigate视图,看晕自己了。
54 楼 withinsea 2008-09-03 22:26
关注借口的方式是写 interface... 而不是排列 public/protected/private 的顺序。第四条毫无意义……
53 楼 zhaoyun04420 2008-08-22 16:51
没有一点意义!
52 楼 zmxt2008 2008-08-15 10:14
写的很有见解,学习中,这样我们就会不会犯同样的错误了。
51 楼 echenyin 2008-08-13 12:25
第一条从没犯过
第二条很有意思,从中发现了自己对于设计上了解的许多缺点
第三条听不懂
第四条没必要
50 楼 lihuyu1231 2008-08-12 09:13
我觉得java程序员里头,都有些自认为高手或者高手都有套自认为的规范,
但是在不发生歧义的情况下问题都不大,但是命名要有意义这才是最重要得。

个人认为作者自己 第一条修改后得例子实在是不怎么样,
方法调用的时候,特征性的参数重要是参数的类型,一些标志性的参数则是要有意义。
49 楼 sunsong 2008-08-10 13:46
作者还是很有见地的。
java命名习惯中,参数命名是最大的问题。
参数,作用域仅仅在方法内部,完全应该跟field区分开来,这样在维护代码的时候一目了然。
还有一个很常见的潜在威胁,那就是setter的默认生成方式:

public void setUsername(String username){
    this.username = username;
}
这里,很容易出问题。一旦this.username前面的this忘记写了, 或者被人删掉了,很难发现。
匈牙利命名方式的主要问题在于类型,而不是变量的用途。
而且,现在的ide重构功能都很强大,如果有变化,重构也很方便。
在粗粒度上把参数、变量、成员分开,完全是应该的。
48 楼 sunsong 2008-08-10 13:45
作者还是很有见地的。
java命名习惯中,参数命名是最大的问题。
参数,作用域仅仅在方法内部,完全应该跟field区分开来,这样在维护代码的时候一目了然。
还有一个很常见的潜在威胁,那就是setter的默认生成方式:

public void setUsername(String username){
    this.username = username;
}
这里,很容易出问题。一旦this.username前面的this忘记写了, 或者被人删掉了,很难发现。
匈牙利命名方式的主要问题在于类型,而不是变量的用途。
而且,现在的ide重构功能都很强大,如果有变化,重构也很方便。
在粗粒度上把参数、变量、成员分开,完全是应该的。
47 楼 FutureInHands 2008-08-05 18:23
第二条有其优势,就是能充分发挥包级私有,但似乎也失去了明显的层次架构,如果在充分利用包级私有和清晰的层次架构我还选择后者层次架构。其他建议感觉都是鸡肋。
46 楼 RednaxelaFX 2008-08-05 17:10
哦对了,我说的“翻反了”不是说翻译错了,是表达方式与原文反过来了。原本作者是“提供建议”,而这里翻译变成了“指出现在的做法的错误”,读起来总觉得别扭……
45 楼 RednaxelaFX 2008-08-05 17:07
John O'Hanley 写道
JavaBeans: Why use them when immutables will do?

引用
3.习惯用JavaBeans而不是不可变对象


这个标题给翻反了,也难怪读起来觉得别扭。作者是推荐使用不可变对象,反对到处用JavaBeans。
引用
It would likely not have anything to say about events and listeners.(不太明白作者的意思)

一个Java Bean在数据绑定或者GUI事件响应等场景中会涉及到事件与监听器。不过不提供任何事件的Java对象也可以是一个Java Bean,所以这点不是特别重要——毕竟如果是一个不可变对象的话,状态不可变,能有发出什么事件呢?自然就得到了“它多半与事件和监听器没啥关系”的论点。

话说这篇是楼主的原创对吧?看起来貌似被别处转载了?

P.S. 命名规范这种东西还是自己舒服就算了……
44 楼 fyting 2008-08-04 23:53
第一条问题很常见,但解决办法不敢苟同。在文本编辑器里看java代码经常会不知所云,而看python、ruby这类语言却没有任何问题。比如我的self.name='xxx',很清晰。java里在实例变量前面加this的引用就可以了,这个问题只在文本编辑器里看代码时存在,在IDE里完全可以用字体区分出field和local variable的,所以人都被惯坏了
第二条是很好的建议,不过按照这个action,model,dao来分package的怕是网上spring的例子看多了吧。真正的项目一般都是先按照功能,再按照代码的行为来划分,也就是说先buyer,seller,再在这里面细分action,model,dao的package
第三条我实在看不懂他的标题和内容的联系。可变和不可变对象在于使用者,你不向数据库里取出的user对象故意setName他就是不可变的。还有顺便说说java这javabean规范真够恶心的,本来就是个语言层面的东西,偏要写一堆java.beans.*,纯粹脑袋进水的表现,我一直在想该用is还是has,getURL对应的property name是url还是URL或者uRL.
第四条,与第一条呼应了。如果代码编写者没用this引用实例变量,我还可以直接在类最前面找到这个变量。如果在类的最后面,我得翻几页,到最后去找它是个啥东西。想想看Core Java里代码的体验吧,很爽?
43 楼 keypoints 2008-08-04 23:33
谁能整理一份比较适用的Java编码规范呀?是经过实践检验的。
42 楼 hulin 2008-08-04 16:48
感觉第一条最有价值
41 楼 freemanxm84 2008-08-04 15:25
扯淡,大家都在用的方法才是好方法,如果有问题,大家为什么在用,最佳实践是从实践中来的,不是空想出来的。完全是自己给自己找麻烦。
40 楼 zhaowei_520 2008-08-04 13:02
把参数名称前都加上 a,字段前都加上 f, 还没有看到过这样的编程方式。而且我感觉这样才不直接,不明白;大家都这样写,你偏要那样搞,再说了,大家反而绝对不习惯。你说让大家改就改吗?还好,你不是 sun 公司的什么 java 规范的什么负责人,要是那样,我们就惨了。。。。
39 楼 sking002 2008-08-01 13:13
int i = 0;
38 楼 Sunr∧se 2008-08-01 09:52
我倒是认为作者提了四个有害的建议。

引用
1.对局部变量(local variables),字段(fields),参数(method arguments)这三种变量的命名没有区分,造成了代码的阅读困难,增加了代码的维护成本。

看到这个命名规范,让我想起了Delphi,但是我在用Delphi的时候一样遇到过问题。强制要求在参数前面+a,字段前面+f,有时候反而会带来意义的混淆。
例如,id,硬要改成fId吗?old,硬要改成fOld吗?那跟Fold的语义如何区分?
最大的故障在于Eclipse的自动生成getter/setter,如果按此命名,那就出现了getFid/setFid,isFold/setFold……
仅此一条,我大胆推测作者是否属于平常不写代码,只是看代码的人?建议不要总是站在高处指挥,偶尔还是需要写写代码练手。

引用
2.包(package)的命名和划分按照行为和层次划分(package-by-layer)而不是根据特征和功能划分(package-by-feature)

也属于不写代码的人纸上谈兵的理论,看上去很美。
不是说把这些class放在一个文件夹下,这个模块就高内聚了。
引用
# com.blah.painting
# com.blah.buyer
# com.blah.seller

这样的分法当然有道理,但是我们还是喜欢在每个下面再分service/dao/model,而且JSP绝不会和这些文件混在一起,因为Web只是系统对外展现内容的一种渠道,如果系统还有一种对外渠道是Delphi开发的客户端,按这种意图,是否也要将Delphi的窗体文件也放到文件夹里,才表示高内聚?

引用
3.习惯用JavaBeans而不是不可变对象

这个就懒得批了,他直接把bean的概念都推翻了,那还有什么好说的,不如推翻J2EE规范另起炉灶好了。

引用
4.类成员的排序没有按照成员的作用域(scope) 的大小从大到小排列,而是喜欢把private放在前面。

作者不是第一个提这个的人,我也真的曾经在项目组内尝试过,但……毫无意义。
因为我自己都不觉得这有什么好处,而且我相信写了多年程序的人,都已经习惯了private/protected/public的从小到大排列?
如果说代码的排列顺序会影响虚拟机对函数的寻址速度,我倒是愿意坚持下去,但是实际上并非如此……而且现在找函数,谁会用pagedown?都在outline上面点的吧?


37 楼 rauldiego 2008-08-01 09:29
包(package)到底该如何划分啊

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 利用反射实现类的动态加载

    利用反射实现类的动态加载

  • Java 动态代理

    1、最简单的动态代理例子 使用动态代理的基本要素:首先需要有一个写好的动态代理工具类,然后要有个接口和对应的实现类, 1、动态代理工具类 package proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** 代理类:帮助我们做一个被代理的业务对象返回。 java.lang.reflect.Proxy:这是 J

  • java合理估算线程池大小——Dark Magic

    具体见并发编程网的文章http://ifeve.com/how-to-calculate-threadpool-size/, 原代码乱序了,这里做一个排序后分享 github地址: https://github.com/sunshanpeng/dark_magic

  • Java中的动态类加载详解

    今天我们将深入探讨Java中的动态类加载,这是一种在运行时加载类文件的重要机制。动态类加载通过反射和自定义类加载器机制,使得程序在运行时可以根据需要动态加载和使用类,提高了应用程序的灵活性和可维护性。Java中的动态类加载能够使程序在运行过程中动态地装载、链接和初始化类,从而增强程序的灵活性和可扩展性。除了Java标准库提供的类加载器外,我们还可以自定义类加载器来实现更灵活的动态类加载需求。在Java中,实现动态类加载主要依赖于Java的反射机制和类加载器(ClassLoader)机制。

  • java工厂模式加策略模式实现动态选择类例子

    1.工厂模式加策略模式实现动态选择类 /** * 退款实现接口 */ public interface RefundIdentifyService { CommonNotify toRefund(RefundModel refundModel); } //支付宝退款实现 @AllArgsConstructor @Service public class AliIdentifyService implements RefundIdentifyService { private

  • Spring动态选择实现类

    一、需求描述 在实际工作中,我们经常会遇到一个接口及多个实现类的情况,并且在不同的条件下会使用不同的实现类,那么如何动态选择某一个实现类呢。 二、代码实现 1.根据ApplicationContext的getBeansOfType和自定义注解实现 spring上下文工具类ApplicationContextUtil import org.springframework.beans.BeansException; import org.springframework.context.Appli

  • java 动态指定方法_spring如何动态指定具体实现类

    在写接口实现时,有时会有多个实现类。这篇文章介绍在调用时通过传入字符串来指定具体的实现类。一.接口与实现类:// 接口public interface ServiceInterface {public void method();}// 具体两个实现类@Service("aService")public class AServiceImpl implements ServiceInterface ...

  • java 动态创建类_Java实现动态创建类操作示例

    本文实例讲述了Java实现动态创建类操作。分享给大家供大家参考,具体如下:Java可以创建动态类,学习看到,此处作为笔记。代码如下:import java.io.IOException;import java.lang.reflect.Method;import java.net.URI;import java.util.ArrayList;import java.util.Arrays;impo...

  • Java动态加载类

    今天上课讲了Java中的一些反射知识。 随便练习了一下。 学生类: public class Student { public static int number; static { number = 0; } public Student() { } private String studentName; public String getStudentName() { return student

  • 《Java核心技术面试精讲》24讲学习总结

    第24讲心得 该讲介绍了哪些方法可以在运行时动态生成一个 Java 类。 我们可以从常见的 Java 类来源分析,通常的开发过程是,开发者编写 Java 代码,调用 javac 编译成 class 文件,然后通过类加载机制载入 JVM,就成为应用运行时可以使用的 Java 类了。从上面过程得到启发,其中一个直接的方式是从源码入手,可以利用 Java 程序生成一段源码,然后保存到文件等,下面就只需要解决编译问题了。有一种笨办法,直接用 ProcessBuilder 之类启动 javac 进程,并指定上面生

  • java动态类加载_实现Java动态类载入机制

    作 为 充 分 利 用Java 的 动 态 类 载 入 机 制 的 最 好 例 子, 带 有Java 扩 展 的Web 浏 览 器 根 据 请 求 从 网 络 或 本 地 文 件 系 统 中 动 态 加 载Java applet( 遵 循 一 定 规 则 的Java 小 应 用 程 序 类), 然 后 在 本 地 系 统 中 执 行 它, 大 大 增 强 了 主 页 的 功 能。---- 其 实,...

  • Java动态调用类的方法案例

    一、场景 需要根据编号动态给类设置值,属性名为“f+费用编号”,例如f01表示编号为01的费用 public class MonitorDayFee implements Serializable { private static final long serialVersionUID = 1L; private Long dayFeeId;//主键 privat...

  • Java动态类加载

    Java动态类加载 文章首发自: https://www.le1a.com/posts/9d41d3f8/ 前言 前面学习了反序列化,正准备趁热打铁去学cc3了,但是发现cc3需要用到动态类加载,就先来学一下。 利用URLClassLoader加载远程class文件 首先了解下什么是ClassLoader? ClassLoader是一个"加载器",它会让Java虚拟机知道如何加载这个类。默认的ClassLoader是根据类名来加载类的,这个类名必须是类的完整路径(跟反射有点类似),例如java.lang.R

  • Spring中动态选择实现类

    在spring中当一个接口有多个实现类的时候,通过创建简单工厂类,根据传入的不同的参数获取不同的接口实现类。 public interface ExecuteService { ExecuteEnum getCode(); // 业务方法 void execute(); } @Service public class FirstExecuteServiceImpl imp...

  • Java反射之一——动态加载机制

    Java程序的运行过程的一个简单的示意图如下: 首先,ClassLoader将xxx.class文件加载到code segment中,然后找到main()函数开始执行,在程序运行过程中,会有更多的class被load到内存。需要注意的是需要一个类时再加载一个类,而不是事先就加载所有的类。这叫做动态加载机制。 public class Reflection { public st...

  • java动态加载类_Java:类的动态加载

    package com.biao.util;import java.io.File;import java.net.URL;import java.net.URLClassLoader;import com.biao.ActionInterface;/*** 使用URLClassLoader动态的加载Class类和jar包中的类. 这样,可以把这些类路径放在配置文件中,动态的加载.*/public...

  • Java中实现动态加载类?

    一、案例引入: 假如某项目组要开发一款Office平台, 里面有Word模块和Excel模块, 你负责的部分是启动程序,即: 当键盘输入"Word"时,启动Word 当键盘输入"Excel"时,启动Excel 你写完代码,但是并不能运行, 因为, 你并没有拿到其他人所写的Word类和Excel类 ...

  • java 动态加载类

    一、什么是动态加载类动态加载:通过Class.forName的方式来得到一个Class类型的实例,然后通过这个Class类型的实例的newInstance来初始化,这种方法我们称之为动态加载程序在运行时调用相应方法,即使其他方法是错误的,程序依旧会执行。通过动态加载可以让程序的可延长性大大提升,对以后的维护和扩展有重要意义。Class c = Class.forName("com.mianshi.t

  • java 通过代码实现动态选择数据源

    类注解 import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.Retentio

Global site tag (gtag.js) - Google Analytics