OOP:upcast vs direct instantiation - java

I'm preparing to SCJP and looks like I don't understand class cast principles.
class Dog extends Animal
First way of creating Dog() instance- make instance of Animal and cast it to Dog(upcast):
Animal a = new Dog();
Dog d1 = (Dog)a;
VS
Second way of creating Dog() instance - make it directly:
Dog d2 = new Dog();
what is the difference between d1 and d2 objects this case?

After the cast of a to Dog, there's no difference between d1 and d2. The cast is potentially problematic. If a isn't actually a Dog, you'll get a ClassCastException at runtime. Therefore, you would be better off verifying the runtime type with instanceof:
Animal a = new Dog();
Dog d1 = null;
if(a instanceof Dog)
{
d1 = (Dog)a;
}
The real issue is that if you need a Dog, declare the variable as a Dog, not an Animal. If you're operating on any type of Animal, use the base class.
The type of a variable only specifies what interface you want to use -- whether it's the interface provided by the base class, an implementation of some class, or an actual interface. The type of a variable does not dictate its runtime type.

Animal a = new Dog();// a dog is created but it will be referred by reference of animal as dog is an animal
Dog d1 = (Dog)a;//now we know that this animal is Dog so we are casting it to dog.
Dog d2 = new Dog();// we are creating instance of dog which is referred by reference of Dog
what is the difference between d1 and d2 objects this case?
d1 and d2 are just reference to dog, both will eventually refer to an instance of Dog .
there is no difference
Also See
Polymorphism

The first way is polymorphic because Animal can be a dog, cat, elephant, etc... whereas the latter way is not. Otherwise, there is no much difference between the 2.

There is no difference in instantiation between these snippets: in both cases you instantiate object of type Dog by using new Dog(). Actually, it's about difference between type of object (runtime type) and type of variable (static type).
But in the first case you assign a reference to that object to variable of type Animal, and then assign value of that variable to another variable of type Dog. This requires cast since variable of type Animal may contain references to objects of types other than Dog, but in your case it references object of type Dog, so that cast is successful.
In the second case you assign value of type Dog to variable of type Dog directly.

Related

method chaining, returning an object from a list and getting values from it

what I have is a list of Dog objects, in the objects there contains a value that is a Boolean to show whether the dog as completed a training or not. What im trying to do is iterate over the list and only return Dog() objects that have completed training, for instance if their are 12 dogs, and only 3 have completed training, the loop should only print those objects.
else if (input == 1) {
for (int i = 0; i < 12; ++i) {
//Create a temporary value to hold the object.
Object tempHold = dogKennel.getAnimal(i);
//If animal has not graduated, skip, else print.
if (!(tempHold.getGraduation())) {
continue;
}
else {
System.out.println(dogKennel);
}
}
getAnimal(i) returns the object at int i
the method .getGraduation is defined and does return a Boolean however the compiler doesnt want to recognize temp value as is, and doesnt go beyond that value. the compiler keeps suggesting to cast tempHold, but even if I do, it doesnt work.
i feel like it would work if i could get it to compile, as the object that is returned would have a getGraduation() method (it is defined for the super class of the animal.)
however the compiler doesn't want to recognize temp value as is, ...the compiler keeps suggesting to cast tempHold, but even if I do, it doesn't work.
The compiler is telling you two things:
An Object is NOT a Dog (the opposite is true. A Dog is an Object).
class Object does not have method isGraduated() defined for them.
To fix this, you can cast Object to Dog:
Dog tempHold = (Dog)dogKennel.getAnimal(i);
Now that we have a Dog, we can safely invoke isGraduated() on it. But the problem is we canNOT be sure that we have a Dog. We may as well have a Cat if we get the Animal from another kennel. In that case, you will get a ClassCastException which tells you that Cats cannot be cast as Dogs.
To avoid getting run time exceptions, you can add a check:
Object tempHold = dogKennel.getAnimal(i);
if(tempHold instanceof Dog) {
Dog dog = (Dog)tempHold;
System.out.println(dog.isGraduated());
}
The instanceof check fixes the problem.
There are ways to avoid this run time check altogether. One would be to create an interface:
public interface CanGraduate {
default boolean isGraduated() {
return false;
};
}
Then make all Animals implement this interface:
public abstract class Animal implements CanGraduate {
//Behavior common among all animals
}
You can now freely add new animal types and be assured that you can safely invoke isGraduated() on them and get a false value as long as they inherit from the above Animal class.
For dogs, isGraduated() is supposed to be more meaningful. So you can override it in their case:
public class Dog extends Animal {
private boolean _graduated = true;
#Override
public boolean isGraduated() {
return _graduated; //or some complex logic that determines graduation
}
}
With this structure, you no longer need to worry about invoking the method on any kind of Animal.
As an example, let us see some driver code:
public class Main {
public static void main(String[] args) {
Dog dog1 = new Dog();
Dog dog2 = new Dog();
Cat cat1 = new Cat();
Cat cat2 = new Cat();
List<Animal> dogKennel = List.of(dog1, dog2);
List<Animal> catKennel = List.of(cat1, cat2);
for(Animal x : catKennel) {
System.out.println(x.isGraduated());
}
}
}
The program will simply output false since Cats can never graduate. If the kennel contained Dogs, it would output the actual graduation status of the dog.
Like the others have said, the getGraduation() method is only defined presumably in the Dog class. This means that the method can only be called on Objects with the type Dog. To define a variable with type Dog you can do Dog temphold = *whatever*. The reason it wants you to cast is because Object is a supertype of Dog. If you'd like to read more about casting you can here: https://javarevisited.blogspot.com/2012/12/what-is-type-casting-in-java-class-interface-example.html
Basically, all you have to do is a cast to convert the object
if (!(((Dog)tempHold).getGraduation()))
{
continue;
}
this casting tells the compiler that even though tempHold is an object of the Object class it also is an object of the Dog class and should have all of its properties
If you want to filter the list for just ones with a certain condition, the most common way to do that these days is with the Stream::filter method.
It would look like this:
List<Dog> completedTraining =
dogKennel
.stream()
.filter(
dog -> !dog.getGraduation()
)
.collect(
Collectors.toList()
)
;

Java SDK10: Is cast explicitly required?

I'm working through a Java book based on JDK 8. In the chapter about inheritance and generalisation the following example is shown:
class A {}
class B extends A {}
class C1 extends B { public void x1() {System.out.println("C1.x1");} }
class C2 extends B { public void x2() {System.out.println("C2.x2");} }
Then, some object variables are declared, all of type A:
A obj1, obj2, obj3, obj4;
These variables are populated with instances of the four classes:
obj1 = new A();
obj2 = new B();
obj3 = new C1();
obj4 = new C2();
Now, obj3.x1() doesn't work because obj3 is of type A, and x1() is not defined in A. In the book, now one can declare a new variable obj5 of type C1 and assign to it the value of obj3:
C1 obj5 = obj3; // then obj5.x1() should work
However on this line I get an Incompatible Types compile error.
Is this different between SDK8 and 10? Or am I missing some error somewhere?
As a side note: casting such as in C1 obj5 = (C1) obj3 works.
By casting, you tell the compiler that in your opinion, the assignment is ok because you consider obj3 to be of type C1. Then the compiler believes you and proceeds.
If you lied on this, you get a runtime exception. If not, all is fine.
You do need to cast, and there is no difference between Java 8 and Java 10 with regard to this. This is easier to understand if you give the classes meaningful names. Suppose that A = Animal, B = Mammal, C1 = Dog, C2 = Cat:
class Animal {}
class Mammal extends Animal {}
class Dog extends Mammal { public void x1() {System.out.println("Woof");}
class Cat extends Mammal { public void x2() {System.out.println("Meow");}
Animal obj1, obj2, obj3, obj4;
obj1 = new Animal();
obj2 = new Mammal();
obj3 = new Dog();
obj4 = new Cat();
When you try to do this assignment:
Dog obj5 = obj3; // obj3 is of type Animal
the cast is necessary because obj3 is of type Animal, but by looking at this line alone the compiler cannot be sure whether it's actually a Dog or something else. You'll have to use a cast to tell the compiler "I know better than you what this is, so I want you to treat this Animal as if it's a Dog".
Note that a runtime check will still be done - if, at runtime, it turns out that obj3 refers to an object that is not a Dog, you'll get a ClassCastException.
Have a look at the following code :
A a = new C1(); //reference variable of *A* class points object of *C1* class
C1 c1 = a; //compile time error, requires casting
C1 c1 = (C1) a; // type casting A to C1
In the above code, typecasting object of C1 class into A class will throw ClassCastExcepiton if a is not an object of the C1 class. If A and C1 class are not related to each other and doesn't part of the same type hierarchy, the cast will throw compile time error e.g. you can not cast String and StringBuffer, as they are not from same type hierarchy.
It’s an error in the book you are quoting. There is no difference between Java 8 and 10 here. Also in Java 8 you need the explicit cast:
C1 obj5 = (C1) obj3;
// then obj5.x1() works:
obj5.x1();
This has been so since Java 1.0, I believe.

why do I need to create a reference of A class, and then an object of B class

I am new in programing and i am watching youtube tutorial (10:05-10:47)
https://www.youtube.com/watch?v=ssAt_qrQpi0&index=31&list=PLsyeobzWxl7rooJFZhc3qPLwVROovGCfh
and I do not understand why we could need reference of class A and an object of class B?
Kotlin example from that video:
var h: Human = Alien()
Java example from that video
Human h = new Alien()
reference of human and object of alien
The usage of "Human" and "Alien" is terrible here. Instead of "Human", think "Animal". Instead of "Alien", think "Dog".
The terminology isn't great either. The "Object" is the literal object itself: the physical Dog <-> the bits associated with it in memory. The "Reference" is the variable, h. It references the object Dog. h is not a "reference of Animal and object of Dog", as the video says with Human/Alien. It's a "reference to a Dog object". However, the variable "h" itself, it not forced to reference only Dogs. In fact, it can reference any Animal.
For example, I can write the code:
Animal mypet = new Dog();
mypet = new Cat();
If I wrote the line Dog mypet, then I would be forced to only write mypet = new Dog() or mypet = getDogFromShelter(myNeighborhoodShelter). It would not let me write mypet = new Cat().
Cats are cool, so that would be terrible. Hence, we write Animal mypet to allow the variable mypet reference any animal. Dog, Cat, Elephant will all be available. However, because of this restriction, I am not allowed to do any Dog-specific things to mypet.
mypet.bark() will not work if mypet is an Animal. Not all Animals can bark. mypet.eat(Food) will work, since all Animals can eat. If I want my pet to Bark, because I know it is a Dog right now, then I can do
((Dog)mypet)).bark();
// Will throw run-time error if mypet is not a Dog!
// This is best to avoid, so just make mypet a Dog type if it must bark.
// If you must make an Animal bark, use if (!(mypet instanceof Dog)) to handle the error propely.
This above code will check to make sure mypet is a dog before letting it bark.
This can be implemented in code by writing
class Animal {
int health = 100;
void eat(Food f) {
health += f.value;
}
}
class Dog extends Animal { // States that "All Dogs are Animals"
// The word "extends" allows you to write Animal a = new Dog();
// "extends" also lets you do "Dog a = new Dog(); a.eat()"
int health = 150; // Dogs are strong
void bark() {
scareNearbyAnimals();
}
}
class Poodle extends Dog {
// Both of these will work:
// Dog mydog = new Poodle();
// Animal mypet = new Poodle();
int glamor = 50; // glamorous
}
The video mixed up Object vs Reference, so I'll make it more explicit with the following code
Dog a = new Dog();
b = a;
a and b both reference the same object in this instance. If Dog uses a lot of memory, then b = a does not cause more memory to be allocated.
b.hasEaten(); // False
a.eat();
b.hasEaten(); // True
b = new Dog(); // Now they are different. a does not affect b
a.eat() allowed the object to eat. The bits in memory have changed: the hunger value has been reset. b.hasEaten() checks the hunger value of the same Dog that a used when it was eating. b = new Dog() will separate them, so that a and b reference distinct dog objects. They will then no longer coupled as they were before.
Ok let me explain you.
We want to create an object "man" of class Human assuming that "man" is a human.
We give the human class some functions that human can do. Let's say walk, run, sit.
Each function tells the object (man) what to do.
In the other hand, we want to create a class for Aliens to create another object. We'll name it "alien". Assume that alien is a humanoid so it can do whatever human can, plus some other special abilities that human cannot. For example "fly".
In order to prevent it to write the exact same functions (walk, run, sit) to class Alien. we inherit the class Human so we can get the functions (walk, run, sit) from Human class.
So let's say:
Human h -> the object "h" is a human(oid)
But "h" is actually an alien so we have to define it so there comes the code:
Human h = new Alien();
In other words. Imagine that you have a structure like this:
Human (functions: walk, run, sit)
-- Alien (functions: (inherit: walk, run, sit), fly)
Please correct me if I'm wrong.
I hope that helps.

difference of two different allocations of subclass

Animal is the parent class of Cat class.
public static void main (String[] args)
{
Animal myCat1 = new Cat; //Allocation 1
Cat myCat2 = new Cat; //Allocation 2
}
What is the diffrerence of two allocation??Each is true ,isn't it?
Animal myCat1 = new Cat();
This is called polymorphism where the super class reference can hold a sub-class object.
Read Java tutorial: Polymorphism
Neither of these are valid. You need (). Apart from that:
the first referes to the instance by its superclass
the second refers to it by its class
You can refer to any object by any of its superclasses, up to Object. This is polymorphism.
To answer your questions:
There is no difference - in both cases 'new Cat ()' allocates an instance of the Cat class.
Both are true - myCat1 is an animal (in fact, a Cat) and myCat2 is a Cat.

When should or shouldn't I use a more general variable type for referencing my object?

There are 2 classes A and B, B extends A. What is the difference between
A a = new B();
and
B b = new B()?
Both create the object of class B. What is the difference?
You are right that in both cases an object of class B is created. The difference between the two declarations is in the type of the variable.
It is very important to keep the distinction between variables and objects in mind. For example, the following code defines 3 variables but only 2 objects:
Circle c1 = new Circle(5);
Circle c2 = c1;
Circle c3 = new Circle(5);
When you say
Shape s = new Circle(5);
instead of
Circle s = new Circle(5);
assuming Circle extends Shape then, even though in both cases you did create a circle object, in the former case you can only call shape methods on the circle (through the variable s) whereas in the second case you can you all circle methods (because you will be calling them through the circle variable c). That is a call like s.getArea() will work in both cases but something like s.getRadius() will ONLY be allowed in the second (unless you use an ugly cast).
So why do we often do things like the first case? That is, why do we often define our variables of a more general type than necessary? Usually we do this because we want to restrict the interface for safety. Perhaps we only care about shapes, but in this case the particular shape just happens to be a circle. If you cared about circle specific properties, then we would have used a circle variable. But we should strive to be as general as possible. Coding to the most general interface allows our code to work with shapes other than circles without modification.
Of course, for this to really sink in, you have to experience it firsthand, but hopefully this explanation is a start. There are many books and blog posts and articles that explain this in more detail with useful real-life anecdotes I'm sure.
A a = new B();
has only the attributes and methods of A.
B b = new B();
has the the attributes and methods of B.
If you added some attributes or methods to B, you can't call them with a.
The advantage is
Fruit f = new Mango();
Suppose
consumeFruit(Fruit f);
now you can call
consumeFruit(new Mango());
consumeFruit(new Strawberry());
Note:
For this case you would be only able to call the methods declared in the reference type. and object type's version will get invoked . and you would be only accessing fields from the reference type's class
See Also
Liskov substitution principle
If you say
List a = new ArrayList();
then you reference ArrayList only in one place in your code. That makes it easier to change it later to something else, like LinkedList;
Of course, this does not work if you need methods specific to ArrayList.
In general, you should use the most general type applicable.
This question is on Polymorphism. Following is an extract from Kathy Siera:
public class TestAnimals {
public static void main (String [] args) {
Animal a = new Animal();
Animal b = new Horse(); //Animal ref, but a Horse object
a.eat(); // Runs the Animal version of eat()
b.eat(); // Runs the Horse version of eat()
}
}
class Animal {
public void eat() {
System.out.println("Generic Animal Eating Generically");
}
}
class Horse extends Animal {
private void eat() { // whoa! - it's private!
System.out.println("Horse eating hay, oats, "
+ "and horse treats");
}
}
If this code compiled (which it doesn't), the following would fail at runtime:
Animal b = new Horse(); // Animal ref, but a Horse
// object , so far so good
b.eat(); // Meltdown at runtime!
Suppose this example:
We have class an animal:
public class Animal {
public void eat() {
// each animal can eat
}
}
Now we have another class dog:
public class Dog extends Animal {
public void bark() {
// dogs can bark
}
}
Now we can write this code:
Animal pet = new Dog();
Now we know, that pet can eat, but nothing more. But if we write
Dog pet = new Dog();
Then we know, that our pet can eat and bark.
Also there is safe and unsafe casting. Safe casting is from Dog to an Animal because each dog is animal (extends it)
Dog pet = new Dog();
Animal animal = pet;
But if we want to cast Animal to Dog we have to test if the instance of animal is really dog, because it doesn't have to be.
Animal pet = new Dog();
Dog myDog = null;
if (pet instanceof Dog) {
myDog = (Dog) pet;
}
Usually, declaring a parent class and assigning it an inherited class is useful when the parent class variable may be assigned different objects. For example
Pet p;
if (favoritePet == Pets.CAT) {
p = new Cat();
} else {
p = new Dog();
}
System.out.println(p.someMethodFromPet());

Categories