Overflow occurs when we assign such a value to a variable which is more than the maximum permissible value.
Underflow occurs when we assign such a value to a variable which is less than the minimum permissible value.
JVM does not throw any exception in case Overflow or underflow occurs, it simply changes the value. Its programmer responsibility to check the possibility of an overflow/underflow condition and act accordingly.
Consider the case of int variable, it is of 32 bit and any value which is more than Integer.MAX_VALUE (2147483647) is rolled over. For example, Integer.MAX_VALUE + 1 returns -2147483648 (Integer.MIN_VALUE).
As int data type is 32 bit in Java, any value that surpasses 32 bits gets rolled over. In numerical terms, it means that after incrementing 1 on Integer.MAX_VALUE (2147483647), the returned value will be -2147483648. In fact, you don't need to remember these values and the constants Integer.MIN_VALUE and Integer.MAX_VALUE can be used.
Underflow is the opposite of overflow. While we reach the upper limit in case of overflow, we reach the lower limit in case of underflow. Thus after decrementing 1 from Integer.MIN_VALUE, we reach Integer.MAX_VALUE. Here we have rolled over from the lowest value of int to the maximum value.
For non-integer based data types, the overflow and underflow result in INFINITY and ZERO values.