The following Java program just calculates the area of a circle. It uses the concept of inner classes available in Java. One of the inner classes (FirstInner) inherits it's enclosing class named Outer and the SecondInner class derives the FirstInner in turn. The program is working just fine. There is no problem at all. Let's have look at it.
package innerclass;
import innerclass.Outer.SecondInner; // Need to be inherited.
import java.util.Scanner;
class Outer
{
protected double r;
public Outer()
{
}
public Outer(double r)
{
this.r=r;
}
public class FirstInner extends Outer
{
public FirstInner(double r)
{
super(r);
}
}
final public class SecondInner extends FirstInner
{
public SecondInner(double r)
{
Outer.this.super(r); //<-------------
}
public void showSum()
{
System.out.print("\nArea of circle = "+(Math.pow(r, 2)*Math.PI)+"\n\n");
}
}
}
final public class Main
{
public static void main(String[] args)
{
Scanner s=new Scanner(System.in);
System.out.print("\nEnter radius:->");
double r=s.nextDouble();
Outer o=new Outer();
SecondInner secondInner = o.new SecondInner(r);
secondInner.showSum();
}
}
Now in the SecondInner class, I'm qualifying it's super class which is the FirstInner class first with this and again with Outer like Outer.this.super(r); which simply looks like just super(r);.
The use of only super(r) rather than Outer.this.super(r); causes a compiler-time error indicating that "cannot reference this before supertype constructor has been called". Why is it so? I mean why I have to use Outer.this.super(r); rather than just super(r)?
One more point when I make the FirstInner class static, the program issues no compile-time error and allows to use just super(r) in place of Outer.this.super(r);. Why?
I get a different error from my Eclipse environment:
"No enclosing instance of type Outer is available due to some intermediate constructor"
This one is clearer and can be linked to the fact that you cannot instantiate a non-static inner class before the outer class has been instantiated.
Please see the example that is described here.
15.11.2 Accessing Superclass Members using super
From the java tut
http://download.oracle.com/javase/tutorial/java/javaOO/nested.html
An instance of InnerClass can exist only within an instance of
OuterClass and has direct access to the methods and fields of its
enclosing instance.
Going by that statement, the following approach makes sense. You are accessing the instance using "this" by resolving with the help of the class name, which is defined here
in primary expressions .
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#20860
class SecondInner extends FirstInner
{
public SecondInner(double r)
{
Outer.this.super(r); //<-------------
}
public void showSum()
{
System.out.print("\nArea of circle = "
+(Math.pow(r, 2)*Math.PI)+"\n\n");
}
}
}
For example if your SecondInner were to be declared within FirstInner it has to be accessed using FirstInner.this.super()
Related
I'm having trouble trying to implement this statement I read in Oracle's Docs about Inheritance when it comes to inner classes.
The statement :
A nested class has access to all the private members of its enclosing class—both fields and methods. Therefore, a public or protected nested class inherited by a subclass has indirect access to all of the private members of the superclass.
In order to test this out i.e. to see if I can achieve the above I created a top level class OC1 which had an inner class IC1 ,then I created another top level class OC2 which extended IC1.
Before I could even start writing a single method , the IDE stopped me at the OC2 class body itself saying
"No enclosing instance of type DataStructure is available due to some intermediate constructor invocation"
I read some other answers and most of them point to either
a) Changing the inner class to static Nested Class -- it resolves the error
b) The whole scenario is unnecessary and convoluted.
Here is the code:
public class DataStructure {
// Create an array
private final static int SIZE = 15;
private int[] arrayOfInts = new int[SIZE];
public DataStructure() {
// fill the array with ascending integer values
super();
for (int i = 0; i < SIZE; i++) {
arrayOfInts[i] = i;
}
}
//other methods
//IC1
protected class instanceArr{
private int a = 8;
private static final int B = 4;
protected instanceArr(){
}
protected void doSomething(){
System.out.println("arrayOfInts[] is accessible " + arrayOfInts[6]);
}
}
//main method
}
OC2
public class DataStructureChild extends DataStructure.instanceArr{
public DataStructureChild(){
}
}
I know that the scenario is not an ideal one but I don't want to change inner class to static nested class - it would defeat my purpose of basically trying to see whether arrayOfInts is accessible without OC1's instance in hand.
Am I misinterpreting this statement ? if not then kindly point me in the correct direction.
PS - this is my first question here - apologies in advance if some guidelines were flouted.
Yes, this is a Trap caused by Java's synthetic sugar. You think the inner-non-static-class have the default-no-arguments-constructor but that is wrong. Internally the constructor of IC1 have the OC1 as first argument in the constructor - even if you can not see it.
Thats why the OC2 constructor must use the OC1 as constructor-argument:
public DataStructureChild(DataStructure argument) {
}
Unfortunaltely this is not enougth, you need to get sure the argument is not-null:
public DataStructureChild(DataStructure argument) {
argument.super();
}
It looks very wierd but it works.
You can do this since you inherit access to the inner class of the parent.
class DataStructureChild extends DataStructure {
public DataStructureChild() {
}
public void foo() {
InstanceArr ins = new InstanceArr();
ins.doSomething();
System.out.println(ins.a);
}
}
But could you please give a link or explain where you read the following? A nested class has access to all the private members of its enclosing class—both fields and methods. Therefore, a public or protected nested class inherited by a subclass has indirect access to all of the private members of the superclass.
The first part I knew about. But I never considered a separate class extending another classes inner class. Especially since there is usually an implicit relationship between classes and their enclosed inner classes.
Edit:
I believe you misunderstood the statement.
It says that your subclass inherits the inner class. That is true.
It also says that once done you have access to the private values of the inherited inner class. That is also true as demonstrated above:
So it was just talking about access the inner class via inheritance, not extending it directly.
However, if you really want to do have that kind of inheritance relationship without passing references around, you can go this route.
public class Inheritance extends Outer.Inner {
public Inheritance() {
new Outer().super();
}
public static void main(String[] args) {
new Inheritance().start();
}
public void start() {
System.out.println(a);
method();
}
}
class Outer {
public Outer() {
}
protected class Inner {
protected int a = 10;
protected Inner() {
}
protected void method() {
System.out.println("This is a private message");
}
}
}
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...
//below class is the example where in subclass extends the innerclass and from the subclass i am trying to access the methods of outer class i.e encapsulating class of inner class.
package innerClass;
public class outterclass {
private int outer=24;
protected int get_outer(){
return outer;
}
protected static class innerclass{
private int outer=25;
protected int get_outer(){
return outer;
}
}
}
package innerClass;
public class subclass_B extends outterclass.innerclass {
void parent_class_info_fetch(){
System.out.println(get_outer());
//i want to access the outer class get_outer method and how do i achieve that?
}
public static void main(String[] args) {
InheritanceStaticInnerClass_B isb=new InheritanceStaticInnerClass_B();
isb.parent_class_info_fetch();
}
}
Your innerclass is not an inner class. It is a static nested class and bears no special relationship to its enclosing class. You cannot reach an instance of the enclosing class because no such instance is available to innerclass or its subclasses.
If innerclass was indeed inner, then you would have to instantiate it with an enclosing instance:
outterclass outer = new outerclass();
subclass_B b = outer.new subclass_B();
Then, in parent_class_info_fetch() you could write
outterclass.this.get_outer()
to reach that method.
Of course, there would be several layers of bad practices in such code, so consider this just an academic execrise.
You should also learn about the basic naming conventions in Java.
The class outterclass.innerclass is a static class field, which means you don't necessarily have an enclosing instance of outterclass. On the other hand, the method get_outer of outterclass is an instance method, so you'll need the enclosing instance to call it.
With the class hierarchy you have, you'd have to make get_outer static (which requires making outer static as well).
Oracle documentation(in below link) says that:
Non-static nested classes (inner classes) have access to other members
of the enclosing class, even if they are declared private.
But in below example I created an object objin (of inner class) and it couldn't access any of the method or variable of its enclosing outer class. Below is the code, could you any one clarify on the same?
http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
package Package_1;
public class Outer {
int k;
public void Multiply()
{
System.out.println("inside outer class' method multiply");
}
public class Inner {
int l;
public void Division()
{
System.out.println("inside inner class' method Divison");
}
}
}
Class with Main method
package Package_1;
public class D {
public static void main(String[] args) {
Outer objout = new Outer();
objout.k = 5;
objout.Multiply();
Outer.Inner objin = objout.new Inner();
objin.l = 7;
objin.Division();
}
}
With objin object I couldn't access that Multiple method in its enclosing class.
I see your "privates"!
From the code of the non-static nested class (inner class) you have access to both public and private members of the enclosing class.
But it's your "privates", not mine!
This is what you're thinking when you try do objin.Multiply(): you are accessing Multiply() as though it's a member of the inner class, but it's not. Remember, you can see it from within the code of the inner class, but it will not be exposed as though it's yours.
This is what the specification says
public class Outer{
private int x;
private void method(){
}
public void publicMethod(){}
public class Inner{
//has access to even private properties of x
method(); //can be called
//NOTE: Only has ACCESS and does not INHERIT those methods
}
}
What you are trying is to access the publicMethod() with the instance of Inner, which does not have any method of that name.
THE CRUX:
The non-static nested classes just has the access to all properties and methods of container class, but does not inherit those methods.
objin.Multiply() cannot work as the crux explains that Multiply() is defined on Outer and not Inner, so there is no method Multiply() on Inner
The documentation doesn't say that you can access to fields and methods of the outer class by using a reference to the inner class. So you can't do
objin.Multiply();
because Multiply is not a method of Inner. What you can do is:
public class Inner {
int l;
public void Division()
{
System.out.println("I can access the field k in outer: " + k);
System.out.println("I can access the method Multiply in outer (even if Multiply was private): ");
Multiply();
// which is a shortcut for
Outer.this.Multiply();
}
}
PS: please respect the Java naming conventions. Methods start with a lowercase letter.
You are trying to access the method by using instance of the Inner class object. It can be accessed outside only by Outer class method. You can call the method inside the class definition of the Inner class directly but not by using the instance of inner class. if you still want to do this try :
package Package_1;
public class Outer {
int k;
public void Multiply()
{
System.out.println("inside outer class' method multiply");
}
public class Inner {
int l;
public void Division()
{
System.out.println("inside inner class' method Divison");
}
public void Multiply() {
Outer.this.Multiply(); //Outer class method.
}
}
}
public class InnerClass {
class Inner
{
public void method()
{
System.out.println("Innerclass");
}
}
}
class Sample extends InnerClass.Inner
{
public static void main(String [] arg)
{
Sample s = new Sample(new InnerClass());
s.method();
}
//why is this mandatory???
Sample(InnerClass i) {
i.super();
}
#Override
public void method() {
System.out.println("derived class");
}
}
when i make a class that derives from an innerclass (Innerclass.Inner) default constructor doesn't works. later i came to know that it requires to include a constructor taking Enclosing class reference why is it so?
Non static inner classes in Java have an implicit reference to the enclosing instance. You can solve your problem with:
public class InnerClass {
static class Inner // can make it public too
{
public void method()
{
System.out.println("Innerclass");
}
}
}
Just don't expect to be able to call any methods on InnerClass without a specific instance.
Because non-static inner classes have an implicit member that points back to their outer class, and you can't create an instance of the inner class without giving it that pointer. If you directly create an instance of an inner class, you have to use new outer.Inner() (or it might be outer.new Inner(), I can never remember). But Sample isn't an inner class, it just inherits one, so the outer instance must be passed in its constructor to the base constructor. Thus, it needs to have some instance of outer available, or create it itself.