[英]Protected variables can be accessed within Child Class or Child Object
是否可以從任何子Object
訪問parentObject
的protected
變量? 或者只能由特定的childObject
訪問? 我的情景清楚地表達了我的懷疑。
我有兩個類ParentClass
和ChildClass
。 ParentClass
是ChildClass
父級。 我在ParentClass
有一個名為protVar
的protected
變量。 它是Object
類型。 然后,我創建兩個Object
,如下所示。
ParentClass p1 = new ParentClass();
ChildClass c1 = new ChildClass();
c1.callMethod(p1); // Here I want to access protected variable of p1 which is a separate object and Not initialized within c1 as super()
現在我能從c1
訪問p1
的protVar
嗎?
免責聲明:答案是從我對另一個問題的回答中復制的。 但是,該問題沒有得到答案。 我相信它也適合這個問題,因此我將這些內容復制到這里進行一些小編輯。
protected
在Java中有點有趣。 雖然我們總是說“protected”可以訪問不同包的子類,但它並不是全局。
舉例來說,如果你有Child
伸出Parent
,並且在保護成員Parent
。 你能在做Child
是訪問的受保護成員Child
,但甚至沒有保護的成員Parent
。 聽起來有點奇怪,雖然他們聽起來一樣嗎?
引自Core Java 9th Edition:
但是,Manager類方法只能查看Manager對象的hireDay字段,而不能查看其他Employee對象。 這種限制是為了使您不能通過形成子類來濫用受保護的機制,只是為了獲得對受保護字段的訪問
(類經理擴展了Employee,Employee中有一個hireDay受保護的成員,而Manager和Employee位於DIFFERENT包中)
例如,
public class Manager extends Employee {
// accessing protected member of itself
public void foo1() {
System.out.println("" + this.hireDay); // OK
}
// access protected member of instance of same type
public void foo2(Manager manager) {
System.out.println("" + manager.hireDay); // OK
}
// access protected member of instance of super-class
public void foo3(Employee employee) {
System.out.println("" + employee.hireDay); // NOT ALLOWED!
}
}
這意味着,受保護的成員允許來自另一個包的子類通過該子類的引用來訪問( this
或者是另一個子類的引用)
並且,具體到OP的答案:如果在ChildClass
聲明了callMethod
,那么NO,你不能這樣做,甚至不會編譯。 但是,如果在ParentClass
聲明了callMethod
,那么一切都很好,因為它只是ParentClass
訪問ParentClass
實例的受保護成員。
更新:
鑒於評論中的批評,我認為值得去JLS看看它說的話:
(引自http://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6.2.1關於訪問受保護成員,第二個子彈)
如果訪問是通過字段訪問表達式E.Id,或方法調用表達式E.Id(...),或方法引用表達式E :: Id,其中E是主表達式(第15.8節),那么當且僅當E的類型是S或S的子類時才允許訪問
這基本上就是我在答案中提供的內容:
內Manager
類, manager.hireDay
可行的,因為manager
是一個主表達,並且訪問被允許的,因為的類型manager
是Manager
或子類Manager
。
因此,基於JLS,為什么manager.hireDay
工作DOES與manager
類型(屬於同一類型)有關系。
是的,派生類可以通過'super'和對基類的另一個引用來訪問基類中的受保護變量。
編輯應該注意的是,我在這里假設相同的包,因為你沒有說明任何關於不同的包。 否則規則是不同的。
如果您的子類和Parent類在同一個包中,則可以直接訪問此對象[如果您願意],否則您有兩個選項。
1 - 在Parent類中創建一個公共getter方法,並使用該方法訪問受保護的字段
2 - Inside子類使用如下給出的反射獲取Parent protected字段
public void callMethod(ParentClass o) {
try {
Field f = o.getClass().getDeclaredField("protVar");
f.setAccessible(true);
Object value = f.get(o);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
雖然這個問題很老,但我正在盡力解釋,因為這對java新手來說是一個相當普遍的問題。
考慮包p1中的Employee類。
package p1;
public class Employee{
protected String hireDay = "hireday";
}
Manager擴展了Employee,並且位於不同的包中。
package p2;
public class Manager extends p1.Employee {
//now even Manager class has hireDay protected variable that was defined in Employee class.
//Since Manager class has protected variable hireDay , for any manager m1 , we can access hireDay as m1.hireDay ONLY within package p2.
}
Enterprenur類擴展了Manager,位於包p3中。
package p3;
public class Enterpreneur extends p2.Manager{
//now Enterpreneur class has inherited hireDay protected variable that Employee class had. (see comments in Employee class.)
//Since Enterpreneur class has protected variable hireDay , for any Enterpreneur e , we can access hireDay as e.hireDay ONLY within package p3.
//the following will work because using Enterpreneur reference e , we can access e.hireday within package p3 , this has nothing to do with
//the fact that right now our code is present in Enterpreneur class , like the other answer said. Note the method is static.
public static void printhireDay(Enterpreneur e){
System.out.println("hireday is :" + e.hireDay);
}
//this will work because using this reference we can only access protected variable in the same class(Enterpreneur) or in a subclass.
public void printhireDay(){
System.out.println("hireday is :" + this.hireDay);
}
// This shouldn't work because using manager reference , we can only access protected field within package p2.
/* public printhireDay(Manager m){
System.out.println("hireday is :" + m.hireDay)
}*/
}
現在在root包中,我們有這個類來測試。
public class HelloWorld{
public static void main(String []args){
p3.Enterpreneur e = new p3.Enterpreneur();
//both of these work.
e.printhireDay();
//printing by passing the reference e.
p3.Enterpreneur.printhireDay(e);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.