What is the difference with 'protected' and 'protected-static' variables? - java

I read a book for OOP and
an example about 'protected' access modifier is strange for me.
Summary of example
This example is to test how 'protected' reserved word effects to variables.
ClassA has 2 protected variables (static / non-static)
package a;
public Class A {
protected int a;
protected static int b;
}
ClassB is derived from ClassA and located another package
ClassB.test has a method to check accessibility (Cannot run)
package b;
public Class B extends ClassA {
ClassA x = new ClassA();
// [O] : Executable
// [X] : Not-executable
void test() {
a = 1; // [O] : Derived from ClassA
b = 1; // [O] : Derived from ClassA
// [X] : a is protected, so only accessible within codes in derived class
x.a = 1; // A)
// [O] : I don't know why it is executable
x.b = 1; // B)
}
}
Actually, b is 'protected' so I thought it cannot be accessed by instance variable like x.a = 1;
But it can be accessible with 'static' keyword.
How can I understand for this?
Shortly A) is fine, but why is B) executable ?

The static keyword means that variable belongs to the class itself instead of the objects of said class. You could replace your call to x.b with ClassA.b. Since ClassB extends ClassA, all protected static variables are accessible for all methods of ClassB at all time.

Related

Some trouble with inner class visibility

I'm facing java inner class and I'm having some trouble with outer variables visibility.
class A {
private int x = 5;
class B extends A{
public void fun(B b){
b.x = 10; //here
}
}
}
Why I can't do something like this (see the "here" tag) if there are no visibility restrictions between inner and outer class? I'm really not understanding these rules.
In your example the member variable x is not a property of class B so b.x = 10 makes no sesne, hence the error, it's nothing to do with visibility rules. Trying x = 10 works fine, which is a short-cut for A.this.x = 10 or super.x = 10.
Modifier private cannot be accessed in sub classes.
class A {
private int x = 5; // The issue is in `private` in this line
class B extends A{
public void fun(B b){
b.x = 10; //here
}
}
}
If you remove the modifier private and change it to default, public OR protected, you will be able to access the variable.
Please go through the link for better understanding.
UPDATE:
Remove extends keyword (Now Class B will not be a sub class but only an inner class), and the variable x will only be accessed using this OR super keyword. The usage is elaborated at link
you need know this three private,protected,default,publicaccess specifiers
private variables only can be modified in the itself class.not include subclass
default variables can be modified in same package.
protected variables can be modified in subclass and in same package and itself
public variables can be modified any where.
you can saw this on this link
beside.if you use this example ,this can modified your variables with usingsuperspecifiers to access your visiable
class A {
private int x = 5;
class B extends A{
public void fun(B b){
b.x = 10; //here error
super.x=1;//this is ok
}
}
}
this b.x = 10; //here error this problem is b is a parm of a methods not a member-variable or a super class variable.
This one is quite special. Inner class can access the private field of the outerclass. This can be shown with the fun(A) method
class A {
private int x = 5;
class B extends A{
public void fun(A a){
a.x = 5; //Valid since we are in the same class (inner-class can access private field)
}
}
Now, if you have a B parameter, this is a bit different because it will try to use the inheritence instead of the outer-inner link :
public void fun(B b){
b.x = 10; //Access using inheritence, not OK for private field
((A)b).x = 10; //Casting into A to be able to access the private field (just like fun(A).
}
Note that this is a problem because you update a reference receive in parameter, you can update the current inner instance easily
public void fun(){
x = 10; //OK : access to A.x from inner class
super.x = 10; //OK : same
this.x = 10; // KO : trying to access a private variable from B scope
}

Difference between super and this in the commands below?

What is the difference between these commands when I have a class A and a Class B where B extends A , and they have a common instance variable size and the commands below are called from a method printSize1 inside B?
class A {
protected int size;
}
class B extends A {
protected int size=7;
public void printSize1() {
System.out.println(((A)this).size)
System.out.println(super.size);
}
}
Also I have the same question with these two. I have a class A and a class B where B extends A, and they both have a method with the same name printSize and an instance variable size and the below commands are called from a method printSize2 inside class B.
class A {
protected int size;
public void printSize() {
System.out.println("Size=" + size);
}
}
class B extends A {
protected int size=7;
public void printSize2 {
((A) this).printSize();
super.printSize();
}
public void printSize() {
System.out.println ("MSize="+size);
}
}
i have a class A and a Class B where B extends A which they have a common instance variable size
No, they don't. They have separate instance variables called size. One is in the part of the object associated with A, and the other is in the part of the object associated with B. Let's call them A$size and B$size. For them to have a common instance variable, you'd remove the declaration of size from B so they're both using A$size.
Redeclaring an ancestor's non-private instance variable (field) is always a bad idea, because it leads to this sort of confusion.
Both of the below output 0 for your example code, because they're both accessing A$size, which you never assign a value to, so it has the default value 0:
System.out.println(((A)this).size); // 0
System.out.println(super.size); // 0
So the question is: Why are they both using A$size and not B$size? Because of the type of the reference we're using to look up size. In both cases, the type of the reference is A, because the type of (A)this is A (via cast) and the type of super in a method in B is also A. Since the type of the reference is A, it's A's size that gets used.
In this particular case there isn't much of a difference between the two, but there would be if you added another layer to the hierarchy:
class A {
protected int size = 1;
}
class B extends A {
protected int size = 2;
}
class C extends B {
protected int size = 3;
void printSize() {
System.out.println(((A)this).size); // 1
System.out.println(super.size); // 2
System.out.println(this.size); // 3
}
}
Moral of the story: Don't redeclare instance variables declared by an ancestor (unless the ancestor's version is private).
Note that this is different for variables than it is for methods. Instance methods are polymorphic. Instance variables are not. With methods, you get the method associated with the final type of the object (unless you use super or a qualified super, because those are special and bypass polymorphism).
This is what's coming into play in your second example in printSize2. Because methods are polymorphic, it doesn't matter that you've cast this to be type A in ((A)this).printSize(), you still get B's printSize. But super.printSize() is special because super is special and bypasses polymorphism, giving B access to A's printSize.

private scope and inheritance in java

Consider this simple java code :
class A {
private int a = 10;
public void print() {
System.out.println(this.getClass().getName() + " " + a);
}
}
public class B extends A {
public void p1() {
print();
}
public static void main(String... args) {
B b = new B();
b.p1();
}
}
If you will run the code , the value that gets printed is B 10 .
My question is if "a" is not inherited when we use "private" modifier but the method is , then there is method print() in class B now but "a" is not part of the class since it is private, so how is it that the compiler doesn't throw error when we try to access it by saying scope of "a " is private ?
print in class A is reachable in class B as it's public and class B is a child of class A.
But print in class A can see all the fields in class A since it's a method of that class. So that function can see a, and hence compilation passes.
Field 'a' is inherited. It is not directly accessible from class B.
Only class A can access field a.
The JLS (8.3. Field Declarations) states this:
A class inherits from its direct superclass and direct superinterfaces all the non-private fields of the superclass and superinterfaces that are both accessible to code in the class and not hidden by a declaration in the class.
A private field of a superclass might be accessible to a subclass - for example, if both classes are members of the same class. Nevertheless, a private field is never inherited by a subclass.
But, what does "inherit" actually mean?
What it actually means is that the name of the (inherited) method or field is present in the namespace of the subclass. A private method is not present. It cannot be named in the namespace of the subclass.
On the other hand, the private field of a superclass must be present in an instance of the subclass. If it wasn't present, then methods declared in the superclass that use the private field could not function.
But then we have the bit about nested classes; e.g.
public class Outer {
class A {
private int a;
...
}
class B extends A {
private int b1 = a; // Compilation error
// field 'a' is still accessible!
private int b2 = ((A this).a; // OK!
}
}
(Yes ... really!!)
The interesting thing though is that the compilation error you get for the above is:
Test.java:7: error: a has private access in Test.A
private int b = a;
The compiler writers have decided to describe this situation as access to a private variable, not as access to a variable that has not been inherited.
My question is if "a" is not inherited when we use "private" modifier but the method is , then there is method print() in class B now
... yes ...
but "a" is not part of the class since it is private,
No!
That's not what inherit means for a field. The field a is present in every instance of B. It is just that it is not accessible. You can't name it.
so how is it that the compiler doesn't throw error when we try to access it by saying scope of "a " is private ?
Because it is there.
Opinion: the Java definition of "inherited" with respect to private fields and methods is confusing. Even counter-intuitive. However, it is what it is.
You are confusing inheritance with visibility/access.
The a attribute is not visible/accessible directly from within B; but it is definitely inherited, in the sense that it is still there, because an instance of B contains an instance of A (class B extends A), and that instance of A (where the print() method lives) always contains that a attribute.

Are static class members static in Java?

In the below code, are b and show inherently static?
public class A {
public static class B {
private int b = 0;
public void show() {
System.out.println(b);
}
}
}
No they aren't static. You need to create an instance of B to access them.
The static keyword in your code example means that instances of B can be created without an instance of A.
If B was not static:
Instances would have an implicit reference to an instance of A.
The only way to create them would be to use new B() inside class A, or using syntax like new A().new B().
Methods in B can refer to A.this (the implicit reference to an instance of A).
Methods in B can refer to A.this.someField (using that implicit reference).
Methods in B can call instance (non-static) methods in A.
However, because B is static:
Instances do not have a reference to an instance of A - you don't need an A to create a B.
Instances can be created using new A.B() (or just new B() from within in class A)
Methods in B cannot refer to A.this.
Methods in B cannot access fields in A (unless passed in as a parameter).
Methods in B cannot call instance (non-static) methods in A.
They are not static. They are instance fields in B.
Meaning you need to have an instance of B to get/set them.
B is static in A but that does not make those fields of B static.
You can create many instances of B without any reference to A.
So B is static class in A but the same is not true for B's instance fields.
The static keyword has two meanings that are actually quite different and that can be confusing.
Static on a variable/method means that it exists at the class level, not the instance level. This means that you only have one copy of that variable/method no matter how many instances of the class you create.
Static on an inner class though just means that the class does not depend upon its outer class. In your example you can create a new B() without having an A. If you didn't have the static keyword on the class you could not create a new B() unless it was within an instance of A.
B is a static inner class of A.
Need to instantiate B.
A.B innerObject = new A.B();
innerObject.show();
The identifier static has a specific purpose here that many people don't immediately grasp. I'm going to take your code and change it a bit.
public class A {
private int a;
public A(int a) {
this.a = a;
}
public class B {
public void show() {
System.out.println(a);
}
}
}
Now, what's happening in class B? Because B is a non-static class, it has access to other non-static members in class A. Essentially, it states that every class A object has their own flavor of class B objects, even thought they are functionally the same. For us to get that same behavior if B was a static class:
public class A {
private int a;
public A(int a) {
this.a = a;
}
public int getA() { return a; }
public static class B {
public void show(A a) {
System.out.println(a.getA());
}
}
}
Here, this implies that the flavor of B objects doesn't change depending on which A object created it. The B class is static so that it cannot access non-static members of the A class object that created it and must access those members explicitly from whichever A object it wants to interact with.
In the previous implementation, a B object would seamlessly access fields and non-static methods of the A object that created it.
These are two different behaviors and often it's clear exactly which one fits your objective.

Favoring static class usage over variable with same name

Class B extends Class A, Class A has a variable named K, I have a static Class named "K" also. Is there a way inside class B to favor using the static class K over the inherited variable K?
(I am working with decompiled code that was obfuscated, I cannot rename either of the versions of K)
You may need to refer to the class K with its full name, ie myPackage.K
Since K is in the default package, I think your only options will be to refer to class K using reflection or else write a class to wrap K so you can use a different name. Or if you're after some static members of K, you could use static imports to get at them, too.
Does this work?
class A {
int X;
}
class B extends A {
static class X {}
void foo() {
X = 5; // A.X variable
B.X x = new B.X(); // B.X nested class
}
}

Categories

Resources