Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Latest commit

 

History

History
History
309 lines (229 loc) · 9.08 KB

File metadata and controls

309 lines (229 loc) · 9.08 KB
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
/*
# Generics
Introduced in Java 5 to allow more compile time checks.
Incurs not runtime cost because of type erasure.
# Templates
Superficially similar concept in C++, but in C++ templates compile exactly to code,
while Java also relies on polymorphism TODO check.
Both types and methods can be generic. both will be commented here.
# Vs polymorphism
<http://programmers.stackexchange.com/questions/227918/java-use-polymorphism-or-bounded-type-parameters>
In many cases, are the same.
In a few cases, generics are more powerful.
Only use them if you need the extra capabilities,
as they make the code harder to read.
Cases where they are needed:
- the type of a function parameter is parametrized by the type
- return value
TODO understand why in those cases are necessary.
# Parametrized types
Types that depend on other types, e.g. `LinkedList<String>`.
# Type arguments
Types passed to parametrized types. E.g. `String` in `LinkedList<String>`.
*/
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class GenericsCheat {
public static <T> T genericMethod(T i) {
return i;
}
public static <T> String genericGetClass(T i) {
return i.getClass().getSimpleName();
}
//public static <T> T genericGetInstance() {
//return what?
//}
//public static <T> Class<T> genericGetClassDotClass(T t) {
//return T.class;
//}
public static <T> String genericMethodGenericArgument(List<T> l) {
return l.getClass().getSimpleName();
}
public static class GenericStatic<T> {
static int i = 0;
}
public static void main(String[] args) {
/*
# Raw types
Generic types but without passing the generic arguments.
This is how Java was before 1.5: the syntax is only kept for backwards compatibility.
Never use this on new code, as you lose compile time checks.
The main reason that generics are useful is that most collections contain a single type of objects.
Generics then add typecasts and typechecks automatically for us.
*/
{
// The pre 1.5 raw types way.
{
@SuppressWarnings({ "rawtypes" })
ArrayList names = new ArrayList();
@SuppressWarnings({ "unchecked" })
boolean b = names.add("abc");
@SuppressWarnings({ "unchecked" })
boolean b2 = names.add(1);
// Object returned by default.
Object name = names.get(0);
// We've done this cast correctly.
name = (String)name;
assert(name.equals("abc"));
boolean fail = false;
try {
name = (String) names.get(1);
} catch (ClassCastException e) {
fail = true;
}
assert fail;
}
// After generics: see how much better this is than with raw types
// if our container is supposed to contain only a single data type.
{
ArrayList<String> names = new ArrayList<>();
names.add("abc");
// No cast needed on the output!
assert(names.get(0).equals("abc"));
// Fail on compile time.
//names.add(1);
//names.add((String)1);
boolean fail = false;
try {
// Compiles, but we've asked for trouble with a double cast.
// And now the exception happens before insertion, not after retrival.
names.add((String)(Object)1);
} catch (ClassCastException e) {
fail = true;
}
assert fail;
}
}
/*
Primitive types cannot be passed as type arguments.
What happens in most cases is that primitive wrappers are used instead,
and boxing and unboxing conversions produce the eye candy.
*/
{
// ERROR: unexpected type.
//LinkedList<int> l;
LinkedList<Integer> m;
}
/*
# Generic method
*/
{
Object o = new Object();
assert GenericsCheat.<Object>genericMethod(o) == o;
// In this case however the type can be inferred from the argument.
assert genericMethod(o) == o;
/*
If you want to pass the type parameter explicitly,
you need to add explicitly:
- the name of the class for static methods
- `this.<T>method()` for instance methods
*/
{
// ERROR
//.<Object>genericMethod(o);
//<Object>genericMethod(o);
}
}
// Impossible stuff wigh generics.
{
/*
# Call constructor of generic type
# Instantiate generic type
Not possible without reflection:
http://stackoverflow.com/questions/75175/create-instance-of-generic-type-in-java
*/
{
//Integer i = genericGetInstance();
}
/*
# Use .class on generic
Not possible because of type erasure.
http://stackoverflow.com/questions/18255117/how-do-i-get-the-class-attribute-from-a-generic-type-parameter
*/
{
//assert Main.<Object>genericGetClassDotClass() == Object.class;
}
// Use generics with static members.
{
// As a consequence, you must access static members without the generic parameters:
// ERROR: Not a statement.
//assert GenericStatic<Integer>.i == 0;
assert GenericStatic.i == 0;
}
}
/*
# Type inference for generics
# <>
# Diamond
Java 7 Coin Project feature.
Java can sometimes infer types, and in that case you can simply write TODO check:
- `<>` for the type parameters of constructors
- nothing for method calls
The rules of type inference are complex and described at:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12
There have been considerable changes in Java 8.
*/
{
// Generic class.
{
// Infer type from argument.
assert genericGetClass(new Object()).equals("Object");
// Infer type from return value. TODO
genericMethodGenericArgument(new ArrayList<>());
/*
Return value to method call inference did not work in Java 7,
likely because of the complication that methods can be overloaded.
This has changed in Java 8.
http://stackoverflow.com/questions/15435747/java-7-generics-type-inference
*/
// Does not work with anonymous subclasses.
//http://stackoverflow.com/questions/9773733/double-brace-initialisation-anonymous-inner-class-with-diamond-operator
}
}
/*
# Type erasure
Compiled bytecode does not contain any special instructions for it.
Wildcards are simply compiled to the most base possible type:
e.g. `List<? extends Number>#get()` compiles to `(Number)List#get`.
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
TODO understand this for real.
# Reified generics
http://stackoverflow.com/questions/879855/what-are-reified-generics-how-do-they-solve-the-type-erasure-problem-and-why-ca
A feature which is not part of the language, but would allow for more flexible generics.
*/
/*
Generics and instanceof
*/
{
ArrayList<String> s = new ArrayList<>();
assert s instanceof ArrayList;
// ERROR. Makes no sense: generics don't generate actual new types:
// only a bunch of automatic typechecks on `.add()`, .get()`, etc.
//assert s instanceof ArrayList<String>;
}
/*
# Unbounded wildcard
# <?>
http://docs.oracle.com/javase/tutorial/java/generics/unboundedWildcards.html
Applications:
- ignore the type
- something that extends from Object, since very class does so.
TODO examples.
*/
{
}
/*
Generics and typecasts
*/
{
ArrayList<String> s = new ArrayList<>();
ArrayList<Integer> i = new ArrayList<>();
ArrayList<Number> n = new ArrayList<>();
//s = i;
//i = n;
//n = i;
//n = (ArrayList<Number>)i;
}
}
}
Morty Proxy This is a proxified and sanitized view of the page, visit original site.