锁定老帖子 主题:对java方法的访问控制的深思考
精华帖 (0) :: 良好帖 (0) :: 新手帖 (11) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-05-31
最后修改:2009-05-31
但是我碰到下面的问题: 1.创建一个包含内部类的类: package javabug; public class Father { protected Father() { FatherInner inner = new FatherInner(); inner.sayOuterClass(); } protected void say() { System.out.println("I'm Father"); } private class FatherInner { void sayOuterClass() { Father.this.say(); } } } 2.创建一个子类继承父类: package javabug.other; import javabug.Father; public class Son extends Father { public Son() { super(); } protected void say() { System.out.println("I'm Son"); } } 3. 创建子类和父类的对象,看控制台输出: public class Test { /** * @param args */ public static void main(String[] args) { Father father = new Father(); Son demo = new Son(); } } output: I'm Father I'm Son 思考:从最后的输出查看,我的理解是输出内容是FatherInner 的sayOuterClass方法在构造函数中执行产生的效果. 对于Son类的属于protected的say方法是不能被FatherInner的对象调用到的.因为Son和Father属于不同的package. 事实上它竟然执行了. 回顾: java的访问控制室编译时检查的,不是运行时检查的. 问题: 这算不算一个java的bug呢? 大家来说说. 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-05-31
难道书上没交modifiers可以被向下继承而不让向上继承?
例如,如果有Father类是这样的: class Father{ protected void helloWorld(){ ... } } 那么子类Son的helloWorld方法的访问权限只能是大于protected而不能小于它。因此: class Son extends Father{ @Override public void helloWorld(){ // 正确 } /* private void helloWorld(){ // 错误 } */ } 对于构造方法的执行流程,建议你多看看Java基础,推荐一本书《Tinking In Java》。 |
|
返回顶楼 | |
发表时间:2009-06-01
yuyoo4j 写道 如果我对java方法访问控制应该是这样的:
但是我碰到下面的问题: 1.创建一个包含内部类的类: package javabug; public class Father { protected Father() { FatherInner inner = new FatherInner(); inner.sayOuterClass(); } protected void say() { System.out.println("I'm Father"); } private class FatherInner { void sayOuterClass() { Father.this.say(); } } } 2.创建一个子类继承父类: package javabug.other; import javabug.Father; public class Son extends Father { public Son() { super(); } protected void say() { System.out.println("I'm Son"); } } 3. 创建子类和父类的对象,看控制台输出: public class Test { /** * @param args */ public static void main(String[] args) { Father father = new Father(); Son demo = new Son(); } } output: I'm Father I'm Son 思考:从最后的输出查看,我的理解是输出内容是FatherInner 的sayOuterClass方法在构造函数中执行产生的效果. 对于Son类的属于protected的say方法是不能被FatherInner的对象调用到的.因为Son和Father属于不同的package. 事实上它竟然执行了. 回顾: java的访问控制室编译时检查的,不是运行时检查的. 问题: 这算不算一个java的bug呢? 大家来说说. 我感觉楼主对于继承关系及构造方法的理解似乎有些问题。 “对于Son类的属于protected的say方法是不能被FatherInner的对象调用到的.因为Son和Father属于不同的package. ” 这句话似乎说明,楼主把继承关系理解为对象间的访问规则。 我认为Son类对象化的过程,是完全按照其自身的继承关系进行初始化的,初始化及对象内调用规则都是按继承关系处理的,与package无关。 楼主的疑惑,或许用下面的例子说明,更直观一些,没有必要还要抬出个内部类来探讨访问控制。 package javabug; public class Father { protected Father() { // FatherInner inner = new FatherInner(); // inner.sayOuterClass(); Father.this.privateSay(); } private void privateSay() { Father.this.say(); } protected void say() { System.out.println("I'm Father"); } // private class FatherInner { // // void sayOuterClass() { // Father.this.say(); // } // } } 你现在用 Son demo = new Son(); 试试,照样打出的是 I'm Son。 这个应该与你用内部类是一个道理,在子类初始化过程中,当调用Father的构造方法进行初始化时,say方法已经被子类所重置,按照继承与多态规则,调用的应是子类的方法。但如果Father的say方法是private的,那么子类将无法继承,当然也无法重置,所以在子类对象的初始化过程中,当调用父类构造方法时,也就调不到子类中新定义的say了。 |
|
返回顶楼 | |
发表时间:2009-06-01
yipsilon 写道 难道书上没交modifiers可以被向下继承而不让向上继承?
例如,如果有Father类是这样的: class Father{ protected void helloWorld(){ ... } } 那么子类Son的helloWorld方法的访问权限只能是大于protected而不能小于它。因此: class Son extends Father{ @Override public void helloWorld(){ // 正确 } /* private void helloWorld(){ // 错误 } */ } 对于构造方法的执行流程,建议你多看看Java基础,推荐一本书《Tinking In Java》。 可能你没理解我的困惑: 1.FatherInner和Son不存在继承关系. 2.FatherInner和Son不存在与相同包中. FatherInner实例的怎么可以调用Son实例的方法呢,我的困惑是这种关系下,modifiers的约束感觉不存在了. |
|
返回顶楼 | |
发表时间:2009-06-01
[quote="netfork"]
[quote="yuyoo4j"]如果我对java方法访问控制应该是这样的: [img]/upload/attachment/109618/54e5f752-a5b1-39bb-bfac-b179b30cfbab.jpg" alt="[/img] 但是我碰到下面的问题: 1.创建一个包含内部类的类: [code="java"]package javabug; public class Father { protected Father() { FatherInner inner = new FatherInner(); inner.sayOuterClass(); } protected void say() { System.out.println("I'm Father"); } private class FatherInner { void sayOuterClass() { Father.this.say(); } } } 2.创建一个子类继承父类: [code="java"]package javabug.other; import javabug.Father; public class Son extends Father { public Son() { super(); } protected void say() { System.out.println("I'm Son"); } } 3. 创建子类和父类的对象,看控制台输出: [code="java"]public class Test { /** * @param args */ public static void main(String[] args) { Father father = new Father(); Son demo = new Son(); } } output: [code="java"]I'm Father I'm Son 思考:从最后的输出查看,我的理解是输出内容是FatherInner 的sayOuterClass方法在构造函数中执行产生的效果. 对于Son类的属于protected的say方法是不能被FatherInner的对象调用到的.因为Son和Father属于不同的package. 事实上它竟然执行了. 回顾: java的访问控制室编译时检查的,不是运行时检查的. 问题: 这算不算一个java的bug呢? 大家来说说. 我感觉楼主对于继承关系及构造方法的理解似乎有些问题。 “对于Son类的属于protected的say方法是不能被FatherInner的对象调用到的.因为Son和Father属于不同的package. ” 这句话似乎说明,楼主把继承关系理解为对象间的访问规则。 我认为Son类对象化的过程,是完全按照其自身的继承关系进行初始化的,初始化及对象内调用规则都是按继承关系处理的,与package无关。 楼主的疑惑,或许用下面的例子说明,更直观一些,没有必要还要抬出个内部类来探讨访问控制。 [code="java"]package javabug; public class Father { protected Father() { // FatherInner inner = new FatherInner(); // inner.sayOuterClass(); Father.this.privateSay(); } private void privateSay() { Father.this.say(); } protected void say() { System.out.println("I'm Father"); } // private class FatherInner { // // void sayOuterClass() { // Father.this.say(); // } // } } 你现在用 Son demo = new Son(); 试试,照样打出的是 I'm Son。 这个应该与你用内部类是一个道理,在子类初始化过程中,当调用Father的构造方法进行初始化时,say方法已经被子类所重置,按照继承与多态规则,调用的应是子类的方法。但如果Father的say方法是private的,那么子类将无法继承,当然也无法重置,所以在子类对象的初始化过程中,当调用父类构造方法时,也就调不到子类中新定义的say了。 我把的例子变通一下: // father: package javabug; public class Father { protected Father() { } protected void say() { System.out.println("I'm Father"); } public class FatherInner { public void sayOuterClass() { Father.this.say(); } } } // son: package javabug.other; import javabug.Father; public class Son extends Father { public Son() { super(); } protected void say() { System.out.println("I'm Son"); } } // Test: package javabug; import javabug.Father.FatherInner; import javabug.other.Son; public class Test { /** * @param args */ public static void main(String[] args) { Father father = new Father(); FatherInner inner1 = father.new FatherInner(); inner1.sayOuterClass(); Son demo = new Son(); FatherInner inner2 = demo.new FatherInner(); inner2.sayOuterClass(); } } 上面的结果输出还是: I'm Father I'm Son 如果将say方法的modified改为private就输出 I'm Father I'm Father 所以我的理解应该是我对 内部类保持外部类this引用的理解可能有错误的地方. 我原来的理解modified应该会规避这种情况的出现,或者在modified要做补充说明了. |
|
返回顶楼 | |
发表时间:2009-06-01
楼主需要理解多态和继承中对象创建过程(重点是构造器调用)两个问题
|
|
返回顶楼 | |
发表时间:2009-06-01
按照搂住的定义:
1. Son 也是一种 Father 2. Father.this 表示当前对象, 当前 new Son() 就是 Son |
|
返回顶楼 | |
发表时间:2009-06-01
yuyoo4j 写道 我把的例子变通一下: // father: package javabug; public class Father { protected Father() { } protected void say() { System.out.println("I'm Father"); } public class FatherInner { public void sayOuterClass() { Father.this.say(); } } } // son: package javabug.other; import javabug.Father; public class Son extends Father { public Son() { super(); } protected void say() { System.out.println("I'm Son"); } } // Test: package javabug; import javabug.Father.FatherInner; import javabug.other.Son; public class Test { /** * @param args */ public static void main(String[] args) { Father father = new Father(); FatherInner inner1 = father.new FatherInner(); inner1.sayOuterClass(); Son demo = new Son(); FatherInner inner2 = demo.new FatherInner(); inner2.sayOuterClass(); } } 上面的结果输出还是: I'm Father I'm Son 如果将say方法的modified改为private就输出 I'm Father I'm Father 所以我的理解应该是我对 内部类保持外部类this引用的理解可能有错误的地方. 我原来的理解modified应该会规避这种情况的出现,或者在modified要做补充说明了. 再次看了一下,我还是觉得这个问题跟内部类似乎没什么关系,还是多态的理解问题。 原来的程序中,内部类持有的是Father的this指针,当调用say方法时,如果this的本原是Son,那么调用的要么是say的重置方法,要么就是Father的私有say方法。 我觉得可能是内部类把你的视线混淆了。 还是用例子说话,把内部类干掉,再看看,理解一下? package javabug; public class Father { protected Father() { Father.this.privateSay(); } private void privateSay() { Father.this.say(); } protected void say() { System.out.println("I'm Father"); } } package xjavabug.other; import javabug.Father; public class Son extends Father { public Son() { super(); } protected void say() { System.out.println("I'm Son"); } } package javabug; import xjavabug.other.Son; public class Test { public static void main(String[] args) { Son demo = new Son(); } } 输出结果: I'm Son |
|
返回顶楼 | |
发表时间:2009-06-01
感觉楼主对于继承关系及构造方法的理解似乎有些问题。 |
|
返回顶楼 | |
发表时间:2009-06-01
内部类是编译器现象
它不是直接调用say方法 |
|
返回顶楼 | |