`
yuyoo4j
  • 浏览: 7038 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

对java方法的访问控制的深思考

阅读更多
如果我对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呢? 大家来说说.
  • 大小: 7 KB
分享到:
评论
23 楼 vix01 2009-06-15  
<p>如果你说的这个是bug,哪么下面这段代码也许更是明显的bug??? (当然不是bug...只是需要细心思考一下...</p>
<pre name="code" class="java">public class AccessControl {
public static void main(String[] args) {
Foo aFoo = new Foo();
StringBuffer sb = aFoo.getSb();
sb.append(800);
System.out.println(sb);
System.out.println(aFoo.getSb());
}
}

class Foo {
private StringBuffer sb = new StringBuffer("123");
public StringBuffer getSb() {
return sb;
}
}</pre>
<p> </p>
22 楼 MyDicta 2009-06-06  
楼主,  我这样发表一下自己的看法吧。。。。。。。。。
  
     在父类中的protected方法,只要你在子类中Override了, 就可以理解为父类中的此方法已被子类覆盖了,在子类中就看不到父类此方法了;只要是子类对方法的引用总是会输出重写后的方法;当然你也可以用Super输出父类中的方法原型。。

    还有就是Protected方法是只要是子类就可以调用,与包名相不相同无关,那个访问修饰表中 在“Protected”行 “其它Package” 列 中应该表明一下(除继承类重写) 
21 楼 mxswl 2009-06-05  
不知道楼主想说啥?
经典的模板设计模式能解决楼主的疑问否?
20 楼 dch1287 2009-06-04  
dch1287 写道
This is private as far as the class user is concerned, but available to anyone who inherits from this class or anyone else in the same package.
19 楼 dch1287 2009-06-04  
dch1287 写道
This is private as far as the class user is concerned, but available to anyone who inherits from this class or anyone else in the same package.

18 楼 dch1287 2009-06-04  
This is private as far as the class user is concerned, but available to anyone who inherits from this class or anyone else in the same package.
17 楼 dch1287 2009-06-04  
楼主为什么认为protected不能被不同package的子类访问呢?

protected的类、类属变量及方法可以被包内的任何类,及包外的那些继承了此类的子类访问

如果把Father和Son中的protected void say()改成void say()再试试结果是
引用
I'm Father
I'm Father
16 楼 jingwuyuan 2009-06-03  
在父类的say()方法里面打印下this你就知道怎么回事了,其实是多态。
15 楼 蓝月鸟 2009-06-03  
friendly?从C++转过来的?


公开的
私有的
一个家族的
一个社区的

流氓一点的
什么作用域不作用域的
一反射
全是浮云
14 楼 keyboard2000 2009-06-03  
简单的问题搞得那么复杂.你的内部类在问题没出现到,干嘛写上去...
就是protected的继承问题
不同包直接访问是不行,但是可以重写super.say()后再升级protected为public就可以直接访问.
13 楼 keyboard2000 2009-06-03  
protected可以在不同包被继承,现在重写的say方法,当然可以执行啦
12 楼 mydolors 2009-06-02  
思考:从最后的输出查看,我的理解是输出内容是FatherInner 的sayOuterClass方法在构造函数中执行产生的效果.
对于Son类的属于protected的say方法是不能被FatherInner的对象调用到的.因为Son和Father属于不同的package.
事实上它竟然执行了.


楼主对于访问控制还有些欠缺。
事实上楼主总结的很全, protected类型可以被同包的类访问,以及任何包的子孙类访问。

11 楼 fjlyxx 2009-06-02  
netfork 写道

“对于Son类的属于protected的say方法是不能被FatherInner的对象调用到的.因为Son和Father属于不同的package. ”
这句话似乎说明,楼主把继承关系理解为对象间的访问规则。


父类如果有say的抽象方法是可以的.楼主的这种继承毫无意义.
类的继承使用羡慕的层次结构的,本人不推荐用方法重载的方式,对于这种情况我情愿剥离一个不能再分割的父类 用抽象方法进行定义需要重载的方法.

几点要注意
1.如果是构造函数是private的 建议类定义为final .
2.如果父类需要调用子类的某些方法的时候可以考虑运用抽象方法.
3.要考虑父类和子类的方法是否冲突.(这里的冲突是指是否存在两个同样的方法能够改变共享数据)
4.防止死循环,这种情况发送在
父类 A
public void testA(){
///
}
子类 B
public void testA(){
    this.testA();//正确的应该是super.testA();
}
像楼主对super和this不清楚的就会发生这种情况了.

10 楼 RednaxelaFX 2009-06-02  
seraphim871211 写道
删除此回复

嗯嘛。Java的protected经常被讨论就是因为它跟C++和C#等的protected语义不同,在同package内也可见……

不过楼主在理解Java的方法与多态的时候可能不够仔细?Java中的方法,只要不是static、private或final的,都可以表现出其多态性。继承类的时候,如果覆盖虚方法,则可见性要大于等于基类上的方法的;这样就保证了基类所定下的“契约”要被派生类所实现。在FatherInner里对Father.this.say()的调用是一个对虚方法的调用,只要在这个调用点上FatherInner能看到Father,就可以调用其say()方法,但因为是虚方法调用,实际调用的版本并不一定是Father上的实现,而会根据“this”的实际类型选择最具体的类的实现版本。从Son的角度看,这一切都是透明的;FatherInner类的存在对Son不可见,只是Father的实现细节而已。

修改:同步删除引用的回复 XD
9 楼 insiku 2009-06-01  
内部类是编译器现象
它不是直接调用say方法
8 楼 whaosoft 2009-06-01  



感觉楼主对于继承关系及构造方法的理解似乎有些问题。
7 楼 netfork 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



6 楼 zozoh 2009-06-01  
按照搂住的定义:
1. Son 也是一种 Father
2. Father.this 表示当前对象, 当前 new Son() 就是 Son

5 楼 flyspider 2009-06-01  
楼主需要理解多态和继承中对象创建过程(重点是构造器调用)两个问题
4 楼 yuyoo4j 2009-06-01  
[quote=&quot;netfork&quot;]
[quote=&quot;yuyoo4j&quot;]如果我对java方法访问控制应该是这样的:
[img]/upload/attachment/109618/54e5f752-a5b1-39bb-bfac-b179b30cfbab.jpg&quot; alt=&quot;[/img]
但是我碰到下面的问题:
1.创建一个包含内部类的类:

[code=&quot;java&quot;]package javabug;

public class Father {

protected Father() {
FatherInner inner = new FatherInner();
inner.sayOuterClass();
}

protected void say() {

System.out.println(&quot;I'm Father&quot;);
}

private class FatherInner {

void sayOuterClass() {
Father.this.say();
}
}
}


2.创建一个子类继承父类:

[code=&quot;java&quot;]package javabug.other;

import javabug.Father;

public class Son extends Father {

public Son() {
super();
}

protected void say() {

System.out.println(&quot;I'm Son&quot;);
}
}



3. 创建子类和父类的对象,看控制台输出:

[code=&quot;java&quot;]public class Test {

/**
* @param args
*/

public static void main(String[] args) {

Father father = new Father();
Son demo = new Son();
}

}


output:

[code=&quot;java&quot;]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=&quot;java&quot;]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(&quot;I'm Father&quot;); 
    } 
 
//    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要做补充说明了.

相关推荐

    java 编程入门思考

    5.2 Java访问指示符 5.2.1 “友好的” 5.2.2 public:接口访问 5.2.3 private:不能接触 5.2.4 protected:“友好的一种” 5.3 接口与实现 5.4 类访问 5.5 总结 5.6 练习 第6章 类再生 6.1 合成的语法 6.2 继承的...

    java 方法的流程控制与异常处理

    本次实验旨在通过一系列具体的编程任务,加深学生对Java语言中流程控制结构的理解,并掌握Java异常处理的基本方法。具体目标包括: - **熟练掌握Java各种流程控制结构(选择结构、循环结构)的使用**:通过对不同的...

    Java方法学习实例收集

    7. **访问控制修饰符** - **public**:所有类都可以访问。 - **private**:仅在本类中可见。 - **protected**:本类及同一包的类和子类可见。 - 默认(无修饰符):同一包内的类可见。 8. **方法的封装** - ...

    风中叶 Java常见笔试、面试题目深度剖析Java 笔试 面试 题目

    特别是对JDBC的使用和与ORM框架(如Hibernate、MyBatis)的结合,能够体现开发者在数据访问层的能力。 最后,面试中还可能涉及设计模式和架构设计。了解23种设计模式,并能灵活运用到实际项目中,可以展示你的代码...

    java 编程基础 源码

    Java编程基础源码是学习Java语言的重要资源,尤其对于初学者而言,通过阅读和分析源码,能够加深对Java语法和编程概念的理解。这个压缩包包含的源程序可能涵盖了一系列的基础编程实例,如变量声明、数据类型、运算符...

    Java基本练习题(Java编程基础知识)

    - 类与对象:理解类的定义,对象的创建与销毁,以及访问控制修饰符(public、private、protected)。 - 继承与多态:理解单一继承和多态的概念,使用super关键字,熟悉抽象类和接口。 - 封装:掌握封装的实现,...

    JAVA管程解决哲学家问题

    Java管程通过提供一个同步原语——`synchronized`关键字,以及在类内部定义的方法来实现对共享资源的访问控制。当一个线程进入管程(即进入`synchronized`代码块或方法)时,其他试图进入的线程会被阻塞,直到当前...

    Java How to Program

    - **数据库访问**:教授如何使用Java访问关系型数据库,包括SQL操作。 #### 面向对象设计案例研究 本书中的自动取款机(ATM)软件开发案例研究是本书的一大亮点,通过这个案例,读者可以学习到: - **需求分析**:...

    Java经典入门+笔记

    综合这份资源,学习者可以系统地掌握Java编程基础,并通过笔记了解作者在学习过程中的思考和经验,从而更有效地学习和理解Java这门语言。同时,通过笔记中的实践案例,可以加深对理论知识的理解,提升编程能力。

    《从零开始学JAVA》配套程序

    《从零开始学JAVA》这本书的配套程序旨在帮助初学者通过实践来深化对Java语言的理解。这个压缩包包含了23个章节的源码,每个章节都对应一个或多个示例程序,涵盖了Java的基础到高级特性。 1. **Java基础** - 变量...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part2

     5.1.3 在持久化类的访问方法中加入程序逻辑  5.1.4 设置派生属性  5.1.5 控制insert和update语句  5.2 处理SQL引用标识符  5.3 创建命名策略  5.4 设置数据库Schema  5.5 设置类的包名  5.6 运行本章的范例...

    Java程序设计案例教程例题源代码徐翠霞.rar

    1. **基础语法**:Java的基础语法包括数据类型(如整型、浮点型、字符型和布尔型)、变量声明与赋值、运算符、流程控制(如if语句、for循环、while循环和switch语句)以及方法定义等。这些是编写任何Java程序的基础...

    JAVA SMART系统-系统框架设计与开发(源代码+论文)(1).zip

    Java SMART系统可能基于MVC(模型-视图-控制器)架构,这是一种广泛应用的设计模式,用于分离业务逻辑、用户界面和数据访问层。此外,Spring框架可能是该系统的核心,它提供了依赖注入、AOP(面向切面编程)和模块化...

    JAVA结课机考练习题

    记得在解答过程中思考每个问题背后所涉及的概念,这样不仅能提高解题速度,也能增强对JAVA的理解。 总的来说,这份练习题涵盖了JAVA面向对象编程的各个方面,从基础到进阶,对即将参加机考的学习者来说是一份宝贵的...

    thinking in java 第四版(英文的)

    1. **基础语法**:本书首先从基础的Java语法开始讲解,包括数据类型(如基本类型与引用类型)、变量声明、运算符、流程控制(if-else、switch、for、while等)、以及方法的定义和调用。 2. **面向对象编程**:Java...

    JAVA 考试竞赛题--有一定的难度

    8. **反射**:Java的反射机制允许在运行时动态访问类、接口、字段和方法,这对于编写通用代码或单元测试非常有用。 9. **泛型**:泛型引入了类型参数,提高了代码的安全性和可读性,避免了类型转换的繁琐过程。 10...

    Java学习从入门到精通 4方法篇

    在《Java学习从入门到精通 4方法篇》这一章节中,主要聚焦于四个关键的学习方法,帮助初学者和进阶者更好地掌握Java编程语言。接下来将详细介绍这四种方法及其应用,为读者提供一个全面而深入的学习指南。 ### 一、...

    java程序员初学20道题

    JDBC(Java Database Connectivity)是Java中用来对数据库进行统一访问、管理的一种机制。通过JDBC,开发人员可以使用标准Java API来连接不同的数据库管理系统。 - **JDBC驱动模型**:JDBC提供了四种不同类型的驱动...

    Java面试题大全 高清 目录 标签

    2. **面向对象**:面试中可能会深入探讨类、对象、接口、抽象类、访问修饰符、构造器、方法重载与覆盖、静态与非静态成员、final关键字、this与super的区别等。理解面向对象的三大特性——封装、继承和多态,是评估...

    java入门到精通(实例源程序).zip

    5. **反射**:利用反射机制动态地访问类的信息和对象的方法。 6. **设计模式**:学习和应用常见的设计模式,如单例模式、工厂模式、观察者模式等,提高代码的可维护性和可扩展性。 7. **JVM内部机制**:理解垃圾回收...

Global site tag (gtag.js) - Google Analytics