I'm trying to make instances of anonymous classes using reflection. But ocassionally I've seen strange behaviour during instantination.
Please, look at these similar fragments of code
public class HideAndSeek {
#SuppressWarnings("unchecked")
public static void main(String[] args) throws IllegalAccessException, InstantiationException{
final String finalString = "I'm final :)";
Object object2 = new Object(){
{
System.out.println("Instance initializing block");
System.out.println(finalString);
}
private void hiddenMethod() {
System.out.println("Use reflection to find me :)");
}
};
Object tmp = object2.getClass().newInstance();
}
}
This code works well, and the output expected
Instance initializing block
I'm final :)
Instance initializing block
I'm final :)
After this I've decided to change code in simple way (just added java.util.Calendar)
import java.util.Calendar;
public class HideAndSeek {
#SuppressWarnings("unchecked")
public static void main(String[] args) throws IllegalAccessException, InstantiationException{
final String finalString = "I'm final :)";
final Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getTime().toString()); //works well
Object object2 = new Object(){
{
System.out.println("Instance initializing block");
System.out.println(finalString);
//simply added this line
System.out.println(calendar.getTime().toString());
}
private void hiddenMethod() {
System.out.println("Use reflection to find me :)");
}
};
Object tmp = object2.getClass().newInstance();
}
}
And here is output that I've got:
Wed Aug 17 02:08:47 EEST 2011
Instance initializing block
I'm final :)
Wed Aug 17 02:08:47 EEST 2011
Exception in thread "main" java.lang.InstantiationException: HideAndSeek$1
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at HideAndSeek.main(HideAndSeek.java:29)
As you may see - new instance hasn't been created.
Could anybody explain me, the reason of such changes?
Thanks
This is a very simple question with a very complex answer. Please bear with me as I try to explain it.
Looking at the source code where the exception is raised in Class (I'm not sure why your stack trace doesn't give the line numbers in Class):
try
{
Class[] empty = {};
final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
// removed some code that was not relevant
}
catch (NoSuchMethodException e)
{
throw new InstantiationException(getName());
}
you see that NoSuchMethodException is being rethrown as InstantiationException. This means there is not a no-arg constructor for the class type of object2.
First, what type is object2? With the code
System.out.println("object2 class: " + object2.getClass());
we see that
object2 class: class junk.NewMain$1
which is correct (I run sample code in package junk, class NewMain).
What then are the constructors of junk.NewMain$1?
Class obj2Class = object2.getClass();
try
{
Constructor[] ctors = obj2Class.getDeclaredConstructors();
for (Constructor cc : ctors)
{
System.out.println("my ctor is " + cc.toString());
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
which gives us
my ctor is junk.NewMain$1(java.util.Calendar)
So your anonymous class is looking for a Calendar to be passed in. This will then work for you:
Object newObj = ctors[0].newInstance(Calendar.getInstance());
If you have something like this:
final String finalString = "I'm final :)";
final Integer finalInteger = new Integer(30);
final Calendar calendar = Calendar.getInstance();
Object object2 = new Object()
{
{
System.out.println("Instance initializing block");
System.out.println(finalString);
System.out.println("My integer is " + finalInteger);
System.out.println(calendar.getTime().toString());
}
private void hiddenMethod()
{
System.out.println("Use reflection to find me :)");
}
};
then my call to newInstance won't work because there are not enough arguments in the ctor, because now it wants:
my ctor is junk.NewMain$1(java.lang.Integer,java.util.Calendar)
If I then instantiate that with
Object newObj = ctors[0].newInstance(new Integer(25), Calendar.getInstance());
a peek inside using the debugger shows that finalInteger is 25 and not the final value 30.
Things are slightly complicated because you're doing all of the above in a static context. If you take all your code above and move it into a non-static method like so (remember, my class is junk.NewMain):
public static void main(String[] args)
{
NewMain nm = new NewMain();
nm.doIt();
}
public void doIt()
{
final String finalString = "I'm final :)";
// etc etc
}
you'll find the ctor for your inner class is now (removing my added Integer reference):
my ctor is junk.NewMain$1(junk.NewMain, java.util.Calendar)
The Java Language Specification, section 15.9.3 explains it this way:
If C is an anonymous class, and the direct superclass of C, S, is an
inner class, then:
If the S is a local class and S occurs in a static context, then
the arguments in the argument list, if any, are the arguments to
the constructor, in the order they appear in the expression.
Otherwise, the immediately enclosing instance of i with respect to
S is the first argument to the constructor, followed by the
arguments in the argument list of the class instance creation
expression, if any, in the order they appear in the expression.
Why does the anonymous constructor take arguments at all?
Since you can't create a constructor for an anonymous inner class, the instance initializer block serves that purpose (remember, you only have one instance of that anonymous inner class). The VM has no knowledge of the inner class as the compiler separates everything out as individual classes (e.g. junk.NewMain$1). The ctor for that class contains the contents of the instance initializer.
This is explayed by JLS 15.9.5.1 Anonymous Constructors:
...the anonymous constructor has one formal parameter for each actual
argument to the class instance creation expression in which C is
declared.
Your instance initializer has a reference to a Calendar object. How else is the compiler going to get that runtime value into your inner class (which is created as just a class for the VM) except through the constructor?
Finally (yay), the answer to the last burning question. Why doesn't the constructor require a String? The last bit of JLS 3.10.5 explains that:
Strings computed by constant expressions are computed at compile time
and then treated as if they were literals.
In other words, your String value is known at compile time because it's a literal so it does not need to be part of the anonymous constructor. To prove this is the case we'll test the next statement in JLS 3.10.5:
Strings computed by concatenation at run time are newly created and
therefore distinct.
Change your code thusly:
String str1 = "I'm";
String str2 = " final!";
final String finalString = str1 + str2
and you'll find your ctor is now (in the non-static context):
my ctor is junk.NewMain$1(junk.NewMain,java.lang.String,java.util.Calendar)
Phew. I hope this makes sense and was helpful. I learned a lot, that's for sure!
Because in the second case there is no default constructor anymore.
In the first case the final string gets inlined because it is a constant.
In the second case the anonymous inner class has to accept instance of Calendar into its constructor to capture the state. You can easily confirm that doing this:
Object tmp = object2.getClass().getDeclaredConstructor(Calendar.class).newInstance(calendar);
Related
I'm trying to make instances of anonymous classes using reflection. But ocassionally I've seen strange behaviour during instantination.
Please, look at these similar fragments of code
public class HideAndSeek {
#SuppressWarnings("unchecked")
public static void main(String[] args) throws IllegalAccessException, InstantiationException{
final String finalString = "I'm final :)";
Object object2 = new Object(){
{
System.out.println("Instance initializing block");
System.out.println(finalString);
}
private void hiddenMethod() {
System.out.println("Use reflection to find me :)");
}
};
Object tmp = object2.getClass().newInstance();
}
}
This code works well, and the output expected
Instance initializing block
I'm final :)
Instance initializing block
I'm final :)
After this I've decided to change code in simple way (just added java.util.Calendar)
import java.util.Calendar;
public class HideAndSeek {
#SuppressWarnings("unchecked")
public static void main(String[] args) throws IllegalAccessException, InstantiationException{
final String finalString = "I'm final :)";
final Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getTime().toString()); //works well
Object object2 = new Object(){
{
System.out.println("Instance initializing block");
System.out.println(finalString);
//simply added this line
System.out.println(calendar.getTime().toString());
}
private void hiddenMethod() {
System.out.println("Use reflection to find me :)");
}
};
Object tmp = object2.getClass().newInstance();
}
}
And here is output that I've got:
Wed Aug 17 02:08:47 EEST 2011
Instance initializing block
I'm final :)
Wed Aug 17 02:08:47 EEST 2011
Exception in thread "main" java.lang.InstantiationException: HideAndSeek$1
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at HideAndSeek.main(HideAndSeek.java:29)
As you may see - new instance hasn't been created.
Could anybody explain me, the reason of such changes?
Thanks
This is a very simple question with a very complex answer. Please bear with me as I try to explain it.
Looking at the source code where the exception is raised in Class (I'm not sure why your stack trace doesn't give the line numbers in Class):
try
{
Class[] empty = {};
final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
// removed some code that was not relevant
}
catch (NoSuchMethodException e)
{
throw new InstantiationException(getName());
}
you see that NoSuchMethodException is being rethrown as InstantiationException. This means there is not a no-arg constructor for the class type of object2.
First, what type is object2? With the code
System.out.println("object2 class: " + object2.getClass());
we see that
object2 class: class junk.NewMain$1
which is correct (I run sample code in package junk, class NewMain).
What then are the constructors of junk.NewMain$1?
Class obj2Class = object2.getClass();
try
{
Constructor[] ctors = obj2Class.getDeclaredConstructors();
for (Constructor cc : ctors)
{
System.out.println("my ctor is " + cc.toString());
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
which gives us
my ctor is junk.NewMain$1(java.util.Calendar)
So your anonymous class is looking for a Calendar to be passed in. This will then work for you:
Object newObj = ctors[0].newInstance(Calendar.getInstance());
If you have something like this:
final String finalString = "I'm final :)";
final Integer finalInteger = new Integer(30);
final Calendar calendar = Calendar.getInstance();
Object object2 = new Object()
{
{
System.out.println("Instance initializing block");
System.out.println(finalString);
System.out.println("My integer is " + finalInteger);
System.out.println(calendar.getTime().toString());
}
private void hiddenMethod()
{
System.out.println("Use reflection to find me :)");
}
};
then my call to newInstance won't work because there are not enough arguments in the ctor, because now it wants:
my ctor is junk.NewMain$1(java.lang.Integer,java.util.Calendar)
If I then instantiate that with
Object newObj = ctors[0].newInstance(new Integer(25), Calendar.getInstance());
a peek inside using the debugger shows that finalInteger is 25 and not the final value 30.
Things are slightly complicated because you're doing all of the above in a static context. If you take all your code above and move it into a non-static method like so (remember, my class is junk.NewMain):
public static void main(String[] args)
{
NewMain nm = new NewMain();
nm.doIt();
}
public void doIt()
{
final String finalString = "I'm final :)";
// etc etc
}
you'll find the ctor for your inner class is now (removing my added Integer reference):
my ctor is junk.NewMain$1(junk.NewMain, java.util.Calendar)
The Java Language Specification, section 15.9.3 explains it this way:
If C is an anonymous class, and the direct superclass of C, S, is an
inner class, then:
If the S is a local class and S occurs in a static context, then
the arguments in the argument list, if any, are the arguments to
the constructor, in the order they appear in the expression.
Otherwise, the immediately enclosing instance of i with respect to
S is the first argument to the constructor, followed by the
arguments in the argument list of the class instance creation
expression, if any, in the order they appear in the expression.
Why does the anonymous constructor take arguments at all?
Since you can't create a constructor for an anonymous inner class, the instance initializer block serves that purpose (remember, you only have one instance of that anonymous inner class). The VM has no knowledge of the inner class as the compiler separates everything out as individual classes (e.g. junk.NewMain$1). The ctor for that class contains the contents of the instance initializer.
This is explayed by JLS 15.9.5.1 Anonymous Constructors:
...the anonymous constructor has one formal parameter for each actual
argument to the class instance creation expression in which C is
declared.
Your instance initializer has a reference to a Calendar object. How else is the compiler going to get that runtime value into your inner class (which is created as just a class for the VM) except through the constructor?
Finally (yay), the answer to the last burning question. Why doesn't the constructor require a String? The last bit of JLS 3.10.5 explains that:
Strings computed by constant expressions are computed at compile time
and then treated as if they were literals.
In other words, your String value is known at compile time because it's a literal so it does not need to be part of the anonymous constructor. To prove this is the case we'll test the next statement in JLS 3.10.5:
Strings computed by concatenation at run time are newly created and
therefore distinct.
Change your code thusly:
String str1 = "I'm";
String str2 = " final!";
final String finalString = str1 + str2
and you'll find your ctor is now (in the non-static context):
my ctor is junk.NewMain$1(junk.NewMain,java.lang.String,java.util.Calendar)
Phew. I hope this makes sense and was helpful. I learned a lot, that's for sure!
Because in the second case there is no default constructor anymore.
In the first case the final string gets inlined because it is a constant.
In the second case the anonymous inner class has to accept instance of Calendar into its constructor to capture the state. You can easily confirm that doing this:
Object tmp = object2.getClass().getDeclaredConstructor(Calendar.class).newInstance(calendar);
Trying to pass only the parent class data from the extended class in a function.
public class ParentClass {
String pageNo;
}
public class ExtendClass extends ParentClass {
String lineNo;
}
In another class i'm trying to
dosomething(...){
savePage((ParentClass)extendClass);
}
savePage(ParentClass pclass){
.....
}
But when i look into the function savePage arguments i can still see lineNo which i don't want to see.
UPDATE
I have added debug pic of the issue i was facing. Even after downcasting to PageApi, i still see "elements" which exist in BoardPage class
It seems to me that what you are trying to achieve is impossible.
If you create an instance of ExtendClass, then that instance always has a lineNo field.
When you explicitly cast or implicitly convert the type ExtendedClass to ParentClass, you don't change the actual instance in any way. At runtime, the instance has that lineNo field ... in all cases. Now the compiler won't let code within the body of the savePage method see or refer to that field (unless the code first casts the reference back to the type ExtendedClass), but the field will be there nonetheless.
You are examining the instances using a debugger. A debugger doesn't follow the rules able what fields should be visible. It sees everything, and it shows you everything. And, it clearly shows you the reality ... that the field is really there.
So ... is there a way to make the field go away entirely? Or hide it from the debugger?
Answers: No, and No.
(Warning: this is tangential to the original question, and probably beyond the OP's understanding.)
Should there be a way to make the field go away? From a language design perspective?
Answer: No.
Consider this code as a "thought experiment":
ExtendedClass ec = new ExtendedClass();
ec.lineNo = 42;
ParentClass pc = (ParentClass) ec; // Actually the cast is redundant
ExtendedClass ec2 = (ExtendedClass) pc;
System.err.println("The old line no is " + ec.lineNo);
System.err.println("The new line no is " + ec2.lineNo);
If (hypothetically) casting from ExtendedClass to ParentClass actually removed a field, then when you cast back to ExtendedClass the field value would no longer be there. But what should ec2.lineNo actually contain? And how could it be different to ec.lineNo ... unless we had actually created a completely new object when we did the type cast(s)?
Thinking it through, if an explicit or implicit type cast created a new object, then you couldn't effectively do polymorphism. Polymorphism depends on being able to operate on a given object from the viewpoints of either its true type or one of its supertypes. If creating that view actually creates a new object ... it simply doesn't work ... unless Java was a pure functional language; i.e. no mutation.
In short, while it might possibly be an attractive idea for a small number of use-cases, this idea would fundamentally break Java as an OO language.
This is my example for the short answer I gave above
import java.lang.reflect.Field;
public class Parenting {
static public class ParentClass {
String pageNo;
public ParentClass() {}
public ParentClass(final ParentClass pOriginal) { // copy CTOR
pageNo = pOriginal.pageNo;
}
}
static public class ExtendClass extends ParentClass {
String lineNo;
}
public static void main(final String[] args) throws IllegalArgumentException, IllegalAccessException {
final ParentClass pc = new ParentClass();
pc.pageNo = "page #7";
final ExtendClass ec = new ExtendClass();
ec.pageNo = "page#24";
ec.lineNo = "line #25";
analyze("Pure Parent", pc);
analyze("Cast Parent", ec);
analyze("Copy Parent", new ParentClass(ec));
}
static private void analyze(final String pTitle, final ParentClass pAnalyzeObject) throws IllegalArgumentException, IllegalAccessException {
System.out.println("Analyzing " + pTitle + ":");
Class<?> p = pAnalyzeObject.getClass();
while (p != Object.class) {
for (final Field f : p.getDeclaredFields()) {
System.out.println("\t" + p.getName() + "\t" + f.getName() + "\t\"" + f.get(pAnalyzeObject) + "\"");
}
p = p.getSuperclass();
}
}
}
I have a question when I saw "Instance variables can be declared in class level before or after use." in the site java_variable_types
I don't understand what is the class level and the meanning of this sequense.
I think they mean that this is legal:
public class Test {
private int someValue;
public int myMethod() {
return someValue + anotherValue;
}
private int anotherValue;
}
(And it is!)
However, I think it is a mistake for the site to describe this as "[i]nstance variables can be declared in class level before or after use".
The phrase "declared in class level" is bad English grammar.
The phrase "in class level" is ambiguous. It could mean declared in the body of a class. However, it could also mean declared as "class-level" (i.e. static) variables. (That is contradictory, and incorrect, but ...)
The phrase "before or after use" is ambiguous. It could mean before or after in the source code file. It could also mean in before or after in the temporal sense. (That would be incorrect. At runtime, all of an object's instance variables are declared and initialized before the code in a method or constructor body is executed.)
While what they are trying to say (I think) in that sentence is correct, they have expressed themselves poorly, and it is clearly causing confusion for some readers.
Instance variable val is declared in line #2( please note the marking) but referenced even before in line #1. You can remove comment from line #3 and comment line #2. Then also it will work.
It means variable val using in line #1 even before declare in case if line#2 consider using after if you consider line#3.
public class prog{
//private int val; //line# 3
public int getVal()
{
return val;//line# 1
}
private int val; //line# 2
prog()
{
val=0;
}
public static void main( String [] args)
{
prog obj= new prog();
System.out.println("val:"+obj.getVal());
}
}
While your reference does a good job of explaining it, I'll add some details for completeness.
An instance variable...
is declared at the class level
can have any visibility that is necessary (public, protected, private, or no modifier to signify package-private)
will receive an initial value after instantiation (that is, you don't have to instantiate the field with a value...but if you don't instantiate a reference value, you may run into a NullPointerException)
The phrase "before or after use" doesn't make much sense, but let's illustrate a scenario:
public class Foo {
private String word;
public void printTheWord() {
System.out.println(word);
}
}
word hasn't been instantiated, but we can use it since it's received an initial value of null. This means that we won't get the value we want, but it will compile.
Contrast this with a local variable. The below code won't compile because word hasn't been instantiated.
public class Foo {
public void printTheWord() {
String word;
System.out.println(word);
}
}
The phrase "before or after use." would mean that the instance variable, which is applicable to the class as a whole ,unlike local variable which is restricted only inside of that method.
It can be declared or initialized at the start of the class,which is generally the most likely way.
Other , inside of the class, it can be declared , after the call of the method using it.
Please find the below code snippet to understand the phrase:
public class InstanceVariable {
//declared before
int foo=4;
public void testInstanceVariableUse(){
System.out.println("The total value of the instance variable is "+ (foo+boo));
}
//declared after
int boo=5;
}
class TestInstanceVariable{
public static void main(String[] args){
InstanceVariable instanceVar = new InstanceVariable();
instanceVar.testInstanceVariableUse();
}
}
Output:
The total value of the instance variable is 9
The following does not compile, giving an 'illegal forward reference' message:
class StaticInitialisation {
static
{
System.out.println("Test string is: " + testString);
}
private static String testString;
public static void main(String args[]) {
new StaticInitialisation();
}
}
However, the following does compile:
class InstanceInitialisation1 {
{
System.out.println("Test string is: " + this.testString);
}
private String testString;
public static void main(String args[]) {
new InstanceInitialisation1();
}
}
But the following does not compile, giving an 'illegal forward reference' message:
class InstanceInitialisation2 {
private String testString1;
{
testString1 = testString2;
}
private String testString2;
public static void main(String args[]) {
new InstanceInitialisation2();
}
}
Why do StaticInitialisation and InstanceInitialisation2 not compile, while InstanceInitialisation1 does?
This is covered by section 8.3.3 of the JLS:
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.
Use of instance variables whose declarations appear textually after the use is sometimes restricted, even though these instance variables are in scope. Specifically, it is a compile-time error if all of the following are true:
The declaration of an instance variable in a class or interface C appears textually after a use of the instance variable;
The use is a simple name in either an instance variable initializer of C or an instance 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.
In your second case, the use isn't a simple name - you've got this explicitly. That means it doesn't comply with the second bullet in the second list quoted above, so there's no error.
If you change it to:
System.out.println("Test string is: " + testString);
... then it won't compile.
Or in the opposite direction, you can change the code in the static initializer block to:
System.out.println("Test string is: " + StaticInitialisation.testString);
Odd, but that's the way it goes.
Lets look at these two example, I guess this will make you clear.
public class InstanceAndSataticInit {
{
System.out.println("Test string is (instance init): " + this.testString);
}
static{
System.out.println("Test string is (static init ): " + InstanceAndSataticInit.testStringStatic);
}
public static String testStringStatic="test";
public String testString="test";
public static void main(String args[]) {
new InstanceAndSataticInit();
}
}
Output:
Test string is (static init ): null
Test string is (instance init): null
And
public class InstanceAndSataticInitVariableFirst {
public static String testStringStatic="test";
public String testString="test";
{
System.out.println("Test string is (instance init): " + this.testString);
}
static{
System.out.println("Test string is (static init ): " + InstanceAndSataticInitVariableFirst.testStringStatic);
}
public static void main(String args[]) {
new InstanceAndSataticInitVariableFirst();
}
}
output :
Test string is (static init ): test
Test string is (instance init): test
So you can say the sequence are like this.
Static variable will be created but not be initialized.
Static initialization will be executed according to the given sequence.
Non Static variable will be created but not be initialized.
Non Static initialization will be executed according to the given sequence.
By sequence I mean appearance in the code.
I guess this steps answer your two not working example StaticInitialisation and InstanceInitialisation2
But in case your second working example InstanceInitialisation1 by using this key word you are actually helping compiler to overlook the textual hierarchy. Same thing happen in case of static when I call InstanceAndSataticInit.testStringStatic in my first example InstanceAndSataticInit
Simple reason - it's too expensive or impossible to analyze and forbid all forward references. e.g.
{
print( getX(); ); // this.x
print( that().x ); // this.x
}
int x;
int getX(){ return x; }
This that(){ return this; }
The spec settles on forbidding some simple cases indicative of common programmer mistakes.
See also Recursive initializer works when I add "this"?
Here what we have to understand is that in 2nd code snippet You are using block and this keyword.
The block executes if object is created.
That means the object is created in heap area.
You are externally using this keyword to get a value of instance variable.
Here object created with default values that will return as value.
With out using this keyword you can't compile 2nd snippet also.
in java we are able to "invoke a static method with class name" and also "invoke a static method with an object"
what is the difference between "invoking a static method with class name" and "invoking a static method with an object" in java?
There is no difference but the recommendation is to call the static methods in a staic way i.e. using the ClassName. Generally static analayzers will report an error if you don't do so.
An important thing to understand here is that static method are stateless and hence calling them with an instance is confusing for someone reading your code. Because no matter what instance you use to call the static method, result will remain the same. This is because a static method belongs to a class but not to an object.
Internally, new ClassName().staticMethod(); is considered as ClassName.staticMethod(). So there is no difference. It just causes confusion.
Consider an example
public class StaticDemo {
static int staticVar = 10;
public static void main(String [] args){
System.out.println(new StaticDemo().staticVar);
System.out.println(StaticDemo.staticVar);
}
}
This outputs
10
10
`
even if you write new StaticDemo().staticVar, it will be considered as StaticDemo.staticVar. So there is no difference at all and always use the Class notation to avoid confusion.
There is no difference at all. But since static methods are at the class level, you can access them using the class name. Though invoking them using class object is possible, it creates a confusion. Why would you like to invoke them for every object if its value is going to be the same?
No, there is none. Apart from possible confusion... A reader of such code cannot reliably tell static from non static members/methods apart if you use an instance to access them:
public class X
{
public static final String foo = "foo";
public static String bar() { return "bar"; }
public static void main(final String... args)
{
final X x = new X();
System.out.println(X.foo); // "foo"
System.out.println(x.foo); // "foo" too -- same reference
System.out.println(X.bar()); // "bar"
System.out.println(x.bar()); // "bar" too -- same reference
}
}
As this is confusing, it is generally preferred to use the class to refer to such members/methods.
Static methods do NOT operate on a class. They are just bound to class instead of to member of that class. This means that they don't have access to any non static members of the class. Other than that, they are not very different than the non-static methods.
In SCJP guide book. having a example as following:
class Frog {
static int frogCount = 0; // Declare and initialize
// static variable
public Frog() {
frogCount += 1; // Modify the value in the constructor
}
}
class TestFrog {
public static void main (String [] args) {
new Frog();
new Frog();
new Frog();
System.out.print("frogCount:"+Frog.frogCount); //Access
// static variable
}
}
But just to make it really confusing, the Java language also allows
you to use an object reference variable to access a static member
Frog f = new Frog();
int frogs = f.frogCount; // Access static variable
// FrogCount using f
In the preceding code, we instantiate a Frog, assign the new Frog
object to the reference variable f, and then use the f reference to
invoke a staticmethod! But even though we are using a specific Frog
instance to access the staticmethod, the rules haven't changed. This
is merely a syntax trick to let you use an object reference variable
(but not the object it refers to) to get to a staticmethod or
variable, but the staticmember is still unaware of the particular
instance used to invoke the staticmember. In the Frog example, the
compiler knows that the reference variable f is of type Frog, and so
the Frog class staticmethod is run with no awareness or concern for
the Frog instance at the other end of the f reference. In other
words, the compiler cares only that reference variable f is declared
as type Frog.
I hope this will help you