面向对象的访问控制为什么要基于Class而不是基于Object


今天发现自己之前对OOP权限控制的部分理解一直有个误区,一个简单的例子

   
  class A {
  
private $resource = 1;

public function paste(A $a)
{
print_r($a->resource);
}
}

$a = new A();
$b = new A();

$a->paste($b); //1

即$a, $b两个对象均为同一class的实例时,$a, $b可以互相访问对方的私有方法。调查了一下似乎Java和C++也是如此。这种设计是出于何种考虑,有什么作用呢?

面向对象 php

毁灭之格雷希尔 11 years, 8 months ago

好问题, 楼主的标题非常准确:
见:
http://docs.oracle.com/javase/specs/j...

Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.

我现在能想到的场景, 就是copy constructor:

   
  public A(A a){
  
this.member1=a.member1;
this.member2=a.member2;
}

为什么这么设计, 我认为是这样: OO是为了把内部实现和外部接口分开, 即是 把类的生产者和类的使用者分开. 如, 我写了一个library, 里面有类A如下,

   
  public class A implements AInf{
  
private int x=1;
public void paste(AInf a){
if(a instanceof A)
System.out.println(a.x); // 我能对a对象做任何事, 因为A就是我写的!!
}
}

实际上这个A.paste()方法只有我(类的生产者)才能控制, 而用户只能看到接口:

   
  public interface AInf{
  
public void paste(AInf a);
}

用户写了代码:

   
  AInf a=new A();
  
AInf b=new A();
b.paste(a); //我是用户, 我只能把a传给A的paste方法, 我不知道paste干了啥

答案补充
上面写了一堆, 其实只为了解释JLS里关于private限定词的描述.
其实我觉得容易让人困惑的是这里:

   
  AInf a=new A();
  
AInf b=new A();
a.control(b);


看起来很像是 对象a调用了control方法, 而control方法中使用了b的private成员; 所以 a使用了 b的private成员.
事实上不应该这么理解, 在a.control(b)时, 首先去找a的类对象A, 找到A对象中的control方法, 传入两个对象参数this(a的引用), b.
如果control方法是这么定义的:

   
  public void control(A para){
  
this.privatemember1=2;
para.privatemember1=2;
}

这里b的private成员被修改了, 可是this(a的引用)的private成员也被修改了啊! 在control方法看来, 这两个对象没什么不同, 都是由类的用户定义并传入.
所以结论是, 在 类A的用户 写语句a.control(b)时, a并没有"控制"b; 谁在控制? control方法; 谁控制control方法? 类的生产者 (作者). => 访问控制基于Class而不是基于Object

最后, 用java反射来改写a.control(b), 可以清楚的看到我上面说的过程:

   
  Method control = a.getClass.getDeclaredMethod("control");  //拿到control方法
  
control.invoke(a,b); //传入a,b(a会被传给this)

AokoRin answered 11 years, 8 months ago

Your Answer