`

Java细节之static方法重写

 
阅读更多
前言
  Java语言拾遗,高手如果感兴趣可跳过前两节。
 
类方法
  方法被声明为static后,则称为类方法。类方法相对于实例方法,前者区别于后者的地方:前者为属于该类的所有实例对象共享,无须实例化对象,仅通过类名即可访问(当然,是否能够直接访问,还取决于所声明的访问权限)。

  因为被static化后产生上述特殊性,所以static变量都会在类被加载时初始化,而类方法也同时随类加载而进驻内存。先来段代码热热身吧~
public class Test ...{
    
public static void main(String[] args) ...{
        A.print();
        System.out.println(A.publicStr);
    }

}


class A ...{
    
private static A a = new A();
    
private static String privateStr = null;
    
public static String publicStr = "A Class";
    
    
private A() ...{
        privateStr 
= "A Calss";
    }

    
    
public static void print() ...{
        System.out.println(privateStr);
    }

}

  上段代码,输出结果为:
null
A Class

  由结果可知,即字符串prvateStr的值为空。嘿,可别认为值应该是下面那样啊。那样的话,进行下去就太具挑战性了。
A Class
A Class

  请记住一点,类变量初始化的顺序与其在类中的赋值顺序一致。

重写(覆盖)
  或许大家对于面向对象编程语言最初的印象就是其语言单元是以父类、子类的关系存在着,而构建这一关系的就是继承机制了。子类可以继承父类一切非private的变量与方法,并且可以添加自己的变量与方法。在构建一个系统时,这机制让我们强烈地感觉到编程是一门优雅的艺术。

  来段小小的代码简单地展示下:
public class Test ...{
    
public static void main(String[] args) ...{
        Programmer pro 
= new Programmer("Jack");
        
        pro.printName();
        pro.printProfession();
    }

}


class Man ...{
    
private String name = null;
    
public final String characteristic = "I am a thinking animal";
    
    
public Man(String name) ...{
        
this.name = name;
    }

    
    
public void printName() ...{
        System.out.println(name);
    }

}


class Programmer extends Man ...{
    
private String profession = "Programmer";

    
public Programmer(String name) ...{
        
super(name);
    }

    
    
public void printProfession() ...{
        System.out.println(characteristic 
+ ", and a " + profession);
    }

}

  结果如下:
Jack
I am a thinking animal, and a Programmer

  如上,子类Programmer中并没定义字符串characteristic,但我们却在其方法printProfession()中调用了;同样,我们正常使用了父类定义的printName()方法。而这就是继承的简单实现。

  继承不仅仅带来以上特性。它还赋予子类重写(覆盖)父类方法的能力(因为旨在讲类方法的重写,所以这儿就不讲重载以及变量在继承机制中的问题了)。方法的重写(覆盖):继承父类的子类,可以通过拟具有相同方法名与参数组的方法来重写父类中对应的方法,从而让子类更个性化。又因为重写(覆盖)的出现,多态也随之产生。多态:通过父类变量可以引用其子类对象,从而调用子类中那些继承自自己并被重写(覆盖)的方法。
public class Test ...{
    
public static void main(String[] args) ...{
        Man manP 
= new Programmer("Jack");
        Man manS 
= new Student("Tom""MayBeHarvard");
        
        manP.printName();
        System.out.println();
        manS.printName();
    }

}


class Man ...{
    
private String name = null;
    
    
public Man(String name) ...{
        
this.name = name;
    }

    
    
public void printName() ...{
        System.out.println(name);
    }

}


class Programmer extends Man ...{
    
private String profession = "Programmer";

    
public Programmer(String name) ...{
        
super(name);
    }

    
    
public void printName() ...{
        System.out.println(
"Hey, I am a " + profession + ". You know, that work is an art.");
        System.out.print(
"My name is ");
        
super.printName();
    }

}


class Student extends Man ...{
    
private String school = null;
    
    
public Student(String name, String school) ...{
        
super(name);
        
this.school = school;
    }

    
    
public void printName() ...{
        System.out.println(
"Hi, I am a student from " + school);
        System.out.print(
"My name is ");
        
super.printName();
    }

}


  结果如下:
Hey, I am a Programmer. You know, that work is an art.
My name is Jack

Hi, I am a student from MayBeHarvard
My name is Tom

  Man类型变量引用其子类对象,并成功调用对应方法打印出个性化的自我介绍。

类方法的重写?
  进行到这儿,对类方法与继承、重写等概念应该有较清楚的认识了。如果您不是很清楚、或者我上面介绍得不够详细,请参考Java的圣经《The Java Language Specification》

  现在开始本文的问题吧:
public class Test ...{
    
public static void main(String[] args) ...{
        Man man 
= new Programmer();
        Programmer pro 
= new Programmer();
        
        man.printName(
"ManCallMe");
        System.out.println();
        pro.printName(
"CallMeByMyself");
    }

}


class Man ...{    
    
public static void printName(String name) ...{
        System.out.println(name);
    }

}


class Programmer extends Man ...{    
    
public static void printName(String name) ...{
        System.out.println(
"Hey, I am a Programmer. You know, that work is an art.");
        System.out.print(
"My name is " + name);
    }

}

  结果如下:
Hey, I am a Programmer. You know, that work is an art.
ManCallMe

Hey, I am a Programmer. You know, that work is an art.
My name is CallMeByMyself

  “结果绝对不是这样!”如果运行过这段代码,您一定会大声的对我说。的确,结果事实上是这样的:
ManCallMe

Hey, I am a Programmer. You know, that work is an art.

  按照多态的介绍,结果应该是上一个啊!?为什么事实却是纠正的那个呢?难道重写(覆盖)没有成功?事实上,重写操作是成功的,因为第二个函数调用输出的结果证明了这点。那这一切的一切的问号是为何呢?

  方法被加载的顺序是这一切的根本原因!

  当一个方法被调用时,JVM首先检查其是不是类方法。如果是,则直接从调用该方法引用变量所属类中找到该方法并执行,而不再确定它是否被重写(覆盖)。如果不是,才会去进行其它操作(例如动态方法查询),具体请参考:方法的加载

  具体到上面那段代码,因为引用man是Man类型变量,所以JVM根据上述规定,调用的是Man中的printName(),而不是Programmer中printName();而pro正是Programmer,同理,其调用是自己的printName(),出现料想外的结果也就纯属正常了。

  最后,以一段有趣的代码结束本文。它也是本文对于类方法理解的强有力证据.它正确输出了结果,呵呵~
public class Test ...{
    
public static void main(String[] args) ...{
        (Man.getMan()).printName();
    }

}


class Man ...{    
    
public static void printName() ...{
        System.out.println(
"None");
    }

    
    
public static Man getMan() ...{
        
return null;
    }

}
分享到:
评论

相关推荐

    《java面向对象程序设计-继承和多态》教案.doc

    示例 4 方法重写 2-1 方法重写 2-2 访问修饰符 3-1 信息隐藏是 OOP 最重要的功能之一,也是使用访问修饰符的原因 信息隐藏的原因包括: 对任何实现细节所作的更改不会影响使用该类的代码 防止用户意外删除数据 此类...

    JAVA语言程序设计【高清版】.pdf

    77 5.5.1 static 77 5.5.2 final和abstract 79 5.5.3 this和super 84 5.6 方法重写 86 5.6.1 方法重写概述 86 5.6.2 应用重写的规则 89 5.6.3 调用父类构造方法 89 5.7 接口 90 5.7.1 多重继承中的...

    Java面试题超级全.zip

    3.synchronized 和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。 ``` ## 74.阐述静态变量和实例变量的区别? ``` 不管创建多少个对象,静态变量在内存中有且仅有一个;实例变量必须依存于某...

    JAVA面试题最全集

    一、Java基础知识 1.Java有那些基本数据类型,String是不是基本数据类型,他们有何区别。 2.字符串的操作: 写一个方法,实现字符串的反转,如:输入abc,输出cba 写一个方法,实现字符串的替换,如:输入...

    JAVA基础课程讲义

    方法的重写(override) 74 隐藏/封装(encapsulation) 75 为什么需要封装?封装的作用和含义? 75 使用访问控制符,实现封装 76 封装的使用细节 76 多态(polymorphism) 76 为什么需要多态? 76 如何实现多态? 77 方法...

    java 面试题 总结

    方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数...

    Java 语言基础 —— 非常符合中国人习惯的Java基础教程手册

    由于对构造方法可以进行重写 ,所以通过给出不同个数或类型的参数会分别调用不同的构造方法。 例子:以类 Rectangle 为例,我们生成类 Rectangle 的对象: Rectangle p1=new Rectangle (); Rectangle p2=new Rectangle...

    AIC的Java课程1-6章

     清楚如何通过向上转型(引用的隐式转型),方法重写,运行期绑定来实现多态性。  体会多态性如何使系统可扩展和可维护。  理解运行时判定引用对象的类型(instanceof),进行强制转型(即引用的显示转型...

    JAVA面向对象详细资料

    20.14 方法重写(核心@Override) 28 20.15 练习: 29 20.16 作业题: 31 21 类与类之间的关系 32 22 GC:垃圾回收机制 33 23 Object类 33 23.1 常用方法:boolean equals(Object) 33 23.2 常用方法:String ...

    java经典面试2010集锦100题(不看你后悔)

    C) Java中的封装就是将对象的数据和操作数据的方法相结合,通过方法将对象的数据和实现细节保护起来。 D) Java语言中的多态的含义可以表达为:对外一个接口,内部多种实现。Java语言支持两种多态:运行时多态和编译...

    超级有影响力霸气的Java面试题大全文档

     方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和...

    java认证所有课程

    你定义的Listener可以继承Adapter类,而且只需重写你所需要的方法。例如: 实现每个Listener接口的所有方法的工作量是非常大的,尤其是MouseListener接口和ComponentListener接口。 以MouseListener接口为例,它...

    javaSE整体学习总结,超级全面

    资源包含了,java中亿点点的细节,构成方法重载的条件,内的定义,构造器的四个要点,创建一个对象分为四步,java内部模型,栈的特点,堆的特点,方法区(又叫静态区,也是堆),this的本质,static关键字核心用法,静态的初始化块...

    突破程序员基本功的16课.part2

    第3课 常见Java集合的实现细节 3.1 Set和Map 3.1.1 Set和Map的关系 3.1.2 HashMap和HashSet 3.1.3 TreeMap和TreeSet 3.2 Map和List 3.2.1 Map的values()方法 3.2.2 Map和List的关系 3.3 ArrayList和...

Global site tag (gtag.js) - Google Analytics