Say I have this class hierarchy:
Animal <-- FourLegged <-- Dog
Animal <-- FourLegged <-- ....
Animal <-- ThreeLegged <-- ... (what has 3 legs?)
Animal <-- TwoLegged <-- Chicken
Animal <-- TwoLegged <-- ...
(Forgot what the scientific terms for four-legged and two-legged animals are. But that's beside point, right? :) )
If I have an Animal object, and I need to know whether it is a FourLegged or if it is a TwoLegged, I would normally do animalObject instanceof FourLegged.
Is that slower than adding a bunch of isFourLegged(), isThreeLegged(), isTwoLegged(), to Animal class?
(I would like to know the performance impact. This is NOT a design exercise. So I would appreciate it if you won't be wasting time suggesting how to re-write the class)
Edit
Some people have suggested adding 'getNumberOfLegs()", which is perfectly reasonably given this specific example. But suppose the point is NOT to have the number of legs, but to get what type of animal this is.
If your subclasses doesn't add any behavior and is just a way to specify the number of legs, you should go with this refactoring called Replace Subclass With Fields. => no need for subclasses any more.
Otherwise, add a polymorphic method like: numberOfLegs(), implemented by each of your Animal's subclasses.
Try
Animal animal = new Dog();
if(animal.getClass().isAssignableFrom(FourLegged.class)){
System.out.println("FourLegged");
}
Do it in same way for others
The question centers around the "speed" of execution: Is one way slower than another?
Unless you're talking about algorithmic differences, the only way to know anything remotely accurate about performance is to measure your expected use case. In Java many variables affect performance, including the JVM chosen, JVM arguments, and so on.
Having said that, it is straightforward to see that instanceof potentially has more work to do:
Set checkClass = this.getClass()
Is checkClass == the target class? If yes, return true.
Does checkClass have a superclass? If no, return false.
Set checkClass = superclass of checkClass
Goto 2
(With potentially more effort involving the possibility of interfaces; in this case I am presuming that the JVM implementation is aware that the target class is not an interface and can use that knowledge to its benefit.)
However, a virtual method call requires no potential iteration: Fetch a function pointer from the object's vtable, and call it.
But when the target class is the immediate superclass of the object, then there is only one iteration in traversing the class hierarchy. Is that case "faster" or "slower" than a virtual method call?
Bottom line: It depends. When performance matters, measure. In the absence of data clearly pointing to a performance bottleneck with the code, prefer code that is clear, concise, understandable, and maintainable.
Related
Recently I refactored the parent class, let's call it Fish.
public class Fish {
...
}
Fish had a lot of functions in it that made it logical to refactor for modularity, so I created a child class, let's call it Shark.
public class Shark extends Fish {
...
}
There is a third class, very much only used as a sort of setup script class which might not be ideal, but it is this way for now. Let's call this third class SwimmingInTheOcean.
public class SwimmingInTheOcean {
public Fish nemo = new Fish();
public Shark bruce = new Shark();
public void func1() {
nemo.move();
}
public void func2() {
nemo.sleep();
}
public void func3() {
ocean.setup...
nemo.sleep();
nemo.eat();
}
public void func4() {
ocean.setup...
nemo.sleep();
print...
}
public void func5() {
bruce.move()
}
public void func6() {
bruce.eat()
bruce.sleep()
}
}
SwimmingInTheOcean creates an object of Fish, because the class has many functions that work on Fish.
There is however, two functions in SwimmingInTheOcean which require an object of type Shark as well.
So far I see three options, but none of them seem ideal.
Create both object type Fish and object type Shark in SwimmingInTheOcean. This is what I did.
Create only an object type Shark, because shark already contains all the functions of Fish. The reason why I did not pick this solution however, is because for most intents it looks very weird to use a Shark instead of a Fish. It would mislead someone reading the code in the future.
Split SwimmingInTheOcean as well into two, but the issue is, the higher level class where I sometimes would be using Shark, I still use Fish 90% of the time. So I would have to split that class as well into two.
This is probably a different issue altogether, but Fish has functions that I have not overloaded yet in Shark, instead I created new functions. Fish can move, eat, sleep, and Shark has sharkMove, sharkEat, sharkSleep instead of overloading. The reason why I haven't overloaded these yet is because the Shark functions still partially use the fish functions, so sharkMove still has the Fish' move as a step 1.
The setup of your question indicates you have much bigger fish to fry, so to speak: Your code doesn't make any sense in the first place.
Specifically, this part:
Create both object type Fish and object type Shark in SwimmingInTheOcean. This is what I did.
It sounds like you're treating objects as being simply namespaces. Not, themselves, things that represent stuff and have actual state.
Let's say you really do have 2 sharks (bruce and sheila) and 1 fish (nemo).
Clearly, in such a situation, nemo.move() and bruce.move() do completely different things - specifically, they cause different state (namely, nemo's position for nemo.move(), and bruce's for bruce.move()) to be used in the calculations and to be affected by the method invocation. They aren't interchangible at all, and therefore, this:
There is however, two functions in SwimmingInTheOcean which require an object of type Shark as well.
Just doesn't make sense. Specifically, it doesn't make sense to see 'I have a function that I need to invoke; this will require an object of type Shark'. You don't "require an object so that some function is available", you "require a shark", and it's not specifically about Bruce's abilities. It's about poor bruce himself. If you need bruce, you need bruce.
Specifically, if the only thing you need bruce for, is things that any fish can do, okay. You still need bruce. Objects aren't interchangible, or, if they are, you've go some fairly bizarre design going on, not very OOP-style. If it works, it works, but this question is specifically about code style, and there is rather little point attempting to answer a question that boils down to:
"I am using this batch of paintbrushes as tools for stirring while I cook a meal. When using the pointed tip brush, should I, as a point of general cooking style, go with a coarse grained weave in the brush, or a fine grained one"? - That's a silly question. The proper question is: "What are proper cooking implements". If somehow brushes are all you have, worrying about making it look good is ridiculous.
Create both object type Fish and object type Shark in SwimmingInTheOcean. This is what I did.
It sounds like all the methods you are interested in are utility methods that do not read or otherwise affect any state except through the parameters you provide, and therefore, should be static, and once you've done that, this question has the obvious answer. Just invoke the methods you need, simple. No need to create any objects anymore.
Create only an object type Shark, because shark already contains all the functions of Fish. The reason why I did not pick this solution however, is because for most intents it looks very weird to use a Shark instead of a Fish. It would mislead someone reading the code in the future.
This is misleading. In java, there's the type of the object and the type of the reference which do not have to be the same thing. This is perfectly legal java code:
Fish fish = new Shark();
and very clearly communicates to any future readers that at the very least the API of the object is interesting solely for its fish-like properties; the fact that you picked a shark is presumably (as in, that's what a future reader would assume) relevant in the sense that the 'shark' implementation is the way you want the API to be implemented.
Here, for example, if you have 3 things you need done, and one of the 3 are things you can do with any fish (say, move them to the top of the aquarium so you can catch them with a net), whereas the other is 'found the fish friendly club' which is a thing only sharks can do, then you would make 2 methods. Your class is called SwimmingInTheOcean which is weird; normally, classes are named to match a tangible concept class, and 'swimmingInTheOcean' isn't it. Aquarium or Ocean, that makes sense as a name. You'd have:
class Ocean {
void simulateDay() {
Shark bruce = new Shark();
foundFishFriendlyClub(bruce);
chaseToTheNets(bruce);
}
void foundFishFriendlyClub(Shark leader) { ... }
void chaseToTheNets(Fish fish) { .... }
}
Here there is no chance that a reader is going to be confused and thinks that somehow chasing into the nets is a thing that applies only to sharks. After all, whilst you call chaseToTheNets with a shark, all sharks are fishes, and the chaseToTheNets method yells from the rooftops you can do that to any Fish.
It's more correct to put the chaseToTheNets method in the Ocean class instead of the Fish class, because it's an act that a fish itself cannot do (if there is a FleetOfTrawlers class, the chaseToTheNets method should be there instead of in Ocean).
It's possible this advice misses the mark because it doesn't apply to your situation. However, if that is the case, your chosen example situation (with nemo and fishes and sharks and oceans) isn't a good way to summarize your situation.
apologies if this is simple or has been answered before, I'm new to Java and in my research I can't find too much on this issue and have not yet found a solution.
I have an ArrayList with multiple classes that all share a common Interface, in this example the interface is called "Packable". I'm trying to create a method that takes a class parameter and sweeps through each element of this ArrayList, returning a new list containing all the items in the original list that are of the same class as the reference parameter.
This is my code so far, trying the instanceof method:
public List<Packable> getOfType(Packable reference){
List<Packable> typeOfItems = new ArrayList<>();
for (Packable item: itemsStored) {
if (item instanceof reference){
typeOfItems.add(item);
}
}
return typeOfItems;
}
This is throwing an error as it doesn't yet recognise reference as a class. This question mentions a method isAssignableFrom with the answer stating: "When using instanceof, you need to know the class of B at compile time. When using isAssignableFrom() it can be dynamic and change during runtime." (Thanks Marc Novakowski)
I understand that given the parameter the class isn't known at compilation and as such I've tried implementing isAssignableFrom and can't really seem to get it to work. The IDE doesn't really recognise or suggest it, and there isn't too much about the method online. I've tried implementing it the way the JavaDocs suggest but this isn't working either:
if (reference.isAssignableFrom(item.getClass())){
typeOfItems.add(item);
}
Any help or advice on methods to look into would be greatly appreciated. Thanks for reading the question, and again apologies if this is simple or has been answered elsewhere and I've just missed it. Thanks everyone
I'm not sure what Packable is, but you appear to be confused about a few concepts here.
In java, Packable reference does not represent the Packable concept. It represents a specific instance of Packable (or null).
In other words, given Dog dog, that means dog is some specific dog. Not 'the general concept of a dog'. We know that the specific animal that dog is referring to is, at least, a Dog. It could be Fifi, the neighbour's schnauzer.
instanceof, on the other hand, is about the general concept of things: if (fifi instanceof Dog) is how you're supposed to use it. You're more or less attempting to do the equivalent of if (fifi instanceof rover) which just doesn't make sense. How can one dog be 'an instance' of another? It's not that the answer is 'true' or 'false', but that the very question doesn't even make sense, which is why javac doesn't compile it. It has no idea what this even means.
Java, being java, makes objects of many things. Notably including the very notion of things. Thus, there is the class java.lang.Class, instances of which represent classes. A bit of alice-going-down-the-rabbit-hole thing is happening here: Classes as a concept are also represented as instances of the java.lang.Class class.
A class OBJECT (so, an instance of java.lang.Class) has the .isAssignableFrom method. This in fact takes another j.l.CLass as argument, it's for checking if one type is a subtype of another. In that sense, the question linked is needlessly confusing - you're really looking for the instanceOf method (there is an instanceof language construct, but the j.l.Class class has an isInstance method, which is unrelated, other than that they roughly accomplish the same goal: Check if some INSTANCE is of a type that is equal to, or a subtype of, some TYPE.
This is an example of how to use it:
Class<?> c = Number.class;
Object o = Integer.valueOf(5);
System.out.println(c.isInstance(o));
this is more or less equivalent to:
Object o = Integer.valueOf(5);
System.out.println(o instanceof Number);
Except now the Number part no longer needs to be written at 'write the code' time, you can supply it, say, read it from a parameter. You'd have to, of course, dynamically construct the Class instance. You can do so either by string-lookup, or by getting the actual type of an actual object. For example:
String input = scanner.next(); // user types in "java.lang.Number"
Class<?> c = Class.forName(input);
Object o = Integer.valueOf(5);
System.out.println(c.isInstance(o));
Or:
Object i = Integer.valueOf(5);
Object d = Double.valueOf(10);
Class<?> c = i.getClass(); // will be java.lang.Integer.class
System.out.println(c.isInstance(d)); // false
But doing this latter bit is really dangerous. Often i.getClass() returns some hidden impl detail subtype (java is hierarchical and object oriented, anywhere, say, an ArrayList is needed, someone is free to make a new class: class MyVariantOfArrayList extends ArrayList, and use that - now you write ArrayList foo = getList(), but foo.getClass() doesn't return ArrayList - no, you invoke that method on the object the foo variable points at, so, it'd be MyVariantOfArrayList.class, not ArrayList.class.
It's possible Packable itself represents a type. But then it either needs to also have isInstance and isAssignableFrom and such (and you need to start questioning why you're badly reinventing the wheel here - java.lang.Class already exists!), or it needs a .getRepresentedClass() method. You can't call it .getClass(), as the JVM has already given all objects that method, and it would return Packable.class itself.
This question already has answers here:
Abstract class in Java
(15 answers)
Closed 8 years ago.
I'm trying to understand this code example from O'Reilly's Programming Scala. I'm a JavaScript programmer and most of the explanations in the book assume a Java background. I'm looking for a simple, high-level explanation of abstract classes and what they're used for.
package shapes {
class Point(val x: Double, val y: Double) {
override def toString() = "Point(" + x + "," + y + ")"
}
abstract class Shape() {
def draw(): Unit
}
class Circle(val center: Point, val radius: Double) extends Shape {
def draw() = println("Circle.draw: " + this)
override def toString() = "Circle(" + center + "," + radius + ")"
}
}
Abstract as in without to many details. Its a formal way to say "we're being vague".
Saying, "I have a form of transportation that I take to work." is more abstract than, "I have a car that I take to work". Of course somewhere something knows exactly what you're taking to work. This is about not having to know exactly what, everywhere. This idea is called abstraction.
How it's used:
An abstract or parent class in most any OOP language is a place to centralize reusable generalized methods and provide the interface to more specified methods whose code resides on more concrete or child classes.
So if I provided an abstract class called Transportation with a takeMeToWork() method on it you could call takeMeToWork() on anything that inherited from Transportation and expect to end up at work. You wouldn't know if you were taking a Car or a Bicycle to work but you'd be going to work. Transportation would only promise that there will be a takeMeToWork() method. It wouldn't define how it works and in fact won't work until it is provided with a Car or Bicycle that does.
If you demand that every form of Transportation have the same cup holder for your drink you could put a useCupHolder() method in the Transportation class once and never have to write it again. It would always be there working exactly the same way. Depending on the language or version of the language that trick might not be available to an interface or "trait". Other than providing default implementation abstract classes aren't much different from traits. This question deals with those differences.
The problem with appreciating this metaphor is that it's hard to see the point until you're in a situation where it proves useful. Right now it probably sounds like a lot of fancy hard to understand stuff that will only make solving whatever problem harder. And that is actually true. Until you've found yourself working with code complicated enough to make use of this and mastered abstraction it really is only going to make things harder. Once you get it though it makes everything easier. Especially when you're not writing code alone. This next metaphor isn't a classic one but it is my favorite:
Why do we have hoods on cars?
(Or bonets for you non-americans)
The car runs fine without it. All the cool engine stuff is easier to get to without it. So what's it for? Without the hood I can sit on the engine block, jam a poll into the rack and pinon, grab the throttle, and drive the car. Now I can do really cool things like change the oil at 50 miles per hour.
We've discovered over the years that people really are more comfortable driving without a dip stick in their face. So we put the hood on the car and provided heated seats, steering wheels, and gas peddles. This makes us comfortable and prevents us from getting a pant leg caught in the fan belt.
In software we provide the same thing with abstraction. It comes in many forms, abstract classes, traits, facade patterns, etc. Even the humble method is a form of abstraction.
The more complex the problem you're solving the more you'll be better off using some wise abstractions. And, well your car looks cooler with the hood on it.
This particular example is not the best since Shape should probably be a trait, not an abstract class.
Inheritance does two separate but related things: it lets different values implement a common interface, and it lets different classes share implementation code.
Common Interface
Suppose we've got a drawing program that needs to do things with a bunch of different shapes - Square, Circle, EquilateralTriangle and so on. In the bad old days, we might do this with a bunch of if/else statements, something like:
def drawShapes(shapes: List[Shape]) =
for { shape <- shapes } {
if(isCircle(shape))
drawDot(shape.asInstanceOf[Circle].center)
...
else if(isSquare(shape))
drawStraghtLine(shape.asInstanceOf[Square].topLeft, shape.asInstanceOf[Square].topRight)
...
}
def calculateEmptySpace(shapes: List[Shape]) =
val shapeAreas = for { shape <- shapes } yield {
if(isCircle(shape)) (shape.asInstanceOf[Circle].radius ** 2) * Math.PI
else if(isSquare(shape)) ...
}
(in Scala we'd actually use a pattern match, but let's not worry about that for the moment)
This is a kind of repetitive pattern; it would be nice to isolate the repetitive "figure out the correct type of shape, then call the right method" logic. We could write this idea (a virtual function table) ourselves:
case class ShapeFunctions[T](draw: T => Unit, area: T => Double)
object ShapeFunctions {
val circleFunctions = new ShapeFunctions[Circle]({c: Circle => ...}, {c: Circle => ...})
val squareFunctions = new ShapeFunctions[Square](...)
def forShape(shape: Any) = if(isCircle(shape)) circleFunctions
else if(isSquare(shape)) squareFunctions
else ...
}
def drawShapes(shapes: List[Shape]) =
for {shape <- shapes}
ShapeFunctions.forShape(shape).draw(shape)
But this is actually so common an idea that it's built into the language. When we write something like
trait Shape {
def draw(): Unit
def area(): Double
}
class Circle extends Shape {
val center: (Double, Double)
val radius: Double
def draw() = {...}
def area() = {...}
}
"under the hood" this is doing something very similar; it's creating a special value Circle.class which contains this draw() and area() method. When you create an instance of Circle by val circle = new Circle(), as well as the ordinary fields center and radius, this Circle has a magic, hidden field circle.__type = Circle.class.
When you call shape.draw(), this is sort of equivalent to shape.__type.draw(shape) (not real syntax). Which is great, because it means that if shape is a Square, then the call will be Square.class.draw(shape) (again, not real syntax), but if it's a Circle then the call will be Circle.class.draw(shape). Notice how a class always gets called with a value of the correct type (it's impossible to call Square.class.draw(circle), because circle.draw() always goes to the correct implementation).
Now, lots of languages have something a bit like this without the trait part. For example, in Python, I can do:
class Square:
def draw(self): ...
class Circle:
def draw(self): ...
and when I call shape.draw(), it will call the right thing. But if I have some other class:
class Thursday: ...
then I can call new Thursday().draw(), and I'll get an error at runtime. Scala is a type-safe language (more or less): this method works fine:
def doSomething(s: Square): s.draw()
while this method won't compile:
def doSomething(t: Thursday): t.draw()
Scala's type system is very powerful and you can use it to prove all sorts of things about your code, but at a minimum, one of the nice things it guarantees is "you will never call a method that doesn't exist". But that presents a bit of a problem when we want to call our draw() method on an unknown type of shape. In some languages (e.g. I believe Ceylon) you can actually write a method like this (invalid Scala syntax):
def drawAll(shapes: List[Circle or Square or EquilateralTriangle]) = ...
But even that's not really what we want: if someone writes their own Star class, we'd like to be able to include that in the list we pass to drawAll, as long as it has a draw() method.
So that's where the trait comes in.
trait Shape {
def draw(): Unit
def area(): Double
}
class Circle extends Shape {...}
means roughly "I promise that Circle has a def draw(): Unit method. (Recall that this really means "I promise Circle.class contains a value draw: Circle => Unit). The compiler will enforce your promise, refusing to compile Circle if it doesn't implement the given methods. Then we can do:
def drawAll(shapes: List[Shape]) = ...
and the compiler requires that every shape in shapes is from a type with a def draw(): Unit method. So shape.__type.draw(shape) is "safe", and our method is guaranteed to only call methods that actually exist.
(In fact Scala also has a more powerful way of achieving the same effect, the typeclass pattern, but let's not worry about that for now.)
Sharing implementation
This is simpler, but also "messier" - it's a purely practical thing.
Suppose we have some common code that goes with an object's state. For example, we might have a bunch of different animals that can eat things:
class Horse {
private var stomachContent: Double = ...
def eat(food: Food) = {
//calorie calculation
stomachContent += calories
}
}
class Dog {
def eat(food: Food) = ...
}
Rather than writing the same code twice, we can put it in a trait:
trait HasStomach {
var stomachContent: Double
def eat(food: Food) = ...
}
class Horse extends HasStomach
class Dog extends HasStomach
Notice that this is the same thing we wrote in the previous case, and so we can also use it the same way:
def feed(allAnimals: List[HasStomach]) = for {animal <- allAnimals} ...
But hopefully you can see that our intent is different; we might do the same thing even if eat was an "internal" method that couldn't be called by any outside functions.
Some people have criticised "traditional" OO inheritance because it "mixes up" these two meanings. There's no way to say "I just want to share this code, I don't want to let other functions call it". These people tend to argue that sharing code should happen through composition: rather than saying that our Horse extends HasStomach, we should compose a Stomach into our Horse:
class Stomach {
val content: Double = ...
def eat(food: Food) = ...
}
class Horse {
val stomach: Stomach
def eat(food: Food) = stomach.eat(food)
}
There is some truth to this view, but in practice (in my experience) it tends to result in longer code than the "traditional OO" approach, particularly when you want to make two different types for a large, complex object with some small, minor difference between the two types.
Abstract Classes versus Traits
So far everything I've said applies equally to traits and abstract classes (and to a certain extent also to classes, but let's not go into that).
For many cases, both a trait and an abstract class will work, and some people advise using the difference to declare intent: if you want to implement a common interface, use a trait, and if you want to share implementation code, use an abstract class. But in my opinion the most important difference is about constructors and multiple inheritance.
Scala allows multiple inheritance; a class may extend several parents:
class Horse extends HasStomach, HasLegs, ...
This is useful for obvious reasons, but can have problems in diamond inheritance cases, particularly when you have methods that call a superclass method. See Python's Super Considered Harmful for some of the problems that arise in Python, and note that in practice, most of the problems happen with constructors, because these are the methods that usually want to call a superclass method.
Scala has an elegant solution for this: abstract classes may have constructors, but traits may not. A class may inherit from any number of traits, but an abstract class must be the first parent. This means that any class has exactly one parent with a constructor, so it's always obvious which method is the "superclass constructor".
So in practical code, my advice is to always use traits where possible, and only use abstract class for something that needs to have a constructor.
An abstract class simply provides a defined interface, a number of methods. Any subclass of the abstract class can be thought of as a specific implementation or refinement of that class.
That allows you to define a method that takes a Shape argument, and the body of the method may then use that interface, e.g. call the shape's draw method, irrespective of the type of shape that was given to it.
In terms of the type system, asking for a Shape ensures statically (at compile time) that you can only pass an object that satisfies the Shape interface, so it is guaranteed to contain the draw method.
Personally, I prefer to use traits instead of abstract classes, the latter has bit of Java smell for me in Scala. The difference is that an abstract class may have constructor arguments. A concrete implementing class, on the other hand, is free to implement more than one trait, whereas it can only extend a single class (abstract or not).
I'm having a problem with casting Classes to each other.
To explain it in more detail, take a look at this image.
In my code, I do SkillBase s = new SkillBase(); and then set some values in that class.
Then I try to do Subclass sub = (Subclass)s; but when running it it gives a ClassCastException.
I added a small debug part, which checks if it's instanceof which returns true.
I've tried the google, saw some questions on here aswell and read them (none of them had an answer that was for me)
So, what do I do?
SkillBase is not an instance of Subclass, so why do you think casting will work? Try with this:
SkillBase s = new Subclass();
Subclass sub = (Subclass)s;
which will succeed. Also I think you are not correct with instanceof, I am certain that:
s instanceof Subclass
yields true in the the code above but false in your case.
Thinking in real world terms: you can always cast Dog to Animal because every dog is an animal*, but casting Animal to Dog might fail since some animals aren't dogs.
* in fact, compiler does that for you, it is known as polymorphism
You can only up-cast i.e. assign sub classes to super class references. Think of it this way: Subclass extends the Superclass by adding a new method f(). Now Superclass doesn't know any thing about f() and hence the problem.
You're probably using instanceof wrong.
The runtime is right to crash, as SkillBase is not a Subclass.
The other way around is true.
s can't be cast to Subclass because it wasn't instantiated as a Subclass. It is a Skillbase. If you want to use a Subclass why not just instantiate it?
Subclass s = new Subclass();
You can still set the parameters you want because they hare inherited by Skillbase and the cast is no longer necessary.
The problem is that you are not using casting properly. A class can always be cast as its parent, but not the other way around. The concept is that a child class (by definition) knows the structure of the parent, and (by definition) already supports all the signatures in the parent. Consequently, the parent is a subset of the child.
The inverse, however, is not true. The parent class knows nothing about the child class and/or whether the child has added extra signatures to its structure. Consequently, there is no way to tell the compiler to treat the parent as a child and make available all the methods that the child has in the parent.
It layman speak, water (child) is a liquid (parent), but not all liquids are water. Consequently, any measurements you want to make on liquids (ie: quantity, viscosity, etc) hold true for water as well, but not the other way around (ex: density of water is completely different than density of oil).
So to bring this all back to your situation, you can cast Subclass as a Skillbase but not the other way around.
Subclass instanceof Skillbase == true
(Skillbase) new Subclass() - also valid
(SKillbase) new Sub#2 - also valid
etc...
A friend and I are studying Java. We were looking at interfaces today and we got into a bit of an discussion about how interfaces are used.
The example code my friend showed me contained this:
IVehicle modeOfTransport1 = new Car();
IVehicle modeOfTransport2 = new Bike();
Where IVehicle is an interface that's implemented in both the car and bike classes.
When defining a method that accepts IVehicle as a parameter you can use the interface methods, and when you run the code the above objects work as normal. However, this works perfectly fine when declaring the car and bike as you normally would like this:
Car modeOfTransport1 = new Car();
Bike modeOfTransport2 = new Bike();
So, my question is - why would you use the former method over the latter when declaring and instantiating the modeOfTransport objects? Does it matter?
There is a big plus on declaring them using the interface, which is what is known as "coding to an interface" instead of "coding to an implementation" which is a big Object Oriented Design (OOD) principle, this way you can declare a method like this:
public void (IVehicle myVehicle)
and this will accept any object that implements that interface, then at runtime it will call the implementation like this:
public void (IVehicle myVehicle)
{
myVehicle.run() //This calls the implementation for that particular vehicle.
}
To answer the original question, why would you use one over the other there are several reasons:
1) Declaring them using an interface, means you can later substitute that value with any other concrete class that implements that interface, instead of being locked into that particular concrete class
2) You can take full advantage of polymorphism by declaring them using an interface, because each implementation can call the correct method at runtime.
3) You follow the OOD principle of code to an interface
It doesn't matter there.
Where it really matters is in other interfaces that need to operate on IVehicle. If they accept parameters and return values as IVehicle, then the code will be more easily extendible.
As you noted, either of these objects can be passed to a method that accepts IVehicle as a parameter.
If you had subsequent code that used Car or Bike specific operations that were used, then it would be advantageous to declare them as Car or Bike. The Car and Bike specific operations would be available for each of the relevant objects, and both would be usable (i.e. could be passed) as IVehicle.
You're really asking: what reference type should I use?
Generally you want to use as general a reference type as possible that still gives you access to the behavior that you need. This means any of the interfaces or parent classes of your concrete type, rather than the concrete type itself. Of course, don't take this point too far -- for example, you certainly don't want to declare everything as an Object!
Consider these options:
Set<String> values1 = new TreeSet<String>();
TreeSet<String> values2 = new TreeSet<String>();
SortedSet<String> values3 = new TreeSet<String>();
All three are valid, but generally the first option of values1 is better because you will only be able to access the behavior of the Set interface, so later you can swap in another implementation quite easily:
Set<String> values1 = new HashSet<String>();
Beware of using the second option values2. It allows you to use specific behavior of the TreeSet implementation in such a way that swapping in a different implementation of Set becomes more difficult. This is fine as long as that's your goal. So, in your example, use a Car or Bike reference only when you need access to something that's not in the IVehicle interface. Be aware though that the following would not work:
TreeSet<String> values2 = new HashSet<String>(); // does not compile!
Still there are times when you need access to the methods that are not in the most general type. This is illustrated in the third option values3 -- the reference is more specific than Set, which allows you to rely on the behavior of SortedSet later.
TreeSet<String> values3 = new ConcurrentSkipListSet<String>();
The question about reference types applies not only where variables are declared, but also in methods where you have to specify the type of each parameter. Fortunately the "use as general a reference type as possible" rule of thumb applies to method parameters, too.
Program to an interface rather than an implementation.
When you program to an interface you will write code that can handle any kind of Vehicle. So in the future your code, without modification, should work with Trains and Planes.
If you ignore the interface then you are stuck with CArs and Bikes, and any new Vehicles will require additional code modifications.
The principle behind this is:
Open to Extension, Closed to Modification.
Because you don't really care what the implementation is... only what it's behavior is.
Say you have an animal
interface Animal {
String speak();
}
class Cat implements Animal {
void claw(Furniture f) { /* code here */ }
public String speak() { return "Meow!" }
}
class Dog implements Animal {
void water(FireHydrant fh) { /* code here */ }
public String speak() { return "Woof!"; }
}
Now you want to give your kid a pet.
Animal pet = new ...?
kid.give(pet);
And you get it back later
Animal pet = kid.getAnimal();
You wouldn't want to go
pet.claw(favorateChair);
Because you don't know if the kid had a dog or not. And you don't care. You only know that --Animals-- are allowed to speak. You know nothing about their interactions with furniture or fire hydrants. You know animals are for speaking. And it makes your daughter giggle (or not!)
kid.react(pet.speak());
With this, when you make a goldfish, the kid's reaction is pretty lame (turns out goldfishes don't speak!) But when you put in a bear, the reaction is pretty scary!
And you couldn't do this if you said
Cat cat = new Cat();
because you're limiting yourself to the abilities of a Cat.
Honestly your argument is rather moot. What's happening here is an implicit conversion to an IVehicle. You and your friend seem to be arguing about whether it's better to do it immediately (as per the first code listing), or later on (when you call the method, as per the second code listing). Either way, it's going to be implicitly converted to an IVehicle, so the real question is -- do you need to deal with a Car, or just a Vehicle? If all you need is an IVehicle, the first way is perfectly fine (and preferable if at a later point you want to transparently swap out a car for a bike). If you need to treat it like a car at other points in your code, then just leave it as a car.
Declaring interfaces and instantiating them with objects allows for a powerful concept called polymorphism.
List<IVehicle> list = new ArrayList<IVehicle>();
list.add(new Car());
list.add(new Bike());
for (int i = 0; i < list.size(); ++i)
list.get(i).doSomeVehicleAction(); // declared in IVehicle and implemented differently in Car and Bike
To explicitly answer the question: You would use an interface declaration (even when you know the concrete type) so that you can pass multiple types (that implement the same interface) to a method or collection; then the behavior common to each implementing type can be invoked no matter what the actual type is.
well interfaces are behaviors and classes are their implementation so there will be several occasions later when you will program where you will only know the behaviors(interface). and to make use of it you will implement them to get benefit out of it. it is basically used to hiding implementation details from user by only telling them the behavior(interface).
Your intuition is correct; the type of a variable should be as specific as possible.
This is unlike method return types and parameter types; there API designers want to be a little abstract so the API can be more flexible.
Variables are not part of APIs. They are implementation details. Abstraction usually doesn't apply.
Even in 2022, it's confusing to understand the true purpose of an interface even to a trained eye who didn't start his/her career in java.
After reading a lot of answers in various online posts, I think that an interface is just a way to not care about the implementation details of a certain activity which is being passed down to a common goal (a certain method). To make it easy, a method doesn't really care how you implement your operations but only cares about what you pass down to it.
The OP is correct in a way to ask why we couldn't just reference to the type of the concrete class than to use an interface. But, we cannot think or understand the use case of an interface in a isolated pov.
Most explanation won't justify it's use unless you look at how classes like ArrayList and LinkedList are derived. Here is my simple explanation.
Class CustomerDelivery {
line 2 -> public void deliverMeMyIphone( DeliveryRoutes x //I don't care how you deliver it){
//Just deliver to my home address.
}
line 3 -> DeliveryRoutes a = new AmazonDelivery();
DeliveryRoutes b = new EbayDelivery();
//sending IPhone using Amazon Delivery. Final act.
deliverMeMyIphone(a.route());
//sending IPhone using eBay Delivery. Final act
deliverMeMyIphone(b.route());
}
Interface DeliveryRoutes {
void route(); // I dont care what route you take, and also the method which takes me as an argument won't care and that's the contract.
}
Class AmazonDelivery implements DeliveryRoutes {
#overide route() {
// Amazon guy takes a different route
}
}
Class EbayDelivery implements DeliveryRoutes {
#overide route() {
// ebay guy takes a different route
}
}
From the above example In line 2, just imagine to yourself what would happen if you cast the type of value x to a concrete class like AmazonDelivery and not the interface DeliveryRoutes type? or what would happen in line 3 if you change the type from the interface to AmazonDelivery type? It would be a mess. Why? because the method deliverMeMyIphone will be forced to work with only one type of delivery i.e AmazonDelivery and won't accept anything else.
Most answers confuse us with by saying Interfaces helps in multiple inheritance which is true, don't get me wrong, but it's not the only story.
With "IVehicle modeOfTransport1 = new Car();", methods owned only by Car are not accessible to modeOfTransport1. I don't know the reason anyway.