I was wondering, aside from syntactic difference, when would one use a generic interface over a method that accepts a generic parameter?
public interface Flight<T>{
void fly(T obj);
}
over
public interface Flight{
void <T> fly(T obj);
}
If you declare a generic method, you always let the caller decide, which type arguments to use for the type parameters. The implementation of the method must be able to deal with all possible types arguments (and it doesn’t even have a way to ask for the actual type arguments).
That said, a method like <T> void fly(T obj); states that the caller may use any type for T while the only thing the implementation can rely on is that the actual type for T will be assignable to Object (like if <T extends Object> had been declared).
So in this specific example, it’s not different to the declaration void fly(Object obj);, which also allows arbitrary objects.
In contrast, a type parameter on an interface is part of the contract and may be specified or restricted by an implementation of the interface:
public interface Flight<T>{
void fly(T obj);
}
allows implementations like
public class X implements Flight<String> {
public void fly(String obj) {
}
}
fixing the type of T on the implementation side. Or
public class NumberFlight<N extends Number> implements Flight<N> {
public void fly(N obj) {
}
}
being still generic but restricting the type.
The signature of an interface is also important when the interface itself is a part of another method signature, e.g.
public void foo(Flight<? super String> f) {
f.fly("some string value");
}
here, the Flight implementation, which you pass to foo, must be capable of consuming a String value, so Flight<String> or Flight<CharSequence> or Flight<Object> are sufficient, but not Flight<Integer>. Declaring such a contract requires type parameters on the interface, not at the interface’s methods.
You should use a generic type when you expect that most of the methods, in the implementations, will perform operations on the type supplied when instantiating the class.
For example, ArrayList<E> is a generic type since most of its operations (add, get, remove etc.) rely on the type specified upon creation of one.
A generic method should be used when only a few methods in the class rely upon the different types.
You can read more about generics in the Java Docs.
Take for example the class java.util.ArrayList<E>. When creating variables of that type, you have to specify a concrete type for T:
ArrayList<String> list = new ArrayList<>();
These concrete types are used, when calling methods from the List interface, that work with the type T. Calling the add method, you can only add String objects to the list. Retrieving elements from the list using get, you will get elements of the concrete type String.
For generic methods, the type T is specified only for this method. And it would make more sense if the methods returns a value of that generic type. You often find code like this:
MyObject obj = SomeClass.staticGenericMethod(MyObject.class)
or
MyObject obj = classInstance.genericMethod(MyObject.class);
And you should start your interface name with a capital letter: Flight<T>
Related
Why a generic static method have a in addition to return type, but a instance method not?
public class Main<T> {
public static <T> T met(T t) {
return t;
}
public T met1(T t) {
return t;
}
}
An instance method can also define the generic type parameter (<T>) in front of the return type, but it doesn't have to, since it can use a generic type parameter already defined in the class level (public class Main<T>).
On the other hand, a static method cannot use the generic type parameter defined in the class level, so it must declare any generic type parameter it intends to use.
i.e. both of the following are valid
public static <T> T met(T t) {
return t;
}
public <T> T met1(T t) {
return t;
}
On the other hand, in the following
public static T met(T t) {
return t;
}
T is assumed to be a type identifier (i.e. the name of some class or interface), and not a generic type parameter.
First, we need to understand what is the "addition". Is it NOT an addition to the return type. It is a "Bounded Type Parameters"
Bounded Type Parameters There may be times when you want to restrict
the types that can be used as type arguments in a parameterized type.
For example, a method that operates on numbers might only want to
accept instances of Number or its subclasses. This is what bounded
type parameters are for.
When you compile your generic class/method/interface. Java compiler converts generic type to code that JVM understands. This process is call type erasure and it requires to know bounds of generic's type parameters. i.e. <T> get converts to Object because it is unbounded and <T extends Comparable<T>> get converts to Comparable
Second, why does a generic static method requires bounded type parameters whereas a generic instance method does not?
This kind of goes hand in hand with the difference between class method and instance method.
When you use the key word static the method becomes a class method. Which means you can invoke without a creating an instance. And that is the problem. Because static method is shared among all instances of the class including instances of different type parameters, Java doesn't know what T is until you instantiate a type. We need to explicitly tell the compiler what instance the class method should expect.
When you don't use the key word static the method is now an instance method. Which means you can't invoke the method until you create an instance of the class. When creating an instance you would need to specify the type parameter. Java compiler can inherently use that type parameter when you invoke instances method so bounded type parameter is optional for instance method.
There is two aspects to this:
A)
Instance methods implicitly acquire all the class type-parameters whereas the static don't. The reason for this is that at compilation time the type assigned to those type-parameters are specific to each object instance reference, so they would never apply to static methods since these don't have a particular instance associated to them.
B)
All methods, instance or class ones can defined additional type-parameters that only apply to that method. These are placed between the modifiers (public, static, ...) and the return type. That is just an arbitrary syntax choice made by the Java language developers. So they could have done it differently, however it makes more sense to have to declare something before it is ever used (e.g. in the parameter type declaration).
for example:
public String add(Set<?> t){
...;
}
public <T> String add(Set<T> t){
...;
}
The first uses wildcard generics; the second is the normal form of a generic method.
What's the difference?
In what situation do we need wildcard generics, not the normal form of generics?
Here is a situation where wildcards are required. This method takes a List<List<?>>, which is a list of lists. The method can add lists of different component types into it:
public void foo(List<List<?>> t) {
t.add(new ArrayList<String>());
t.add(new ArrayList<Integer>());
}
You cannot do this using generic type parameters without wildcards. For example, the following does not work:
public <T> void foo(List<List<T>> t) {
t.add(new ArrayList<String>()); // does not compile
t.add(new ArrayList<Integer>()); // does not compile
}
Since support for generics was added, using a parameterized type without providing a type parameter usually causes a compiler warning. On the other hand, there are situations where you don't care at all what the type parameter is (i.e. you don't use the type anywhere) or, even worse, you might not know what T is at all, and using <?> lets you express just that without causing a compiler warning.
Possible use case for the "don't care" case (very simple for brevity, but you get the idea):
public void clearList(List<?> list) {
list.clear();
}
An example for the "don't know" case: an actual method signature from Class class:
static Class<?> forName(String className);
Here the method returns an object of some Class type. Class is generic but of course you don't know the type because it depends on the className parameter which is resolved at runtime. So you can't put T here since T is not known at compile time (even for a particular call site), and using just Class without type parameter would be a bad practice and cause a compiler warning.
The wildcard form is when you don't mind what types of objects you are handling.
The generics form allows you to add contraints on the type of objects handled.
An example use case could be the following :
a generic repository with add/update/remove methods, you define common behavior using the generic type :
public class Repository<T>{
public void add(T t){...}
public void update(T t){...}
public void remove(T t){...}
}
Then to make a repository for Apple and Banana you just extend this class and replace T with the real type :
public class AppleRepo extends Repository<Apple> {}
public class BananaRepo extends Repository<Banana> {}
If the generic Repository was declared as Repository<?>, it would not be good because it is not restricted to Banana, and you would not be able to use Banana specific methods inside it without casting objects;
Also the generics allow you to express further constraints, for example
Repository<T extends Fruit>
allows you to restrict the generic repository class to fruits. And you will be able to make calls to Fruit methods in its code.
There's not difference in calling the methods.
In the second method (add(Set<T>)) you can create variables of type T:
public <T> String add(Set<T> t){
T item = t.iterator().next();
//....
}
That gives you some additional type checking.
In the first method you're left with using Object.
What are advantage between a generic method and a method just accepts Object? How does it ensures type safety?
For example: What difference does it make when define my interface in either of the form mentioned in below code snippet?
public interface MyInterface {
public <MT> String myMethod(MT t);
}
OR
public interface MyInterface {
public String myMethod(Object t);
}
In my opinion Generic methods are advantageous only when we type bound around it.. for example type parameter should of Serializable class like. Otherwise it doesn't make sense.. looking for more insight
public interface MyInterface {
public <MT extends Serializable> String myMethod(MT t);
}
A method is usually made generic to ensure that two arguments are compatible with each other, or to return a value whose type depends on the generic type of the method.
For example,
public static <T> void sort(List<T> list, Comparator<? super T> c)
makes sure the type of the list and the type of the comparator are compatible, which wouldn't necessary be the same if the signature was
public static void sort(List list, Comparator c)
In the following example, the returned value's type depends on the generic type of the method:
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
which allows doing:
List<Integer> intList = ...;
Integer min = Collections.min(intList);
If the method was
public static Comparable T min(Collection coll)
you would have to do
Integer min = (Integer) Collections.min(intList);
and you wouldn't have any warning from the compiler if you changed the code to
Long min = (Long) Collections.min(intList);
It can be also nice to see what it means from the compile/runtime point of view.
If you use generics, then the compiler generates the necessary code during compilation and you would't do runtime casting on your relevant objects and/or type checking.
On the other hand, if you use only the Object class as a generic type, you would probably end up having slightly less code (since the compiler wouldn't be generating anything) but you would need to take care of runtime type safety and casting by yourself.
You are partially correct. Generic method and method as a object look like same in some context but the major difference is how compiler handles both
For the object as params type conversion is done based on the typecasting basically it is being handled runtime but for the generic type compile time only it is being handled.
Compile time handling is much better than the run time one. So the generic method is good to use as compare to object as a parameter in your context
Generic method restricts the type of parameter that can be passed to the method. That brings in more cohesive code which limits the input that it can work on, and thus can be reasonably assumed to have certain features.
For e.g
public interface MyInterface {
public [MT extends BaseClass] String myMethod(MT t);
}
Here you always know that all the methods that are applicable for BaseClass are applicable to t in this method.
I recently came upon an instance of the following pattern:
public interface IFooFactory {
<K> Foo<K> create();
}
See here for a concrete example. I don't see what a client programmer is supposed to do in the implementation of create other than instantiate Foo with a formal type parameter of Object or with no formal type parameter at all. I also don't see what's the benefit or type constraint that the framework designer tried to express by defining the interface IFooFactory in this way.
Consider Collections.emptyList(). The list object returned is always the same: since the list is empty and immutable, there is nothing the caller can do with the object returned in order to make it show different behaviour depending on the concrete type substituted for the type parameter. So, a single implementation (with raw types) suffices:
public static <T> List<T> emptyList() {
return THEEMPTYLIST;
}
public static final List THEEMPTYLIST = new List() {
public int size() { return 0; }
...
};
The emptyList method makes this more convenient for the caller, though, since it enables type inference:
List<String> noStrings = Collections.EMPTY; // Gives compiler warning due to use of raw types
List<String> noStrings2 = Collections.emptyList(); // No compiler warning, type parameter inferred.
The benefit is for the user of the method, not the implementer. Collections.emptyList() is a good example of a beneficial use of this pattern. It allows you to declare an empty list like this:
List<String> myEmptyList = Collections.emptyList();
Had the method returned a raw List, List<Object>, or List<?>, using the method in this way would require a cast.
I don't see what a client programmer is supposed to do in the
implementation of create other than instantiate Foo with a formal type
parameter of Object or with no formal type parameter at all.
Umm... It's very easy...
<K> Foo<K> create() {
return new Foo<K>();
}
I have n number of java classes each containing its own set of variables.
I have a method which has to accept one of these n classes as a parameter based on some condition.
How can I make all these classes as subclasses to a generic type so that my method signature accepts all these different types? I dont want to overload the method. And if use the type 'Object' for the parameter, I am losing the nature of the input param class I am passing.
Define an interface that all your classes implement. Then declare your parameter in the method's head as the type of that interface.
Is this what you want?
public interface common<T extends common<?>> {
public void commonMethod(T param, ...);
}
public class child implements common<child> {
public void commonMethod(child param, ...) {
...
}
}
How can I make all these classes as subclasses to a generic type so that my method signature accepts all these different types?
Simple make an abstract class, MySuperClass, this class gets inherited by all the classes you wanted to be passed to the Method. This super class have common functionality and attributes.
The other way, if your subclasses are likely to extend other class; or, there is nothing common among the class (except the fact that they all are passed to the method of yours) you can have an interface, say MySuperClass (well ideally, I like interface to start with I, like IMySuperClass).
I dont want to overload the method.
Once you have your super-class, or interface ready, your method signature would look something like myMethod(Param1 val1, MySuperClass myObj, Param3 val3).
Simple.
If you can't use polymorphism (as suggested by the others), then you could use Java generics to do this:
E.g. this can be used to put any object into a cache:
public <T> void doSomethingWithObject(final T object) {
...
}
And you could call it like this: e.g. using String
yourInstance.<String> doSomethingWithObject(object);