I am reading Thinking In Java at the moment and I encountered one small problem. I am doing exercise 12 from chapter 8.
Create an interface with at least one method, in its own package. Create a class in a >separate package. Add a protected inner class that implements the interface. In a third >package, inherit from your class and, inside a method, return an object of the protected >inner class, upcasting to the interface during the return.
So I created these .java files:
A.java
package c08;
public interface A
{
void one();
}
Pr2.java
package c082;
import c08.*;
public class Pr2
{
protected class InPr2 implements A
{
public void one() {System.out.println("Pr2.InPr2.one");}
protected InPr2() {}
}
}
Ex.java
package c083;
import c082.*;
import c08.*;
class Cl extends Pr2
{
A foo()
{
InPr2 bar=new InPr2();
return bar;
}
}
And my NetBeans IDE underlines
InPr2();
and says that:InPr2() has protected access in C082.Pr2.InPr2 and I am wondering why.
If I didn't explicitly state that constructor in InPr2 should be protected it would be only accessible in C082 package, but when I am inheriting class Pr2 shoudn't it be available in class Cl, because InPr2 is protected? Everything is fine when I change constructor to public.
The constructor of InPr2 is protected, meaning that only classes inheriting from InPr2 (not Pr2) can call it. Classes that inherit from Pr2 can see the class Pr2, but they can't call its protected members, like the protected constructor.
It should work just fine as you have it, except changing the protected InPr2() {} to public InPr2() { }. In other words "Anyone can instantiate this class IF they can see the class to begin with."
Even though the class InPr2 is accessible in Cl, its constructor is not. A protected constructor is accessible only to subclasses and classes in the same package.
Change:
Pr2.java
package c082;
import c08.*;
public class Pr2
{
protected class InPr2 implements A
{
public void one() {System.out.println("Pr2.InPr2.one");}
// This constructor was available only
// to a class inheriting form Pr2.InPr2 - protected InPr2() {}
public InPr2() {}
}
}
The constructor fromPr2.InPr2 was just available to a class if it extended Pr2.InPr2.
Protected member variables, methods and constructors are not accessible outside the package unless they are inherited.
When we try to create an object of InPr2 the compiler will show error as the protected constructor is not accessible outside the package.
The creation of an object depends on the access modifier of the Constructor too.
You can do one thing: InPr2 can be inherited inside class C.
no class in java can be protected.
Related
Say I have a class declared with default access. If a member in the class is declared protected or public, is it equivalent to the member being declared with default access?
For example:
In CarA.java:
class CarA { //class declared with default access
public int odometer;
protected void forward(int distance){...
}
protected static void tally(){...
}
}
In CarB.java:
class CarB { //class declared with default access
int odometer;
void forward(int distance){...
}
static void tally(){...
}
}
Are CarA and CarB equivalent?
My reasoning is that since the class is not declared as public, the class is not accessible outside of its package, so its members should not be accessible outside of its package as well. Could someone confirm my thinking is correct?
No, they're not equivalent. Define these in the same package:
public class CarC extends CarA { }
public class CarD extends CarB { }
And in a different package:
import your.package.CarC;
import your.package.CarD;
public class NewClass
{
public static void tryThis(CarC c, CarD d) {
int n1 = c.odometer; // legal
int n2 = d.odometer; // illegal
}
}
No, these would not be equivalent. The odometer would almost be equivalently privileged*, the methods would not be.
This is because what you're calling "default access", also referred to as package-private, means that other members of that package can access the object or method in question. So where you've made odometer public, it would essentially be available to anything with access to the parent class, the protected status of the methods would be available to the package and classes that extend the class in question, even if they are outside of the package, unlike package-private.
*The public odometer in CarA could be accessed by an object or method outside of this package by routing it through a public class that extends this class whereas the package-private odometer in CarB would always be package-private. This is a great reason why one should avoid writing code like that, other developers might assume that the variable is not publicly available.
As far as I know, you can access the members of the class when you can create an instance of the class or when you inherit the class.
A default class can not be accessed outside the package. So I think you can not inherit it as well(outside the package). So I think they are pretty much the same.
You can access the protected members of the class when you can access the class itself(CarA).
Hope I'm right and this gives you some idea.
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.
Actually, I am trying to finish this practice in "Think in Java" for self-learning purpose --
Exercise 6: (2) Create an interface with at least one method, in its own package. Create a
class in a separate package. Add a protected inner class that implements the interface. In a
third package, inherit from your class and, inside a method, return an object of the
protected inner class, upcasting to the interface during the return.
so I created a class named IgetResult.java under directory "a" which has a IIGetResult Interface.
interface IIGetResult {
String getResult();
}
public class IgetResult {
}
then I create another class in another directory -- directory b
import a.IgetResult.IIGetResult;
public class PracticeClass {
protected class inner implements IIGetResult {
#Override
String getResult(){ return "result";}
}
public static void main(String[] args) {
System.out.println("practice start");
}
}
In the final step, I compile the two java classes with command:
# javac a/.java b/.java
and get the following error:
./a/IgetResult.java:1: duplicate class: IIGetResult
interface IIGetResult {
^
./a/IgetResult.java:4: duplicate class: IgetResult
public class IgetResult {
^
b/PracticeClass.java:1: cannot access a.IgetResult
bad class file: ./a/IgetResult.java
file does not contain class a.IgetResult
Please remove or make sure it appears in the correct subdirectory of the classpath.
import a.IgetResult.IIGetResult;
^
Please teach me go through this practice, thanks in advance.
As per the quote:
Create an interface with at least one method, in its own package.
So we create IGetResult.java file in folder a:
package a;
public interface IGetResult {
String getResult();
}
Create a class in a separate package. Add a protected inner class that implements the interface.
Now we create a class in a separate package (folder), with inner class which implements the interface:
package b;
import a.IGetResult;
public class InnterTest {
protected class GetResultImpl implements IGetResult {
#Override
String getResult() { return "result"; }
}
}
In a third package, inherit from your class and, inside a method, return an object of the protected inner class, upcasting to the interface during the return
So now we create a sub-class of InnerTest class in third separate package:
package c;
import a.IGetResult;
import b.InnterTest;
public class InnerTestSubclass extends InnerTest {
public IGetResult getResultClass() {
//Up-casting happens automatically since GetResultImpl is sub-class of IGetResult
return new GetResultImpl();
}
}
I typed it by hand, but you should get the idea. Hope that helps.
I can see the following issues:
You are missing the 'package <a/b/c>' declaration in your classes.
Your a.IIGetResult interface should be public, otherwise it won't be visible in the 'b' package.
The Java convention is for class name to start with an upper case, thus your inner class insided PracticeClass should be named 'Inner' instead.
Your inner class should have a public constructor, so that the later can be invoked from a class extending PracticeClass defined in another package.
The overriden inner.getResult() method should be public (but out-of-topic).
Your class IGetResult should be defined in a third package (c?) and should extends PracticeClass (though I must admit your instructions are a little bit confusing to me).
Aplly the above points along with #dimoniy's answer and you should be OK.
Your class needs to be inside of your interface. This needs to be in a file called IIGetResult.java
interface IIGetResult {
String getResult();
public class IgetResult implements IIGetResult{
#Override
String getResult() { return null; }
}
}
Say there's the following base class:
package bg.svetlin.ui.controls;
public abstract class Control {
protected int getHeight() {
//..
}
//...
}
Also, in the same package, there's a class that inherits:
package bg.svetlin.ui.controls;
public abstract class LayoutControl extends Control {
public abstract void addControl(Control control);
//...
}
Then, there's a third class in another package:
package bg.svetlin.ui.controls.screen;
public abstract class Screen extends LayoutControl {
//...
}
And, finally, there's the implementation class, again in a different package:
package bg.svetlin.ui.controls.screen.list;
public class List extends Screen {
private final Vector controls = new Vector();
public void addControl(Control control) {
height += control.getHeight();
controls.addElement(control);
}
}
Even though List inherits from Control, and the getHeight() is protected, there's the following error:
getHeight() has protected access in bg.svetlin.ui.controls.Control
I've checked that my imports are right. I'm using NetBeans.
Any idea what's wrong? I thought protected fields and methods are visible to the children even if the latter are in a different package.
Thanks!
I thought protected fields and methods are
visible to the children even if the latter are in a different package.
That's correct. The class itself has an access to the inherited protected members. But, what you're trying to do it to call the getHeight method on some Control reference. You're allowed to call it only on this instance!
For a better understanding, let me quote Kathy Sierra's SCJP Preparation Guide:
But what does it mean for a subclass-outside-the-package to have
access to a superclass (parent) member? It means the subclass inherits
the member. It does not, however, mean the
subclass-outside-the-package can access the member using a reference
to an instance of the superclass. In other words, protected =
inheritance. The subclass can see the protected member
only through inheritance.
You're right. Any protected member or method accessible from children class, but you want access to protected method of a parameter instance in addControl method. You can access only to protected method of List class (this.getHeight())
The following is my ProtectedConstructor.java source code:
package protectCon;
public class ProtectedConstructor{
public int nothing;
ProtectedConstructor(){
nothing = 0;
}
}
And following is the UsingProtectedCon.java source:
package other;
import protectcon.ProtectedConstructor;
public class UsingProtectedCon extends ProtectedConstructor{ //**Line 4**
public static void main(String... a) {
}
}
When I compile UsingProtectedCon.java, I get error at Line 4 shown above. It says that ProtectedConstructor() is not public ; so cannot be accessed outside package.
However, since my class is public, shouldn't I be able to extend it outside package. I am anyway not creating any instance of it.
Now, if I make the constructor of ProtectedConstructor class as public or protected then the code compiles fine with no error.
So then why is it necessary even for the constructor to be public or protected, and not just have default access?
If you want to extends a class outside its package it must have a constructor that is public or protected because in Java every constructor must call a constructor from its superclass.
Because of this there is an implied super() call in every constructor which does not have this() or an explicit call to super() as its first statement. And if you don't specify a constructor at all Java will add a default parameterless constructor, so in effect your code looks like this:
public class UsingProtectedCon extends ProtectedConstructor {
public UsingProtectedCon() {
super();
}
public static void main(String... a) {
}
}
So in other words your code is failing to compile because the call to super() in the default constructor cannot be resolved.
constructor is a member of class like field and method so access modifier applies to it in the same manner it apples to all the member of class
when you extend the class A in B , A's its default constructor will get called from B's constructor implicitly (if you don't call any of the overloaded constructor)
in your class ProtectedConstructor is defined with Package-Private access
This means that outside the package its not seen even by the classes that extend from your ProtectedConstructor class
Define your constructor with 'protected' access modifier instead and you'll be done:
package protectCon;
public class ProtectedConstructor{
public int nothing;
protected ProtectedConstructor(){
nothing = 0;
}
}
Your constructor is not public. Default scope is package-private.
JLS 6.6.7 answers your question. A subclass only access a protected members of its parent class, if it involves implementation of its parent. Therefore , you can not instantiate a parent object in a child class, if parent constructor is protected and it is in different package.Since the default constructor of the subclass would try to call parent class constructor ,you got this error.
See this SO Post for details
to avoid all confusion do it like this.
package protectCon;
public class ProtectedConstructor{
public int nothing;
public ProtectedConstructor(){
nothing = 0;
}
}
package other;
import protectCon.ProtectedConstructor;
public class UsingProtectedCon extends ProtectedConstructor{ //**Line 4**
public UsingProtectedCon(){
super();
}
public static void main(String... a){
}
}
You can have constructors which are public, protected (for internal used) and even private.
A simple example is String which has public constructors for general use and package-local constructors for internal use.
The ObjectOutputStream class has a public constructor which takes an OutputStream and a protected constructor which can only be used by a sub-class.
BTW: if you have an abstract class, does it make sense to make the constructor public as if often the case. ;) hint: it is the same as protected.
If child will have constructor which is private in parent,we can make child's instance with that constructor and cast it to parent's type.
So to prevent this java compiler is not allowing constructor to have constructor which is private in parent.