打字猴:1.700441026e+09
1700441026
1700441027 }
1700441028
1700441029 //覆写父类的非静态方法
1700441030
1700441031 @Override
1700441032
1700441033 public void doAnything(){
1700441034
1700441035 System.out.println(“我是子类非静态方法”);
1700441036
1700441037 }
1700441038
1700441039 }
1700441040
1700441041 注意看程序,子类的doAnything方法覆写了父类方法,这没有任何问题,那doSomething方法呢?它与父类的方法名相同,输入、输出也相同,按道理来说应该是覆写,不过到底是不是覆写呢?我们先看输出结果:
1700441042
1700441043 我是子类非静态方法
1700441044
1700441045 我是父类静态方法
1700441046
1700441047 这个结果很让人困惑,同样是调用子类方法,一个执行了子类方法,一个执行了父类方法,两者的差别仅仅是有无static修饰,却得到不同的输出结果,原因何在呢?
1700441048
1700441049 我们知道一个实例对象有两个类型:表面类型(Apparent Type)和实际类型(Actual Type),表面类型是声明时的类型,实际类型是对象产生时的类型,比如我们例子,变量base的表面类型是Base,实际类型是Sub。对于非静态方法,它是根据对象的实际类型来执行的,也就是执行了Sub类中的doAnything方法。而对于静态方法来说就比较特殊了,首先静态方法不依赖实例对象,它是通过类名访问的;其次,可以通过对象访问静态方法,如果是通过对象调用静态方法,JVM则会通过对象的表面类型查找到静态方法的入口,继而执行之。因此上面的程序打印出“我是父类静态方法”,也就不足为奇了。
1700441050
1700441051 在子类中构建与父类相同的方法名、输入参数、输出参数、访问权限(权限可以扩大),并且父类、子类都是静态方法,此种行为叫做隐藏(Hide),它与覆写有两点不同:
1700441052
1700441053 表现形式不同。隐藏用于静态方法,覆写用于非静态方法。在代码上的表现是:@Override注解可以用于覆写,不能用于隐藏。
1700441054
1700441055 职责不同。隐藏的目的是为了抛弃父类静态方法,重现子类方法,例如我们的例子,Sub.doSomething的出现是为了遮盖父类的Base.doSomething方法,也就是期望父类的静态方法不要破坏子类的业务行为;而覆写则是将父类的行为增强或减弱,延续父类的职责。
1700441056
1700441057 解释了这么多,我们回头看一下本建议的标题:静态方法不能覆写,可以再续上一句话,虽然不能覆写,但是可以隐藏。顺便说一下,通过实例对象访问静态方法或静态属性不是好习惯,它给代码带来了“坏味道”,建议读者阅之戒之。
1700441058
1700441059
1700441060
1700441061
1700441062 编写高质量代码:改善Java程序的151个建议 [:1700438103]
1700441063 编写高质量代码:改善Java程序的151个建议 建议34:构造函数尽量简化
1700441064
1700441065 我们知道在通过new关键字生成对象时必然会调用构造函数,构造函数的简繁情况会直接影响实例对象的创建是否繁琐。在项目开发中,我们一般都会制订构造函数尽量简单,尽可能不抛异常,尽量不做复杂算法等规范,那如果一个构造函数确实复杂了会怎么样?我们来看一段代码:
1700441066
1700441067 public class Client{
1700441068
1700441069 public static void main(String[]args){
1700441070
1700441071 Server s=new SimpleServer(1000);
1700441072
1700441073 }
1700441074
1700441075 }
[ 上一页 ]  [ :1.700441026e+09 ]  [ 下一页 ]