While this is obviously a RTFM case, somehow I failed to find a concise source explaining it all.
public class Outer {
private class Inner {
}
}
Private class Inner is an inner class of a public class Outer.
My question is about visibility of Inner from outside `Outer'.
Should I be able to instantiate Inner in another class? If yes, are there any limitations (like this class being in the same package, etc.)?
Can Inner be used as a concrete type when using collections? For example, should I be able to declare ArrayList <Inner> in another class?
If another class extends Outer will Inner come along in terms of the above questions?
Inner is private, therefore only its parent, Outer, can do anything at all with it.
The "FM" in this case is the Java Language Specification. You want section 6.6.1 which includes:
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.
So the constructor can be called anywhere within the declaration of Outer (including within any other nested classes that Outer declares), but nowhere else. Access is not inherited - it's as simple as whether the source code that's trying to call the constructor is within the source code of Outer.
Related
This is maybe a dumb question, but I'm pretty surprised to see that using the private inner class as a generic type in the outer class isn't allowed.
If I make the inner class protected, it compiles fine.
Additionally, I have to precise Outer.Inner instead of just Inner, otherwise the inner class isn't found. This also looks a little weird.
Why can't Inner be private ? And why it is allowed to be protected ?
public class Outer extends AbstractSet<Outer.Inner> {
private static class Inner {
// ...
}
// ...
}
The error is:
Outer.java:3: error: Inner has private access in Outer
public class Outer extends AbstractSet<Outer.Inner> {
^
1 error
I'm using Java SE 17, but I think it doesn't matther much.
Note the meaning of private from the language spec §6.6.1, emphasis mine:
Otherwise, the member or constructor is declared private. Access is permitted only when the access occurs from within the body of the top level class or interface that encloses the declaration of the member or constructor.
The extends clause is not part of the class body. The syntax for a class declaration looks like this (Classes):
NormalClassDeclaration:
{ClassModifier} class TypeIdentifier [TypeParameters] [ClassExtends]
[ClassImplements] [ClassPermits] ClassBody
ClassBody:
{ {ClassBodyDeclaration} }
The "body" of the class refers strictly to the things inside the curly braces. Therefore, you cannot access the private class Inner in the extends clause.
If Inner is protected or package-private, on the other hand, then access is allowed, because both of them allows access from the same package.
Similarly, the scope of a member class declaration is the body of the class too (§6.3):
The scope of a declaration of a member m declared in or inherited by a class or interface C (§8.2, §9.2) is the entire body of C, including any nested class or interface declarations.
Therefore, the extends clause is not in scope of the Inner class, which is why you need to use a more qualified name to refer to it, rather than its simple name.
I know that an inner class has access to everything in the outer class (because it's a member of that class) but what about the other way around?
Does the outer class have access to private variables and methods within an inner class?
I've seen articles mentioning that inner classes should be private so that they are accessible only to the outer class. What does that do to the accessibility of that inner class?
What is best practices in dealing with access levels when it comes to your inner classes? I'm assuming more encapsulation the better but does that come at the expense of accessibility?
This topic is covered in some detail by Effective Java (2nd edition) Item 22: "Favor static member classes over nonstatic".
A brief summary:
An inner class should not have access to an outer class instance, unless that access is required, i.e. inner classes should be static by default. To get technical, Effective Java calls these static member classes, as opposed to inner classes, and uses the term nested class to encompass both the static and nonstatic versions.
An outer class always has access to the members of its inner classes, even when those members are private. In this way, an inner class can expose itself only to its outer class.
"An inner class should exist only to serve its outer class."
Personally, I'm inclined to implement an inner class whenever doing so allows the inner class's constructors to be private, i.e. when a class can only be instantiated from one other (outer) class. Any additional encapsulation, such as making the entire inner class private, is desirable; but public inner classes are perfectly acceptable. There are many examples in Java, such as AbstractMap.SimpleEntry.
If I declare a variable as private in an inner class, the variable is visible to the outer class. I am unable to understand the logic here. Shouldn't it ideally be only accessible within an inner class?
I think the answer is subjective as the question basically seems to be asking why Sun/Oracle's language designers decided to allow a certain behavior.
That said, here is an attempt at an answer...
First some terminology, a class declared within a class is a nested class. An inner class is a non-static nested class which must reside within an instance of the outer class. So the inner class is a part of the outer class and in that sense, all members of the inner class are to an extent members of the outer class.
http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's methods and fields. Also, because an inner class is associated with an instance, it cannot define any static members itself.
Another thought is that the valid use cases for an inner class preclude the necessity to allow the inner class to hide members from the outer class. That is, there is no notion that the outer class would not be coupled to the inner class.
Why allow private at all then? Because private members can still be hidden from other classes which may gain access to an instance of an inner class.
Alright, I know it's the rule:
According to JLS: 8.1.3 Inner Classes and Enclosing Instances, inner
classes may not declare static initializers or member interfaces.
Inner classes may not declare static members, unless they are
compile-time constant fields.
According to 8.5.2 Static Member Type Declarations, "Member interfaces
are always implicitly static. It is permitted but not required for the
declaration of a member interface to explicitly list the static
modifier". They are always top-level, not inner.
I just wonder why. What may happen if we are allowed to declare interface within an inner class? Won't inner class become top-level class if I put it into another Class file?
Won't inner class become top-level class if I put it into another Class file?
No, it still is an inner class, which the filename indicates (IIRC it's OuterClass$InnerClass.class).
Inner classes have access to the outer class' attributes, i.e. they depend on their outer class' instance. With interfaces you couldn't do this. Think of a completely unrelated class that would have to be created by the corresponding outer class' instance. How would that be done if the outer class doesn't know who implements that interface?
What you can do is declare static interfaces in your outer class, thus merely using the outer as a namespace:
public class OuterClass {
public static interface InnerInterface { //protected and private would be fine too, depending on what makes sense
}
}
Edit: actually, I misread the question and since interfaces are static anyways, here's an updated code snippet:
public class OuterClass {
public static InnerClass { //static inner class making OuterClass just be a namespace
public interface InnerInnerInterface { //protected and private would be fine too, depending on what makes sense
}
}
}
As a workaround you could define an abstract inner inner class, with the drawback that you have to stick to the single inheritance constraint.
Think of it in terms of static vs. non-static context. A "top-level" class establishes a static context because it can be accessed without any enclosing instance. I.e. you can access top-level classes from a main method. The same applies to any static members of a top-level class. An inner class, however, neither exists in* nor establishes any static context. Therefore it can't have any static members, and it can only be accessed via an instance of its containing class, like constructors and other instance members. From a main method, you wouldn't be able to say Outer.Inner.SOME_FIELD because members of an inner class only have meaning with respect to the containing class.
*sort of
By definition a top level class and its inner class(es) are tightly coupled. Interfaces are a means of reducing coupling.
Inner classes are supposed to be implementation details of the top-level class and should therefore be invisible to the client. Any functionality you wish to access of an inner class should be done so through the top-level class, because conceptually speaking, that functionality should be visible only as functionality of the top-level class, so that the class designer can swap out or otherwise drastically change inner classes without breaking clients' builds.
I'm new to Java and have the following question regarding inner classes:
When implementing an inner class, do I need to declare its attributes and methods scope i.e. public, private, protected?
EDIT: With the absence of delegates (as in C#) could someone mention how best to implement a messaging system in Java that enables communication between multiple forms (Jframe)?
I have read that I can use inner classes for this but I'm also told I should not implement inner classes more than a few lines in size. Which school should I follow?
If you want to.
An inner class is roughly speaking like any other class. (Except that if you don't declare it static, it will have an EnclosingClass.this reference.)
I would suggest treating inner classes as private.
In Java, an outer class and all of its nested (including inner) classes can fiddle with each others privates. (The generated bytecode may be pointlessly verbose with additional synthetic access methods, but this is highly unlikely to matter.)
From an interface point of view, a class having weird inner class types is a bit weird. And more difficult to test if you are into that sort of thing. Too often nested type are created because creating a new file in a bad IDE is a bit of a pain - don't be tempted with nasty shortcuts.
Having said that inner classes are very useful. Use them with taste.
when implementing a inner class do i need to declare its attributes and methods scope i.e. public, private, protected?
It depends completely on how you wanted the inner class to behave.
By default, an inner class is non-static:
public class Example1
{
int a;
public class Example2
{
int b;
void test () {}
}
}
A non-static inner class can be instantiated only inside a non-static method of the outer class. This is because every instance of a non-static inner class must be associated with an instance of the outer class. In a sense, every instance of a non-static inner class exists ``inside'' an instance of the outer class. A single instance of the outer class may have associated with it more than one instance of the inner class.
Because an instance of a non-static inner class has an associated instance of the outer class, the methods of the inner class can access directly any of the members (fields or methods) of the outer class instance. For example, the test method defined above can access both a and b directly
A class defined within another class is called a nested class. Like other members of a class, a nested class can be declared static or not. A nonstatic nested class is called an inner class. An instance of an inner class can exist only within an instance of its enclosing class and has access to its enclosing class's members even if they are declared private.
The following table shows the types of nested classes:
Types of Nested Classes Type Scope Inner
static nested class member no
inner [non-static] class member yes
local class local yes
anonymous class only the point
where it is
defined yes
Although this is not an answer your question but make sure you are aware of the "static" modifier of inner classes.
public class Stuff {
public static class SubStuff {
//private or protected
}
}
Is different than this:
public class Stuff {
public class SubStuff {
//only private
}
}
If you have a static inner class than you might want protected variables, protected methods so on. But for inner classes that are not static generally you want everything private.
Google for the difference.
Inner can be seen by only the enclosing class. Its mostly used to achieve a utility function within the class. Lets use Door and Password as example.
public class Door {
public boolean isPassword(String key) {
//local inner class - its hidden from the world
class Password{
public boolean isPassword(String key) {
if(!key.equals("xyz")) {
System.out.println("Not Password. Door is locked");
return false;
}else {
System.out.println("Password corect. Door is opened");
return true;
}
}
}
return new Password().isPassword(key);
}
}