If a class is private then must the constructor be private as well?
No, there is no such restriction. See JLS ยง8.8.3. Constructor Modifiers.
It's worth pointing out that only a nested class can be declared private. The JLS permits the constructors for such a class to use any valid access modifiers.
If you mean nested class, the answer is no. Making the inner class private makes it only usable within the outer class.
Edit: It appears that outer classes have full access to the innards of the inner classes regardless of their access modifiers. This invalidates my above reasoning, but regardless, there is no such restriction. Curiously though, now it appears that if the inner class is private, its constructor is essentially private, regardless of its access modifier, since noone else can call it.
No it hasn't. On the contrary, if you create an instance of the inner class using a private constructor (which is default for a private class) from the outer class Java will create an additional class to prevent access violation and keep JVM happy
If you compile this class
class Test {
private class Test2 {
Test2() {
}
}
Test() {
new Test2();
}
}
javac will create Test.class, Test#Test2.class
and if you compile this class
class Test {
private class Test2 {
}
Test() {
new Test2();
}
}
javac will create Test.class, Test#Test2.class, Test$1.class
No it is not fix, you can set it private/public/any you want.
But in some case I prefer to make constructor private, when you don't want to allow other classes to create object of this class. then in that case you can do something like this, by setting constructor private.
private class TestClass{
private TestClass testClass=null;
private TestClass(){
//can not accessed from out side
// so out side classes can not create object
// of this class
}
public TestClass getInstance(){
//do some code here to
// or if you want to allow only one instance of this class to be created and used
// then you can do this
if(testClass==null)
testClass = new TestClass();
return testClass;
}
}
Btw it depends on your requirement.
It does not have to be private. But it can. Example:
public class Outer {
// inner class with private constructor
private class Inner {
private Inner() {
super();
}
}
// this works even though the constructor is private.
// We are in the scope of an instance of Outer
Inner i = new Inner();
// let's try from a static method
// we are not in the scope of an instance of Outer
public static void main(String[] args) {
// this will NOT work, "need to have Inner instance"
Inner inner1 = new Inner();
// this WILL work
Inner inner2 = new Outer().new Inner();
}
}
// scope of another class
class Other {
// this will NOT work, "Inner not known"
Inner inner = new Outer().new Inner();
}
It doesn't make a difference if you use private or public constructor on private inner classes. The reason is that the inner class instance is part of the outer class instance. This picture says it all:
Note that we are talking about an inner class. If the nested class was static, the official terminology is static nested class, which is different from an inner class. A public static nested class would be accessible without outer class instance just by calling new Outer.Inner(). See here for more information about inner- and nested classes. http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Related
I cannot figure out if this is a hidden feature I have never discovered or a bug from IntelliJ Idea.
Having this class,
public class StackOverflow {
private String abc;
public static class StackOverflowExtended extends StackOverflow {
public StackOverflowExtended() {
abc = "";
}
}
}
IntelliJ tells me that I cannot access abc because either it has private access or because I'm in a static context.
As soon as I access abc by super, it starts working.
public class StackOverflow {
private String abc;
public static class StackOverflowExtended extends StackOverflow {
public StackOverflowExtended() {
super.abc = "";
}
}
}
There's no bugs or hidden features going on. You're probably mixing up inheritance and inner classes.
A non-static inner class can access the variables of its outer class, even if they're private.
public class StackOverflow {
private String abc;
public class StackOverflowExtended extends StackOverflow {
public StackOverflowExtended() {
abc = "";
}
}
}
A static inner class cannot access the fields of its outer class, because it's static. It can exist without having an instance of its outer class.
The reason why super.abc works on the static inner class, is due to it being its subclass. Accessibility independent of its scope, is then again due to it being an inner class.
The scope and accessibility of any private member (field, constructor or method) is the complete body of its declaring class, including any nested classes.
If the inner class is non-static, it is bound to the instance of the outer class, so you can access the private instance variable.
In your case, the inner class is static, so you need to specify an object instance of the outer class, such as super (because in your case the inner class extends the outer class).
The only "weird" thing is that when you try to access it using this.abc, it fails because then apparently the rule that subclasses cannot access private members of their parents takes precedence.
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.
//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).
The inner class is the class defined inside a class, and the inner class can be declared as public, private, protected. If the inner class defined as private and protected, can outer class access the members of inner class? and can inner class access members of outer class?
If the inner class defined as private
and protected, can outer class access
the members of inner class?
Yes. These qualifiers will only affect the visibility of the inner class in classes that derive from the outer class.
Can inner class access members of
outer class?
Yes, including the ones declared private, just as any instance method can.
In general, you can (access private fields on inner classes and vice-versa). The following code compiles under Eclipse:
public class Outer {
private int x;
public void f() {
Inner inner = new Inner();
inner.g();
inner.y = 5;
}
private class Inner {
private int y;
public void g() { x = 5; }
}
}
That said, you can configure your IDE/compiler to treat accesses to such fields as errors (in Eclipse this setting is called "Access to non-accessible member of an enclosing type", under Preferences -> Java -> Compiler -> Error/Warnings -> Code Style)
Explanation is in context of regular inner class[Regular inner classes cannot have static members declared inside them]
You can access any field of outer class from inner class directly.
class Outer {
private static int x = 0;
class Inner {
void print() {
System.out.println(x); // x can be directly accessed
}
}
public static void main(String[] args) {
new Outer().new Inner().print();
}
}
Even Outer class can access any field of Inner class but through object of inner class.
class Outer {
private class Inner {
private int x = 10;
}
void print() {
Inner inner = new Inner();
System.out.println(inner.x);
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.print();
}
}
"A nested class is a class defined
within another class. A nested class
should exist only to serve its
enclosing class. If a nested class
would be useful in some other context,
then it should be a top-level class.
There are four kinds of nested
classes: static member classes,
nonstatic member classes, anonymous
classes, and local classes. All but
the first kind are known as inner
classes."
(Joshua Bloch, from the book Effective Java.)
As for your questions: it is very easy to test by yourself. But the answer is yes (even for private members), as long as you are not trying to access a non-static member (other than from a reference) from a static context, or trying to access a member which is in an inaccessible scope.
That is, very much as one would expect =).
Yes! You can access both an inner class member from outer class, and vice-versa(irrespective of the access modifier).
However, for a static nested class you cannot access its field just by the field name, and you need to access it like
InnerClass.staticInnerField
though you can access the static fields of the outer class from the inner class directly by the fields names.
In Java, whenever an inner class instance is created, it is associated with an instance of an outer class. Out of curiosity, is it possible to associate the inner class with another instance of an outer class instead?
Yes, this is possible, although it sounds like a really bad idea to me. The idea is to set the otherwise final pointer to the outer instance using reflection (which is not guaranteed to succeed).
import java.lang.reflect.*;
public class Me {
final String name;
Me(String name) {
this.name = name;
}
class InnerMe {
String whoAreYou() {
return name;
}
}
InnerMe innerSelf() {
return new InnerMe();
}
public static void main(String args[]) throws Exception {
final Me me = new Me("Just the old me!");
final InnerMe innerMe = me.innerSelf();
System.out.println(innerMe.whoAreYou()); // "Just the old me!"
Field outerThis = innerMe.getClass().getDeclaredFields()[0];
outerThis.setAccessible(true);
outerThis.set(innerMe, new Me("New and improved me!"));
System.out.println(innerMe.whoAreYou()); // "New and improved me!"
}
}
The crucial part here is outerThis.setAccessible(true); -- a SecurityManager could enforce a policy that prohibits this from succeeding.
If you are speaking about instantiation time, it's possible using the following syntax:
public class Outer {
public class Inner {}
}
...
Outer o = new Outer();
Outer.Inner i = o.new Inner();
However, it's not possible (without setAccessible(true)) to associate the existing instance of inner class with the other instance of outer class, because the field pointing to the enclosing instance is final:
javap Outer$Inner
Compiled from "Outer.java"
public class Outer$Inner extends java.lang.Object{
final Outer this$0;
public Outer$Inner(Outer);
}
You should be able to, using reflection.
Just get all fields of the inner class (getClass().getDeclaredFields())and see which field holds the parent, then change it (using field.set(innerInstance, newParent). Before that you should make the field accessible - setAccessible(true))
Since the field appears to be final, you may take a look at this article to see how to circumvent that.
That said, you shouldn't need to do this at all - it would be a double ugly hack for no actual gain.