Why parent class may not be protected? (Java) - java

I am not sure why in a context like the following
class Parent {
private void method1() {
System.out.println("Parent's method1()");
}
public void method2() {
System.out.println("Parent's method2()");
}
}
public class Child extends Parent {
public void method1() {
System.out.println("Child's method1()");
}
public static void main(String args[]) {
Parent p = new Child();
p.method2();
}
}
Parent may be package private, but not protected.
Specifically the error generated is
modifier protected not allowed here
Which would seem to indicate that it is an issue of access privilege - but I am suspicious that this may be a red herring. Private modifier also generates an error (naturally).

In Java, Top level classes can have only package private and public modifiers.
Making a class private doesn't make any sense. If no one use that class for any reason, then why we need that class?
protected access modifier means, only visible within the enclosing class and any subclasses, and also anywhere in the enclosing class's package. No body knows which classes going to be subclass of a protected class. So, it also doesn't make sense
But both private and protected can be (and frequently are) applied to nested classes and interfaces, just never top-level classes and interfaces

You cannot use the protected access modifier for top level classes.
according to the spec $8.1.1
The access modifier public (§6.6) pertains only to top level classes (§7.6) and to member classes (§8.5), not to local classes (§14.3) or anonymous classes (§15.9.5).
The access modifiers protected and private (§6.6) pertain only to
member classes within a directly enclosing class or enum declaration
(§8.5).

Related

Java: Cannot access protected methods of nested class subclass in subclass of outer class

I'm decomposing a class to allow for reuse, different info-hided implementations etc.
It was:
public class Outer
{
public static class Inner
{
// ...
protected static void innerDoSomething()
{
// ...
}
}
public outerDoSomething()
{
//...
Inner.innerDoSomething();
//...
}
}
And all was well and good, since the outer Outer class is allowed to access protected members of nested Inner class.
But trying to decompose as such:
public class SuperOuter
{
public static class SuperInner
{
// ...
protected static void innerDoSomething()
{
// ...
}
}
// ...
}
public class SubOuter extends SuperOuter
{
public static class SubInner extends SuperInner
{
// ...
protected static void innerDoSomethingElse()
{
// ...
}
}
public outerDoSomething()
{
//...
SubInner.innerDoSomethingElse(); // OK
SubInner.innerDoSomething(); // Error: cannnot access!
//...
}
}
innerDoSomething() is not accessible, even if protected members of SubInner are accessible by SubOuter, and all protected members of SuperInner should be part of SubInner protected interface.
The only way to make it work, seems to be to add explicit delegation for each method, such as:
public static class SubInner extends SuperInner
{
// ...
protected static void innerDoSomethingElse()
{
// ...
}
protected static void innerDoSomething()
{
SuperInner.innerDoSomething();
}
}
Which is annoying, error-prone and time-wasting. I'm tempted to just declare innerDoSomething() as public, but it's not really correct since it's meant to be used only by SubOuter and its subclasses.
How come? Shouldn't innerDoSomething() protected access be ihnerited and accessibile by SubOuter?
The protected method cannot be access from different package through variable reference.
It will work if the two classes SuperOuter and SubOuter will be in the same package.
OK, I think I got around it, carefully re-reading Gosling's The Java Programming Language, 4th ed:
SuperOuter and SubOuter are in different packages, as they logically should be, so there's no blanket whole-package protected members accessibility in place.
Access to protected member of a nested class is actually intended as a special means of access between outer and nested classes (see Chapter 5. Nested Classes and Interfaces)
Yet, protected member accessibility is not simply transitive: apart form nested/outer grant, you need to both to be in a subclass and have a reference that is at least of the type of that subclass (i.e. at least SubXXX, SuperXXX is not enough), because, I quote paragraph 3.5. What protected Really Means:
Each subclass inherits the contract of the superclass and expands that
contract in some way. Suppose that one subclass, as part of its
expanded contract, places constraints on the values of protected
members of the superclass. If a different subclass could access the
protected members of objects of the first subclass then it could
manipulate them in a way that would break the first subclass's
contract and this should not be permissible.
So, even if in my case xxxInner are meant to logically be part of xxxOuter, and SubOuter extends SuperOuter so the former logically should be able to access any protected members of the latter, still SubOuter cannot access protected members of SuperInner in SuperOuter just in the same way as it couldn't if it had received a SuperInner as an argument to a parameter, because that argument could belong to a completely different hierarchy ramification. There's no specific provision in the language to make the connection in this case.
This also explains why explicit delegation works: SubOuter has access to protected members of SubInner, because outer/nested grant, and SubInner has access to protected members of SuperInner because of extension, but SubOuter cannot access protected members of SuperInner because the latter could actually belong to a different hierarchy ramification, and it's SubInner's job to make the connection, so to say.
Explicit delegation respects everything of the above, logically and by language definitions, so it should be the "correct" way to go, considering proper access, but it's error-prone in implementation because of redundancy (what if I invoke SuperInner.innerDoSomethingElse() inside SubInner.innerDoSomething()?)
Ultimately: I could automate the explicit delegation with some python scripting, for example (I did to automate creation of Builder patterns, which have similar redundancy weakness), or simply renounce to the added safety of access control and make the protected members public.

Java, protected access of methods of nested subclass not working. Forced to public [duplicate]

I would like to understand what's happening in the example below (where a protected member is being accessed from outside the package through a subclass).
I know for classes outside the package, the subclass can see the protected member only through inheritance.
There are two packages: package1 and package2.
package1: ProtectedClass.java
package org.test.package1;
public class ProtectedClass {
protected void foo () {
System.out.println("foo");
}
}
package2: ExtendsprotectedClass.java
package org.test.package2;
import org.test.package1.ProtectedClass;
public class ExtendsprotectedClass extends ProtectedClass {
public void boo() {
foo(); // This works,
// since protected method is visible through inheritance
}
public static void main(String[] args) {
ExtendsprotectedClass epc = new ExtendsprotectedClass();
epc.foo(); // Why is this working?
// Since it is accessed through a reference,
// foo() should not be visible, right?
}
}
package2: UsesExtendedClass.java
package org.test.package2;
public class UsesExtendedClass {
public static void main(String[] args) {
ExtendsprotectedClass epc = new ExtendsprotectedClass();
epc.foo(); // CompilationError:
// The method foo() from the type ProtectedClass
// is not visible
}
}
It is understood that the boo() method in ExtendsprotectedClass can access foo(), since protected members can be accessed through inheritance only.
My question is, why is the foo() method working fine when accessed through a reference in the main() method of ExtendsprotectedClass but will not work when accessed through the epc reference in UsesExtendedClass?
Code within the ExtendsprotectedClass class is allowed to access protected members of ProtectedClass via a reference of type ExtendsprotectedClass. From the JLS section 6.6.2:
A protected member or constructor of an object may be accessed from outside the package in which it is declared only by code that is responsible for the implementation of that object.
and
Let C be the class in which a protected member m is declared. Access is permitted only within the body of a subclass S of C. In addition, if Id denotes an instance field or instance method, then:
If the access is by a qualified name Q.Id, where Q is an ExpressionName, then the access is permitted if and only if the type of the expression Q is S or a subclass of S. [...]
UsesExtendedClass isn't reponsible for the implementation of ExtendsprotectedClass, hence the final call fails.
EDIT: The reasoning behind this is that protected access is designed to help subclasses implement the functionality they need, giving more access to the internals of the superclass than would normally be available. If that were available to all code, it would be pretty close to making the method public. Basically, the subclasses are trusted not to break encapsulation; they're given more capabilities within objects of their own type. The public API shouldn't expose those details, but the protected API can just for the purposes of giving subclasses more opportunities.
It is working in the first case because it is being called from the same class even the method is being accessed through a reference. You could even call a private method of ExtendsprotectedClass through a reference in the same main method.
I believe you've answered your own question; UsesExtendedClass does not inherit from ProtectedClass, and -- by definition -- "protected" members are accessible only in the class in which they are declared / defined or in a class that inherits from the one in which they are declared or defined.
take a look on this picture from : http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
its clear that protected member of class can be accessed via subclass.

What is the default access level for methods in a public abstract class in Java?

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");
}
}

When Child class override a protected member then member become access able with . operator?

package xxx.yyy;
public class ParentClass {
protected void doPrint(){
System.out.println("Parent.....");
}
}
package aaa.bbb;
import cathy.inner.ParentClass;
public class Child extends ParentClass {
public void getName(){
System.out.println("Child....");
}
}
A client in package aaa.bbb can not uses new Child().doPrint(). But if child override the then client can use new Child().doPrint().
It seems strange to me because during override we can't change the access modifier to more restrictive, but is this case inherited method seems private.
Why this is implemented in such a manner ?
Super class method's access modifier is protected and it states method would be accessible with in class, package and subclass.
So it is not accessible in subclass's package.
when you override that particular method in subclass with protected access modifier then it would accessible as protected methods are accessible under same package.
Protected will allow only child classes to access methods... Its not a strange its one type of restriction which java have...

Java: protected access across packages

I would like to understand what's happening in the example below (where a protected member is being accessed from outside the package through a subclass).
I know for classes outside the package, the subclass can see the protected member only through inheritance.
There are two packages: package1 and package2.
package1: ProtectedClass.java
package org.test.package1;
public class ProtectedClass {
protected void foo () {
System.out.println("foo");
}
}
package2: ExtendsprotectedClass.java
package org.test.package2;
import org.test.package1.ProtectedClass;
public class ExtendsprotectedClass extends ProtectedClass {
public void boo() {
foo(); // This works,
// since protected method is visible through inheritance
}
public static void main(String[] args) {
ExtendsprotectedClass epc = new ExtendsprotectedClass();
epc.foo(); // Why is this working?
// Since it is accessed through a reference,
// foo() should not be visible, right?
}
}
package2: UsesExtendedClass.java
package org.test.package2;
public class UsesExtendedClass {
public static void main(String[] args) {
ExtendsprotectedClass epc = new ExtendsprotectedClass();
epc.foo(); // CompilationError:
// The method foo() from the type ProtectedClass
// is not visible
}
}
It is understood that the boo() method in ExtendsprotectedClass can access foo(), since protected members can be accessed through inheritance only.
My question is, why is the foo() method working fine when accessed through a reference in the main() method of ExtendsprotectedClass but will not work when accessed through the epc reference in UsesExtendedClass?
Code within the ExtendsprotectedClass class is allowed to access protected members of ProtectedClass via a reference of type ExtendsprotectedClass. From the JLS section 6.6.2:
A protected member or constructor of an object may be accessed from outside the package in which it is declared only by code that is responsible for the implementation of that object.
and
Let C be the class in which a protected member m is declared. Access is permitted only within the body of a subclass S of C. In addition, if Id denotes an instance field or instance method, then:
If the access is by a qualified name Q.Id, where Q is an ExpressionName, then the access is permitted if and only if the type of the expression Q is S or a subclass of S. [...]
UsesExtendedClass isn't reponsible for the implementation of ExtendsprotectedClass, hence the final call fails.
EDIT: The reasoning behind this is that protected access is designed to help subclasses implement the functionality they need, giving more access to the internals of the superclass than would normally be available. If that were available to all code, it would be pretty close to making the method public. Basically, the subclasses are trusted not to break encapsulation; they're given more capabilities within objects of their own type. The public API shouldn't expose those details, but the protected API can just for the purposes of giving subclasses more opportunities.
It is working in the first case because it is being called from the same class even the method is being accessed through a reference. You could even call a private method of ExtendsprotectedClass through a reference in the same main method.
I believe you've answered your own question; UsesExtendedClass does not inherit from ProtectedClass, and -- by definition -- "protected" members are accessible only in the class in which they are declared / defined or in a class that inherits from the one in which they are declared or defined.
take a look on this picture from : http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
its clear that protected member of class can be accessed via subclass.

Categories