using getter with java generic method argument - java

I have a method that takes a generic parameter type. The scenario I have is this method will be called with different parameter types.
class something{
public void someMethod(){
List<A> listA = ....; //Class A have a field String Id;
List<B> listB = ....; //Class B haave a field String Id;
testMethod(listA);
testMethod(listB);
}
private <T> void testMethod( List<T> list ){
for( T event : list ){
//TODO (something like): event.getId();
}
}
}
In the above code all the parameters will be be a List<someObjectType>. All the object types have a common field and need to use the getter to fetch its value. Now since the method definition is generic, how do I achieve this?

Have A and B implement a common interface that has a method getID:
interface SomeInterface {
String getID();
}
then you could have:
private <T extends SomeInterface> void testMethod(List<T> list) {
for (T event : list) {
// now you can use `event.getID()` here
}
}

There is no point in creating such a generic method without bounded type. Since T isn't bounded to any type, you can't use specific interface on the objects inside the list. So if you want testMethod to get list of objects of any type, you should use List<?> instead.

This cannot be done. You can't handle two different lists with incompatible interfaces the same way in your method, unless you do something with instanceof, i.e.
public void testMethod(List<? extends Object> list) {
if(list.get(0) == null) return;
if(list.get(0) instanceof A) {
// Do the A stuff
} else {
// Do the B stuff
}
}

Define your method like this with T extending your common class/interface BaseType:
private <T extends BaseType> void testMethod( List<T> list ){
for( T event : list ){
//TODO (something like): event.getId();
}
}
Example:
public void someMethod() {
List<Integer> listA = Arrays.asList( new Integer[] {1, 4, 9} );
List<Double> listB = Arrays.asList( new Double[] {1.5, 4.2, 9.3} );;
testMethod(listA);
testMethod(listB);
}
private <T extends Number> void testMethod( List<T> list ){
for( T event : list ) {
// Note intValue() method is being called here which is provided
// in the base class Number that is being extended by T
System.out.println(event.intValue());
}
}

As other answers said, you need to bound the type parameter by some interface. But for what you're using it for, you don't actually need to have a T:
private void testMethod(List<? extends SomeInterface> list) {
for (SomeInterface event : list) {
// now you can use `event.getID()` here
}
}

I don't know if i really understand what you want.
But if you know, you will store for example Strings into your List and want to use the toUpperCase() method, how about just casting it?

Related

Java - Generics - Casting generic object in generic specified object doesn't work

I'm trying to resolve this apparently simple generic casting problem :
First, declaring this simple generic object :
public interface GenericObject<T> {}
Second, declaring this working interface :
public interface Generic { // I don't want to do Generic<T>
<T> void setGenericObject(GenericObject<T> obj);
}
Then, let's implements this interface :
public class GenericImpl implements Generic {
private GenericObject<String> genericObject; // This is needed
#Override
public <String> void setGenericObject(GenericObject<String> obj) {
genericObject = obj; // eclipse give me this error :
// Type mismatch: cannot convert from
// interfaces.GenericObject<String> to
// interfaces.GenericObject<java.lang.String>
}
}
How can I solve this error ?
Edit :
Actualy, the only way I have to solve this issue is to do this :
public class GenericImpl implements Generic {
private GenericObject<String> genericObject;
#SuppressWarnings("unchecked") // I don't realy like this
#Override
public <T> void setGenericObject(GenericObject<T> obj) {
genericObject = (GenericObject<String>) obj;
}
}
The real problem is that
public <String> void setGenericObject(GenericObject<String> obj)
where the String has nothing to do with the your intended java.lang.String. Here the String is just a type parameter whose name is String by accident.
Please refer to Is it possible to have an interface method defined with a generic return type and a concrete implementation define the return type?.
Case 1:
If T is not used in Generic, then just use a wildcard.
class Generic {
List<?> list;
void set(List<?> list) {
this.list = list;
}
int size() {
return list.size(); // doesn't care about T
}
}
Case 2:
If T is only used as local variables, then declare <T> on the method
class Generic {
<T> void swapFirstAndSecond(List<T> list) {
T first = list.get(0), second = list.get(1);
list.set(1, first);
list.set(0, second);
}
}
Case 3:
If several fields and methods use the same type T, but the exact type of T is not important, then delacre <T> on the class
class Generic<T> {
List<T> list;
void set(List<T> list) {
this.list = list;
}
T getFirst() {
return list.get(0);
}
}
Case 4:
If T must be a specific type, like String, then don't declare type parameter <T>
class Generic {
List<String> list;
void set(List<String> list) {
this.list = list;
}
boolean isFirstContainsSecond() {
String first = list.get(0), second = list.get(1);
// call String.contains here, so T must be String
return first.contains(second);
}
}

How to call to LinkedList with generic type

I'm using several LinkedList each one from different type, for example :
LinkedList<A> typeA = new LinkedList<>();
LinkedList<B> typeB = new LinkedList<>();
LinkedList<C> typeC = new LinkedList<>();
and then i want to print them according to the type, so for each type I call to the appropriate function.
void funcA(LinkedList<A> ls)
void funcB(LinkedList<B> ls)
void funcC(LinkedList<C> ls)
and I wonder if the is any option of calling one function and inside that function to check the type.
Thank for those who help! Have a nice day :)
As other have mentioned, you can use a generic function like:
public static <T> void genericFunc(LinkedList<T> ls) {
//you can do something with the list but
//you do not know what T is so you can't invoke T's methods
//(apart from those belonging to Object)
}
If you want to have additional control over the types contained in T, assuming that all your objects inherit from a base class A, then you can do:
public static <T extends A> void genericFunc(LinkedList<T> ls) {
for (T t : ls){
t.somePublicMethodOfA();
}
}
I'd use another generic parameter to the function to indicate how the list is to be printed based on the type.
See http://www.functionaljava.org/javadoc/4.7/functionaljava/fj/Show.html
Example:
void func<A>(LinkedList<A> list, Show<A> aShow) {
listShow(aShow).printLn(list)
}
If you were using Scala you would make Show[A] an implicit parameter.
You could use a unbound generic type in the list parameter of the method, it would look as follow:
public static void main(String[] args) {
List<String> listStr = Arrays.asList("A","B","C");
List<Integer> listInt = Arrays.asList(1,2,3);
printList(listStr);
printList(listInt);
}
private static void printList(List<?> list) {
for(Object obj : list){
if(obj instanceof String){
String str = (String) obj;
System.out.printf("String: %s \n", str);
} else if(obj instanceof Integer){
Integer integer = (Integer) obj;
System.out.printf("Integer: %s \n", integer);
}
}
}
you can use a generic method.
public <T> void func(LinkedList<T> ls) { // T can be any type
// do something
}

Converting List of Generic type classes to List of Objects

Hi as my generic type method returns the List as follows
List<Class<Department>> departmentsByAppId = commonDao.getDaoData(new Object[]{appStateObject.getAppId()}, new String[]{"appId"}, new String[]{"eq"}, Department.class);
So how can we convert this data to normal list likeList<Department> without iterating.
Assuming your generic type method is declared in a generic interface and that department got a DAO interface that extends that last one, you could do something like that :
YourGenericDaoInterface.java :
public interface YourGenericDaoInterface<E> {
List<E> getDaoData(Object[] objArray, String[] appId, String[] eq, Class clazz);
}
YourGenericDaoImplementation.java :
#Override
List<E> getDaoData(Object[] objArray, String[] appId, String[] eq, Class clazz) {
// do your stuff here
}
YourDepartmentDaoInterface.java :
public interface YourDepartmentDaoInterface extends YourGenericDaoInterface<Department> {
}
So basically it does the following :
By making YourDepartmentDaoInterface inherits YourGenericDaoInterface<Department> you obtain the method getDaoData and tell that the return type is of type Department then when you'll use your method you will directly call :
List<Department> dep = commonDao.getDaoData(new Object[] appStateObject.getAppId()}, new String[]{"appId"}, new String[]{"eq"}, Department.class);
You can iterate the list and add each object to another list after performing the appropriate casting:-
List list = new ArrayList();
for(int i=0;i<=departmentsByAppId.size();i++)
{
list.add((Department)departmentsByAppId.get(i));
}

Generic method that accepts two types of List

I want to write a function that can accept two similar types. But not same.
MyClassA {
abc()
a2b()
}
MyClassB {
abc()
a3b()
}
One method is same in these two. The function should accept list of any of these two types and I want to invoke abc() on objects in the list.
This does not seem to help:
private <T> Set<MyclassX> createObject(List<T> classes) {
Set<MyclassX> x;
if ( T instanceof MyClassA) {
for ( MyClassA a : classes ) {
if (a.abc().equals("somethig")) {
x.add( t.abc());
}
}
}
return x;
}
I don't even need to check instanceof. I just need to iterate through the list and compare the values. if there is a match, then call the method abc()
Just create a common interface and make MyClassA and MyClassB implement it:
interface MyClass {
void abc();
}
I suggest you to use abstract super class like this:
abstract SuperClass{
abc();
abstract ab(); // Only if the other methods share signatures
}
MyClassA extends SuperClass {
ab();
}
MyClassB extends SuperClass{
ab();
}
private <T> Set<? extends SuperClass> createObject(List<T> classes) {
...
}
If you only want to iterate over a collection that contains instances of MyClassA and MyClassB, then call the method abc() on those instances.
This can be work well with JPA because there is an annotation so called MappedSuperclass .
This way you can decompose the same logic from descendant classes in a way that fits with your requirements and can be used with generics. Here is a Hibernate example of how to use
Using generics, you can do this:
private <T> Set<MyclassX> createObject(List<T> classes) {
Set<MyclassX> x;
for ( T a : classes ) {
if (a.abc().equals("somethig")) {
x.add( t.abc());
}
}
}
return x;
}
Assuming that t.abc() returns a MyclassX. (And I mean this literally, I'm not assuming that the X stands for something else.)
Type information can be passed in as an argument
<T> void method(Class<T> clazz, List<T> list)
{
if(clazz==MyClassA.class)
{
#SuppressWarnings("unchecked)
List<MyClassA> listA = (List<MyClassA>)list;
....
}
else if...
A better solution is probably to convert a List<MyClassX> to a List<Abc> before passing it in
interface ABC
abc()
void method(List<Abc> list)
the conversion is probably going to be easy in java8
List<MyClassA> list1 = ...
method( list1.map( e->e.abc() ) );

Generic instance variable in non-generic class

I'm trying to write a class that has a generic member variable but is not, itself, generic. Specifically, I want to say that I have an List of values of "some type that implements comparable to itself", so that I can call sort on that list... I hope that makes sense.
The end result of what I'm trying to do is to create a class such that I can create an instance of said class with an array of (any given type) and have it generate a string representation for that list. In the real code, I also pass in the class of the types I'm passing in:
String s = new MyClass(Integer.class, 1,2,3).asString();
assertEquals("1 or 2 or 3", s);
String s = new MyClass(String.class, "c", "b", "a").asString();
assertEquals("\"a\" or \"b\" or \"c\"", s);
Originally I didn't even want to pass in the class, I just wanted to pass in the values and have the code examine the resulting array to pick out the class of the values... but that was giving me troubles too.
The following is the code I have, but I can't come up with the right mojo to put for the variable type.
public class MyClass {
// This doesn't work as T isn't defined
final List<T extends Comparable<? super T>> values;
public <T extends Comparable<? super T>> MyClass (T... values) {
this.values = new ArrayList<T>();
for(T item : values) {
this.values.add(item);
}
}
public <T extends Comparable<? super T>> List<T> getSortedLst() {
Collections.sort(this.values);
return this.values;
}
}
error on variable declaration line:
Syntax error on token "extends", , expected
Any help would be very much appreciated.
Edit: updated code to use List instead of array, because I'm not sure it can be done with arrays.
#Mark: From everything I've read, I really want to say "T is a type that is comparable to itself", not just "T is a type that is comparable". That being said, the following code doesn't work either:
public class MyClass {
// This doesn't work
final List<? extends Comparable> values;
public <T extends Comparable> MyClass (T... values) {
this.values = new ArrayList<T>();
for(T item : values) {
this.values.add(item);
}
}
public <T extends Comparable> List<T> getSortedLst() {
Collections.sort(this.values);
return this.values;
}
}
error on add line:
The method add(capture#2-of ? extends Comparable) in the type List<capture#2-of ? extends Comparable> is not applicable for the arguments (T)
error on sort line:
Type mismatch: cannot convert from List<capture#4-of ? extends Comparable> to List<T>
Conclusion:
What it comes down to, it appears, is that Java can't quite handle what I want to do. The problem is because what I'm trying to say is:
I want a list of items that are
comparable against themselves, and I
create the whole list at once from the
data passed in at creation.
However, Java sees that I have that list and can't nail down that all the information for my situation is available at compile time, since I could try to add things to the list later and, due to type erasure, it can't guarantee that safety. It's not really possible to communicate to Java the conditions involved in my situation without applying the generic type to the class.
I think that the simple answer is that you cannot do that. If the type of one of a classes attributes depends on a type parameter, that parameter has to be declared at the class level. And I don't think that it "makes sense" any other way.
If T in your example is not a type parameter of the class, what is it? It cannot be the type parameter of the method, because that type is determined by how the method is called. (If the method is called in different static contexts with different inferred types for T, what is the notional type of T in the context of the attribute declaration?)
So to bring this back to what you are trying to do here, an instance of MyClass will hold elements of some type, and you want to be able to insert and remove elements in a statically typesafe fashion. But at the same time you don't want to be able to say what that type is. So how is the compiler supposed to statically distinguish between a MyClass instance that holds (say) Integer objects and one that holds String objects?
I don't even think you could implement this with explicit dynamic typechecks. (I think that type erasure means that the implementation of the getSortedList() method cannot find out what actual type is bound to its return type.)
No. The real solution is to make MyClass a generic class that declares the type parameter T; e.g.
public class MyClass <T extends Comparable<T>> {
and remove the declaration of the method-level type parameter T from the two methods.
There's plenty of unchecked warnings in this, but in principle it's not necessary to keep the List as anything but something containing things you know are Comparable. You enforce the rules you need to in the constructor, and everything else should be fine. How about something like this:
public class MyClass {
final private List<Comparable> values;
public <T extends Comparable<? super T>>MyClass(T... values){
this.values = new ArrayList<Comparable>();
for(T item : values) {
this.values.add(item);
}
}
public <T extends Comparable<? super T>> List<T> getSortedLst() {
Collections.sort(this.values);
return (List<T>)this.values;
}
}
A quick test using the following shows that for classes that implement Comparable (like Integer and String) MyClass behaves as expected, but will throw a compilation error for classes that do not implement Comparable:
class Junk { }
public static void main(String[] args){
MyClass s = new MyClass(1,2,3);
System.out.println(s.getSortedLst());
MyClass a = new MyClass("c", "a", "b");
System.out.println(a.getSortedLst());
MyClass c = new MyClass(new Junk());
}
I believe the following will achieve what you want (stronger typing of Comparable). This will prevent people adding Comparable objects which are not from your interface to the list and allow multiple implementations.
public class test<T extends ComparableType> {
final List<T> values = new ArrayList<T>();
public test (T... values) {
for(T item : values) {
this.values.add(item);
}
}
public List<T> getSortedLst() {
Collections.sort(this.values);
return Collections.unmodifiableList(this.values);
}
}
public interface ComparableType extends Comparable<ComparableType> {}
public class ConcreteComparableA implements ComparableType {
#Override
public int compareTo(ComparableType o) {
return 0;
}
}
public class ConcreteComparableB implements ComparableType {
#Override
public int compareTo(ComparableType o) {
return 0;
}
}
edit:
I know this may be obvious; but if you do not wish the class to be Generic this solution will also work with:
public class test {
final List<ComparableType> values = new ArrayList<ComparableType>();
public test (ComparableType... values) {
for(ComparableType item : values) {
this.values.add(item);
}
}
public List<ComparableType> getSortedLst() {
Collections.sort(this.values);
return Collections.unmodifiableList(this.values);
}
}
Consider it like this (what I am about to say isn't reality. but it illustrates why you need to do what you need to do):
class Foo<T>
{
private T value;
T getValue() { return value; }
void setValue(T val) {value = val; }
}
// some code that uses the above class
Foo<Integer> iFoo = new Foo<Integer>();
Foo<String> sFoo = new Foo<String>();
iFoo.setValue(5);
sFoo.setValue("Hello");
When this happens the compiler (DOES NOT REALLY DO WHAT I AM ABOUT TO SAY!) generates the following code:
class IntegerFoo
{
private Integer value;
Integer getValue() { return value; }
void setValue(Integer val) {value = val; }
}
class StringFoo
{
private String value;
String getValue() { return value; }
void setValue(String val) {value = val; }
}
// some code that uses the above class
IntegerFoo iFoo = new IntegerFoo();
StringFoo< sFoo = new StringFoo();
iFoo.setValue(5);
sFoo.setValue("Hello");
If you were able to have the instance variables/methods parameterized without parameterizing the class the above thing (WHICH IS NOT REALITY!) wouldn't work.
What you are trying to do should be possible with static methods, but I don't think that is what you want.
Can you explain why you want to do the code you are trying to do? Perhaps we can figure out a better way to do what you want to do that works within the language.
I'd do it this way (I did it as a list or as an array), unless you really need the instance variable/methods:
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class MyClass
{
public static <T extends Comparable<T>> List<T> asSortedList(final T ... vals)
{
final List<T> temp;
temp = new ArrayList<T>(vals.length);
temp.addAll(Arrays.asList(vals));
Collections.sort(temp);
return (Collections.unmodifiableList(temp));
}
public static <T extends Comparable<T>> T[] asSortedArray(final Class<?> clazz,
final T ... vals)
{
final T[] temp;
temp = (T[])Array.newInstance(clazz,
vals.length);
System.arraycopy(vals,
0,
temp,
0,
vals.length);
Arrays.sort(temp);
return (temp);
}
public static void main(final String[] argv)
{
final List<String> list;
final String[] array;
list = MyClass2.asSortedList("c", "a", "b");
System.out.println(list);
array = MyClass2.asSortedArray(String.class, "z", "y", "x");
System.out.println(Arrays.deepToString(array));
}
}
the type constraint you want on the variable can't be expressed directly. you can introduce a new type to bridge the problem.
static class MyList<T extends Comparable<? super T>> extends ArrayList<T>{}
final MyList<?> values;
however, there is no point to be extremely type safe in a private piece of code. Generic is there to help you clarify your types, not to obfuscate them.
public class MyClass<T extends Comparable<? super T>> {
// This doesn't work as T isn't defined
final List<T> values;
public MyClass (T... values) {
this.values = new ArrayList<T>(Arrays.asList(values));
}
public List<T> getSortedLst() {
Collections.sort(this.values);
return this.values;
}
}

Categories