1

i am studying generics and i have some difficulty to understand some concepts: i have create a generic interface as showed down:

   public interface ICOperations<A,B> {
      A findById(B b);
      A saveOrUpdate(A a);
      <G> G deleteById(A a);  }

I was thinking that Type parameter at the line of code :

    <G> G deleteById(A a);

can be used only in case that i have define it at the line of code :

   public interface ICOperations<A,B> {

My question is : what does it mean a parameter type ?

And if some one can explain it with an example of a method in a class that can implement the method deleteById.

G is the return type of the method, A is the parameter type of the method, and what is and for what is used ?

lirio oliro
  • 21
  • 1
  • 7
  • Possible duplicate of [What are Generics in Java?](https://stackoverflow.com/questions/7815528/what-are-generics-in-java) – MC Emperor Dec 14 '17 at 13:56

4 Answers4

2

Declaring a generic type parameter for a specific method that returns an instance of that generic type makes more sense if the method also accepts some argument that serves as a means to produce an instance of that type.

For example, consider the Stream<T> interface.

It has a map method with a generic type parameter R. It received as an argument a Function that transforms a Stream element of type T to a Stream element of type R. This allows the method to transform a Stream<T> to a Stream<R>:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

Example:

Stream<String> stream = Stream.of("aaa","bb","c");
Stream<Integer> lengths = stream.map(String::length);

In this example T is String and R is Integer.

On the other hand, I see no real life usage of your <G> G methodName(A a); example, since any class implementing methodName(A a) has no way of returning an instance of G.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • it happends a lot that you receive two different objects and you should return a third type of object. In Java Lambda, under the Function pakcage we have the interface BiFunction (T,U,R) that accept two arguments and return a result ( all of them can be of different types. ps: i was studying generics for a week and i start reading about Lambda and now i am turning back a little at generics ( cause i see that i missed some thing :) – lirio oliro Dec 14 '17 at 14:09
  • @liriooliro Are you asking something in this comment? Because if you do, I didn't get the question. Yes, the Stream framework has a lot methods with multiple type parameters. – Eran Dec 14 '17 at 14:12
  • _"... I see no real life usage of your ` G methodName(A a);`..."_ what about custom cast operator `public static R cast(T t) {return (R) t;}` so you dont have to write some long class names when explicitly casting e. g. `set((SomeThirdPartyClassWithLengthyName) o);` instead you can simply write `set(cast(o))`. – matoni Dec 14 '17 at 14:36
1

<G> G metodName(A a) is using argument of type A defined in your interface, while return type G is infered from the left side of assignment operator thus it can be anything based on assignment construction. Consider these lines: Person p = methodName(someInstanceA);, Vector v = methodName(someInstanceA);. In first case, G turns into a Person and in second case, G turns into a Vector. Since you can not know in advance what assignment would be used, method implementation has to return "something" that is cast to type G:

@Override
public <G> G methodName(A a) {
    return (G) a; // if A does not extends G, an exception will be thrown
}

More reasonable is to to define a method signature in this way:

@Override
public <G super A> G methodName(A a) {
    return (G) a; // always legal
}

In example above, it is always safe to cast instance of A to G as G is expected to be a super type of A (i. e. casting to parent type). Since G is constrained to be a parent class of A an assignment will compile if and only if the left side of assignment matches the specified constrained.

However, you will see more often an method signature, which infers parametrized-type from a supplied argument:

public <G> G methodName(G g, A a) {
    // G is defined as "any" object, thus only object methods can be accessed:
    // g.toString(); g.hashCode(); ... but g.someMethod(); would not compile...
    // do-something with g and a...
    return g;
}

As you can pass anything in place of G, G is effectivelly of Object type and so, there is only a few scenarios when something like this would be helpful or sufficient for your needs. Thus if you want to do something more meaningful, you should use some type constraint as mentioned above (G super A, G extends SomeOtherType). For more details about generics constraints see Wildcards.

matoni
  • 2,479
  • 21
  • 39
  • i cannot use super or becuase the method that comes me in mind are the normal delete method that takes as parameter an Integer or a String and return the object that was deleted ( usually is used for some type of service when you delete all the data ( and you return the result to fron end and in the case that the client makes an error cancelling the data they can do revocer or uncancell. ( so they recall another service) – lirio oliro Dec 14 '17 at 15:08
  • @liriooliro you have described DAO layer which operates on data of specified type, in such case just define one DAO interface for each data-type e.g. PersonDAO which supports operation addPerson(Person), getPerson(long id), removePerson(long id), .... UserDAO with methods addUser(User), getUser(long id), removeUser(User), ... With DAO per class-type there would be no return type conflict. If this is the first time you heard about DAO pattern, then I would recommend you to search some topics about what is DAO and why it is so useful. – matoni Dec 14 '17 at 17:00
0

Well you can define type parameters on class level(in your case A and B) and on method level(G). If you make new class K that implements ICOperations you should say for example: public class K<String, Integer> ... and <Long> Long methodName(String s). That mean that your will pass String as parameter in your method from class K and you will receive Long as an answer.

Spasoje Petronijević
  • 1,476
  • 3
  • 13
  • 27
  • 1
    My doubt was about another concept that i think that i clarify it. Corretc me it i make a mistake: I have two ways to use letters in a generic interface: The first way if i passed the letters to the interface ( A, B ) The second way is with the method G methodName(A a); If i write only G methodName(A a) the compiler say that G is never defined. If i write G methodName(A a); if function correctly, so i think that in this case i am creating a new Type Parameter for my method, and in all the other cases i think that we ovveride the Type Parameter from Interface definition. – lirio oliro Dec 14 '17 at 14:01
0

Thanks to everyone that respond. I think that i made a confusion in general about different concept in java.

1 Concept If i implements an interface from a class i should override all the method of the interface at my class. So at my class i will override method.

2 Concept if i desire to use a parametrized type as a method parameter in a generic method i should define it as parameter type of the interface otherelse i will receive compile error.

//i passed B as Parameter to my interface and i use it at my method as parameter

public interface ICOperations<B> {
  <A> A findById(B b);

//i don't passed the B as parameter type at my interface so when i passed it as method parameter the compiler say to me that i dont know the symbol B.

public interface ICOperations {
  <A> A findById(B b);

If i dont define a letter at my interface definition (in my case i have only A and B :

public interface ICOperations<A,B>

but i need to create a new letter i need to use the diamond annotation ( and here we arrive at the point that i say about the letter G.

<G> G deleteById(A a);

In this case we totally loose the Type Safety because it has no connection with the interface itself.

When we create a Generic Interface ( in my case: public interface ICOperations<A,B> i am defining that this interface will be composed from two type ( A and B ) and every class that will implement my interface shoud define the type to substitute A and B. I create a class called Operations: public class Operations implements<Integer,String> , Now i have the definition of the interface as this:

public interface ICOperations<A,B>{
    A findById(B b)
}

and the definition of my class as: public class Operations implements<Integer,String>

And when i override my method i should define :

public class Operations implements ICOperations<Integer,String>

   @Overrided
   Integer deleteById(String id){
  //some code here
}
lirio oliro
  • 21
  • 1
  • 7