Java

NOTE: This is combined so far between video lectures and texts. Reorganize it to be more coherent.

What Is Java?

Java is a class-based, object-oriented programming language that is designed to have as few platform dependencies as possible.

An important concept to understand is that Java, unlike Python, which is only interpreted, is a compiled language. Typically, a compiler's main functionality is to convert high-level language to low-level language that can be understood by the machine.

Basically,the Java compiler, just like any other compiler, does the task of translation. In other words, a compiler translates code from human-readable for to a platform-readable machine code. (Platform here refers to the operating system and the hardware architecture).

The Java compiler does not translate Java classes directly to machine code. Rather, it converts the Java classes called bytecodes by generating files with the .class file extensions. This bytecode is created for a virtual platform, the Java Virtual Machine (JVM).

First, the bytecode verifier in the JVM checks the bytecode. Then, the JVM converts the bytecode to machine-readable code.

This explains how Java achieves its platform independence. Since the JVM converts the bytecode to a machine specific code, there are different JVMs for different platforms.

What Are Data Types in Java and How Do they Differ?

Every time that a variable is used within your code, the compiler must know how to interpret and use the variable's data. Java programming, by design, has set data types to avoid undesired errors when processing data. This is why Java is referred to as a strongly typed language. This also means a variable's type cannot change once it has been declared, unlike other languages, such as Python.

For example, consider that you're writing a simple function that, given two integers, calculates the average.

average = (a + b) / 2;

Ask yourself: What should happen if either a or b are note of type integer? What if they are a float, double, or even a string? Java solves this by having strict data typing rules. Unlike Python and other languages, in Java, you must declare variable's data type, as it is instantiated?

The eight primitive data types in Java are shown in this table:

Data Type Size Description
Byte 1 Byte Whole numbers: 128
Long 8 Bytes Large whole numbers: -9.223E18 to 9.223E18
Float 4 Bytes Decimal numbers: Stores 6 or 7 decimals
Double 8 Bytes Decimal numbers: Stores 15 decimal digits
Boolean 1 BIT True or false
Char 2 Bytes E.g, A, 4, #, etc.
Short 2 Bytes E.g -32 768 to 32 767
Int 4 Bytes E.g -2.147E9 to -2.147E9

What is Casting?

Casting is a technique used in Java, and in Python as well, to change a variable's data type. If a string needs to be converted into an integer, the string will need to be casted as an int, as show below.

String stringnumber = "12";
Int number = Integer.valueOf(stringnumber);

NOTE: It is possible to do the same conversion from an integer to a string by using the code below:

String.valueOf([integer]);

Data Type Hierarchy

In Java, there is a specified hierarchy of data types when performing math operations. One common rule of Java is that the result of a math operation will always inherit the most precise data type used within the equation.

For example, when taking the sum of a double and an integer, the result will always be a double. When dividing two integers, the answer will always result in an integer.

This may seem counterintuitive at first, but it is one of the many quirks of Java.

To see this in practice, try this out below:

Classes vs Objects in Java

Java classes and objects go hand in hand and are often misused in conversation. To get a better understanding of the differences, think of a class as a recipe and an object as the completed dish.

Classes are what you, the programmer, write out and set characteristics for. Like a recipe, each class can have required ingredients; these are a class's variables and construction parameters. The recipe will also have instructions on how to use these ingredients; these are methods within the class that utilize the variables.

Objects resemble a finished dish. Objects are instances of a predefined class within a program. After writing a recipe, the chef will send out copies to all their friends, whi will then go and make their own instances of that recipe and use it to feed their families.

How Classes and Objects Are Used in Java

In most cases, a completed program is going to consist of hundreds, if not thousands, of lines of code. If this were all written in a single Java file, debugging and adding features would be nearly impossible. Java solves this problem by allowing the use of packages. Packages allow for programmers to reference certain parts of code even though it may be outside another code's directory. This produces one of Java's most desired features: modularity.

Packages allow a programmer to instantiate classes into objects within other classes. This may seem complex at first. However, if you continue to use the recipe metaphor from above, it gets easier.

If a chef friend were to send you their cookbook, they could simply not tell you to make chicken and expect you to reference a specific recipe. This is because there are most likely multiple chicken recipes within the cookbook. In order for you to complete the task, your friend must tell you specifically to "Cook the Pesto Chicken on page 32." Packages act in a similar way. If a programmer wishes to generate a object from a class and that class is not in the current directory, then the programmer must provide a location to look for the class.

This is done by using the import keyword at the beginning of the code. Once a package is imported, the classes within the package can now be used in the current scope, as they are defined within the new class itself.

OpenJava

OpenJava was the first open source implementation of the Java language and it is associated with the many components of the Java platform: the Java Virtual Machine (OpenJVM), the Java Class Library (OpenJCL), the Java Development Kit (OpenJDK) and the Java Runtime Environment (OpenJRE).

Basics

Compiling & Running

To compile a java program, use the javac command. To run a java program, use the java command.

javac Hello.java
java Hello

Import

Importing modules is done with the import keyword. The java.io package provides for system input and output In Java the program file name must match the specific class name.

import java.io.*;

public class Hello {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}

Here we're just using System.out.println to print to the console. The System.out is a static member of the System class, imported from java.io.

Data Types

Let's write a program that looks at the basic datatypes. There's:

Let's try using these with a program to convert Fahrenheit to Celsius.

public class Fahrenheit {
public static void main(String[] args) {
for (int f = 0; f <= 150; f+= 10) {
System.out.println(f + " " + (f - 32) * (5.0 / 9.0))
}
}
}

Here we're using a for loop to iterate over the range of temperatures. It uses the int type to iterate a for loop and to subtract 32 from the current temperature. The 5.0 / 9.0 is a double type. The System.out.println method takes a String and a double as arguments. If the 5.0 / 9.0 was an int by rewriting as 5 / 9, you'd get all 0's for the result because the int division truncates the result. These are the things that need to be considered in strongly typed languages.

Classes and Objects

Java is known as a object-oriented language. They describe how different kinds of objects relate to each other and how they can interact through functions and data.

Private Members

When an object is created, it is said to be an instance of a class. The parent class is the class from which the object is derived. You may not want to expose the internal workings of the class to the outside world. This is where the keyword private comes in.

Private inheritance is a way to hide the implementation details of a class. It means that whoever inherits from the class cannot access the private members. You'll have to define public methods to access the private members.

// ./Person.java
public class Person {
// private variable
private String name;

// constructor
public Person(String name) {
setName(name);
}

// getters & setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

As you'll see the private variable name is seemingly accessible to the getName & setName methods, which are public. That means to any instance of the Person class, the name variable is unable to access the Person.name variable directly, but thanks to getName & setName it can be accessed indirectly. These kinds of functions are called accessors or setters & getters.

// ./Consumer.java
import java.io.*;

public class Consumer {
public static void main(String[] args) {
Person p = new Person ("Peter Parker");
System.out.println(p.getName())
}
}

When p is instantiated, the Person constructor is called, which calls the setName method to set the name to "Peter Parker". Then the getName method is called to print the name to the console, showing the name is "Peter Parker" and is accessible to the Consumer class, but not the variable that stores that name.

Also note that Person was imported from the java.io package. This is because the two java files, the Person class and the class consuming it are in the same directory.

Packages

In the previous example of Person and Consumer, those different classes were broken up into different files, or packages. To simplify development by improving code reuse, readability and maintainability, packages are used to group related classes.

In this example file tree below, the Person class is in the person.java package, And the Consumer class is in the consumer.java package and their contents are are the same as before. Here is the file tree.

$ tree
.
├── University
│ └── person.java
└── consumer.java

2 directories, 2 files

One modification to the consumer.java file allows it to import the Person class from the University package by adding one line near the top to import it.

import java.io.*;
import University.Person;

public class Consumer {
public static void main(String[] args) {
Person p = new Person ("Peter Parker");
System.out.println(p.getName());
}
}

To import classes from a package, you need to use the import keyword. Then relative to the current directory, you need to specify the package name. In this case, the package name is University and the class name is Person. So the import statement becomes import University.Person.

Java Containers

Setting up a java development environment can be quite a pain. Fortunately java containers can really help simplify things. There's tons of lightweight java containers available. These days, unless specific reasons exist usually due to enterprise needs, the OpenJava stack is the best choice. Here is a link to the official OpenJDK container.

It is a highly stripped down linux environment within the container, so you will likely want to add some tools to it. Maybe a text editor to edit code or configuration files in the shell of the container. This could include the nano editor or vim editor. Edit the container's Dockerfile to add the tools you need.

FROM openjdk:11-jdk-slim
RUN apt-get update && apt-get install -y \
nano \
vim \
neovim # \
# any other tools you need...

Then run the container and ssh into it or attach to it.

docker run -it -rm --name openjdk11 openjdk:11-jdk-slim

References

Web Links

Note Links