I didn't get to understand the polymorphism.
taking this example :
Object o = new String ("foo");
I can't do
o.substring (1,2)
can anyone explain this problem to me ?
This is a consequence of the Liskov Substitution Principle, which states (summarized):
If S and T are objects, and T is a subtype of S, then T may be used where S is expected.
String is-a subtype of Object, so if your assignment operation expects Object, then it will happily accept Object or any of its subtypes.
(Note: Object is not a String. All Strings are Objects, but not all Objects are Strings.)
This doesn't mean you get access to any of the subtype's methods. Given the inheritance hierarchy, an Object has no clue about any of its children's specific methods, nor can it - there is no way to inform an ancestor class of its descendant's capabilities. Because Object has no substring method associated with it, your code correctly results in a compilation failure.
(And it should, given that Object is the ancestor of all classes. There's no guarantee that any given Object is a String.)
The standing advice is to not use an overly inspecific object type (as you go up the hierarchy chain, the capabilities become less specific - you lose functionality as you go up to Object) to accomplish something specific to a more specific type.
You are confusing dynamic and static typing with polymorphism.
Java is a statically typed language so the compiler recognizes that Object doesn't have a substring() method and throws an error. Polymorphism happens after the compilation, when the code is actually executed.
First thing It's not polymorphism.
In Simple way, In your case o object will only call methods which are defined in Object class. If String class has overridden any method of Object class then object o will execute that method of String class otherwise Object o will call Its own method.
For example :
substring() method is only defined in String class So In this case your code will throw exception, however if you call equals() , hashcode() , toString() methods (as these are defined in Object class ) then definition inside String class will get executed because String Class has overridden these methods. And if any of the methods from object Class has not been overridden in its child class then definition inside Object class will get executed.
substring is from the String class, not the Object class. So the below code will work:
String o = new String ("foo");
o.substring(1,2);
This code will not work:
Object o = new String ("foo");
o.substring(1,2);
Since String inherits from Object, String can call Object's methods, such as toString. However, Object does not inherit from String, so an Object cannot call String's methods, such as substring.
Related
I'm seeing this syntax and can't understand what it means. It doesn't look like a regular object instantiation. The 'new' keyword isn't there and the class name is put in parenthesis... then there's a method call at the end.
MyClass myObj = (MyClass) someMethod(arg);
In Java,
someMethod(arg)
is a call of a method named someMethod with a single parameter arg.
All methods (except void ones) return a value. The type of the return value is part of method definition. In your case, we don't know what the someMethod returns (because you didn't provide its definition), but we can assume it is not void.
The expression
(MyClass) obj
is a type cast, which tells the compiler to treat obj as if it was of type MyClass. During compilation, compiler checks that the definition of obj is compatible with MyClass, and if it is, it allows you to treat it like one. During run time, Java virtual machine checks that the actual object obj is actually instance of class MyClass. If it is not, it will throw a ClassCastException.
Typically, type casts are used to "upgrade" how the compiler sees an object into something more specific. For example, if a pet shop by definition sells Animals, and you ordered a Hamster, then you can reasonably assume thet what you get is not just an Animal, but a Hamster (assuming Hamster extends Animal).
Now, put this together and you get a type cast applied to a method return value.
There is a method somewhere that is returning an object based on the arg arugment. The developer has provided a cast, to coerce the object into the MyClass type.
This is common in a Singleton pattern (where the same object instance is returned if the arg argument is the same), or in a static constructor. Usually the method is doing a new MySubclass( ... ) somewhere and returning that.
If you have only a Class object, how does one get a method reference to a method such as toString? Later we will have instances of this particular class on which we will invoke this method via the method reference.
For example, consider a Java enum, a subclass of Enum. Here T is defined as <T extends Enum>.
Class c = MyEnum.class
…
Function< T , String> f = c :: toString ;
I get an error saying "invalid method reference".
For toString, it's as easy as Object::toString. All Objects have toString, so you can use it right there. For other methods where you don't know statically that the object has that method, there's no easy way; you have to write a lambda that does it the ugly reflective way.
If you can access your Class object using a class literal in the form Class<MyEnum> c=MyEnum.class;, it implies that the type MyEnum is known at compile time. In this case, the Class object is an unnecessary detour. You can access all methods of the class MyEnum using the form MyEnum::methodName, e.g.
Function<MyEnum,String> f=MyEnum::toString;
This is what the tutorial describes as “Reference to an Instance Method of an Arbitrary Object of a Particular Type”. It doesn’t require an actual MyEnum instance.
Nevertheless, there is no point in dealing with MyEnum when you want to have a Function<T,…> as that function must be able to consume arbitrary instances of T, not necessarily being MyEnum. So this function can only use methods existing in T and it doesn’t need to search them in MyEnum.
Since your target method is not specific to MyEnum, that’s possible:
Function<T,String> f=T::toString;
But as already pointed out, the method toString is defined in java.lang.Object, so you may also use the form
Function<T,String> f=Object::toString;
as a method declared for all objects may also get invoked on instances of T. Though even this is a bit pointless as you can also use
Function<Object,String> f=Object::toString;
reflecting the ability to consume any instance of Object, not just T. Carefully written Generic code will always use wildcards to avoid unnecessary restrictions regarding its input. So it will accept a function which can consume T (which implies the ability to consume MyEnum) without requiring its type parameter to exactly match that type. For example:
<R> Stream<R> map(Function<? super T,? extends R> mapper)
map, applied on a Stream<T> will accept a Function<Object,…> as Object is a supertype of T…
So you can use T::methodName to access every method available for the bounds of that type, i.e. in your case you can use all methods of Enum and, of course, Object, but no methods specific to MyEnum not present in its supertypes. This isn’t different to ordinary method invocations you try to apply on instances of T. Further, a method not present in T wouldn’t be eligible for creating a valid Function<T,…> anyway.
If you want to create Function instances for methods not known at compile-time, you will have to use Reflection, and this is the only case where you have to deal with Class objects (in the context of method references). The second example of this answer shows how to create a Function for an instance method returning an object but that’s really only for those who know precisely what they are doing…
Note also that such reflectively created Functions have to use raw types as their appropriate generic type can’t be declared as it would refer to a type not present at compile-time.
What you are trying here, is to get the reference of toString() for the class Class, which is probably not what you intended. As toString() is defined for all objects, this should work (not tested):
Function< T , String> f = t -> t.toString();
I know Java's constructors can't have any type and interestingly it cannot even be void. A logical explanation for that would be that a constructor returns the initialized object's reference.
MyClass myObject = new MyClass();
The constructor of myClass will now return the object reference after instantiating it and save it in the object variable MyObject and that's why the constructor can't have a return type.
Is that right? Could someone confirm this?
No, actually, the constructors are compiled into the class file like methods having the name <init> and a void return type. You can see these "<init>" invocations in stack traces. The expression new Type() is compiled as an instruction new which just creates the instance of Type and an additional method invokation (invokespecial) to one of the constructors declared in Type.
The verifier will ensure that such a special method is invoked at exactly once on a newly created instance and that it is called before any other use of the object.
It’s just a programming language design decision to let constructors have no return type from the Java language point of view. After all, new Type(…) is an expression that evaluates to the newly created instance of Type and you can’t get a return value from the constructor with that programming language construct. Further, if you add a return type, Java will unconditionally assume that it is a method, even if it has the same name as the class.
That’s simply how it was defined: (It makes parsing the class definition easier)
The SimpleTypeName in the ConstructorDeclarator must be the simple name of the class that contains the constructor declaration, or a compile-time error occurs.
In all other respects, a constructor declaration looks just like a method declaration that has no result (§8.4.5).
I suppose you could say that constructors have a "special syntax" used specifically for returning instances of the desired object. You do not specify the return type in these cases. The new keyword is used together with the constructor method to produce an instance of the class type.
If you'd like to control the return type of an instance generation method, then you should probably be looking at using a type of factory design pattern, wherein a static method creates an instance (using a constructor), and then returns a more explicit type (say for example, the super type, or an interface type).
This pattern is good when you'd like to decide which type to return based on some parameter, but leave the actual type hidden to the consumer of the instance generation method.
A constructor is not a methed. It does not return anything. It is used for initialization purposes, especially useful when those initializations depend on parameters or there is a chance that exceptions will be thrown (though both are optional).
So, unlike a method, it is not inherited and does not have a return type (not even void).
The idea is that you are "constructing" an instance of MyClass by calling the constructor itself. The idea of the constructor is to instantiate and not to return. Having created myObject you can then refer to public methods and variables part of its declaration which will provide you with the required data being returned as an answer to a call. It is important to understand that the constructor does not return anything it simply creates an instance which can then be used to refer to methods and variables (which return data) declared within the instantiated class.
I don't understand why this works in java:
If I have an Integer object in a object, example:
Object myIntObj = new Integer(5);
Now if i do:
System.out.println(myIntObj);
the output is: 5
I now that the Integer class has an ovveride of the toString method but in this case is different (I think).
For the polymorphism, if I have a "child object" in a "father variable" the object doesn't change its real type (in this case Integer) But... it (in the Object variable) can just use the method of the Object Class, so why if I write:
System.out.println(myIntObj);
I can see directly the number 5 and not the reference of this object? Because toString method in the object class by default return just a string of the reference of the object.
like:
Object currentPlayer = new Player();
System.out.println(currentPlayer);
In this case the output is the reference of the Player objecet because is called the toString method in the object class.
So why in the example of before I don't see the reference but directly the number?
by logic, the rules of the polymorphism says that: if u have a "child" object in a "father" variable, this object, inside, remanis the same but he is used like an istance of object, so he can just uses the class object and so just the method of object, so is really strange that I don't see the reference but directly the number.
I hope you understand what I mean.
Your last paragraph where you explain your reasoning is slightly incorrect.
so why in the example of before i don't see the reference but directly
the number? by logic, the rules of the polymorphism says that: if u
have a "child" object in a "father" variable, this object, inside,
remanis the same but he is used like an istance of object, so he can
just uses the class object and so just the method of object, so is
really strange that i don't see the reference but directly the number.
The beginning is correct, but the part I bolded is an incorrect conclusion you drew from it.
You are correct that with polymorphism, the object truly remains whatever type it is, but the reference type (the type of the variable) defines what you can do with it. However, the reference type does not describe what the object does
That is the intent behind polymorphism. It is an abstraction to define what can be done separately from how it works. For example, if you have this example:
public class Vehicle {
public int getWheelCount() {
return 1;
}
}
public class Car extends Parent {
public int getWheelCount() {
return 4;
}
public void blowHorn() {
System.out.println("Honk honk!");
}
}
public class Bicycle extends Parent {
public int getWheelCount() {
return 2;
}
}
Car car = new Car();
car.getWheelCount(); // 4
car.blowHorn(); //"Honk honk!"
Vehicle v = new Car();
v.getWheelCount() // 4
v.blowHorn(); // COMPILE ERROR HERE! Unknown method
Bicycle b = new Bicycle();
b.getWheelCount(); // 2
Vehicle v = new Bicycle();
v.getWheelCount(); // 2
What you can conclude from this is that when over-riding a method in a sub-class, the child version is always called. A car is always a car whether you are referring to it as a vehicle or as a car. But by referring to it as a vehicle, you are limited to invoking methods which are defined on all vehicles.
To tie it to the example, all Vehicle objects have a wheel size, therefore getWheelCount() is always callable whether it's Vehicle.getWheelCount() or Car.getWheelCount(). However, Car.getWheelCount() is what executes because Car over-rides it.
If the reference type is Vehicle, you cannot call blowHorn() because that method is only available on Car.
Going back to your example, an Integer is an Integer.
Object i = new Integer(5);
i.toString(); // 5
This prints 5 because i is an integer. The Integer class over-rides toString. The reference type (the type you are referring to the object as) only determines which methods you can call, but not which parent/child class's version of the method is called.
By defining it as Object this means you will only have access to methods that are defined in the Object class.
This includes toString().
So when you instantiate new Player() you still only have access to the methods from Object, but if you override this (like Integer.toString() does), you will still have the output as defined in the instantiated class.
PS: Father -> Parent
This is how the concept of overriding methods works: once an object somewhere in the inheritance hierarchy provides an implementation, it is this implementation that is going to be called, unless it is overridden by another class further down the inheritance hierarchy.
Since java.lang.Integer provides an override of toString(), this override is called instead of the implementation provided by the java.lang.Object.
There is no difference between System.out.println(myIntObj) and System.out.println(myIntObj.toString()), because println will call toString internally on all objects which it does not know how to print.
The reason your Player class behaves differently is that it does not override toString(). If it did, you would see its results printed. With no override, however, the default implementation provided by java.lang.Object is called, which prints some generic object info.
Object myIntObj = new Integer(5);
Here you're creating a new Integer instance, not a bare Object instance. The fact that you're assigning it to an Object reference doesn't transform it into a bare Object. It's still an Integer, but you can reference it as an Object because it extends Object. So when you call myIntObj.toString(), you're calling that instance's toString() method. That instance turns out to be an Integer instance. And so Integer.toString() is called.
Object currentPlayer = new Player();
In this case the same rules apply when calling currentPlayer.toString(): you're actually calling Player.toString(). If Player class does not override toString(), then first ascending parent class toString() implementation is called. If Player directly extends Object, then Object.toString() is called, but if for example Player extends Human and Human extends Object, then Human.toString() is going to be called if it exists. If not, then Object.toString().
Consider this case where Employee has a subclass Manager that has a method getDetails() overridden,
Employee e=new Employee();
Employee m=new Manager();
If you invoke e.getDetails() you will get the behavior associated with Employee.
If you invoke m.getDetails() you will get the behavior associated with Manager.
In general, you get the behavior associated with the object to which the variable refers at runtime. This behavior is often referred to as virtual method invocation.
So the reason why you are getting the behavior associated with Integer when your reference is an object is because you are referring to an Integer object at runtime.
Consider the following code from The Java Programming Language book
public class MyClass extends HerClass implements Cloneable {
public MyClass clone()
throws CloneNotSupportedException {
return (MyClass) super.clone();
}
// ...
}
When the overiding clone() function already species the return type as MyClass then what is the requirement of specifying it again in the return statement ?
Also since the clone of Myclass's super class object is being created (cause clone() is being called wrt superclass), how can it be of Myclass type?
Thanks in advance
Because clone() returns an object of class Object, and you must cast it to the correct type. But you know it is an object of type MyClass, so that cast is correct.
In theory you're right: as you have to specify the type of function return values the compiler could try and perform the correction automatically. On the other hand requiring an explicit conversion helps identify possible errors.
Unless you have specific requirements the clone() method of the Object class already does the right thing, i.e. it creates an object of the correct class and copies all the non-static attributes in the cloned object. However it cannot return it as a derived type because at compile time that type is not known to the Object class itself.
It is true that the clone() method could have been provided automatically for all classes, but sometimes you don't want it to be available and at other times you want to override the default behaviour; for instance you might have an id attribute in your class that you want to be different for each instance of your class even when cloned. Having to override the clone() method gives you a place where you can implement such functionality.
This is because the clone() method in Object returns an Object. However you can return your subclass in clone() because it extends an Object. If the method in MyClass looked like this
public Object clone()
Then it would still be a valid cloneable object and it would work. You wouldn't need to cast anything. The interface, Cloneable is just a marker interface, which means it doesn't actually have any methods.
Your easy question first: why is super.clone() cast to MyClass? That's because the declaration of HerClass.clone() specified a returned value of HerClass, so you must cast it to the right type.
Now, for the more difficult question: how can super.clone() actually return an instance of MyClass? I actually had a hard time finding the answer, but I did somewhat find an answer in Effective Java by Joshua Bloch. There is still some "magic" in the background of Object.clone() that I don't quite understand.
Item 11 from the book:
In practice, programmers assume that if they extend a class and invoke
super.clone from the subclass, the returned object will be an instance
of the subclass. The only way a superclass can provide this
functionality is to return an object obtained by calling super.clone.
If a clone method returns an object created by a constructor, it will
have the wrong class. Therefore, if you override the clone method in a
nonfinal class, you should return an object obtained by invoking
super.clone. If all of a class’s superclasses obey this rule, then
invoking super.clone will eventually invoke Object’s clone method,
creating an instance of the right class.
I originally tried to answer your question by writing a program without knowing you always had to call super.clone(). My homemade clone method for HerClass was returning a new instance of HerClass generated from a constructor (new HerClass()). The code compiled, but it failed at execution when I was trying to cast (MyClass) super.clone(). Only methods that are chained down from Object.clone() can return a value that is an instance of one of their subtype.
Note that if HerClass.clone() is not explicitly implemented, by default it simply returns Object.clone(). The default method has protected access, but since you are calling it from a subclass, it's not a problem.