Variables are symbolic names that store data. They are used to distinguish data from each other. Just as we distinguish people by their names, we also distinguish data by giving them variable names. Each variable has a type. These data types are divided into two categories: primitive types used in variable declarations and reference types used in object declarations. Variables created with primitive types are stored in the stack memory. Variables created with reference types are stored in the heap memory.

Variable Declaration Rule:

Access_Modifier Data_Type variable_name

  1. Access modifiers can be keywords like public, private, protected, static, etc. Writing them is not mandatory. If not written, they are considered public.
  2. When declaring variables, the type is written first. Then the variable name is written.

Example of a variable declaration:

int x; // Declares a variable named x, but it doesn't have a value yet.
int x = 2; // Allocates memory for x and assigns the value 2 to it.

Variable Declaration Rules:

  1. Every variable must have a type.
a = 10; // This would give an error: a cannot be resolved to a variable.
System.out.println(a); // This would also give an error: The local variable a may not have been initialized.
  1. Variables cannot be used without being assigned a value.
  2. Variables of the same type can be declared on the same line.
String a = "Java", b = "C++", c = "C#"; // Variables a, b, and c of type String are declared.

Primitive Types:

  1. byte:
    • 8-bit unsigned integer type.
    • Range: -128 to 127.
  2. short:
    • 16-bit unsigned integer type.
    • Range: -32,768 to 32,767.
  3. int:
    • 32-bit unsigned integer type.
    • Range: -2^31 to 2^31-1.
  4. long:
    • 64-bit unsigned integer type.
    • Range: -2^63 to 2^63-1.
  5. float:
    • 32-bit floating-point type.
    • Precision: Approximately 7 decimal places.
  6. double:
    • 64-bit floating-point type.
    • Precision: Approximately 15 decimal places.
  7. char:
    • 16-bit Unicode character type.
    • Range: ‘\u0000’ to ‘\uffff’.
  8. boolean:
    • Represents logical (boolean) values.
    • Can only be true or false.

Reference Types:

In reference types, variables store addresses. Reference types are defined using the new keyword. Reference types are stored in the heap memory.

Unlike primitive types, operations in reference types are performed on the variable itself. In other words, operations are performed on the original value, not on a copy. This may result in a change in value.

Example:

public class Main {
    public static void main(String[] args) {
        
        RefType num = new RefType();
        num.refNum = 10;
        System.out.println("First value of number: " + num.refNum); // Output = 10
        sum(num);
        System.out.println("First value of number: " + num.refNum); // Output = 30

    }

    public static void sum(RefType refType) {
        refType.refNum = refType.refNum + 20;
    }

    static class RefType {
        public int refNum;
    }
}

Here, we created a variable named num of type RefType. In the RefType class, there is a variable. By assigning a value to num.refNum, we sent it directly to the sum() method. Here, refType.refNum received a new value, and now num.refNum became 30. If it had been sent as a copy, we would still get the value 10. In reference types, since variables store the addresses in memory, the original value changes.

String Data Type:

String is a reference type. The String type is composed of the combination of characters. Unlike char, String is defined within double quotes.

String writing = "Ahmet Senocak";
System.out.println(writing);

Primitive Types in Reference Type Form:

A variable can be declared both as a primitive type and as a class derived from that type. Variable types are also classes. This means that in addition to declaring variables in the known way, they can also be declared as an object derived from a class.

public class Main {
    public static void main(String[] args) {
        
        int i = 5; // Primitive type: int
        Integer j = new Integer(3); // Reference type: Integer (Reference type of int in Java)
        System.out.println("Primitive type (int) value: " + i);
        System.out.println("Reference type (Integer) value: " + j);
    }
}

Boxing and Unboxing Concepts:

Boxing and unboxing are terms used in Java for primitive data types. Boxing is the process of converting a primitive value to the corresponding wrapper class (e.g., converting int to Integer). Unboxing is the process of obtaining the primitive value from a wrapper class (e.g., converting Integer to int). Here is an example:

public class BasicBoxingUnboxingExample {
    public static void main(String[] args) {
        // Boxing: Converting int to Integer
        int primitiveInt = 42;
        Integer wrapperInteger = primitiveInt; // Autoboxing

        // Unboxing: Converting Integer to int
        Integer anotherWrapperInteger = 30;
        int anotherPrimitiveInt = anotherWrapperInteger; // Autounboxing

        // Printing to the console
        System.out.println("Boxing Example - primitiveInt: " + primitiveInt + ", wrapperInteger: " + wrapperInteger);
        System.out.println("Unboxing Example - anotherWrapperInteger: " + anotherWrapperInteger + ", anotherPrimitiveInt: " + anotherPrimitiveInt);
    }
}

In this example, autoboxing and autounboxing are used. Starting from Java 5, automatic conversion was introduced to perform these transformations without explicitly calling methods such as valueOf and intValue. Autoboxing and autounboxing make the code cleaner and more readable.

Type Casting:

Suppose we have received a number from the user. If we want to perform mathematical operations with this number, we need to convert it to the int type because the number entered by the user is received as a string type. Another example is when we want to discard the fractional part of a decimal number.

public class TypeCastingExample {
    public static void main(String[] args) {
        // Automatic conversion (small to large)
        int smallInt = 10;
        double doubleNumber = smallInt; // Automatic conversion from int
        System.out.println("Automatic Conversion (small to large):");
        System.out.println("smallInt: " + smallInt);
        System.out.println("doubleNumber: " + doubleNumber);
        
        // Explicit conversion (large to small)
        double anotherDouble = 20.56;
        int intNumber = (int) anotherDouble; // Explicit conversion from double to int
        
        System.out.println("\nExplicit Conversion (large to small):");
        System.out.println("anotherDouble: " + anotherDouble);
        System.out.println("intNumber: " + intNumber);
  }
}

In this example, automatic conversion from int to double (small to large) and explicit conversion from double to int (large to small) are demonstrated. In explicit conversion, the target data type is specified in parentheses, and this conversion may result in data loss, as there may be loss of information when converting from a larger type to a smaller type.

Leave a Reply

Your email address will not be published. Required fields are marked *