0% found this document useful (0 votes)
3 views40 pages

15prog2_JavaGenerikus

Generics in Java allow types to be parameters for classes, interfaces, and methods, enhancing code reusability and type safety. They provide benefits such as stronger compile-time type checks, elimination of casts, and the ability to implement generic algorithms. The document also covers generic classes, methods, bounded type parameters, wildcards, and type erasure, illustrating their usage and syntax with examples.

Uploaded by

orsika2004
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
Download as pptx, pdf, or txt
0% found this document useful (0 votes)
3 views40 pages

15prog2_JavaGenerikus

Generics in Java allow types to be parameters for classes, interfaces, and methods, enhancing code reusability and type safety. They provide benefits such as stronger compile-time type checks, elimination of casts, and the ability to implement generic algorithms. The document also covers generic classes, methods, bounded type parameters, wildcards, and type erasure, illustrating their usage and syntax with examples.

Uploaded by

orsika2004
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1/ 40

Generics

• In a nutshell, generics enable types (classes


and interfaces) to be parameters when
defining classes, interfaces and methods.
Much like the more familiar formal
parameters used in method declarations, type
parameters provide a way for you to re-use
the same code with different inputs. The
difference is that the inputs to formal
parameters are values, while the inputs to type
parameters are types.
Generics
• Code that uses generics has many benefits over
non-generic code:
• Stronger type checks at compile time.
A Java compiler applies strong type checking to
generic code and issues errors if the code violates type
safety. Fixing compile-time errors is easier than fixing
runtime errors, which can be difficult to find.
• Elimination of casts.
• Enabling programmers to implement generic
algorithms.
• By using generics, programmers can implement
generic algorithms that work on collections of different
types, can be customized, and are type safe and easier
to read.
Generics
• A generic type is a generic class or interface that is
parameterized over types.
• A generic class is defined with the following format:
class name<T1, T2, ..., Tn> { /* ... */ }
• The type parameter section, delimited by angle
brackets (<>), follows the class name. It specifies
the type parameters (also called type
variables) T1, T2, ..., and Tn.
• A type variable can be any non-primitive type you
specify: any class type, any interface type, any array
type, or even another type variable.
• This same technique can be applied to create
generic interfaces.
Generics
• By convention, type parameter names are
single, uppercase letters.
• The most commonly used type parameter
names are:
• E - Element (used extensively by the Java
Collections Framework)
• K - Key
• N - Number
• T - Type
• V - Value
• S,U,V etc. - 2nd, 3rd, 4th types
Generics
public interface Pair<K, V> {
public K getKey(); public V getValue(); }

public class OrderedPair<K, V> implements Pair<K, V> {


private K key; private V value;
public OrderedPair(K key, V value) {
this.key = key;
this.value = value; }
public K getKey() {
return key; }
public V getValue() {
return value; }
}
Generics
Pair<String, Integer> p1 =
new OrderedPair<String, Integer>("Even", 8);
Pair<String, String> p2 =
new OrderedPair<String, String>("hello", "world");
Generics
• To reference the generic class from within your
code, you must perform a generic type invocation,
which replaces T with some concrete value, such
as Integer.
• You can think of a generic type invocation as being
similar to an ordinary method invocation, but
instead of passing an argument to a method, you
are passing a type argument.
• An invocation of a generic type is generally known
as a parameterized type.
• To instantiate this class, use the new keyword, as
usual, but place i.e <Integer> between the class
name and the parenthesis.
Generics
• You can replace the type arguments required to
invoke the constructor of a generic class with
an empty set of type arguments (<>) as long as
the compiler can determine, or infer, the type
arguments from the context. This pair of angle
brackets, <>, is informally called the diamond.

OrderedPair<String, Integer> p1 =
new OrderedPair<>("Even", 8);
OrderedPair<String, String> p2 =
new OrderedPair<>("hello", "world");
Generics
• You can also substitute a type parameter with a
parameterized type:
OrderedPair<String, Box<Integer>> p =
new OrderedPair<>("primes",
new Box<Integer>(...));
Generics
• Generic Methods
• Generic methods are methods that introduce their
own type parameters. This is similar to declaring a
generic type, but the type parameter's scope is
limited to the method where it is declared. Static
and non-static generic methods are allowed, as
well as generic class constructors.
• The syntax for a generic method includes a list of
type parameters, inside angle brackets, which
appears before the method's return type. For static
generic methods, the type parameter section must
appear before the method's return type.
Generics
• Generic Methods
public class Util {
public static <K, V> boolean
compare(Pair<K, V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue()); }
}
Generics
• Generic Methods
public class Pair<K, V> {
private K key; private V value;
public Pair(K key, V value) {
this.key = key; this.value = value; }
public void setKey(K key) { this.key = key; }
public void setValue(V value) { this.value = value; }
public K getKey() { return key; }
public V getValue() { return value; }
}
Generics
• Generic Methods
Pair<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "pear");
boolean same = Util.<Integer, String>compare(p1,p2);
Generics
• Generic Methods
The type has been explicitly provided, as shown in
bold. Generally, this can be left out and the compiler
will infer the type that is needed:
Pair<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "pear");
boolean same = Util.compare(p1, p2);

This feature, known as type inference, allows you to


invoke a generic method as an ordinary method,
without specifying a type between angle brackets.
Generics
• 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.
• To declare a bounded type parameter, list the type
parameter's name, followed by the extends keyword,
followed by its upper bound, which in this example
is Number. Note that, in this context, extends is used
in a general sense to mean either "extends" (as in
classes) or "implements" (as in interfaces).
Generics
• Bounded Type Parameters
class Sample <T extends Number>{
T data;
Sample(T data){
this.data = data; }
public void display() {
System.out.println("Data value is: "+this.data); } }
Generics
• Bounded Type Parameters
public class BoundsExample {
public static void main(String args[]) {
Sample<Integer> obj1 =
new Sample<Integer>(20);
obj1.display();
Sample<Double> obj2 =
new Sample<Double>(20.22d);
obj2.display();
Sample<Float> obj3 =
new Sample<Float>(125.332f);
obj3.display();
Sample<String> obj4 = new Sample<String>(“Apple"); //error String
obj3.display();
}}
Generics
• Bounded Type Parameters
• Bounded type parameters allow you to invoke
methods defined in the bounds:
public class NaturalNumber<T extends Integer> {
private T n;
public NaturalNumber(T n) { this.n = n; }
public boolean isEven() { return n.intValue() % 2 == 0; }
// ... }
Generics
• Bounded Type Parameters
• a type parameter can have multiple bounds:
<T extends B1 & B2 & B3>
• A type variable with multiple bounds is a subtype of
all the types listed in the bound. If one of the bounds
is a class, it must be specified first.
Generics
• Bounded Type Parameters
public static <T> int countGreaterThan(
T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e > elem) // compiler error
++count;
return count;
}
Generics
• Bounded Type Parameters
public static <T extends Comparable<T>>
int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e.compareTo(elem) > 0)
++count;
return count;
}
Generics
• Generic Classes and Subtyping
• https://
docs.oracle.com/javase/tutorial/java/generics/inherit
ance.html

interface PayloadList<E,P> extends List<E> {


void setPayload(int index, P val); ... }
Generics
• Wildcards
• In generic code, the question mark (?), called
the wildcard, represents an unknown type. The
wildcard can be used in a variety of situations: as the
type of a parameter, field, or local variable;
sometimes as a return type (though it is better
programming practice to be more specific). The
wildcard is never used as a type argument for a
generic method invocation, a generic class instance
creation, or a supertype.
Generics
• Wildcards
• Upper Bounded Wildcards
• You can use an upper bounded wildcard to relax the
restrictions on a variable. For example, say you want
to write a method that works
on List<Integer>, List<Double>, and List<Number>;
you can achieve this by using an upper bounded
wildcard.
Generics
• Wildcards
• Upper Bounded Wildcards
• To declare an upper-bounded wildcard, use the wildcard
character ('?'), followed by the extends keyword, followed by
its upper bound. Note that, in this context, extends is used in a
general sense to mean either "extends" (as in classes) or
"implements" (as in interfaces).
• To write the method that works on lists of Number and the
subtypes of Number, such as Integer, Double, and Float, you
would specify List<? extends Number>. The
term List<Number> is more restrictive than List<? extends
Number> because the former matches a list of
type Number only, whereas the latter matches a list of
type Number or any of its subclasses.
Generics
• Wildcards
• Upper Bounded Wildcards
public static void process(List<? extends Foo> list) {
for (Foo elem : list) { // ... } }

• It is true that ? is extends Foo


Generics
• Wildcards
• Unbounded Wildcards
List<?>
• There are two scenarios where an unbounded
wildcard is a useful approach:
• If you are writing a method that can be implemented
using functionality provided in the Object class.
• When the code is using methods in the generic class that
don't depend on the type parameter. For
example, List.size or List.clear. In fact, Class<?> is so often
used because most of the methods in Class<T> do not
depend on T.
Generics
• Wildcards
• Unbounded Wildcards
public static void printList(List<?> list) {
for (Object elem: list)
System.out.print(elem + " ");
System.out.println();
}
Generics
• Wildcards
• Lower Bounded Wildcards
• A lower bounded wildcard restricts the unknown type
to be a specific type or a super type of that type.
• A lower bounded wildcard is expressed using the
wildcard character ('?'), following by
the super keyword, followed by its lower bound: <?
super A>.
• You can specify an upper bound for a wildcard, or
you can specify a lower bound, but you cannot
specify both.
Generics
• Wildcards
• Lower Bounded Wildcards
public static void
addNumbers(List<? super Integer> list) {
for (int i = 1; i <= 10; i++) {
list.add(i);
}}
It works on lists of Integer and the supertypes
of Integer, such as Integer, Number, and Object
? is a supertype of Integer
Generics
• Wildcards
• Lower Bounded Wildcards
public static void
addNumbers(List<? super Integer> list) {
for (int i = 1; i <= 10; i++) {
list.add(i);
}}
It works on lists of Integer and the supertypes
of Integer, such as Integer, Number, and Object
? is a supertype of Integer
Generics
• Wildcards
• Lower Bounded Wildcards
Example: 15Generics
Generics
• Type Erasure
• To implement generics, the Java compiler applies
type erasure to:
• 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.
• Insert type casts if necessary to preserve type safety.
• Generate bridge methods to preserve polymorphism in
extended generic types.
• Type erasure ensures that no new classes are
created for parameterized types; consequently,
generics incur no runtime overhead.
Generics
• Type Erasure
• During the type erasure process, the Java compiler
erases all type parameters and replaces each with
its first bound if the type parameter is bounded,
or Object if the type parameter is unbounded.
Generics
• Type Erasure
public class Node<T> {
private T data;
private Node<T> next;
public Node(T data, Node<T> next) {
this.data = data;
this.next = next; }
public T getData() { return data; } // ...
}
• Because the type parameter T is unbounded, the Java
compiler replaces it with Object:
Generics
• Type Erasure
public class Node {
private Object data;
private Node next;
public Node(Object data, Node next) {
this.data = data;
this.next = next; }
public Object getData() {
return data; } // ...
}
Generics
• Type Erasure
public class Node<T extends Comparable<T>> {
private T data;
private Node<T> next;
public Node(T data, Node<T> next) {
this.data = data;
this.next = next; }
public T getData() { return data; } // ...
}
The Java compiler replaces the bounded type
parameter T with the first bound class, Comparable:
Generics
• Type Erasure
public class Node {
private Comparable data;
private Node next;
public Node(Comparable data, Node next) {
this.data = data;
this.next = next; }
public Comparable getData() {
return data; } // ... }
Generics
public static <T> T convertInstanceOfObject( Object o, Class<T> clazz) {
try { return clazz.cast(o);
} catch(ClassCastException e) { return null; } }

public static void main(String args[]) {


String s = convertInstanceOfObject("string", String.class);
System.out.println(s);
Integer i = convertInstanceOfObject(4, Integer.class);
System.out.println(i);
String k = convertInstanceOfObject(345435.34, String.class);
System.out.println(k); }

You have to use a Class instance because of the generic type erasure
during compilation.

You might also like