I am writing a project in Java.
I have a structure where I have instances of objects A, B and C, all of which extend class Parent.
I want to have a list of all objects of type Parent - i.e. I want to store any object of type A, B or C in this list.
I have created a list class with the function
private class Item
{
private Parent parent;
public void addItem(Parent set){ /* adds set to the list */};
}
My original idea was to do something like this:
A a = new A(); B b = new B();
addItem(a);
addItem(b);
But a and b are not Parents they are A and Bs.
Can someone suggest a way of being able to add instances of As, Bs, Cs... to a list of Parents?
I believe what you mean is how do you polymorph an a,b,c to their parent super type? Well, since they subtype the parent type the add method as you defined it should cast your subtype to parent implicitly.
Otherwise how you explicitly refer to the parent type of a subtype is by using a type cast expression... Which is expressed like this:
T_Parent varname = (T_Parent) Name_Subclass;
Related
If I have super class (Animal) and a sub class (Cat).
What does the third point mean? And when we have to cast?
Cat obj = new Cat(); means creating an object from Cat class
Animal obj = new Animal(); means creating an object from Animal class
Animal obj = new Cat();
First lets understand Class, reference and Object. Suppose we have a class named SomeClass
SomeClass ref = new SomeClass();
Above we have an Object of SomeClass created in Heap and a reference variable refers to it. We have named the reference variable as ref. Object is present in heap and we can just access it using a reference. So Object type is of the actual class (on which new keyword has been applied). Reference variable type can be of actual class or its Parent class.
Now let us see the relationship of Inheritance. A class inheriting from another class share a Child-Parent relationship.
Child inherits the behaviour of its Parent and can then override some of the behaviour and also can add some additional behaviour. Hence Object of Child can be used at any place where Parent object is expected, as Child has all the behaviour of its Parent so invoking any behaviour present in the Parent will be handled by the Child.
Parent class do not know about the additional behaviour of its child class ( child class is written later in time.) Hence object of Parent can not be used at the places where Object of Child is expected (If additional behaviour of Child is invoked on Parent object then it will not be honoured).
Now let us assume we have classes ParentClass and ChildClass such that ChildClass inherits ParentClass
ParentClass reference = new ParentClass(); // Valid
ParentClass reference = new ChildClass(); //Valid
ChildClass reference = new ChildClass(); //Valid
ChildClass reference = new ParentClass();// Not Valid.
Note that
ParentClass reference = new ChildClass(); // Here Object is of type ChildClass and Reference is of type ParentClass.
Now when to cast. Any place expecting the object of ParentClass, there is no need to cast, both the objects (of ParentClass or of ChildClass) are fine.
Any place expecting the Object of type ChildClass but if we have a case like below then casting is needed.
public void someMethod(ChildClass expected){
//some implementation
}
ParentClass ref = new ChildClass();
someMethod(ref);//Invalid : Compilation Issue
someMethod((ChildClass)ref);// Valid
ParentClass anotherRef = new ParentClass();
someMethod(anotherRef); // Invalid : Compilation Issue
someMethod((ChildClass)ref); //Invalid, compiles but Runtime it will fail.
Thumb rule : Child is Child, Child is Parent, Parent is Parent , Parent is not Child.
Another example for understanding.
public abstract class List{
public abstract void add(int element);
public abstract void remove(int element);
public int size();
}
public class Application{
private List listReference;
public void setList(List ref){
listReference = ref;
}
}
//Now you may create sub classes as below
public class ArrayList extends List{
// all the abstract methods of List have been implemented
}
public class LinkedList extends List{
//all the abstract methods of List have been implemented
}
Now in main method you can pass ArrayList or LinkedList or any other implementation.
public class Init{
public static void main(String[] args){
Application app = new Application ();
app.setList(new LinkedList());
//or you can set it like this
List listRef = bew ArrayList();
app.setList(listRef);
//or you can set it like this
LinkedList linkedListRef = new LinkedLiet();
app.setList(linkedListRef);
}
}
Notice that the method setList() accepts List type of reference and we can provide any implementation of the List abstraction. This leads to a flexible design.
Classes should be dependent on the abstraction. Programming to interface is a Design Principle which leads to easy maintenance of the application code.
The reason why this is confusing on the face of it is that it is not something that you would typically do in real code, except in the case of a Factory.
As hinted at in Zabuza's comment, you can do this because a Cat 'is-a' kind of Animal and so you can assign an object of type Cat to an object of type Animal. But you can't do the assignment the other way of course, because an Animal is not a kind of Cat.
Now, there are some lurking issues that come with actually being able to create an instance of the the supertype as well as the subtype that mean you typically wouldn't actually do this in real code because it complicates a lot of things down the road. What you would more likely do is make Animal an interface and have a GenericAnimal class that implements it, along with having Cat implement it.
Say you have an object that represents a zoo, and most zoos typically have a collection of animals. The most obvious way to represent this would be this:
java.util.Collection<com.myproject.Animal> zooAnimals;
So now imagine the zoo builds a new habitat, and it's for a lion. For the sake of the story assume we have a very lazy data model and instead of having a specific com.myproject.animals.cats.Lion subtype we just said "lions are cats, close enough". So to update the data structure that tracks all the animals and their names and addresses and favorite foods and whatever else, we might do this:
com.myproject.Animal newArrival = new com.myproject.animals.Cat("Larry the Lion", "Africa Exhibit", "Gazelles");
zooAnimals.add(newArrival);
Now imagine that the zoo continues to grow, and gets an Ostrich in the Africa habitat. And the same lazy data model applies so we just call it a Bird.
com.myproject.Animal newArrival = new com.myproject.animals.Bird("Oliver the Ostrich", "Africa Exhibit", "Whatever Ostriches Eat");
zooAnimals.add(newArrival);
Now actually writing that exact code would normally only happen in very specific cases inside a factory object or something, and realistically type hierarchies like this have a tendency to not work very well in practice at all, contrary to what a lot of us learned in Object Oriented Programming class, but for the sake of the question that is an example situation where you might do what you are asking about.
Lastly, you also asked when you have to cast. You would have to do this if you had code that needed to know about any special methods or fields that the Cat or Bird types have that Animal does not have. For instance the Cat type might have a property called tailLength because cats typically have tails and for whatever reason the zoo likes to keep track of that. Similarly the Bird type might have a property called wingSpan because birds have wings and we want to keep track of how big they are. The Animal type doesn't have any of these properties so if we get the object for the lion or the ostrich out of the zooAnimals collection (and maybe we looked at the name or something to figure out it was the lion) we would have to cast back to the Cat type in order to access the tailLength property. Same thing for the ostrich and it's wingspan.
for( Animal theAnimal : zooAnimals ){
if( theAnimal.getName().equals("Larry the Lion") ){
Cat theCat = (Cat)theAnimal;
System.out.println("Larry's tail is " + theCat.getTailLength() + " inches long";
}
else if( theAnimal.getName().equals("Oliver the Ostrich") ){
Bird theBird = (Bird)theAnimal;
System.out.println("Oliver's wingspan is " + theBird.getWingSpan() + " inches";
}
}
Again you probably wouldn't actually do something like that in real code, but perhaps it helps to illustrate the example.
I'm trying to implement a linked collection using generics, something like the following.
public class A<E> {
private class B {
private B[] b;
private E item;
private B() {
this.b = new B[2];
}
} // end inner class B
} // end class A
A is the collection and B an element or node in the collection with an array referencing successors/predecessors and an item.
The array creation is not allowed. The error I get is generic array creation. Am I right to think that what it's actually creating is an array of A<E>.B?
If not, what's causing the error?
If so, how can I get around this?
I have obviously omitted a substantial amount of code, if what I've provided is not enough please let me know. Any advice would be appreciated. Thank you.
EDIT 1: I should have mentioned that the parameterized type must be the same in A as in B. So passing <E> to the inner class is not possible, as it creates E#2 and leaves A with E#1.
You call B inherits the generic from the outer class, as it is not static. And you can't just make it static, because it will then need E also.
So your B.b array will indeed need a type that is generic, i.e. A<E>.B or if you'd change your code to a static inner class, A.B<E> (if you would use private static class B<E>).
In Java, due to the way generics are implemented (by erasure), the type of the array is not well-defined. On one hand, it should be an array of B, on the other hand, it should be an array of Object.
The most workable solution seems to be to use Object[] and cast explicitly.
If you want increased type safety, you can of course use an ArrayList<B>, which internally uses Object[], too!
In you particular code, B b1, b2; might also be an option which is actually faster (no bounds checking) and needs less memory (no array object; no size information).
B is a non-static inner class. That means it has a reference to an instance of the enclosing class. So it is implicitly parameterized by the type parameter of outer class. So when you write B, it means A<E>.B. To create an array, you should use the raw class. However, B is not the raw class; to refer to the raw class you need to explicitly qualify it: A.B
So this is that you want:
this.b = new A.B[2];
You need to pass E to the inner class as well
private class B<E> {
private B[] b;
private E item;
private B() {
this.b = new B[2];
}
} // end inner class B
we can achieve the output in two ways one is typecasting and one is without typecasting
A a=new B() // without typecaste
A a = (A)a// with Typecaste
in both ways we get same output.so, what is the use of typecasting
Let's assume that you have a list of Animals. and you have Tigers and Lions in it.
ArrayList<Animal> animals = new ArrayList<>();
//add some Tigers and some Lions
//sort so Tigers are at the beggining of the list
Tiger t = (Tiger)animals.get(0);
Without casting you will get type missmatch at compile time. With a cast you only risk ClassCastException which can be easy caught with a try-catch
It's just an example of a proper use of class casting in Java.
Casting is for "the opposite direction", i.e. for converting to a expression of a subtype of the original expression.
Example
Given
Object o = "Hello World";
String s = o;
does not compile, but
String s = (String) o;
compiles. This may yield a ClassCastException however, e.g. if a Integer was stored in o.
Casting has different uses. Unfortunately, your example doesn't exercise any useful example of casting since you create an instance of A (a) then cast it to an A.
What you need to understand is there are apparent types and actual types. An apparent type would be List<T> list;. Here we see that it's a list. But the actual type might be an ArrayList<T> (List<T> list = new ArrayList<>();). In this scenario we can, with care, cast the apparent type to the actual type. This would allow us to then use the functionality of the actual type. For example, let's look at some code; given:
List<Integer> list = new ArrayList<>();
ArrayList<Integer> aList;
LinkedList<Integer> lList = new LinkedList<>();
We can do this without issue (although dangerous in general)...
// Dangerous but OK with a cast
// list might not be an ArrayList
aList = (ArrayList<Integer>) list;
// Use ArrayList methods
aList.trimToSize();
list = lList;
LinkedList<Integer> danger = (LinkedList<Integer>) list;
...but it's also possible to do:
aList = (ArrayList<Integer) list;
// Use ArrayList methods
aList.trimToSize();
// list = lList;
LinkedList<Integer> danger = (LinkedList<Integer>) list;
The last snippet results in a ClassCastException because list isn't a LinkedList.
Casting goes beyond that though. Consider when you have two integers you want to divide. Without a cast you could end up with an integer result where a floating point is more appropriate. Consider:
int i = 2;
int j = 3;
System.out.println("No cast: " + i/j + " ;With cast: " + (double)i/j);
Output:
No cast: 0 ;With cast: 0.6666666666666666
So, it depends on the use case.
A a = new B();
will only works if B inherit from A.
If B inherit from A, the type cast is not required as B is a A. Type cast will be necessary if you need to type cast to a subclass:
A a = new B();
B b = (B) a;
While this would be illegal :
A a = new A();
B b = (B) a;
as a is not a B.
Java implicitly upcast with assignment, so in the code you've provided the casting operator is redundant; a is already of type A:
A a = new B(); // without typecast operator (implicit upcast)
A a = (A)a; // with redundant typecast operator
One reason to have a casting operator is that you may also wish to downcast (which is not done implicitly in Java). For instance, when a is a type A reference to an object of class B (e.g. when B is a subclass of A) one may need to downcast to access certain methods:
A a = new B(); // implicit upcast
C c = ((B)a).methodOfBOnly(); // explicit downcast
You may also want to check this question on why Java doesn't do implicit downcasting.
There can be times when upcasting needs to be done explicitly as well. For instance, if a class contains overloaded methods
C method(A x){/*does one thing*/}
C method(B x){/*does another*/}
and assuming b is of type B, the calls to method((A)b) and method(b) would behave differently.
A a=new B()
is applicable only when class B extends class A. In this way the extra methods that are available in class B other than class A will be available with reference a.
When you do this
A a = (A)a
Then actually you are down casting the object of class B into an object of class A. And it is true that child can be type cast to parent. After this statement the reference a will not be able to call any method of class B which were not in class A because now the reference a points to an object of class A.
It is useful in many scenarios.
For example, you want to have a collection of Objects that point to same base class. Instead of maintaining separate collections for each sub class, you maintain a single collection of base class. And then when you want to use any child object you type cast the base class object to child class object to do that.
ArrayList<Base> children = new ArrayList<Base>();
children.add(new Child1());
children.add(new Child2());
Console.WriteLine(((Child1)children.get(0)).getChildName());
Console.WriteLine(((Child2)children.get(1)).getChildName());
Now base class does not have any method named getChild1Name or getChild2Name. And you need to typecast object of base class to respective child class to do that.
public class B extends C <A> {
}
What does this mean? That C needs to extend A? What extra restriction am I putting instead of just saying B extends C?
In this case, C is a class that can take a generic parameter, and you are giving it a specific type A as the parameter. Then, B extends that specific parameterization of C.
For example, suppose:
class C<T> {
T example();
}
class B extends C<Integer> {
}
Then B.example() would return an Integer.
You are defining a class B that inherits from class C, parameterized with type A. A must be a class or interface.
E.g.
class MyStringList extends ArrayList<String>
means that MyString IS AN ArrayList that will only contain String elements. This class could then define e.g. a concatenate() method that returns the concatenation of all Strings in the list.
Because of this inheritance, you will be able to assign an instance to a List<String> variable:
List<String> strings = new MyStringList();
But you will not be able to assign it to List type variables with other parameters:
List<Object> objects = new MyStringList(); // does not compile
Class B is a C.
C and B are parameterized with an A. (Which means they can have methods and such that use A methods, or the methods of classes that descend from A.)
A classic use case for this would be that you have a DAO (Data Access Object). You make a generic DAO with some basic methods, like GenericDAO with a generic save method. To make it so other DAOs can extend GenericDAO, you parameterize that class with Entity, and you make sure all your Entitys are saveable.
Then you have GenericDAO<Entity, and a bunch of implementations of that, for example UserDAO extends GenericDAO<User> where User is an entity.
C<A> does not mean that C is extending A, it means it can have A as the type parameter.
This is very similar to Comparable<T> and Comparator<T> interfaces in java.
Consider following example
public class NameSort implements Comparator<Employee> {
public int compare(Employee one, Employee another){
return (int)(one.getName() - another.getName());
}
}
means that Comparator is using Employee objects for sorting them using its name.
You can also take another example
List<String> list = new ArrayList<String>();
This line means that List is using String objects as parameters
In simple words
That doesn't mean anything, unless there are some methods defined in Class C or its ascendants, to either accept or return Type A parameters.
By doing so you are ensuring the Type safety by imposing restrictions saying "They can accept or return objects of Type A".
public class B extends C <A> {
}
If A is undefined there is no restriction on B( can be any the of Object Class).
If the Type of A is defined,then B must be of type A or a Subclass of A.
I'm trying to implement a linked collection using generics, something like the following.
public class A<E> {
private class B {
private B[] b;
private E item;
private B() {
this.b = new B[2];
}
} // end inner class B
} // end class A
A is the collection and B an element or node in the collection with an array referencing successors/predecessors and an item.
The array creation is not allowed. The error I get is generic array creation. Am I right to think that what it's actually creating is an array of A<E>.B?
If not, what's causing the error?
If so, how can I get around this?
I have obviously omitted a substantial amount of code, if what I've provided is not enough please let me know. Any advice would be appreciated. Thank you.
EDIT 1: I should have mentioned that the parameterized type must be the same in A as in B. So passing <E> to the inner class is not possible, as it creates E#2 and leaves A with E#1.
You call B inherits the generic from the outer class, as it is not static. And you can't just make it static, because it will then need E also.
So your B.b array will indeed need a type that is generic, i.e. A<E>.B or if you'd change your code to a static inner class, A.B<E> (if you would use private static class B<E>).
In Java, due to the way generics are implemented (by erasure), the type of the array is not well-defined. On one hand, it should be an array of B, on the other hand, it should be an array of Object.
The most workable solution seems to be to use Object[] and cast explicitly.
If you want increased type safety, you can of course use an ArrayList<B>, which internally uses Object[], too!
In you particular code, B b1, b2; might also be an option which is actually faster (no bounds checking) and needs less memory (no array object; no size information).
B is a non-static inner class. That means it has a reference to an instance of the enclosing class. So it is implicitly parameterized by the type parameter of outer class. So when you write B, it means A<E>.B. To create an array, you should use the raw class. However, B is not the raw class; to refer to the raw class you need to explicitly qualify it: A.B
So this is that you want:
this.b = new A.B[2];
You need to pass E to the inner class as well
private class B<E> {
private B[] b;
private E item;
private B() {
this.b = new B[2];
}
} // end inner class B