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.
Related
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.
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...
class MyClass
{
public static final int num=90;
}
Why am I allowed to create a public member in a non-public class?
Is there another way of accessing this member that I do not know of (other than through the class name)?
Since your question was about members, I will address both fields and methods (non-static; Anthony Accioly's answer touches on another good use case, which also includes static fields).
While in many situations this is just an ambiguous consequence of the language's grammar (in particular: public fields in non-public classes, as in your example snippet), there are very good reasons for needing to be able to use public methods in non-public classes.
Expanding on Mik378's answer, consider, e.g., the following (contrived example):
import ...;
class BleebleAscendingComparator implements Comparator<Bleeble> {
#Override public int compare (Bleeble o1, Bleeble o2) { ... }
}
class BleebleDescendingComparator implements Comparator<Bleeble> {
#Override public int compare (Bleeble o1, Bleeble o2) { ... }
}
public class BleebleView {
public enum SortMode { ASC, DESC };
public Comparator<Bleeble> getDisplayOrderComparator (SortMode mode) {
if (mode == SortMode.ASC)
return new BleebleAscendingComparator();
else
return new BleebleDescendingComparator();
}
}
You cannot instantiate one of those Comparator implementations directly outside of that context, but they must override public methods of Comparator, and their functionality is accessible via a Comparator interface.
This same reasoning applies to, e.g., private or protected inner classes. If you were not able to declare methods public, you would have no way of overriding public methods of interfaces that they inherit or classes that they extends.
Practical Examples:
You use this every time you override a public method in an anonymous inner class (e.g. every time you override public void actionPerformed in an anonymous ActionListener).
Consider any non-public class that you would like to store in a HashMap. You would override the public equals() and hashCode() in that non-public class, and the implementation of HashMap can access them regardless of the fact that the class is non-public.
The often overridden public toString() is another common example of a public member of a potentially non-public class.
A more complex example is the use of java.sql.Driver in java.sql.DriverManager (in general, factory-type designs make heavy use of this concept) -- an SQL driver implementation may not make implementation classes public (e.g. the Oracle driver produces non-public Connection objects).
Many more... if you keep an eye out for examples of this, you'll be surprised how common it really is!
Don't forget that classes with default access can be subclassed by public classes in the same package.
package package1;
class MyDefaultClass {
public static final int MY_CONSTANT = 0xCAFEBABE;
}
public class PublicExporter extends MyDefaultClass {
}
Now the public class acts as a bridge, and you are able to consume MyDefaultClass public members from other packages.
package package2;
import package1.PublicExporter;
public class Consumer {
public static void main(String[] args) {
System.out.printf("%x\n", PublicExporter.MY_CONSTANT);
}
}
Consumers can even import static members:
import static package1.PublicExporter.MY_CONSTANT;
public class Consumer {
public static void main(String[] args) {
System.out.printf("%x\n", MY_CONSTANT);
}
}
When a public method belonging to an enclosing class A returns a reference (public supertype reference, like an interface) to its inner class B having default scope, external client (outside A's package) can only call B's methods but can't CREATE themselves fresh instances of B.
If the B's methods weren't public, external client couldn't reach them, and worse: would cause a compilation error since not well implementing its interface.
This modeling could be useful in a certain context, to improve code design.
When you declare a variable public it essentially becomes exactly that ; it's able to be seen throughout your entire program, without any special getters/setters. The class does not necessarily need to be public in order for its members to be public also.
Remember, in Java you can only have 1 public class per compilation unit( .java file), and that public class needs to have the same name as the compilation unit. Other than that, it doesn't "own" ownership of the keyword public.
The fact that you declared num as public and static allows you to say System.out.println(MyClass.num). The public attribute allows you to get the num variable directly. Thus, you do not have to create a method to return num for you. Because it is public, you can also say
MyClass mc = new MyClass();
System.out.println(mc.num);
However, since you also added the static declaration, you should only access it via the class name, i.e MyClass.num
Point to take home: public variables can exist in any type of class, and they allow you to access them without the need for getters and setters. Public classes, however, are not the only classes that can own public variables.
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
I have a java public class I need to modify (only one method). The class is in a package so I'm writing a new class that extends the first class and overriding the method I need to change.
Class A is
public class A {
GL gl;
GLU glu;
PGraphicsOpenGL pgrap;
//other fields
//constructor
public void method() {
this.gl = pgrap.gl;
this.glu = pgrap.glu;
//something else I don't want in class B
}
}
Class B is something like
public class B extends A {
//constructor that recalls super()
public void method() {
super.gl = pgrap.gl;
super.glu = pgrap.glu;
}
}
but I get an error for super.gl = pgrap.gl: The field A.gl is not visible.
I don't have any getter method written in the package, what should I do?
Thanks.
NOTE: I am not able to recompile the package or add the class B to the package.
The default access specifier is package-private which means classes in the same package as A can access this variable using the instances of A
A a = ....
a.gl = ...; // this works.
And package-private members (and private members) are not inherited, only protected and public members are.
Since A#method() is already doing the assignment operation, you call super.method() in B#method() to get your desired behavior. Or you should mark them as protected.
Controlling Access to Members of a Class
A.gl and A.glu are package-private (no explicit modifier). The only way you'd be able to access them is if class B is in the same package as class A.
If they were protected you'd be able to access them as you wish:
The protected modifier specifies that the member can only be accessed
within its own package (as with package-private) and, in addition, by
a subclass of its class in another package.
Fields gl and glu have package access. Use protected access modifiers to make accessible them in sub-classes.
Define variables as protected.
protected int gl;
protected int glu;
Because your variables have default access you will be able to access them in the Same package. So you need to move either B or define them as protected so that they will be accessible to child classes.
Assuming that you can't declare your class B in the same package of class A and you can't directly modifiy class A then only choice is to go by reflection:
public void method() {
Field[] fields = this.getClass().getSuperClass().getDeclaredFields();
for (Field field : fields) {
if (field.getName().equals("gl")) {
field.setAccessible(true);
field.set(this, pgrap.gl);
}
}
}