Reputation: 21
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 ?
Upvotes: 1
Views: 3622
Reputation:
<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.
Upvotes: 1
Reputation: 21
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
}
Upvotes: 0
Reputation: 393781
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
.
Upvotes: 2
Reputation: 1598
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.
Upvotes: 0