Hello world!

The purpose of a hello world program is to give an insight into how code is magically transformed into a simple program printing a "hello world" message. The following code written in java is an example of hello world program.

This code is composed of a java Class representing a structure that contains the entry point for the java platform to execute the main code. this entry point is a function often called the Main function.

First and Foremost, to be able to run that code, you need to compile it with the Java CompilerThe java compiler transforms java code into an intermediate low-level code known as BytecodeThis intermediate code is interpreted into a running application by using the java Runtime Interpreter.

  • Javac is the java compiler tool. 
  • Java is the java Runtime interpreter.

These tools can be found in the JDK that stands for java Development Kit. The JDK contains a set of tools used for java development, execution and debugging purposes. it can be downloaded from the official site of oracle. 

here is the command that compiles the previous code and generates a HelloWorld.class file containing the byte code

  • javac HelloWorld.java

The following command line interprets the Bytecode into a running application.

  • java HelloWorld

Don't forget to remove the extension .class from the filename in front of the interpreter and to be in the directory of the bytecode file before executing the command.

The output should be

  • Hello world !

Sometimes, your program awaits for arguments to be passed to it.
Note that in most modern IDEs, you won't need to type those commands manually, instead, you will just have to configure your IDE with the appropriate JDK and compile and run your application 
conveniently through buttons.

Arguments are passed to the program as follows 

  • java HelloWorld ismail

the program now prints 

  • Hello ismail

Classes' structure

A Class is like a blue print, it describes how the instantiated object will behave in the running program and at what state it will resemble in memory.
Classes structure is mainly composed of two parts, Data and Methods.

Data or state, also known as fields, are stored as part of the object in memory and must have a Data type.
For instance, here is how to declare a variable that will hold an String value
private String variableName="Ismail";
Methods or Functions are a primary component of the OOP paradigm, they operate on data during the life cycle of an application.
For instance, here is a method that initializes the previous integer variable
 public void setVariableName(String variableName){this.variableName=variableName;}

Classes live inside files with the .java extension which are called java files, a Java file can contain an unlimited number of Package private classes, however, it can only contain a single Public class whose name must conform to the name of the java file, otherwise, the java file won't compile.

Package private and Public are java key words known as access modifiers, which we'll see them in detail in a future section.

 

Packages

Java files can be organized within directories called Packages, they are used to group a certain set of Classes that shares the same domain.
The java representation of a package is the directory path separated by a dot instead of slashes. For instance, the package of the directory com/isqo, is com.isqo
A package linking statement should be set at the beginning of the file to logically link a java file to a package.

packages allows us to have two classes sharing the same name each one lives separately in its package.

Data types

Java counts eight Primary types, in total, each one plays a certain role and imposes a specific memory allocation size.

Data  TypeDescriptionMemory allocation Size
byte
a byte variable hold a byte value between -128 (-1 * 2^7) and 127 (2^7 - 1), this type is usually used with Arrays to hold a sequence of raw data that could represent a JPEG picture , a large text file, etc...8 bits
short
short is greater than byte by 8 bits, short variables may hold a value between -32768 ( -1 * 2^15) and 32767 (2^15 - 1).from my experience, this data type is not used on a day-to-day basis, unless you work on high-performance demanding or mathematical application.16 bits
char
char variables hold 16 bits that are Unicode encoded values (UTF-16). let's take the 'a' encoded character, its hexadecimal value is 0x0061 which is the equivalent of the binary 0000000001100001 value, luckily, we don't have to deal with bits to refer to characters. In the real world, char data types are rarely used, we use instead String objects.
16 bits
int
This type is regularly and widely used in the world of java for holding integer values. An int variable may hold a value between -2147483648 ( -1 * 2^31) and 2147483647 (2^31 - 1).32 bits
long
long is greater than int by double, which means, it may hold a value between -9223372036854775808 ( -1 * 2^63) and 9223372036854775807 ( 2^63 - 1), as with short type, it isn't a type that we'll use regularly.64 bits
float

float type is used for manipulating floating-point values, its boundaries are greater than integer even though they got the same allocation size,

(1.40129846432481707e-45, 3.40282346638528860e+38). explaining this in details is beyond the scope of this section but briefly, it is is due to the IEEE 754 standard that imposes a specific binary composition on float values that causes them to become less precise but could be greater than what a maximum integer value can be.  

32 bits
double
double is greater than float by double, as with long and short data types, this data type is specifically used in the mathematical or scientific context 64 bits
boolean
boolean type is used to hold true or false booleans values, boolean variables are usually used to represent objects state.JVM-dependent (on hotspot jvm, i got approximately one byte=8 bits)

So far, we've seen only primary data types.
Another data type exists and especially for objects, it is called Reference data type. we call it this way, because when we allocate a fragment of memory during instantiation, we get a reference pointing to it that allows us to access that fragment.
For the following ClassA on line 3

We have the variable declaration below on line 7  whose type is of ClassA 

Memory allocation

The memory is composed of two main areas, the stack and the heap. When an object is instantiated, its memory fragment is allocated from the heap.

In the program above, on line 7, we instantiate the ClassB and allocate a fragment of memory by using the new key word followed by a special function call whose name is the same as its class.This special function is called constructor.

The instantiation returns a reference pointing to that fragment which is finally stored in the objectB variable.

By default, each class has a hidden constructor that takes no argument, however,we could explicitly define it.

Sometimes, we are constrained to write it especially when we define other constructors that have arguments. if we don't and try to instantiate an object with it, it won't compile.

the code below doesn't compile because of line 7, we instantiate ClassB with an undefined constructor.

Initialization order

When an object is instantiated, its internal fields are initialized following the order in which they are declared except the fields that are initialized inside the constructor, they are initialized at the end of the process. 

Classes Imports

Often, you'll need a function of a Class that lives in a different package. in this case, you have to use the import statement
In the example above, In order to instantiate ClassB on line 5, we need to import ClassB from the packages.classes.imports.b package on line 3.

Someday, you will be tempted to import many classes located in the same package using this single statement :

It won't work, only the classes living inside packages.classes.imports.b will be imported, the nested packages inside won't.

Putting many asterisks in the import statement as follows doesn't also work

Note that only one Asterisk is allowed and should be at the the end of the import statement, therefore, to import multiple sets of classes,you will need multiple import statements.

you will often face import collisions when importing two classes that have the same name but live in different packages.The compiler doesn't know which one to choose and therefore fails.

Also beware of ambiguous import, in the example below, the code won't compile because Date class lives in both packages and the compiler won't know which Date Class to import.

Importing Classes explicitly takes precedence over wildcards, the following compiles successfully because java.util.Date Class won't be imported. 

Fields and methods structure

A field is basically composed of three main elements, an Access modifier , Data type and the Variable identifierit could also possess other types of key words, but they are all optional, except Data types which are mandatory. 
let's decompose the structure of a variable of integer type
so for the above example, we have two key words :
  • private: represents the private access modifier, which is simply a key word that controls the access scope of the variable from the outside.
  • int: represents the integer data type
  • variableName: the variable identifier or name, it must respect a certain identification pattern.

beware, A java class cannot contain multiple fields with the same name.

A java method is basically composed of two key words : an Access modifier and a Return type plus the Function identifier. A function could have a list of parameters but it is not mandatory.

let's decompose the setVariableName function.

from the above example, we have:

  • public: represents the public access modifier, which is simply a key word that controls the access scope of a variable from the outside.
  • void: represents the return data type, in this case, it is void which means return nothing.
  • setVariableName: the function identifier or name, it must respect a certain identification pattern.
  • (String variableName): The parameters list,which is optional, infinite and of various data types.

For example, the parameter list below contains four elements of various data types.

The return type could be any possible data type.The example below has two methods, one that returns an integer and another that returns boolean.

Each method has its signature, and it is what define the uniqueness of a function. A Class cannot contain two methods with the same signature. a method signature is composed of the Function identifier and The parameters list data types order.

For instance, the code below won't compile because the two methods have the same identifier and even though the parameter lists are not the same, they have the same data types order.

The examples below will compile because the parameters lists are different.
Here, The methods names are different.
Note that, the return type and access modifier are not part of the method signature.

Access modifiers

In the real world, there will be plenty of objects interacting with one another, and sometimes an object would need to retrieve data stored in other objects or execute operations on them.

The role of access modifiers is to control the level of this access. Access modifiers can be put in front of many java elements like Classes, Variables, Methods, and so on.

Package private

A package private Class method implies that all the Classes that exist in the same package as the Method Class can call it directly with no restriction whereas the classes that live outside cannot. The same level of accessibility applies to variables and classes. There is no key word for package private. To declare a package private java element, you have to remove the access modifier key word.

In the example above, we've three classes. Classes A and B are in the same package access.modifiers.a; whereas Class C is in a different package access.modifiers.b;

The ClassC can call the method MethodA because ClassC and ClassA are in the same Package While ClassB cannot because MethodA is package private and ClassB isn't in access.modifiers.a;

Note that Classes cannot be private or protected because their access level is more restrictive than public and protected, imagine a public method inside a protected class, it doesn't make sense.

Private

When a Class Method or variable is private, it isn't reachable from outside. To declare a private java element, you have to put the private key word in front of it.

the example below doesn't compile because we try to call the private methodA from Class B.

Protected

Protected access modifier is a special one, it is mainly related to the OOP inheritance concept which we didn't explain it so far, but just remember that protected access modifier behaves like package private in addition to the fact that some special classes called children or implementers living outside the main package can access the protected elements of the parent class.

Public

,A Public java element like the Classes defined in the examples above are reachable from everywhere.

Naming pattern

Naming your java components has to respect a certain pattern otherwise your code won't compile. The pattern states that your identifier must begin with letters [A-Z]underscore (_) or Dollar ($) symbols. Starting your component name with a number isn't possible. you also aren't allowed to use special characters like @!* and Reserved java key words like public private and so one.

Valid identifiers

  • public void Ok1453$4z_(int a) // here we have a method
  • private int _eaze445ae // here we have a variable
  • public class $_aezae54_ // here we have class

Invalid identifiers

  • Ok@1453$4z_ (it contains @)
  • 1_eaze445ae (it starts with 1)
  • public, private (java reserved keyword)

Variables scope

A java variable might live inside three different scopes during a specific lifetime

Local scope

The scope of method and initializer blocks.

At the end of the block's execution, the variable is destroyed.

Instance scope

Here, the variable's lifespan depends upon the instantiated object in which it lives. if the object is destroyed, the variable will too.

Class scope

If a field is declared static, it is going to live until the program terminates.

Commenting code

Three types of comments exist, single-line,multi-line and Java doc comments

Single-line

Multi-line

Java-doc

Java-doc/multi-line comments cannot contain other multi-line/Java-doc comments.Otherwise, the compiler will throw "illegal start of type" Error message like in the example below.

Mathematical Operators

Mathematical operations are used everywhere whether to calculate a company's payroll or the employees' number. The structure of an operation is composed of operands and operators and usually The result is assigned to variables. the statement below is an example of an operation.

 int a=1 + 2

  • 1 and 2 are the operands
  • The sign + is the Addition operator.
  • The sign=is the Assignment operator

Java supports other operators for different purposes :

  • Relational and equality operators
  • Logical operators 
  • Ternary operators
  • Unary operators
  • Binary operators

We'll see each one in the next sections .

Arithmetic operators

Java supports using the following classical arithmetic operators

  • Multiplication *
  • Division /
  • Modulus % 
  • Addition +
  • Subtraction -

Assignment operators

These operators are usually used to assign Mathematical operations results to variables .The most-used assignment operator is the equal operator "=", which simply assigns operations' result to variables.

Sometimes, You'll encounter Compound Assignment operators which always have the equal sign on the right side beside other operators +=, -=, *=, /=, %=, &=, ^=, !=, <<=,>>=, >>>=

This way of writing operators behaves as a shortcut that uses the previous value of the statement's variable as an operand in the whole operation.


Relational and Equality operators

Relational operators are used to evaluate a test case before entering a protected block of code

  • less than <
  • greater than >
  • less than or equal to<=
  • greater than or equal to>= 
  • instanceof 
  • equal to == 
  • not equal to !=

Short-circuit/logical/operators

These operators are used to verify a set of tests either

  • Collectively using the Conditional-And, implying that if one test fails, the whole evaluation fails. (in code we write &&)
  • Or individually with the Conditional-or, implying that only one test evaluated to True is needed, the other tests aren't passed by. (in code we write ||)

Ternary operators

Ternary operators are used to compact conditional blocks of code into one line. These conditional blocks must treat only two cases, for instance, this example 

  • if(test){First case;}else{Second case;}   

becomes :

  • Test First case : Second case 

If the Test evaluates to true, the first case block is entered, otherwise, the second.


Unary operators

These kind of operators are involved with just one expression, they don't need more than one operand unlike arithmetic operators.

  • Post-unary operators expression++,expression--
  • Pre-unary operators ++expression, --expression
  • The unary plus + 
  • The unary minus: - 
  • The logical not: ! 

Shift and Logical operators

These operators are less commonly used, They perform bits' operations : 

  • The signed left shift << 
  • The signed right shift >>
  • The unsigned right shift >>>   
  • Bitwise AND &  
  • Bitwise exclusive OR 
  • Bitwise inclusive OR 
  • Bitwise complement ~

Numeric promotion

During arithmetic operations, the type of operands could change into a larger one. This phenomenon is called numeric promotion, it happens when we perform arithmetic operations involving smaller and larger data types. For instance, if we add two numbers, one is int, the other is float. Java will promote the int one to float before performing addition, the result's type will be the larger type, which is float.

In the example above, on line 5, the number 5 is firstly promoted to its float version which is 5.0f before doing addition.

Notice that the statement on line 3 doesn't compile because assigning a result of larger type (float) to a variable of smaller type (int) is not possible. the float result must be casted to int as we've done on line 4.  Casting means adapting a value to its holder's type which usually implies loosing a part of that data to be able to fit in, this feature should be used with precaution.

Smaller operands types like byte, short, and char are always promoted to int , even if neither of the operands is int.

Order of precedence