Java How to tell which Object is in a HashMap - java

I have a HashMap:
HashMap<String, anObjectClass> myHash = new HashMap<String, anObjectClass>();
I have my anObjectClass:
public class anObjectClass {
private String name;
private ArrayList<String> myObjectList = new ArrayList<String>();
}
I have another class that extends my anObjectClass that adds another String:
public class secondObjectClass extends anObjectClass {
String quote;
}
Which means I have two kinds of objects within my HashMap:
My anObjectClass objects which have a String name and an ArrayList of Strings: myObjectList
And my secondObjectClass objects which adds another String: quote.
My question is, if I have a String key, say "ABC". I know I can tell whether or not there is a key "ABC" in my HashMap with the containsKey() method. But once I have found a key "ABC", how do I tell if it is an anObjectClass object or a secondObjectClass object? In other words, how can I tell what kind of object matches with that key? Thank you in advance.

For objects for which you control the definitions, define a boolean
boolean isBaseClass() { return(true); }
and in the subclass define
boolean isBaseClass() { return(false): }
but more generally, use method inheritance instead of this kind of test,
because it can be extended to any family of classes.
// bad
if(x.isBaseClass()) { doThis(); } else { doThat(); }
// better
x.doNextThing()

You can use the keyword instanceof to determine the types of different objects in Java.
In your example, say you are trying to determine the type of an object obj that is either an instance of anObjectClass or secondObjectClass. You can tell the type by using the following code:
if(obj instanceof secondObjectClass) {
// obj is of type secondObjectClass
} else if(obj instanceof anObjectClass) {
// obj is of type anObjectClass
}
This is fine, but beware - types are transitive. That is, an instance of secondObjectClass is also of type anObjectClass because it is a subclass of it. It is therefore helpful to be as specific as possible when using instanceof.

You can also use isAssignableFrom method of Class class.
So your code will look like
if(obj.getClass().isAssignableFrom(BaseClass.class)) {
//bla
}
if(obj.getClass().isAssignableFrom(SuperClass.class)) {
//blabla
}
I like this because I don't have to worry about the order of if else's nor do I need to write nested if elses.
EDIT
By order I meant while using instanceof, your if elses have to be placed in a way that the sub class is checked before the base class instanceof check. Sorry for causing any confusion. Thanks #EJP for pointing out.

Related

Check if some object is instance of some class in a list

So, I want to have a List of types, then loop through the List and check if an Object is instance of the type in that list.
This is how I would imagine it to work, but that is no Java syntax.
Type1.class also doesn't work
List<Object> types = new ArrayList();
types.add(Type1);
types.add(Type2);
for (Object type : types) {
if (someObject instanceof type) {
doSomething();
}
}
or the same thing with List<Class> or something like that
this clearly doesn't work, but I dont know whats the best way to do it. Of course I could just hardcode every Object I want to check, but that doesn't seem that elegant.
From the Java docs :
In Java instances of the Class class represent classes and interfaces in a running Java application.
You could use Class::isInstance method to determine if object is instance of given type and then apply processing based on this evaluation:
List<Class<?>> types = new ArrayList<>();
types.add(String.class);
types.add(Integer.class);
String someObject = "someString";
for (Class<?> type : types) {
if (type.isInstance(someObject)) {
// do smoething
}
}
These kinds of requirements call for the use of reflection. There is a class in Java meant to represent the type of an object: class Class. Instances of that class effectively represent the types of objects. So you could do:
List<Class<?>> types = new ArrayList<>();
types.add(Type1.class);
types.add(Type2.class);
for (Class<?> type : types) {
if (type.isAssignableFrom(someObject.getClass())) {
doSomething();
}
}
Note that in this situation it's important to know whether you want to check if your target object has exactly the same type as a type in a list, or can be assigned to the type in the list. The code sample covers the second option because it's closer to the original intent. If you need an exact match, you would do:
object.getClass() == type;
See also Class.isInstance vs Class.isAssignableFrom

Check Vector type

I want to know if Vector is holding <String> or <Integer>.
my function public void printVector(Vector <?> v){
I tried if(v instanceof <String>) but the compiler won't allow it.
whats the issue?
A code example that may be relevant:
import java.util.Iterator;
import java.util.Vector;
public class Cool {
public static void main(String[] args) {
Vector<Integer> v;
v = new Vector<>(5);
v.add(Integer.valueOf(5));
test(v);
}
private static void test(Vector<?> v) {
Iterator<?> iterator = v.iterator();
if (iterator.hasNext()) {
System.out.println(iterator.next().getClass());
}
}
}
This will print out class java.lang.Integer.
Your "test" method will have to check the type against a set of superclasses you're interested in (Employee/Customer/etc).
Also, Using vectors is generally considered bad practice in java.
Theoretically, you cannot know, because of type erasure. Basically, it means that you cannot get the generic type of the vector at runtime.
Now, in a real application, if you know that every objects are of the same type, you can get the first one and check its type with instanceof.
Note : this is not a good practice. Avoid that if you can. And as said by the others, you should consider other collections than Vector.
Note : as a rule of thumb, using instanceof is a clue of design flaw. Also, this is a costly operation.
If there is no first element, then your array is empty so you can just drop it.
As has been pointed out, Java's type erasure will make the compile-time generic type information unavailable run-time.
A common workaround for this is to pass the Class of the generic parameter as a method argument. This way you can then check whether the method was indeed passed a list of Customers or Employees:
public void print(List<?> list, Class<?> clazz) {
if (clazz == Employee.class) {
// ...
} else if (clazz == Customer.class) {
// ...
} else {
// ...
}
}
You could then call the method as follows:
Vector<Employee> legacy = new Vector<>();
// do stuff
print(legacy, Employee.class);
Note that resorting to instanceof or class checks is usually a sign of bad object oriented design and in general, you can achieve a more elegant solution through polymorphism, i.e. overriding the print() method for different object types -- or having a single print() method that utilizes different toString() implementations of the domain objects.

Questions about the Class method "forName()"

How do I let the user insert a String and check for classes with the same "name"?
Imagine I have a method marked as public A[] getB(String bString) and two classes, A and B, where B extends A.
In this method I want to search through an existing A[] for objects that are upcast from being from the class B and return an A[] with said objects.
I searched through the internet and found out that the class Class has the method forName(), but I don't really understand how to use it. For example, I do this:
Class<?> cl = Class.forName(bString);
Where bString is a String that contains B, B being another class.
My questions are:
What exactly is the object "cl" now?
How could I now check if objects are of the same class as it?
What exactly is the object "cl" now?
cl is an instance of Class class.
How could I now check if objects are of the same class as it?
you have 2 object o1 and o2 you can use getClass()
o1 != null && o2 != null && o1.getClass().equals(o2.getClass())
The method Class.forName(String) returns a Class object for the corresponding class, if known. To quote from its documentation:
Returns the Class object associated with the class or interface with the given string name.
An example would be:
Class threadClass = Class.forName("java.lang.Thread");
Note that the name of the class needs to be fully qualified, not just Thread but java.lang.Thread.
The object you are getting is, as said, a representation of the corresponding class. You can use it to dynamically create instances, check methods, and so on. Here is its documentation and here is an example:
Class<?> threadClass = Class.forName("java.lang.Thread");
// Dynamically create a thread, unchecked cast
Thread thread = (Thread) threadClass.newInstance();
You can check whether two objects are of the same class by using the getClass (documentation) method which every object has:
if (first.getClass().equals(second.getClass()) {
// Same
} else {
// Different
}
However note that this comparison is strict. It would throw false if you compare Integer and Number although Integer extends Number. If you want a less strict variant you may use the instanceof operator:
if (first instanceof second) {
// Is type of
} else {
// Not type of
}
are you sure you wouldn't rather use isInstance?
You could change your method to take a Class instead of a String, since that's what you're really using, a Class.
public A[] getB(Class type){
// I'm assuming you have an array of all As somewhere, called Aarray here
List<A> BList = new ArrayList<>();
for(int i = 0; i < Aarray.length; i++){
if(type.isInstance(Aarray[i])){
BList.add(Aarray[i]);
}
}
return BList.toArray();
}

Is it possible to iterate through an array list with elements of different data types and put them out?

Without generics it is possible to create an ArrayList with elements of different types. I want to iterate through it and put out the elements. I can not use a for-each-loop, because it wants a specific type. I tried Iterator but wasn't successful.
So I have two questions:
Is it possible to iterate through an array list and put out (e. g. with System.out.println) all elements no matter of which type they are?
Is it possible to iterate through an array list and put out only the elements which are of a specific type (e. g. only the Strings)?
Sure!
The toString method is defined on the Object class. The Object class is the base class of every user-defined class. You could easily write:
for (Object item: itemList) {
// prints all items
System.out.println(item);
if (item instanceof YourDesiredClass) {
YourDesiredClass specificItem = (YourDesiredClass) item;
//doSomethingElse(specificItem)
}
}
Is it possible to iterate through an array list and put out (e. g.
with System.out.println) all elements no matter of which file type
they are?
Yes, You can use the Object class
List<Object> myList = new ArrayList<>();
myList.add("Hello World"); // string
myList.add(Math.PI); // a double
myList.add(188); // an int
myList.add(9099099999999L); // a Long
// for java8
myList.forEach(System.out::println);
//before java8
for (Object object : myList) {
System.out.println(object);
}
Is it possible to iterate through an array list and put out only the
elements which are of a specific file type (e. g. only the strings)?
Yes, you can use the iterator and get the Object checking it against the class you need....
Iterator<Object> it = myList.iterator();
while (it.hasNext()) {
Object x = it.next();
if (x instanceof String) {
System.out.println("this is a String: " + x);
}
}
As far as I know, yes.
You can make ArrayList which contains Objects (see Java class Object), because each class you define in Java at least extends class Object which is a top class.
Now let me answer your questions:
yes, it is. Each object in the list knows which class it is instance of and has method toString(). When you swipe through ArrayList and call toString() for every object, the most specific method toString() will be called. For example, if it's instance of Integer (let's say it's called number) and you casted it to Object, call number.toString();, although compiler now looks at that number as the Object, it will call toString() method from Integer class. That's called dynamic polymorphism
yes, you can check which class is the Object instance of. Each of these objects has that info; casting it to Object class is just like saying to compiler "here is some object, I want you to look at it as an instance of class Object" - just like putting glasses to a compiler.
And object knows which class it is, so you can just ask, for example:
if(myObject instanceof String){
//do something;
}
Hope it helped, I tried to explain it the best way I could so you understand what's going on "under the hood" :)
Just object
new ArrayList<Object>().iterator().forEachRemaining(element -> {
System.out.println(element);
});
A specific type
new ArrayList<Object>().stream().filter(element -> element instanceof String).iterator()
.forEachRemaining(System.out::println);
Edit: this answer requires Java 8
Is it possible to iterate through an array list and put out (e. g. with System.out.println) all elements no matter of which file type they are?
Sure, you can iterate a list (or arraylist) of Objectclass and do what you need.
Is it possible to iterate through an array list and put out only the elements which are of a specific file type (e. g. only the strings)?
Yes, you can use instanceof and do specific actions for specific classes.
Usage example:
List<Object> genericList = new ArrayList<>();
genericList.add("test");
genericList.add(2);
genericList.add('c');
for (Object object: genericList) {
// "Put" out object (question 1)
System.out.println(object);
// Check object type (question 2)
if (object instanceof AnyClass) {
//doSomething()
}else if (object instanceof AnotherClass){
//doSomethingElse()
}
}
You can always use a Type all the Objects have in common. The last one will always be Object, since every Class extends Object.
But since we don't like to cast it's mostly the better approach to build a basic class for that:
public abstract class FileType
{
public abstract String getTypeName();
public abstract String getTypeDescription();
}
public class JSON extends FileType
{
#Override
public String getTypeName()
{
return "JSON";
}
#Override
public String getTypeDescription()
{
return "JavaScript Object Notation";
}
}
public class TXT extends FileType
{
#Override
public String getTypeName()
{
return "TXT";
}
#Override
public String getTypeDescription()
{
return "Textfile";
}
}
Now you can make a List of FileType's and use the Methods of it:
List<FileType> fileTypes = new ArrayList<>();
list.add(new JSON()); // JSON fits good in here
list.add(new TXT()); // TXT also
for (FileType fileType : list)
{
System.out.println(fileType.getTypeName()); // have the FileType-Methods savely available
}

How to create an object in a utility class based on if statement in Java? (Or based on a particular string)

I would have a string that is parsed into an array, as shown here:
class Example extends ParentClass {
private String[] array;
public static Example parseString(String lineToParse) {
array = lineToParse.split("\");
}
public ObjectType1() { // arguments: String, String, String
}
public ObjectType2() { // arguments: String, String, String, double, double
}
}
What I'm wondering is could I do this?
if (array[0].equals("Test")) {
public ObjectType1()
}
Or is there a better way to do this?
I want to create various objects with different arguments each, and the first argument (array[0]) will be applicable to each object, so I was wondering if I could create objects within an if statement like this, or a switch (not sure if that would work either).
I believe a factory method would be useful for you, one that returns instances of classes according to the parameter received:
// ObjectType1, ObjectType2, ObjectType3 inherit from ObjectType
static ObjectType getInstance(String[] array) {
if (array[0].equals("Test"))
return new ObjectType1(array);
else if (array[0].equals("Test2"))
return new ObjectType2(array);
else
return new ObjectType3(array);
}
For the record, actually you can define a class inside a method, this is valid code in Java ... of course, that's hardly a good thing to do:
// ObjectType1, ObjectType2 inherit from ObjectType
public ObjectType example(String[] array) {
if (array[0].equals("Test")) {
class ObjectType1 {
ObjectType1(String[] array) {
}
}
return new ObjectType1(array);
}
else {
class ObjectType2 {
ObjectType2(String[] array) {
}
}
return new ObjectType2(array);
}
}
"Creating" an object means "instantiating it", with new:
ObjectType1 foo = new ObjectType1(...);
You can do that anywhere it's legal to instantiate a class, including in an if statement.
You cannot define classes in arbitrary locations, however.
If you just want to call a method (which should start with a lower-case letter if you want Java developers to understand what you're trying to do), you can call it from anywhere, including inside if statements.
This sounds like you may want to use a [static factory method][1].
[1]: http://en.m.wikipedia.org/wiki/Factory_method_pattern
I guess that you want to dynamically create objects based on a configuration file?
There are lots of ways to achieve this. One simple way is to use reflection to create the objects. Then you do not need any if/switch statements, and if you want to create a new type of object your code does not need to be changed.
Here are some examples for using reflection: Reflection API Code Samples

Categories