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.
Related
This question already has answers here:
Dynamic dispatch and binding
(2 answers)
Closed 2 years ago.
Im confused, when i use getClass( ) from a superclass reference variable that's pointing to a subclass object, the result is the subclass.
Heres a simple example:
public `class` TestGetClass
{
public static void main(String[] args)
{
Object obj = new Integer(20);
System.out.println("obj class: " + obj.getClass());
}
}
The output gives me the Integer class instead of the Object class.
obj class: class java.lang.Integer
Can someone explain please
What you're looking for is simply:
Object.class.
obj.getClass() in java could plausibly be interpreted in two different ways:
It means: Take the expression 'obj', which is a reference (i.e., a pointer). Follow the pointer and find the object it is pointing at. Ask that object what its type is.
just like 1, except, because the variable type was Object, invoke the implementation of the getClass() method from the java.lang.Object class. i.e., no dynamic dispatch.
It means: Take the locally declared variable named obj. What type did I declare it as, right here in this method? Don't care about the object/pointer at all, just the declaration.
Now, the java lang spec is crystal clear: In java, #1 is what happens. #2 is not available (you can't opt out of dynamic dispatch. As a matter of obvious language design, private methods don't do it because they don't need it, and static methods don't do it because, by being static, they just aren't a part of the hierarchy in the first place - so those seeming exceptions really don't apply. There is no other way to opt out).
Here's the thing about option #2 though: is completely pointless.
In java, you can't have mystery meat variables. Somebody declares them, and the type is written right there in the source file. There is no such thing as 'eh, figure it all out at runtime'. Even java10's var doesn't work that way (it's still locked in, for sure, at compile time).
So, you already know. It is object, what point is there to repeat it?
If you want a java.lang.Class<?> instance that represents Object, there's syntax for this. it is:
Class<?> objClass = Object.class;
In java, can we pass superclass Object to subclass reference ?
I know that it is a weird question/practically not viable,
but I want to understand the logic behind this
Why is it not allowed in java.
class Employee {
public void met1(){
System.out.println("met1");
}
}
class SalesPerson extends Employee
{
#Override
public void met1(){
System.out.println("new met1");
}
public void met2(){
System.out.println("met2");
}
}
public class ReferenceTest {
public static void main(String[] args) {
SalesPerson sales = new Employee(); // line 1
sales.met1(); // line 2
sales.met2(); // line 3
}
}
What would have happened if Java allowed compilation of line 1?
Where would the problem arise?
Any inputs/link are welcomes.
If your SalesPerson sales = new Employee(); statement was allowed to compile, this would have broken the principles of Polymorphism, which is one of the features that the language has.
Also, you should get familiar with that does compile time type and runtime type mean:
The compile-time type of a variable is the type it is declared as, while the runtime type is the type of the actual object the variable points to. For example:
Employee sales = new SalesPerson();
The compile-time type of sales is Employee, and the runtime type will be SalesPerson.
The compile-time type defines which methods can be called, while the runtime type defines what happens during the actual call.
Let's suppose for a moment that this statement was valid:
SalesPerson sales = new Employee();
As I said, the compile-time type defines which methods can be called, so met2() would have been eligible for calling. Meanwhile, the Employee class doesn't have a met2() and so the actual call would have been impossible.
No. It makes zero sense to allow that.
The reason is because subclasses generally define additional behavior. If you could assign a superclass object to a subclass reference, you would run into problems at runtime when you try to access class members that don't actually exist.
For example, if this were allowed:
String s = new Object();
You would run into some pretty bad problems. What happens if you try to call a String method? Would the runtime crash? Or perhaps a no-op would be performed? Should this even compile?
If the runtime were to crash, you could use runtime checks to make sure the objects you receive will actually contain the methods you want. But then you're basically implementing guarantees that the Java type system already provides at compile-time. So really that "feature" cost you nothing but a bunch of type-checking code that you shouldn't have had to write in the first place.
If no-ops were executed instead of nonexistent methods, it would be extremely difficult to ensure that your programs would run as written when the members you want to access don't exist, as any reference could really be an Object at any point. This might be easy to handle when you are working on your own and control all your code, but when you have to deal with other code those guarantees essentially vanish.
If you want the compiler to do the checking, assuming compiler writers don't hunt you down and give you a stern talking-to -- well, you're back to "normal" behavior once more. So again, it's just a lot of work for zero benefit.
Long story short: No, it's not allowed, because it makes zero sense to do so, and if a language designer tried to allow that they would be locked up before they could do any more harm.
If you inherit from a class, you always specialize the common behavior of the super class.
In your example, the SalesPerson is a special Employee. It inherits all behavior from the super class and can override behavior to make it different or add new behavior.
If you, as it is allowed, initialize a variable of the super type with an instance of the sub type like Employee e = new SalesPerson(), then you can use all common behavior on that variable.
If instead, you were possible to do the other way round, there might be several uninitialized members in the class.
You find this very often when using the Java Collection API, where for example you can use the common List class on operations like iterating through it, but when initializing it, you use for example the sub class ArrayList.
I know this question has been asked a lot, but the usual answers are far from satisfying in my view.
given the following class hierarchy:
class SuperClass{}
class SubClass extends SuperClass{}
why does people use this pattern to instantiate SubClass:
SuperClass instance = new SubClass();
instead of this one:
SubClass instance = new SubClass();
Now, the usual answer I see is that this is in order to send instance as an argument to a method that requires an instance of SuperClass like here:
void aFunction(SuperClass param){}
//somewhere else in the code...
...
aFunction(instance);
...
But I can send an instance of SubClass to aFunction regardless of the type of variable that held it! meaning the following code will compile and run with no errors (assuming the previously provided definition of aFunction):
SubClass instance = new SubClass();
aFunction(instance);
In fact, AFAIK variable types are meaningless at runtime. They are used only by the compiler!
Another possible reason to define a variable as SuperClass would be if it had several different subclasses and the variable is supposed to switch it's reference to several of them at runtime, but I for example only saw this happen in class (not super, not sub. just class). Definitly not sufficient to require a general pattern...
The main argument for this type of coding is because of the Liskov Substituion Principle, which states that if X is a subtype of type T, then any instance of T should be able to be swapped out with X.
The advantage of this is simple. Let's say we've got a program that has a properties file, that looks like this:
mode="Run"
And your program looks like this:
public void Program
{
public Mode mode;
public static void main(String[] args)
{
mode = Config.getMode();
mode.run();
}
}
So briefly, this program is going to use the config file to define the mode this program is going to boot up in. In the Config class, getMode() might look like this:
public Mode getMode()
{
String type = getProperty("mode"); // Now equals "Run" in our example.
switch(type)
{
case "Run": return new RunMode();
case "Halt": return new HaltMode();
}
}
Why this wouldn't work otherwise
Now, because you have a reference of type Mode, you can completely change the functionality of your program with simply changing the value of the mode property. If you had public RunMode mode, you would not be able to use this type of functionality.
Why this is a good thing
This pattern has caught on so well because it opens programs up for extensibility. It means that this type of desirable functionality is possible with the smallest amount of changes, should the author desire to implement this kind of functionality. And I mean, come on. You change one word in a config file and completely alter the program flow, without editing a single line of code. That is desirable.
In many cases it doesn't really matter but is considered good style.
You limit the information provided to users of the reference to what is nessary, i.e. that it is an instance of type SuperClass. It doesn't (and shouldn't) matter whether the variable references an object of type SuperClass or SubClass.
Update:
This also is true for local variables that are never used as a parameter etc.
As I said, it often doesn't matter but is considered good style because you might later change the variable to hold a parameter or another sub type of the super type. In that case, if you used the sub type first, your further code (in that single scope, e.g. method) might accidentially rely on the API of one specific sub type and changing the variable to hold another type might break your code.
I'll expand on Chris' example:
Consider you have the following:
RunMode mode = new RunMode();
...
You might now rely on the fact that mode is a RunMode.
However, later you might want to change that line to:
RunMode mode = Config.getMode(); //breaks
Oops, that doesn't compile. Ok, let's change that.
Mode mode = Config.getMode();
That line would compile now, but your further code might break, because you accidentially relied to mode being an instance of RunMode. Note that it might compile but could break at runtime or screw your logic.
SuperClass instance = new SubClass1()
after some lines, you may do instance = new SubClass2();
But if you write, SubClass1 instance = new SubClass1();
after some lines, you can't do instance = new SubClass2()
It is called polymorphis and it is superclass reference to a subclass object.
In fact, AFAIK variable types are meaningless at runtime. They are used
only by the compiler!
Not sure where you read this from. At compile time compiler only know the class of the reference type(so super class in case of polymorphism as you have stated). At runtime java knows the actual type of Object(.getClass()). At compile time java compiler only checks if the invoked method definition is in the class of reference type. Which method to invoke(function overloading) is determined at runtime based on the actual type of the object.
Why polymorphism?
Well google to find more but here is an example. You have a common method draw(Shape s). Now shape can be a Rectangle, a Circle any CustomShape. If you dont use Shape reference in draw() method you will have to create different methods for each type of(subclasses) of shape.
This is from a design point of view, you will have one super class and there can be multiple subclasses where in you want to extend the functionality.
An implementer who will have to write a subclass need only to focus on which methods to override
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.