Type Casting, Garbage Collection, and Thread Intercommunication in Java

Type Casting in Java

Implicit (Widening) Type Casting

Implicit type casting is the automatic conversion of a smaller data type to a larger data type by the Java compiler. This type of casting is safe and does not result in data loss because it converts a lower precision type to a higher precision type.

public class ImplicitTypeCasting {

	public static void main(String[] args) {

		int intVal = 100;

		long longVal = intVal; // int to long (widening)

		float floatVal = longVal; // long to float (widening)

		System.out.println("Int value: " + intVal);

		System.out.println("Long value: " + longVal);

		System.out.println("Float value: " + floatVal);

	}

}

Explicit (Narrowing) Type Casting

Explicit type casting is the manual conversion of a larger data type to a smaller data type. This type of casting is not safe and can result in data loss because it converts a higher precision type to a lower precision type. It requires explicit syntax to perform the conversion.

public class ExplicitTypeCasting {

	public static void main(String[] args) {

		double doubleVal = 100.04;

		long longVal = (long) doubleVal; // double to long (narrowing)

		int intVal = (int) longVal; // long to int (narrowing)

		System.out.println("Double value: " + doubleVal);

		System.out.println("Long value: " + longVal);

		System.out.println("Int value: " + intVal);

	}

}

Garbage Collection in Java

Garbage Collection in Java is a process by which the Java Virtual Machine (JVM) automatically identifies and discards objects that are no longer needed by a program, thereby freeing up memory resources. This is an automatic process, which relieves developers from the responsibility of manual memory management and helps to prevent memory leaks and other related issues.

How Garbage Collection Works

  • Identification of Garbage: The JVM identifies objects that are no longer reachable or in use. An object is considered unreachable if no live thread can access it directly or indirectly through a chain of references.
  • Garbage Collection Algorithms: Various algorithms can be used to collect garbage, including:
  • Mark-and-Sweep: The garbage collector traverses all live objects and marks them. It then sweeps through the heap, collecting all unmarked objects.
  • Generational Garbage Collection: Objects are categorized based on their age. The heap is divided into several generations:
  • Young Generation: Newly created objects.
  • Old (or Tenured) Generation: Long-lived objects.
  • Permanent Generation (Metaspace in Java 8 and later): Metadata such as class definitions.

Memory Management in Java

Java uses an automatic memory management system to handle the allocation and deallocation of memory. This system is primarily composed of the heap and the stack:

  • Heap Memory:
  • Description: The heap is a runtime data area from which memory for all class instances and arrays is allocated.
  • Management: The heap is managed by the garbage collector, which automatically frees memory occupied by objects that are no longer in use.
  • Stack Memory:
  • Description: The stack is used for storing local variables and function call-related data.
  • Management: Memory allocation and deallocation for the stack are handled in a Last-In-First-Out (LIFO) manner. Each thread has its own stack.
public class GarbageCollectionExample {

	public static void main(String[] args) {
		GarbageCollectionExample obj1 = new GarbageCollectionExample();
		GarbageCollectionExample obj2 = new GarbageCollectionExample();
		obj1 = null; // Eligible for garbage collection
		obj2 = null; // Eligible for garbage collection
		System.gc();
	}

	@Override
		protected void finalize() throws Throwable {
			System.out.println("Garbage collection is performed!");
		}

}

Call by Value and Call by Reference

Call by Value means that a copy of the actual parameter is passed to the method. Changes made to the parameter inside the method do not affect the original value.

public class CallByValueExample {

	public static void main(String[] args) {
		int original = 10;
		modifyPrimitive(original);
		System.out.println("Original value after method call: " + original);
	}

	public static void modifyPrimitive(int value) {
		value = 20; // This change is local to this method
	}

}

Call by Reference means that a reference to the actual parameter is passed to the method. Changes made to the parameter affect the original value. Java does not support call by reference directly but achieves similar behavior for objects because it passes the reference to the object by value.

class Person {
    String name;
}

public class CallByReferenceExample {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = “Alice”;
        modifyObject(person);
        System.out.println(“Person’s name after method call: ” + person.name);
    }

    public static void modifyObject(Person p) {
        p.name = “Bob”; // This changes the name field of the original object
    }
}

# threads intercommunication

class Customer{    
int amount=10000;    
synchronized void withdraw(int amount){    
System.out.println(“going to withdraw…”);    
if(this.amount
System.out.println(“Less balance; waiting for deposit…”);    
try{wait();}catch(Exception e){}    }    
this.amount-=amount;    
System.out.println(“withdraw completed…”);    }    
synchronized void deposit(int amount){    
System.out.println(“going to deposit…”);    
this.amount+=amount;    
System.out.println(“deposit completed… “);    
notify();    }    }    
class Test{    
public static void main(String args[]){    
final Customer c=new Customer();    
new Thread(){    
public void run(){c.withdraw(15000);}    
}.start();    
new Thread(){    
public void run(){c.deposit(10000);}    
}.start();    }}    

#write a java program that to create two threads so that one thread prints even and other thread print odd number between 100 and 200

class EvenOddPrinter {
private int number = 100;
private final Object lock = new Object();
public void printEven() {
synchronized (lock) {
while (number
if (number % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ” – Even: ” + number);
number++;          lock.notify();
} else {              try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println(“Thread interrupted”);
 }}}}}
 public void printOdd() {
 synchronized (lock) {
 while (number
 if (number % 2 != 0) {
 System.out.println(Thread.currentThread().getName() + ” – Odd: ” + number);
 number++;         lock.notify();
 } else {            try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println(“Thread interrupted”);                    }
}}}}}
public class EvenOddThreadExample {
public static void main(String[] args) {
EvenOddPrinter printer = new EvenOddPrinter();
Thread evenThread = new Thread(printer::printEven, “EvenThread”);
Thread oddThread = new Thread(printer::printOdd, “OddThread”);
evenThread.start();
oddThread.start();    }}

#wrapper classes

class main {
public static void main (string[]args){
Integer a= Intrger.value of (5);
Double b=Double.value of (6.5);
Boolean c = Boolean.TRUE;
system.out.println(a),(b),(c);}}

# wap to generate a random number

import java.util.Scanner;
class Main{
public static void main(String[]args){
System.out.println(“Enter 10 numbers”);
int[]nums=new int[10];
for(int i=0;i
nums[i]=sc.nextInt();
int rI=(int)(Math.random()*10);
int val=nums[rI];
system.out.println(“Value’+val);
sc.close();}}

#JDBC CRUD 1 Connect to the database 

try { 
 Class.forName(“com.mysql.jdbc.Driver”); 
 Connection con = DriverManager.getConnection( 
  “jdbc:mysql://localhost:3306/mydb“, “username”, 
  “password”); 
 System.out.println(“Connection established.”); 

catch (Exception e) { 
 e.printStackTrace(); 
}

2Create a new record 

try { 
String sql = “INSERT INTO table_name (column1, column2, column3) VALUES (?, ?, ?)”; 
PreparedStatement statement = con.prepareStatement(sql); 
statement.setString(1, “value1”); 
statement.setString(2, “value2”); 
statement.setInt(3, 123); 
statement.executeUpdate(); 
System.out.println(“Record created.”); 
} catch (SQLException e) { 
e.printStackTrace(); 
}

3. Read a record

try { 
String sql = “SELECT column1, column2, column3 FROM table_name WHERE id = ?”; 
PreparedStatement statement = con.prepareStatement(sql); 
statement.setInt(1, 1); 
ResultSet result = statement.executeQuery(); 
if (result.next()) { 
 String column1 = result.getString(“column1”); 
 String column2 = result.getString(“column2”); 
 int column3 = result.getInt(“column3”); 
 System.out.println(“Column 1: ” + column1); 
 System.out.println(“Column 2: ” + column2); 
 System.out.println(“Column 3: ” + column3); 

} catch (SQLException e) { 
e.printStackTrace(); 
}

4. Update a record

try { 
String sql = “UPDATE table_name SET column1 = ?, column2 = ?, column3 = ? WHERE id = ?”; 
PreparedStatement statement = con.prepareStatement(sql); 
statement.setString(1, “new_value1”); 
statement.setString(2, “new_value2”); 
statement.setInt(3, 456); 
statement.setInt(4, 1); 
statement.executeUpdate(); 
System.out.println(“Record updated.”); 
} catch (SQLException e) { 
e.printStackTrace(); 
}

5. Delete a record

try { 
String sql = “DELETE FROM table_name WHERE id = ?”; 
PreparedStatement statement = con.prepareStatement(sql); 
statement.setInt(1, 1); 
statement.executeUpdate(); 
System.out.println(“Record deleted.”); 
} catch (SQLException e) { 
e.printStackTrace(); 
}

# Runnable threads class MyRunnable implements Runnable{
public void run(){
System.out.println(“Runnable Thread”);}}
class MyThread extends Threads{
public void run(){
System.out.println(“Thread class”);}}
class Main{
public static void main(String[]args0{
MyRunnable a=new MyRunnable();
Thread b = new Thread(a);
MyThrad c=new MyThread();
b.start();
c.start();}}