The Lesson
The Program
The Assignment
- In this lesson we are going to learn about a wonderful feature called generics!
- What is generic programming?
- Generic programming is programming when you don't really know about the data type you are working with.
- This is very useful when working with storage types as well as for a few other things.
- How do Generics work?
- When doing generic programing, langauges usually go about two different ways of doing it:
- The first is called Template programming and is used in C++, and a few other languages.
- When you specify the type for the object the whole class is copied and the template type is replaced with the specified one.
- This is really powerful as you can do different things for different templates if necessary.
- It does result in slightly longer compile times and larger files.
- But since whole new classes are made there is no casting or type checking so it is usually faster.
- The second method is called Generic programming and is clearly used by Java (and some others) since the names are the same.
- When you compile your code the compiler will look at all of the uses of your generic class and then do what is called type erasure.
- Type erasure will take the information you write in your code and decide on a good base class for everything.
- So if you are creating a box class that can only hold things that extend the square class the compiler will replace the generic type with Square.
- But if you are creating a very general list that can hold anything it will probably use the Object class.
- The Object class is used most often as it fits most cases.
- But if you are creating a very general list that can hold anything it will probably use the Object class.
- Then after doing type erasure the compiler inserts casts and type checks into your code.
- These casts and type checks are done at execution/run time and so it SLIGHTLY slows your code.
- The decrease in speed is impossible to notice between a program that uses generics and one that doesn't.
- The only time this decrease is noticed is when comparing languages that use generics and ones that use templates.
- So if you think you should use generics don't be afraid to use them the speed decrease is incredibly small.
- Because of type erasure and the casts and type checks code compilation tends to be faster and files smaller.
- This is because there are not a lot of versions of your generic class and instead only one.
- These casts and type checks are done at execution/run time and so it SLIGHTLY slows your code.
- The first is called Template programming and is used in C++, and a few other languages.
- When doing generic programing, langauges usually go about two different ways of doing it:
- How do we use generics in java?
- There are two cases where generics can be used: Creating generic classes and parametizing (specifying the type) for a generic class.
- In both cases we will be using the carrot brackets ("<" and ">") with something in between them.
- Creation:
- When creating a generic class we put the brackets next to the name of the class when we declare it (where we write "class NAME")
- Within the brackets we write the name of our generic type.
- We try to keep names to one letter and there is a certain convention that we try to follow.
- E - Element
- K - Key (Used in maps)
- V - Value (Used in maps)
- N - Number (No idea where this is used)
- T - Type (The most common generic type)
- S, U, V, etc. - 2nd, 3rd, 4th types
- These aren't the only names you can use and the name means absolutely nothing.
- It will help people understand what you are trying to do with your generic type though which is helpful.
- After creating the generic class, any time we need to use that generic class just refer to it by it's name as if it was a normal class.
- So if a method must return our generic type and our type is called "U" (apparently T and S were taken) we would type:
- U METHODNAME() { ... }
- So if a method must return our generic type and our type is called "U" (apparently T and S were taken) we would type:
- When creating a generic class we put the brackets next to the name of the class when we declare it (where we write "class NAME")
- Paremetizing
- Paremetizing a generic class is pretty easy.
- When you go to create a new instance of that class all you have to do is type the type within brackets after the class name.
- Example: new ArrayList() or new LinkedList()
- You can optionally leave out the paremetization but this is extremely frowned upon.
- The only reason you can even do it is for backwards compatibility with older code.
- There are two cases where generics can be used: Creating generic classes and parametizing (specifying the type) for a generic class.
- Limits of generics:
- Generics are really cool and all but there are some limits to what they can do.
- Arrays:
- The first problem is that you cannot create an array from a generic type.
- This is because in java, arrays like to know a few things about themselves at compile time.
- One of these things happens to be it's type and so generic arrays really can't be done.
- But then how does the generic class ArrayList (which is backed by an array) work?
- Well it is most likely a little bit more complicated than our program below but I did my best to show you a rough draft.
- The real version would probably have more safety checks and such since it is actually part of java.
- Well it is most likely a little bit more complicated than our program below but I did my best to show you a rough draft.
- This is because in java, arrays like to know a few things about themselves at compile time.
- The first problem is that you cannot create an array from a generic type.
- instanceof:
- You cannot use the "instanceof" keyword with generics as yet again, we really don't know the type of a generic so we can't see if something matches it.
- This is made worse because of type erasure so most things would just wind up being "instanceof Object" which everything is.
- You cannot use the "instanceof" keyword with generics as yet again, we really don't know the type of a generic so we can't see if something matches it.
- primitive data types:
- You cannot use primitive data types inside your parametization (no ArrayList or ).
- Instead you have to use the Class versions of the primitives (Integer, Float, Double, etc...).
- You don't have to worry too much about interchanging between the Class versions and the primitives as the compiler will take care of this for you.
- This is called auto boxing and it is a cool feature but a dangerous one.
- We will talk about it soon.
- This is called auto boxing and it is a cool feature but a dangerous one.
- Generics in parameters:
- One really cool thing you can do with generics is accept specific types of generic objects in your parameters.
- For example, the Class class is actually generic and is generic according to the class of the object.
- So if you have a String object and call the .getClass() method on it, it will return a Class object.
- When creating something that stores classes of a certain type (for example a list of all entity classes) you can use inheritance with your generics.
- If all of our entities extend the Entity class we can use the wildcard operator along with generic bounding to improve our list.
- Wild Card Operator:
- The wild card is the question mark (?) and is used for an unknown type.
- Generic Bounding:
- This is quite an interesting and complicated topic but for now you just need to know that you can use this to tell if something extends another class.
- This is done with the "extends" keyword.
- So for our object that stores classes that all extend Entity we could have it be parametized to <? extends Entity>.
- Now it can store any type (?) but only if it extends Entity.
- The Diamond (<>):
- The diamond is one of the few new features in java that I will actually be teaching you.
- All it does is prevent you from having to retype the parametization if it is already obvious what it is.
- This usally happens when you declare and instantialize a variable at the same time.
- The compiler will infer the parametization and put it in for you.
- In order to use the diamond just use empty brackets.
- An example of this is: Box<Box> boxOfBoxes = new Box<>();
- Inheritance:
- The Java official tutorials makes a special point about this so I decided I would do the same.
- Due to how generics work, inheritance is impossible to do for the most part and when it can be done it is not like you think.
- If you have class B that extends from class A (making A the base class) and then have an arraylist of a and b, then:
- While an object of type B could be stored in a variable of type A.
- An object of type ArrayList could NOT be stored in a variable of type ArrayList.
- Even though the generic type being used is a subclass of the other one, the two arraylists are not related.
- What is generic programming?
- In this program I have made a simple version of an ArrayList (a common list we will learn about next lesson).
- This list uses generics in order to allow you to make a list that can store any data type.
- Our arraylist will automatically resize to double the previous size when you try to add a new element past it's old limit.
- Your assignment for this lesson is to create your own version of a Linked List.
- What is a Linked List:
- It is called a linked list because the list consists of nodes that are linked to each other.
- The actual Linked List will usually contain a variable for the first node in the list, and one for the last node.
- Upon adding something to the list you add it to the Node, add the new node to the last node, and then make the new node the last node.
- If you need get a certain one you can do this with a counter decremented each time it moves to the next node.
- You should be able to store and retrieve anything using generics.