Its said that, statics are much comfortable with statics in java. I'm trying to achieve small thing there where I want to change outer's class static variable value using inner static class's instance for that specific instance only. I think its a ideal case. If not please share with me. And moreover all inner classes have access to outer class's members.
So here is my code.
package org;
import org.Outerclass.innerclass;
public class Outerclass {
static String name = "Europe";
String getname() {
return name;
}
public void setname(String name) {
this.name = name;
System.out.println(this.name);
}
void setstaticname() {
Outerclass.innerclass i = new Outerclass.innerclass();
i.name = "London"; // Error "name cannot be resolved or is not a field" ?
System.out.println(i.name);
}
static class innerclass {
void updatename() {
Outerclass o = new Outerclass();
o.setname("USA");
}
}
public static void main(String[] args) {
innerclass p = new innerclass();
System.out.println(p.name); // Error "name cannot be resolved or is not a field" ?
}
}
I have tried in two ways and vice versa but same errors. Any suggestions ?
name is a member of OuterClass. And you are trying to access it using innerclass instance. That's why you are getting this error.
Also what is this + here System.out.println(+p.name); ?
Edit:
From inner class you can access outer class static members just like below:
name = "";
or
Outerclass.name = "";
change +p.name to name or OuterClass.name. + inside System.out.println will give you another compile time error.
static members are not available in object level they are available in class level. static are initialized at compile time where object is created at run time
i.name should be Outerclass.name since name is a member of Outerclass and not innerclass
in your code, i is an instance of innerclass.
Related
I'm currently reading Effective Java by Joshua Bloch and I love it! But on page 112 (Item 24) Bloch writes:
A static member class is the simplest kind of nested class. It is best
thought of as an ordinary class that happens to be declared inside
another class and has access to all of the enclosing class’s members,
even those declared private.
And that really confuses me. I would rather say:
A static member class is the simplest kind of nested class. It is best
thought of as an ordinary class that happens to be declared inside
another class and has access to all of the enclosing class’s static members,
even those declared private.
Here is a snippet that illustrates my understanding of the quote:
public class OuterClass {
public void printMessage(String message) {
System.out.println(message);
}
private static class InnerClass {
public void sayHello() {
printMessage("Hello world!"); //error: Cannot make a static reference to the non-static method printMessage(String)
}
}
}
You can see that InnerClass's sayHello method does not have access to OuterClass's printMessage method as it is declared in a static inner class while the printMessage method is an instance method. It looks like the author suggests that a static member class can access nonstatic fields of the enclosing class. I am convinced that I have misunderstood something in his last sentence but I cannot figure out what. Any help will be appreciated!
edit: I changed the visibility of the two methods because it is irrelevant to my question. I'm interested in static members, not private members.
Just because InnerClass is static, doesn't mean it couldn't obtain a reference to an instance of OuterClass through other means, most commonly as a parameter, e.g.
public class OuterClass {
private void printMessage(String message) {
System.out.println(message);
}
private static class InnerClass {
private void sayHello(OuterClass outer) {
outer.printMessage("Hello world!"); // allowed
}
}
}
If InnerClass had not been nested inside OuterClass, it would not have had access to the private method.
public class OuterClass {
private void printMessage(String message) {
System.out.println(message);
}
}
class InnerClass {
private void sayHello(OuterClass outer) {
outer.printMessage("Hello world!"); // ERROR: The method printMessage(String) from the type OuterClass is not visible
}
}
Note the error message. It's not saying you don't have access. It's saying the method cannot be called. Instance methods don't mean anything without an instance to
call them on. What the error message is telling you is that you don't have that instance.
What Bloch is telling you is that if that instance existed, code in the inner class could call private instance methods on it.
Say we have the following class:
public class OuterClass {
public void publicInstanceMethod() {}
public static void publicClassMethod() {}
private void privateInstanceMethod() {}
private static void privateClassMethod() {}
}
If we try to call those private methods from some random class, we can't:
class SomeOtherClass {
void doTheThing() {
OuterClass.publicClassMethod();
OuterClass.privateClassMethod(); // Error: privateClassMethod() has private access in OuterClass
}
void doTheThingWithTheThing(OuterClass oc) {
oc.publicInstanceMethod();
oc.privateInstanceMethod(); // Error: privateInstanceMethod() has private access in OuterClass
}
}
Note that those error messages say private access.
If we add a method to OuterClass itself, we can call those methods:
public class OuterClass {
// ...declarations etc.
private void doAThing() {
publicInstanceMethod(); // OK; same as this.publicInstanceMethod();
privateInstanceMethod(); // OK; same as this.privateInstanceMethod();
publicClassMethod();
privateClassMethod();
}
}
Or if we add a static inner class:
public class OuterClass {
// ...declarations etc.
private static class StaticInnerClass {
private void doTheThingWithTheThing(OuterClass oc) {
publicClassMethod(); // OK
privateClassMethod(); // OK, because we're "inside"
oc.publicInstanceMethod(); // OK, because we have an instance
oc.privateInstanceMethod(); // OK, because we have an instance
publicInstanceMethod(); // no instance -> Error: non-static method publicInstanceMethod() cannot be referenced from a static context
privateInstanceMethod(); // no instance -> Error: java: non-static method privateInstanceMethod() cannot be referenced from a static context
}
}
}
If we add a non-static inner class, it looks like we can do magic:
public class OuterClass {
// ...declarations etc.
private class NonStaticInnerClass {
private void doTheThing() {
publicClassMethod(); // OK
privateClassMethod(); // OK
publicInstanceMethod(); // OK
privateInstanceMethod(); // OK
}
}
}
However, there's trickery going on here: a non-static inner class is always associated with an instance of the outer class, and what you're really looking at is:
private class NonStaticInnerClass {
private void doTheThing() {
publicClassMethod(); // OK
privateClassMethod(); // OK
OuterClass.this.publicInstanceMethod(); // still OK
OuterClass.this.privateInstanceMethod(); // still OK
}
}
Here, OuterClass.this is special syntax for accessing that outer instance. But you only need it if it's ambiguous, e.g. if the outer and inner classes have methods with the same name.
Note too that the non-static class can still do the things the static one can do:
private class NonStaticInnerClass {
private void doTheThingWithTheThing(OuterClass oc) {
// 'oc' does *not* have to be the same instance as 'OuterClass.this'
oc.publicInstanceMethod();
oc.privateInstanceMethod();
}
}
In short: public and private are always about access. The point Bloch is making is that inner classes have access that other classes don't. But no amount of access allows you to call an instance method without telling the compiler what instance you want to call it on.
The way you showed it requires inheritance. But methods and fields could be access in this way:
public class OuterClass {
private void printMessage(String message) {
System.out.println(message);
}
private static class InnerClass {
private void sayHello() {
OuterClass outer = new OuterClass();
outer.printMessage("Hello world!");
}
}
}
But, that the static inner class doesn't have access to the printMessage function doesn't have to do with that it is an inner class, but that it is static and can't invoke a non-static method. I think that the use of the word "static" you proposed was implicit in the first sentence. What he is pointing out, or chose to emphasize, is just that the inner class can still access private methods of its parent class. He might have just though it unnecessary or confusing to make the static/non-static distinction in the same sentence, too.
The way I see it, the text is absolutely right. Static member classes can access the private members of the enclosing classes (sort of). Let me show you an example:
public class OuterClass {
String _name;
int _age;
public OuterClass(String name) {
_name = name;
}
public static OuterClass CreateOuterClass(String name, int age) {
OuterClass instance = new OuterClass(name);
instance._age = age; // Notice that the private field "_age" of the enclosing class is visible/accessible inside this static method (as it would also be inside of a static member class).
return instance;
}
}
public class OuterClass {
private static class InnerClass {
public int id = 0;
}
private static InnerClass[] innerArr;
}
Need to get innerArr value with reflection in Java.
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class<?> cla = loader.loadClass("OuterClass");
Field innerArrRef = cla.getDeclaredField("innerArr");
innerArrRef.setAccessible(true);
OuterClass.InnerClass[] innerArrValue = (OuterClass.InnerClass[])innerArrRef.get(cla);
Above code doesn't work for InnerClass is a private class.
Let's adjust your OuterClass code a bit to make it more interesting: put in instance of InnerClass in the array:
private static InnerClass[] innerArr = { new InnerClass() };
Now you can't directly refer to the private type InnerClass in another class that is trying to get the static field using reflection. You can first refer to it as an array of Object.
public static void main(String[] args) throws Exception {
Class<?> cla = OuterClass.class;
Field innerArrRef = cla.getDeclaredField("innerArr");
innerArrRef.setAccessible(true);
Object[] innerArrValue = (Object[]) innerArrRef.get(cla);
You'll need to use reflection and the Class object to use the InnerClas type.
One way is to use the declaredClasses property of the OuterClass' class object:
Class<?> inner = cla.getDeclaredClasses()[0];
But if there's more than one member class, you need to loop through the array and search for the right one. Another way is to use the knowledge that javac will give your InnerClass a fully-qualified type name that looks like mypackage.OuterClass$InnerClass:
Class<?> inner = cla.getClassLoader().loadClass(cla.getName() + "$InnerClass");
Once you have the class object of the InnerClass, you can use reflection to access its field and methods:
Field id = inner.getField("id");
System.out.println("Inner id: " + id.getInt(innerArrValue[0]));
}
I'm learning how to use inner classes, but I'm encountering a troubling error when I try to compile it. I'm trying to see how inner and outer classes can use one another's variables and methods.
When I try to compile this code it says:
.../src/MyOuter.java:39: non-static variable inner cannot
be referenced from a static context
Code:
public class MyOuter{
private int x;
public MyInner inner = new MyInner();
public int getOuterX(){
return x;
}
private void doStuff(){
inner.go();
}
class MyInner{
public int getInnerX(){
return x;
}
void go(){
x = 42;
}
}
public static void main(String[] args) {
MyOuter outer = new MyOuter();
outer.doStuff();
System.out.println("outer.x = " + outer.getOuterX());
System.out.println("inner.x = " + inner.getInnerX());
}
}
Thanks in advance for the help!
Since getInnerX() method is defined in MyInner class. You can't access it directly without the object of MyInner class .So change the line
System.out.println("inner.x = " + inner.getInnerX());
to
System.out.println("inner.x = " + outer.inner.getInnerX());
As was said, you first need to extract the inner variable before referencing it the static main method. Try something like the following:
{
public static void main(String[] args) {
MyOuter outer = new MyOuter();
MyInner inner = outer.inner;
outer.doStuff();
System.out.println("outer.x = " + outer.getOuterX());
System.out.println("inner.x = " + inner.getInnerX());
}
From Understanding Instance and Class Members:
Fields that have the static modifier in their declaration are called static fields or class variables. They are associated with the class, rather than with any object. Every instance of the class shares a class variable, which is in one fixed location in memory. Any object can change the value of a class variable, but class variables can also be manipulated without creating an instance of the class.
Since your inner variable is associated with an object, it cannot be referenced like a static variable might be. Were it static, it would be shared between all instance of 'MyOuter' and would be accessible in the manner you have tried there.
I'm looking to do something like this in Java:
public OuterClass {
public innerClass = new Object() {
private var1;
public void myMethod() {
...
}
}
}
and use it like this:
OuterClass outer = new OuterClass();
outer.innerClass.myMethod();
The reason is to basiclly namespace some methods within the OuterClass to keep things organised.
I know I could create an instance of innerClass and assign it to a public instance variable of OuterClass but I'm looking for an inline way of doing it like above example. I don't want it to be possible to instantiate the innerClass more than once hence the inline approach.
This woule be similar to the following JavaScript:
var innerObject = new function() {
...
}
What you asked in the question title is possible, but unfortunately not what you really want.
In your code, the line with the declaration of the field innerClass misses a type for the field. With the rest of the code unchanged, there is only one possibility: Object.
So your code would read like this:
public OuterClass {
public Object innerClass = new Object() {
private var1;
public void myMethod() {
...
}
}
}
This is actually possible, but calling the method myMethod is not possible. When you access outer.innerClass, this expression is of type Object, which does not have a method myMethod, so the code won't compile.
You can however introduce an interface MyInnerInterface
interface MyInnerInterface {
void myMethod();
}
and change the type of the field to MyInnerInterface:
public OuterClass {
public MyInnerInterface innerClass = new MyInnerInterface() {
private var1;
public void myMethod() {
...
}
}
}
Then accessing the method is possible. However you have the drawback of the additional interface.
Also this code is unusual and I wouldn't consider it good. If you really want to have an inner class here, don't use an anonymous class, but a real class:
public OuterClass {
public class InnerClass {
private var1;
public void myMethod() {
...
}
}
public InnerClass innerClass = new InnerClass();
}
Still, using an inner class for "scoping" accesses from the outside is something I wouldn't do. Inner classes should usually be an implementing detail of the outer class and not be accessible to the public. Better think about how to separate your API into real co-existing classes (which of course might have references onto each other, and possibly access package-private members).
Have you tried:
public class OuterClass {
public static void main(String[] args) {
OuterClass o = new OuterClass();
o.new InnerClass().method();
}
class InnerClass {
public void method() {
//do something
}
}
}
That uses the syntax you propose, but does not address your requirement that you don't want more than one instance of InnerClass.
Given what I know of every other type of static feature of programming––I would think the answer is 'no'. However, seeing statements like OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass(); makes me wonder.
Yes, there is nothing in the semantics of a static nested type that would stop you from doing that. This snippet runs fine.
public class MultipleNested {
static class Nested {
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Nested();
}
}
}
See also
public static interface Map.Entry<K,V>
public static class AbstractMap.SimpleEntry<K,V>
Probably the most well-known nested type. Obviously instantiated multiple times.
Now, of course the nested type can do its own instance control (e.g. private constructors, singleton pattern, etc) but that has nothing to do with the fact that it's a nested type. Also, if the nested type is a static enum, of course you can't instantiate it at all.
But in general, yes, a static nested type can be instantiated multiple times.
Note that technically, a static nested type is not an "inner" type.
JLS 8.1.3 Inner Classes and Enclosing Instances
An inner class is a nested class that is not explicitly or implicitly declared static.
That is, according to JLS terminology, an inner class is one that isn't static. If it's static, then it's just a nested type.
So what does static mean?
static simply means that the nested type does not need an instance of the enclosing type to be instantiated.
See also
Java inner class and static nested class
Java: Static vs non static inner class
#polygenelubricants :
But in general, yes, a static nested
type can be instantiated multiple
times.
Just to be sure 100% of that I extended your snippet:
public class MultipleInner {
static class Inner {
private int state;
public int getState() { return state; }
public void setState(int state) { this.state = state; }
}
public static void main(String[] args) {
List<Inner> inners = new ArrayList<Inner>();
for (int i = 0; i < 100; i++) {
Inner inner = new Inner();
inner.setState(i);
inners.add(inner);
}
for (Inner inner : inners) {
System.out.println(inner.getState());
}
}
}
And of course the result is:
0
1
2
3
.
.
.
97
98
99
It is legal. The fact that the inner class is static gives you a benefit here; its instances are not bound to any instance of the containing class, so they can be freely instantiated (as long as the access qualifier allows it).
The price, however, is that the inner class can't use non static members/methods of the containing class.
Yeah you can make instances of it as many times as you want.
Maybe the reason why you see that, is because the programme thought about storing a reference somewhere. Though i agree with you seems strange :S
Inner class can use non static members/methods of containing class. It can use them only through an object reference of the enclosing class-
public class MultipleInner {
private int outerstate =10;
static class Inner {
private int state;
public int getState() { return state; }
public void setState(int state) { this.state = state; }
}
public static void main(String[] args) {
Inner inner = new Inner();
inner.setState(new MultipleInner().outerstate);
System.out.println(inner.getState());
}
}
So, inner class doesn't have to pay the price of not being able to access the non static members of the enclosing class.
Static nested classes are indeed instanced - they are, as said, top-level classes which live in the namespace of the 'outer' class, and obey static semantics respecting references to the 'outer' class. This code sample demonstrates :
public class OuterClass {
String outerStr = "this is the outer class!!" ;
public static class StaticNestedClass {
String innerStr = "default / first instance" ;
}
public static void main(String[] args) {
OuterClass.StaticNestedClass nestedObject1 = new OuterClass.StaticNestedClass();
OuterClass.StaticNestedClass nestedObject2 = new OuterClass.StaticNestedClass();
nestedObject2.innerStr = "second instance" ;
System.out.println(nestedObject1.innerStr) ;
System.out.println(nestedObject2.innerStr) ;
}
}
output:
default / first instance
second instance