Accessing inner class methods on already created outer class object - java

Let's say I have class like this:
class Outer {
public void getOuterValue() { }
class Inner {
public void getInnerValue() { }
}
}
I understand that I could create an object of this class as:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
But let's suppose I am getting this object from some other method:
void someMethodSomewhere(Outer o) {
// How do I call getInnerValue() here using o?
}
Is there a way to call "getInnerValue" method using "o" in the scenario above?
Please let me know.

No. You need to have an instance of Inner to call methods on it.
An instance of the outer class is not enough (it would work the other way around: the inner class instance has a reference to the outer class instance).

void someMethodSomewhere(Outer o) {
// How do I call getInnerValue() here using o?
}
You can't. getInnerValue() is a method in Inner. Outer is not an Inner and does not have a reference to an Inner. When you are handed o, there is no way to navigate from that to any instance of Inner because there isn't one associated with o.

Related

A query about class nesting in java

public class Outer{
public class Inner{
}
}
public class Main {
public static void main(String[] args) {
Outer objOut = new Outer();
//Outer.Inner object1= objOut.new Inner(); // runes without a problem
//objOut.Inner object2= objOut.new Inner(); //gives error
}
}
This might sound little amateur but, What are the difference between Outer.Inner vs objOut.Inner.
You cannot use a variable name as the type of another variable, which is what you're trying to do with objOut.Inner. The type of the variable is Inner (or optionally Outer.Inner).
Because Inner is an inner class, it's associated with an instance of its outer class (its enclosing instance). When you create an instance of it, you can optionally¹ specify what object instance it's associated with, which is what you're doing with objOut.new Inner.
This example may help make it a bit clearer:
public class Example {
private String str;
public class Inner {
void show() {
// Show the string for the Example this Inner is part of
System.out.println(Example.this.str);
}
}
public Example(String s) {
this.str = s;
}
public static void main(String[] args) {
Example e1 = new Example("e1");
Example e2 = new Example("e2");
Inner i1 = e1.new Inner();
i1.show(); // "e1"
Inner i2 = e2.new Inner();
i2.show(); // "e2"
}
}
Live Copy
Notice how the i1 Inner instance gets e1 as its enclosing Example instance, and so sees e1's str, but i2 gets e2 as its enclosing instance so it sees e2's str.
I suggest this Java tutorial for more information.
¹ Sometimes it's not optional, such as in my Example class above, since where new Inner is used, there's no default instance it could use. It would be optional in an instance method of Example, but not in that static method.
This one :
Outer.Inner = objOut.new Inner();
will not compile but if you change it to :
Outer.Inner object = objOut.new Inner();
will mean creating an instance of inner class which has reference to Outer class - objOut will be instance of Outer class.
Also this :
objOut.Inner = objOut.new Inner();
will not compile since objOut which is the instance of Outer class does not have poperty Inner.
And it is not Outer class that knows the instance of Inner class - it is Inner class instance that knows the Outer class instance with which it was created.
EDIT
The line :
objOut.Inner object2= objOut.new Inner();
will not compile since Inner type identifer belongs to Outer class and not instance of this class.
Both don't compile.
To make the former compile, a variable should be declared, and the name to that variable should be given.
Outer.Inner obj = objOut.new Inner();
The latter wouldn't compile even if you did this step since objOut.Inner is neither a type (because the primary expression objOut is not a type) nor a valid name (because . is not allowed within an identifier (jls-3.8)).
A simplified rule (jls-14.4) for your case would be
LocalVariableType VariableDeclaratorId [= VariableInitializer];

Access methods within local inner classes in Java

Is there any way to access the methods of local inner classes in Java. Following code is the sample code that I tried before. According to that what is the mechanism to access the mInner() method?
class Outer{
int a=100;
Object mOuter(){
class Inner{
void mInner(){
int y=200;
System.out.println("mInner..");
System.out.println("y : "+y);
}
}
Inner iob=new Inner();
return iob;
}
}
class Demo{
public static void main(String args[]){
Outer t=new Outer();
Object ob=t.mOuter();
ob.mInner(); // ?need a solution..
}
}
As ILikeTau's comment says, you can't access a class that you define in a method. You could define it outside the method, but another possibility is to define an interface (or abstract class). Then the code would still be inside your method, and could access final variables and parameters defined in the method (which you couldn't do if you moved the whole class outside). Something like:
class Outer {
int a = 100;
public interface AnInterface {
void mInner(); // automatically "public"
}
AnInterface mOuter() { // note that the return type is no longer Object
class Inner implements AnInterface {
#Override
public void mInner() { // must be public
int y = 200;
System.out.println("mInner..");
System.out.println("y : " + y);
}
}
Inner iob = new Inner();
return iob;
}
}
class Demo {
public static void main(String[] args) { // the preferred syntax
Outer t = new Outer();
Outer.AnInterface ob = t.mOuter();
ob.mInner();
}
}
Note: not tested
Note that the return type, and the type of ob, have been changed from Object. That's because in Java, if you declare something to be an Object, you can only access the methods defined for Object. The compiler has to know, at compile time (not at run time) that your object ob has an mInner method, and it can't tell that if the only thing it knows is that it's an Object. By changing it to AnInterface, the compiler now knows that it has an mInner() method.
The scoping rules of a local class are pretty much the same as the scoping rules of a variable, that is, it is confined to the enclosing block.
The same way you cannot access variable iob from main, you cannot access local class Inner from main.
Outside the enclosing block, there's no difference between a local class and an anonymous class. Neither can be accessed. The difference is that within the enclosing block, the local class can be accessed by name, especially useful if you need to access it repeatedly, e.g. to create multiple instances.
The only way to interact with a local/anonymous class outside the enclosing block, is through any superclass or interface implemented by the class in question.
To access the inner class create an object of inner class..
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
from your example
outer t=new outer();
outer.inner inner1=t.new inner();
Hope this helps you...

Access outer class's methods after extending inner class

I know I can access methods of outer class from within the inner class.
Like the below class:
class outer {
void outerMethod() {}
class inner {
void innerMethod() {
outerMethod();
}
}
}
I want to know how can I do this if I extended the inner class?
I want to do the following:
class newClass extends outer.inner {
void innerMethod() {
outerMethod();
}
}
I want to be able to access method() from newClass
Instance of non-static inner class requires existence of outer class instance which it will belong to.
So to make class newClass extends outer.inner { compile you either need to
make inner class static, and remove requirement of existence of outer class instance (but this will also limit your class a little)
or ensure that inner will belong to some outer instance, which you can do by calling outerInstance.super() inside your constructor of your class which extends this inner class.
In case of option 2, probably simplest solution would be explicitly passing instance of outer to your class like
class newClass extends outer.inner {
private outer o;
public newClass(outer outerInstance) {
outerInstance.super();
this.o = outerInstance;
}
void innerMethod() {
o.outerMethod();
}
}
Now you can simply call your outerMethod() on passed instance of outer class.
But remember that calling outerMethod is possible only when this method has proper visibility for your newClass. So despite the fact that inner is able to use any method of its outer class your newClass may not have access to it.

How to access "this" reference of anonymous outer class in java

I have the following problem. Two nested anonymous types. I want to access "this" reference of the outer anonymous class inside the most inner class. Usually if one has anonymous nested class in a named outer class (lets call it "class Outer") he/she would type inside the nested class Outer.this.someMethod(). How do I refer the outer class if it's anonymous ?
Example Code:
public interface Outer {
void outerMethod();
}
public interface Inner {
void innerMethod();
}
...
public static void main(String[] args) {
...
new Outer() {
public void outerMethod() {
new Inner() {
public void innerMethod() {
Outer.this.hashCode(); // this does not work
} // innerMethod
}; // Inner
} // outerMethod
}; // Outer
...
} // main
The error I get is
No enclosing instance of the type Outer is accessible in scope
I know that I can copy the reference like this:
final Outer outerThisCopy = this;
just before instantiating the Inner object and then refer to this variable. The real goal is that I want to compare the hashCodes of outerThisCopy and the object accessed inside the new Inner object (i.e the Outer.this) for debugging purposes. I have some good arguments to think that this two objects are different (in my case).
[Context: The argument is that calling a getter implemented in the "Outer" class which is not shadowed in the "Inner" class returns different objects]
Any ideas how do I access the "this" reference of the enclosing anonymous type ?
Thank you.
You cannot access an instance of anonymous class directly from inner class or another anonymous class inside it, since the anonymous class doesn't have a name. However, you can get a reference to the outer class via a method:
new Outer()
{
public Outer getOuter()
{
return this;
}
public void outerMethod()
{
new Inner()
{
public void innerMethod()
{
getOuter().hashCode();
}
};
}
};

Implicit reference to an enclosing class in Java

Lets say I have a Outer class. Lets say there is a non static member class Inner. So an Outer instance will have a reference to an instance of Inner if the Outer class declares a field of type Inner and that is by definition. But how does Inner instance also has a implicit reference to Outer? When is this association created?
You have it the other way around:
public class Outer {
void foo() {
// In this Outer method, we have no implicit instance of Inner.
innerbar(); // Compiler error: The method bar() is undefined for the type Outer
Inner.this.innerbar();// Compiler error: No enclosing instance of the type Outer.Inner is accessible in scope
// instead, one has to create explicitly instance of Inner:
Inner inner1 = new Inner();
Inner inner2 = new Inner();
inner1.innerbar(); // fine!
}
class Inner {
void innerbar() {};
void callOuter () {
// But Inner has an implicit reference to Outer.
callMe();
// it works also through Outer.this
Outer.this.callMe();
}
}
void callMe() {}
}
From the Java language Spec
An instance i of a direct inner class C of a class O is associated
with an instance of O, known as the immediately enclosing instance of
i. The immediately enclosing instance of an object, if any, is
determined when the object is created (§15.9.2).
The code
class Outer {
class Inner {
void printOuterThis() {
System.out.println(Outer.this);
}
}
}
Outer.Inner oi = new Outer().new Inner();
is mostly equivalent to this:
class Outer {
static class Inner {
Outer outerThis;
public Inner(Outer outerThis) {
this.outerThis = outerThis;
}
void printOuterThis() {
System.out.println(outerThis);
}
}
}
public class Scratch {
public static void main(String[] args) {
Outer.Inner oi = new Outer.Inner(new Outer());
}
}
The compiler automatically emits code that does what happens in the second: a field (this$0 that holds the value of Outer.this) for the implicit reference and transforms all constructors of Inner and calls to them to add initialisation of this field.

Categories

Resources