论坛首页 Java企业应用论坛

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

浏览 10776 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (11) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-05-31   最后修改:2009-05-31
OO
如果我对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
   发表时间: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》。
0 请登录后投票
   发表时间: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了。
0 请登录后投票
   发表时间: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的约束感觉不存在了.
0 请登录后投票
   发表时间: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要做补充说明了.
0 请登录后投票
   发表时间:2009-06-01  
楼主需要理解多态和继承中对象创建过程(重点是构造器调用)两个问题
0 请登录后投票
   发表时间:2009-06-01  
按照搂住的定义:
1. Son 也是一种 Father
2. Father.this 表示当前对象, 当前 new Son() 就是 Son

0 请登录后投票
   发表时间: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



0 请登录后投票
   发表时间:2009-06-01  



感觉楼主对于继承关系及构造方法的理解似乎有些问题。
0 请登录后投票
   发表时间:2009-06-01  
内部类是编译器现象
它不是直接调用say方法
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics