1

After reading some of examples I still can't quite get what Generics are. The best explanation I found so far would be What does <> (angle brackets) mean in Java?

From what I read you do not need to cast return value to type if you use generics.

But what Generics actually do? From what I understood is that make sure(?) that returned value is already cast to the type defined in brackets.

But that would imply, that Java requires every assign to be cast.

String str = (String) otherstring;

is proper, and

String str = otherstring;

is not proper.

So from what I understood generic <String> would make sure the value is cast before its assigned, so we do not have to cast it?

Do Java need every value to be cast even if its of same type already?

Community
  • 1
  • 1
Grzegorz
  • 3,538
  • 4
  • 29
  • 47
  • Main idea of generic is to overcome run time exception and provide compile time warning. – someone Feb 16 '15 at 09:37
  • Java typically doesn't need any type cast, except in the special situation of down-casts, which should be avoided. If you have to cast with Generics, it is because you are working with a library that doesn't use generics, but you do. Or, you are doing something that could be unsafe, or you are attempting to bend a class designed for generics to do something it wasn't designed to do. Sometimes such scenarios are valid (but not often), so there's a casting operation permissible for those corner cases. Try not to use them. – Edwin Buck Feb 16 '15 at 10:09

4 Answers4

1

PHP is easier in a sense, but that's just because it doesn't concern itself with some of these issues. With PHP you deal with the issues later.

Casting is basically in one of two directions (up or down). An up-cast is stating that you would prefer to work with the object only through the interface of a class that it inherits from (or inherits the interface of).

For example, if I have a FileInputStream, I could change it to "just" an InputStream

FileInputStream fileInput = ...
InputStream input = (InputStream)fileInput;

Note that this have exactly zero effect on implementation of the reachable methods; but is does sometimes hide methods that were previously available.

fileInput.getFileName();  // let's pretend this works
input.getFileName(); // this shouldn't work, as any InputStream doesn't have a file name.

Downcasting is different (and dangerous). You basically state that even though you have an InputStream, somehow you know that it should be treated as a FileInputStream

InputStream input2 = ...;
FileInputStream fileInput2 = (FileInputStream)input2;

If the input2 in this scenario doesn't have the appropriate type of a FileInputStream, then you will get a class cast exception at runtime. If it does have the appropriate type, then fileInput2 will be assigned.

The main reason for such a typing system is so you can easily write reusable components. The "higher" types (cast up types) specify general contracts, while the "lower" types (cast down types) specify specific details that vary within the general contracts specified by their super-types.

Generics; however, are a different ball of wax. Basically when dealing with Collections, and things that relate to Collections, the rules are similar (but must be different due to a number of reasons).

One of the reasons generics act differently is backwards compatibility. The design goal of adding "extra" type information to an already existing type (like a java.util.List) meant that for mixed generics and non-generics use, the type effectively cannot exist at runtime. This property of the generic type not being considered present at runtime is called "erasure". In short, when you write

List<Student> students = new ArrayList<Student>();

you are effectively compiling

List students = new ArrayList();

But your compiler will do "extra" work to make sure that in any bit of source code you write, you can only add a "Student" object. Likewise, when you read across the List, you don't need to cast to a "Student" object, as the compiler will assume only "Student" objects can be in the list.

Note that for such a system to work, it is compile-time only. This means that they details of type hierarchy and run time casting don't apply. This reflects itself in the new type constraints added by generics.

T extends Student

means that T can be cast to a Student (up cast)

T super Student

means that T is a super class of Student This latter one is tricky, but useful in certain scenarios.

If CollegeStudent, HighSchoolStudent, and GradeSchoolStudent all extend Student, then all three types of Student can be stored in a List<? extends Student> at the same time.

If something needs to assure that a Collection will at least provide Students, you can then give is a List<? super Student>.

public void studentProcessor(Collection<? super Student> students);

could process a List<Student>, a List<CollegeStudent>, a List<GradeSchoolStudent>, etc.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • https://developer.android.com/training/load-data-background/setup-loader.html I have here CursorLoader returned. But in definition there is . Meaning I will get CursorLoader stripped cast up to Cursor before returning? – Grzegorz Feb 16 '15 at 09:48
  • @Gacek In your case the means that while you are dealing with a wrapper of another type, the wrapper can only contain a Cursor. You cannot make any assumptions that it is a particular sub-class of Cursor, nor can the wrapper be accessed as a mixed collection of unknown types that all happen to be Cursors. To restate this second restriction another way, everything below the Cursor type is forbidden for you to know. – Edwin Buck Feb 16 '15 at 09:57
  • Now I start to understand it. Need to dig in some more details about basics of Java to probably fully understand it. Thank you for your detailed explanation (Thanks to everyone for theirs too!) – Grzegorz Feb 16 '15 at 10:14
  • @Gacek Glad to help. Good luck with it. – Edwin Buck Feb 16 '15 at 10:19
  • According to the last portion of your answer :- `public void studentProcessor(Collection super Student> students);` could process a List, a List, a List, etc. But since CollegeStudent and GradeSchoolStudent are subclasses of Student they cannot be added to `? super Student` , maybe super class of `Student` like `Person`, then `List` could be processed – Mustafa sabir Feb 17 '15 at 06:34
0

The difference between casting and the use of generics, is that they are a compile-time mechanism. Meaning, that instead of getting a runtime exception, the code below simply won't compile:

Clazz <T> c = new Clazz <U> ();

if T cannot be cast to U.

Michał Szydłowski
  • 3,261
  • 5
  • 33
  • 55
0

A generic class provides functionality for any object you can imagine - this handled class is sometimes called your parameter. For example the java.util.List interface and its implementing classes, e.g. ArrayList<E> provide list functionality (adding of elements, removing of elements, element counting, etc...) for an arbitrary type E (it could be used for managing a list of your very own type Maroun). The implementation of the generic type has to be independent of the parameter it handles. In the example - List is independent from Maroun

So the concept of generics has pretty much nothing to do with typecast, as you can see ;)

0

Use generics when you have a class for which an instance can be parametrized by type. The common example is a collection.

Before generics, a Collection included many objects which were classified as just that, Objects. Although chances are that the objects had more specific types that could not be recognized by the compiler, and therefore required dangerous runtime casting to the actual types.

Now you can parametrize Collection<E> where E is the element type. Now the compiler can make sure that a Collection<Foo> only has Foo instances added to it, and it can return typed Foo instances with no casting required.

The111
  • 5,757
  • 4
  • 39
  • 55