I have studying Java, and wanna understand how to realize idea of such factory of products?
(or other way structure of code)
public interface VirtualBD <E extends Enum<E>> {
void addInStorage(Class<E> type, Product product, int amount);
}
1 Question: how to use generic to get any type of Enum class as parameter
Root Categorie
public abstract class Product {
...
}
public enum AlchogolType {
Beer, Vodka;
}
public enum nonAlchogolType {
FreshJuise, Lemonade;
}
SubCategories
public abstract class Alchogol extends Product {
...
}
public abstract class nonAlchogol extends Product {
...
}
public class Beer extends Alchogol {
...
}
And, here is a problem begin's:
public class AlchogolTables implements VirtualBD{
HashMap<Alchogol, Integer> beer = new HashMap<Alchogol, Integer>();
HashMap<Alchogol, Integer> vodka = new HashMap<Alchogol, Integer>();
#Override
public void addInStorage(AlchogolType type, Product product, int amount) {
switch (type) {
case Beer:
beer.put((Alchogol) product,amount);
break;
case Vodka:
vodka.put((Alchogol) product,amount);
break;
default:
break;
}
}
}
in my idea - i want to use addInStorage method for different products, like:
public class OtherBeveragesTables implements VirtualBD{
HashMap<nonAlchogol, Integer> orangeFresh = new HashMap<nonAlchogol, Integer>();
HashMap<nonAlchogol, Integer> soda = new HashMap<nonAlchogol, Integer>();
#Override
public void addInStorage(nonAlchogolType type, Product product, int amount) {
switch (type) {
case FreshJuise:
orangeFresh.put((nonAlchogol) product,amount);
break;
case Lemonade:
soda.put((nonAlchogol) product,amount);
break;
default:
break;
}
}
}
how can i use Enum AlchogolType/nonAlchogolType as parametr?
I doubt the correctness of the organization of the code for such a task as: writing a factory for many products with categories, some differences and similarities.
Is a CAST: beer.put((Alchogol) product,amount); normal way?
Question 1
"how can i use Enum AlchogolType/nonAlchogolType as parametr?"
When reading your question, I assume that you are looking for a way on how you can pass both AlchogolType and NonAlchogolType as parameter in the same method. Unfortunately this is not possible, since a method asks for a specific type. Unlike classes, enums cannot override from other classes/enums. This means that the parameter type given in the method cannot be anything else than that.
Let's say there is EnumOne (APPLE, BANANA, PINEAPPLE) and EnumTwo (AUDI, BWM, FORD). If a method asks for a parameter of type EnumOne there is no way of passing anything else that is not defined in the EnumOne enum. You will get compiler errors when trying to pass values from, let's say, EnumTwo.
If you would like to have a work-around for this, you can try and put the values in one enum class. Only do this if your code can still remain maintainable and efficient.
Question 2
"I doubt the correctness of the organization of the code for such a task as: writing a factory for many products with categories, some differences and similarities."
Even though you are using abstraction to divide logic from your models in your code, you are still using separate classes (VirtualDB classes in your case) that prevent your program from using the benefits of abstraction in Object-oriented-programming.
Using abstractions in your model classes (Beer in your case), is good. I would recommend keeping it like that and not go further with applying abstraction in combination with your factory classes.
I believe you only need 1 factory class that holds all of your products. You can make a HashMap for every type of drink, but that makes it so you always have to update your factory class when you make a new type of drink. What you can do is make a single HashMap with as key Product and as value Integer and then save your enum of the type of drink in the Product class. The reason is because the type of drink is a property of a product. Now the only way to tell the type of drink is by knowing in what HashMap it is saved in. That seems inefficient considering later in your code you might have access to a Product instance, without having access to the HashMap in your factory. When saving the type of drink in the Product instance itself, you can make a method that returns the type of drink and that's it.
Question 3
"Is a CAST: beer.put((Alchogol) product,amount); normal way?"
Whether this is ok or not really depends on what you did beforehand. This all has to do with the "A dog is an animal, but an animal is not always a dog" story.
Let's say you have an abstract class Animal and two classes Dog and Cat that both inherit from the Animal class. If you have an instance of an Animal inherited class that you want to cast to Dog and you did not check before if this instance is actually a dog, you are asking for errors to be thrown. The instance could be an instance of a Dog class, but it could also be an instance of a Cat class. If you try to cast it and you are casting it to the wrong inherited type, you will get a java.lang.ClassCastException.
To solve the probable situation where this error could be thrown, always check beforehand if the variable you are trying to cast is of a specific inherited type. You should have a look at the instanceof keyword.
FYI, modern IDEs will most of the time give you a warning when you try to cast a variable if you did not check it beforehand.
My main language is not English. I tried to explain it the best I could. If you do have comments or anything that you would like to let me know, feel free to edit my comment or put a comment under it.
Related
I'm working on a school project and I need to create an ArrayList containing two types of objects,"managers" and "ticket salesmen",since I created an abstract class "user" and these two types extend it,I have created an ArrayList type "user" and stored both "managers" and "ticket salesmen" in it,but how do I access these two types? I can only access each element of the list as a "user",and get attributes that the abstract class has,not as "manager" or "ticket salesman".How can I get attributes of these two objects and can I identify objects type,as in which class is it an instance of?
you can use instanceof operator to identify the actual type of user
User obj = new Manager();
User obj2 = new SalesMan();
System.out.println(obj instanceof Manager); // true
System.out.println(obj instanceof SalesMan);// false
System.out.println(obj2 instanceof Manager); // false
System.out.println(obj2 instanceof SalesMan);// true
You should first check what the type is of the subclass. This can be done by using the instanceOf operator. Once you determined the subclass type, you should cast the User to that particular subclass. After casting you have access to the functionality of that certain subclass.
However note that the use of instanceOf should be avoided when possible. To avoid the use of instanceOf you could take a look at the accepted answer on this question.
Iterate through the arrayList, check type using instanceof, then cast to use the methods and attributes. Try something like this.
for (User user : arrayList) {
if (user instanceof Manager) {
Manager manager = (Manager) user;
//manager.method();
} else if(list instanceof SalesMan){
SalesMan salesMan = (SalesMan) user;
//salesMan.method();
}
}
An alternative would be to get the type of class using getClass():
for (Object obj : userArrayList) {
if (obj.getClass().equals(Manager.class)) {
...
}
if (obj.getClass().equals(Salesman.class)) {
...
}
}
It should also be noted that instanceof will work also in the case of subclasses but this way, it won't.
Kindly follow below link for your solution:
https://stackoverflow.com/a/34437757/3095589
Might be possible it will be helpful to you...
While the other answers perfectly describe how to achieve what you asked for, what you seek to do is generally considered a bad practice in object oriented design for various reasons:
Coupling: When your code makes decisions based on an object's type, you will have to add more conditional checks whenever you add more types, i.e. a third User type. This is bad, because it makes maintaining your code exponentially harder. When you add additional subclasses, you will have to find all the places in your code that may need special behavior. Forget to do this for even one of the mentioned places, and your code breaks.
Using instanceof means you need to treat different subclasses of a superclass in different ways; so that superclass probably did not have enough shared functionality/data to be a superclass in the first place? Why store them together if they share so little characteristics?
Consider redesigning your code. If you still believe Manager and TicketSalesMan must inherit from User, and you need to perform some operation on them in an iterated loop, consider overriding a method instead of using instanceof. Look at the code below:
public abstract class User
{
public abstract void doOperation();
}
public class Manager extends User
{
public void doOperation()
{
// do stuff that managers do
}
}
public class SalesMan extends User
{
public void doOperation()
{
// do stuff that salesmen do
}
}
public class Main
{
public static final void main(String[] args)
{
ArrayList<User> users = getUsers();
for(User u: users)
{
u.doOperation();
}
}
}
As I proceed through my online tutorial, I came across this lesson. I have an interface and two classes that implements that interface.
public interface Payable {
double getPaymentAmount();
}
and
class Invoice that implements the above interface Payable
class SalariedEmployee that extends an abstract class Employee which implements Payable interface.
A test class that contains the main method to test this.
Now in the test class, when creating an array of objects, the type of object was referred to as Payable[] rather than SalariedEmployee[] or Invoice[], like
public static void main(String[] args) {
Payable[] payableObjects = new Payable[4];
payableObjects[0] = new Invoice("0000", "abc", 1,2);
payableObjects[1] = new SalariedEmployee("test", "user", "000-000", 35);
Is this because all the classes implements the interface Payable[] ?
If an interface is defined at the top level hierarchy, is it always possible to create objects of all the classes that implements that interface?
Your question title is not grammatical, but the word choice suggests there's a subtle misunderstanding of concepts going on.
You can only create a class as that class. That is, you can't write new Payable and somehow expect there to be any Invoice or SalariedEmployee objects being created.
But you can make a reference to a Payable point to any object that implements Payable. That's pretty much the fundamental idea of subtype polymorphism.
What's going on in the example is that an array of four Payable references is created. These references don't yet point at anything (they're null) and there are no Invoice or SalariedEmployee objects around yet, only the array object.
Then, the code creates two objects and assigns them to two of the references. This works the same as if the array elements were independent variables. (Almost, but the difference is due to array covariance, which isn't important at this point.) In particular, the result of the new operator has the type Invoice in the first case, not Payable. You can assign the Invoice to the Payable reference, but the conversion happens at assignment, not at creation.
So technically, the answer to your title question is "no, objects are always created as the type you specify in the new expression, but you can convert the references afterwards".
for your first question: yes, you would get a compiler error if it wasn´t the case.
for the second case, take the List or the Map as an example. Look at the following example. We declare a list but depending on the the flag, we want the this specific List to act different, since it represents a different class
public class BookList{
List <String> list;
public BookList(boolean flag) {
if(flag) {
list = new ArrayList<>();
} else {
list = new LinkedList<>();
}
}
}
Since we declared it just as List we are able to assign different type of lists that implement this interface. You could change the usecase of this class very simple, while you are still able to acces every method that is provided by the interface.
That´s what your array of Payable is doing aswell. You want to assign different types of classes into this array, which all implement this interface.
This would make it more easy, to create methods for this specific interface. Take a summing method as an example for your case.
public int sumPayable(Payable[] payables) {
int sum = 0;
for(Payable p : payables) {
sum += p.getPaymentAmount();
}
return sum;
}
In this case, it wouldn´t matter what the actuall class of each of this classes that do implements Payable is, since you could simply pass an array, like you did create, to this method.
Imagine situation:
I have got two classes
public class Fruit{
}
and:
public class FruitOnSale extends Fruit{
int price;
public int getPrice() or something
}
My program has one fruit and one fruitOnSale object. I would like to create completly new (clone) fruit2 [Fruit] based on the fruitOnSale (for example somebody has bought fruitOnSale and it needs to appear in his bag but as a normal fruit cause it is no more in shop). The method getPrice and field price are deleted during it.
Then backwards - somebody creates a shop (...) and puts his fruit on sale. Now I need to convert fruit to FruitOnSale (I want it to be in the shop as 'on sale' and in my bag as 'normal', but as independent objects).
These classes will be rebuilded, modified and lots work may be done on them, so I don't want to manualy rewrite them just by copying every field because it's sensless. Is it possible through clonning? Or have you got better ideas?
Use composition:
public class Fruit {
// your regular fruit class
}
Your "fruit on sale":
public class FruitOnSale {
private Fruit fruit;
private int price;
public FruitOnSale(Fruit fruit, int price) {
this.fruit = new Fruit(fruit.getName());
this.price = price;
}
public Fruit getFruit() {
return Fruit(fruit.getName());
}
}
Now you can construct FruitOnSale instances by passing in a Fruit instance, and you can get a Fruit instance from FruitOnSale instance as well. Notice that when you initialize a FruitOnSale instance with a Fruit instance, it creates a "copy" of the Fruit instance. It's good to do this, otherwise you could modify the original Fruit instance, which would then affect the FruitOnSale instance. This is not what you want, if you are assuming that these are immutable. Similarly, getFruit() doesn't return a reference to the internal instance, but creates an entirely-new Fruit instance as well.
While solving this particular example using inheritance does not violate the Liskov Substitution Principle, in general it is a good idea to think about the impact of extending the base class. For example, there might be some things that you can do with Fruit, that don't make sense with FruitOnSale (i.e., could lead to inconsistent, illogical, or unpredictable behavior); this would be an example of LSP being violated.
Cloning and Inheritance are two very different and very unrelated concepts in which both is unlikely to help you in your current case, if I understand you correctly.
Cloning normally refers to when you want to duplicate existing objects at runtime, thus the term should be avoided when used in a programming context unless the subject matter actually has relevance to the concept of object cloning.
Inheritance is used in contexts where you want to provide a more specific version or an alternative implementation of something, thereby extending the features of the more vague/abstract version with addition/altered functionality.
To give an example, we can declare two classes as follows:
public class WoodenFurniture{
public void burn(){
// Implementation here
}
}
and
public class WoodenChair extends WoodenFurniture{
public void sit(){
// Implementation here
}
}
Note in this case, WoodenChair is a more specific version of WoodenFurniture and thus WoodenChair inherits all functionality of WoodenFurniture, including the aforementioned burn() method.
Whilst your Fruit and FruitOnSale class demonstrates such a relationship, where FruitOnSale is a more specific version of Fruit, your application of inheritance is incorrect.
In your question body, you suggest mutating a Fruit object between multiple states carrying different information should be done through inheritance, which is only true if you are continuously adding or specifying detail to your current object. In this particular case, composition should be used, as described by Vivin Paliath.
But in the case you are describing, you want to repeatedly change or toggle between different states of the same object. Especially by saying method getPrice and field price are deleted during it you demonstrate inheritance is not what you want. This should be done by adding fields to your original object to append state-specific information as opposed to the creation of multiple classes, as follows:
public class Fruit{
private boolean onSale = false;
private int price = 0;
/**
* Retrieves the price of the fruit if it is on sale.
*/
public int getPrice(){
// Check if the fruit is in the onSale state
if(!onSale){
// Rather than throwing exception, you can alternatively return an invalid price e.g. -1 to denote "not for sale"
throw new IllegalStateException("not on sale");
}
return price;
}
public void putOnSale(int price){
this.price = price;
onSale = true;
}
public void takeOffSale(){
onSale = false;
}
}
The class above represents an example implementation of something on the lines of what you want. In this case, we do not need to go through the trouble of converting between object types nor break any inheritance policy regarding how objects should interact.
I have came across the following point the advantage of object composition over class inheritance. But I often see the following sentence in many articles
In object composition, functionality is acquired dynamically at run-time by objects collecting references to other
objects. The advantage of this approach is that implementations can be replaced at run-time. This is possible because
objects are accessed only through their interfaces, so one object can be replaced with another just as long as they
have the same type.
But doubt may be naive, since i am a beginner. How the implementation can be replaced in runtime? If we write a new line of code, don't we need to compile to reflect the change? Then what is meant be replacing at runtime? quite confusing.
Or any other magic, behind the scene activities happen. Can anyone please reply.
Think of an implementation of Stack. A simple implementation of Stack utilizes a List behind the scenes. So naively, you could extend ArrayList. But now if you want a separate Stack backed by a LinkedList instead, you would have to have two classes: ArrayListStack and LinkedListStack. (This approach also has the disadvantage of exposing List methods on a Stack, which violates encapsulation).
If you used composition instead, the List to back the Stack could be provided by the caller, and you could have one Stack class that could take either a LinkedList or an ArrayList, depending on the runtime characteristics desired by the user.
In short, the ability of the implementation to "change at runtime" refers not to an instance of the class being able to change its implementation at runtime, but rather that the class does not know at compile time what its precise implementation will be.
Also note that a class using composition need not allow the delegate implementation to be chosen at runtime (by the caller). Sometimes doing so would violate encapsulation, as it would give the caller more information about the internals of the class than is desirable. In these cases, composition still carries the benefits of only exposing the methods of the abstraction, and allowing the concrete implementation to be changed in a later revision.
Real-life examples
By the way, I use the example of Stack because it's not purely hypothetical. Java's Stack class in fact extended Vector, which made it forever carry the baggage of synchronization and the performance characteristics of an array-backed list. As a result, using that class is heavily discouraged.
A perfect example of correctly using composition for a collection can also be found in the Java library, in Collections.newSetFromMap(Map). Since any Map can be used to represent a Set (by using dummy values), this method returns a Set composed of the passed-in Map. The returned Set then inherits the characteristics of the Map it wraps, for example: mutability, thread safety, and runtime performance--all without having to create parallel Set implementations to ConcurrentHashMap, ImmutableMap, TreeMap, etc.
There are two strong reasons to prefer composition over inheritance:
Avoids combinatorial explosions in class hierarchy.
Can be modified at run-time
Let's say that you are writing an ordering system for a pizza parlor. You would almost certainly have a class Pizza...
public class Pizza {
public double getPrice() { return BASE_PIZZA_PRICE; }
}
And, all else being equal, the pizza parlor probably sells a lot of pepperoni pizza. You can use inheritance for this - PepperoniPizza satisfies an "is-a" relationship with pizza, so that sounds valid.
public class PepperoniPizza extends Pizza {
public double getPrice() { return super.getPrice() + PEPPERONI_PRICE; }
}
Okay, so far so good, right? But you can probably see that things we haven't considered. What if a customer wants pepperoni and mushrooms, for instance? Well, we can add a PepperoniMushroomPizza class. Already we have a problem - should PepperoniMushroomPizza extend Pizza, PepperoniPizza, or MushroomPizza?
But things get even worse. Let's say our hypothetical pizza parlor offers sizes Small, Medium, and Large. And crust varies too - they offer a thick, thin, and regular crust. If we are just using inheritance, suddenly we have classes like MediumThickCrustPepperoniPizza, LargeThinCrustMushroomPizza, SmallRegularCrustPepperoniAndMushroomPizza, et cetera...
public class LargeThinCrustMushroomPizza extends ThinCrustMushroomPizza {
// This is not good!
}
In short, using inheritance to handle diversity along multiple axes causes a combinatorial explosion in the class hierarchy.
The second problem (modification at run-time) derives from this as well. Suppose that a customer looks at the price of their LargeThinCrustMushroomPizza, gawks, and decides they'd rather get a MediumThinCrustMushroomPizza instead? Now you are stuck making a whole new object just to change that one attribute!
This is where composition comes in. We observe that a "pepperoni pizza" does indeed have an "is-a" relationship with Pizza, but it also satisfies a "has-a" relationship with Pepperoni. And it also satisfies "has-a" relationships with crust type, and size. So you re-define Pizza using composition:
public class Pizza {
private List<Topping> toppings;
private Crust crust;
private Size size;
//...omitting constructor, getters, setters for brevity...
public double getPrice() {
double price = size.getPrice();
for (Topping topping : toppings) {
price += topping.getPriceAtSize(size);
}
return price;
}
}
With this composition-based Pizza, the customer can choose a smaller size (pizza.setSize(new SmallSize())) and the price (getPrice()) will respond appropriately - that is, the run-time behavior of the method may vary according to the run-time composition of the object.
This is not to say that inheritance is bad. But where it is possible to use composition instead of inheritance to express a diversity of objects (like pizzas), composition should usually be preferred.
The other answers speak a bit about this, but I thought that an example of how the behaviour can change at runtime would be helpfull. Suppose you have a interface Printer:
interface Printer {
void print(Printable printable);
}
class TestPrinter implements Printer {
public void print(Printable printable) {
// set an internal state that can be checked later in a test
}
}
class FilePrinter implements Printer {
public void print(Printable printable) {
// Do stuff to print the printable to a file
}
}
class NetworkPrinter implements Printer {
public void print(Printable printable) {
// Connects to a networked printer and tell it to print the printable
}
}
All of the Printer classes can now be used for different purposes. TestPrinter can be used as a mock or stubb when we run tests. FilePrinter and NetworkPrinter each handle a specific case when printing. So assume we have a UI widget where the user can press a button to print something:
class PrintWidget {
// A collection of printers that keeps track of which printer the user has selected.
// It could contain a FilePrinter, NetworkPrinter and any other object implementing the
// Printer interface
private Selectable<Printer> printers;
// A reference to a printable object, could be a document or image or something
private Printable printable;
public void onPrintButtonPressed() {
Printer printer = printers.getSelectedPrinter();
printer.print(printable);
}
// other methods
}
Now at runtime when the user selects another printer and presses the a print button the onPrintButtonPressed method gets called and the selected Printer used.
That is the Polymorphism which is the core concept of OOP.
It means ‘a state of having many shapes’ or ‘the capacity to take on different forms’. When applied to object oriented programming languages like Java, it describes a language’s ability to process objects of various types and classes through a single, uniform interface.
As mark said List is a Uniform interface and its Different implementations are like ArrayList.....etc
This is interesting to answer. I am not sure whether you have used factory pattern or not. But if yo have then understanding this with that example should be good. Let me try to put it here:
Suppose you have a parent class called Pet as defined here
package com.javapapers.sample.designpattern.factorymethod;
//super class that serves as type to be instantiated for factory method pattern
public interface Pet {
public String speak();
}
And there are few subclasses such as Dog, Duck etc, sample here:
package com.javapapers.sample.designpattern.factorymethod;
//sub class 1 that might get instantiated by a factory method pattern
public class Dog implements Pet {
public String speak() {
return "Bark bark...";
}
}
package com.javapapers.sample.designpattern.factorymethod;
//sub class 2 that might get instantiated by a factory method pattern
public class Duck implements Pet {
public String speak() {
return "Quack quack...";
}
}
And there is a factory class which returns you a Pet depending on the input type, sample here:
package com.javapapers.sample.designpattern.factorymethod;
//Factory method pattern implementation that instantiates objects based on logic
public class PetFactory {
public Pet getPet(String petType) {
Pet pet = null;
// based on logic factory instantiates an object
if ("bark".equals(petType))
pet = new Dog();
else if ("quack".equals(petType))
pet = new Duck();
return pet;
}
}
Now lets see how at the run time we can have different kind of Pets created depending on the input, sample here
//using the factory method pattern
public class SampleFactoryMethod {
public static void main(String args[]) {
// creating the factory
PetFactory petFactory = new PetFactory();
System.out.println("Enter a pets language to get the desired pet");
String input = "";
try {
BufferedReader bufferRead = new BufferedReader(
new InputStreamReader(System.in));
input = bufferRead.readLine();
// factory instantiates an object
Pet pet = petFactory.getPet(input);
// you don't know which object factory created
System.out.println(pet.speak());
} catch (IOException e) {
e.printStackTrace();
}
}
}
Now if you run the program for different kind of inputs such as "bark" or "quack", you will get a differnt pet. You can change the above program to take different inputs and create different Pets.
Here it answers your question that without changing the code, just depending on type of input you get different behavioral pets.
Hope it helps!
How the implementation can be replaced in runtime?
Let's use some code example to brighten the day (a loop that reads a new line everytime, and reprint all lines read so far):
List<String> myList = new ArrayList<String>(); // chose first "implementation"
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String line = br.readLine(); // do something like read input from the user
myCounter.resetChronometer(); // hypothetical time counter
myList.add(line); // add the line (make use my "implementation")
// and then do some final work, like printing...
for(String s: myList) {
System.out.println(s); // print it all...
}
//But, hey, I'm keeping track of the time:
myCounter.stopChronometer();
if (myCounter.isTimeTakenTooLong())
// this "implementation" is too slow! I want to replace it.
// I WILL replace it at runtime (no recompile, not even stopping)
List<String> swapList = myList; // just to keep track...
myList = new LinkedList<String>(); // REPLACED implementation! (!!!) <---
myList.addAll(swapList); // so I don't lose what I did up until now
// from now on, the loop will operate with the
// new implementation of the List<String>
// was using the ArrayList implementation. Now will use LinkedList
}
}
Just as you said: This is [only] possible because objects [myList] are accessed only through their interfaces (List<String>). (If we declared myList as ArrayList<String> myList, this would never be possible...)
I give lessons on the fundamentals of the Java programming language, to students who study this subject in college.
Today one of them got me really confused with her question, so I told her to give me just a day to think about the problem, and I'll give her as accurate of an answer as I can.
She told me that the teacher got really angry when she used the keyword instanceof in her exam.
Also, she said that the teacher said that there is not a way to prove how polymorphism worked if she used that word.
I thought a lot to try to find a way to prove that in some occasions we need to use instanceof, and also that even if we use it, there still some polymorphism in that approach.
So this is the example I made:
public interface Animal
{
public void talk();
}
class Dog implements Animal {
public void talk() {
System.out.println("Woof!");
}
}
public class Cat implements Animal
{
public void talk() {
System.out.println("Meow!");
}
public void climbToATree() {
System.out.println("Hop, the cat just cimbed to the tree");
}
}
class Hippopotamus implements Animal {
public void talk() {
System.out.println("Roar!");
}
}
public class Main {
public static void main(String[] args) {
//APPROACH 1
makeItTalk(new Cat());
makeItTalk(new Dog());
makeItTalk(new Hippopotamus());
//APPROACH 2
makeItClimbToATree(new Cat());
makeItClimbToATree(new Hippopotamus());
}
public static void makeItTalk(Animal animal) {
animal.talk();
}
public static void makeItClimbToATree(Animal animal) {
if(animal instanceof Cat) {
((Cat)animal).climbToATree();
}
else {
System.err.println("That animal cannot climb to a tree");
}
}
}
My conclusions are the following:
The first approach (APPROACH 1) is a simple demo of how to program to an interface, not a realization. I think that the polymorphism is clearly visible, in the parameters of the method makeItTalk(Animal animal), and also in the way the method talk is called, by using the animal object.(This part is ok)
The second part is the one that makes me confused. She used instanceof at some point in her exam (I don't know how their exam looked like), and that was not accepted correctly because the teacher said, you are not proving polymorphism.
To help her understand when she can use instanceof, I thought about telling her, that she can use it, when the method she needs to call is not in the interface, but it is just in one of the implementing classes.
As you can see, only cats can climb to trees, and it would not be logical to make a Hippopotamus or a Dog climb to a tree. I think that could be an example of when to use instanceof
But what about polymorphism in approach 2?
How many uses of polymorphism do you see there (only approach 2)?
Do you think this line has some type of polymorphism in it?
((Cat)animal).climbToATree();
I think it does, because in order to achieve a Casting of this type, the objects need to have an IS-A relationship, an in some way that is polymorphism.
What do you think, is it correct?
If yes, how would you explain with your own words, that casting relies on polymorphism?
The reason the instanceof method is seen as bad is simple. Cats aren't the only Animal that might be able to climb a tree.
What happens if down the road you need to add a Koala class. Then your simple if becomes a not so simple or. Then, what happens when you add another class? and another one. And another one. That's the prime reason why instanceof is seen as bad. Because it couples the implementation to a concrete class, rather than opening it for the callee to determine what to do.
Simply implement the makeItClimbToATree() method to throw a CantClimbTreesException if called on an animal that can't climb. That way you have the best of both worlds. Easy to implement, and easy to extend.
IMHO, instanceof has only 1 truly valid use: In a test case to test the returned instance from a method matches the expected return type (in non-type safe languages).
Basically any other use can more than likely be refactored away or designed differently to negate the need for its use.
Another way to look at it is this: Polymorphism allows you to eliminate almost all conditional statements from your code. The only conditionals that you can't get rid of (at least all of them) are in object creational methods (such as in a factory where it must choose the class based upon a runtime argument). Just about any other conditional can be replaced by polymorphism. Therefore, anything that does conditional execution is by definition anti-polymorphic. That's not to say it's bad (there's a huge difference between Good and Good Enough), But in an academic discussion, it's not polymorphic...
Never forget the 60/60 rule. 60% of your total development time will be spent maintaining the code you wrote, and 60% of that time will be spent adding new features. Make maintaining easier, and your life will be easier as well. That's why instanceof is bad. It makes the initial design easier, but complicates the long term maintenance (which is more expensive anyway)...
In your above example, there is no need to call
makeItClimbToATree (new Hippopotamus ());
It could be easily avoided, if makeItClimbToATree wouldn't expect an animal, but something more specific, which is really able to climb a tree. The necessity to allow animals, and therefore to use instanceof, isn't visible. If you manage the animals in a List of animals, it will be more obvious.
While ircmaxells explanation starts great, while introducing the Koala and other TreeClimbers, he doesn't see a second extension which is hiding in a sea anemone: different capabilities of animals like seaAnemoneHider, winterSleeping, blueEyed, bugEating, and so on, and so on. You would end up with boolean over boolean, constantly recompiling the base class, as well as breaking extending customer classes, which would need recompilation again, and wouldn't be able to introduce their own possibilities in a similar manner.
Customer A would need Customer B to declare a NotBugEatingException, to get your behaviour into the base class.
Introducing your own interfaces, combined with instanceof, is a much cleaner approach, and more flexible. Customer A might define divingLikeAPenguin and customer B trumpeting, both not knowing of each other, both not affecting the Animal class and not provoking useless recompilations.
import java.util.*;
interface Animal {
public void talk ();
}
interface TreeClimbing {
public void climbToATree ();
}
class Dog implements Animal {
public void talk () { System.out.println("Woof!"); }
}
class Cat implements Animal, TreeClimbing {
public void talk () { System.out.println("Meow!"); }
public void climbToATree () { System.out.println ("on top!"); }
}
public class TreeCriterion {
public static void main(String[] args) {
List <Animal> animals = new ArrayList <Animal> ();
animals.add (new Cat ());
animals.add (new Dog ());
discuss (animals);
upTheTree (animals);
}
public static void discuss (List <Animal> animals) {
for (Animal a : animals)
a.talk ();
}
public static void upTheTree (List <Animal> animals) {
for (Animal a : animals) {
if (a instanceof TreeClimbing)
((TreeClimbing) a).climbToATree ();
}
}
}
We don't need a third animal, dog and cat are enough. I made them default visible instead of public, to make the whole example fit into a single file.
Do you think this line has some type of polymorphism in it?
((Cat)animal).climbToATree();
No. Especially, since Cat is a leaf class in the example.
I think it does, because in order to achieve a Casting of this type, the objects need to have an IS-A relationship, an in some way that is polymorphism.
Polymorphism requires the IS-A relationship, but not the other way round.
Polymorphism is when you dispatch to (potentially) different methods based on an abstract interface. If you don't have that dispatching, then it is not using polymorphism. In your example, using instanceof to cast to a class with no subclasses, you are removing the need for dispatching.
(Of course, there is more than one way to "do polymorphism" in Java. You can implement it using interfaces, using abstract classes, or using concrete classes with subclasses ... or hypothetical subclasses that may be written in the future. Interfaces (and dispatching based on an interface) are generally the best way because they give a clean separation of the API from the identity of class.)
And on a separate note, using instanceof like that is typically a sign of poor design and / or poor modelling. Specifically, it hard-wires the assumption that only cats can climb, which is trivially falsified if we include other animals into the model / program. If that happens, your code breaks.
Maybe I'm missing the point and don't get the context of the exam question, but whether an Animal can climb a tree should be a part of the class that implements Animal. For example, if Animal is an interface, you could have a method boolean isCapableOfClimbing() and then each implementing class would be able to indicate its capability.
A method that attempted to make the animal climb could then use that. It doesn't make sense for a method that's trying to make the animal climb a tree check whether it's an instance of a particular class, since then that method is specifying something that should be specified in the implementing class. A simple method should not provide behaviour for a class that it's using.
As for your question of when to use instanceof, once place where it will almost always be used is if overriding the equals() method of a class, since it only accepts an Object and you typically have to ensure it is of the same type so it can be cast and then meaningfully compared.
What about something like the code below? It solves the generality problem by separating the tree-climbing as another interface you can implement or not on your animals. It fits the problem better: climbing trees is not an intrinsic property of all animals, only of a subset of them. At least to me it looks much clearer and elegant than throwing NotImplementedExceptions.
public interface Animal {
public void talk();
}
public interface AnimalCanClimbTrees extends Animal {
public void climbToATree();
}
public class Dog implements Animal {
public void talk() {
System.out.println("Woof!");
}
}
/* Animal is probably not needed, but being explicit is never bad */
public class Cat implements Animal, AnimalCanClimbTrees
{
public void talk() {
System.out.println("Meow!");
}
public void climbToATree() {
System.out.println("Hop, the cat just cimbed to the tree");
}
}
class Hippopotamus implements Animal {
public void talk() {
System.out.println("Roar!");
}
}
public class Main {
public static void main(String[] args) {
//APPROACH 1
makeItTalk(new Cat());
makeItTalk(new Dog());
makeItTalk(new Hippopotamus());
//APPROACH 2
makeItClimbToATree(new Cat());
makeItClimbToATree(new Hippopotamus());
}
public static void makeItTalk(Animal animal) {
animal.talk();
}
public static void makeItClimbToATree(Animal animal) {
if(animal instanceof AnimalCanClimbTrees) {
((AnimalCanClimbTrees)animal).climbToATree();
}
else {
System.err.println("That animal cannot climb to a tree");
}
}
}
The instanceof operator has nothing to do with polymorphism. It is simply used to see whether or not an object is an instance of a particular class. You see this operator being used a lot in the equals() method, because the method takes a generic Object as a parameter:
public class Cat implements Animal{
#Override
public boolean equals(Object obj){
if (obj == null || !obj instanceof Cat){
//obj is null or not a "Cat", so can't be equal
return false;
}
if (this == obj){
//it's the same instance so it must be equal
return true;
}
Cat catObj = (Cat)obj; //cast to "Cat"
return this.getName().equals(catObj.getName()); //compare the two objects
}
}
If a class does not implement a method, then it should throw an exception. I believe the "official" exception you are supposed to throw is UnsupportedOperationException. To be "correct", I think the Animal interface should have a public void climbToATree(); method. The climbToATree() methods in the Dog and Hippo classes should throw an UnsupportedOperationException because they cannot implement this method. But if you are throwing this exception very often, then there may be something wrong with your object model, as this is not a common thing to do I don't think.
Also note that it's helpful (but not required) to use the #Override annotation with polymorphic programming in Java. This will cause a compilation error to be thrown if a method with this annotation does not override a parent method, implement an abstract method, or (in Java 6) implement an interface method. This can help catch any mistakes you make in the method signature. For example:
public String tostring(){
return "foobar";
}
Without the annotation, the program would compile and run successfully. But this was not your intention! You wanted to override toString(), but you accidentally spelled the name wrong!!
I'm surprised no one wrote anything about Late Binding. Polymorphism in Java = Late Binding. The method being called will be be attached to the object when we finally know its type. In your example:
if(animal instanceof Cat) {
((Cat)animal).climbToATree();
}
You are calling climbToATree() on a Cat object so the compiler accepts it. At run time, there is no need to check the type of the calling object since climbToATree() belongs to Cat only. And so there is no polymorphism in these lines of code.
About casting being related to Polymorphism, it isn't. Casting just limits the fields that are shared in both objects, if the cast is legal. You could do this:
class A {
int getInt() {}
}
class B extends A {
int getInt() {}
}
// in main
A a = new B();
A b = (A)a;
b.getInt(); // This would still call class B's getInt();
The cast itself added no value, getInt() was bound at run time to the runtime type of a, which was class B.
A polymorphic and OOP approach would be to place the method makeItClimbToATree on the Animal interface:
public interface Animal{
public void talk();
public void makeItClimbToATree();
}
Then the implementors of Animal would provide the behavior for the method, which for all other than Cat could be to throw an exception. This is polymorphic because you operate on different implementations of Animal through a single method.
The function which uses the instanceOf operator is considered "bad" OOP because it requires knowledge of all the implementation types to determine the behavior of the method.