So I wrote a simple java code here as shown below.
package com.example.aakash;
public abstract class Book {
String title;
String author;
Book(String t,String a){
title=t;
author=a;
}
abstract void display();
}
So Book is an abstract class which is to be extended by two different class called MyBook and ABook class as shown below.
package com.example.aakash;
public class MyBook extends Book {
private int price;
MyBook(String t, String a,int p) {
super(t, a);
price = p;
}
#Override
public void display(){
System.out.println("Title: "+title);
System.out.println("Author: "+author);
System.out.println("Price: "+price);
}
}
package com.example.aakash;
public class ABook extends Book {
private int price;
ABook(String t, String a,int p) {
super(t, a);
price = p;
}
#Override
public void display(){
System.out.println("Title: "+title);
System.out.println("Author: "+author);
System.out.println("Price: "+price);
}
}
package com.example.aakash;
import java.util.ArrayList;
public class Main {
public static void main(String[] args){
ArrayList<Book> myArray = new ArrayList<Book>();
String bookName = "Book";
for(int i=1;i<=10;i++){
if(i%2==0){
String tempBook = bookName + i;
String author = "Author2";
Book temp = new MyBook(tempBook,author,i*50);
myArray.add(temp);
}else{
String tempBook = bookName + i;
String author = "Author1";
Book temp = new ABook(tempBook,author,i*50);
myArray.add(temp);
}
}
for(int i=0;i<10;i++){
Book temp = myArray.get(i);
temp.display();
System.out.println("--------------------------------------------------");
}
myArray.get(5).display();
}
}
Okay so when I run this program, the display method print the right book,author and price every single time. Just the way they are stored. However at runtime, JVM doesn't know that weather a Book object on the array list is of type MyBook or ABook. So my question is how does calling the display method print the right book every single time. How does ArrayList of Book object get stored on heap? (i.e all objects get store in heap in Java) Does it store it as upcasted Book object. Or does it store it as the actual MyBook and ABook type of object so that when display method is called, JVM explicitly knows that weather the method on MyBook or ABook is to be called?
P.S. Yes example is kind of bad but suppose I don't even have similar display method on MyBook and ABook. Even then the JVM still executes the correct display method. So please explain what is going on in JVM when up-casting is done.
The concrete object is an ABook declared as Book.
Which display method select is resolved at runtime, not a compile time.
From JLS:
If the method that is to be invoked is an instance method, the actual
method to be invoked will be determined at run time, using dynamic
method lookup (§15.12.4).
Basically it means that the real instance type is taken at runtime. If the method is overwritten in that class this method is executed, if it is not overwritten the method of the super class is invoked.
You are mixing up objects and references. You never store an object in an ArrayList, you are just storing a reference to an object. A reference might have a broader type than the object it is pointing to, but that never changes the actual type of the object.
In fact, due to type erasure, an ArrayList<Book> doesn’t even contain references of the type Book, it has no knowledge about it. It only contains references of type Object, but that’s sufficient for the ArrayList to work as all it needs, is the method boolean equals(Object) that is declared in java.lang.Object. Since the type of the reference does not change the type of the actual object, invoking equals on an object via a reference typed as Object will still invoke the most specific method of the actual type, if the equals method has been overridden.
You may also store the same object multiple times in a List, whereas “store an object” is a colloquial term which you always have to translate to “store a reference to that object” for yourself. There’s still only one object if you do that and the list will just contain multiple references to it. Modifying that object through one of these references will become visible through all other references immediately.
The type of an object is fixed right when it is created and stored within the object in an implementation specific manner. That’s also the reason why a runtime type cast narrowing the type to a more specific one can verify the correctness. The cast is not changing the type of the object, it’s only creating a new reference to the same object with a more specific type out from a reference with a broader type, after the correctness has been proven. This also happens implicitly when retrieving a reference from the ArrayList<Book>; the reference of type Object stored in the list is converted to the reference of type Book you will receive.
This concept is called Polymorphism.
ABook is a Book
MyBook is a Book
You can have an ArrayList and have inside objects of ABook and MyBook.
But everytime that you get an object of this ArrayList, you can only call book's method, unless you make a downcast to one of this subclass. But you have to be sure of the subclass before the cast, because you might get an CastException.
Finally, if you call an override method, at runtime he will always call the object method. At runtime he we always call the objects method.
Related
I'm a Java newbie so excuse me if this sounds like a dumb question.
Can someone explain to me what is going on with this method?
public static void policyInNoFaultState( AutoPolicy policy ) <===line in question
Is "policy" of object type from AutoPolicy? therefore policy inherits everything AoutoPolicy has?
Is this the reason I can use the "Dot" command exp. policy.getAccountNumber(), policy.getMakeAndModel()
I pasted part of the program I think applies to this question.
I appreciate any help you can give.
//Creating AutoPolicy ojbects
AutoPolicy policy1 = new AutoPolicy(11111111,"Toyota Camary", "NJ");
AutoPolicy policy2 = new AutoPolicy(22222222, "Ford Fusion", "ME");
//Creating policyInNoFaultState method to display results
public static void policyInNoFaultState( AutoPolicy policy ){
System.out.println("The auto policy:");
System.out.printf("Account #: %d; Car: %s;%nState %s %s a no-fault state%n%n",
policy.getAccountNumber(), policy.getMakeAndModel(),policy.getState(),(policy.isNoFaultState() ? "is": "is not"));
}//End of policyInNoFaultState
A class in Java defines a type and basically acts as template for all instances (objects) created from that class. This template defines data (fields) and behavior (methods) available for all of instances of this type. "Static" members of the type are shared between all instances and non-static members (also called "instance members") are distinct between instances.
Consider the following simple example (beware, this makes no promises about best practices how to define and use classes and instances):
class MyType {
public static int Shared = 42;
public int NonShared;
public void Print() {
System.out.println("This is me: " + (Shared + NonShared));
}
}
You can create several instances of this class which will all share the same shared field but each have their own value for the instance field:
MyType a = new MyType();
MyType b = new MyType();
a.NonShared = 21;
b.NonShared = 84;
a.Print(); // prints "This is me: 63"
b.Print(); // prints "This is me: 126"
a.Shared = 0;
a.Print(); // now prints "This is me: 21"
b.Print(); // now prints "This is me: 84"
a and b are instances of class/type MyType. In a way, 42, 21, and 84 are instances of the type int.
When you define a method to act on values, you have to specify which kind of values the method should be able to handle. This is done by specifying the type for each of its parameters. Let's have a look at another arbitrary example method:
static String format(MyType object, String info) {
return info + ".NonShared = " + object.NonShared;
}
Above method returns a single instance of type String and works one two parameters of type MyType and String respectively. This is required so that the compiler knows which members (fields or methods) are available for each parameter. Otherwise calling object.NonShared would not be possible.
MyType c = new MyType();
c.NonShared = 7;
String formatted = format(c, "formatting");
System.out.println(formatted); // prints "formatting.NonShared = 7"
Note that in this simple case, the type of variable c matches the type of the parameter object exactly. This is not required, you can pass any subtype (or "child class") to the parameter. The parameter's type merely defines the minimum number of members that must be supported by any argument that is passed to the function. You can think of it as a contract between the input parameter and the processing function.
static Integer firstValue(Collection<Integer> list) {
list.get(0);
}
List<Integers> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
firstValue(numbers);
The above code will not work. It will not even compile! Even though numbers is an instance of the interface type List with concrete implementation type ArrayList and has an instance-method get, this is not available (nor known) inside the method, which can only work with Collection types. The Collection type does not define an get method, despite implementations of it (sub types, child classes) might provide it.
By using the smallest possible type for any given task, you gain a lot of flexibility. All collections implement the add method. By defining a method which can work with Collection, you can pass in any implementation which adheres to this type and modify it:
static void addValue(Collection<Integer> bag) {
bag.add(4);
}
List<Integer> list = new ArrayList<>();
Set<Integer> set = new HashSet<>();
Deque<Integer> stack = new ArrayDeque<>();
Queue<Integer> queue = new PriorityQueue<>();
addValue(list);
addValue(set);
addValue(stack);
addValue(queue);
I hope this clears things up! If there is any detail that is still unclear, please point it out in the comments and I will try to extend my answer with further points.
Here "policy" is holding the reference number of an object of "AutoPolicy" type. That is pointing the object passed in parameter.
For better understanding you can go through topic "pass by value and pass by reference in java"
So, for example,
Person p = New Person()
Person z = New Adult()
Let's say the Adult Class had it's own method called drive(), why couldn't I do:
z.drive()
I know this won't work, but what is the logic behind this not working? When you say: Person z = New Adult(), aren't you specifying it is an Adult instance?
The "logic" behind it not working is because that's how Java was designed to work. Java is a statically typed language which means that every variable has a declared type at compile time. Java is also strongly typed which means that the values that can be held and the operations that are supported are limited to the declared type. This enforcement is called type safety.
The advantage of a static type checking is that the compiler will prevent you from assigning incompatible types or calling methods that are not available. Errors can be caught at compile time vs runtime.
Try a search for "strong vs. weak typing" which will give many more details, arguments, and the pros/cons of the approaches.
When you say: Person z = New Adult(), aren't you specifying it is an Adult instance?
You're creating an Adult object, but the declaration Person z says that the variable z is allowed to refer to any kind of person, not just an adult. You could write z = new Child() on the very next line.
When you call a method on z, Java checks that it's valid for all objects that the variable could refer to. It doesn't analyze the preceding code to try to figure out what specific type it actually does refer to, because in most cases that isn't possible. (The variable could've been passed in as a method argument, for example, or it could've been set to either an Adult or Child based on an if statement.) There may be specific cases where it's guaranteed that the variable will refer to a specific class, but the Java language doesn't treat those cases specially. If the variable was declared with type Person, you can only call Person methods on it.
If you write Adult z = new Adult(), then you can call z.drive(), because the variable is guaranteed to refer only to adults, never children.
You asked this, I quote:
When you say: Person z = New Adult(), aren't you specifying it is an
Adult instance?
No, just the opposite, more precisely:
//Main.java, first version.
class Person {
public void drive() {
System.out.println("Person.drive");
}
}
class Adult extends Person {
#Override
public void drive() {
System.out.println("Adult.drive");
}
}
public class Main {
public static void main(String[] args) {
Person p = new Person();
p.drive(); // Person.drive
Person a = new Adult();
a.drive(); // Adult.drive
}
}
Second Variation, this time Person has NO drive() method:
//Main.java, second version.
class Person {}
class Adult extends Person {
// NO overriding here ..
public void drive() {
System.out.println("Adult.drive");
}
}
public class Main {
public static void main(String[] args) {
Person p = new Adult(); // 1
// Now this cast is needed:
Adult a = (Adult) p; // 2
a.drive(); // Adult.drive(), as before // 3
}
}
Put these two separate programs in a Main.java, respectively, compile and run.
Let's consider the second version. Behold the lines marked with //1 and //2.
In //1 what's happening is the so-called slicing of class Adult. Adult is an extension of Person and therefore has the privilege to claim more memory than a Person object. But you assign a Person to an Adult object, so not all the memory of the bigger Adult object might be initialzed.
Therefore, Jave urges you to cast the Person to an real Adult object in //2, so that you show it that you know what you're doing. Only then are you permitted to call a.drive() in //3.
Hope, that helps to clarify things a bit.
Regards, Micha
As I have learned, Object class is a top level class and it is a parent of all classes. If we do not know a type of class at compile time, we can assign it to a object of Object class.
I am trying to clone a object to object of a Object class. Also trying to get the object from HashMap which is already instantiated. I am having problem in doing this. Can you figure out it and explain the right ways of doing it? I have commented in which lines I get compile time error. My main doubts are:
If a parent class' object can be used for cloning, then it must work with Object class too as it is top level class.
And how to access object from map and use it for method call and cloning.
Code:
import java.util.HashMap;
import java.util.Map;
class Sample {
public void call(){
}
}
class Question extends Sample implements Cloneable {
#Override
public void call(){
System.out.println("hello");
}
#Override
public Object clone()throws CloneNotSupportedException{
return super.clone();
}
public static void main(String args[]) throws CloneNotSupportedException{
Map<Character,Object> map=new HashMap();
Question s=new Question();
Sample q=new Question();
Sample cl=(Question)s.clone();
Object ob=(Question)s.clone();//no compile time error
map.put('o',s);
s.call();//hello
q.call();//hello
cl.call();/hello
ob.call();//Compile time error: cannot find symbol call
map.get('o').call();//Compile time error: cannot find symbol call
Object obj=(Question) (map.get('o')).clone();// Compile time error: clone has protected access in Object
}
}
The following line can be simplified
Object ob=(Question)s.clone();//no compile time error
// the cast is unnecessary:
Object ob= s.clone();
But like you said, the ob will still contain a Question object. The problem is that once you start using this ob reference, java just knows it contains a value of Object, or a subclass of it. So for java ob could be a Number or a String or an Airplane.
Object ob = "airplane";
Once it gets to the line ob.call() it refuses. Because it's not sure that the ob object has a call method. For example, if it was a String or a Number it would be impossible.
For this reason you have to perform a simple cast first:
((Question)ob).call();
// or
((Sample)ob).call();
Just let java know that it's an object with a call method.
The map#call issue has the same reasoning:
map.get('o').call();
//could be any of these
((Sample)map.get('o')).call();
((Question)map.get('o')).call();
But the last problem is more tricky. Actually a lot gets clear when you split up your statement in multiple lines:
Object obj=(Question) (map.get('o')).clone();
// would be the same like writing:
Object value = map.get('o');
Object value2 = value.clone();
Object obj = (Question) value2; // The (Question) cast is actually unnecessary.
The problem is in the value.clone() step. It is true that the Object class has a clone method, but it's marked as protected whereas the clone methods in your Question and Sample classes are public.
So in short Object#clone is not accessible ; Sample#clone and Question#clone are accessible.
// so you want this:
Object value = map.get('o');
Object value2 = ((Question)value).clone(); // add a cast here
Object obj = value2;
If you prefer to do it all in 1 line:
Object obj=((Question) (map.get('o'))).clone();
import javax.swing.*;
public class Toast {
static Object[] objects = { new JButton(),
new String("Example"), new Object() };
public static void main(String[] args) {
System.out.println( new Count(objects) );
for (Object o : objects)
System.out.println(o);
}
}
class Count {
int b, s, o;
public Count(Object[] objects) {
for (int i=0; i<objects.length; i++)
count(objects[i]);
}
public void count(JButton x) { b++; }
public void count(String x) { s++; }
public void count(Object x) { o++; }
public String toString() {
return b + " : " + s + " : " + o + "\n";
}
}
Above is a piece of code that appears in some form or the other in past exam papers for one of my upcoming tests. The idea of the question is to gauge if you fully understand polymorphism, dynamic and static casting. Basic ideas of OO.
I would like to put out what I think is correct and if people would be able to correct me or add points that would be greatly appreciated.
From what I can see in the above code:
Items are upcast to objects in the object array as every class in java technically inherits from the object class. This is why when count is run it will say there are 3 objects not 1 Jbutton, 1 string and 1 object.
When the enhanced for loop is run the toString of that object type e.g. Example from the string and memory address of the object (not sure what the JButton will print). As this is done at runtime this is known as dynamic casting.
I cannot see any other points that would be relevant to the above bit of code.
The idea behind static cast and dynamic cast is related to the moment a type decision needs to be made. If it needs to be made by the compiler then it's static cast. If the compiler postpones the decision to runtime then it's dynamic cast.
So, your first observation is incorrect. The upcast does not explain the count. Objects do not loose they type but the compiler needs to perform a static cast to decide which method to invoke and it chooses count(Object). There is no dynamic dispatch in java which means that the method called is always decided at compile time.
You second observation is also incorrect. What is in use is polymorphism. In Java, methods are always invoked for the type of the instance and not for the type in the code. Also, there is no dynamic casting here. The compiler can verify all the types. It's just that method invocation is always virtual but that's not a cast.
Actually in this example, I don't see a single case of dynamic casting. The compiler can verify all types. You normally only see dynamic casting when down casting and there is no case of that.
Here's what I would take away:
The compiler implicitly upcasts when performing assignments. This includes assigning to array elements during initialization.
The compiler and JVM do not implicitly downcast when selecting method overloads. The static type of the objects array is Object[], so the count(Object) method will always be called.
The JVM does implicitly "downcast" (in a sense) when invoking a virtual method. The println loop will always invoke the toString method of the actual object instance rather than always invoking Object.toString.
In your Count() method, always count(object) will be called as all objects are up casted to object.
To prevent that you can call method instance of and then downcast the object and call the count
public Count(Object[] objects) {
for (int i=0; i<objects.length; i++)
{
if(objects[i] instanceof JButton)
count((JButton) objects[i]);
else if(objects[i] instanceof String)
count((String) objects[i]);
else
count(objects[i]);
}
}
I have two classes A and B while B is a subtype of A:
public class A {
private String stringVar;
public A() {
stringVar = "";
}
public String getStringVar() {
return stringVar;
}
public void setStringVar(String str) {
this.stringVar = str;
}
#Override
public String toString() {
return getStringVar();
}
}
Class B:
public class B extends A {
private int intVar;
public B() {
intVar = 0;
}
public int getIntVar() {
return intVar;
}
public void setIntVar(int intVar) {
this.intVar = intVar;
}
#Override
public String toString() {
return super.toString() + " " + getIntVar();
}
}
As you can see in the following main method I assign the b to a. Now "a" can't invoke b's methods which is clear, because I'm using an instance of type A now. But it behaves like a B when toString is invoked. Curious, I would have expected toString of a. Why is this so?
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
b.setIntVar(200);
b.setStringVar("foo");
a = b;
System.out.println(a);
}
}
Because a points to the implementation of B.
And is declared as A.
So behavior of B. And methods visible of A.
To use B methods do like this
((B) a).getIntVar();
Think of it like this
Object o = new FancyObject();
When compiling this only Objects methods will be accepted even though it's a FancyObjcet with lots of methods.
To use the methods of FancyObject on o do like this.
Object o = new FancyObject();
(FancyObject o).fancyMethod();
Quote "because I'm using an instance of type A now" you are still using an instance of type B. You can see it like you have upcasted b but it's the same instance.
Picture cross linked from another site with credits in the picture, if this is against the rules then somebody is free to edit this part of my answer.
This is nature of inheritance / polymorphism and overriding methods.
Overrided methods will be determined in runtime based on objects real type and not based on reference type.
Therefore a.toString() is actually b.toString() because it is determined in runtime.
http://download.oracle.com/javase/tutorial/java/IandI/override.html
The concept you need to understand is the difference between References and Objects.
a is a reference (a local variable in this case) that points first to an Object of type A and then to an Object of type B.
The compiler knows that it must be of type A (or a subtype thereof), so it can safely call all methods A defines, but they will be called on the actual Object, not on the original Type of a.
This is polymorphism: The object that a holds has static type A, but it is still an Object of dynamic type B. Dynamic dispatch therefore chooses the overridden toString() defined in B.
That's exactly how Java's runtime polymorphism works. All that matters is the actual type at runtime. What you have done is take a reference to an A and point it at an instance of B. You have changed the type of the thing that a points to.
Try
a = (A)b;
No, B Overrides the toString method of A, so if an object is an instance of B, when you call its toString method, you get whatever method that instance has. In general, if you have an object and call its methods, the method called is the one that is in the instance, not in the variable type. The only exception is static methods.
In C++, this is not the case. The method called is the one of the variable type, if one exists, unless you explicitly select the above described behavior by making a method virtual.
That is called runtime polymorphism in OOP.