How to pass an object with an unknown type to a class with an unknown type

I am currently working on homework for the Java programming course that I am taking. I do not require an exact answer, but for some recommendations.

The problem I'm working on is this:

I have a filter class that implements the Filter interface. This interface has only one method - matches(T element)

I set up my filtering method to test Integer, which is passed in for simplicity.

There is also a decorator class that decorates a collection class only to display objects that pass the filter.

I'm having problems with the contains (Object o) method working correctly.

Basically, the contains(Obj o) method in the FilteredCollection class must first check if the object passes through the filter, and then, if so, call the undecorated contains() method on that object.

Assuming that I want to use this FilteredCollection class with many different types of filters, how can I determine which type of object will be passed, and then be able to pass this object to the current filter that is implemented.

Here is my PrimeNumberFilter Class:

 public class PrimeNumberFilter implements Filter<Integer> { public boolean matches(Integer e) { int n = e.intValue(); if (n != 2 && n % 2 == 0) { return false; } for (int i = 3; i * i <= n; i += 2) { if (n % i == 0) { return false; } } return true; } } 

Then here is my abbreviated FilteredCollection Class:

 class FilteredCollection<T> implements Collection<T> { Collection<T> fc; Filter<T> currentFilter; private FilteredCollection(Collection<T> coll, Filter<T> filter) { this.fc = coll; this.currentFilter = filter; } public static <T> FilteredCollection<T> decorate(Collection<T> coll, Filter<T> filter) { return new FilteredCollection<T>(coll, filter); } public boolean contains(Object o) { //What do I do here? return fc.contains(o); } 

The object passed to the contains method must pass a filter, in this case a PrimeNumberFilter .

The error I get is that she wants to overlay the object on type T, and I know that this will never work due to erasure.

I did a lot of research and I boiled it to use reflection.

The only hint my instructor will give me is that the object has only a few methods that I can use, and I must use one of them.

Thank you for your help!

EDIT:. One of the requirements of the project is NOT to attach the object to T in any method. Therefore, although these answers are great, I cannot use them.

+4
source share
4 answers

Used method Object.equals(Object) . You can iterate the fc collection and check if it contains an element with equals(o) . If so, continue with the specified element (which is of type T ).

 for(T e : fc) { if(o.equals(e)) { // carry on with e } } 

You can also use o == null .

+4
source

There is nothing wrong with the code.

The problem is that the java.util.Collection.contains(Object o) interface is not typed. This is out of your control.

Option 1: a simple approach

In your implementation of this method, you can use:

 public boolean contains(Object o) { return o != null && currentFilter.matches((T)o) && fc.contains(o); } 

Option 2: add the getParameterType () method to the filter interface

This method returns the general filter type implemented in various subclasses.

 interface Filter<T> { boolean matches(T parameter); Class<T> getParameterType(); } 

Then...

 public boolean contains(Object o) { return o != null && currentFilter.getParameterType().isAssignableFrom(o.getClass()) && currentFilter.matches((T)o) && fc.contains(o); } 

Option 3: Defining a General Type Using Reflection

Technically, the generic filter type will not be deleted at runtime. Type erasure does not apply here because PrimeNumberFilter is an actual class that implements a typically typed interface.

 @SuppressWarnings("unchecked") public boolean contains(Object o) { Class<?> genericTypeOfFilter = getGenericTypeOfFilter(currentFilter); return o != null && genericTypeOfFilter.isAssignableFrom(o.getClass()) && currentFilter.matches((T)o) && fc.contains(o); } static <T> Class<T> getGenericTypeOfFilter(Filter<T> filter) { try { @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) Class<T> type = (Class<T>) ((ParameterizedType)filter.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0]; return type; } catch (Exception e) { throw new IllegalStateException("Unexpectedly failed to read generic type of filter: " + filter, e); } } 

If it was my code, I would go with option 2 in this case, it is more reliable than relying on reflection.

+4
source

The type applied to T will work, you just need to be careful to catch a ClassCastException , because you cannot check the type before casting due to erasure.

This will leave you with something like:

 public boolean contains(Object other) { try { return currentFilter.matches((T)other) && fc.contains(other); } catch (ClassCastException e) { //Add some logging. return false; } } 

Using exceptions this way is generally disapproving, but in this case you have little choice.

0
source

Since the contains method uses .equals, and .equals is an overridden version of qn in Object in Object, I would consider creating a new collection with the parameter type Object, so for example, ArrayList will use the addAll method to add everything from the T-type collection - this will work because all classes inherit from Object. Then, when he uses the equals method, he will still be one of the class T (if T overrides it). This is not an ideal approach, but I think it is simpler and more accurate than trying to check if an object can be moved to T.

 public boolean contains(Object o) { Collection<Object> temp = new ArrayList<Object>(); temp.addAll(fc); return temp.contains(o); } 
0
source

Source: https://habr.com/ru/post/1480994/


All Articles