Next we’ll examine Java generics.
This is an advanced topic, but one that you are bound to encounter as you continue to use Java.
Generics also allow the compiler to better check our code—and we always want that.
So let’s do this!
We’ve already seen generics at use when using Java’s containers like Lists.
We can create a bareList, but using one requires dangerous downcasting:
// This List can store any Object
Strings= (String) list.get(1); // Oh no! A runtime error...
Instead, by providing a type parameter when we create the list, we can get the compiler to help us:
// This List can store only Strings
list.add(4); // Now the compiler will fail here...
Strings= (String) list.get(1);
Remember: runtime errors cause things to fail right in the user’s face.
This is not good!
Compiler errors, in contrast, must be caught in development.
So transforming runtime errors to compiler errors helps us produce more correct programs.
This is good!
There are a few important things to understand about how Java compiles generic classes.
First, the type parameter is not a variable.
You can use them in most places that you would normally use a type, but you can’t assign to them, or use them in a constructor call:
privateEvalue; // This is fine, since E replaces a type
E=String; // But you can't reassign a type parameter
value=newE(); // Also doesn't work, since maybe E doesn't have an empty constructor?
One useful way to think about what happens when your program is compiled is that the compiler replaces the type parameters with types used in your code.
So, given this generic class:
If I create a Example<String>, it’s almost as if I had written this code:
You regularly see generic type parameters in Javadoc.
Now that we’ve discussed a bit about how to use type parameters in our own code, we’re more prepared to understand documentation for classes that use them.
Let’s look at one familiar example together and discuss how to identify and interpret these type parameters.
Homework: BinaryTree Balanced
Created By: learncs.online Staff
/ Version: 2020.11.0
Let's determine if a binary tree is height balanced.
A tree is height balanced if the height of any node's two subtrees (right and left) never differ by more than 1.
Provide a public class named BinaryTreeBalanced providing a single public class method named isBalanced.
isBalanced accepts a BinaryTree and returns true if the tree is balanced, and false otherwise.
If the passed tree is null, you should throw an IllegalArgumentException.
A few hints on this problem:
Your main entry point method will probably need to start the recursion using a private helper method, because the
main method needs to throw on null which you want to handle as a valid base case in your recursion
This helper method will probably have the same arguments as the main method, so you'll need to change something
else to make sure that the method signature is different and the compiler can determine which one you want to use
You will probably need a second helper method implementing tree height that you call in your primary recursive