I have a protected method (I don't want this method to be seen outside Superclass or it subclasses). I want to use it in copy constructor, but I can't. Code:
public class Superclass {
protected HashMap<Object, Object> getData() {
return new HashMap<>();
}
}
public class Subclass extends Superclass {
public Subclass(Superclass abstractClass) {
init(abstractClass);
}
private void init(Superclass abstractClass) {
//ERROR!!! getData has protected access in Superclass
for (Map.Entry<Object, Object> entry : abstractClass.getData().entrySet()) {
//do something
}
}
}
How can I overcome this problem if I still want to create Subclass object from Superclass object without exposing getData() method?
EDIT Classes are in different packages!
You tried to access a method, before creating an instance. The instance is not yet fully initialized.
Calling methods of objects that are being constructed from their own constructor can result in unexpected behavior as the objects are not initialized consistently until the constructor finishes.
While in the same package the following works fine for me:
Superclass:
public class Superclass {
protected List<String> getData() {
return Arrays.asList("a", "b", "c");
}
}
Subclass:
public class Subclass extends Superclass {
public static void main(String[] args) {
Superclass superObject = new Superclass();
Subclass subObject = new Subclass(superObject);
}
public Subclass(Superclass abstractClass) {
//ERROR!!! getData has protected access in Superclass
for (String entry : abstractClass.getData()) {
System.out.println(entry);
}
}
}
Mind you, I'm not sure that's what you're actually trying to do. Why are you passing an instance of Superclass in the constructor of Subclass for example? Also, you had a HashMap rather than a List, but HashMaps aren't Iterable, so you can't use the extended for loop on them.
However:
If those classes are in different packages, things change. Look at the language specifications; in §6.6.1 it says:
[I]f 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.
And §6.6.2 states:
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.
Now, as calling a function in an init method is not considered responsible for implementation, you may not access the member here. Sorry, that's how the language works.
Accessing a protected method from a class in a different package is not possible - see http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html. The fact that you are inheriting from Superclass does not count, since you are trying to call the method on a reference to Superclass, not on the base class itself.
So, what you are trying to do does not work - if it would, it would break Java's access control: you could then simply inherit from any class and implement a method which takes a super class reference as parameter, and then access all protected methods of the super class (you can, of course, still inherit from the base class and access the protected members of the superclass, even cross-package).
If getData() is a method which needs to be called from another package, you need to make it public.
On a side note, you should probably rethink your design - is it really necessary to pass a reference to a Superclass object in the Subclass constructor?
Related
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.
I have a class java ProductManager which extends another class with the same name,
located in another project with another package("com.services") .
I have to invoke a method deleteProduct(Long productId) located in the super-class.
try{
Object service = CONTEXT.getBean("ProductManager");
Method method = service.getClass().getDeclaredMethod("deleteProduct", Long.class);
method.invoke(service, productId);
} catch(Exception e){
log.info(e.getMessage());
}
I couldn't delete the product:
I get this info:
com.franceFactory.services.ProductManager.deleteProduct(java.lang.Long)
the product isn't deleted :(
The various getDeclaredMethod() and getDeclaredMethods() only return methods declared on the current class instance. From the javadoc:
This includes public, protected, default (package) access, and private methods, but excludes inherited methods.
The important part here is "but excludes inherited methods". This is why you are getting an exception with your code as it currently stands, it is not returning the deleteProduct() method from the parent class.
Instead if you wanted to continue using reflection you would need to use the getMethod method as this returns all public methods, "including those declared by the class or interface and those inherited from superclasses and superinterfaces."
If you have to use reflection then don't use getDeclaredMethod() because (as its name suggest) it can return only methods declared in current class, while you claim you want to invoke method declared in other class (to be precise declared in super class).
To get public method (including also inherited ones) use getMethod().
If your are overriding that method, just use the reserved word super (from the Oracle documents):
public class Superclass {
public void printMethod() {
System.out.println("Printed in Superclass.");
}
}
public class Subclass extends Superclass {
// overrides printMethod in Superclass
public void printMethod() {
super.printMethod(); // This calls to the method defined in the superclass
System.out.println("Printed in Subclass");
}
public static void main(String[] args) {
Subclass s = new Subclass();
s.printMethod();
}
}
This code will write:
Printed in Superclass.
Printed in Subclass
In other case (you are not overriding it, just using it), just write this.methodName(...). All methods inherited are directly available.
Disclaimer: I am not sure I totally understand your question. I will still try to answer what I think I understand.
The Product in package com.franceFactory.services (Lets call it A)
extends The Product class in package com.services (Lets call it B)
So A extends B.
B has method deleteProduct(java.lang.Long)
A overrides the method deleteProduct(java.lang.Long)
You have instance of Class A. So by OOPS concept method deleteProduct of object A is going to get called.
There is no way you can call the super method from outside unless you have the instance of class B.
EDIT
OPs Clarification yes, it's public, but it isn't overridden in my class
The method in super is getting called here. The product is not getting deleted for reason on what is written on the method.
Consider
class MyClass{
public MyClass(Integer i){}
}
class MyExtendedClass extends MyClass{
public MyExtendedClass(SomeType s){ ... }//Compile error if SomeType!=Integer
public MyExtendedClass(Integer i){
super(i);
...
}
}
Why we cant define constructor of MyExtendedClass with signature different from MyClass's constructor? Why we must call a constructor of superclass firstly?
You can define a constructor with a different signature. But in the constructor of the subclass you have to call the constructor of the base class. The base class needs to initialize itself (e.g. its private members) and there is no other way to do it other than by calling one of its constructors.
Why we cant define constructor of MyExtendedClass with signature different from MyClass's constructor?
You can of course do it. The error you are getting is for a different reason.
Why we must call a constructor of superclass firstly?
Because that is how the objects of your class are initialized. An object's state comprise of all the fields in it's own class, plus all the non-static fields of all the superclasses.
So, when you create an instance, the state should be initialized for all the superclasses and then finally of it's own class. That is why the first statement of a constructor should be super() chaining to the superclass constructor, or this() chain to it's own class constructor.
The reason your code probably failed is, you are trying to call the superclass constructor with string argument. But there is no such constructor currently. The super class has just a single constructor taking an int argument. Also, adding super() would not work too. Because your superclass doesn't have a 0-arg constructor.
Try changing your constructor to:
public MyExtendedClass(SomeType s){
super(0);
}
and it would work. Alternatively, add a 0-argument constructor to your super class, and leave the subclass constructor as it is. It would also work in that case.
Suggested Read:
I wrote a blog post on Object Creation Process
Your constructor can have a different signature. But you must call one of super constructors. This is how Java works, see the Java Language Specification.
Alternative 1: You can call a static method, like following:
public MyExtendedClass(SomeType s){ super(convertToInt(s)); }
private Integer convertToInt(SomeType st){ ... }
Alternative 2: Use composition / delegate instead of inheritance.
class MyExtendedClass [
private MyClass delegate;
public MyExtendedClass(SomeType s){
do what you want
delegate = new MyClass(...);
}
public void doSomething(... params){
delegate.doSomething(params);
}
I have the following code snippet that attempts to use this and super.
class SuperClass
{
public final int x=10;
public final String s="super";
public String notOverridden()
{
return "Inside super";
}
public String overrriden()
{
return "Inside super";
}
}
final class SubClass extends SuperClass
{
private final int y=15;
private final String s="sub"; //Shadowed member.
#Override
public String overrriden()
{
return "Inside sub";
}
public void test()
{
System.out.println(super.notOverridden());
System.out.println(this.notOverridden());
System.out.println(this.overrriden());
System.out.println(super.overrriden());
System.out.println(this.s);
System.out.println(super.s);
System.out.println(this.x);
System.out.println(super.x);
System.out.println(this.y);
}
}
public final class Test
{
public static void main(String[] args)
{
SubClass subClass=new SubClass();
subClass.test();
}
}
In this simplest of Java code, the statements that redirect the output to the console inside the method test() within the class SubClass display the following output.
Inside super
Inside super
Inside sub
Inside super
sub
super
10
10
15
So, it appears that there is no difference between this and super, when they are used to access methods which are not overridden in its subclass(es) and in case of variables, when they are not shadowed in its subclass(es).
Both of them tend to point to super class members. There is however, an obvious difference, if such is not a case.
Are they same, when methods are not overridden or variables are not shadowed in respective subclasses?
So, it appears that there is no difference between this and super,
when they are used to access methods which are not overridden in
its subclass(es) and in case of variables, when they are not
shadowed in its subclass(es).
There is a difference. If you override methods in third class, and call test from it, you will see, that super still calls implementations of SuperClass. And this will call new implementations (overridden).
Addition:
this.method() usage implies the method belongs to instance of the object. So the last implementation will be used (with exception of private methods).
super.method() usage implies method of the instance, but implemented before the current class (super, or super.super etc).
Yes, they are the same. notOverridden methods and not shadowed variables are inherited by subclass.
To better understand this, knowing how object is located in memory is helpful. For example in the figure below. Assume it's an object of a subclass. The blue area is what it inherits from its parent, and the yellow area is what is defined by itself. The method has the similar design except that it uses a Vtable.
Child object has the same memory layout as parent objects, except that it needs more space to place the newly added fields. The benefit of this layout is that a pointer of parent type pointing at a subclass object still sees the parent object at the beginning.
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.