I have class Employee, and two derived classes Hourly and Salary. Instantiations of those derived classes are placed in the same Array List called employeeList. When I read these objects from file using ois.readObject() how can I ensure the data ends up in the appropriate derived class? Thank you!
Note: I am not familiar with ObjectInputStream, so I am not exactly sure if this dynamic dispatch would work here, but I recommend giving this a try:
You could have your employee interface look like this:
interface Employee {
// Whatever other methods you have defined
void populateFieldsFromObject(Object obj);
}
Then each subclass would implement this method differently:
class HourlyEmployee implements Employee {
// Other methods/fields...
#override
void populateFieldsFromObject(Object obj) {
if (!(obj instanceof HourlyEmployee)) {
throw new IllegalArugmentException("Object not of correct type");
}
HourlyEmployee objEmp = (HourlyEmployee)Object;
this.hourly = objEmp.hourly;
}
}
class SalaryEmployee implements Employee {
// Other methods/fields...
#override
void populateFieldsFromObject(Object obj) {
if (!(obj instanceof SalaryEmployee)) {
throw new IllegalArugmentException("Object not of correct type");
}
SalaryEmployee objEmp = (SalaryEmployee)Object;
this.salary = objEmp.salary;
}
}
Then you can just iterate through your List of employees, and call:
employee.populateFieldsFromObject(ois.readObject());, as Dynamic Dispatch should automatically determine which method to call based on the type of the object.
Let me know if this works.
I assume they are extensions of the Employee class ? If you have an array like this:
List<Employee> emps = ...
then you can do something like:
for (Employee e : emps) { if (e instanceof Hourly) ... }
You still need to check the elements. You can also use filter them like this:
emps.stream().filter(e -> e instanceof Hourly).collect(Collectors.toList())
Related
I have two ArrayLists - ArrayList1 and ArrayList2. Each of them is filled with objects - Object1 and Object2, respectively.
Both of these objects have method 'getText'.
Object1:
public String getText() { return "1";}
Object2:
public String getText() { return "2";}
At certain point I would like to loop through each of these lists using the same method (just with different parameter).
loopThroughList(1)
loopThroughList(2)
What is the syntax if I want to call a method, but I don't know which object it is going to be? This is the code I have so far:
for (Object o : lists.getList(listNumber)) {
System.out.println(o.getText());
}
It says Cannot resolve method getText. I googled around and found another solution:
for (Object o : lists.getList(listNumber)) {
System.out.println(o.getClass().getMethod("getText"));
}
But this gives me NoSuchMethodException error. Even though the 'getText' method is public.
EDIT: To get the correct list, I am calling the method 'getList' of a different object (lists) that returns either ArrayList1 or ArrayList2 (depending on the provided parameter).
class Lists
public getList(list) {
if (list == 1) {
return ArrayList1;
}
else if (list == 2) {
return ArrayList2;
}
}
Define an interface for the getText method
public interface YourInterface {
String getText();
}
Implement the interface on the respective classes
public class Object1 implements YourInterface {
#Override
public String getText() {
return "1";
}
}
public class Object2 implements YourInterface {
#Override
public String getText() {
return "2";
}
}
Modify your getList method to return List<YourInterface>
public static List<YourInterface> getList(int list){
List<YourInterface> result = new ArrayList<>();
if(list == 1){
// your initial type
List<Object1> firstList = new ArrayList<>();
result.addAll(firstList);
} else {
// your initial type
List<Object2> secondList = new ArrayList<>();
result.addAll(secondList);
}
return result;
}
Declaration for loopThroughList
public static void loopThroughList(List<YourInterface> list){
list.forEach(yourInterface -> System.out.println(yourInterface.getText()));
}
Sample usage.
public static void main(String[] args) {
loopThroughList(getList(1));
loopThroughList(getList(2));
}
Interfaces work great here, but there a couple of other options if you're dealing with legacy code and cannot use interfaces.
First would be to cast the list items into their respective types:
for (Object o : lists.getList(listNumber)) {
if(o instanceof Object1) {
Object1 o1 = (Object1)o;
System.out.println(o1.getText());
}
else if(o instanceof Object2) {
Object1 o2 = (Object2)o;
System.out.println(o2.getText());
}
else {
System.out.println("Unknown class");
}
}
You can also use reflection to see if the object has a getText method and then invoke it:
for (Object o : lists.getList(listNumber)) {
try {
System.out.println(o.getClass().getDeclaredMethod("getName").invoke(o));
}
catch(Exception e) {
System.out.println("Object doesn't have getText method");
}
}
This is awful. Can you elaborate on what specifically you are trying to do? Java is strong typed by design, and you are trying to get around it. Why? Instead of Object, use the specific class, or interface as previously suggested. If that's not possible, and you must use lists of Objects, use instanceof and casting eg:
for (Object o : lists.getList(listNumber)) {
if (o instanceof Object1) {
Object1 o1 = (Object1) o;
System.out.println(o1.getText());
} else if (o instanceof Object2) {
Object2 o2 = (Object2) o;
System.out.println(o2.getText());
}
}
This is where interfaces come in.
interface HasText {
public String getText();
}
class Object1 implements HasText {
#Override
public String getText() {
return "1";
}
}
class Object2 implements HasText {
#Override
public String getText() {
return "2";
}
}
private void test() {
List<HasText> list = Arrays.asList(new Object1(), new Object2());
for (HasText ht : list) {
System.out.println(ht);
}
}
If one of your objects is not in your control you can use a Wrapper class.
class Object3DoesNotImplementHasText {
public String getText() {
return "3";
}
}
class Object3Wrapper implements HasText{
final Object3DoesNotImplementHasText it;
public Object3Wrapper(Object3DoesNotImplementHasText it) {
this.it = it;
}
#Override
public String getText() {
return it.getText();
}
}
private void test() {
List<HasText> list = Arrays.asList(new Object1(), new Object2(), new Object3Wrapper(new Object3DoesNotImplementHasText()));
for (HasText ht : list) {
System.out.println(ht);
}
}
Just to add more to this answer and give you some more to think on this (Will try to do it in a simple, non-formal way). Using interfaces is the proper way of doing such operation. However, I want to stand on the "bad idea":
for (Object o : lists.getList(listNumber)) {
System.out.println(o.getClass().getMethod("getText"));
}
What you are doing here, is using a mechanism called Reflection:
Reflection is a feature in the Java programming language. It allows an
executing Java program to examine or "introspect" upon itself, and
manipulate internal properties of the program. For example, it's
possible for a Java class to obtain the names of all its members and
display them.
What you actually attempted, is using that mechanism, to retrieve the method through a Class reflection object instance of your Class (sounds weird, isn't it?).
From that perspective, you need to think that, if you want to invoke your method, you now have, in a sense, a meta-Class instance to manipulate your objects. Think of it like an Object that is one step above your Objects (Similarly to a dream inside a dream, in Inception). In that sense, you need to retrieve the method, and then invoke it in a different (meta-like) way:
java.lang.reflect.Method m = o.getClass().getMethod("getText");
m.invoke(o);
Using that logic, you could possibly iterate through the object list, check if method exists, then invoke your method.
This is though a bad, BAD idea.
Why? Well, the answer relies on reflection itself: reflection is directly associated with runtime - i.e. when the program executes, practically doing all things at runtime, bypassing the compilation world.
In other words, by doing this, you are bypassing the compilation error mechanism of Java, allowing such errors happen in runtime. This can lead to unstable behavior of the program while executing - apart from the performance overhead using Reflection, which will not analyze here.
Side note: While using reflection will require the usage of Checked Exception handling, it still is not a good idea of doing this - as you practically try to duck tape a bad solution.
On the other hand, you can follow the Inheritance mechanism of Java through Classes and Interfaces - define an interface with your method (let's call it Textable), make sure that your classes implement it, and then use it as your base object in your list declaration (#alexrolea has implemented this in his answer, as also #OldCurmudgeon has).
This way, your program will still make the method call decision making at Runtime (via a mechanism called late binding), but you will not bypass the compilation error mechanism of Java. Think about it: what would happen if you define a Textable implementation without providing the class - a compile error! And what if you set a non-Textable object into the list of Textables? Guess what! A compile error again. And the list goes on....
In general, avoid using Reflection when you are able to do so. Reflection is useful in some cases that you need to handle your program in such a meta-way and there is no other way of making such things. This is not the case though.
UPDATE: As suggested by some answers, you can use instanceof to check if you have a specific Class object instance that contains your method, then invoke respectively. While this seems a simple solution, it is bad in terms of scaling: what if you have 1000 different classes that implement the same method you want to call?
your objects have to implement a common interface.
interface GetTextable {
String getText();
}
class One implements GetTextable {
private final String text;
public One(final String text) {
this.text = text;
}
public String getText() {
return this.text;
}
}
class Two implements GetTextable {
private final String text;
public Two(final String text) {
this.text = text;
}
public String getText() {
return this.text;
}
}
#Test
public void shouldIterate() throws Exception {
List<GetTextable> toIterate = Arrays.asList(new One("oneText"), new Two("twoText"));
for(GetTextable obj: toIterate) {
System.out.println(obj.getText());
}
}
I'd like to have a for each loop to loop through an array of objects.. but only the objects that are an instance of a specific class. To be more clear of what I mean, I've included the example below...
//Declare a list of employee objects
List<Employee> employees = new ArrayList<Employees>;
//Create some employees...
Employee employee = new Employee();
//The class EmployeeExtender extends and is a child of Employee
EmployeeExtender employeeExtended = new EmployeeExtender();
//Now add all the employees, even the ones of different instances to the list
employees.add(employee);
employees.add(employeeExtended);
Now I would like to introduce a for each loop that loops through the employees list that only loops through employees that are an instance of EmployeeExtender. I could just loop through each one and use an if statement (as shown below) but I would like to know if there was a way without making a seperate list to do this.
//I would like to only loop through employees that are an instance of EmployeeExtender
for(Employee employee : employees){
//I would like to not have this if statement...
if(employee instanceof EmployeeExtender){
//do logic...
}
}
Are my only options creating separate lists, or using the if statement? I'd like to know if there are more options. Thanks.
One option that hasn't been considered is to dispatch the logic to an empty method, that's overridden in the subclass you're interested in. I don't think I'd recommend doing it this way, but you did ask for options other than the straightforward for-each / instanceof way of doing it.
public class Employee {
public void doTheLogic(TheClassYoureCallingFrom caller) {
}
}
public class EmployeeExtended extends Employee {
#Override
public void doTheLogic(TheClassYoureCallingFrom caller) {
// The actual logic goes here.
}
}
public class TheClassYoureCallingFrom {
List<Employee> employees = new ArrayList<Employees>;
public void theMethodYoureCallingFrom() {
for (Employee employee : employees) {
employee.doTheLogic(this);
}
}
}
Of course, if you're not using any of the methods of the calling class, there's no need to pass it as a parameter.
You could use Streams:
employees.stream()
.filter(employee -> employee instanceof EmployeeExtender)
.forEach(employee -> {
//do logic
});
I've been thinking about implementing a certain tactic for my code.
This is my setup:
I've got an interface called "Object".
Then I've got an interface called "Entity" that extends "Object".
From entity then springs countless implementations, like "army", "city", "lemon", etc.
Now, I want to gather all of these Objects into some form of map. Then from that map I want to get the particular implementation of "Object".
My thought out solution for this is as follows:
Object has method :
public Entity getEntity()
All implementations of Object returns null, while Entity returns itself.
Likewise, in entity I'd have:
public Army getArmy()
public City getCity()
That way, I can simply pull an object from the map and get the specific class from it with a series of null checks, like so;
Object o = Objects.getObject(2dCoordinates);
Entity e = o.getEntity();
if (e != null){
Army a = e.getArmy();
if (a != null)
a.armySpecificMethod();
}
All without using "instanceof" and casting, which I hate.
The question is whether there's some unforeseen problem about this? I'd rather learn from someone that knows before refactoring my code and find out for myself.
You asked if there are any pitfalls to your strategy. I would say no, since C# uses the same strategy with their as keyword. Example: e as Army would return e if e is-a Army, or null otherwise. It is basicly a cast that instead of failing returns null.
However you don't have to implement this functionality using interfaces, you can write your own as method for example like this:
static <T> T as(Class<T> clazz, Object obj) {
if (clazz.isInstance(obj)) {
return (T) obj;
}
return null;
}
usage:
Object o = Objects.getObject(2dCoordinates);
Entity e = as(Entity.class, o);
if (e != null) {
Army a = as(Army.class, e);
if (a != null)
a.armySpecificMethod();
}
Another approach would be to register callbacks/strategies to be invoked on particular events. Something like that:
public interface OnMapClicked<T> {
void onItemSelected(T item);
}
And your GameMap (or whatever) implementation would be:
public GameMap {
private final Map<Class<?>, OnMapClicked> listeners = new HashMap<>();
public <T> void registerListener(Class<? extends T> type, OnMapClicked<T> listener) {
listeners.put(type, listener);
}
//
private void onMapClicked(Coordinates coordinates) {
Object object = findObject(coordinates);
listeners.get(object.getClass()).onItemSelected(object);
}
}
That's very rough untested implementation, but hopefully you got the idea. There is one usage of non-generic instance here (in onMapClicked), but it should be safe, since we're checking the input type in registerListener.
With the introduction of generics, I am reluctant to perform instanceof or casting as much as possible. But I don't see a way around it in this scenario:
for (CacheableObject<ICacheable> cacheableObject : cacheableObjects) {
ICacheable iCacheable = cacheableObject.getObject();
if (iCacheable instanceof MyObject) {
MyObject myObject = (MyObject) iCacheable;
myObjects.put(myObject.getKey(), myObject);
} else if (iCacheable instanceof OtherObject) {
OtherObject otherObject = (OtherObject) iCacheable;
otherObjects.put(otherObject.getKey(), otherObject);
}
}
In the above code, I know that my ICacheables should only ever be instances of MyObject, or OtherObject, and depending on this I want to put them into 2 separate maps and then perform some processing further down.
I'd be interested if there is another way to do this without my instanceof check.
Thanks
You could use double invocation. No promises it's a better solution, but it's an alternative.
Code Example
import java.util.HashMap;
public class Example {
public static void main(String[] argv) {
Example ex = new Example();
ICacheable[] cacheableObjects = new ICacheable[]{new MyObject(), new OtherObject()};
for (ICacheable iCacheable : cacheableObjects) {
// depending on whether the object is a MyObject or an OtherObject,
// the .put(Example) method will double dispatch to either
// the put(MyObject) or put(OtherObject) method, below
iCacheable.put(ex);
}
System.out.println("myObjects: "+ex.myObjects.size());
System.out.println("otherObjects: "+ex.otherObjects.size());
}
private HashMap<String, MyObject> myObjects = new HashMap<String, MyObject>();
private HashMap<String, OtherObject> otherObjects = new HashMap<String, OtherObject>();
public Example() {
}
public void put(MyObject myObject) {
myObjects.put(myObject.getKey(), myObject);
}
public void put(OtherObject otherObject) {
otherObjects.put(otherObject.getKey(), otherObject);
}
}
interface ICacheable {
public String getKey();
public void put(Example ex);
}
class MyObject implements ICacheable {
public String getKey() {
return "MyObject"+this.hashCode();
}
public void put(Example ex) {
ex.put(this);
}
}
class OtherObject implements ICacheable {
public String getKey() {
return "OtherObject"+this.hashCode();
}
public void put(Example ex) {
ex.put(this);
}
}
The idea here is that - instead of casting or using instanceof - you call the iCacheable object's .put(...) method which passes itself back to the Example object's overloaded methods. Which method is called depends on the type of that object.
See also the Visitor pattern. My code example smells because the ICacheable.put(...) method is incohesive - but using the interfaces defined in the Visitor pattern can clean up that smell.
Why can't I just call this.put(iCacheable) from the Example class?
In Java, overriding is always bound at runtime, but overloading is a little more complicated: dynamic dispatching means that the implementation of a method will be chosen at runtime, but the method's signature is nonetheless determined at compile time. (Check out the Java Language Specification, Chapter 8.4.9 for more info, and also check out the puzzler "Making a Hash of It" on page 137 of the book Java Puzzlers.)
Is there no way to combine the cached objects in each map into one map? Their keys could keep them separated so you could store them in one map. If you can't do that then you could have a
Map<Class,Map<Key,ICacheable>>
then do this:
Map<Class,Map<Key,ICacheable>> cache = ...;
public void cache( ICacheable cacheable ) {
if( cache.containsKey( cacheable.getClass() ) {
cache.put( cacheable.getClass(), new Map<Key,ICacheable>() );
}
cache.get(cacheable.getClass()).put( cacheable.getKey(), cacheable );
}
You can do the following:
Add a method to your ICachableInterface interface that will handle placing the object into one of two Maps, given as arguments to the method.
Implement this method in each of your two implementing classes, having each class decide which Map to put itself in.
Remove the instanceof checks in your for loop, and replace the put method with a call to the new method defined in step 1.
This is not a good design, however, because if you ever have another class that implements this interface, and a third map, then you'll need to pass another Map to your new method.
I have 3 class and, first is Person :
public class Person {
Person() {
}
}
Second is Engineer that extends of Person
public class Engineer extends Person {
Engineer() {
}
}
and another extends of Person
public class Doctor extends Person {
Doctor() {
}
}
Last one is Work that take in constructor an object Person
public class Work {
Work(Person p) {
//how to insure that p is Engineer ?
}
}
How to detect that an object p is Engeneer and not from another class ?
You can use the instanceof keyword for checking the type of an object. It works like this
if(p instanceof Engineer) {
// do Engineer stuff
} else {
// not an Engineer object
}
You can check it with the following:
if (p instanceof Engineer)
or
if (p.getClass() == Engineer.class)
Use something like:
if (p.getClass() == Engineer.class) {
//Is engineer
}
p.getClass()
(and from there, .getName())
or the operator instanceof (note, a Doctor and an Engineer will be return instanceOf Person as true; check for the more specific class)
You shouldn't need to do this.
Work(Engineer p) {
// p is an Engineer
}
or
Work(Person p) {
p.doWork(); // calls the appropriate work methopd for any person.
}
public class Work {
// ensure only Engineer can pass in
Work(Engineer p) {
}
}
or using instanceof keyword
The instanceof operator compares an object to a specified type. You
can use it to test if an object is an instance of a class, an instance
of a subclass, or an instance of a class that implements a particular
interface.
public class Work {
Work(Person p) {
// make sure p is type of Engineer
if(p instanceof Engineer) {
// dowork
Engineer e = (Engineer) p;
} else {
// not engineer or p is null
}
}
}
Use instanceof keyword like
if(p instanceof Engineer) {
// do something
}
if(p instanceof Doctor) {
// do something
}
but this is not right way,
you should have Enginner's behavior(method) in Engineer's class and Doctor's behavior in Doctor class.
See Peter's answer, Runtime polymorphism will detect which method to call automatically.
i.e.
class Engineer extends Person {
// properties
// methods
public void doWork() {
// does engineering work
}
}
class Doctor extends Person {
// properties
// methods
public void doWork() {
// does doctor work like check patients, operation or other his task
}
}
class Work {
Work(Person p) {
p.doWork(); // if you pass engineer obj here, Engineer.doWork() is called. And if you pass doctor, Doctor.doWork() is called.
// You don't need to use instanceof.
}
}
Engineer and Doctor have same method names in above case but in some cases you may need to use instanceof, for e.g. Doctor will have checkPatient() method, Engineer will have some different method name like designEngine(), then you will have to use instanceof.