`
redhatqhd
  • 浏览: 1437 次
  • 来自: ...
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

覆盖与隐藏

J# 
阅读更多

JAVA类继承过程中其成员的一些问题

 构造函数不能继承。子类的构造函数可以通过super关键字显式调用父类中的构造函数。如果子类中的构造函数没有显式调用父类中的构造函数,编译器就会自动在子类的构造函数中调用父类中参数为空的构造函数。于是,当父类中没有参数为空的构造函数,而子类中又没有显示调用父类的其他构造函数,编译时就会报错。这一点需要特别注意。当父类中没有定义任何构造函数时,编译器就会为它指定一个参数为空的默认的构造函数;如果父类中定义了构造函数,那么编译器就不会为它指定一个参数为空的默认构造函数了。因此,如果某个类有可能成为其他类的父类,为了避免发生不必要的编译错误,最好为它编写一个参数为空的构造函数。

eg1.父类Sup中没有定义构造函数,编译程序将为它指定一个参数为空的默认构造函数。子类Sub中也没有定义构造函数,编译程序也会为它指定一个参数为空的默认的构造函数,并且会在这个默认的构造函数中调用父类的参数为空的构造函数。
public class Sub  extends Sup{
    //子类中没有定义构造函数
    public static void main(String args[]){
        Sub sub=new Sub();
    }
}

class Sup{
    //父类中没有定义构造函数
}


eg2.父类Sup中没有定义构造函数,编译程序将为它指定一个参数为空的默认构造函数。子类定义了一个带整型参数的构造函数,在这个构造函数中子类没有显式调用父类的构造函数,所以编译器为在它里面调用父类中参数为空的构造函数。

public class Sub  extends Sup{
    //子类中定义类一个带整型变量参数的构造函数
    public Sub(int i){
        //
    }
    public static void main(String args[]){
        Sub sub=new Sub(1);
    }
}
class Sup{
    //父类中没有定义构造函数
}
eg3.父类中定义了一个带整型参数的构造函数,因此编译器不再为它指定参数为空的默认的构造函数。子类中也定义了一个带整型参数的构造函数。编译时,编译器将试图在子类的构造函数中调用父类的参数为空的构造函数,但是父类中没有定义参数为空的构造函数,所以编译程序将会报错。排错的方法时在子类的构造函数中显示调用父类的构造函数,或者在父类中添加一个带空参数的构造函数。

public class Sub  extends Sup{
    //子类中定义类一个带整型变量参数的构造函数
    public Sub(int i){
        //
    }
    public static void main(String args[]){
        Sub sub=new Sub(1);
    }
}

class Sup{
    //父类中定义了一个带整型参数的构造函数
    public Sup(int i){
        //
    }
}
   排错方法1:

public class Sub  extends Sup{
    //子类中定义类一个带整型变量参数的构造函数
    public Sub(int i){
        super(i);//调用父类中的构造函数
    }
    public static void main(String args[]){
        Sub sub=new Sub(1);
    }
}

class Sup{
    //父类中定义了一个带整型参数的构造函数
    public Sup(int i){
        //
    }
}
   排错方法2:

public class Sub  extends Sup{
    //子类中定义类一个带整型变量参数的构造函数
    public Sub(int i){
        //
    }
    public static void main(String args[]){
        Sub sub=new Sub(1);
    }
}

class Sup{
    //父类中定义了一个带整型参数的构造函数
    public Sup(int i){
        //
    }
    //定义一个带空参数的构造函数
    public Sup(){
        //
    }
}

二、类方法和实例方法在继承过程中的问题:
  
   首相要明确一个概念,JAVA中通过什么来区别不同的成员——答案是标记。所谓标记,对于方法而言是指方法的名字、参数的数量和参数的类型;对于变量而言是指变量的名称。注意,标记不包括方法的返回值和变量的类型。

   如果子类的实例方法和父类的实例方法具有相同的标记,子类的方法将覆盖父类的方法。但是如果子类的方法和父类的方法具有相同的标记,但是具有不同的返回值类型,编译程序将会报错。排错的方法是修改子类中这个方法的返回值类型,使它父类中相同标记的方法的返回值一样。

public class Sub  extends Sup{
    //子类中的这个方法父类中的方法有相同的标记,
    //但返回值不同,编译程序就会报错
    int test(){
        return  1;
    }
}

class Sup{
    void test(){
        //
    }
}
   排错:

public class Sub  extends Sup{
    //子类中的方法正确覆盖了父类中的方法
    void test(){
        //
    }
}

class Sup{
    void test(){
        //
    }
}
   同样如果子类的类方法和父类的类方法具有相同的标记,那么子类的类方法将隐藏父类的类方法。注意这里不叫覆盖,而叫隐藏,两者的区别将在后面讨论。同样,如果子类的类方法和父类的类方法具有相同的标记和不同的返回值,编译程序也会报错。解决的问题的方法同实例方法一样。

   但是实例方法不能覆盖类方法,类方法也不能隐藏实例方法,否则编译程序就会报错。
  
   实例方法不能覆盖类方法(编译时报错):
public class Sub  extends Sup{
    //实例方法不能覆盖类方法,编译时报错
    void test(){
        //
    }
}

class Sup{
    static void test(){
        //
    }
}
   类方法不能隐藏实例方法(编译时报错): public class Sub  extends Sup{
    //类方法不能隐藏实例方法,编译时报错
    static void test(){
        //
    }
}

class Sup{
     void test(){
        //
    }
}
   覆盖和隐藏的区别。对于隐藏的方法,运行时系统调用当前对象引用的编译时类型中定义的方法;对于覆盖的方法,运行时系统调用当前对象引用运行时类型中定义的方法。一个是调用编译时类型中定义的方法,一个是调用运行时类型中定义的方法。通过下面这个例子可以直观的看出两者之间的差别。

class Planet {
    public static void hide() {
        System.out.println("The hide method in Planet.");
    }

    public void override() {
        System.out.println("The override method in Planet.");
    }
}

class Earth extends Planet {
    public static void hide() {
        System.out.println("The hide method in Earth.");
    }

    public void override() {
        System.out.println("The override method in Earth.");
    }

    public static void main(String args[]) {
        Earth earth = new Earth();
        Planet planet = (Planet) earth;
        planet.hide(); // result:"The hide method in Planet."
        planet.override(); // result:"The override method in Earth."
    }
}
   Earth类覆盖了Planet类的override方法,并隐藏了它的hide方法。在main方法中创建了一个Earth的实例,并将此实例转换为一个Planet的引用。然后通过Planet引用调用override方法和hide方法。hide方法是类方法,因此根据引用的类来决定调用哪个方法,所以planet.hide()调用的是Planet的类方法hide。override方法是实例方法,因此调用的是运行时的实例中的方法,因为planet引用的是Earth的实例,因此planet.override()调用的是Earth类中实例方法override。

   JAVA正是通过实例方法的这种覆盖关系来实现多态的目的。

三、类的变量在继承过程中的问题:
  
   如果子类中的变量如果和父类中的变量具有相同的标记——即相同的名字——那么子类中的变量一就会隐藏父类中的变量。不过他们的类型是什么,也不管他们是类变量还是实例变量。只要他们具有相同的名字。

public class Sub extends Sup {
    float i; //子类中的实例变量隐藏父类中的类变量,并且具有不同的类型
    float j; //子类中的类变量隐藏父类中的实例变量,并且具有不同的类型
    int k; //子类中的实例变量隐藏父类中的实例变量
    static int l; //子类中的类变量隐藏父类中的类变量
}

class Sup {
    static int i ;
    int j;
    int k;
    static int l;
}
   同子类中的类方法隐藏父类中的类方法一样,当子类中的变量覆盖父类中的变量的时候,到底使用哪个变量,要根据引用的类型来确定。

   下面是一个类成员继承关系的综合例子:
package basic;

public class Subclass extends Superclass {
    static String staticString = "static String in Subclass";

    String instanceString = "instance String in Subclass";

    static void staticPrintf(float a) {
        System.out.println("static printf method in Subclass");
    }

    void instancePrintf(float a) {
        System.out.println("instance printf method in Subclass");
    }
   

    public static void main(String args[]) {
        Subclass sub = new Subclass();
        Superclass sup = (Superclass) sub;
        System.out.println(sub.staticString); // static String in Subclass
        System.out.println(sub.instanceString); // instance String in Subclass
        System.out.println(sup.staticString); // static String in Superclass
        System.out.println(sup.instanceString); // instance String in Superclass

        sub.staticPrintf(1); // static printf method in Subclass
        sub.instancePrintf(1); // instance printf method in Subclass
        sup.staticPrintf(1); // static printf method in Superclass
        sup.instancePrintf(1); // instance printf method in Subclass
    }
}

class Superclass {
    static String staticString = "static String in Superclass";

    String instanceString = "instance String in Superclass";

    static void staticPrintf(float a) {
        System.out.println("static printf method in Superclass");
    }

    void instancePrintf(float a) {
        System.out.println("instance printf method in Subclass");
    }
   
}

分享到:
评论

相关推荐

    C++成员函数的重载、覆盖与隐藏

    文件详细描述了C++成员函数的重载、覆盖与隐藏技术,对于初学C++的人员很有帮准,也是我们程序猿参考、学习的重要资料。

    SigalHu#MyBlog#类中成员函数的重载、覆盖与隐藏[转]1

    原文:C++类成员函数的 重载、覆盖和隐藏区别重载成员函数被重载的特征:相同的范围(在同一个类中)函数名字相同参数不同virtual 关键字可有可无void s

    Java方法的覆盖与隐藏的区别分析

    本篇文章介绍了,关于Java方法的覆盖与隐藏的区别分析。需要的朋友参考下

    C++ 中函数重载、覆盖与隐藏详解

    C++ 中函数重载、覆盖与隐藏详解 在C++语言中,函数扮演着很重要的角色,不管面向过程设计,还是基于对象设计;不管是面向对象编程,还是基于泛型编程,函数都可以随处而见。在谈论C++中的函数重载、覆盖和隐藏之前...

    类成员函数的重载、覆盖与隐藏之间的区别总结

    以下是对类成员函数的重载、覆盖与隐藏之间的区别进行了详细的总结分析,需要的朋友可以过来参考下。希望对大家有所帮助

    成员函数的重载、覆盖与隐藏详细解析

    1 重载与覆盖成员函数被重载的特征:(1)相同的范围(在同一个类中);(2)函数名字相同;(3)参数不同;(4)virtual 关键字可有可无。覆盖是指派生类函数覆盖基类函数,特征是:(1)不同的范围(分别位于派生...

    类成员函数的重载、覆盖和隐藏

    类成员函数的重载、覆盖和隐藏区别以及抽象类等

    C++中的多态、重载、覆盖与隐藏

    上网看C++的一些资料,突然看到虚函数,突然让我回想起继承,覆盖什么的,决定总结一些资料,加上自己的体会写一篇。  1、C++中的虚函数(virtual function)  虚函数是C++中用于实现多态(polymorphism)的...

    C++中的函数重载、覆盖与隐藏

    在谈论C++中的函数重载、覆盖和隐藏之前,先回顾下函数的基础知识。  函数的声明包括函数的返回值类型,函数名称,参数列表(参数的类型、参数的个数、参数的顺序)。例如,声明一个两个整数之和的函数,int iAdd...

    重载、覆盖和隐藏

    重载、覆盖和隐藏

    C++的重载、隐藏、覆盖规则

    C++的重载、隐藏、覆盖规则 C++的重载、隐藏、覆盖规则 C++的重载、隐藏、覆盖规则

    Java中的方法和变量在继承时的覆盖问题

    变量和方法覆盖和隐藏的不同:一个类的实例无法通过使用全局名或者强制自己转换为父类型,以访问父类中被隐藏的方法,然而强制转换子类为父类型之后,可以访问父类中被隐藏的变量。另外静态方法不能覆盖父类的实例...

    方法和变量在继承时的覆盖和隐藏问题

    最近有个同学问了我一个小问题,觉得很有意思,之前一直没有想到过。他说“java中存在方法覆盖,是否存在变量的覆盖呢?”。

    重载、覆盖、多态与函数隐藏

    要弄清楚重载、覆盖、多态与函数隐藏之间的复杂且微妙关系之前,我们首先 要来回顾一下重载覆盖等基本概念。 首先,我们来看一个非常简单的例子,理解一下什么叫函数隐藏hide。

    高质量C++/C编程指南

    8.2 成员函数的重载、覆盖与隐藏 60 8.3 参数的缺省值 63 8.4 运算符重载 64 8.5 函数内联 65 8.6 一些心得体会 68 第9章 类的构造函数、析构函数与赋值函数 69 9.1 构造函数与析构函数的起源 69 9.2 构造函数的初始...

    高质量C++、C编程指南.doc )

    8.2 成员函数的重载、覆盖与隐藏 60 8.3 参数的缺省值 63 8.4 运算符重载 64 8.5 函数内联 65 8.6 一些心得体会 68 第9章 类的构造函数、析构函数与赋值函数 69 9.1 构造函数与析构函数的起源 69 9.2 构造函数的初始...

Global site tag (gtag.js) - Google Analytics