Is There a Way to Access the Outside?
public class OuterClass {
String data;
public void outerMethod(String data) {
this.data = data;
}
public enum InnerEnum {
OPTION1("someData"),
OPTION2("otherData");
InnerEnum(String data) {
// Does not work:
OuterClass.this.outerMethod(data);
}
}
}
As Eric said, enums are implicitly static. To do what you want, add a method, callOuterMethod(OuterClass oc) that calls oc.outerMethod(data) to do what you want:
public enum InnerEnum {
OPTION1("someData"),
OPTION2("otherData");
final String data;
InnerEnum(String data) {
this.data = data;
}
void callOuterMethod(OuterClass oc) {
oc.outerMethod(data);
}
}
Can't do that. The enum is implicitly static, even though you didn't declare it to be. See similiar question/answer:
"Nested enum types are implicitly static. It is permissable to explicitly declare a nested
enum type to be static."
In Java, are enum types inside a class static?
I believe you're confusing object instances with types. What you have declared is two nested types. That is not the same as two nested object instances.
The keyword this has no meaning when operating with types. It only takes on meaning when dealing with object instances. So, if you're trying to call an instance method of the outer type from the inner type then you need a reference to an instance of the outer type.
However, if you make the method of the outer type static then you can invoke the static method from the nested type without needing a reference to an instance of the outer type. Just keep in mind that if you do that, the method is "the same for all instances" - meaning that it shares any state with all instances of the OuterClass - so it can only access static members of the type.
In the example below, the outerMethod is declared static, and as such it can be called from the nested type without needing a reference to an instance of OuterClass. However, by doing that, it can no longer access the private instance member data (without a reference to an instance of course). You could declare a static member staticData and access that instead, but just keep in mind that that member will be shared by all instances of OuterClass, and by all invokations of outerMethod.
public class OuterClass {
String data; // instance member - can not be accessed from static methods
// without a reference to an instance of OuterClass
static String staticData; // shared by all instances of OuterClass, and subsequently
// by all invocations of outerMethod
// By making this method static you can invoke it from the nested type
// without needing a reference to an instance of OuterClass. However, you can
// no longer use `this` inside the method now because it's a static method of
// the type OuterClass
public static void outerMethod(String data) {
//this.data = data; --- will not work anymore
// could use a static field instead (shared by all instances)
staticData = data;
}
public enum InnerEnum {
OPTION1("someData"),
OPTION2("otherData");
InnerEnum(String data) {
// Calling the static method on the outer type
OuterClass.outerMethod(data);
}
}
}
Related
This is a short subquestion of a larger question I am working towards to.
Why can't I access the outer classes field through an instance of inner class in outer class in line 8?
The field is visible from inner class.
The problem persists for non-static methods in outer class.
The visibility of the field does not matter. Its visible from inner class either way.
The field could be accessed through a (private) getter in inner class, but one of the reasons for my problem is, that i would like to avoid those.
It's supposed to become a variation of the immutable builder pattern, so outer and inner class are developed in close coherence. That's the only reason I would dare to access the fields directly w/o getters.
public class OuterClass {
private static OuterClass instanceOf(InnerClass innerClass) {
return new OuterClass(innerClass.outerField);
}
public static OuterClass instanceOf(int arg) {
return new OuterClass(arg);
}
private int outerField;
private OuterClass(int arg) {
this.outerField = arg;
}
// Outer class getters...
public InnerClass build() {
return new InnerClass(this);
}
public class InnerClass {
private InnerClass(OuterClass outerClass) {
outerField = outerClass.outerField;
}
// Inner class setters......
public OuterClass build() {
return OuterClass.instanceOf(this);
}
} // End InnerClass
} // End OuterClass
Why can't I access the outer classes field through an instance of
inner class in outer class in line 8?
Because the field is a field of the class OuterClass and not of the class InnerClass. So to access it, you need an instance of the class OuterClass, not of the class InnerClass.
Sure, inside InnerClass definition, you can implicitly access all the fields of OuterClass. But that's only a matter of access from inside this context. You're not specifying what is the object of which you're trying to access the field, so the language automatically selects that for you. It's usually this.field, but in the case of a field from the containing class, it's actually OuterClass.this.field.
Once you're trying to indicate what is the object of which you're trying to access a field, rather than let the language implicitly select that object for you, well this object must actually be of the class that contains the field.
I have the following code for my class, with one parameter:
public class StudentChart {
public StudentChart(int[] Results) {
int[] results = Results;
}
How can I use results elsewhere in the class? I had assumed that variables and arrays declared in the constructor were global, but apparently not.
Also, what is the purpose of using the constructor to store data if it's not global?
You should check out some articles on scope in Java.
Instance Variables
Variables defined within in a class itself and not in a constructor or method of the class.They are known as instance variables because every instance of the class (object) contains a copy of these variables. The scope of instance variables is determined by the access specifier that is applied to these variables.
public class StudentChart{
//instance variable private is the "access modifier" you can make it public, private protected etc.
private int[] results;
Argument Variables
These are the variables that are defined in the header of constructor or a method. The scope of these variables is the method or constructor in which they are defined. The lifetime is limited to the time for which the method keeps executing. Once the method finishes execution, these variables are destroyed.
public int foo(int argumentVariable)
public class Foo{
public Foo(int constructorVariableArgument)
constructorVariable = constructorVariableArgument
}
Local Variables
A local variable is the one that is declared within a method or a constructor (not in the header). The scope and lifetime are limited to the method itself.
public void foo(){
int methodVariable = 0;
}
Loop Variables
Loop variables are only accessible inside of the loop body
while(condition){
String foo = "Bar";
.....
}
//foo cannot be accessed outside of loop body.
Make it a class variable. This way, when you call the constructor, you will fill the results array and can use it elsewhere in your class. You'll also want this class variable to be private.
public class StudentChart {
private int[] results;
public StudentChart(int[] Results) {
results = Results;
}
}
Suppose we have this class and its inner class:
/* Outer.java */
public class Outer {
private static class Inner {
private final Object foo;
public Inner(Object foo) {
this.foo = foo;
}
public Object getFoo() {
return foo;
}
}
Inner inner = parse(/* someMistery */);
// Question: to access foo, which is recommended?
Object bar = inner.getFoo();
Object baz = inner.foo;
}
I am surprised that inner.foo works.
Since foo is private, it can be accessed only through getFoo(), right?
Since foo is private, it can be accessed only through getFoo(), right?
In this case, Outer has access to it too, because Inner is a member of Outer.
6.6.1 says:
[If] the member or constructor is declared private, [then] access is permitted if and only if it occurs within the body of the top level class that encloses the declaration of the member or constructor.
Note that it's specified to be accessible within the body of the top level class that encloses the declaration.
This means, for example:
class Outer {
static class Foo {
private Foo() {}
private int i;
}
static class Bar {{
// Bar has access to Foo's
// private members too
new Foo().i = 2;
}}
}
Whether to use a getter or not is really a matter of taste. The important realization here is that outer classes have access to the private members of their nested classes.
As a recommendation, I would personally say:
If the nested class is private (only the outer class has access to it), I wouldn't bother even giving it a getter unless the getter does a computation. It's arbitrary, and somebody else can come along and choose not to use it. If the styles are mixed, the code has a vagueness. (Do inner.foo and inner.getFoo() really do the same thing? We have to go waste time examining the Inner class to find out.)
But you could go through a getter anyway if that's the style you are comfortable with.
If the nested class isn't private, use the getter so the style is uniform.
If you really want to hide the private members, even from the outer class, you can use a factory with a local or anonymous class:
interface Nested {
Object getFoo();
}
static Nested newNested(Object foo) {
// NestedImpl has method scope,
// so the outer class can't refer to it by name
// e.g. even to cast to it
class NestedImpl implements Nested {
Object foo;
NestedImpl(Object foo) {
this.foo = foo;
}
#Override
public Object getFoo() {
return foo;
}
}
return new NestedImpl(foo);
}
As a pedantic note, your static class Inner {} is technically a static nested class, not an inner class. class Inner {} (without static) would be an inner class.
This is specifically defined to be so:
The static keyword may modify the declaration of a member type C within the body of a non-inner class or interface T. Its effect is to declare that C is not an inner class.
It all depends on your piece of code from where do you want to access that object. Since it is a static nested class, so you will be able to access your object from either ways. Refer to this link http://www.javatpoint.com/static-nested-class for better understanding of inner classes.
I investigate java inner classes.
I wrote example:
public class Outer {
public Outer(int a){}
public class Inner {
public Inner(String str, Boolean b){}
}
public static class Nested extends Inner{
public static void m(){
System.out.println("hello");
}
public Nested(String str, Boolean b , Number nm) { super("2",true); }
}
public class InnerTest extends Nested{
public InnerTest(){ super("str",true,12); }
}
}
I invoke it from main using following string:
new Outer(1).new Inner("",true);
I see compile error:
java: no enclosing instance of type testInheritancefromInner.Outer is in scope
Can you explain me this situation?
UPDATE
Inner is an inner class. It can only be created when there is an enclosing instance of the class containing the Inner class definition.
However, you've created a static nested class, Nested, which extends from this class. When you try to invoke the super constructor
public Nested(String str, Boolean b , Number nm) { super("2",true); }
it will fail because the super constructor, for Inner, depends on an instance of Outer, which doesn't exist in the static context of the Nested class. Jon Skeet provides a solution.
An explanation of the solution appears in the JLS here.
Superclass constructor invocations may be subdivided:
Unqualified superclass constructor invocations begin with the keyword
super (possibly prefaced with explicit type arguments).
Qualified superclass constructor invocations begin with a Primary
expression.
They allow a subclass constructor to explicitly specify the newly
created object's immediately enclosing instance with respect to the
direct superclass (ยง8.1.3). This may be necessary when the superclass
is an inner class.
As Sotirios has said, your nested (not-inner) class doesn't implicitly have an instance of Outer to effectively provide to the Inner.
You can get round this, however, by explicitly specifying it before the .super part:
public Nested(String str, Boolean b, Number nm) {
new Outer(10).super("2", true);
}
Or even accept it as a parameter:
public Nested(Outer outer) {
outer.super("2", true);
}
However, I would strongly advise you to avoid such convoluted code. I avoid nested classes most of the time, named inner classes almost always, and I can't ever remember using a combination of them like this.
Consider the following:
public class OuterClass {
private String attribute = "outer";
class InnerClass {
private String attribute = "inner";
public doSomething() {
System.out.println(this.attribute);
System.out.println(OuterClass.this.attribute);
}
}
}
The InnerClass is not static and must be created against an instance of it's outer class.
new OuterClass().new InnerClass()
The regular innerclass holds a reference to the outer class in which it was created, that is accessible using Outer.this.myAttribute (particularly useful in this case where there is a "naming colision"
When creating an anonymous innerclass, it's the same: the anonymous innerclass created holds a reference to the outer class, this is why when declaring a predicate inside a method (anonymous method-local innerclass), we can still access, inside the innerclass, the variables of the outerclass without having to declare them final (while we should for variables passed as method parameters.
public class OuterClass {
// Do not need to be final because the innerclass keeps a reference to the outerclass
// even if it's an anonymous innerclass, it's still an innerclass
private String classAttribute = "classAttribute";
public Runnable doSomething() {
// Should be final because the variable lives on the stack and the reference to this object
// must be copied so that the String object is still accessible when the stack frame is destroyed
final String localVar = "localVar";
return new Runnable() {
#Override
public void run() {
System.out.println(classAttribute);
System.out.println(localVar);
}
};
}
}
And finally, we can declare constants in an interface, which are implicitly marked public static final. An object can be a constant.
Thus an object created as an anonymous innerclass is a legal constant for an interface.
For exemple, when using Guava, I usually declare in my interface functions and predicates which permits me to leverage the useful Guava functions like Maps.uniqueIndex(...).
public interface AlternativeNameable {
String getAlternativeName();
Function<AlternativeNameable,String> GET_ALTERNATIVE_NAME = new Function<AlternativeNameable,String>() {
#Override
public String apply(AlternativeNameable input) {
return input.getAlternativeName();
}
};
}
So you may ask yourself what is my question? Here it is:
When declaring an anonymous class as an interface constant (see my last code sample), on which outerclass does the anonymous innerclass holds a reference to?
Fields defined in interfaces always implicitly have the modifiers public static final. It's a constant, and as such it has no associated outer class.
Also, member types of interfaces are implicitly public and static, which holds true for anonymous classes as well.
Inner classes of interfaces are implicitly static and as such, do not require reference to outer class.