I have a code-
public class Hello
{
void create()
{
Inner obj=new Inner();
obj.r=100; //Able to access private variable x
obj.display(); //displays 100
}
class Inner
{
private int r=45;
void display()
{
System.out.println("r is : "+r);
}
}
public static void main(String[] args)
{
Hello ob=new Hello();
ob.create();
}
}
In the above code,by creating an instance of the inner class,we are able to access the private variable defined in that class.But this is not in the case of inheritance.Why it is so?For e.g.,in this code-
class One
{
private int x;
void getData()
{
x=10;
}
void display()
{
System.out.println("x is : "+x);
}
}
class Two extends One
{
int y;
void putData()
{
One o=new One();
o.x=13; //Error
}
}
public class File
{
public static void main(String[] args)
{
Two to=new Two();
to.putData();
}
}
What is the exact reason behind it?Thanks in advance...
See the Java Language Specification.
Otherwise, 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 (§7.6) that encloses the declaration of the member or constructor.
Meaning that a top-level class can access the private members of it's nested classes.
Or said another way: Private means private to the top-level class and all it's nested classes, not private to the nested class itself.
Related
I am just learning Java concepts.
Can anyone let me know why i am not able to run this program?
package innerClasses;
public class Test {
int i=10;
static int j=20;
public void m1() {
int k=30;
final int m=40;
class Inner {
public void m2() {
System.out.println(i);
}
}
}
public static void main(String[] args) {
Test t = new Test();
Test.Inner in = t.new Inner();
t.m1();
}
}
Can anyone let me know why i am not able to run this program?
The most basic reason is because of scope. In order to do
Test.Inner in = t.new Inner();
Inner must be defined in Test, but it is instead defined in m1 scope.
The class Inner is declared inside the method m1(), what makes it not available outside this method.
Your code has to look like the following to be able to run, although it will not print anything...
public class Test {
int i=10;
static int j=20;
public void m1() {
int k=30;
final int m=40;
}
class Inner {
public void m2() {
System.out.println(i);
}
}
public static void main(String[] args) {
Test t = new Test();
Test.Inner in = t.new Inner();
t.m1();
}
}
Replacing t.m1(); by in.m2(); will output 10.
EDIT
In case you have to create the inner class inside the method, make it like
public class Test {
int i=10;
static int j=20;
public void m1() {
int k=30;
final int m=40;
class Inner {
public void m2() {
System.out.println(i);
}
}
// this is what makes it run
Inner myInner = new Inner();
myInner.m2();
}
public static void main(String[] args) {
Test t = new Test();
t.m1();
}
}
to compile and run.
IMHO this is not a good way to go...
A method inner class is only visible to that method only so you can't use this at any other location.
for using this class you have to declare it outside of the method.
You cannot compile it as the scope of Inner class is the m1 method.
If you want to be able to create instances of Inner class you can define it directly inside the Test:
public class Test {
int i=10;
static int j=20;
public void m1() {
int k=30;
final int m=40;
}
// On the Test class level
class Inner {
public void m2() {
System.out.println(i);
}
}
public static void main(String[] args) {
Test t = new Test();
Test.Inner in = t.new Inner();
t.m1();
in.m2(); // prints 10
}
}
Another feature provided by Java is to use anonymous classes. It can be created by implementation of some Interface:
// Define an interface to be able to implement it inside the method
interface Inner {
void m2();
}
public class Test {
int i=10;
static int j=20;
public void m1() {
int k=30;
final int m=40;
// Implement interface and call method on it
// Functional style:
((Inner) () -> System.out.println(i)).m2();
// Legacy style:
new Inner() {
#Override
public void m2() {
System.out.println(i);
}
}.m2();
}
public static void main(String[] args) {
Test t = new Test();
t.m1(); // prints 10 twice
}
}
or extending some class:
// A class we going to extend
class Inner {
void m2() {
System.out.println(11);
}
}
public class Test {
int i=10;
static int j=20;
public void m1() {
int k=30;
final int m=40;
// Extend inner class and call method on it
new Inner() {
void m2() {
System.out.println(i);
}
}.m2();
}
public static void main(String[] args) {
Test t = new Test();
t.m1(); // prints 10, not 11
}
}
So the best way for you depends on what code design do you want to get finally.
Your class Inner is what the JLS calls a Local Class (14.3. Local Class Declarations).
The scope of a Local Class is defined as (6.3. Scope of a Declaration):
The scope of a local class declaration immediately enclosed by a block (§14.2) is the rest of the immediately enclosing block, including its own class declaration.
The scope of a local class declaration immediately enclosed by a switch block statement group (§14.11) is the rest of the immediately enclosing switch block statement group, including its own class declaration.
In your case it is declared in a block, which is the body of your method. So the scope where your class is visible is the rest of this method body.
As the type Inner is not visible in main(), you cannot use it there. You could create instances of it and use them within m1(), though.
The very basic reason for compile time error is "Scope".
As per your code, class Inner is defined inside method m1 (this class is called Local class/method local class),so if you observe the scope of method variable, its within the declared method only and we cannot access any method variable outside that method and this is reason, the scope of class Inner is limited to the m1 method
so if you want to instantiate class Inner and invoke its methods then you must do it in m1 method (in code , you are trying to create class Inner object outside method m1, which is not possible) hence the code would be
public class Test {
int i = 10;
static int j = 20;
public void m1() {
int k = 30;
final int m = 40;
class Inner {
public void m2() {
System.out.println(i);
}
}
Inner in = new Inner();
in.m2();
}
public static void main(String[] args) {
Test t = new Test();
t.m1();
}
}
some more info , the local classes can be used when any repeated functionality is required inside a method (as nested methods are not allowed in java, so we can create inner class) and off course if we are not interested to create class level method for example
class Outer {
public void cal() {
class Inner {
public void sum(int x, int y) {
System.out.println("sum : "+(x+y));
}
}
Inner i= new Inner();
i.sum(10, 20); //sum is repeatdly needed in between code
i.sum(100, 200);
i.sum(1000, 2000);
i.sum(10000, 20000);
}
}
public class TestClass {
public static void main(String[] args) {
new Outer().cal();
}
}
abstract class Person {
abstract void eat();
}
class TestAnonymousInner {
public static void main(String args[]){
Person p=new Person() {
void eat(){System.out.println("nice fruits");}
};
p.eat();
}
}
Internal class generated by the compiler
static class TestAnonymousInner$1 extends Person
{
TestAnonymousInner$1(){}
void eat()
{
System.out.println("nice fruits");
}
}
For which reason does the compiler create the anonymous class as static? What would happen if it's non-static?
The code as shown creates an anonymous class in a static context. An inner class (or non-static nested class) needs to have a reference to the enclosing object(*). In this case there is no enclosing object because it is created in a static method, so using a static nested class is the only valid option.
This can easily be demonstrated by transforming your example to
public class TestInner {
public static void main(String args[]){
Person p = new Testperson();
p.eat();
}
public class Testperson extends Person {
void eat() {
System.out.println("nice fruits");
}
}
}
Compiling this will yield the error
non-static variable this cannot be referenced from a static context
While it will compile just fine if you change it to:
public class TestInner {
public static void main(String args[]){
Person p = new Testperson();
p.eat();
}
public static class Testperson extends Person {
void eat() {
System.out.println("nice fruits");
}
}
}
*: The compiler will modify the constructor(s) of an inner class to accept the enclosing object as a parameter, and constructor calls will be rewritten to pass this as the value of that parameter. This is not the case for static nested classes.
I have two nested classes inside a class with the outer class extending another class. The structure is something like this.
public class EXTENSION_CLASS
{
public int Get_Value()
{
return(100);
}
}
public class OUTER extends EXTENSION_CLASS
{
public static class NESTED1
{
public void Method1()
{
int value=0;
value=Get_Value();
System.out.println("Method1: "+value);
}
}
public static class NESTED2
{
NESTED1 Nested1_Instance=new NESTED1();
public void Method2()
{
Nested1_Instance.Method1();
}
}
public void run()
{
NESTED2 Nested2_Instance=new NESTED2();
Nested2_Instance.Method2();
}
public static void main (String[] args)
{
OUTER New_Class=new OUTER();
New_Class.run();
}
}
I'm expecting the output: "Method1: 100". But, am getting the output: "OUTER.java:16: error: non-static method Get_Value() cannot be referenced from a static context value=Get_Value();". How can i make this working?
Cheers !
Rajesh.
Remove the static modifier from the declaration of NESTED1 and NESTED2, like so:
public class NESTED1
If you want keep the nested classes static, you will have to create an instance of OUTER in the Method1() to access Get_Value().
public void Method1()
{
int value=0;
OUTER outer = new OUTER();
value=outer.Get_Value();
System.out.println("Method1: "+value);
}
You're trying to make a static reference to a non-static member.
This means that you're trying to access a instance member from a static member of the class.
To fix the issue, remove the static modifier from both the NESTED1 and NESTED2 clases.
Alternately, if you do not wish to remove the static modifier, you will have to create an object of the OUTER or EXTENSION_CLASS classes and then invoke Get_Value() using the object.
For example:
public void Method1()
{
int value=0;
EXTENSION_CLASS ext = new EXTENSION_CLASS ();
value=ext.Get_Value();
System.out.println("Method1: "+value);
}
OR
public void Method1()
{
int value=0;
OUTER outer = new OUTER();
value=outer.Get_Value();
System.out.println("Method1: "+value);
}
The error says every thing. You can not call non-static methods from static methods / class.
To make it work, Simply add static keyword to 'Get_Value' method in EXTENSION_CLASS.
Why doesn't a static block in the class get executed when I don't create a reference variable for an object (anonymous) of that class?
For example, let us consider this simple class:
public class StaticDemo {
private static int x;
public static void display(){
System.out.println("Static Method: x = "+x);
}
static {
System.out.println("Static Block inside class");
}
public StaticDemo(){
System.out.println("Object created.");
}
}
Another class using it:
public class UseStaticDemo {
public static void main(String[] args) {
StaticDemo Obj = new StaticDemo();
Obj.display();
System.out.println("------------");
new StaticDemo().display();
}
}
Output:
Static Block inside class
Object created.
Static Method: x = 0
------------
Object created.
Static Method: x = 0
A static initializer block only runs once, when the class is loaded and initialized.
Also, static methods have absolutely no relation to any instances. Doing
new StaticDemo().display();
is pointless and unclear.
class outer
{
public void outerfunction()
{
private class inner // Line-1
{
public void showinner()
{
System.out.println("I am in Inner Class");
}
}
}
}
Line-1 : This Line gives error.
I know if I write abstract or Final for class inner. then,it is fine. Why class inner can't be private ?
A private class is visible to all the methods and nested classes in the same file. Normally you would think of private as narrowing the scope of use, but in this case using private you are broadening the scope of where is the class is visible in a way Java doesn't support.
Making the method private is the same as doing this
class outer {
private class inner { // Line-1
public void showinner() {
System.out.println("I am in Inner Class");
}
}
public void outerfunction() {
}
}
Which looks fine until you consider that a nested class can use the values in it's outer context.
class outer {
public void printInner() {
// accessible in the same .java file because we made it private
inner i = new inner();
i.showInner(); // what should `x` be?
}
public void outerfunction(final int x) {
private class inner { // Line-1
public void showinner() {
System.out.println("I am in Inner Class, x= " + x);
}
}
}
}