Just found this construction does not compile:
class A {
private int data;
public static int process(B b) {
return b.data;// error here: 'data has private access in A'
}
}
class B extends A {}
Of course this problem can be solved easily manually (cast b to A, make field protected, etc.). But the question is, why java does not allow such construction? I thought that compiler must know that B is a subclass of A, so methods of A must have access to A's private fields.
The only possible problem I can think of is if B has its own 'data' field, compiler must not know which field we want to access, but that's what inheritance is for, right?
Well, the compiler doesn't allow it because the language specification doesn't allow it. JLS section 8.3 (field declarations) specifies (emphasis mine):
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.
So looking up the field as a member of the subclass (6.5.6.2) must fail - the compiler is being slightly helpful in explaining why it's failed rather than just saying the member doesn't exist, but I believe that in a pure sense, the look up should just say "Type B doesn't have a member called data" rather than complaining that it's inaccessible.
As for why the language was designed that way - I'm not sure. The equivalent code in C# is fine, and it makes perfect sense to me. For example, in the C# 5 specification, section 3.4:
When a type inherits from a base class, all members of the base class, except instance constructors, destructors and static constructors, become members of the derived type. The declared accessibility of a base class member does not control whether the member is inherited—inheritance extends to any member that isn't an instance constructor, static constructor, or destructor. However, an inherited member may not be accessible in a derived type, either because of its declared accessibility (§3.5.1) or because it is hidden by a declaration in the type itself (§3.7.1.2).
Related
This question already has answers here:
What is the difference between public, protected, package-private and private in Java?
(30 answers)
Closed 7 years ago.
Recently I've come across the following piece of code:
enum Animals {
DOG("woof"), CAT("meow"), FISH("burble");
String sound;
Animals(String s) {
sound = s;
}
}
class TestEnum {
static Animals a;
public static void main(String[] args) {
System.out.println(a.DOG.sound + " " + a.FISH.sound);//Expected compilation failure
}
}
I would expect the code to fail to compile because of this a.DOG.sound part. But to my surprise it doesn't. I've searched all around including the official documentation to find out the access level but found nothing. Is it public or default?
The implicit access level of a manually declared field in an enum is package-private, exactly the same as it in normal classes. Thus your sound field will be accessible if and only if Animals and TestEnum are in the same package.
I tried to find a solid quote for this in the JLS but the enum rules are unfortunately scattered all over the place, specified as exceptions to the rules for normal classes, and the rules thus have to be assembled from pieces. JLS §6.6.1 Determining Accessibility says:
A member (class, interface, field, or method) of a reference type, or a constructor of a class type, is accessible only if the type is accessible and the member or constructor is declared to permit access:
If the member or constructor is declared public, then access is permitted.
All members of interfaces lacking access modifiers are implicitly public.
Otherwise, if the member or constructor is declared protected, then access is permitted only when one of the following is true:
Access to the member or constructor occurs from within the package containing the class in which the protected member or constructor is declared.
Access is correct as described in §6.6.2.
Otherwise, if the member or constructor is declared with package access, then access is permitted only when the access occurs from within the package in which the type is declared.
A class member or constructor declared without an access modifier implicitly has package access.
Otherwise, the member or constructor is declared private, and 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.
This means that class types (class and enum) get the rule that members implicitly have package access, while interface types (interface and #interface) get the rule that members are implicitly public.
It is not immediately obvious from the above that "class member" includes enums in its definition of "class", but it does. Because of their broad overlap, the JLS groups enums with classes in many places (and annotation types get likewise grouped with interfaces). JLS §8.9 Enum Types says "An enum declaration specifies a new enum type, a special kind of class type"; and JLS §8.2 Class Members makes clear that the term "class members" means members of a "class type".
However, enums do get two special rules with regard to member accessibility that are not included in the quoted section above:
The enum constants themselves (in your example they are DOG, CAT, and FISH) may not have any explicit access modifiers (JLS §8.9.1), and are always public static final fields of the enum type (JLS §8.9.3).
Enum constructors must be private (to prevent people creating extra constants) and are private implicitly (JLS §8.9.2).
Apart from those two exceptions, the access rules of normal classes apply to enums. If your Animals enum is made public, it and all its constants are accessible outside the package, but the sound field is package-private, and is not accessible outside the package unless you declare it public explicitly.
If you can import enum you can access enum constants
If enum is accessible (specifically declared public) outside the package it's elements are also accessible and if no modifier specified it will only be accessible inside package. By default enum constants are accessible if enum is accessible means those are public static final by default.
I would expect the code to fail to compile because of this a.DOG.sound
part. But to my surprise it doesn't.
It will be same as any other variable can behave in any class if no default modifier it will be accessible inside package only.
I have a class A. I define another class B within a method (even main) of the class A and class B can access all the variables within the scope of the method it is defined in. What is the terminology for such classes (as B)? Some people have been saying Nested classes or Inner classes but IIRC, those are the classes where they have another class as their data members (kinda like composition in C++).
The second part of my question is that some people have been saying that when you have a class defined within a method of another class, then the variables of the first class (A) that are accessed by the later class (B) need to be declared final. Is this to be followed strictly and why so?
According to the Java Language Specification these are "local classes":
A local class is a nested class (§8 (Classes)) that is not a member of
any class and that has a name (§6.2, §6.7).
or "anonymous [inner] classes", which are just the ones that don't have a name (e.g. Interface x = new Interface() { ...).
These are special cases of inner classes which is generally what I've heard people refer to them as.
As for your second question, "Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted." So it is a compile-time error if you try to access non-final local variables. Obviously this part must be followed strictly if you want your class to compile.
I have not personally heard the advice that you should not access non-final fields of the enclosing class, and I'm pretty sure it's allowed. While arguments could be made that fields should be final unless they can't be, I don't see any stylistic reason this should be more important in inner classes. There is a technical difference that accessing a field from an inner class may cause the compiler to create and call synthetic getters and setters, but this is generally a minor performance concern.
I have recently been moving through a couple of books in order to teach myself Java and have, fortunately, mostly due to luck, encountered very few difficulties. That has just changed.
I read a section on the following under inheritance and the whole superclass subclass setup
-- When a new superclass object is created, it is, like all objects, assigned a reference (superReference in this example)
-- If a new subclass object (with the defining subclass extending the superclass) is created, and then the superReference reference is set to refer to that instead of the original object, it is my understanding that, since the reference is made for a superclass, only members defined by the superclass may be accessed from the subclass.
First - is this correct?
Second: If I am overriding a method and therefore have one in the super and one in the sub, and I create a superclass object and then assign its reference, as I did above, to a subclass object, by the principle called something like Dynamic Method Dispatch, a called overridden method should default to accessing the subclass method right?
Well, my question is:
If a reference to a superclass-object is retooled for a subclass-object and will deny direct object.member access to subclass-defined members, only supporting superclass-defined members, how can, if a superclass reference is retooled for a subclass object, an overridden method apply to the subclass-object if access is limited by the superclass-originated-reference-
If you try like:
class SuperClass{
int intVar = 0;
void method(){
//in super class
}
}
class SubClass extends SuperClass{
int intVar = 2;
void method(){
//in sub class
}
}
Then
SuperClass obj = new SubClass();
int val = obj.intVar;// this is taken from SuperClass as variables are decided on reference basis
//if both superclass and subclass contain the same variable it is called shadowing
obj.method();// it is taken from the SubClass as it is method overriding
//and is decided at runtime based on the object not the reference
Check comments. Hope this helps.
only members defined by the superclass may be accessed from the subclass.
First : This is just plain wrong. The subclass may access it's own member without a problem. However once you have assigned a subclass instance to a super class variable (reference) the you can only call methods or members made accessible from the super class only. Is this what you meant to say?
Second : Methods that will be executed are the methods in the instance (object). Not the methods in reference (variable) type. So yes overridden methods will always be executed.
Third : A subclass may override a method but not a instance property. Whatever member variables are in the super class will be in the subclass as well. And you can override methods in the subclass just so long as you keep their existing access modifier or use a more accessible access modifier.
In Oracle documentation doesn't mention that or at least it is not clear or explicitly explained. This behaviour seems to me like virtual methods in C++ with the difference that in such language it is clear through the use of the keyword virtual preceding the methods defined in the base or parent class (superclass in java) and that must be redefined in the child class. In C++ there are not virtual variables, just virtual methods.
In that case, when we have a pointer (reference) to a base class that points to an instance of a child class and there are methods with the same signature and variables with the same name in both the parent and child classes, the definitions of the methods that will be executed are those of the parent class if they are not preceded by the keyword virtual, on the other hand the definitions in the child class will be executed for the methods declared as virtual.
In the case of the variables, the ones in the base class are taken and not the ones in the child classes.
Resuming, the similarities are:
-In java, variables are taken based in the reference
-In C++ there are not virtual variables
So in the case we are talking about, hidding variables in the child classes or subclasses are not taken but the hidden
-In java, methods are taken based on the object or instance
-In C++ virtual methods must be redefined in the child classes and those are taken
What do we we call a constructor, if it is not a member of a class as stated in Oracle doc: http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
I think the term "member" was defined to exclude constructors for the sake of convenience. Constructors, even public ones, are not inherited; members are inherited (unless they are static and/or private). It would be awkward when talking about the rules of inheritance to always have to say "members except constructors".
From the Java Language Specification, §8.2:
Constructors, static initializers, and instance initializers are not members and therefore are not inherited.
Just call constructors "constructors".
Its a special method that every class has, which is called after creation of the object. in JVM its called using invokespecial so, lets just call it a special method?
And since there is just 1 special method in Java - they all call it "constructor"
All the doc is saying is that the constructor is not inherited by default. Since the constructor is a method that is invoked on the construction of the object in the memory heap, then once you create a subclass that inherits from a super class, the constructor of the super class is not invoked by default.
For instance if you have a class Vehicle and a subclass Car, assume the Vehicle constructor is as follows:
public Vehicle(String vehName) {
this.vehName = vehName;
}
Then, even though your class Car inherits from class Vehicle, the vehName member (field) will not be set as the constructor above does.
So you will need to do something like this:
public Car(String vehName) {
super(vehName);
}
Hope that helps
In Java, a class body (the area between braces) can contain the following key items: (1) Fields (2) Methods (3) Other Classes (nested classes) (4) Constructors (5) Initializers
An object created from a particular class shall take the shape that is similar to the blueprint (class) from which it's created. Now, if you look at items that can be contained in a class body, only item (1) to (3) help in determining what sort of object can be created from a particular class definition.
Constructors and initializers only play part in actual creation of the object (e.g. initialization of already defined fields), but do not determine what shape/state that object shall carry, and what behaviors it will display.
For this reason, to me, it make sense to call item (1) to (3) class members (i.e. class members are those items within a class body that determine how an object created from the class looks like and behave); whereas constructors and initializers are not members because their absence in a class definition does not affect a class state and behavior.
As such, only class members can be inherited as the whole point behind inheritance is to enable a subclass reuse state and behavior of its superclass.
A Constructor is a method which is in a class which is used to create a new instance of that class.
Being a member of a class just means that the item in question is in the class.
Constructor is a method which name is same as the class. It is used to initialize the object of class. It's implicit in action. Parametric constructor initialize object with different value.
Why can't constructors be final, static, or abstract in Java?
For instance, can you explain to me why this is not valid?
public class K {
abstract public K() {
// ...
}
}
When you set a method as final it means: "I don't want any class override it." But according to the Java Language Specification:
JLS 8.8 - "Constructor declarations are not members. They are never inherited and therefore are not subject to hiding or overriding."
When you set a method as abstract it means: "This method doesn't have a body and it should be implemented in a child class." But the constructor is called implicitly when the new keyword is used so it can't lack a body.
When you set a method as static it means: "This method belongs to the class, not a particular object." But the constructor is implicitly called to initialize an object, so there is no purpose in having a static constructor.
The question really is why you want constructor to be static or abstract or final.
Constructors aren't inherited so can't be overridden so whats the use
to have final constructor
Constructor is called automatically when an instance of the class is
created, it has access to instance fields of the class. What will be
the use of a static constructor.
Constructor can't be overridden so what will you do with an abstract
constructor.
A Java constructor is implicitly final, the static / non-static aspects of its semantics are implicit1, and it is meaningless for a Java constructor to be abstract.
This means that the final and static modifiers would be redundant, and the abstract keyword would have no meaning at all.
Naturally, the Java designers didn't see in any point in allowing redundant and/or meaningless access modifiers on constructors ... so these are not allowed by the Java grammar.
Aside: It is a shame that they didn't make the same design call for interface methods where the public and abstract modifiers are also redundant, but allowed anyway. Perhaps there is some (ancient) historical reason for this. But either way, it cannot be fixed without rendering (probably) millions of existing Java programs uncompilable.
1 - Actually, constructors have a mixture of static and non-static semantics. You can't "call" a constructor on an instance, and it they are not inherited, or overridable. This is similar to the way static methods work. On the other hand, the body of a constructor can refer to this, and call instance methods ... like an instance method. And then there is constructor chaining, which is unique to constructors. But the real point is that these semantics are fixed, and there is no point allowing a redundant and probably confusing static modifier.
public constructor: Objects can be created anywhere.
default constructor: Objects can be created only in the same package.
protected constructor: Objects can be created by classes outside the package only if it's a subclass.
private constructor: Object can only be created inside the class (e.g., when implementing a singleton).
The static, final and abstract keywords are not meaningful for a constructor because:
static members belong to a class, but the constructor is needed to create an object.
An abstract class is a partially implemented class, which contains abstract methods to be implemented in child class.
final restricts modification: variables become constant, methods can't be overridden, and classes can't be inherited.
Final: Because you can't overwrite/extend a constructor anyway. You can extend a class (to prevent that you make it final) or overwrite a method (to prevent that you make it final), but there is nothing like this for constructors.
Static: If you look at the execution a constructor is not static (it can access instance fields), if you look at the caller side it is (kind of) static (you call it without having an instance. Its hard to imagine a constructor being completely static or not static and without having a semantic separation between those two things it doesn't make sense to distinguish them with a modifier.
Abstract: Abstract makes only sense in the presence of overwriting/extension, so the same argument as for 'final' applies
No Constructors can NEVER be declared as final. Your compiler will always give an error of the type "modifier final not allowed"
Final, when applied to methods, means that the method cannot be overridden in a subclass.
Constructors are NOT ordinary methods. (different rules apply)
Additionally, Constructors are NEVER inherited. So there is NO SENSE in declaring it final.
Constructors are NOT ordinary methods. (different rules apply)
Additionally, Constructors are NEVER inherited. So there is NO SENSE in declaring it final.
No Constructors can NEVER be declared final. YOur compiler will always give an error of the type "modifer final not allowed"
Check the JLS Section 8.8.3 (The JLS & API docs should be some of your primary sources of information).
JLS section 8 mentions this.
Constructors (§8.8) are similar to methods, but cannot be invoked
directly by a method call; they are used to initialize new class
instances. Like methods, they may be overloaded (§8.8.8).
But constructors per say are not regular methods. They can't be compared as such.
why constructor can not be static and final are well defined in above answers.
Abstract: "Abstract" means no implementation . and it can only be implemented via inheritance. So when we extends some class, all of parent class members are inherited in sub-class(child class) except "Constructor". So, lets suppose, you some how manage to declare constructor "Abstract", than how can you give its implementation in sub class, when constructor does not get inherit in child-class?
that's why constructor can't be
abstract .
lets see first
final public K(){
*above the modifier final is restrict 'cause if it final then some situation where in some other class or same class only we will override it so thats not gonna happen here proximately not final
eg:
we want public void(int i,String name){
//this code not allowed
let static,, static itz all about class level but we create the object based constructor by using 'new' keyword so,,,,,, thatsall
abstract itz worst about here not at 'cause not have any abstract method or any declared method
Unfortunately in PHP the compiler does not raise any issue for both abstract and final constructor.
<?php
abstract class AbstractClass
{
public abstract function __construct();
}
class NormalClass
{
public final function __construct() {
echo "Final constructor in a normal class!";
}
}
In PHP static constructor is not allowed and will raise fatal exception.
Here in AbstractClass obviously a constructor either can be declared as abstract plus not implemented or it can be declared as something among (final, public, private, protected) plus a function body.
Some other related facts on PHP:
In PHP having multiple constructor __construct() is not possible.
In PHP a constructor __construct() can be declared as abstract, final, public, private and protected!
This code was tested and stood true for in PHP versions from 5.6 up to 7.4!