What address is super in 4th line pointing to in the following code?
public class SuperChk {
private void test() {
System.out.println(toString());
System.out.println(super.toString()); //4
}
#Override
public String toString() {
return "Hello world";
}
public static void main(String[] args) {
SuperChk sc1 = new SuperChk();
sc1.test();
}
}
Look at it this way.
Implicitely, your class will inherit from the superclass Object so you can access your object either with an Object reference or with a SuperChk reference
Object
public class Object {
// Other methods
public String toString(){
// This is the method super.toString() will use once called in SuperChk
return getClass().getName() + "#" + Integer.toHexString(hashCode());
}
}
SuperChk
public class SuperChk extends Object {
private void test() {
System.out.println(toString());
System.out.println(super.toString()); //4
}
#Override
public String toString() {
return "Hello world";
}
public static void main(String[] args) {
SuperChk sc1 = new SuperChk();
sc1.test();
}
}
Output
Hello world
SuperChk#15db9742
You can see that the toString() method from the Object class prints :
The class name first.
Then "#"
Then the hexadecimal representation of the HashCode which is also defined in a method of the superclass Object
Classes in Java all derive from Object. Since you have no explicit parent class, then the parent is Object and super is referencing Object. Object does support the toString() method. See the Java class hierarchy.
super is not an expression. So super does not "point to" anything, and you cannot use super by itself.
super.something() is an expression that allows you to call a method on the object that this points to, but the lookup for which implementation to call proceeds up from the superclass of the class whose code this is in, rather than up from the object's runtime class as would happen if you did this.something().
Here, both toString() and super.toString() are called on the object that this points to (which is a SuperChk instance). However, they call different toString() implementations -- in the first case, the lookup is based on the runtime class of the object, which is SuperChk, and SuperChk does provide its own implementation of toString(), so SuperChk's implementation is used. In the second case, the lookup is based on the class that is the superclass of the class the code is in (SuperChk), which is Object, so Object's toString() is used.
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
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.
Can any one explain?
When we are overloading a constructor with different parameters one having data type object and other having data type string, and when we are creating the object of this class with providing input parameter as null it is calling the constructor with string as input parameter but not the constructor having input parameter as Object. Since Object is the super class of String, can any one tell me why it is calling constructor with input parameter string?
Class A
{
public A(Object o)
{
System.out.println("Object Drawn");
}
public A (String o)
{
System.out.println("String Drawn");
}
public static void main(String args[])
{
new A(null);
}
}
Output:- String Drawn
It always calls the most specific matching method or constructor. If it didn't you would always call Object and overloading it would be pointless.
This approach is using in Java and C++
Why It calls base class method when we declare method as static in base as well as in derive class and do upcasting.
class Base
{
static void show(){
System.out.println("Base class....");
}
}
class Derive extends Base
{
static void show(){
System.out.println("Drive class....");
}//method hidding.....
public static void main(String[] args)
{
Base b= new Derive();
b.show();
}
}
There are several issues here to mention:
static methods are not inherited and not overridden by the sub-classes
static methods do not need an instance to be called, they need a class
So, basically, calling b.show(); actually means calling Base.show();
You're calling Base.show, not Derive.show. Method hiding is not overriding.
ยง8.4.8.2. of the Java Language Specification gives an example that demonstrates exactly what happens here:
A class (static) method that is hidden can be invoked by using a reference whose type is the class that actually contains the declaration of the method. In this respect, hiding of static methods is different from overriding of instance methods. The example:
class Super {
static String greeting() { return "Goodnight"; }
String name() { return "Richard"; }
}
class Sub extends Super {
static String greeting() { return "Hello"; }
String name() { return "Dick"; }
}
class Test {
public static void main(String[] args) {
Super s = new Sub();
System.out.println(s.greeting() + ", " + s.name());
}
}
produces the output:
Goodnight, Dick
because the invocation of greeting uses the type of s, namely Super, to figure out, at compile time, which class method to invoke, whereas the invocation of name uses the class of s, namely Sub, to figure out, at run-time, which instance method to invoke.
Just one more completion to the answers above. It's best to invoke class methods by their class not by an instance variable: Base.show() not b.show() to make clear that the method is a static method. This is especially useful in your case when you are hiding a method, not overriding it.
interface I
{
void show();
}
class A implements I
{
void show()
{
System.out.println("class A");
}
public static void main(String s[])
{
I i=new A();
i.show();
i.toString();
}
}
Q> As interface I does not contain the abstract method toString() but still The following code gets compiled. How?
when super class variable is used to refer sub class obj then compiler first searches the similar method in the super class if not found gives error.
here Interface does not contain the method toString().
ex=>
class A
{
void show()
{
System.out.println("show");
}
}
class B
{
void show()
{
System.out.println("show B");
}
void display()
{
System.out.println("display B");
}
public static void main(String s[])
{
A a=new B();
a.show(); //will execute
a.display(); //give error
}
All classes inherit from Object. Object has a toString.
To use any interface it must be backed by a actual class. So the Java compiler knows that it can use any method defined in java.lang.Object when dealing with an Interface.
To put it a slightly different way:
interface I { ... }
has an "magic"
interface I extends Object { ... }
So you can use Objects methods when detail with I. However you can not use any methods in the concrete class that do not appear in the interface. So to combine you two examples:
interface Car {
void drive();
}
class Convertible implements Car {
void drive() {}
void openRoof() {}
public static void main() {
Car porscheBoxster = new Convertible();
porscheBoxster.drive(); // OK - exists in interface
porscheBoxster.toString(); // OK - exists in java.lang.Object.
porscheBoxster.openRoof(); // Error. All we know is the porscheBoxster is of type Car.
// We don't know if it is a Convertible or not.
}
}
Every class in Java is an Object, thus, they are always able to run the following methods:
clone()
equals(Object)
finalize()
getClass()
hashCode()
notify()
notifyAll()
toString()
wait()
wait(long)
wait(long, int)
Because 'toString()' is in the class Object which every non-primitive data is derived from. So every object has this method.
In Java, every class you construct, inherits from the base class Object.
This means that your class by default will have a lot of useful methods, amongst others toString().