This question already has answers here:
Understanding Java's protected modifier
(6 answers)
Closed 7 years ago.
I am in process of learning the Java access modifiers. For that, I have created a class Machine:
package udemy.beginner.interfaces;
public class Machine {
public String name;
private int id;
protected String description;
String serialNumber;
public static int count;
public Machine(){
name = "Machine";
count++;
description = "Hello";
}
}
Then, in another package, I have created a class Robot as a subclass of a car Machine:
package udemy.beginner.inheritance;
import udemy.beginner.interfaces.Machine;
public class Robot extends Machine {
public Robot(){
Machine mach1 = new Machine();
String name = mach1.name;
//here I am getting error "The field Machine.description is not visible"
String description = mach1.description;
}
}
I am getting an error when trying to access the field description in the class Robot. From my understand of how protected access modifier works, it should be OK though, but maybe I messed up something. Any thoughts?
EDIT: I have tried to move Robot class to the same package as Machine class is in and now it works, without a need to use this. If someone can explain me this. According to the answers below, it should not work as well ...
You can't access a protected superclass field in a different instance of the class.
There's a good reason: you don't know whether it has the same subclass as yourself, or a completely different subclass. If it were allowed to access the protected field, you would be allowed to access the internals of entirely unrelated classes.
If you are sure that the object is of the same subclass as the class that wants to access the superclass field, you can cast the object; when you that, you can access the protected field.
The rules are described in the Java Language Specification section 6.6.2
6.6.2. Details on protected Access
A protected member or constructor of an object may be accessed from outside the package in which it is declared only by code that is
responsible for the implementation of that object.
6.6.2.1. Access to a protected Member
Let C be the class in which a protected member is declared. Access is
permitted only within the body of a subclass S of C.
In addition, if Id denotes an instance field or instance method, then:
If the access is by a qualified name Q.Id, where Q is an
ExpressionName, then the access is permitted if and only if the type
of the expression Q is S or a subclass of S. [This is the relevant section]
protected variables are accessible outside class, but only through inheritance. So, if you change that statement to this:
public Robot(){
Machine mach1 = new Machine();
String name = mach1.name;
// This will work (access on `this` reference)
String description = this.description;
}
Actually protected modifier means that, the field is visible to be inherited by the subclasses, and it can be used only there, using this reference.
Related
I've got some doubts regarding protected identifier. In the first chapter of Sun Certified Java Programmer Study Guide by K.Sierra I found the following information:
"Once the subclass-outside-the-package inherits the protected member, that member (as inherited by the subclass) becomes private to any code outside the subclass, with the exception of subclasses of the subclass."
I provided sample code which reflects the above statement and it is absolutely clear to me.
// Parent class
package package1;
import package2.Child;
public class Parent {
protected int i = 5;
}
// Child class
package package2;
import package1.Parent;
public class Child extends Parent {
// variable 'i' inherited
}
package package2;
public class Neighbour {
public void protectedTesting(){
Child child = new Child();
System.out.println(child.i); // no access
}
}
I've started experimenting and made a small change - moved Neighbour to package1. And there is an access to "i" variable which is a little bit surprising for me as it is not in accordance to statement "becomes private to any code outside the subclass"
Neighbour class after change:
package package1;
import package2.Child;
public class Neighbour {
public void protectedTesting(){
Child child = new Child();
System.out.println(child.i); // access!
}
}
Please clarify it to me. Thanks.
In short, protected is package-private as well as visible to subclasses. Even the JLS is vague on this (JLS §6.6.2):
A protected member or constructor of an object may be accessed from outside the package in which it is declared only by code that is responsible for the implementation of that object.
It specifies that outside the package, only subclasses can access protected members. This implies that you can also access the variable within the package. It's poor wording, but true nonetheless that protected members have package-level visibility as well as subclass-level visibility.
See also:
This related question
The Java Trail for access control
And there is an access to "i" variable which is a little bit surprising for me as it is not in accordance to statement "becomes private to any code outside the subclass"
--> But you moved class Neighbour in package package1 which is true according to "Protected members can be accessed by classes in same package"
"Once the subclass-outside-the-package inherits the protected member, that member (as inherited by the subclass) becomes private to any code outside the subclass, with the exception of subclasses of the subclass."
--> Inside package it is still protected and not private for all classes within the package.
The truth is not in "Sun Certified Java Programmer Study Guide" but in the Java Language Specification
6.6.2. Details on protected Access
A protected member or constructor of an object may be accessed from
outside the package in which it is declared only by code that is
responsible for the implementation of that object.
protected visibility includes package level visibility.
Inheritance allows you to treat your Child object as an instance of Parent.
As the member i of Parent is declared in the same package, it is accessible from Neighbour.
package package1;
import package2.Child;
public class Neighbour {
public void protectedTesting() {
Parent neighboured = new Child();
System.out.println(neighboured.i); // access
}
}
This question already has answers here:
Why is the access to a private field not forbidden?
(6 answers)
Closed 8 years ago.
class MC {
private String name;
void methodA(MC mc){
System.out.println(mc.name);
}
}
Why am I able to access name variable in methodA? I am confused here, can someone please explain?
You can access it because methodA is part of class MC. Every method in a class can access that class's private data members (in the current instance and in any other instance). Only other classes cannot. For example:
class MC {
private String name;
void methodA(MC mc){
System.out.println(mc.name);
}
}
class SomeOtherClass {
void printMC(MC mc){
System.out.println(mc.name); //compiler error here
}
}
Here is some official documentation on this topic: http://download.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
Because private does not apply to the object, it applies to the class. If private applied to the object, then your intuition would be correct: MC.methodA would have access to this.name, but it would not have access to mc.name (where mc is some other MC object).
However, a subtle rule of visibility modifiers is that they control access for any code in that class to the members of the other objects of that same class. So all of the code in the MC class has access to the private name field of all objects of type MC. That is why MC.methodA has access to mc.name (the name of some other MC object) and not just its own name.
Edit: The relevant section of the Java Language Specification is 6.6.1 Determining Accessibility:
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.
because you have accessed it from the scope it's private to.
your private implementations and data will be private to (and accessible in) the scope (e.g. class) they have been declared in.
Iam preparing for SCJP , also i came to know that protected members scope is within the package as well as in other package with some conditions like possible only with inheritance.
For example :
i have three classes as Parentclass Childclass Friendclass
package x.parent;
class Parentclass{
protected int x=10;
...............
}
package x.child;
class Childlass extends Parentclass{
super.x=20;
...............
}
package x.child;
import x.parent.Parentclass;
class Friendclass{
Parentclass pc = new Parentclass();
pc.x=30;
...............
}
Whats the reason behind that, in Friendclass the member x will not accept to assign a value to that, behaves as private member not in case of Childclass.
There are four access modifiers
private - just this class
no modifier - just this class or this package (NOT subclass)
protected - just this class, this package, or subclass
public - everyone and their cousin
Since it uses the default modifier, it has access if one of the following is true:
Is part of the class itself (Nope!)
Is part of the package of the class itself (Nope!)
So it fails the criteria, and so you don't get access.
You can't even access Parentclass.x in Childclass because x has default visibility (not protected). See http://download.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
edit:
x.child.Friendclass is not in the same package as x.parent.Parentclass.
x.child.Friendclass does not inherit from x.parent.Parentclass.
as TotalFrickinRockstarFromMars's summary states and the Java access control docs also state, this means that Friendclass is not allowed to access the field x.
I've recently started learning Java using JDK1.6. If this is a silly question, please excuse me.
If private variables can be directly accessed by objects in main() how are they 'private'?
public class Account1
{
private int accountNum;
private String name;
Account1() {
accountNum = 1101;
name = "Scott";
}
public void showData() {
System.out.println("Account Number: " + accountNum +
"\nName: " + name);
}
public static void main(String[] args) {
Account1 myA1 = new Account1();
myA1.showData();
System.out.println(myA1.accountNum); //Works! What about "Private"?!
}
}
Which gives the output:
Account Number: 1101
Name: Scott
1101
Your main is in the Account1 class, so it's still in the same scope.
Private variables can be accessed from any code belonging to the same type. If your main method was in a separate class then it wouldn't be able to access them (without using reflection).
The "main" method of a given class is part of that class. Methods that are part of a class have access to private members of that class. That makes sense to me. Doesn't necessarily mean you should use it, of course.
One way to think about it is to think about one class's knowledge of another class's internal workings. My Person class shouldn't know what happens inside my Order class; it just calls public methods on it. But anything inside Person will of course know about the internal structure of Person -- even a different instance of Person.
This is because the main() function is a member of the class. It has access to all members of the class.
In real world code, the main function is usually situated in a "harness" class that actually bootstraps the rest of the code. This harness class is usually very lightweight and instantiates other classes that do the real work.
They are private in that they can only be accessed by that class. This means they are accessible from static methods of that class (such as main) and also from instance methods (such as showData).
One instance of the class can also access private members of another instance of the class.
If you had a separate class, say, Account2, it would not be able to access provate members of Account1.
In java, there's three levels of access:
Public - Open to the world
Private - Open only to the class
Protected - Open only to the class and its subclasses (inheritance).
So why does the java compiler allow this to happen?
TestBlah.java:
public class TestBlah {
public static void main(String[] args) {
Blah a = new Blah("Blah");
Bloo b = new Bloo("Bloo");
System.out.println(a.getMessage());
System.out.println(b.getMessage()); //Works
System.out.println(a.testing);
System.out.println(b.testing); //Works
}
}
Blah.java:
public class Blah {
protected String message;
public Blah(String msg) {
this.message = msg;
}
protected String getMessage(){
return(this.message);
}
}
Bloo.java:
public class Bloo extends Blah {
public Bloo(String testing) {
super(testing);
}
}
Actually it should be:
Open only to the classes on the same package the class and its subclasses (inheritance)
That's why
Because protected means subclass or other classes in the same package.
And there's actually a fourth "default" level of access, when the modifier is omitted, which provides access to other classes in the same package.
So protected is between default and public access.
To be more specific, you're expecting protected to work as it does in C++.
However, in Java, it has a different meaning. In Java, a protected method is available to the class (obviously), all the other classes in the same package and any subclasses of this class. Classes in other packages will not have access unless they subclass this original class.
See this similar question for more specific information on inheritance markers.
Personally, I almost never use protected. I develop applications rather than frameworks so I'm much more likely to define public methods, private data and, quite often, mark my whole class as final.
There are actually four levels of access: "public", "protected", "private" & default also known as package private or package protected. Default limits accessibility to the package. Default is quite useful and I use it frequently.
You're able to call b.getMessage() because b is of type Bloo, which extends Blah, and getMessage() is protected. Protected, as you mentioned, allows subclasses to access the method.
You've got the following errors, though:
Calling super() with no arguments in the Bloo constructor is an error. The compiler can't find the no-parameter Blah constructor because you defined one with a String parameter.
Calling new Blah() in TestBlah main method is an error for the same reason as above.
Referring to a.testing and b.testing is an error because you didn't define the variable testing for any class.