I am preparing for an Oracle examination and answered incorrectly to the following question:
the combination abstract private is legal for inner classes
As it turns the answer is true, I answered false, as I could not find any use cases for having an abstract private inner class, that cannot be overridden from subclasses. Can someone explain, why/for what do we have that in the language?
The Java language specification defines the meaning of private members as follows:
Otherwise, the member or constructor is declared private, and 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.
That is, a private inner class is accessible (and may be subclassed) from any code residing in the same source file. For instance, you could do:
public class C {
private abstract class A {
abstract void foo();
}
void bar() {
new A() {
#Override void foo() {
// do something
}
}
}
}
It is interesting to note that a method declared private can not be overriden, but methods in private classes can be.
the combination abstract private is legal for inner classes
Its a bit confusing but the rule is that an inner class can't have an abstract private method.
if exam is saying the contrary then its wrong.
UPDATE: if what you mean is in class declaration, then answer is true, check this valid piece of code...
public class MyOuter {
abstract private class MyInner {
//the combination abstract private is legal for inner classes: TRUE
}
}
To know why or when use it, check the suggested link, there is a good explanation about this...
Related
I create an method local Inner Class and combine with abstract class. The code work fine but I do not understand the error popup in IntelliJ about I can't set Method in inner class that extend from abstract inner class to be private.
I have to change from "Private InnerClassSubclass" to "Public InnerClassSubclass" and if I won't the error is follow:
'innerMethod()' in 'InnerClassSubclass' clashes with 'innerMethod()'
in 'InnerClass'; attempting to assign weaker access privileges
('private'); was 'public'.
I thought private is stronger privilege isn't it? only allow class within the same class to access.
I also try to change 'abstract class InnerClass' to 'private abstract class InnerClass' also got this error;
"Modifier 'private' not allowed here" at private of 'private abstract
class InnerClass'
the code is below:
public class Outerclass {
// instance method of the outer class
private void outer_Method() {
int num = 23;
// method-local inner class
abstract class InnerClass {
abstract public void innerMethod();
} // end of inner class
class InnerClassSubclass extends InnerClass {
public void innerMethod() { //if I extends, I can't use private for innerMethod here.
System.out.println("This is method inner class " + num);
}
}
// Accessing the inner class
new InnerClassSubclass().innerMethod();
}
public static void main(String args[]) {
Outerclass outer = new Outerclass();
outer.outer_Method();
}
}
Could someone clarify me why? Thank you.
You can't restrict the visibility of methods in a subclass.
Assume an Animal class has a public method "breath()". Client code receives an Animal object and invokes that method.
Now imagine you had a Dog subclass, and you pass a doggy object. How should the client code know that his specific Animal does not offer that method?!
Thus: restricting visibility of methods is conceptually wrong, and therefore the compiler gives you an error that exactly says so.
'innerMethod()' in 'InnerClassSubclass' clashes with 'innerMethod()' in 'InnerClass'; attempting to assign weaker access privileges ('private'); was 'public'.
This is correct. You will always be able to write
InnerClass ic = new InnerClassSubclass();
ic.innerMethod(); // method is public
Consider this more general case.
static void callInnerMethod(InnerClass ic) {
ic.innerMethod(); // method is public
}
You can't make this cause a compile error when you pass an InnerClassSubclass. In a more general case you only know the actual type at runtime so it's not solvable at compile time.
InnerClass ic = Class.forName(someString).asSubClass(InnerClass.class).newInstance();
ic.innerMethod(); // this will compile as the method is public.
Firstly, you cannot make the method private because as per java overriding principles, child class cannot make the access modifier of overriding method tighter than that in it's parent class. Here, because parent class have access modifier as public, it should be made public in child class as well
Secondly, inner class can only have only two access modifier : abstract and final. You cannot declare it as private
Consider the following snippet.
package breakoop;
public class BreakOOP {
public static class A{
private int a;
}
public static class B extends A{
public int f(){
return super.a;
}
}
public static void main(String[] args) {
B b = new B();
System.out.println(b.f());
}
}
The example only compiles if A and B are encapsulated within the BreakOOP class.
This seems to go against some of the fundamental concepts of OOP. Can someone explain why this compiles? What is the reasoning behind it?
Check this: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html. It says it increases encapsulation by allowing the static class to access private members of the top level class (sometimes you may need to do that). And a is private member of class A, which is in the scope of BreakOOP, which in turn makes it accessible inside class B.
The Java Language Specification states:
A private class member or constructor is accessible only within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
Since classes A and B are defined within the body of BreakOOP that rule applies and B can see private members of A.
As for the OOP concepts: since A and B are static inner classes they don't have the special life-cycle relation with BreakOOP that true inner classes have (i.e. you don't need an instance of BreakOOP to create a new instance of A or B but they still have a somewhat special relation in that they have access to private members. If they should not have that kind of relationship then they shouldn't be inner classes but true top level classes.
Normally the default access level of methods is package local. But it seems to me that it is different for public abstract classes. In those classes the default seems to be public. Is this correct?
Update
#EJP
It was a bug in my code. It is possible to shadow the package local method with a public method, which confuses me. This makes me think that a public abstract could be similar to an interface where the methods are public. See the example:
a/A.java:
package a;
public abstract class A
{
String a () { return "a"; }
}
test_a.java:
class test_a
{
static class NewA extends a.A
{
public String a () { return "new a"; }
}
public static void main (String[] args)
{
NewA a = new NewA();
System.out.println(a.a());
}
}
False, let's see with a quick example:
package apackage;
public abstract class AbstractFoo {
//A method with default visibility
abstract void bar();
}
A quick implementation :
public class Foo extends AbstractFoo {
#Override
void bar() {}
}
Now, in another package :
public static void main(String[] args) throws Exception{
AbstractFoo something=new Foo();
something.bar();//Compiler complains here
Compiler complains about visibility. So the default visibility for methods is package protected, even if the class is public abstract.
The Java Language Specification for Java 7 does not mention separate rules for abstract methods, as such an abstract method without a qualified access level is default aka package private, just like a normal method would have been.
See also 6.6.1. Determining Accessibility:
A member (class, interface, field, or method) of a reference (class, interface, or array) type or a constructor of a class type is accessible only if the type is accessible and the member or constructor is declared to permit access:
If the member or constructor is declared public, then access is permitted.
All members of interfaces are implicitly public.
Otherwise, if the member or constructor is declared protected, then access is permitted only when one of the following is true:
Access to the member or constructor occurs from within the package containing the class in which the protected member or constructor is declared.
Access is correct as described in §6.6.2.
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.
Otherwise, we say there is default access, which is permitted only when the access occurs from within the package in which the type is declared.
(emphasis mine)
Also note that the term 'default access' is equivalent to 'package private', the only 'exception' to this is method declarations in an interface, which simply are always public and therefor don't need to be prefixed.
Edit:
As adenoyelle indicates in his answer, you can override a 'default' abstract method in a different package (as required by the rules in JLS 8.4.3.1. abstract Methods), as such you could consider them to be protected, but a quick scan of the JLS doesn't seem to make this explicit.
Edit 2:
I just tested it. It is impossible to implement an abstract class that has a method with default access in a different package. It simply does not compile. This shows that the method has default (package private) access, not protected. It also indicates that 8.4.3.1 doesn't actually require that it is always possible to implement an abstract method, just that it excludes nonsensical options like private abstract void method()
For example compiling:
package example;
public abstract class AbstractTest {
abstract void testMethod();
}
and
package example.sub;
import example.AbstractTest;
public class TestImpl extends AbstractTest {
void testMethod() {
//implemented
}
}
Leads to compile error:
example\sub\TestImpl.java:8: error: TestImpl is not abstract and does not override abstract method testMethod() in AbstractTest
public class TestImpl extends AbstractTest {
^
1 error
The default visibility is known as “package” (though you can't use this keyword), which means the field will be accessible from inside the same package to which the class belongs.
uf you declare as public than it will be public for all no matter its abstract or not
Default access modifier means we do not explicitly declare an access modifier for a class, field, method etc.
A variable or method declared without any access control modifier is available to any other class in the same package.
So there is no matter of the method is abstract or not .
The access level of the methods would remain as default(would be only visible within the package) even if the abstract class is of public access level. Only if the child class overrides the method with a pulbic access modifier, it would be visible outside the package.
You are on to something, just a bit off: in interfaces the default—and in fact the only choice— is public. In all classes the default is the same, which is package-private.
Even if the subclass "tries" to override the method with "default" access defined in the abstract class in the subclass with "public" access, compiler still complains that chap6.AbstractImpl is not abstract and does not override abstract method getHelp() in random.AbstractLearner.
So, in effect the compiler error message is really misleading here because there is no way that this can be fixed unless the access specifier for the getHelp() method in the AbstractLearner is changed to public.
package random;
public abstract class AbstractLearner {
abstract void getHelp();
}
package chap6;
import random.AbstractLearner;
public class AbstractImpl extends AbstractLearner {
public void getHelp() {
System.out.println("Hello");
}
}
I am new to java and have been scratching my head understanding some its concepts.
I am following the tutorial Java tutorial. However, I cannot find the usefulness of using Static Nested Classes. I mean I think I need some good examples as to why I should want to use it. Can someone provided me some codes as examples so I can understand it better?
thax
The benefit of a static nested class over an "ordinary" class is that you can use it to reflect the relationship between two classes.
For example in the JDK there is java.util.Map and java.util.Map.Entry.
java.util.Map.Entry is declared as a public static interface and doing it this way clearly signposts its relationship to Map. It could have been defined as java.util.MapEntry but doing it as a static nested interface makes it clear that it has a strong relationship to Map.
So you'd probably only use static nested class when the nested class would only ever be used in the context of its parent.
The following example might not be for a Java beginner but one nice example of static nested class is when you want to use the Builder pattern to construct immutable objects of the outer class. The static nested class is allowed to access private members of the outer class thus constructing objects of the outer class although it has a private constructor and initializing private fields of the outer class.
E.g.
public class SomeClass {
private int someField;
private int someOtherField;
private SomeClass()
{}
public static class SomeBuilder {
private int someField;
private int someOtherField;
public SomeBuilder setSomeField(int someField)
{
this.someField = someField;
return this;
}
public SomeBuilder setSomeOtherField(int someOtherField) {
this.someOtherField = someOtherField;
return this;
}
public SomeClass build() throws ValidationException
{
validateFields();
SomeClass someClass = new SomeClass();
someClass.someField = someField;
someClass.someOtherField = someOtherField;
return someClass;
}
private void validateFields() throws ValidationException {
//Validate fields
}
}
public int getSomeField() {
return someField;
}
public int getSomeOtherField() {
return someOtherField;
}
}
Nested or inner class is just an ordinary class defined into other class. The reason to do this is typically to hide inner class from others, i.e. it is yet another level of encapsulation.
Inner class can be private, protected and public that mean exactly the same as for fields and methods.
If inner class is not private you can access it from outside too. Its name is OuterClass.InnnerClass. The nesting depth is not limited by Java specification, so inner class can have its own inner classes etc.
If inner class is not static it has yet another feature: ability to call outer's class methods and fields.
Inner class can be also anonymous. This is very useful for small callbacks, event handlers etc.
Hope this helps. Do not hesitate to ask other more concrete questions.
Another thing I should add is that if an inner class is not static, an instance of it will automatically have a reference to its parent class instance. You can reference it by using: NameOfOuterClass.this.
But if it is static, then it will not.
This, among other things, comes into play during GC (garbage collection).
Because, if an object of the inner class is not being GCed, then the outer class object it references will not be GCed either (in cases where the inner class was not static).
What is the reason of declaring a member of a private inner class public in Java if it still can't be accessed outside of containing class? Or can it?
public class DataStructure {
// ...
private class InnerEvenIterator {
// ...
public boolean hasNext() { // Why public?
// ...
}
}
}
If the InnerEvenIterator class does not extend any class or implement any interface, I think it is nonsense because no other class can access any instance of it.
However, if it extends or implements any other non private class or interface, it makes sense. An example:
interface EvenIterator {
public boolean hasNext();
}
public class DataStructure {
// ...
private class InnerEvenIterator implements EvenIterator{
// ...
public boolean hasNext() { // Why public?
// ...
}
}
InnerEvenIterator iterator;
public EvenIterator getIterator(){
return iterator;
}
}
This method can be made public in order to indicate that it's semantically public, despite the fact that compiler doesn't enforce visibility rules in this particular case.
Imagine that during some refactoring you need to make this inner class top-level. If this method is private, how would you decide whether it should be made public, or some more restrictive modifier should be used? Declaring method as public tells reader the intentions of original author - this method shouldn't be considered an implementation detail.
It is useful when you implement any interface.
class DataStructure implements Iterable<DataStructure> {
#Override
public Iterator<DataStructure> iterator() {
return new InnerEvenIterator();
}
// ...
private class InnerEvenIterator implements Iterator<DataStructure> {
// ...
public boolean hasNext() { // Why public?
// ...
return false;
}
#Override
public DataStructure next() {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public void remove() {
throw new UnsupportedOperationException("Not supported yet.");
}
}
public static void main(String[] ex) {
DataStructure ds = new DataStructure();
Iterator<DataStructure> ids = ds.iterator();
ids.hasNext(); // accessable
}
}
I think you are missing the implementing the Iterator interface part in your sample code. In that case, you can't make the hasNext() method have any other visibility identifier other than public since that would end up reducing its visibility (interface methods have public visibility) and it won't compile.
There are many combinations of access modifiers which are not useful. A public method in a private inner class is only useful if it implements a public method in a public class/interface.
public class DataStructure {
// ...
private class InnerEvenIterator implements Iterator {
// ...
public boolean hasNext() { // Why public?
// ...
}
}
public Iterator iterator() {
return new InnerEvenIterator();
}
}
BTW: abstract classes often have public constructors when actually they are protected
If the inner class is private it cannot be accessed by name outside of the outer class. Inner and outer classes have access to each other's private methods and private instance variables. As long as you are within the inner or outer class, the modifiers public and private have the same effect. In your code example:
public class DataStructure {
// ...
private class InnerEvenIterator {
// ...
public boolean hasNext() { // Why public?
// ...
}
}
}
As far as the class DataStructure is concerned, this is completely equivalent to:
public class DataStructure {
// ...
private class InnerEvenIterator {
// ...
private boolean hasNext() {
// ...
}
}
}
This is because only DataStructure can access it, so it doesn't matter if you set it to public or private. Either way, DataStructure is still the only class that can access it. Use whichever modifier you like, it makes no functional difference. The only time you can't choose at random is when you are implementing or extending, in which case you can't reduce the access, but you can increase it. So if an abstract method has protected access you can change it to public. Granted neither one actually makes any difference.
If you plan on using an inner class in other classes, and therefore making it public, you probably shouldn't make it an inner class in the first place.
Additionally, I don't see any requirement for inner classes extending or implementing other classes. It might be common for them to do so, but it's certainly not required.
There are multiple aspects which have to be considered here. The following will use the term "nested class" because it covers both non-static (also called "inner class") and static classes (source).
Not related to private nested classes, but JLS §8.2 has an interesting example which shows where public members in package-private or protected classes could be useful.
Source code
Overriding methods
When your nested class implements an interface or extends a class and overrides one of its methods, then per JLS §8.4.8.3:
The access modifier of an overriding or hiding method must provide at least as much access as the overridden or hidden method
For example:
public class Outer {
private static class Nested implements Iterator<String> {
#Override
public boolean hasNext() {
...
}
#Override
public String next() {
...
}
}
}
The methods hasNext() and next() which override the Iterator methods have to be public because the Iterator methods are public.
As a side note: JLS §13.4.7 describes that it is possible for a class to increase the access level of one of its methods, even if a subclass overrides it with, without causing linkage errors.
Conveying intention
Access restriction is defined in JLS §6.6.1:
A member [...] of a reference type [...] is accessible only if the type is accessible and the member or constructor is declared to permit access
[...]
Otherwise, the member or constructor is declared private, and access is permitted if and only if it occurs within the body of the top level type (§7.6) that encloses the declaration of the member or constructor.
Therefore members of a private nested class can (from a source code perspective; see also "Reflection" section) only be accessed from the body of the enclosing top level type. Interestingly the "body" also covers other nested classes:
public class TopLevel {
private static class Nested1 {
private int i;
}
void doSomething(Nested1 n) {
// Can access private member of nested class
n.i++;
}
private static class Nested2 {
void doSomething(Nested1 n) {
// Can access private member of other nested class
n.i++;
}
}
}
So from a compiler-provided access restriction perspective there is indeed no point in using a public member in a private nested class.
However, using different access levels can be useful for conveying intention, especially (as pointed out by others) when the nested class might be refactored to a separate top level class in the future. Consider this example:
public class Cache {
private static class CacheEntry<T> {
private final T value;
private long lastAccessed;
// Signify that enclosing class may use this constructor
public CacheEntry(T value) {
this.value = value;
updateLastAccessed();
}
// Signify that enclosing class must NOT use this method
private void updateLastAccessed() {
lastAccessed = System.nanoTime();
}
// Signify that enclosing class may use this method
public T getValue() {
updateLastAccessed();
return value;
}
}
...
}
Compiled class files
It is also interesting to note how the Java compiler treats access to members of nested classes. Prior to JEP 181: Nest-Based Access Control (added in Java 11) the compiler had to create synthetic accessor methods because the class file could not express the access control logic related to nested classes. Consider this example:
class TopLevel {
private static class Nested {
private int i;
}
void doSomething(Nested n) {
n.i++;
}
}
When compiled with Java 8 and inspected with javap -p ./TopLevel$Nested.class you will see that a synthetic access$008 method has been added:
class TopLevel$Nested {
private int i;
private TopLevel$Nested();
static int access$008(TopLevel$Nested);
}
This slightly increased the size of the class files and might have decreased performance. This is one reason why package-private (i.e. no access modifier) access has often be chosen for members of nested classes to prevent creation of synthetic access methods.
With JEP 181 this is no longer necessary (javap -v output when compiled with JDK 11):
class TopLevel$Nested
...
{
private int i;
...
private TopLevel$Nested();
...
}
...
NestHost: class TopLevel
...
Reflection
Another interesting aspect is reflection. The JLS is sadly not verify specific in that regard, but §15.12.4.3 contains an interesting hint:
If T is in a different package than D, and their packages are in the same module, and T is public or protected, then T is accessible.
[...]
If T is protected, it is necessarily a nested type, so at compile time, its accessibility is affected by the accessibility of types enclosing its declaration. However, during linkage, its accessibility is not affected by the accessibility of types enclosing its declaration. Moreover, during linkage, a protected T is as accessible as a public T.
Similarly AccessibleObject.setAccessible(...) does not mention the enclosing type at all. And indeed it is possible to access the members of a public or protected nested type within non-public enclosing type:
test1/TopLevel1.java
package test1;
// package-private
class TopLevel1 {
private static class Nested1_1 {
protected static class Nested1_2 {
public static int i;
}
}
}
test2/TopLevel2.java
package test2;
import java.lang.reflect.Field;
public class TopLevel2 {
public static void main(String... args) throws Exception {
Class<?> nested1_2 = Class.forName("test1.TopLevel1$Nested1_1$Nested1_2");
Field f = nested1_2.getDeclaredField("i");
f.set(null, 1);
}
}
Here reflection is able to modify the field test1.TopLevel1.Nested1_1.Nested1_2.i without having to make it accessible despite it being inside a private nested class inside a package-private class.
When you are writing code for an environment where untrusted code is run you should keep that in mind to prevent malicious code from messing with internal classes.
So when it comes to the access level of nested types you should always choose the least permissive one, ideally private or package-private.