A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 最初的理想 黑马帝   /  2012-2-5 19:51  /  4481 人查看  /  12 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 最初的理想 于 2012-2-7 19:40 编辑

父类中的静态成员变量,静态方法是否可以被子类继承,如果可以继承的话,是否和普通成员的规则一样呢?我认为静态成员不能被继承,和继承根本扯不上关系。因为静态成员不是对象的特性,只是为了找一个容身之处,所以需要放到一个类中而已。竟然如此也就谈不上继承了。这个问题大家怎么看?

评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

12 个回复

倒序浏览
可以被继承的,但是不可以被重构,做个实验就可以证明,遇到问题 要多想 然后测试一下自己的想法 才能提高自己    嘿嘿。。。。

评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

回复 使用道具 举报
可以继承是肯定的。
子类和父类可以有相同返回类型、方法名、参数列表的静态方法,如果从这个层面讲,子类算是override父类的静态方法吧。
但准确的讲此时只是子类对父类静态方法的隐藏(hide),子类的静态方法完全体现不出多态,就像子类字段隐藏父类的字段一样,在利用引用访问对象的字段或静态方法时,是引用类型(type)决定了事实上访问的是哪个字段,而非当前引用实际代表的是哪个类。因此,子类静态方法不能覆盖父类静态方法。
另外,在jdk1.5之前,覆盖要求子类方法的返回类型与父类的方法严格一致,但jdk1.5后,子类方法的返回类型可以是父类方法返回类型的子类。
结论:其实java class中的private与static就相当于final,都不可被子类重写.重写编译就会报错。


评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

回复 使用道具 举报
本帖最后由 黑马唐浩 于 2012-2-5 21:03 编辑

网上看到一个帖子。我刚看了一遍,有空的话你也看一遍吧。
我能力有限,无法总结。但希望能帮到你。


引自http://hi.baidu.com/codinggirl/blog/item/02151fcd57dc670f93457e7f.html
codinggirl的空间百度空间

   
static块的加载机制:类的static块会在类被加载时执行一次且仅一次,java的类加载机制是在jvm启动的时候java的核心类(rt.jar中全部类)会被全部载入,而用户定义的类仅在被使用的时候才被加载。

接下来将通过几个实例来说明static在继承中的使用机制

实例一、

class Parent{
public static String staticVar = "parent";
}

class ChildOne extends Parent{
static{
   staticVar = "childOne";
}
}

class ChildTwo extends Parent{
static{
   staticVar = "childTwo";
}
}


public class StaticBlock {
public static void main(String[] args){
   System.out.println(ChildOne.staticVar);
   System.out.println(ChildTwo.staticVar);
}
}

输出:

parent
parent

我原本想当然的以为ChildOne 和ChildTwo继承自Parent,那也就分别继承了staticVar,因而它们分维护一个静态变量staticVar。那当调用ChildOne.staticVar时,加载ChildOne,staticVar就会被赋值为"ChildOne"。但现在的输出时"parent"而非"childOne",我不能理解这是为什么,是因为ChildOne只能拥有一份Parent的staticVar的拷贝,还不能改变它的值,所以ChildOne加载时的static块无效? 太奇怪了,于是我继续往类里添加代码。

实例二、我在parent里添加了一个输出静态变量的方法

class Parent{
public static String staticVar = "parent";

public static void PrintStaticVar(){
   System.out.println(staticVar);
}
}

class ChildOne extends Parent{
static{
   staticVar = "childOne";
}

}

class ChildTwo extends Parent{
static{
   staticVar = "childTwo";
}
}
public class StaticBlock {
public static void main(String[] args){
   System.out.println(ChildOne.staticVar);
   System.out.println(ChildTwo.staticVar);
  
   ChildOne.PrintStaticVar();
   ChildTwo.PrintStaticVar();
}
}

输出:

parent
parent
parent
parent

实例三、

class Parent{
public static String staticVar = "parent";

public static void PrintStaticVar(){
   System.out.println(staticVar);
}
}

class ChildOne extends Parent{
static{
   staticVar = "childOne";
}

public static void PrintStaticVar(){
   System.out.println(staticVar);
}
}

class ChildTwo extends Parent{
static{
   staticVar = "childTwo";
}
}


public class StaticBlock {
public static void main(String[] args){
   System.out.println(ChildOne.staticVar);
   System.out.println(ChildTwo.staticVar);
  
   ChildOne.PrintStaticVar();
   ChildTwo.PrintStaticVar();
}
}

输出:

parent
parent
childOne
childOne

在ChildOne里的 PrintStaticVar 方法没有override标志,(思考:难道静态方法不能继承)。

我依旧认为ChildOne和ChildTwo是分别维护一个staticVar的,当看到ChildTwo.staticVar的值也变为"childOne"时,我就更奇怪了。难道staticVar是共享的?我往ChildTwo里也添加了PrintStaticVar方法,结果证明staticVar是共享的。这样就得重新看实例一,不过,不管staticVar是共享的,还是被父类子类单独维护的,当调用ChildOne.staticVar时,加载ChildOne,staticVar就会被赋值为"ChildOne",这句话都应该会成立,因此依旧不能解释,实例一的结果。发现一个问题,既然staticVar 不是ChildOne维护的,它只是共享了Parent的staticVar。那当调用ChildOne.staticVar时,ChildOne真的被加载了吗?

实例四、

class Parent{
public static String staticVar = "parent";
static{
   System.out.println("Parent 被加载了");
}
public static void PrintStaticVar(){
   System.out.println(staticVar);
}
}

class ChildOne extends Parent{
static{
   System.out.println("ChildOne 被加载了");
   staticVar = "childOne";
}

}

class ChildTwo extends Parent{
static{
   staticVar = "childTwo";
   System.out.println("ChildTwo 被加载了");
}

}
public class StaticBlock {
public static void main(String[] args){
   System.out.println(ChildOne.staticVar);
   System.out.println(ChildTwo.staticVar);
  
   ChildOne.PrintStaticVar();
   ChildTwo.PrintStaticVar();
  
   }
}

输出:

Parent 被加载了
parent
parent
parent
parent

也就是只有Parent类被加载了,尽管执行了ChildOne.staticVar和ChildOne.PrintStaticVar();
,但是因为staticVar是属于Parent的,PrintStaticVar();也是属于Parent的,ChildOne并没有被加载。当然ChildOne里的static块没有执行,staticVar的值也就不会改变了,输出就全成了parent。

实例五、最后的实验

class Parent{
public static String staticVar = "parent";
static{
   System.out.println("Parent 被加载了");
}
public static void PrintStaticVar(){
   System.out.println(staticVar);
}
}

class ChildOne extends Parent{
static{
   System.out.println("ChildOne 被加载了");
   staticVar = "childOne";
}

public static void PrintStaticVar(){
   System.out.println(staticVar);
}
}

class ChildTwo extends Parent{
static{
   staticVar = "childTwo";
   System.out.println("ChildTwo 被加载了");
}

public static void PrintStaticVar(){
   System.out.println(staticVar);
}
}
public class StaticBlock {
public static void main(String[] args){
   System.out.println(ChildOne.staticVar);
   System.out.println(ChildTwo.staticVar);
  
   ChildOne.PrintStaticVar();
   ChildTwo.PrintStaticVar();
  
   System.out.println(ChildOne.staticVar);
   System.out.println(ChildTwo.staticVar);
}
}

输出:

Parent 被加载了
parent
parent
ChildOne 被加载了
childOne
ChildTwo 被加载了
childTwo
childTwo
childTwo

ChildOne被加载了,而且staticVar的值也改变了。为什么呢?因为ChildOne里有了自己的PrintStaticVar方法(不是重载)。所以当调用ChildOne.PrintStaticVar();时就需要载入ChildOne类,这样,ChildOne类里的static块也就在它被载入时,一次且仅一次的执行了。

因此,实例一到实例四的结果都可以解释为:ChildOne和ChildTwo一直在使用父类的静态变量和静态方法,都没有被加载。

到现在,我完全明白了java中static在继承中的运行机制了。

结论:

       1.父类的static变量和static方法是属于父类的,而且被继承机制里的所有类共享(子类和自身)。当子类调用父类的static方法和使用父类的static变量时,如ChildOne.staticVar和ChildOne.PrintStaticVar();,不能想当然的认为使用到了ChildOne,所以ChildOne要被加载进来。要看变量和方法实际属于哪个类,因为staticVar和PrintStaticVar();都是属于父类的,所以有且仅有父类Parent被加载进来。

        2.子类不继承父类的静态变量和静态方法,因此在子类中有一个父类一样的静态方法时,不会被标记为override,它的功能是隐藏了父类的静态方法。如实例五中所示,这时,ChildOne.PrintStaticVar();调用的就是自己的方法,所以ChildOne被加载了。因此,结论是,父类的静态方法和静态变量是属于父类的,子类只能隐藏,不能覆盖。(这里的实例都是针对方法,其实对静态方法和静态实例,都是符合这一结论的)

评分

参与人数 1技术分 +3 收起 理由
admin + 3 虽然没看完,但必须表扬,3分

查看全部评分

回复 使用道具 举报
黑马唐浩 发表于 2012-2-5 20:57
网上看到一个帖子。我刚看了一遍,有空的话你也看一遍吧。
我能力有限,无法总结。但希望能帮到你。

{:3_47:}很详细
回复 使用道具 举报
本帖最后由 陈腾跃 于 2012-2-5 21:47 编辑

写了个简单的代码:
  1. class Fu
  2. {
  3.         public static int num = 100;
  4.        
  5.         public static void app()
  6.         {
  7.                 System.out.println("fu de app function!");
  8.         }
  9. }

  10. class Zi extends Fu
  11. {
  12.         //static int num = 200;
  13.        
  14.         public void add()
  15.         {
  16.                 System.out.println("zi de add function!");
  17.                
  18.                 //输出父类的num成员变量
  19.                 System.out.println(num);
  20.         }
  21.        
  22.         //复写父类app方法
  23.         /*
  24.         public void app()
  25.         {
  26.                 System.out.println("zi de app function!");
  27.         }
  28.         */
  29. }

  30. class StaticClassFunctionJiCheng
  31. {
  32.         public static void main(String[] args)
  33.         {
  34.                 Zi test = new Zi();
  35.                
  36.                 test.add();
  37.                 test.app();
  38.         }
  39. }
复制代码
输出结果:
fu de app function!
zi de add function!
100

试图复写父类的app方法结果:
StaticClassFunctionJiCheng.java:17: Zi 中的 app() 无法覆盖 Fu 中的 app();被覆盖的方法为 static
        public void app()
                    ^
1 错误

试图在Zi类重新定义变量num结果:
fu de app function!
zi de add function!
200



有什么不对的地方望各位朋友果断拍砖^_^

评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

回复 使用道具 举报
1.不管是动态的还是静态的继承extends就是把父类所有的代码搬到子类,静态的方法和成员变量都能被继承,
2.如果直接在一个类中定义2个同名的方法或者同名同型的成员编译不让通过,如果是子类继承父类时子类有方法或者成员与子类同名同型了,这样的情况下即使没有@Override字样也会调用子类的,子类有的调用子类的,子类没有的就去找父类的
3.当一个子类中的成员变量或者方法被调用就会去加载这个类,当调用了这个子类所属的父类的成员时就会去加载他的父类,而不会去加载子类,当一个类被首次加载的时候,就会调用这个类的static{}方法一次
这是我个人感觉的,可以按照我的这个思路去想想,应该没有错

评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

回复 使用道具 举报
凡是继承来的都是父类的,但是除了继承之外还可以定义自己的方法。父类中被final修饰的方法不能被继承

评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

回复 使用道具 举报
易伟 黑马帝 2012-2-5 23:21:37
9#
彭沛东 发表于 2012-2-5 22:40
凡是继承来的都是父类的,但是除了继承之外还可以定义自己的方法。父类中被final修饰的方法不能被继承 ...

哥们  父类中被final修饰的方法是可以被继承的,只是不能被子类覆盖而已。子类继承父类不一定就要重写父类的方法,但是子类的对象一样可以调用父类中被final修饰的方法,只调用不重写是可以的。

评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

回复 使用道具 举报
秦碧 黑马帝 2012-2-5 23:48:53
10#
父类中的静态成员 无论成员变量还是成员方法都可以被子类继承;
我认为静态成员不能被继承,和继承根本扯不上关系。因为静态成员不是对象的特性,只是为了找一个容身之处,所以需要放到一个类中而已。竟然如此也就谈不上继承了。
关于这一点 我这么想的 比如动物这个类 有一个属性:是活的 那么有一个静态的boolean型变量b为true,而子类继承他时,比如一直猫 也是活的 就继承动物这一属性 也就是说猫的b=true;
另外对静态的覆盖有个小发现:
成员方法: 静态覆盖静态,静态覆盖非静态是可以的  静态覆盖非静态 ,非静态覆盖静态 是非法的
成员变量: 静态覆盖静态,静态覆盖非静态是合法的  静态覆盖非静态 ,非静态覆盖静态 也是合法的。

评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

回复 使用道具 举报
其实静态方法都是在方法区里面放置的,
普通方法呢,用this和super来动态绑定调用,
而静态方法是静态绑定的,
所以一般是根据类名来查找调用,

  1. class Fu
  2. {
  3.         public static void test(){
  4.                 System.out.println("fu-----test");
  5.         }
  6. }

  7. class Zi extends Fu
  8. {
  9. }

  10. class testing2
  11. {
  12.           public static void main(String []args){

  13.                 Zi z = new Zi();
  14.                 z.test();
  15.           }
  16. }
复制代码
输出答案是 父类的test

要是按照这样的理论,估计就算是静态也是持有了父类引用
但是估计是静态绑定了此引用。
如果子类复写了静态方法
根据申请空间的类变量所指的类来查找并调用方法

评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

回复 使用道具 举报
子类复写了静态方法
根据申请空间的类变量所指的类来查找并调用方法
回复 使用道具 举报
在一个类中还可以定义静态成员,但静态成员是所有对象公有的。静态成员分为静态数据成员和静态成员函数。

   1.静态数据成员

   在类中定义静态数据成员的方法就是在该成员的前面加上关键字static.

   定义静态数据成员的语句格式如下:

   class 类名

   {

   ……

   static 类型说明符 成员名;

   ……

   };

   静态数据成员是类的所有对象共享的成员。静态数据成员所占的空间不会随着对象的产生而分配,也不会随着对象的消失而回收。对静态数据成员的操作和类中一般数据成员的操作是不一样的,定义为私有的静态数据成员不能被外界所访问。静态数据成员可由任意访问权限许可的函数所访问。

   由于静态数据成员是类的所有对象共享的,而不从属于任何一个具体对象,所以必须对类的静态数据成员进行初始化,但对它的初始化不能在类的构造函数中进行,其初始化语句应当写在程序的全局区域中,并且必须指明其数据类型与所属的类名,其初始化格式如下:

   类型 类名::变量名=值;

   对于在类的public部分说明的静态数据成员,在类的外部可以不使用成员函数而直接访问,但在使用时必须用类名指明所属的类,其访问格式为:

   类名::静态数据成员名

   对于在类的非public部分说明的静态数据成员,则只能由类的成员函数访问,其访问方法与访问类中普通数据成员的访问方法完全一样,但在类的外部不能访问。

   2.静态成员函数

   静态成员函数的定义与一般成员函数的定义相同,只是在其前面冠以static关键字,其定义格式如下:

   class 类名

   {

   …

   static 类型 函数名(形参)

   {   函数体   }

   …

   };

   说明:

   (1)类的静态成员函数只能访问类的静态数据成员,而不能访问类中的普通函数成员(非静态数据成员),因为普通数据成员只有类的对象存在时才有意义。

   (2)静态成员函数与类相联系,而不与类的对象相联系,所以,在类的外部调用类中的公有静态成员函数,必须在其左面加上“类名::”,而不是通过对象名调用公有静态成员函数。在类的外部不能调用类中的私有静态成员函数。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马