access modifiers in Java - a recap - java

I'm trying to understand what these modifiers really means, beacause I think there's a lot of confusion about what they do or don't do.
So, here's what I know:
four access modifiers are used:
public , protected , private , no modifier(package private).
1) with respect to members inside its definition: a class can access every one of them no matter what the access modifier.
2) with respect to another class, which it doesn't inherit from nor shares the same package: it can access only members which are marked as public.
3) with respect to another class in the same package,but which it doesn't inherit from: it can access only members marked as public , protected and have no modifier(package private).
now comes the tricky part (at least for me..)
4) if a class A inherits from another class B, but doesn't share the same package, A has all the members (fields and methods) declared public and protected in B.
BUT with respect to AN INSTANCE of B, A can only access public members (not protected or no modifier(package private) ones, am I right on this??).
5) if a class A inherits from another class B, and they share the same package, A has all the members (fields and methods) declared public , protected AND no modifiers(package private)in B (am I right??).
Since A and B are in the same package, A is able to access protected , no modifier(package private) members of any instance of B (and of course public ones as well).
In addition, since A is-a B which members will another class (say, C) trying to access a member of A (of one of its instance of course, but let's keep it simple) be able to get to??
I know for sure C will be able to access public members, but what about protected , or no modifier(package private) ones in case 4 and 5?
(I leave private aside, since those members can only be accessed inside the defining class)
please, help!
This is what happens in terms of access/inheritance :
package one;
//class with all kind of modifiers
public class A {
protected void methodProtected(){}
public void methodPublic(){}
void methodDefault(){}
private void methodPrivate(){}
}
//same package,no inheritance
package one;
public class B {
{
new A().methodDefault();
new A().methodProtected();
new A().methodPublic();
}
}
//same package,inheritance
package one;
public class C extends A {
{
new A().methodDefault();
new A().methodProtected();
new A().methodPublic();
methodDefault();
methodProtected();
methodPublic();
}
}
//different package,inheritance
package two;
import one.A;
public class D extends A{
{
new A().methodPublic();
A a = new A();
//compiler error: can't access protected members
//a.methodProtected();
methodPublic();
methodProtected();
}
}
//different package,no inheritance
package two;
import one.*;
public class E {
{
new A().methodPublic();
}
}
now, I would like to know what happens when E tries to access B,C or D,
and what if E inherits from A or one of the other classes, or is in the same package?? what a mess...

Related

Java member access when class has default access

Say I have a class declared with default access. If a member in the class is declared protected or public, is it equivalent to the member being declared with default access?
For example:
In CarA.java:
class CarA { //class declared with default access
public int odometer;
protected void forward(int distance){...
}
protected static void tally(){...
}
}
In CarB.java:
class CarB { //class declared with default access
int odometer;
void forward(int distance){...
}
static void tally(){...
}
}
Are CarA and CarB equivalent?
My reasoning is that since the class is not declared as public, the class is not accessible outside of its package, so its members should not be accessible outside of its package as well. Could someone confirm my thinking is correct?
No, they're not equivalent. Define these in the same package:
public class CarC extends CarA { }
public class CarD extends CarB { }
And in a different package:
import your.package.CarC;
import your.package.CarD;
public class NewClass
{
public static void tryThis(CarC c, CarD d) {
int n1 = c.odometer; // legal
int n2 = d.odometer; // illegal
}
}
No, these would not be equivalent. The odometer would almost be equivalently privileged*, the methods would not be.
This is because what you're calling "default access", also referred to as package-private, means that other members of that package can access the object or method in question. So where you've made odometer public, it would essentially be available to anything with access to the parent class, the protected status of the methods would be available to the package and classes that extend the class in question, even if they are outside of the package, unlike package-private.
*The public odometer in CarA could be accessed by an object or method outside of this package by routing it through a public class that extends this class whereas the package-private odometer in CarB would always be package-private. This is a great reason why one should avoid writing code like that, other developers might assume that the variable is not publicly available.
As far as I know, you can access the members of the class when you can create an instance of the class or when you inherit the class.
A default class can not be accessed outside the package. So I think you can not inherit it as well(outside the package). So I think they are pretty much the same.
You can access the protected members of the class when you can access the class itself(CarA).
Hope I'm right and this gives you some idea.

Why protected access modifier works differently when it's used along with static from that used with non static

Normally it is said that when we are using protected for a field in a class then its subclass cannot access it using a reference of the Base Class given that the subclass is in a different package . That is true . But I found that it behaves differently when a static keyword is added with the field . It becomes accessible . How is it possible . Is any one having the answer .
package com.car;
public class Car {
static protected int carNo=10;
}
package com.bmw;
import com.car.*;
public class BMW extends Car {
public static void main(String[] args) {
//Its accessible here
System.out.println(new Car().carNo);
}
}
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.
If the access is by a field access expression E.Id, where E is a Primary expression, or by a method invocation expression E.Id(. . .),
where E is a Primary expression, then the access is permitted if and
only if the type of E is S or a subclass of S.
Source : https://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6.2.1
see
public class BMW extends Car {
public static void main(String[] args) {
System.out.println(new BMW().carNo);
}
}
is valid because new BMW() is a subclass of Car, even being in a different package.
public class BMW extends Car {
public static void main(String[] args) {
System.out.println(new Car().carNo);
}
}
is not valid because new Car() is not a subclass of Car, and it's being called in a different package. (see Java: Is a class a subclass of itself? for a discussion if a class is subclass of itself)
Now, if carNo is static, this is legal
System.out.println(new Car().carNo);
However, the right syntax here would be
System.out.println(Car.carNo);
because carNo is not an instance field, since it's static. In fact, even this will work from inside BMW
System.out.println(carNo);
because
Only members of a class that are declared protected or public are inherited by subclasses declared in a package other than the one in
which the class is declared
as stated at https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.2
The main method is in BMW, that is a subclass of Car. Thus, it has access to the protected variable.
The reason it was not visible before was because static methods, like main, cannot access non-static variables. Once both criterias are fullfilled, the main method can access it.
class Car {
protected int a = 9;
}
class BMW extends Car{
public static void main(String[] args) {
int b = a; // cannot make a static reference to a non static field warning error shown by eclipse
}
}
Two ways to remove it:
either make a static
class Car {
protected static int a = 9;
}
class BMW extends Car{
public static void main(String[] args) {
int b = a; // cannot make a static reference to a non static field
}
}
or call it outside main in a non static method, main being static cannot call to class variables
class Car {
protected static int a = 9;
}
class BMW extends Car{
public void m() {
int b = a;
}
public static void main(String[] args) {
}
}
You are mixing two concepts here:
1) accessing static variables from non-static context
2) protected access modifier
in java you can access protected members through inheritance or only within the same package.
Try accessing noCar here:
class Car{
int noCar = 9;
public static void main(String[] args) {
int b = noCar; // cannot make a static reference to a non static field warning error shown by eclipse
}
}
EDIT: considering packages
package com.bmw;
import com.car.*;
public class BMW extends Car {
public static void main(String[] args) {
System.out.println(new BMW().carNo);
Car car = new Car();
// Car has no idea that BMW is the child class
// and since it is not public we cannot access it directly
//can be accessed like this
car.getCarNo();
// you can do this because BMW has the variable carNo because of it extending Car
BMW bmw = new BMW();
int a = bmw.carNo;
}
}
package com.car;
public class Car {
protected int carNo=10;
public int getCarNo() {
return carNo;
}
public void setCarNo(int carNo) {
this.carNo = carNo;
}
}
The reason being the keyword "static".
Static associates the variable with the class and the not the instance. Since the class is public , all it's static variables will also be public i.e. all the variables will be accessible from other classes.
Also BMW extendsCar. Hence it will always be visible to BMW.
Yes, that is weird. In order to shed some light on this behaviour, it may be helpful, first of all, to recap how the protected modifier works in the absence of the static keyword, and why it works the way it does.
If class T declares a protected member m, then T and any class belonging to the same package as T can access the member, i.e. can say t.m; the type of the reference (t) must be T or a subclass of T. Additionally, any subclass U of T outside T's package can say t.m; in this case, the type of t must be U or a subclass of U.
The final part of this statement contains an important restriction. Its motivation is succintly explained in section 3.5 of The Java Programming Language (fourth edition) by Arnold, Gosling and Holmes:
The reasoning behind the restriction is this: Each subclass inherits the contract of the superclass and expands that contract in some way. Suppose that one subclass, as part of its expanded contract, places constraints on the values of protected members of the superclass. If a different subclass could access the protected members of objects of the first subclass then it could manipulate them in a way that would break the first subclass's contract -- and this should not be permissible.
Let's try to better understand this explanation by putting your Car and BMW classes to work. The following is a modified version of Car. I replaced the carNo field with an equally protected, but non-static, color field. The class also declares an obvious public getter/setter pair.
package com.car;
import java.awt.Color;
public class Car {
protected Color color;
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
Here is the BMW class, which at the moment does nothing but inherit Car's members.
package com.bmw;
import com.car.Car;
public class BMW extends Car {
}
Finally, let's add another subclass of Car.
package com.ferrari;
import com.car.Car;
import java.awt.Color;
public class Ferrari extends Car {
public Ferrari() {
color = Color.RED;
}
#Override
public void setColor(Color color) {
log("Nope. I'm proud of my color.");
}
...
}
As you can see, in our application Ferrari objects show an exclusive preference for a certain color (which is almost true in the real world, too). The color field is set in the constructor, and made read-only by a straightforward override of setColor(). Notice, by the way, that direct access to the color protected member is permitted here because the reference (an implicit this) is of the right type, that of the accessing subclass (Ferrari plays the role of U in the above description).
Now, suppose that BMW objects want to demonstrate their superiority over other cars, so they ask the class's programmer to be enhanced by means of a bold overtake() method. The programmer obliges.
...
public class BMW extends Car {
public void overtake(Car car) {
log("Wow! Become green with envy!");
car.setColor(Color.GREEN);
}
...
}
But, reading the application logs, the programmer soon discovers that, while this works fine with other cars, Ferrari objects stubbornly resist any insolence. He then, urged by BMW objects to find a solution, tries to by-pass the setColor() method...
...
public class BMW extends Car {
public void overtake(Car car) {
log("Wow! Become green with envy!");
car.color = Color.GREEN; // <-
}
...
}
... which is exactly what we can't do in Java. The Ferrari subclass's expanded contract places a constraint on the value of the color protected member. If the BMW subclass could directly access the color field through a Car (or Ferrari) reference, it would be able to break that contract. Java does not allow this.
So, this is why the protected modifier behaves the way it does when applied to non-static members. With protected static members, things change altogether. If the color field were static, any method inside BMW could directly access it. In your code, the BMW class accesses the carNo field without a hitch.
In the example above, the Ferrari class can restrict the possible values of the color field by overriding the instance setColor() method, which effectively amounts to changing, without violating, the superclass's contract.
Now, Java is, by design, a class-based object-oriented language, which does not have a concept of class object in the same sense as, for example, Objective-C. In Objective-C, classes are, literally, objects, and class methods (analogous, but non identical, to Java static methods) are, so to speak, instance methods of the class object -- with all the consequences of this fact: in particular, they can be overridden and used as polymorphic operations, the array class method in NSArray and NSMutableArray being an obvious example.
In Java, there is no class object -- an instance of java.lang.Class is by no means the same thing as an Objective-C class object. Static methods are, in essence, functions with an associated namespace. Most importantly, they can be inherited, but can't be overridden -- only hidden, just like static and non-static fields. (By the way, this means that invoking a static method is more efficient than calling an instance method, because not only its form, but also its implementation can be chosen at compile-time.)
But, and this is the end of the story, if static members cannot be overridden, they cannot really change the superclass's contract either. And, if they cannot change the superclass's contract, a subclass cannot break the contract of a different subclass by only accessing the latter's static members. If we recall that avoiding this kind of violations was precisely the reason of the restriction concerning protected non-static members, we can now understand why the designers of Java ended up lifting that restriction for protected static members. Once again, we can find a concise allusion to this line of thought in a short passage from section 3.5 of The Java Programming Language:
Protected static members can be accessed in any extended class... This is allowed because a subclass can't modify the contract of its static members because it can only hide them, not override them -- hence, there is no danger of another class violating that contract.

Java default access specifier is accessible outside the package?

I tried following piece of program and I came to know we can access default/package level instance variable.
I want to understand why it is allowed in java.
1.
package com.test;
class A {
public int i = 10;
}
2.
package com.test;
public class B extends A{
}
3.
package com.child;
import com.test.B;
public class C extends B{
public int getI(){
return this.i;
}
public static void main(String[] args) {
System.out.println(new C().getI());
}
}
I'm able to run this program successfully. What I want to understand is how it possible to access default access variable from another packkage.
Because it extends B which extends A.
B inherits all public members from A, regardless A's own visibility. That's why C sees the member too.
This is of course quite confusing. The root problem is that a public class extends a non-public class. Maybe the language should forbid that.
there are 4 different access levels: public, private, protected and package-private. Public is visible to everything, outside package even. Private is visible only inside class. Protected is visible to class and to all classes, that extends it. Package-private is default (when you don't specify any of others), and it is visible to all classes within one package, where the variable is initialized

protected access when using objects

I understand that protected access means that one can access the member within the package and any subclass, regardless of the package. What I find hard to understand is that, in a subclass, when I create an object of the class which has the protected member, I get a "not visible" error?
This is demonstrated by the following code (which is an expanded version based on an answer by YiFan Wu). Note that I have the same lines of code inside and outside of the package. Thus I have two questions:
Why does using the object change everything?
This object access difference does not happen within the package i.e. see test() in class A1.
package a;
public class A{
protected int a;
}
class A1{
public void test(){
A ref = new A();
ref.a=8; // no issue
}
}
package b;
public class B extends A{
}
package c;
public class C extends B{
public void accessField(){
a = 2; //That works.
A ref = new A();
ref.a=8; // not visible!!
}
}
Any help much appreciated...
Thanks,
Sean.
Because C is in another package, and you're creating an A, not a subclass of A.
Flip the question on its head: why should it be visible? You already know the packaging rules, and you already know the field access rules.
In the last case you're making a new instance of an A object. This is completely different from using an instance of the subclass to access its parent class's members.
When you create a subclass, it creates a parent class first. The only subclass that has access to protected members in the parent instance is that subclass that the parent class was created with.

Why can't I call a protected method from an inheriting class in another package in Java?

Say there's the following base class:
package bg.svetlin.ui.controls;
public abstract class Control {
protected int getHeight() {
//..
}
//...
}
Also, in the same package, there's a class that inherits:
package bg.svetlin.ui.controls;
public abstract class LayoutControl extends Control {
public abstract void addControl(Control control);
//...
}
Then, there's a third class in another package:
package bg.svetlin.ui.controls.screen;
public abstract class Screen extends LayoutControl {
//...
}
And, finally, there's the implementation class, again in a different package:
package bg.svetlin.ui.controls.screen.list;
public class List extends Screen {
private final Vector controls = new Vector();
public void addControl(Control control) {
height += control.getHeight();
controls.addElement(control);
}
}
Even though List inherits from Control, and the getHeight() is protected, there's the following error:
getHeight() has protected access in bg.svetlin.ui.controls.Control
I've checked that my imports are right. I'm using NetBeans.
Any idea what's wrong? I thought protected fields and methods are visible to the children even if the latter are in a different package.
Thanks!
I thought protected fields and methods are
visible to the children even if the latter are in a different package.
That's correct. The class itself has an access to the inherited protected members. But, what you're trying to do it to call the getHeight method on some Control reference. You're allowed to call it only on this instance!
For a better understanding, let me quote Kathy Sierra's SCJP Preparation Guide:
But what does it mean for a subclass-outside-the-package to have
access to a superclass (parent) member? It means the subclass inherits
the member. It does not, however, mean the
subclass-outside-the-package can access the member using a reference
to an instance of the superclass. In other words, protected =
inheritance. The subclass can see the protected member
only through inheritance.
You're right. Any protected member or method accessible from children class, but you want access to protected method of a parameter instance in addControl method. You can access only to protected method of List class (this.getHeight())

Categories

Resources