前不久写一个东东,因设计不当,用到了这块内容,也上网搜索了很多资料,感觉还是不够清晰。望高手、专家踊跃参与讨论。看谁能让大家信服。
题:静态属性和方法能否被继承?是如何继承的?class base{
    protected static String p="123";
    public static String getP(){return p;}
    public static void setP(String a){p=a;}
    public static String test(){return p+"test";}
}
class sub extends base{
    private static String p="abc";
    //public static String getP(){return p;}
}class test{
    public static void main(String[] a){
        //base.setP("123");
        //sub.setP("abc");
        System.out.println(base.getP());
        System.out.println(sub.getP());
    }
}请就题而论,给一个清晰的解释,谢谢!

解决方案 »

  1.   

    打印只能是123 123 
    父类赋值后子类只能继承不能重新赋值class sub extends base{
      private static String p="abc";
          public static String getP(){return p;}
    }你要是改成这样  可以打印出123 abc 但是相当于子类重新定义了一个字段方法而已  并非全部继承而来的
      

  2.   


    class base{
        protected static String p="123";
        public static String getP(){return p;}
        public static void setP(String a){p=a;}
    }
    class sub1 extends base{//将继承base类所有可继承的属性和方法,类毫无意义}
    class sub2 extends base{
        private static String p="abc";
        //public static String getP(){return p;}
        //定义自己的p属性,这个属性和父类base的p属性毫无关系。
        /**
          * 继承了所有base类的可继承的不包含p的属性和方法。问题在这里:
          * 1.首先可以肯定有getP和setP方法,但这两个方法操作的P却不知道是base的还是sub2的。
          * 2.如果定义了自己的getP和serP方法,将隐藏base的get和set方法。那么sub2和base都有自己的set和get方法。
          * 3.在外面调用时,用 "类名.可访问方法或属性" 来访问(调用)属性(方法)。类似第一点,如果静态属性是外面无法访问的,而提供一个外面可访问的方法去操作属性,那么继承并没有起到预想的效果。
          * 
          * 综合前面,是否可以这样说,静态属性和方法能继承,但应该称之为"伪继承"。这种继承没有意义??
          */
    }class test{
        public static void main(String[] a){
            //base.setP("123");
            //sub.setP("abc");
            System.out.println(base.getP());
            System.out.println(sub.getP());
        }
    }
      

  3.   

    我没有运行你这个代码,只是用眼看了一下,提醒你Java命名规范类名首字母大写还是我那句话,static的方法一般都是工具类方法,调用的时候都是用 类名.方法名调用,而且一般都不好在static的属性和方法上进行继承,至于你说的“伪继承”是个人理解吧,知道怎么调用,怎么是正确的方法就OK了,没必要钻一些平时根本不太用得着的灰色语法范畴
      

  4.   

    谢谢楼上的哥,关于命名规范平时都还是很遵守的 :),这个是用来测试就随便写写了。其实也不是去钻那些灰色语法,只是恰巧遇到了。还是你说的对,static的方法一般是工具类,一般不继承。而这个问题其实也就是想弄明白自己对静态属性和方法的继承是否理解有误,如果弄不明白那只能在今后不这么做,但却又担心哪天会遇到。有点矛盾又有点尴尬……呵呵
      

  5.   

    这里关键是p这个变量,指的是this.p,所以父类的使用的p,就是父类的p,子类中使用的p就是子类中定义的p,如果子类想使用父类的变量,应该可以用super.p来获取。方法也是一样。
    调用子类的方法时,如果子类自己定义了,就是用自己的,如果没定义,就使用父类的。而方法中使用的变量如果在方法对应的类中定义了,就使用本类的变量,如果没定义,就是用父类的变量。
      

  6.   

    还是以贴的代码为例子。在sub2中没定义get和set方法,那么在test类中,调用sub2.getP()的时候就应该是调用了base.getP(),而base.getP()就应该得到base的p属性。现在反过来思考,如果我想通过sub2.getP()获取到sub2的p属性,那么就需要在sub2中定义getP方法,那继承岂不是没用,对于静态属性和方法,继承岂不是没意义?
      

  7.   

    System.out.println(base.getP());-----很明显执行的是base中的getP(),得到base中的p(“123”)
    System.out.println(sub.getP());-------sub中没有getP()方法,将会调用base中的getP(),得到base中的p(“123”)
    所以打印出来都是123
    但是,如果public static String getP(){return p;}不注释掉,System.out.println(sub.getP());将会调用sub中的getP()
      

  8.   

    这个涉及到方法和属性的寻址。也涉及到对象和类的空间分配。
    关于寻址(或者说绑定):
    从某代码发起的一次访问请求(代码所在的源和代码访问的目标有可能是同一个类或对象,也有可能不是):
    ①子类中找不到的方法和属性,到父类找,不管是静态还是动态。
    ②不写前缀(或写this)时从本对象所属的子类(可能比本类层次低)开始找方法。如果用类名(静态方法情况下)或用super指定了目标类,则从该目标类开始找方法。
    ③不写前缀(或写this)时从本代码所属的类开始找属性,如果用类名(静态方法情况下)或用super指定了目标类,则从该目标类开始找属性。关于空间分配:
    ①每个类的static属性及所有的方法放类自己的空间中。
    ②每个类的非static属性放对象中。
    ③子类对象包含父类对象,也就是说,子类对象创建的时候,会为所有的父类属性分配空间。父类代码发起的对父类非静态属性的访问,最终访问的是子类对象空间中的父类属性。好,开始分析楼主顶楼的代码:
    base.getP();直接找到父类的getP()方法,getP()方法中return p返回父类中的p属性值,123
    接着执行
    sub.getP();子类没有该方法,往上找,依然找到父类的getP()方法,getP()方法依然return p返回父类中的p属性值,123问题复杂,有不明白的地方,继续讨论。
      

  9.   

    base 给你提供了一个共享的数据 也提供了 访问和修改的方法 
    当然static的方法 它操作它方法体中指定的static的那个数据继承了base 子类就继承了 访问和修改base共享数据的能力 
    当你屏蔽掉了访问和修改的能力  继承来的增强功能都被屏蔽了 
    显然没有继承来任何东西,继承也就显得多余了
      

  10.   

    回到楼主的问题上来
    Sun把方法的继承称为重写或覆盖(Override),与之对应的是重载(Overload),相信这两个概念一般人都很熟悉了。
    重载很简单,通过方法的“签名”来实现,是编译器静态行为,没什么多说的。
    那么重写呢?重写发生在继承的过程中。重写方法的调用是在运行期间动态进行的,这种方式称为动态绑定。在Java中,重写方法的这种动态性很彻底,你无法在使用子类时调用被重写的父类方法(除非由子类自己显式调用),Java强制将调用绑定到子类上。
    而实例域则没有重写(或继承)的概念。它们的访问控制符(public、protected、package或private)仅仅决定该实例域的可见性,而与继承无关。这与局部变量隐藏实例变量的概念是类似的,不属于继承的范畴。
    下面的例子中SubBook继承Book,它们都定义了一个同名的int型变量
    Book b1 = new Book();
    Book b2 = new SubBook();
    SubBook b3 = (SubBook) b2;
    SubBook b4 = new SubBook();
    打印b1~b4的变量的值,发现b1和b2访问的是父类中的变量、b3和b4访问的是子类中的变量。也就是说,实例域的访问与实际类型无关,而只取决于此实例当前被赋予的类型,可以认为这也是一种编译器静态行为。静态属性和静态方法与实例域是非常相似的,没有继承的概念,都是编译器的静态行为。
      

  11.   

     我没有运行 自己认为输出的应该是"123" 和"123"
      就代码而言  有疑问的地方估计在sub.getP() 这里.
       因为子类没有重写getP()方法 .So 调用的还是父类的getP() 输出的自然也是"123"了
          父类里虽然定义了p变量 是private 修饰的 这样和父类的p变量也没有构成属性重写
        因为子类重写必须要比父类权限要大  即使修饰符改成public 了 也输出的"123"
      因为在sub.getP()里实现的是super.p 要是重写了getP()结果就不一样的 .  
           ..... 我说错了 希望指出来 .谢谢 !