DEV Community

Zander Bailey
Zander Bailey

Posted on

Stay Classy Part 3: Java Abstraction

In some programming languages abstraction can be a powerful tool, and a very necessary one. In other languages, while still useful, abstraction can be more of a style choice. Java is a good example of the former. As an object oriented language, Java uses classes for everything, and as such needs abstraction to avoid things like writing several classes to perform nearly identical tasks with slight differences. Typing and classes are very important in Java because types are specified for the input and output of every function. In Python you can just pass anything into a function regardless of type, and as long as the object can be used in the operations performed, there won’t be a problem. Java is much stricter about typing, so a Java function will only accept as input the specified type. So let’s see what this looks like:

//Java
public int myFunction(int a){

    return a+1;
} 
#Python
def myFunction(a):

    return a+1

Notice how in the Java example the types are defined for input and output, whereas in the Python example there are no defined type, it will simply throw an error if it attempts to add something incompatible. Both examples would work with an integer, what if you tried them with a float? The Python version would be fine, since it could still add 1 to a float. But the Java example would have a problem, since the input type is int and not float. It would also be a problem, since adding a float to 1 would make the output a float and the output type is predefined as int. We could change the input and output types to float, but what if we still wanted to use an int as well? Let’s go over each part individually.

First, let’s look at the input. We want to be able to accept an int or a float, but those are two separate types, right? Well, in Java int and float are primitive types, but they are extended by the object classes Integer and Float, respectively. Integer and Float function almost identically to int and float, but have extra methods and functionality. How does this help us? In order to use both float and int interchangeably, we need to get more generic, but as primitive types int and float have no generic form. But Integer and Float do, namely Number. Integer and Float both extend the class Number. Integers and Floats use very similar operations, so they both extend the same class, which allows us to exploit that shared inheritance. How does this work? Instead of having myFunction accept an int type parameter, we can have it accept a Number instead, which will accept an int or a float:

public int myFunction(Number a){

    return a+1;
} 

But we have a problem. Because we input ‘a’ as a Number, the function now only recognizes it as a generic Number, which does not have defined interaction with an int or a float. This means we have to cast it to the right type in order to interact with it. Fortunately Java has the instanceof operator. We can use instance of to check which type it is, and then cast it appropriately:

public int myFunction(Number a){

    if(a instanceof Integer){
        return (int)a+1;
    }else if(a instanceof Float){
        return (float)a+1;
    }else{
        return -1;
    }
} 

Okay, now we can accept an int or a float and it can perform the operation no problem. Except for the output. Now is a good time to mention, that Java function also specify an exact type of output. Currently, this function can only output an int, which is fine if our inout is a also an int, but if we use a float the operation will turn the output into a float as well, which is not something we can return. So how do we fix this? We can also turn the output into a Number. If we turn the output into a Number it will accept any type of Number as output:

public Number myFunction(Number a){

    if(a instanceof Integer){
        return (int)a+1;
    }else if(a instanceof Float){
        return (float)a+1;
    }else{
        return -1;
    }
} 

Of course it is important to note that calling this function will return a Number, and it will then be necessary to cast the output. In this example, another way around this would be to always cast the input as a float, and then always return a float:

public Float myFunction(Number a){

    return (float)a+1;
} 

As long as we don’t mind always receiving our output as a float it works for this example. But in many class-related situations this might not be the case, and the previous solution would be more applicable.

Top comments (0)