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.
Related
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>
The type erasure page says that
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
However, for the following class:
public class Foo<E extends CharSequence> {
public E something;
}
javap -c Foo prints:
public class Foo<E extends java.lang.CharSequence> {
public E something;
}
Why is the type parameter not replaced with the bound (CharSequence), but is preserved as E?
What you printed isn't bytecode. It is the method signature. It's put there so the compiler can enforce typesafety when compiling other classes that call it.
Type information is preserved on classes and methods, but not on actual fields. If you wrote
class Foo extends Bar<String> {
}
...you could extract Bar<String> at runtime, but if you had
new Bar<String>();
...you could not extract Bar<String> there.
I agree with #user207421 answer. One can differentiate between raw types and complete generic type by trying out the following code:
public class App {
public static void main(String args[]) {
Foo raw = new Foo(Something);
}
}
When you check the bytecode for this class, you will find that E is missing. So this is a raw type. These raw types are not bounded and may even require casting due to which Exceptions might be thrown. That is why Generics are used; to ensure type safety. It is a complete source code mechanism.
The type parameter is preserved because it must be known for sub-classing.
Definitions
public class Foo<E extends CharSequence>
and
public class Foo<CharSequence>
are NOT equal, since latter would not allow sub-class to be declared as, say:
public class MyStringFoo extends Foo<String> { }
whereas former does.
The build method below creates an instance of TypedMemberDTO.
TypedMemberDTO can contain a typed List
The Member.getDetails returns an Object type, which I know will only be one of 2 types at runtime. These types have nothing in common apart from extending Object.
What I want to do is create a build method that uses generics to set the details in the TypedMemberDTO.
The code compiles fine, and runs fine, although I'm a bit confused as to what the <U> typing actually provides me.
In reality, if I used raw types here instead of <U>, would I have achieved the same compile time benefits?
Is there a better way to write the build method?
public class TypedMemberDTO<T> extends MemberDTO {
private List<T> details;
public List<T> getDetails() {
return details;
}
public void setDetails(List<T> details) {
this.details = details;
}
}
public <U> TypedMemberDTO<?> build(Member member, String attributeName) {
TypedMemberDTO<U> typedMemberDTO = new TypedMemberDTO<U>();
List<U> dtos = (List<U>) member.getDetails(attributeName);
typedMemberDTO.setDetails(dtos);
return typedMemberDTO;
}
Generics don't exist at runtime. They are only used at compile time to allow your code to avoid as many ClassCastExceptions at runtime as possible by avoiding coerced casts. But at runtime, the type of objects belonging to generic classes is simply the raw type.
This means that if your Member class is not generic, as the compiler cannot tell what kind of List it has returned, there is no difference between using this and using raw types.
Generic methods are there to impose particular constraints on the relationship between parameter types and return type or between the type of one parameter and another. In this case, you do not have any mention of the generic type U in the parameter list. So in essence, it checks nothing.
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'm familiar with simple class declaration public class test but I don't understand public class test<T>.
< T > refers to a generic type.
Generic types are introduced in Java to provide you with compile time, and this is important due to type erasure, type-safety.
It's especially useful in Collections because it frees you from manual casting.
It is a good idea to read more on generics, especially the documentation on the topic by Angelika Langer is very good: http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
I assume that HTML ate your <T> (you need to write <T> to display it)
T is a type parameter or "generic" parameter. Say you have a List. Then it is for the structure of the list unimportant what exactly you are storing there. Could be Strings, Dates, Apples, SpaceShips, it doesn't matter for list operations like add, remove etc. So you keep it abstract when defining the class ("this is an abstract list"), but specify it when you instantiate it ("this is a list of Strings")
//in Java, C# etc would be similar
//definition
public class List<T> {
public void add(T t) { ... }
public void remove(T t) { ... }
public T get(int index) { ... }
}
//usage
List<String> list = new List<String>();
list.add("x"); //now it's clear that every T needs to be a String
...
You are probably referring to Java Generics:
http://www.oracle.com/technetwork/java/javase/generics-tutorial-159168.pdf
This is parametric polymorphism, another important form of polymorphism other than subtyping.
In Java land, they call it Generics (see also Lesson: Generics).