When I attempt to compile the following the code, I get the compilation error:
unexpected type System.out.println( new Test().C.i );
^
required: class,package
found: value
class Test {
class C {
static final int i = 0;
}
public static void main(String... z) {
System.out.println( new Test().C.i );
}
}
But, if I change new Test().C.i to new Test().new C().i it compiles just fine.
Why? If i is static in C, then I shouldn't have to instantiate C. I should just be able to call it through the class C, not a C object.
What am I missing?
The problem is that "." Identifier in the Java syntax expects the identifier to refer to a variable and not a type.
This is specified in 6.5.6.2. Qualified Expression Names of the JLS (among other places):
If Q is a type name that names a class type (§8 (Classes)), then:
If there is not exactly one accessible (§6.6) member of the class
type that is a field named Id, then a compile-time error occurs.
Otherwise, if the single accessible member field is not a class
variable (that is, it is not declared static), then a compile-time
error occurs.
Otherwise, if the class variable is declared final, then Q.Id denotes
the value of the class variable.
The type of the expression Q.Id is the declared type of the class
variable after capture conversion (§5.1.10).
If Q.Id appears in a context that requires a variable and not a value,
then a compile-time error occurs.
Otherwise, Q.Id denotes the class variable.
The type of the expression Q.Id is the declared type of the class
variable after capture conversion (§5.1.10).
Note that this clause covers the use of enum constants (§8.9), since
these always have a corresponding final class variable.
While I can definitely appreciate the logic of why you'd think that it'd work like that - I actually expected it to work as well - it's not a big deal: Since there is always exactly only one i you can refer to it by Test.C.i. If i is non-static new Test().new C().i would be the correct way to access it.
Another way to look at it is to read 15.8. Primary Expressions which has the actual syntax for primary expressions (which is what we deal with here): It allows ClassInstanceCreationExpression (which is why new Test().new C().i works) as well as FieldAccess (which works for Test.C.i because the "class" is resolved recursively - only the last identifier has to refer to a field then).
I think the reason why new Test().new C().i works is because class Test is a top-level class and is treated as static. If you were to change your inner class C to be static then new C().i would work.
However, you should NOT access static members in a non-static way.
To access your static field do:
System.out.println(C.i);
Edit:
For those saying that class Test is not static please refer to this stackoverflow answer.
All top-level classes are, by definition, static.
What the static boils down to is that an instance of the class can
stand on its own. Or, the other way around: a non-static inner class
(= instance inner class) cannot exist without an instance of the outer
class. Since a top-level class does not have an outer class, it can't
be anything but static.
Because all top-level classes are static, having the static keyword in
a top-level class definition is pointless.
Just to show you how dumb of an idea it is to access a static field this way I created the following project:
class Test {
class C {
static final int i = 0;
}
public static void main(String[] args) {
// BAD:
System.out.println(new Test().new C().i);
// Correct:
System.out.println(C.i);
}
}
If you compile the class and view it in jd-gui you can see how it was compiled:
class Test {
public static void main(String[] args) {
void tmp13_10 = new Test(); tmp13_10.getClass(); new C(); System.out.println(0);
System.out.println(0);
}
class C {
static final int i = 0;
C() {
}
}
}
Related
I have always thought that inner class CAN NOT refer non final variable defined in outer class
But, when I write the following code, it compiles correctly and can be run in Intellij Idea,
I am confused,could some one help explain why the following code works? thanks!
public class Outer {
/**
* non final variable greeting is used in inner class, non final is OK?
*/
private String greeting = "Greeting1";
/**
* non final variable s is used in inner class, non final is OK?
*/
public String doWork(String s) {
class Inner {
public String speak(String ss) {
return greeting + "--- " + s + "---" + ss;
}
}
Inner obj = new Inner();
return obj.speak("Inner");
}
public static void main(String[] args) {
Outer obj = new Outer();
//Can assign here.
obj.greeting="Greeting2";
System.out.println(obj.doWork("Outer"));
}
}
The Java Language Specification says:
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.
You most likely recalled/remembered an incorrect version of that. You might have mistook it as:
Any instance variable, 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.
greeting is a field (aka instance variable), so can be used in inner classes whether or not it is final or not.
ss, though it is a formal parameter, is effectively final, so it can be used in inner classes too. Note that the phrase "effectively final" has a formal definition in §4.12.4, but informally, it just means "you did not reassign it another value in this method" in this context.
See this post for why this restriction exists.
I am preparing for Java 11 certification and while revising Java concepts, I got trapped in one of the silly concept.
I know that OuterClass's instance fields could be accessed from an InnerClass using OuterClass.this.
Please help me to understand why we cannot re-assign a value to OuterClass's instance fields inside an InnerClass (outside a method or block).
public class OuterClass {
String outerInstanceField = "Outer instance field"; // Instance Field
class InnerClass {
OuterClass.this.outerInstanceField = "Inside Inner Class, now";
}
}
Above code throws error:
However, this works perfectly fine if the re-assignment is done either in a block or in the InnerClass method.
public class OuterClass {
String outerInstanceField = "Outer instance field"; // Instance Field
class InnerClass {
{
OuterClass.this.outerInstanceField = "Inside Inner Class, now";
System.out.println(OuterClass.this.outerInstanceField);
}
void print(){
OuterClass.this.outerInstanceField = "Inside Inner Class's method, now";
System.out.println(OuterClass.this.outerInstanceField);
}
}
public static void main(String[] args) {
OuterClass outerObject = new OuterClass();
InnerClass innerObject = outerObject.new InnerClass();
innerObject.print();
}
}
Output:
Nested Class class example
class OuterClass {
static String outerInstanceField = "Outer instance field"; // Static/Class Field
static class InnerClass {
OuterClass.outerInstanceField = "Inside nested Class, now"; // Compiler error
static {
OuterClass.outerInstanceField = "Inside nested Class's static block, now"; // works fine
System.out.println(OuterClass.outerInstanceField);
}
}
}
I might be wrong here, but where you first have this assignment is a completely non-dynamic (for lack of better word and because I don't want to use the in this context ambiguous word 'static') area. There you would define things about the current scope, like which fields this class has or which methods.
That's why the assignment to String outerInstanceField works, as you are in the Scope of the OuterClass and are defining how it is defined.
What you are doing in the Innerclass is actually dynamic, i.e. something that would be executed. But you cannot even tell, when. Is it at the time of class loading? When some object is created? You have no information about that.
You also cannot put for example an if or a loop there, which basically is the same.
In this second snippet you could for example also try to add a static before the block. This will also not work, because it will be executed when the class is loaded and then you cannot even have an instance of OuterClass.
Edit, as response to your comment: It would be nice if you added a small example of what you mean, so I can be sure but if I understand correctly, the problem is the following: The InnerClass in your example is not static. This means, it will always belong to exactly one instance of OuterClass. This is, why OuterClass.this is unambiguous and works. On the other hand, there can be an arbitrary number of InnerClass-Objects for one OuterClass Instance, i.e. InnerClass.this can not be determined uniquely and therefore does not work.
Considering below scenario:
public class A{
int x = 10;
}
class B extends A{
x = 0;
int y = x;
}
If we execute above code, we receive compiler error:
We cannot have isolated expressions outside the scope of a constructor, a method, or an instance/static initialization block.
So, the questions narrows down to whether variable assignment is an expression or statement.
In The Java™ Tutorials, under topic Expressions, Statements, and Blocks it is mentioned that assignment and declaration are statements.
Also,
Learning Java, by Patrick Niemeyer, Daniel Leuck
mentions,
Technically, because variable assignments can be used as values for further assignments or operations (in somewhat questionable programming style), they can be considered to be both statements and expressions.
So, I am considering it as special case of expression.
I was reading the question here : Java : in what order are static final fields initialized?
According to the answer
"except that final class variables and fields of interfaces whose
values are compile-time constants are initialized first ..."
I think this is not correct because the following will fail :
static {
String y = x;
}
public static final String x = "test";
In the static block, x is not recognized. Can anyone please comment if that answer is correct ?
The order of initialization doesn't change the fact that the JLS doesn't let you refer to variables before they're declared in various cases. This is described in JLS§8.3.3:
Use of class variables whose declarations appear textually after the use is sometimes restricted, even though these class variables are in scope (§6.3). Specifically, it is a compile-time error if all of the following are true:
The declaration of a class variable in a class or interface C appears textually after a use of the class variable;
The use is a simple name in either a class variable initializer of C or a static initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
That's why your code gets this compilation erorr:
error: illegal forward reference
The statement that static fields that are constant variables are initialized first is indeed defined in JLS§12.4.2:
Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC.
Then, initialize the static fields of C which are constant variables (§4.12.4, §8.3.2, §9.3.1).
...
Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.
As you can see, constant variables are initialized in step 6, but others in step 9.
This demonstrates the behavior:
public class Example {
static String y;
static {
y = foo();
}
static String foo() {
return x.toUpperCase();
}
public static final String x = "test";
public static void main(String[] args) throws Exception {
System.out.println(x);
System.out.println(y);
}
}
That compiles, and outputs:
test
TEST
In contast, if you change the x line so it's not constant anymore:
public static final String x = Math.random() < 0.5 ? "test" : "ing";
It compiles, but then fails because x is null as of y = foo();.
For the avoidance of doubt: I don't recommend using methods to initialize fields like that. :-)
As this answer states:
... they are initialized in the order in which they appear in the source.
You are absolutely right, your example fails, because you are trying to use a variable that is declared after the usage. Since static block are executed in order of the source code, you are absolutely correct and should suggest and edit for that answer, because this statement is invalid:
except that final class variables ... are initialized first.
Consider the int a variables in these classes:
class Foo {
public int a = 3;
public void addFive() { a += 5; System.out.print("f "); }
}
class Bar extends Foo {
public int a = 8;
public void addFive() { this.a += 5; System.out.print("b " ); }
}
public class test {
public static void main(String [] args){
Foo f = new Bar();
f.addFive();
System.out.println(f.a);
}
}
I understand that the method addFive() have been overridden in the child class, and in class test when the base class reference referring to child class is used to call the overridden method, the child class version of addFive is called.
But what about the public instance variable a? What happens when both base class and derived class have the same variable?
The output of the above program is
b 3
How does this happen?
There are actually two distinct public instance variables called a.
A Foo object has a Foo.a variable.
A Bar object has both Foo.a and Bar.a variables.
When you run this:
Foo f = new Bar();
f.addFive();
System.out.println(f.a);
the addFive method is updating the Bar.a variable, and then reading the Foo.a variable. To read the Bar.a variable, you would need to do this:
System.out.println(((Bar) f).a);
The technical term for what is happening here is "hiding". Refer to the JLS section 8.3, and section 8.3.3.2 for an example.
Note that hiding also applies to static methods with the same signature.
However instance methods with the same signature are "overridden" not "hidden", and you cannot access the version of a method that is overridden from the outside. (Within the class that overrides a method, the overridden method can be called using super. However, that's the only situation where this is allowed. The reason that accessing overridden methods is generally forbidden is that it would break data abstraction.)
The recommended way to avoid the confusion of (accidental) hiding is to declare your instance variables as private and access them via getter and setter methods. There are lots of other good reasons for using getters and setters too.
It should also be noted that: 1) Exposing public variables (like a) is generally a bad idea, because it leads to weak abstraction, unwanted coupling, and other problems. 2) Intentionally declaring a 2nd public a variable in the child class is a truly awful idea.
From JLS
8.3.3.2 Example: Hiding of Instance Variables This example is similar to
that in the previous section, but uses
instance variables rather than static
variables. The code:
class Point {
int x = 2;
}
class Test extends Point {
double x = 4.7;
void printBoth() {
System.out.println(x + " " + super.x);
}
public static void main(String[] args) {
Test sample = new Test();
sample.printBoth();
System.out.println(sample.x + " " +
((Point)sample).x);
}
}
produces the output:
4.7 2
4.7 2
because the declaration of x in class
Test hides the definition of x in
class Point, so class Test does not
inherit the field x from its
superclass Point. It must be noted,
however, that while the field x of
class Point is not inherited by class
Test, it is nevertheless implemented
by instances of class Test. In other
words, every instance of class Test
contains two fields, one of type int
and one of type double. Both fields
bear the name x, but within the
declaration of class Test, the simple
name x always refers to the field
declared within class Test. Code in
instance methods of class Test may
refer to the instance variable x of
class Point as super.x.
Code that uses a field access
expression to access field x will
access the field named x in the class
indicated by the type of reference
expression. Thus, the expression
sample.x accesses a double value, the
instance variable declared in class
Test, because the type of the variable
sample is Test, but the expression
((Point)sample).x accesses an int
value, the instance variable declared
in class Point, because of the cast to
type Point.
In inheritance, a Base class object can refer to an instance of Derived class.
So this is how Foo f = new Bar(); works okay.
Now when f.addFive(); statement gets invoked it actually calls the 'addFive() method of the Derived class instance using the reference variable of the Base class. So ultimately the method of 'Bar' class gets invoked. But as you see the addFive() method of 'Bar' class just prints 'b ' and not the value of 'a'.
The next statement i.e. System.out.println(f.a) is the one that actually prints the value of a which ultimately gets appended to the previous output and so you see the final output as 'b 3'. Here the value of a used is that of 'Foo' class.
Hope this trick execution & coding is clear and you understood how you got the output as 'b 3'.
Here F is of type Foo and f variable is holding Bar object but java runtime gets the f.a from the class Foo.This is because in Java variable names are resolved using the reference type and not the object which it is referring.
Clarification: this question is not about access modifier
Confirmed that B.m() and b.m() statements both works in the following code:
class A {
static void m() { //some code }
}
class B extends A {
}
class Example {
public static void main (String [] args) {
B.m(); // running A's m() static method
}
public void try() {
B b = new B();
b.m(); // running A's m() static method
}
}
My question is can we said "static method is inherited"?
if "inherited" is the correct term, if we add a method to B class we same signature of the static class:
class A {
static void m() { //some code }
}
class B extends A {
static void m() { //some code }
}
class Example {
public static void main (String [] args) {
B.m(); // running B's m() static method
}
public void try() {
B b = new B();
b.m(); // running B's m() static method
A a = new B();
a.m(); // running A's m() static method, no polymorphism
}
}
In this case, notice that we have no polymorphism, is it the correct term to said that "static method is inherited but not overridden, subclass static method hide superclass static method"?
Last doubt, for these 2 terms, "inherited" and "overriden", which one is directly tied to the term "polymorphism" ?
Yes, I think "inherit" is the correct term here, even if it's not as descriptive as it might be. From section 8.4.8 of the Java Language Specification:
A class C inherits from its direct superclass and direct superinterfaces all non-private methods (whether abstract or not) of the superclass and superinterfaces that are public, protected or declared with default access in the same package as C and are neither overridden (§8.4.8.1) nor hidden (§8.4.8.2) by a declaration in the class.
That doesn't specify instance methods, but there are specific restrictions on what is allowed to hide or override what, which wouldn't make sense if static methods were not inherited.
Really though, I would simply view static methods as "accessible without qualification" rather than anything else, given that they don't take part in polymorphism etc. I think it's worth being very clear about that - for example, one static method can hide an inherited one, but it can't override it.
In other words, while I think "inherit" is technically correct, I would try to avoid using it without any further explanation.
For your second question, I'd say that based on the above, overriding is tied to polymorphism, but inheriting isn't necessarily.
(I would also strongly advise you to avoid calling static methods "via" variables, and also to use the name of the class which declares the static method wherever you specify the name at all. I know that's not part of the question, but I thought I'd just add it anyway...)
I think trying to apply words like 'inherited' and 'overridden' to this sort of thing is not productive. It's misleading because it gives the impression there is something comparable of what goes on with virtual instance methods, and you point out there isn't.
(But as Jon Skeet points out, the Java language spec doesn't agree with me, it groups these together in the same section.)
Guys I would like to share my knowledge in java with all java lovers out there!
First of all let me tell you that static members are those members which can be accessed directly without creating an object of that particular class, when static members of a class is used in some other class then it should be used by specifying the class name .(dot) static member's name(e.g. A.i in the following example), and also if any subclass class is getting inherited from a super class which has static members and if both subclass and super class are in the same package then that static members can be accessed from the base class without even using the class name of the super class. Please go through the
Example:
package myProg;
class A
{
static int i = 10;
A()
{
System.out.println("Inside A()");
}
}
class B extends A
{
public static void main(String[] args)
{
System.out.println("i = " + i); //accessing 'i' form superclass without specifying class name
System.out.println("A.i = " + A.i); //again accessing 'i' with the class name .(dot) static member 'i'
/*
we can also use the super class' object in order to access the static member compiler
will not show any error but it is not the exact way of using static members. static members are created
so that it could be used without creating the class object. see below the usage of object to use the
static member i.
*/
A obj = new A(); //creating class A object and A() also gets called
obj.i = 20;
System.out.println("obj.i = " + obj.i);
}
}
/*
This program was to show the usage of static member. Now, lets discuss on the topic of static member inheritance.
SO GUYS I WOULD LIKE TO TELL YOU THAT STATIC MEMBERS ARE NOT INHERITED. This undermentioned program is
to show the inheritance of static members.
*/
class A
{
static int i = 10; //initially the value of i is 10
static int j = 20; //lets use one more static member int j, just to see the value of it through class A, and B
static
{
/*
This is static initialization block(SIB) of class A,
SIB gets executed first in the order of top to bottom only one time
when the class is loaded.
*/
System.out.println("A-SIB");
}
}
class B extends A
{
static
{
i = 12;//trying to modify the i's value to 12
System.out.println("B-SIB");
}
}
class D extends A
{
static int k = 15;
static
{
System.out.println("D-SIB");
}
}
class C
{
public static void main(String [] arhs)
{
System.out.println("D.k: " + D.k);
/*here we are trying to access the static member k from class D,
it will try to search this class and then that class
will be loaded first i.e. SIB of class D will be loaded and SOP
statement of class D will be printed first. When the class loading
is done then the compiler will search for the static int k in class
D and if found SOP statement will be executed with the value of k.
*/
/*
ONE GROUND RULE: as soon as the compiler see this statement the compiler will load
class D into the memory, loading of class into memory is nothing but
storing all the static members (i.e. static constant & SIBs) into the
memory.
*/
System.out.println("B.i: " + B.i);
/*Now, this is what we are talking about... we think that static int i's
value is there in class B and when we write B.i it compiles and executes
successfully BUT... there compiler is playing a major role at this statement...
Try to understand now... we know that class B is the subclass of class A
BUT when the compiler sees this statement it will first try to search
the static int i inside class B and it is not found there, then since it is
the subclass of A, the compiler will search in class A and it is found
there. NOW, WHEN STATIC INT I IS FOUND IN CLASS A THE COMPILER WILL CHANGE
THIS STATEMENT B.i TO A.i and the class B WILL NOT AT ALL BE LOADED INTO
THE MEMORY BECAUSE STATIC I IS ONLY PRESENT IN CLASS A. But in the previous
statement static int k is present inside class D so when we try to access k's value
the class D will be loaded into memory i.e. SIB will be executed and then
the SOP statement of the value of k. USING B.i IS NOT WRONG BUT COMPILER
ASSUMES THAT THE PROGRAMMER HAS MADE A MISTAKE AND IT REPLACES THE CLASS NAME
B.i TO A.i. Thus this show that static members are not inherited to the subclass.And
therefore the vaue of i will NOT BE CHANGE TO 12 AS YOU CAN SEE IN THE SIB OF
CLASS B, it will be 10 only..
*/
System.out.println("A.j: " + A.j);//this statement will be executed as it is, compiler will not make
System.out.println("A.i: " + A.i);//any modifications to these statements.
System.out.println("B.j: " + B.j);//again compiler will modify this statement from B.j to A.j
}
}
Guys if you still have any confusion mail me at this email-id:
pradeep_y2k#yahoo.co.in
Regards
Pradeep Kumar Tiwari
Ok static methods cannot be overridden but can be redefined in other words its called hiding
check this http://www.coderanch.com/how-to/java/OverridingVsHiding they explain pretty well