Generics In Java - Full Simple Tutorial
Summary
TLDRIn this Java tutorial video, the presenter, John, a lead Java software engineer, dives into the concept of generics in Java. He explains that generics can be confusing at first glance due to the use of various symbols and conventions. However, he assures viewers that by the end of the video, they will understand what generics are, why they are essential, and how to implement them in their code. John begins by illustrating the problem generics solve, which is the issue of code duplication when creating classes that handle different data types. He then demonstrates how to create a generic class, using a 'Printer' class as an example, and how to specify the type of object the class will handle. The video also covers the use of generics with Java's Collections Framework, the importance of type safety, and advanced topics such as bounded generics, multiple bounds, generic methods, and wildcards. By the end, John has shown how generics allow for flexible and type-safe programming in Java, ultimately reducing code duplication and increasing maintainability.
Takeaways
- 📚 **Generics in Java**: Generics allow for the creation of classes, interfaces, and methods that can operate on any data type while providing compile-time type safety.
- 🔄 **Elimination of Code Duplication**: Before generics, developers had to create separate classes for each data type they wanted to handle, leading to code duplication. Generics solve this by allowing one class to handle multiple types.
- 🔑 **Type Parameters**: Classes and methods that use generics define a type parameter (commonly denoted as 'T') which stands for 'type' and can be used to specify the type of object the class or method will work with.
- 🚫 **Type Safety**: Generics enforce type safety, meaning that if you create a `Printer<Integer>`, you can't accidentally pass a `String` to it, which would cause a compile-time error.
- 🔄 **Wrapper Classes**: Generics do not work with primitive types like `int` or `long`. Instead, wrapper classes like `Integer` and `Long` are used to maintain type safety.
- 📦 **Collections Framework**: Java's Collections Framework widely uses generics, such as `ArrayList<Cat>`, which ensures that only objects of type `Cat` can be added to the list.
- 🚀 **Advanced Generics**: You can create bounded generics by specifying that the type parameter extends a particular class or implements an interface, allowing for more specific behavior.
- ➡️ **Multiple Bounds**: It's possible to specify that a type parameter extends multiple classes or interfaces, although only one class is allowed, followed by any number of interfaces.
- 📢 **Generic Methods**: Methods can also be generic, allowing them to work with different types, which can be specified when the method is called.
- 🔄 **Generic Wildcards**: Wildcards, denoted by a `?`, can be used when you want a generic type to accept any type, without knowing the exact type at compile time.
- 📋 **Bounded Wildcards**: Similar to bounded generics, bounded wildcards can specify that the unknown type must extend a particular class or implement an interface, providing a level of type safety.
Q & A
What is the main purpose of using generics in Java?
-Generics in Java are used to create classes, interfaces, and methods that can work with different types of objects without losing type safety. They help to avoid code duplication and ensure that the correct type of object is used throughout the program.
What problem did Java developers face before the introduction of generics?
-Before generics, developers had to create separate classes for different data types, which led to code duplication and maintenance issues. For example, if a class was designed to hold integers, a separate class would be needed to handle doubles or strings.
How does a generic class declaration look like in Java?
-A generic class in Java is declared by placing a type parameter in angle brackets after the class name and before the opening curly brace. By convention, this type parameter is often referred to as 'T', which stands for 'type'. For example: `public class Printer<T> { ... }`.
What is the issue with using raw types in Java?
-Raw types refer to using generic types without specifying the type parameter. This can lead to a loss of type safety, as the compiler cannot verify the type of objects being used with the generic class, potentially resulting in runtime errors like `ClassCastException`.
How do generics ensure type safety in Java?
-Generics ensure type safety by enforcing that only objects of the specified type can be used with a generic class or method. This prevents runtime errors that would occur if an object of an incompatible type were to be used.
What are bounded generics in Java?
-Bounded generics are a way to limit the type parameter to a specific class or interface. This is done by using the 'extends' keyword followed by the class or interface name. For example, `<T extends Animal>` ensures that T can only be a subclass of `Animal`.
How can you specify that a generic type must implement a certain interface?
-To specify that a generic type must implement a certain interface, you use the 'extends' keyword followed by the interface name within the type parameter. For example, `<T extends Serializable>` indicates that T must implement the `Serializable` interface.
What are wildcards in the context of Java generics?
-Wildcards in Java generics are used when you want to specify that a generic type can accept any type. They are represented by a question mark (?) and can be used to define a method or class that operates with any object type without specifying it.
How do you create a generic method in Java?
-A generic method in Java is created by declaring a type parameter within angle brackets in the method signature. For example: `public static <T> void shout(T thingToShout) { ... }`. This method can then be used with any type of object.
What is the limitation when using multiple bounds in generics?
-When using multiple bounds in generics, you can only have one class and it must be listed first, followed by interfaces (if any). Java does not support multiple inheritance, so the class name must precede any interface names in the bounds list.
Why can't a list of integers be considered a subtype of a list of objects in Java?
-In Java, the type system is invariant, meaning that even though `Integer` is a subclass of `Object`, a `List<Integer>` is not a subtype of `List<Object>`. This is because lists are covariant in their element types, and allowing such a subtype would break type safety.
Outlines
😀 Introduction to Generics in Java
The video begins with an introduction to generics in Java, which can be confusing at first due to the use of various symbols and conventions. The speaker, John, a lead Java software engineer, promises to clarify generics by the end of the video. He explains that understanding generics requires insight into the problems Java developers faced before their introduction. John uses the example of creating a class to hold and print an integer, and the issue of code duplication that arises when similar classes are needed for different data types. He then introduces the concept of generics as a solution to this problem, demonstrating how to make a class generic by using a type parameter (conventionally called 'T').
📚 Using Generics in Java Classes
John demonstrates how to use generics in Java classes with a practical example. He shows how to create a generic Printer class that can handle different types of objects, not just integers. He explains the use of type parameters with angle brackets and how to specify the type when creating an instance of a generic class. The video also covers the limitations of generics with primitive types and the solution of using wrapper classes. John further illustrates the use of generics in Java's Collections Framework, particularly with ArrayList, and the importance of type safety, which prevents runtime errors that would arise from casting objects inappropriately.
🔄 Advanced Generics: Bounded Types and Multiple Bounds
The video delves into advanced topics in generics, such as bounded types and multiple bounds. John explains how to create a generic class that only accepts objects of a certain type or implementing a specific interface by using the 'extends' keyword. He also demonstrates the concept of multiple bounds, where a generic type can be restricted to a subclass of a class and an implementation of an interface. The video showcases the use of the '&' symbol to separate multiple bounds and the syntactical requirement of listing the class name first followed by interfaces. Generic methods are also introduced, showing how to create methods that can accept any type of object and highlighting the use of generic type parameters in method signatures.
🔄 Wildcards and Generics in Lists
The final part of the video discusses wildcards in generics, which are used when the exact type of a generic is unknown. John illustrates this with an example of a method that can print any list of objects. He explains the use of the question mark as a wildcard and how it allows a method to accept lists of any type. Bounded wildcards are also introduced, showing how to specify that a list must contain objects of a certain type or implementing an interface. The video concludes with an encouragement to like and subscribe for more Java tutorials and a reminder to continue learning.
Mindmap
Keywords
💡Generics
💡Type Parameter
💡Type Safety
💡Code Duplication
💡Wrapper Classes
💡Collections Framework
💡Bounded Generics
💡Multiple Bounds
💡Generic Methods
💡Wildcards
💡Type Erasure
Highlights
Generics in Java can be confusing at first due to their syntax, but they are essential for type safety and flexibility in programming.
Before generics, developers faced code duplication issues when creating classes for different data types.
The introduction of generics allows for a single class to handle multiple types, reducing code duplication.
Generics are defined using type parameters in angle brackets, often represented by 'T', which stands for 'Type'.
Using generics in Java collections framework, such as ArrayList, ensures type safety and prevents errors at compile time.
Generics do not work with primitive types, but wrapper classes like Integer can be used instead.
Bounded generics allow for specifying that the generic type must extend a certain class or implement an interface.
Multiple bounds can be applied to a generic type, ensuring it meets several requirements.
Generic methods can be created, allowing them to work with any type specified as a parameter.
Wildcards can be used in generics to allow for lists or other collections to hold any type of objects.
Bounded wildcards can specify that a collection should hold objects of a certain type or a subtype.
The use of generics prevents type safety issues that can arise when using raw types or collections.
John, a lead Java software engineer, shares his knowledge on generics in a clear and understandable way.
The video provides a step-by-step guide on how to implement generics in Java, starting with a simple Integer Printer class.
An example demonstrates how to convert a specific class into a generic one by using type parameters.
The video explains the concept of casting and its relation to type safety when using non-generic collections.
Advanced generic concepts such as bounded generics and multiple bounds are explained with examples.
The video concludes with practical applications of generics, showcasing their importance in modern Java programming.
Transcripts
in this video we're going to talk all
about generics in java generics can be
super confusing the first time you see
them with all the t's and question marks
and angle brackets and k's and v's but i
promise by the end of this video you'll
know exactly what generics are why they
exist and why they're useful and how you
can use them in your own programs my
name is john i'm a lead java software
engineer and i love sharing what i've
learned with you in a clear and
understandable way i also have a full
job of course available and a link down
in the description if you're interested
first to have a good understanding of
what generics do and why they exist it
helps to know the kinds of problems that
java developers were running into before
generics existed let's say i wanted to
create a class where all it would do is
hold an integer value that i give it and
then print out that integer whenever i
wanted to so we might call something
like that integer printer you can go
ahead and click finish and create that
so this class would be pretty simple we
would have an integer field for the
thing that we want to print so we can
call it thing to print and we can have a
constructor for this class that takes in
this thing to print so that would be
public integer printer then it takes in
an integer for the thing to print and
that would just set this dot thing to
print equal to the thing to print that
was passed in and we can have one method
to actually print this out whenever we
want to so that would be public void
print and all that does is just print
out the thing to print to the console so
system.out.printline thing to print so
if we wanted to use this integer printer
class we would just create an integer
printer printer equals new integer
printer
and pass in the integer that we want to
print here in the constructor so let's
say we want to print out the number 23
now of course we can call printer.print
and when we run our program of course it
prints out 23. but what if we wanted to
do exactly the same thing for a double
instead of an integer well we couldn't
use this class right because it only
holds an integer it doesn't hold a
double so what can we do well basically
what we have to do is make a copy of
this entire class and we can call it
double printer and then inside that
double printer we would basically have
all of the exact same code except
instead of integer we would have double
so this new class will work great for
holding and printing doubles but what if
we now want a class that'll do exactly
the same thing but work for strings well
of course you have to do the exact same
thing again you have to copy that class
make a new class called string printer
and change all these doubles to strings
if you want your class to be able to
print strings so now we have three
completely separate versions of
essentially the same kind of class and
you can start to see the problem we
would need a whole other class if we
wanted to do this with floats or dogs or
cats or cars or trucks or whatever type
of object that we wanted to print so
we'd end up with a ton of code
duplication and this is with a really
simple class if you had a more
complicated class the code duplication
would be even worse well that is where
generics come in generics offer you the
ability to have one class like this that
is flexible for many many different
types so let's go back to our original
integer printer and make it generic so
first instead of calling it integer
printer let's just call it printer
because it should be able to print
anything now when you want to use
generics in a class like this in java
right here after the class name in the
declaration but before the curly braces
you have to define what is called a type
parameter and you'll put your type
parameter in angle brackets like this by
convention in java typically you'll see
this type parameter just called t but
technically you can call this type
parameter whatever you want but i'm
going to just be using t so you can kind
of get used to seeing it because that's
the convention that you'll see elsewhere
you can think of it as standing for type
in this class what this t represents is
the type of thing that this printer is
going to be able to hold and print so
instead of just having an integer field
here it's going to be of type t
right now as we're coding this class we
don't know what types of things this
printer is going to be asked to print
but this gives the ability to create
printers for any types that you want so
of course we also have to change the
name of our constructor to just printer
to match the class name and that
constructor also instead of taking in an
integer is going to take in something of
type t so now this class is a generic
printer for whatever type we want but
now how do we actually use this class if
we want to for example create an integer
printer like we had before well back
here in our main method instead of an
integer printer now of course we're
going to just create a printer but now
you can see that we have a warning here
that printer is a raw type and
references to generic type printer
should be parameterized it wants to know
the type of thing that we want to be
able to print and in this example we
want to be able to print integers so how
we specify that is in angle brackets
here after printer we type in integer
that tells java i want a printer for
integers and we have a similar warning
here to get rid of that you just need to
put in angle brackets after the class
name printer in older versions of java
you used to have to put the type in
there again but you don't have to do
that anymore this integer here that
we're passing in in the angle brackets
is what's going to be used as this
t-type in this printer object that we
are creating now we can run our program
as we did before and it still prints out
23. but now what's cool is we can go in
and get rid of those two extra classes
that we made the double printer and the
string printer we can just delete those
because now we can use our generic
printer class to be able to create
printers for doubles and strings also so
now all we have to do if we want to
create a printer for doubles we just say
printer and pass in double or t the type
that we want this printer to be able to
print we can call it double printer
equals new printer and give it a value
like 33.5 and we can call
doubleprinter.print and of course it
prints out 33.5 so now we've created one
printer class that can print any type
that we get it doubles ants longs floats
pigs monkeys cars trucks whatever one
thing to note though is that generics
don't work with primitive types like
lowercase int and lowercase long but all
you have to do is just use the wrapper
classes like integer and everything
should just work the same way one place
that you've probably already used
generics all the time is with java's
collections framework for example if you
wanted to create an arraylist you've
probably done this where you've
specified in angle brackets the type of
thing that you want to have in your list
so if you want to create an arraylist of
cats you say arraylist cat we'll call it
cats equals new array list this gives
you an arraylist that you can only add
cats to so you can say cats.add
new cat and that works fine but if you
try to do cats.add
and pass in a new dog instead you get an
error because we specified that cat was
the type of thing that this list was
going to hold and if we try to give it a
dog we get an error in the same way up
here where we created a printer for
doubles if we try to pass in a string
hey there
we get a similar error because we told
java that this was going to be a printer
for doubles and here we're trying to
give it a string but you might be
thinking well hey john if we want to be
able to create a list of anything we
want why do we have to deal with all
these generics why can't we just create
like an array of just objects and then
we can put whatever we want in it well
it is true that you can do that and your
code will work but it won't be type safe
at all let me show you what i mean let's
say that our arraylist instead of
holding cats just holds objects this is
the kind of thing you'd have to do if
generics didn't exist you just have to
create an arraylist that can hold
whatever so in this imaginary world
without generics we still want to create
a list of cats so we've added our new
cat to our list but let's say sometime
later on in the code we want to be able
to get stuff off our list and use it so
if we want to get this first cat off the
list and put it in a variable we would
want to create a cat call it my cat
equals cats.get
the first element of the list at index
0. but here we get an error that we have
a tight mismatch you can't convert from
object to cat java doesn't know that
this is supposed to be a list of cats it
just knows it's a list of objects so we
have to tell java yes i know this is a
cat so you can go ahead and cast it to a
cat so i can store it in this variable
but what if instead of adding a cat to
the list somebody adds a dog well the
code all looks the same there's no
compilation errors or anything but of
course if you try to run it you're going
to get a classcast exception
right here on this line because you're
trying to cast this element in the list
as a cat but it's actually a dog so just
having an arraylist that can hold
whatever type of object causes all types
of these type safety issues and generics
solves that problem for us so now we can
say yes i want to create a list of cats
so then in the code if somebody tries to
add a dog to that list they get an error
and it won't even compile and also since
java knows that this is a list that can
only contain cats whenever you get a
thing off of that list it is 100
guaranteed to be a cat and you don't
have to do any special casting that's
how generics help us they offer the
ability to create classes that can
accommodate tons of different types but
also the structure and the type safety
of knowing exactly which type you're
using that class with at the moment but
there are even more cool advanced things
that you can do with generics let's go
back to our generic printer class so
right now we can create a printer of
whatever class that we want to right but
what if instead of being a printer for
any type we want this to be a more
specialized printer for animals for
example i have this cat class here that
extends the animal class and i also have
a dog class here that extends the animal
class so if we want this to just be a
printer for any type of animal instead
of just saying t we can say t
extends
animal now back here in our main method
we now get an error when we try to
create a printer for integers or doubles
because now this printer only works for
animals so we can create a cat printer
and in the constructor we can pass in a
new cat or we can create a printer for a
dog and pass in a new dog but what's
cool about that is now in our printer
class since we know that whatever is
passed in as this type extends animal
any method that is defined in the animal
class is available to us in our thing to
print variable because we know that this
thing to print this t is going to be
some type of an animal so now because we
know this thing to print is an animal
down here in our print method we can
call thing to print dot
eat because this eat method is available
in the animal class so if we didn't have
this extends animal if we just took in
any type at all we can't call the eat
method because this tea type isn't
guaranteed to be an animal at all so
there's no way to know whether it will
have an eat method available on it or
not when you do this type of thing it's
called a bounded generic because you're
giving a certain bound a limit on the
type that's able to be passed in you can
also use bounds with interfaces let's
say you wanted to guarantee that this
type implemented the serializable
interface you just put in extends
serializable you might think that
because this is an interface you should
put implements here instead of extends
but no it's just not the proper syntax
it still has to be extends even though
it's a little bit weird another cool
thing you can do is have multiple bounds
let's say you wanted to make sure that
it was a subclass of animal and also
implemented the serializable interface
to do that you can just say extends
animal
and serializable here with an ampersand
and you can list as many things as you
want here all separated by ampersands
there's just a couple restrictions you
can only have one class which makes
sense because java doesn't support
multiple inheritance and you always have
to list the class name first with any
interfaces after that if you try to
switch it around and put the interface
first you'll get an error in addition to
having generic classes you can also have
generic methods let's say we wanted to
make a method that can take in any type
of object and print it out with
exclamation points private static void
let's call it shout since it'll print
things out with exclamation points it'll
take in some kind of type that we're
going to call t we'll call it thing to
shout and inside that method all we're
going to do is print out that thing to
shout with a bunch of exclamation points
after it so right now we're getting an
error here because java is saying hey t
isn't the type what do you want me to do
with this to tell java that this t is
supposed to be a generic type right here
in the method signature right before the
return type you put that generic type in
angle brackets again you can call this
whatever as long as it matches here and
in the parameters but by convention
you're still just going to see t most of
the time so now here in our main method
we can call our shout method with
whatever we want you can send in a
string like john you can send in an int
57 or you can even send in a cat so this
can take in any type of parameter that
we want to send and when we run it it'll
print them out with exclamation points
java also supports the ability to have
multiple different generic types here so
in addition to taking in this t thing to
shout we can also take in say
the
other thing to shout all we have to do
is add this v to our angle brackets here
and separate them with a comma and now
this method will take in two of any sort
of type so we can pass in john and 74
and also go ahead and print out
other thing to shout and that works and
is now flexible with any two types at
all if you want you can also have
multiple generic types like this in your
generic classes so over here in our
printer class if we wanted to have
another field here let's call it v
other thing and all we have to do is
specify that up here in our angle
brackets as well separated by a comma if
you happen to want to return one of
these generic values that are being
passed into your generic methods all you
have to do is specify that return type
as the return type here so instead of
void if you want to return something of
type t you just put t here as the return
type and then in here of course you just
have to return something of type t which
can just be this
thing to shout the other advanced
generics topic i want to talk about is
wild cards let's talk about a situation
where you might want to use a wild card
and then we'll show how you can do it
let's say we wanted to be able to create
a method that can take in a list that
holds any type of objects and we want to
be able to print out that list so we
might call that print list so how do we
specify in the parameters here that we
want to be able to take in a list that
contains any type of thing you might
think that we can just say okay i want
to take in a list of objects we can call
it my list and all we'll do is just
print out that list to the console so
now up here we can create a list of
integers
call it in list
equals new array list we can take our
int list
and add the number three and then we can
try and call our print list method with
our int list as the parameter but if we
try and do that we get an error here
that says we can't pass in this list of
integers as this parameter that's
supposed to be a list of objects but it
might feel like you should be able to do
that right of course an integer is a
subclass of object so shouldn't we be
able to pass in just a list of integers
well even though integer is a subclass
of object a list of integers is not a
subclass of a list of objects so this
doesn't work this is where a wild card
will work to solve your problem so
instead of saying that this is a list of
objects we say that this is going to be
a list of unknown by passing in a
question mark this question mark is the
wild card you use a wild card a question
mark as the type parameter when you're
using a generic when you don't know
what exactly that generic type is going
to be so it's saying hey java i've got
this method here and i want it to be
able to take in a list of anything but i
don't know what it's going to be a list
of so now you can call this method with
a list of whatever you want in this case
we're doing it with a list of integers
but you can also do it with a list of
anything else let's say we had a list of
cats add a new
cat to that list change this to catlist
here and pass the catlist into our print
list method and it now works with lists
of both types with no errors you can
also have bounded wild cards similarly
to how we did in our generic class so
instead of being a list of anything at
all we can say this has to be a list of
something that extends the animal class
but now you can see up here that we're
getting an error when we're trying to
call this method with a list of integers
and that's because integer doesn't
extend animal we don't get that same
error here when we're calling it with a
list of cats because cat does extend
animal if you enjoyed this video or
learned something please let me know by
leaving a like and be sure to subscribe
so you don't miss each new java tutorial
and of course don't stop now keep
learning by watching one of the other
videos below thank you so much for
watching i really appreciate you being
here with me i'll see you next time
Weitere ähnliche Videos ansehen
5.0 / 5 (0 votes)