Say I have two classes where SubClass inherits from (extends) SuperClass.
What is the difference between:
SuperClass obj1 = new SubClass();
and:
SubClass obj2 = new SubClass();
Both will look to the constructor of the Superclass and initialise it (the correct one, obviously). Both have access to the superclass implementations. But one is (as far as I am aware) a subclass wrapped in a superclass (the first example) and the other is a subclass object (the second example).
How will this effect the way code is run and interpreted?
What are the real world issues that a developer needs to be aware of regarding how these two objects differ?
Thanks in advance for any help!
The only difference with initializing it as a superclass is that if the subclass implementation has methods which the superclass does not, they will not be accessible via this object reference.
But "internally", this is still an instance of the subclass; so, if you call a method defined in the superclass but the subclass has overriden it, it is the subclass' method which is called: the JVM looks up methods from the more specific to the more general.
As a convoluted example, let us take Object and String:
final Object o = "Hello!"; // in fact this calls new String("Hello!")
o.toString(); // <-- uses String's .toString(), not Object's
// Can't do that: String defines .subString() but Object does not
o.subString(1);
It may help to think what the compiler knows about and what the runtime knows and a simple example:
public class Product {
public double getPrice() {...}
}
public class Book extends Product() {
public int getPageCount() {...}
}
and a simple program:
Product p = new Product();
p.getPrice(); // OK
p.getPageCount(); // compiler error
Book b = new Book();
b.getPrice(); // OK
b.getPageCount(); // OK
Product pb = new Book();
pb.getPrice(); // OK
pb.getPageCount(); // compiler error
// but we can still use the getPageCount() of pb;
((Book)pb).getPageCount(); // compiles
// however if pb was not a Book then you would get a runtime error (ClassCastException)
You can test for the actual class by:
if (pb instanceof Book) {
((Book)pb).getPageCount();
}
This is often necessary when developing classes, but if your code has a lot of instanceof it probably needs rethinking.
SuperClass obj1 = new SubClass();
What you're seeing here is a type of substitutability. What this means is, let's say you make another sub class of SuperClass, SiblingClass. Without using the superclass reference type, we would have to change more code, getters and setters, collections that might want to use it. By referencing them as the supertype, all you need to do is pass in the new SiblingClass object on construction.
Related
This question already has answers here:
A Base Class pointer can point to a derived class object. Why is the vice-versa not true?
(13 answers)
Closed 7 years ago.
This is rather basic question. But I can't understand well the concept of inheritance.
Suppose I have two classes, A and B with both have a test() method that returned 1 and 2 respectively, and B inherited A class. In main method I declare the instance as such;
A a1 = new B();
and call the method a1.test(), it will return 2. This is the concept of polymorphism. But when I have a method test2() in just subclass, I can't call the method using the same instance declaration as above. Why is that happen?
I can't call the method using the same instance declaration as above. Why is that happen?
Because the type of the variable is A, and class A does not have a method test2(). The Java compiler only looks at the type of the variable to check if you can call a method, it does not look at the actual object (which is in this case a B).
This is all easier to understand if you use more concrete and meaningful names for your classes, instead of abstract names such as A and B. Let's call them Animal and Bear instead:
class Animal {
}
class Bear extends Animal {
public void growl() { ... }
}
class Cat extends Animal {
public void meow() { ... }
}
Animal a1 = new Bear();
Animal a2 = new Cat();
// Doesn't work, because not every Animal is a Bear, and not all
// animals can growl.
a1.growl();
// You wouldn't expect this to work, because a2 is a Cat.
a2.growl();
Because variable type is A, and class A does not have a method test2():
Rather you can use:
A a1 = new B(); // upcasting
B b1 = (B)a1; // Downcasting a1 to type B
b1.test2(); // now you can call test2 function
Because, the left side of your condition determines which method's you can call, and right side determines which methods will be called. So in this case class A does't have test2() method.
Imagine A = "TV" and B = "HD_TV".
You can say
TV tv = new HD_TV() // HD TV
and
TV tv = new TV() // ordinary TV
because an HD_TV is a TV.
You can say:
tv.show(movie)
It will show what is on TV, but you will get a better picture with the HDTV.
You cannot say:
tv.showHD(hdMovie) // Compiler error !!!
because in declaring tv as TV, you are saying it might not be an HD TV. Even though you can see that in this case it is, the compiler still respects your declaration that it is just a TV and you can only use methods supported for a TV.
That is because you are declaring the instance a1 as an A. Because B inherits A, you can call all the functions declared in A and they might have a different meaning if they are overloaded in B, but you do not have any access to B-only things.
You can see the first A as some kind of a header file, if you are familiar with that. It declares what A contains, without looking at how the functions are implemented or what the default vars are of everything in A. As a direct consequence, you can only access everything that is declared to literally be in A.
The left-hand side - A in this case - is the declared type, and it doesn't know about anything specific to child classes. The right-hand side - ´B´ in this case - is the actual type, and this provides the behaviour.
So, this will work because the declared type B knows about methods available in the class B.
B b1 = new B();
b1.test2();
If it was possible to have a1.test2(), that would mean every class would have to know about every child it has - including those in other libraries, when projects are assembled!
When B inherits A class and the reference of A is created with object of B like A a1 = new B();.
On Compile time java compiler looks for method availability in class A.
So it allows calling method test() but not the test2().
As test() method is available in class A but test2() is not available in class A.
You can type cast the object created like ((B)a1).test2().
This will work.
Here a1 object is of type A. a1 is pointing to an object of type B.
a1 is a reference of type A to an object of type B.
since a1 is of type A it know only test() which is declared in its class definition already. In case you want to access test2 declared in class B you need to type cast the a1 object back to B
like
B b1 = (B)a1
b1.test2() will be accessible.
This happens because you declare A variable and use B class which is an A. The compiler know it's an A but doesn't know it's a B later in the code. It's easier to use real life objects as example.
For example you have:
class Pet() {
method feed();
}
And a
class Dog() extends Pet {
method feed();
method bark()
}
If you have a code in another class:
So if you have code :
Pet dogPet=new Dog();
You know it's a dog here because you create the instance and you can use:
((Dog)dogPet).bark(); or just declare the variable as a dog instead of pet.
But if you have a method in another class:
void someMethod(Pet aPet){
// Here you don't know if the Pet is a dog or not. So you know only that it
//can be fed but you don't know if it barks. Even if a Dog is supplied to the method
}
In a1 = new B(), the actual type of the object created is B but you reference it as its supertype so you can call a method that accepts A (polymorphism).
So if a method is overridden in subclass, a1.test() is executing subclass's test().
In order to execute test2() you have to do that: ((B) a1).test2();
There is a concept called Up casting and Down casting.Up-casting is casting to a supertype, while downcasting is casting to a subtype. Supercasting is always allowed, but subcasting involves a type check and can throw a ClassCastException.,See the Example Code:
class A{
public int test(){
return 1;
}
}
class B extends A{
public int test(){
return 2;
}
public int test2(){
return 3;
}
}
and
A a1 = new B();
a1.test2();//not possible
Here you can't invoke methods of class B.
I´m having little diffculties understanding dynamic binding and inheritance in java.
Heres a liitle bit of code:
printer.print(person); // Printer is printing a person, which says: I am a Person
printer.print(specialPerson); // Printer is printing a special person, which says: I am a SpecialPerson
printer.print((Person)specialPerson); // Printer is printing a person, which says: I am a SpecialPerson
System.out.println(person); // I am a Person
System.out.println(specialPerson); // I am a SpecialPerson
System.out.println((Person)specialPerson); // I am a SpecialPerson
System.out.println(((Object)specialPerson).toString()); // I am a SpecialPerson
SpecialPerson is a child class of Person here. Both classes override the toString method. Also there is a class Printer which has 2 methods for person and specialperson objects. I understand the first 3 lines: it calls the printer class and executes the method with the matching type. The 3rd line the object is dynamically casted to a person object. But I don´t understand line 6: Why doesnt´t the casting of the object change the method which is called. Isn´t it called by the dynamic type but the static type?
If method is declared on the super object you can call it without compilation error and this is early-binding/static polymorphism. Which method will be executed depends on what the dynamic type of the object is and this is late-binding/dynamic polymorphism.
So for example:
public class Super {
public void foo(){};
}
public class Sub extends Super {
#Override
public void foo(){
System.out.println("sub");
}
public void bar(){};
}
Super s1 = new Super();
Super s2 = new Sub();
Sub s3 = new Sub();
s1.foo(); //prints nothing
s2.foo(); // prints "sub"
s3.foo(); // prinss "sub"
s2.bar(); // won't compile even though s2 is really a Sub object
In java all overridden methods are virtual methods as described here. This differs from other languages such as C++ where you need to use the virtual keyword to get this behaviour.
From Wikipedia:
Virtual functions are resolved 'late'. If the function in question is 'virtual' in the base class, the most-derived class's implementation of the function is called according to the actual type of the object referred to, regardless of the declared type of the pointer or reference. If it is not 'virtual', the method is resolved 'early' and the function called is selected according to the declared type of the pointer or reference.
Since there are only virtual methods in this case the function is called according to the actual type of the object referred to - it doesn't matter if you cast it to some base class object.
say, I have the following code (it's a quiz question, so I can run it in my IDE but the logic how it's working is not quite clear to me):
public class Test {
public static void main(String[] args){
A aInstance1 = new A();
A aInstance2 = new B();
A aInstance3 = new C();
aInstance1.doSth();
aInstance2.doSth();
aInstance3.doSth();
}
}
class A {
public static void doSth(){
System.out.println("Doing something in A");
}
}
class B extends A {
public static void doSth(){
System.out.println("Doing something in B");
}
}
class C extends B {
public static void doSth(){
System.out.println("Doing something in C");
}
}
The output will be the following:
Doing something in A
Doing something in A
Doing something in A
Thus, my first question is: what is the meaning of the declaration like
A aInstance2 = new B();
i.e., why to create an object of class B declaring it as an instance of class A? How the properties of aInstance2 as an object of class B change compared to the declaration
B aInstance2 = new B();
?
If I remove the word static from the declaration of the methods doSth() in the classes A, B, and C, the output changes to
Doing something in A
Doing something in B
Doing something in C
Thus, when the methods were static, the method doSth() of class A didn't get overridden by those of the subclasses and the output was always "Doing something in A" produced by the objects of different classes, whereas when it became an instance (non-static) method, it gets overridden (if I'm using the right term here). Why is it so?
Removing the word static you are doing Dynamic Binding , because you are pretty much saying : "Even though i know this object is of type A i want it to behave like a B ".
Adding the word static means you are making that method part of the class[Reference type] ,and each time you are calling :"A dosmth()" he knows it only applies to A so it shows the result of the mothod from the class A.
As to what would you do this?I for one learned about this feature from school and studied it even more when i decided to go to interviews becuase it;s one of the things that the interviewer wants to see if you can handle.
If you don't mind I will post a link with information about Static and Dynamic Binding
http://javarevisited.blogspot.ro/2012/03/what-is-static-and-dynamic-binding-in.html
Because static method is based on Reference type .
aInstance1.doSth();
aInstance2.doSth();
aInstance3.doSth();
So internally it converts into :
A.doSth();
A.doSth();
A.doSth();
Static methods are class methods while non-static ones are instance methods. Therefore, when you call a static method over an instance you are actually calling it over the declared type of this instance. So, all below calls actually performs the same call: A.doSth() since all instances are declared as type A.
aInstance1.doSth();
aInstance2.doSth();
aInstance3.doSth();
When you remove the static keyword, doSth() method becomes an instance method. Instance methods are performed over objects instead of classes. Moreover, when you re-declare an instance method in a subclass, this method is overriden by the subclass. In your example, class B and C override doSth(). Thus, each class provides its own implementation.
Overriding depends on having an instance of a class. A static method is not associated with any instance of a class so the concept is not applicable.
Making static methods works faster, because there's no need to wait until run-time to figure out which method to call.
Overriding in Java simply means that the particular method would be called based on the run time type of the object and not on the compile time type of it.
Illustration -
When doSth() is static:
A aInstance1 = new A();
A aInstance2 = new B();
A aInstance3 = new C();
aInstance1.doSth();
aInstance2.doSth();
aInstance3.doSth();
In the above code, the compiler will decide at compile time that without instance it should be called for A. No overriding.
When doSth() is not static:
A aInstance1 = new A();
A aInstance2 = new B();
A aInstance3 = new C();
aInstance1.doSth();
aInstance2.doSth();
aInstance3.doSth();
In the above code, the compiler will decide at run time that the method is not static and should be overridden by there respective instances.
static methods are at class level and act on the reference type(LHS of ==) unlike instance level methods which are dynamically dispatched based on the instance type(RHS of ==)
I am looking at the Interface chapter provided on the Java website
Using Interface as a type
So my understanding was that the whole point of interface is that it is like a class but it's not possible to form objects from it, but this page says how to use interface as a data type. the line Relatable obj1 = (Relatable)object1; seems to create an object of type Relatable which is an interface. Although I must say that the new keyword has not been used here, thus not really creating a reference to an object of type Relatable. Is that really the cause for this line NOT creating an object of type Relatable?
Again, it further says
If you make a point of implementing Relatable in a wide variety of
classes, the objects instantiated from any of those classes can be
compared with the findLargest() method—provided that both objects are
of the same class.
What does this mean? Does this mean anything that implements Relatable can call findLargest()? If it's so, why does it say provided that both objects are of the same class?
----- EDIT -----
From the previous chapters of this tutorial:
Definition of relatable:
public interface Relatable {
// this (object calling isLargerThan)
// and other must be instances of
// the same class returns 1, 0, -1
// if this is greater // than, equal
// to, or less than other
public int isLargerThan(Relatable other);
}
Using relatable as a type:
public Object findLargest(Object object1, Object object2) {
Relatable obj1 = (Relatable)object1;
Relatable obj2 = (Relatable)object2;
if ((obj1).isLargerThan(obj2) > 0)
return object1;
else
return object2;
}
----- EDIT 2 -----
In the chapter on anonymous classes, it does this:
public class HelloWorldAnonymousClasses {
interface HelloWorld {
public void greet();
public void greetSomeone(String someone);
}
.
.
.
HelloWorld englishGreeting = new EnglishGreeting();
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
So how does this work?
the line Relatable obj1 = (Relatable)object1; seems to create an object of type Relatable
No. This line creates a reference (obj1) of type Relatable and assigns it to object1. In order for this to work, object1 has to be cast to the (interface) type Relatable.
No new objects are being created here.
Does this mean anything that implements Relatable can call findLargest()?
Yes.
If it's so, why does it say provided that both objects are of the same class?
It has to do with the implementation of isLargerThan(). Since any class implementing the Relatable interface can't know anything about other classes implementing it, they can't do meaningful comparisons with other classes. Therefore, in order for this to work, both objects need to be of the same class.
Response to EDIT 2
So how does this work?
Instead of first defining a class and then creating an instance of it, as in the case with the EnglishGreeting, the frenchGreeting is created on the fly. What happens under the cover is that a new class implementing HelloWorld is created, just like in the english case, only this time it is anonymous (you never get to give it a name). It is just a convenience shortcut for those times when you need a one-time implementation of an interface.
Interface types belong to the category of reference types in java. You can never instantiate an interface, but it can be assigned references to any of the objects of classes which implement it:
A variable whose declared type is an interface type may have as its
value a reference to any instance of a class which implements the
specified interface.
Interfaces are like behaviors. If a class happens to implement an interface, lets say Serializable, this adds a behavior to the class, which is, the class can be serialized.
This helps you introduce abstraction in your code. For example lets assume that you need a method in one of your utility classes which will be responsible for the actual job of serialization. Without interfaces you will end up writing a lot of methods, one for each object type that you want to serialize. Now imagine if you asked each of those objects to take care of their serialization themselves (by implementing a serialize method declared in the interface they implemented). With such implementation you need to write only one utility method for serialization. This method can take an argument of Serializable type, and instances of any class implementing this interface can be passed to the method. Now within the method you only need to invoke the serialize method on the interface variable. At runtime this will result in actual object's serialize method getting invoked.
Hope I was able to keep it simple.
Interface in Java is a mutual structure for classes that implement the interface, so the classes benefit from the methods/other member of that interface in their own way, which is called polymophism,
interface A
{
// method header only declared here, so implementation can vary between classes
public int foo();
}
class B implements A
{
public override String foo()
{
return "Class B";
}
}
class C implements A
{
public override String foo()
{
return "Class C";
}
}
so you can call foo() both from class B and C but they will react differently since they implement that method in their own way
An interface is just a class that defines the behaviour of an object, but not the underlaying implementation of it.
By making Relatable obj1 = (Relatable)object1; you are just casting the object1 to a Relatable type, and therefore you can call any of the methods defined in the Relatable interface
To your first question about Relatable obj1 = (Relatable)object1;:
A simple Relatable obj1; will not create an instance of Relatable, but specifies that any object assigned to it must be of a type implementing the Relatable-interface.
Therefore any object that is to be cast, must be of a type implementing the Relatable-interface.
I am having some confusion about extended classes. I think the best way to explain what I want to do is with some skeleton code:
abstract class Player
{
public int solve()
{ // One method of solving problem
}
}
class otherPlayer extends Player
{
public char solve(int num)
{ //Different method of solving same problem
}
}
// I suspect this is a wrong way to create Player
Player first = new otherPlayer;
// Because this gives me an error...
first.solve(5)'
// And this uses the super class's method of solving problem
first.solve();
// I don't want to do this though...
otherPlayer first = new otherPlayer;
// Because I actually define the Players in a method
// that returns a type Player():
private Player genPlayer()
{ // Take input from keyboard
Player newPlayer;
if (specific set of answers)
newPlayer = new otherPlayer();
else newPlayer = new Player();
return newPlayer;
}
My understanding of extended classes is limited. If I say "TypeA var = new TypeB", and TypeB extends TypeA, it seems that var only has access to methods in the TypeA class. What does it do, then to say it is a new TypeB? Why is that even a legal way to instantiate a variable? And how would you recommend I restructure this program so I can make it work (I'd prefer to keep the method, so I don't have to make a mess every time I create a Player)?
I really just want to know how to create an extended class as if I were a person who knew what he was doing.
You need to do something like:
abstract class Player {
abstract void solve(int num);
}
class OtherPlayer extends Player {
void solve(int num) {
//...
}
}
That is, to call a method through variables of type Player, at least its signature must be declared on that class - and must be implemented in all subclasses. There is no way to call a method that may or may not exist in a subclass using a variable of the superclass type.
Imagine you could do this:
class Player {
// ...
}
class FooPlayer extends Player {
void solveInt(int num) {
// ...
}
}
class BarPlayer extend Player {
void solveString(String s) {
// ...
}
}
Player[] players = new[] {new FooPlayer(), new BarPlayer()};
// this is the sort of code you want to work
for (Player p : players) {
p.solveInt(123);
}
what's supposed to happen when the method is called on BarPlayer? As you can see, it doesn't make much sense to allow this.
While it's not very useful to do Player player = new FooPlayer() explicitly, it does let you not have to know which exact subtype of Player the value is. It's missing the point to look at the methods that are different between the subtypes - the point of polymorphism is that the same method (i.e. with the same signature) is implemented in a different way between the subclasses:
class Player {
abstract String greet();
}
class EnglishPlayer extends Player {
String greet() {
return "Hello";
}
}
class JapanesePlayer extends Player {
String greet() {
return "Konnichi wa";
}
}
The point of TypeA a = new TypeB() is programming to contract. It means you can change TypeB into any other type that extends TypeA and be guaranteed not to have to change any other line of your code.
first, you are getting an error in the instantiation syntax. It should be new otherPlayer(). Also classes should be capitalized in java.
I assume the code is within a method, otherwise it will not compile.
Finally, to answer your question why you extend a class, if otherPlayer had its own implementation solve() (no arguments) then which method would be called would depend on the instantiation you used, not on the variable type. In other words, first.solve() would call the method in otherPlayer, not in player.
extension is about superclasses and subclasses.
if typeA is a subclass of typeB, then you could say
typeA extends typeB, and typeA would inherit all of the methods of typeB
it only works one way, kind of like a child can inherit traits from their parents, but the parents don't inherit anything from the child
if you want a method in the subclass to behave differently than in the parent class, simply write a new method with the same name/parameters. subclass methods automatically override superclass methods. then, if you want to use the superclass version of a method, you can use the super keyword
Inheritance is something that happens when you extend a class, you need to figure out the common methods you want in your class and subclass and define any alternates in your subclass.
Check this out for more info: http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
you declared 'first' as a Player reference that is referencing an otherPlayer object. This is legal, but if you want otherPlayer behavior, you will have to typecat 'first':
((otherPlayer)first).solve(5)
First of all, you can't instantiate abstract classes, so you can't code newPlayer = new Player();.
Then, it's perfectly legal to write something like ClassA a = new ClassB(); as long as ClassB is a subclass of ClassA and ClassB is not an abstract class.
In the case you have a method in ClassB that overrides a method of ClassA, which one is called depends on the dynamic type of the object that is actually the type you used for instantiate that object, this is called Polymorphism. There is lot of material about this (Object Oriented Programming and Java) on the web, but I think a great place to start at, is the book Thinking in Java by Bruce Eckel, he offers the third edition for free at his site (http://www.mindview.net/Books/TIJ/).