Since the subclass is not constructed yet, is it unsafe to call an abstract method in a super class constructor?
However, if the method's behaviour does not depend on the constrction of subclass, e.g. just return a constant with regard to the subclass, is it still unsafe or will it work reliably?
Moreover, if it works, how to do it if I do not want to make the super class abstract?
Update: for last question
public class SuperClass {
public SuperClass() {
System.out.println(getValue());
}
public String getValue() {
return "superclass";
}
public static void main(String[] args) {
new SubClass();
}
}
class SubClass extends SuperClass {
public SubClass() {
super(); // Comment out this or not will not affect the result
}
public String getValue() {
return "subclass";
}
}
I wrote a test, and figure it out: the result is : subclass
Thanks to #Tim Pote's example.
It is generally (though not necessarily) considered unsafe. As you said, the superclass may not be fully constructed, and therefore won't be ready to handle all of the calls a subclass might make in its overridden method.
However, in the case that all subclasses simply return a constant that isn't dependent on any other method, then it should be fine. The only downside is that you can't guarantee that a subclass will override that method in an appropriate manner.
In regards to your last question: this isn't an issue of an abstract vs. concrete superclass. This is an issue with calling overridable methods in a constructor. Abstract vs. concrete is beside the point.
Edit in response to the OP's comment
I'm not certain what you mean by "polymorphiscly". Calling a virtual method always invokes the sub-most implementation. The only time a superclasses implementation is invoked is via the super keyword. For example:
public class SuperClass {
public SuperClass() {
System.out.println(getValue());
}
public String getValue() {
return "superclass";
}
public static void main(String[] args) {
new SubClass();
}
public static class SubClass extends SuperClass {
public String getValue() {
return "subclass";
}
}
}
prints subclass.
And this:
public class SuperClass {
public SuperClass() {
System.out.println(getValue());
}
public String getValue() {
return "superclass";
}
public static void main(String[] args) {
new SubClass();
}
public static class SubClass extends SuperClass {
public String getValue() {
return super.getValue() + " subclass";
}
}
}
prints superclass subclass
As others have explained there is an inherent risk in calling abstract methods in super class constructor.
The one exception I have found is when the subclass provides some "constant" information, e.g getId(), getHandledMessages() and suchlike.
Related
Method calls are always determined based on the runtime type of the object, however how can I call shadowed methods of base classes from an inherit instance?
class Base {
String str = "base";
String str() { return str; }
}
class Impl extends Base {
String str = "impl";
String str() { return str; }
}
class Test {
public static void main(String[] args) {
System.out.println(((Base) new Impl()).str); // print 'base'
System.out.println(((Base) new Impl()).str()); // print 'impl'
}
}
For example above, how can I call the str() method of Base class from an Impl instance, preferably without using reflection?
Using the Keyword super
Accessing Superclass Members
If your method overrides one of its superclass's methods, you can invoke the overridden method through the use of the keyword super. You can also use super to refer to a hidden field (although hiding fields is discouraged). an example below.
public class Superclass {
public void printMethod() {
System.out.println("Printed in Superclass.");
}
}
calling printMethod since child class
Here is a subclass, called Subclass, that overrides printMethod():
public class Subclass extends Superclass {
// overrides printMethod in Superclass
public void printMethod() {
super.printMethod();
System.out.println("Printed in Subclass");
}
public static void main(String[] args) {
Subclass s = new Subclass();
s.printMethod();
}
}
if you want to read more
https://docs.oracle.com/javase/tutorial/java/IandI/super.html
I am trying to create a generic method, but it requires data from the sub class. Is there a way to do this, or is there a better implementation?
Example of my situation:
public class Super {
public static Object method() {
return doSomethingWith(specificToSubClassValue);
}
}
public class Sub1 extends Super {
public static String specificToSubClassValue = "123";
}
public class Sub2 extends Super {
public static String specificToSubClassValue = "456";
}
I obviously cannot do this. What is a better approach?
One alternative I can think of is to override the #method method in each sub class, but it will be the same code in each instance so I wanted to throw it in the parent class (and it won't be truly overridden since it is static), but I am not sure how to approach it since it is dependent on the sub class value.
Static methods in Java can't be overwritten, and can't access children-specific information: they know nothing about inheritance.
What you need here is instance method, which you can overwrite. An you also may use generics.
public class Super<T> {
public Object method() {
final T specificToSubClassValue = getSpecificToSubClassValue();
if (specificToSubClassValue != null) {
return specificToSubClassValue.hashCode();
} else {
return null;
}
}
protected T getSpecificToSubClassValue() {
return null;
}
}
class Sub1 extends Super<String> {
#Override
protected String getSpecificToSubClassValue() {
return "abc";
}
}
class Sub2 extends Super<Integer> {
#Override
protected Integer getSpecificToSubClassValue() {
return 123;
}
}
Declare an abstract method in Super, which will be used to return the value from the implementing classes. Note that this can only be achieved with non-static methods. As per #JB Nizet's comment, static methods cannot be overriden by subclasses. I've removed the static modifier from the code below to shown you how it would work.
public class Super {
public static Object method() {
return doSomethingWith(specificToSubClassValue);
}
protected abstract Object getValue ();
}
public class Sub1 extends Super {
public static String specificToSubClassValue = "123";
#Override
protected Object getValue () {
return specificToSubClassValue;
}
}
public class Sub2 extends Super {
public static String specificToSubClassValue = "456";
#Override
protected Object getValue () {
return specificToSubClassValue;
}
}
Well, te whole idea of inheritance is that the superclass should not be able to do that much without the sub-class. Otherwise the whole inheritance would be pointless exercise and spaghetti code. But you are tackling the problem the wrong way. Make sub-class "spill" the data you need (through getter) and use the generic method from superclass on the data in the sub-class.
Also the overriding of super class methods is highly overrated. You should strive for your super method to be as flexible and re-usable as possible, and even then strive rather for overloading, instead of overriding.
You could have:
public class Super {
public Object method(String specificValue) {
return doSomethingWith(specificToSubClassValue);
}
And then have your sub do this
public class Sub1 extends Super {
public static String specificToSubClassValue = "123";
Object method(specificToSubClassValue);
}
This way you accomplish exactly what you want, operate on the class specific value using the super method.
I have an abstract super class A with a method doSomething(). A sub-class of A must implement doSomething(), but there is also some common code that should be called every time a subclass calls doSomething(). I know this could be achieved thus:
public class A {
public void doSomething() {
// Things that every sub-class should do
}
}
public class B extends A {
public void doSomething() {
super.doSomething();
// Doing class-B-specific stuff here
...
}
}
There seem to be three issues with this, though:
The method signatures have to match, but I might want to return something in the sub-class methods only, but not in the super-class
If I make A.doSomething() abstract, I can't provide a (common) implementation in A. If I don't make it abstract, I can't force sub-class to implement it.
If I use a different method to provide the common functionality, I can't enforce that B.doSomething() calls that common method.
Any ideas how the methods should be implemented?
What about the following?
public abstract class A {
protected abstract void __doSomething();
public void doSomething() {
// Things that every sub-class should do
__doSomething();
}
}
public class B extends A {
protected void __doSomething() {
// Doing class-B-specific stuff here
...
}
}
The first bullet point however is not so clear. The signature can't match if you want to return something different.
add call back to doSomething()
public class A {
public void doSomething() {
// Things that every sub-class should do
doSomethingMore()
}
}
protected abstract void doSomethingMore()
so all subclusses will have to ipmelment doSomethingMore() with additional actions but external classes will call public doSomething()
For first point alone - you can consider the below answer and for enforcing subclass implementation it can be abstract but calling common code functionality can happen if the base class has some implementation.
Return type can be Object in Base Class and returning null. In SubClass the specific return type can be put as given below.
public class InheritanceTutorial {
static class Base{
public Object doSomething(){
System.out.println("parent dosomething");
return null;
}
}
static class SubClass extends Base{
public Integer doSomething(){
super.doSomething();
System.out.println("child dosomething");
return 0;
}
}
/**
* #param args
*/
public static void main(String[] args) {
SubClass subClass = new SubClass();
subClass.doSomething();
}
}
what is the need of having a rule like this in java :
"a subclass cannot weaken the accessibility of a method defined in the superclass"
If you have a class with a public method
public class Foo {
public void method() {}
}
This method is accessible and you can therefore do
Foo foo = new Foo();
foo.method();
If you add a subclass
public class Bar extends Foo {
#Override
public /* private */ void method() {}
}
If it was private, you should not be able to do
Foo bar = new Bar();
bar.method();
In this example, a Bar is a Foo, so it must be able to replace a Foo wherever one is expected.
In order to satisfy the above statement, a sub class cannot make an inheritable member less accessible. It can however make it more accessible. (This basically only applies to methods.)
What it means
The subclass method cannot have a more restrictive visibity than the superclass method.
For example, if the superclass defined
protected void a() { } // visible to package and subclasses
the subclass can override it with one of
public void a() { } // visible to all
protected void a() { } // visible to package and subclasses
but not
void a() { } // visible to package
private void a() { } // visible to itself
Why it is
Suppose the definition was
class A {
public void a() { }
}
class B extends A {
private void a() { }
}
Now, consider the following code
A instance = new B();
instance.a(); // what does this call?
On the one hand, any B has a publically accessible a method. On the other hand, the a method of a B instance is only accessible to B.
More generally, a subclass(interface) must fulfill the contract of its superclass(interface).
Visibility is only one example of this principle. Another example is that a non-abstract class must implement all methods of any interface it implements.
class Person {
public String name() {
return "rambo";
}
}
// subclass reduces visibility to private
class AnonymousPerson {
private String name() {
return "anonymous";
}
}
It's legal to call the following method with either a Person, or an AnonymousPerson as the argument. But, if the method visibility was restricted, it wouldnt' be able to call the name() method.
class Tester {
static void printPersonName(Person p) {
System.out.println(p.name());
}
}
//ok
Tester.printPersonName(new Person());
this call is legal, because a Person is a AnonymousPerson, but it would have to fail inside the method body. This violates "type safety".
Tester.printPersonName(new AnonymousPerson());
To fulfill the interface contract. Let's say I have an interface, IFlying, as:
public interface IFlying {
public void fly();
}
And I have an implementation that weakens accessibility:
public class Bird implements IFlying {
private void fly(){
System.out.println("flap flap");
}
}
I now have some library function that accepts an IFlying, and calls fly upon it. The implementation is private. What happens now? Of course, it means that the fly method cannot be accessed.
Hence, the accessibility may not be made more restrictive in an implementation.
need some help on this, If interface cannot have a constructor, what happens here?
interface A{
String toString();
}
public class B{
public static void main(String[] args) {
System.out.println(new A() {
public String toString() {
return "what happens here!!";
}
});
}
}
An instance of an anonymous class implementing A is created.
This has very little to do with constructors, except that the default no-arg constructor will be called, and the toString() method is already defined in the Object class, so the interface is superfluous.
public static void main(String[] args) {
System.out.println(new A() {
public String toString() { return "what happens here!!"; }
});
}
can be more explicitly rewritten as follows:
public static void main(String[] args) {
class ImplA() extends Object implements A {
public ImplA() { super(); }
public String toString() { return "what happens here!!"; }
}
System.out.println(new ImplA());
}
From the above you can understand the following:
the local class ImplA is a subclass of Object and also implements A;
Object has a nullary constructor;
ImplA defines a nullary constructor, which delegates to Object's nullary constructor;
the constructor thus declared is called when writing new ImplA();
Your version of code just employs Java's syntactic sugar which lets you combine local class declaration with class instantiation into a single expression.