Java - Object Type Casting and Inheritance - java

I have superclass A, which is extended by subclasses B1 and B2. Then, I have five subclasses (C1, C2, C3, C4, C5) that extend either B1 or B2.
I am trying to make an array containing one of each of these five subclasses.
These objects are all instantiated as instances of type A.
ClassA[] objects = new ClassA[5];
I attempt to reassign each of the objects to one of the subclasses:
objects[0] = new ClassC1;
objects[1] = new ClassC2; // etc...
At this point, any methods that existed in Class A work fine, but methods defined in B1/B2 or the other subclasses are not found:
objects[0].MethodFromC1(); // returns a "symbol not found" error
The instanceof keyword indicates that objects[0] is an instance of classes A, B1/B2, and C1.
What can I do to maintain my array of class objects (to loop through and perform operations), while getting my code to recognize the methods of the subclasses?

If you are doing a lot of instanceof and conditional logic based on class, you are completely missing out on the benefits of an object-oriented language. Just stick to C.
You should have some method do(), for example, that is abstract in ClassA but implemented in ClassB and ClassC. Then you iterate over the array and call do() on every object in there. The polymorphic call will result in the right do()'s being called.
Hope that helps.

Elements in the objects array don't know anything about ClassC1 since they're only guaranteed to be members of ClassA.
For instance, if you have a class hierarchy of Animal and subclass Cat and its subclass Lion, you're trying to call the Animal.maimSafarigoer() method. Animals in general don't know anything about safarigoers, only Lions know how to do that.
Use the instanceof operator to check if you're operating on a particular subtype.
(Sorry for the gruesome analogy. :-) )

You're trying to implement variants in Java. This subject has long been one of the things I hate the most about this language.
http://jazzjuice.blogspot.com/2010/10/6-things-i-hate-about-java-or-scala-is.html
I have listed about 8 suboptimal ways to do variants there.

You can use the instanceof keyword in the if statement and cast the object to the desired type. For example,
for (ClassA obj : objects) {
// do something common...
if (obj instanceof ClassC1) {
ClassC1 c1Obj = (ClassC1) obj;
c1Obj.MethodFromC1();
}
}

Related

What is the appropriate instance declaration of a subclasses?

I have a class called A (the parent) and class B (subclass of A)
My question is what is the difference between the next lines :
B b1 = new B();
A b2 = new B();
I know that variables and methods in class B cannot be accessed in case of object b2
But how it works in memory ? what is the point of this? when to use each of them ?
One reason to use the superclass as the variable type:
Suppose you have an Animal class, and several subclasses like Elephant, Tiger, Giraffe, Hippo, etc.
Now you have another class called Zoo, which contains an Array called animals. Then you could have:
animals[0] = new Tiger();
anumals[1] = new Elephant();
But it is better to have animals declared as an ArrayList that can grow or shrink:
animals.add( new Tiger() );
animals.add( new Elephant() );
animals.add( new Hippo() );
If a subclass has a method that is not an overload of a parent method, you can still access the subclass methods via the superclass variable by casting it:
Animal a = animals.get(index);
if ( a instanceof Tiger ) {
((Tiger)a).tigerMethod( ... );
}
Not that this type of thing might not be the best design, but it illustrates the point.
Object can have multiple Interfaces, let's say class B inherits from class A:
Class A can have 5 public methods,
Class B have additionaly 5 own public methods,
so in class B you see all 10 methods, whereas using class A you see only 5.
This is important, because in this way you can control which part (of the interface) of the class you give to other's (other programmers to use).
For egzample:
If you return from your public method a List<>, like:
public List<SomeClass> giveMeSomeList() {
// both return statements are perfectly valid as return type is List<>
return new LinkedList<SomeClass>();
// return new ArrayList<SomeClass>();
}
then you are allowed to use any implementation of the List<> you have eg. You can chnage the implementation, that you construct and return an ArrayList<> or LinkedList<> from your method, but since the declared return type is List<> it makes no harm, no one will rely upon that you return concrete implementation (at least your'e not responsible for that), just that it will be a kind of List<>. But if you return from your public method very concrete implementation of a class, then your give others invitation to use and rely upon this concrete implementation, which in turn block the methos from the ability to chanage the underlying implementation without doing harm to other code.
So in this way (using apropriate types) you can make some restrictions on other programmers as to which methods they are allowed to use (the interface), and give you some freedom to change the implementation in the future - like in the exmple with lists.
When you use an interface in an method arguments type, you make the method more general, as it can be used with any subtype of the interface (or type).
Sometimes you just need very concrete implementation as an argument to your method, because without that you cannot do the needed operation, so you will rely on very concrete type to be supplied to your method, and declare that type in the arguments of the method.

Upcasting in Java for non primitive types

Let us consider we have two classes A and B. B is a sub class for A because B extends A. If We create an instance of A Class and assign that in to a A type will contains all the properties of A. Similarly when I create an Instance of B and assign it to B type will get all the properties of B along with properties of A because it is inheriting from A. According to above lines instance of A contains properties a few as compared to properties contains to instance B. That means Instance of B is Bigger than Instance of A as casting should be explicit when narrowing implicit when widening. According to my theory Instance of B is bigger we are trying to store it in A type we need conversion.
A a1=new (A)B();
The above conversion is taking place implicitly. But my question is how it is implicit, Instance of B is bigger we are trying to convert that to small type which is A. How this is possible???
Answer me with examples thank you in advance.
You are thinking in terms of object size, but in Java, non primitive types are never contained, only referred to. Thus, your code is casting the result of new B(), which is of type "reference to B", to type " reference to A". Since all references are the same size, no data is lost in the cast.
So, I really don't understand your question. I just think you are confused about what happens to the class B members when a upcast to his super class is made. In that case, you ended up with a instance of A wich means that Object type is A and non of B stored data will remain.
In Java, with
B b = new B();
A a = b;
one defines references b and a. Under the hood, references are implemented with pointers, and thus, all references are the same size. Of course, an instance of a B might indeed require more memory than an instance of A (I take it, this is what you mean by "bigger").
By the way, in C++ this is not the case.
B b();
does define an object, not a reference, and therefore
A a = b;
in C++ is indeed not allowed.
Think about this:
class Animal{
public void eat(){}
}
class Monkey extends Animal{
public void climbTree(){}
}
I can now do this:
Animal someAnimal = new Monkey(); //This is ok. (Create a Monkey and identify is as an Animal)
someAnimal.eat(); //This is ok too. (All Animal objects can eat)
someAnimal.climbTree(); //Not ok. Java sees someAnimal as a general Animal, not a Monkey yet.
From the above example, someAnimal is a Monkey object which is stored within a variable of higher hierarchy (Animal).
The object itself is perceived as the a more general class (The Animal class) and I don't think an implicit casting is done here since all Monkeys are already Animals (but not the other way round).
Explicit casting can be done when you want to let the compiler knows that the object actually belongs to a more specific class. For example:
((Monkey)someAnimal).climbTree(); //This is ok. Inform Java someAnimal is actually a Monkey which knows how to climb.
Example :
Class Employee {
private String name;
private double Salary;
//getter & setter
//mutators to increase salary etc;
}
class Manager extends Employee {
private double bonus;
//inherits methods from superclass
// sub class specific methods
}
Employee e = new Manager(); //is fine as manager is also an Employee...
The prefixes super and sub come from the language of sets used in theoretical computer science and mathematics. The set of all employees contains the set of all managers, and thus is said to be a superset of the set of managers. Or, to put it another way, the set of all managers is a subset of the set of all employees.
~ From core java series
hope this helps...
The cast isn't actually implicit like you're saying. What is actually happening is this:
B b1 = new B();
A a1 = (A)b;
The (A) is an explicit cast, what's more important is to stop considering the size of things in the sense that the size of B is different from the size of A. This can be an implicit assignment because B IS-A A, so using A as an interface for B is completely safe, because we know that B has at least the same members as defined by A.
So the perfectly safe (and not erroneous) method of doing this is simple:
A a1 = new B();
Done!

Abstract class and its subclasses [duplicate]

Basically what the title says, but some elaboration. I have a SuperClass with a couple of SubClasses. I needed an ArrayList to hold both types of Subclasses so hence the ArrayList of type SuperClass. I tried to access Subclass1's getQuantity() method using ArrayList.get(0).getQuantity(); (assuming that index 0 is of type SubClass1). I get the error: getQuantity is undefined for the type SuperClass.
Do the SubClass objects not keep their properties when put into a SuperClass ArrayList? And if they do keep their properties, how do I access them?
The objects themselves are still a subclass, but when you get them out of the collection it only knows about the superclass so it can't tell you which is which, it has to pick the common denominator.
If you know exactly that a specific index holds an object of type Subclass you can just cast it:
Subclass myObject = (Subclass) list.get(0);
System.out.println(myObject.getQuantity());
And it should work.
And a safer way requires testing if the object is really what you think it is:
SuperClass myObject = list.get(0);
if ( myObject instanceof Subclass) {
Subclass mySubObject = (Subclass) myObject;
System.out.println(mySubObject.getQuantity());
}
The first example raises an exception if the object is not of type Subclass, the second one wouldn't since it tests before to make sure.
What you need to understand here is that SuperClass myObject = list.get(0) is not the object itself, but a reference to access the object in memory. Think about it as a remote that allows you to control your object, in this case, it's not a fully featured remote, since it doesn't show you all your object can do, so you can switch to a better one (as in Subclass myObject = (Subclass) list.get(0)) to be able to access all features.
I'd surely recommend the Head First Java book as it covers this stuff in great detail (and I stole this remote example from there).
All of the objects retain their own class identity, but the code that uses the ArrayList isn't directly aware of it. As far as it's concerned, the ArrayList only holds references to SuperClass-type objects, and it can only call SuperClass's methods on objects it retrieves from it.
The calling code can use instanceof or similar techniques to find out if a particular object in a collection is of a subtype, but this is usually bad practice, since it usually indicates mixing of the different levels of abstraction. The one case where this is generally considered reasonable is if the subclass has some optional high-performance characteristic that the caller can take advantage of (and that measurement has determined is worth complicating the code for); one example might be that while List's get() method is has no performance guarantees, some implementations, like ArrayList, also implement RandomAccess, which indicates that there's no performance penalty to using get() in any order.
When you have some ArrayList and you fill it with things that extend SuperClass you have to check instanceof and cast to get to the methods specific to those subclasses.
Example:
ArrayList<Animal> animals = new ArrayList<Animal>;
animals.add(new Duck());
animals.add(new Cow());
animals.add(new Horse());
for (Animal animal : animals)
if (animal instanceof Horse) {
Horse horse = (Horse)animal;
horse.gallop();
}

In what ways are subtypes different from subclasses in usage?

A subtype is established when a class is linked by means of extending or implementing. Subtypes are also used for generics.
How can I differentiate subtyping from subclasses?
In Java, subclassing is a kind of subtyping.
There are a number of ways Java allows subtyping:
When class A extends B, A is a subtype of B because B b = new A(...); is ok.
When interface A extends B, A is a subtype of B because B b = new A() { ... } is ok.
When class A extends B, A[] is a subtype of B[] because B[] b = new A[0] is ok.
When class A implements B, A is a subtype of B because B b = new A(...) is ok.
It sounds like you want a way to distinguish one from the others. The below should do that.
static boolean isSubclass(Class<?> a, Class<?> b) {
return !b.isArray() && !b.isInterface() && b.isAssignableFrom(a);
}
It won't handle subtyping of generic classes due to type erasure though. Class instances don't carry type parameters at runtime so there is no way to distinguish the runtime type of a new ArrayList<String>() from a new ArrayList<Integer>().
For once, Wikipedia gives a very straight answer to the question:
http://en.wikipedia.org/wiki/Subtype_polymorphism
Subtyping should not be confused with the notion of (class or object)
inheritance from object-oriented languages; subtyping is a relation
between types (interfaces in object-oriented parlance) whereas
inheritance is a relation between implementations stemming from a
language feature that allows new objects to be created from existing
ones. In a number of object-oriented languages, subtyping is called
interface inheritance.
In short, subtyping occurs when you derive an interface (method signatures/access points/ways of reacting to the outside world) from another whereas subclassing occurs when you derive an implementation (methods, attributes/internal state and inside logic) of a class from another class through inheritance.
This terminology is not often used in this way and type usually refers to the data type.
In general, subclassing means to inherit the attributes of a parent. Subtyping merely means that operations on the supertype can be performed on the subtype. Note that subclassing is a special case of subtyping.
in Java, interfaces represent the structure for describing what behaviors a type can exhibit, which makes it the natural representation for subtyping. Subclassing is manifested in the class hierarchy.
Subclass is not the same as subtype. You might create subclasses that are not subtypes. To understand what a subtype is, lets start giving an explanation of what a type is.
When we say that the number 5 is of type integer, we are stating that 5 belongs to a set of possible values (as an example, see the possible values for the Java primitive types). We are also stating that there is a valid set of methods I can perform on the value like addition and subtraction. And finally we are stating that there are a set of properties that are always satisfied, for example, if I add the values 3 and 5, I will get 8 as a result.
To give another example, think about the abstract data types, Set of integers and List of integers, the values they can hold are restricted to integers. They both support a set of methods, like add(newValue) and size(). And they both have different properties (class invariant), Sets does not allow duplicates while List does allow duplicates (of course there are other properties that they both satisfy).
Subtype is also a type, which has a relation to another type, called parent type (or supertype). The subtype must satisfy the features (values, methods and properties) of the parent type. The relation means that in any context where the supertype is expected, it can be substitutable by a subtype, without affecting the behaviour of the execution. Let’s go to see some code to exemplify what I’m saying. Suppose I write a List of integers (in some sort of pseudo language):
class List {
data = new Array();
Integer size() {
return data.length;
}
add(Integer anInteger) {
data[data.length] = anInteger;
}
}
Then, I write the Set of integers as a subclass of the List of integers:
class Set, inheriting from: List {
add(Integer anInteger) {
if (data.notContains(anInteger)) {
super.add(anInteger);
}
}
}
Our Set of integers class is a subclass of List of Integers, but is not a subtype, due to it is not satisfying all the features of the List class. The values, and the signature of the methods are satisfied but the properties are not. The behaviour of the add(Integer) method has been clearly changed, not preserving the properties of the parent type. Think from the point of view of the client of your classes. They might receive a Set of integers where a List of integers is expected. The client might want to add a value and get that value added to the List even if that value already exist in the List. But her wont get that behaviour if the value exists. A big suprise for her!
This is a classic example of an improper use of inheritance. Use composition in this case.
(a fragment from: use inheritance properly).
In java, subtyping applies to interfaces, but subclasses does not apply to interfaces.
I don't think Java distinguishes between them? You have only classes.

Java rules for casting

When can a certain object be cast into another object? Does the casted object have to be a subtype of the other object? I'm trying to figure out the rules...
Edit: I realized that I didn't explain my issue at all: basically I am casting an object to an interface type. However, at run-time, I get a java.lang.ClassCastException. What needs to happen with my object so that I can cast it to this interface? Does it have to implement it?
Thanks
In Java there are two types of reference variable casting:
Downcasting: If you have a reference
variable that refers to a subtype
object, you can assign it to a
reference variable of the subtype.
You must make an explicit cast to do
this, and the result is that you can
access the subtype's members with
this new reference variable.
Upcasting: You can assign a reference
variable to a supertype reference
variable explicitly or implicitly.
This is an inherently safe operation
because the assignment restricts the
access capabilities of the new
variable.
Yes, you need to implement the interface directly or indirectly to enable assigning your class object reference to the interface type.
Suppose we want to cast d object to A,
A a = (C)d;
So internally 3 rules have been checked by Compiler and JVM.
The compiler is checking first 2 rules at Compile time and JVM will check last one rule at Runtime.
Rule 1 (Compile time checking):
Type of 'd' and C must have some relation (child to parent or parent
to child or same time).If there is no relationship then we will get a
compile error(inconvertible types).
Rule 2 (Compile time checking):
'C' must be either same type or derived type(subclass) of 'A'
otherwise we will get a compile error(incompatible types).
Rule 3 (Runtime Exception):
Runtime object type of 'd' must be same or derived a type of 'C'
otherwise we will get a runtime exception (ClassCastException
Exception).
Find following examples to get more idea,
String s = new String("hello"); StringBuffer sb = (StringBuffer)s; // Compile error : Invertible types because there is no relationship between.
Object o = new String("hello"); StringBuffer sb = (String)o; // Compile error : Incompatible types because String is not child class of StringBuffer.
Object o = new String("hello"); StringBuffer sb = (StringBuffer)o; // Runtime Exception : ClassCastException because 'o' is string type and trying to cast into StingBuffer and there is no relationship between String and StringBuffer.
There's an intuitive way of thinking about this - you're not changing an object with a cast, you're only doing something that would already be permitted if the type was known - inotherwords, you can only cast to a type that your object already is. So just look "up" the object chain to see what kinds apply to your object.
So you can cast to an interface only if it's defined somewhere higher up in the chain (e.g. if your classes parent implements it, etc. etc). It has to be explicit - from your question it sounds like you may be thinking that if you implement method "void foo()" then you should be able to cast to an interface that defines the method "void foo()" - this is sometimes described as "duck typing" (if it quacks like a duck, it's a duck) but is not how java works.
This will work:
class Foo implements Runnable {
public void run() {}
}
Foo foo = new Foo();
System.out.println((Runnable) foo);
But this will not:
class Bar {
public void run() {}
}
Bar bar = new Bar();
System.out.println((Runnable) bar);
Because although Bar has a run() method that could implement Runnable.run(), Bar is not declared to implement Runnable so it cannot be cast to Runnable.
Java requires that you declare implemented interfaces by name. It does not have duck typing, unlike some other languages such as Python and Go
You can cast if the runtime type of an object is a subtype of what you're trying to cast it into.
EDIT:
Yes, the object that you're trying to cast will need to implement the interface in order for you to cast it successfully.
If:
interface MyInterface{}
class MyClass implements MyInterface{}
Then
MyClass m = new MyClass();
MyInterface i = (MyInterface)m;
is possible.

Categories