Why can't I use protected constructors outside the package? [duplicate] - java

This question already has answers here:
What is the difference between public, protected, package-private and private in Java?
(30 answers)
Closed 7 years ago.
Why can't I use protected constructors outside the package for this piece of code:
package code;
public class Example{
protected Example(){}
...
}
Check.java
package test;
public class Check extends Example {
void m1() {
Example ex=new Example(); //compilation error
}
}
Why do i get the error even though i have extended the class?
Please explain
EDIT:
Compilation error:
The constructor Example() is not visible

Usually protected means only accessible to subclasses or classes in the same package. However here are the rules for constructors from the JLS:
6.6.2.2. Qualified Access to a protected Constructor
Let C be the class in which a protected constructor is declared and
let S be the innermost class in whose declaration the use of the
protected constructor occurs. Then:
If the access is by a superclass constructor invocation super(...),
or a qualified superclass constructor invocation E.super(...), where E
is a Primary expression, then the access is permitted.
If the access is by an anonymous class instance creation expression
new C(...){...}, or a qualified anonymous class instance creation
expression E.new C(...){...}, where E is a Primary expression, then
the access is permitted.
If the access is by a simple class instance creation expression new
C(...), or a qualified class instance creation expression E.new
C(...), where E is a Primary expression, or a method reference
expression C :: new, where C is a ClassType, then the access is not
permitted. A protected constructor can be accessed by a class instance
creation expression (that does not declare an anonymous class) or a
method reference expression only from within the package in which it
is defined.
As an example, this does not compile
public class Example extends Exception {
void method() {
Exception e = new Exception("Hello", null, false, false);
}
}
but this does
public class Example extends Exception {
Example() {
super("Hello", null, false, false);
}
}
and so does this
public class Example {
void method() {
Exception e = new Exception("Hello", null, false, false) {};
}
}
So the rules are clear, but I can't say I understand the reasons behind them!

protected modifier is used only with in the package and in sub-classes outside the package. When you create a object using Example ex=new Example(); it will call parent class constructor by default.
As parent class constructor being protected you are getting a compile time error. You need to call the protected constructor according to JSL 6.6.2.2 as shown below in example 2.
package Super;
public class SuperConstructorCall {
protected SuperConstructorCall() {
}
}
package Child;
import Super.SuperConstructorCall;
public class ChildCall extends SuperConstructorCall
{
public static void main(String[] args) {
SuperConstructorCall s = new SuperConstructorCall(); // Compile time error saying SuperConstructorCall() has protected access in SuperConstructorCall
}
}
Example 2 conforming to JLS 6.6.2.2:
package Super;
public class SuperConstructorCall {
protected SuperConstructorCall() {
}
}
package Child;
import Super.SuperConstructorCall;
public class ChildCall extends SuperConstructorCall
{
public static void main(String[] args) {
SuperConstructorCall s = new SuperConstructorCall(){}; // This will work as the access is by an anonymous class instance creation expression
}
}

In fact you are already using protected constructor of Example because Check has an implicit constructor and implicit Example constructor call:
public Check() {
super();
}

Related

Cannot define extra methods in an Anonymous Inner Class in Java

When defining extra methods (that do not override the super class methods) in an Anonymous Inner Class the code compiles fine without any issues but if I try to call the extra method it throws an error. So is it only possible to override methods in the sub class when extending with an anonymous inner class? If it is so can anyone please explain me why?
Here's what my code looks like
class SomeClass {
public static void main(String[] args) {
SomeOtherClass a = new SomeOtherClass() {
#Override
public void methodFromSuperClass() {
System.out.println("Method from super class!");
}
public void subClassMethod() {
System.out.println("Sub class method");
}
};
a.methodFromSuperClass(); //This works fine
a.subClassMethod(); // But calling this extra method throws an error
}
}
This is the error that I'm getting
SomeClass.java:20: error: cannot find symbol
a.subClassMethod();
^
symbol: method subClassMethod()
location: variable a of type SomeOtherClass
1 error
This situation is exactly the same as if the anonymous class had a name:
class SomeOtherClass {
public void methodFromSuperClass() { }
}
class Subclass extends SomeOtherClass {
#Override
public void methodFromSuperClass() {
System.out.println("Method from super class!");
}
public void subClassMethod() {
System.out.println("Sub class method");
}
}
And you did:
SomeOtherClass a = new Subclass();
a.subClassMethod();
Wouldn't you agree that you shouldn't be able to call subClassMethod here? After all, the compiler knows that a is of type SomeOtherClass, but not which subclass of SomeOtherClass it is. It doesn't analyse your code that far back to see that you actually assigned an instance of Subclass to it.
The situation with anonymous classes is basically the same. It's just that this time, the subclass doesn't have a name in your code, but it's still a subclass, and the same reasoning that "the compiler doesn't analyse your code that far back" applies.
Since the anonymous subclass has no name, you can't do something like Subclass a = new Subclass(); as in the named subclass example, but since Java 10, you can do:
var a = new SomeOtherClass() { ... };
var lets the compiler infer the type of the variable for you without you saying the type name. The compiler will infer the anonymous subclass as the type for a, and this will allow you to do:
a.subClassMethod();
Finally, it is totally allowed to declare extra members in anonymous classes - it's just rather hard to access them from anywhere other than inside the anonymous class, or the local scope, because the anonymous class has no name. Declaring extra members is still sometimes useful though, because you can access them in the overridden methods for example.
Your assumption is correct. It is not possible to call the unoverridden method this way.
Consider an example where you have declared an interface and instantiated it with a concrete class, then you still only have access to the methods defined in the interface and not in the class.
public interface MyInterface{
public void someMethod();
}
public class MyImpl implements MyInterface{
//someMethod() implementation
// ...
// newMethod()
public void newMethod(){
//some implementation
}
}
public class Main{
public static void main(String[] args){
MyInterface inter = new MyImpl();
inter.someMethod(); // this call is ok
inter.newMethod(); // this call leads to a Symbol not found Exception,
// because MyInterface has no method named newMethod...
}
}
Hope it is now clearer what is meant by this

How to force my subclass constructor not to call base class constructor?

public class Base {
public Base() {
foo();
}
public void foo() {
System.out.println("Base.foo()");
}
}
public class Derived extends Base {
public Derived () {}
public void foo() {
System.out.println("Derived.foo()");
}
}
And then, when i call those:
public class Running {
public static void main(String[] args) {
Base b = new Base();
Derived d = new Derived();
}
}
It outputs:
*Base.foo()*
*Derived.foo()*
So why, when it gets to derived constructor, it invokes the base constructor but uses the derived's method instead?
PS: If I mark those methods as private, it will print out:
*Base.foo()*
*Base.foo()*
This is how Java works read this page https://docs.oracle.com/javase/tutorial/java/IandI/super.html
And more specifically the Note here :
Note: If a constructor does not explicitly invoke a superclass
constructor, the Java compiler automatically inserts a call to the
no-argument constructor of the superclass. If the super class does not
have a no-argument constructor, you will get a compile-time error.
Object does have such a constructor, so if Object is the only
superclass, there is no problem.
So as you can see this is expected behavior. Even though you dot have a super call it is still automatically inserting it.
In regards of the second Question even though you are within the super constructor body still you Instance is of the Subtype. Also if you have some familiarity with C++ read this Can you write virtual functions / methods in Java?
The reason why it will write the base class when marking with private is because private methods are not Inherited. This is part of the Inheritance in Java topic.
To answer the question in your title. As I said, you cannot avoid the base class constructor being called (or one of the base class constructors if it has more than one). You can of course easily avoid the body of the constructor being executed. For example like this:
public class Base {
public Base(boolean executeConstructorBody) {
if (executeConstructorBody) {
foo();
}
}
public void foo() {
System.out.println("Base.foo()");
}
}
public class Derived extends Base {
public Derived() {
super(false);
}
public void foo() {
System.out.println("Derived.foo()");
}
}
public class Running {
public static void main(String[] args) {
Base b = new Base(true);
Derived d = new Derived();
}
}
Now the main method prints only:
Base.foo()
Because in the contructor of the Derived class it automatically gets injected a call to super(), if you do not add a call to super or to other constructor in the same class (using this).

Why protected method is not accessible from subclass?

Consider the following code snippets:
package vehicle;
public abstract class AbstractVehicle {
protected int speedFactor() {
return 5;
}
}
package car;
import vehicle.AbstractVehicle;
public class SedanCar extends AbstractVehicle {
public static void main(String[] args) {
SedanCar sedan = new SedanCar();
sedan
.speedFactor();
AbstractVehicle vehicle = new SedanCar();
// vehicle //WON'T compile
// .speedFactor();
}
}
SedanCar is a subclass of AbstractVehicle which contains a protected method speedFactor. I am able to call the method speedFactor if it is referenced by the same class. When the super class is used for reference the method speedFactor is not accessible.
What is reason for hiding the method?
Your SedanCar class is in a different package than the AbstractVehicle class. protected methods can only be accessed from the same package or from subclasses.
In case of SedanCar:
SedanCar sedan = new SedanCar();
sedan.speedFactor();
You are calling a protected method from the same package: OK. SedanCar is in package car and main() method is in a class which is in package car (actually the same class).
In case of AbstractVehicle:
AbstractVehicle vehicle = new SedanCar();
vehicle.speedFactor();
You try to call a protected method but from another package: NOT OK. The main() method from which you try to call it is in package car while AbstractVehicle is in package vehicle.
Basically understand this:
You have a variable of type AbstractVehicle which is declared in another package (vehicle). It may or may not hold a dynamic type of SedanCar. In your case it does, but it could also hold an instance of any other subclass defined in another package, e.g. in sportcar. And since you are in package car (the main() method), you are not allowed to invoke vehicle.speedFactor() (which is the protected AbstractVehicle.speedFactor()).
Because protected is visible to the class itself (like private) and its subclass instances. It is not public.
For example,
package vehicles;
public abstract class AbstractVehicle {
protected int speedFactor() {
return 5;
}
public int getSpeed() {
return 10*speedFactor(); //accessing speedFactor() "privately"
}
}
package vehicles.cars;
public class SedanCar extends AbstractVehicle {
#Override
protected int speedFactor() { //overriding protected method (just to show that you can do that)
return 10;
}
#Override
public int getSpeed() {
return 20*speedFactor(); //this is part of the instance (!!!) therefore it can access speedFactor() protected method too
}
}
package vehicles.main;
public class Main {
public static void main(String[] args) {
AbstractVehicle vehicle = new SedanCar();
int speed = vehicle.getSpeed(); //accessing public method
vehicle.speedFactor(); //cannot access protected method from outside class (in another package)
}
}
The static main() method is not part of the instance, that is why it cannot access the protected method.
The protected modifier specifies that the member can only be accessed within its own package (as with package-private) and, in addition, by a subclass of its class in another package.
This is the reason why you can't directly call the method inside the main method on the vehicle object.
See: https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
Subclasses in different package can't access protected methods and protected variables from superclass using superclass reference.
Only way to access protected data of superclass in subclass is through inheritance
below are two code snippets
package nee;
import parentdata.Parent;
class Child extends Parent{
public void testIt(){
System.out.println(x); // able to access protected x defined in Parent
}
}
package nee;
import parentdata.Parent;
class Child extends Parent {
public void testIt(){
Parent p=new Parent();
System.out.println(p.x) // results in compile time error
}
}
In language specification
6.6.2.1 Access to a protected Member
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.
If the access is by a field access expression E.Id, where E is a Primary expression, or by a method invocation expression E.Id(. . .), where E is a Primary expression, then the access is permitted if and only if the type of E is S or a subclass of S.
for in depth details visit
http://www.jot.fm/issues/issue_2005_10/article3.pdf
Back in my SCJP for Java 1.5 days, one thing that I used to remember was be wary of superclass reference variables. It isn't quite as surprising to see this now and one thing why this gets confusing is the rule is protected is visible to subclass or same package. What if it's both subclass and different package?
If you create another package, and do
package yetAnotherPackage;
import car.SedanCar;
public class Main {
public static void main(String[] args) {
new SedanCar().speedFactor();
}
}
you'll see that
The method speedFactor() from the type AbstractVehicle is not visible
Looks like the rule just propagates. As long as you have a subclass and try to access the protected method within the package of the subclass (or if no subclass, then the package of the parent), you should be good.

What means "methods without access control can be declared more private in subclasses" in Java?

In java access modifiers and inheritance topic says below 4 points. What does "more private" mean in 3rd point ?
...
...
Methods declared without access control => can be declared more private in subclasses
...
Methods declared without access control => can be declared more private in subclasses
It is WRONG. This is exactly the reverse of the case. Methods declared with any level of access control must be overridden with that level or a more public level: in this case, the access level base class is 'default', so you can override with public or protected.
Contrary to what the Google documentation says, you cannot override with private. See JLS §8.4.8.3:
The access modifier (§6.6) of an overriding or hiding method must provide at least as much access as the overridden or hidden method, as follows:
If the overridden or hidden method is public, then the overriding or hiding method must be public; otherwise, a compile-time error occurs.
If the overridden or hidden method is protected, then the overriding or hiding method must be protected or public; otherwise, a compile-time error occurs.
If the overridden or hidden method has package access, then the overriding or hiding method must not be private; otherwise, a compile-time error occurs.
(This has a translation in Russian on RU.SO)
There's actually no such term as 'more' or 'less private'. Instead 'more / less visible' is used.
The statement in the question is wrong. A method cannot be made less visible as that would break the Liskov substitution principle:
Let Φ(x) be a property provable about objects x of type T. Then Φ(y) should be true for objects y of type S where S is a subtype of T.
Here's a repo on GitHub that illustrates all possible variants with inheritance of a package-access method in Java.
https://github.com/NickVolynkin/PackageAccessTest
public class Parent {
//package access
void foo() {
}
}
public class ChildPublic extends Parent {
// Legal
#Override
public void foo() {
}
}
public class ChildProtected extends Parent {
// Legal
#Override
protected void foo() {
}
}
public class ChildPrivate extends Parent {
// Illegal
/*
#Override
private void foo() {
}
*/
}
public class SamePackageAccessTest {
{
new Parent().foo();
//these have overriden foo()
new ChildPublic().foo();
new ChildProtected().foo();
//this one had not overriden foo()
new ChildPrivate().foo();
}
}
package otherpackage;
import test.*;
public class OtherPackageAccessTest {
{
//Legal!
new ChildPublic().foo();
//illegal
/*
new ParentPackage().foo();
new ChildProtected().foo();
new ChildPrivate().foo();
*/
}
}
Full information can be found in this Java Tutorial
Methods declared without access control can be redefined (overridden is not quite the correct word here) in child classes that are not in the same package.
package p1;
public class A {
void m() {}
}
package p1;
public class B {
//This does not work as class is in the same package and this would be an attempt to reduce visibility
private void m() {}
}
package p2;
public class C extends A {
//This works fine as class C does not 'see' the parent method
private void m() {
}
}

Constructor's Private scope

Given this code snippet, could you explain why it woks?
The thing is that the class constructor is marked private, so should not it prevent us to call it with new operator?
public class Alpha {
protected Alpha() {}
}
class SubAlpha extends Alpha {
private SubAlpha() {System.out.println("ok");}
public static void main(String args[]) {
new SubAlpha();
}
}
It all works because the static method is part of the class and it can see all private fields and methods, right? Outside this "new" initialization would never work?
The only private constructor in your question is SubAlpha, which SubAlpha itself is calling. There's no issue, a class can call its own private methods. The Alpha constructor is protected, so SubAlpha has access to it.
Edit: Re your edit: Yes, exactly. A separate class (whether a subclass or not) would not have access to SubAlpha's private constructor and could not successfully construct a new SubAlpha().
Example 1:
public class Beta
{
public static final void main(String[] args)
{
new SubAlpha();
// ^--- Fails with a "SubAlpha() has private access in SubAlpha"
// compilation error
}
}
Example 2:
public class SubSubAlpha extends SubAlpha
{
private subsubAlpha()
{
// ^== Fails with a "SubAlpha() has private access in SubAlpha"
// compilation error because of the implicit call to super()
}
}
This is, of course, constructor-specific, since scope is always member-specific. If a class has a different constructor with a different signature and a less restrictive scope, then a class using it (including a subclass) can use that other constructor signature. (In the case of a subclass, that would require an explicit call to super(args);.)
The code works as the main method is also in the same class. You may not be able to initialize SubAplha from a different class.

Categories

Resources