将私有成员变量视为存在于声明它们的类中。如果子类调用其父类中更改成员变量的方法,则将该更改视为发生在父类中。这是在头脑中对其进行建模的有用方法,因为只有父类才能具有读取或写入该变量值的代码。
子类必须向父类发出请求,然后对父类中声明的成员变量执行某些操作。
如果使用子类中的代码重写父类中的方法,则该重写方法无法访问私有成员变量,即使父类中的重写方法可以访问私有成员变量。不过,子类中的重写方法可以调用父类中的重写方法。
例如:
public class Parent {
private int bar = 0;
public void setBar(int value) {
bar = value;
}
}
public class Derived extends Parent {
@override
public void setBar(int value) {
bar = value + 1; // NOT ALLOWED
super.setBar(value + 1); // ALLOWED (same result)
}
}
低级信息:
不过,在较低级别,我可能会创建一个 SubClass 实例,它将分配一块内存块,为 SubClass 的所有实例变量以及所有父类(包括 Object)分配空间。
方法本身的代码位于由某个类加载器为包含每个方法的类分配的内存中。这是按班级分配的。因此,即使数据一起存储在实例中,各种子类和父类的代码也不会存储在一起。
访问规则不允许子类中的代码访问为父类或祖先类私有的实例变量分配的内存。
然而,在这种情况下,很少值得花精力去考虑这么多细节。这就是我的经验。其他人可能会有不同的看法。
注意:有多种方法可以通过反射来访问私有变量。
能见度
我可能需要一些帮助,因为我是凭记忆工作的。
分配给成员变量的可见性有四个级别。这与类变量和方法中使用的四个相同。
private - 这些变量只能由声明它们的同一类中的代码访问。 (嗯......它们也可以被该类中的内部类访问。)
包 - 这些可以通过同一类中的代码以及与该类位于同一包中的任何类中的代码来访问。包含该代码的类可能位于源文件或某个 jar 文件中,或者实际上位于类路径中的任何位置。 (注意:没有关键字“package”。如果没有其他关键字来指示可见性,则变量具有包级别可见性。我喜欢将“package”一词放在 /* */ 注释中。)
protected - 这些可以通过同一类中的代码以及该类的任何子类中的代码以及与该类相同的包中的任何类中的代码访问。
public - 这些可以通过任何其他类中的代码访问。
警告:也有一些方法会导致您原本期望可见的代码不可见。这是因为类加载器的工作方式。 Java EE 具有嵌套的类加载器,最终可能会出现一个类加载器加载的代码对另一个类加载器加载的代码不可见的情况。您最终可能会得到两个具有相同全名(包括包)的类。我认为所有这些都是“高级”主题,我必须阅读它才能解释它。我确实想指出这种情况的发生,并且可能会让您对可见性产生疑问。
public class MyClass {
private int foo1 = 1; // visible in this class only
protected int foo2 = 2; // visible here, in subclasses and in classes with same package
int foo3 = 3; // visible here and in classes with the same package
public int foo4 = 4; // visible here, there and everywhere
/* package */ int foo5 = 5; // how I like to do 'package' variables with a comment
// to show I intended to do it on purpose. If you read
// my code you don't have to wonder if I forgot it.
...
}
最后一个实用的注意事项:我发现从长远来看,将几乎所有成员变量设为私有非常有用。如果您需要将它们更改为更可见的内容,请这样做,或者只是创建具有所需可见性的 getter 和 setter 方法。一个优点是,如果我提供 getter 而没有 setter,或者 getter 是公共的并且 setter 受到保护,我可以提供只读访问权限。我还可以创建一个只写变量,可以设置但从不读取。这适用于依赖注入,但您应该对此发表评论。也许你能看到优点。缺点是您需要编写更多行代码,但如果您愿意,其他 IDE 中的 Eclipse 会为您生成这些方法。