0% found this document useful (0 votes)
11 views9 pages

Java Basics

The document discusses various Java concepts including inner classes, annotations, generics, and design patterns. It explains inner classes such as static nested classes, local inner classes, and anonymous inner classes, along with their usage. Additionally, it covers annotations for metadata, generics for type safety, and design patterns like Singleton, Factory, and Observer, highlighting their importance in Android development.

Uploaded by

questandlearn001
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views9 pages

Java Basics

The document discusses various Java concepts including inner classes, annotations, generics, and design patterns. It explains inner classes such as static nested classes, local inner classes, and anonymous inner classes, along with their usage. Additionally, it covers annotations for metadata, generics for type safety, and design patterns like Singleton, Factory, and Observer, highlighting their importance in Android development.

Uploaded by

questandlearn001
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 9

11.

Inner Classes

Defined as a non-static class inside another class.

class Outer {
private String message = "Hello";

class Inner {
void showMessage() {
System.out.println(message);
}
}
}

public class Main {


public static void main(String[] args) {
// Create an instance of the Outer class
Outer outer = new Outer();

// Create an instance of the Inner class using the Outer instance


Outer.Inner inner = outer.new Inner();

// Call the showMessage method of the Inner class


inner.showMessage();
}
}

javac Outer.java Main.java

java Main

Static Nested Class:

class Outer1 {
static String message = "Hello";

static class Nested {


void showMessage() {
System.out.println(message);
}
}

public static void main(String[] args) {


// Create an instance of the static nested class
Outer.Nested nested = new Outer.Nested();

// Call the showMessage method of the Nested class


nested.showMessage();
}
}

Local Inner Class:


class Outer {
void display() {
// Local Inner Class defined within a method
class Inner {
void show() {
System.out.println("Inside local inner class");
}
}

// Create an instance of the local inner class and call its method
Inner inner = new Inner();
inner.show();
}

public static void main(String[] args) {


// Create an instance of the Outer class
Outer outer = new Outer();

// Call the display method to invoke the local inner class


outer.display();
}
}

Anonymous Inner Class:

public class Main {


public static void main(String[] args) {
// Create an anonymous inner class implementing Runnable
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Anonymous inner class");
}
};

// Call the run method


runnable.run();
}
}

---------------------

12. Annotations
Annotations in Java provide metadata about the code. They do not directly affect
the code's behavior but can influence how the code is processed (e.g., by the
compiler or frameworks).

Commonly Used Annotations:


@Override:

Indicates a method is overriding a superclass method.

public class ExampleClass {


@Override
public String toString() {
return "Example";
}

public static void main(String[] args) {


// Create an instance of the ExampleClass
ExampleClass example = new ExampleClass();
// Call the toString method (implicitly or explicitly)
System.out.println(example); // Implicit call to toString()
System.out.println(example.toString()); // Explicit call to toString()
}
}

@Deprecated:

Marks a method or class as outdated, advising against its use.

public class ExampleClass1 {


@Deprecated
void oldMethod() {
System.out.println("This is a deprecated method. Use something newer.");
}

void newMethod() {
System.out.println("This is the new and recommended method.");
}

public static void main(String[] args) {


ExampleClass1 example = new ExampleClass1();

// Calling the deprecated method


example.oldMethod();

// Calling the new method


example.newMethod();
}
}

@SuppressWarnings:

Suppresses compiler warnings.

import java.util.ArrayList;
import java.util.List;

public class ExampleClass2 {


@SuppressWarnings("unchecked")
void method() {
// Example of unchecked operation: assigning a raw type to a generic type
List rawList = new ArrayList();
rawList.add("Hello");
rawList.add(123); // Mixed types in raw list

// Casting rawList to a generic List<String>, which can cause warnings


List<String> stringList = rawList;

// Printing elements (this may cause runtime issues if types mismatch)


for (String item : stringList) {
System.out.println(item);
}
}
public static void main(String[] args) {
ExampleClass2 example = new ExampleClass2();

// Call the method containing suppressed warnings


example.method();
}
}

Custom Annotations:

Developers can define their own annotations.

MyAnnotation.java
----------------------------
// Define the custom annotation
@interface MyAnnotation {
String value();
}

ExampleClass3.java
------------------------------
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class ExampleClass3 {

// Apply the custom annotation to a method


@MyAnnotation(value = "This is a custom annotation")
void annotatedMethod() {
System.out.println("Method is annotated with MyAnnotation.");
}

public static void main(String[] args) throws Exception {


ExampleClass3 example = new ExampleClass3();

// Access the custom annotation using reflection


Method method = example.getClass().getMethod("annotatedMethod");

// Check if the method is annotated with MyAnnotation


if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
System.out.println("Annotation value: " + annotation.value());
}

// Call the annotated method


example.annotatedMethod();
}
}

Why it’s Important in Android:


Android uses annotations like @Nullable, @NonNull, @RequiresPermission, and
@UiThread to enhance code readability, prevent bugs, and enforce proper threading.

14. Generics
Generics enable classes, interfaces, and methods to operate on types specified at
runtime, ensuring type safety and reducing runtime errors.

How Generics Work:


Generic Class:

Box.java
------------
// Generic class Box that can hold any type of object
class Box<T> {
private T value;

// Method to set the value of the box


void setValue(T value) {
this.value = value;
}

// Method to get the value from the box


T getValue() {
return value;
}
}

Utils.java
-------------
// Utility class with a generic method to print elements of an array
class Utils {
// Generic method to print an array of any type T
public static <T> void printArray(T[] array) {
for (T item : array) {
System.out.println(item);
}
}
}

Main.java
----------------
public class Main {
public static void main(String[] args) {
// Using the Box class with an Integer type
Box<Integer> intBox = new Box<>();
intBox.setValue(10);
System.out.println("Value in intBox: " + intBox.getValue());

// Using the Box class with a String type


Box<String> strBox = new Box<>();
strBox.setValue("Hello, Generics!");
System.out.println("Value in strBox: " + strBox.getValue());

// Using the Utils class to print an array of Integers


Integer[] intArray = {1, 2, 3, 4, 5};
Utils.printArray(intArray);

// Using the Utils class to print an array of Strings


String[] strArray = {"A", "B", "C"};
Utils.printArray(strArray);
}
}
--------------------------------------------------------------------
Generic Method:

java
Copy code
class Utils {
public static <T> void printArray(T[] array) {
for (T item : array) {
System.out.println(item);
}
}
}
Bounded Type Parameters:

Restrict the types used in generics.


java
Copy code
class NumberBox<T extends Number> {
private T value;

void setValue(T value) {


this.value = value;
}

T getValue() {
return value;
}
}

---------------------------------------------------------------------------------
Why it’s Important in Android:
Generics are widely used in Android APIs, such as ArrayAdapter,
RecyclerView.Adapter, and AsyncTask, to ensure type safety and reduce boilerplate
code.

15. Basic Design Patterns


Design patterns are reusable solutions to common problems in software design. They
provide a standard way to structure and organize code.

Key Design Patterns for Android:


Singleton Pattern:

Ensures a class has only one instance and provides global access to it.
Singleton.java
---------------------
public class Singleton {
// Static variable to hold the single instance
private static Singleton instance;

// Private constructor to prevent instantiation


private Singleton() {}

// Public method to provide access to the instance


public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

Main.java
---------------
public class Main3 {
public static void main(String[] args) {
// Get the Singleton instance
Singleton singleton = Singleton.getInstance();

// Print the instance to check if it's created


System.out.println(singleton);
}
}

Usage in Android: Managing a shared resource like a database or network connection.

Factory Pattern:

Creates objects without exposing the instantiation logic to the client.


Shape.java
---------------
public interface Shape {
void draw();
}

Circle.java
------------------
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Circle");
}
}

Rectangle.java
---------------------
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Rectangle");
}
}

ShapeFactory.java
-----------------------------
public class ShapeFactory {
// Factory method to return different shapes based on the input type
public static Shape getShape(String type) {
if ("circle".equalsIgnoreCase(type)) {
return new Circle();
} else if ("rectangle".equalsIgnoreCase(type)) {
return new Rectangle();
}
return null;
}
}

Main.java
---------------
public class Main4 {
public static void main(String[] args) {
// Get a Circle object from the factory
Shape circle = ShapeFactory.getShape("circle");
circle.draw(); // Output: Drawing a Circle

// Get a Rectangle object from the factory


Shape rectangle = ShapeFactory.getShape("rectangle");
rectangle.draw(); // Output: Drawing a Rectangle

// Attempt to get an invalid shape


Shape unknown = ShapeFactory.getShape("triangle");
if (unknown == null) {
System.out.println("Shape not recognized.");
}
}
}

Observer Pattern:

Establishes a one-to-many dependency so when one object changes state, its


dependents are notified.
Observer.java
--------------------
public interface Observer {
void update(String message);
}

Subject.java
-------------------

import java.util.ArrayList;
import java.util.List;

public class Subject {


private List<Observer> observers = new ArrayList<>();

// Add an observer to the list


public void addObserver(Observer observer) {
observers.add(observer);
}

// Remove an observer from the list


public void removeObserver(Observer observer) {
observers.remove(observer);
}

// Notify all observers about a change


public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}

ConcreteObserver.java
-----------------------------------

public class ConcreteObserver implements Observer {


private String name;

public ConcreteObserver(String name) {


this.name = name;
}

@Override
public void update(String message) {
System.out.println(name + " received message: " + message);
}
}

Main.java
------------

public class Main5 {


public static void main(String[] args) {
// Create a subject
Subject subject = new Subject();

// Create observers
Observer observer1 = new ConcreteObserver("Observer 1");
Observer observer2 = new ConcreteObserver("Observer 2");
Observer observer3 = new ConcreteObserver("Observer 3");

// Add observers to the subject


subject.addObserver(observer1);
subject.addObserver(observer2);
subject.addObserver(observer3);

// Notify all observers with a message


subject.notifyObservers("The subject has changed!");

// Remove observer2 and notify again


subject.removeObserver(observer2);
subject.notifyObservers("The subject has changed again!");
}
}

Usage in Android: The LiveData and ViewModel architecture components are based on
this pattern.

Model-View-Controller (MVC) and Model-View-ViewModel (MVVM):

Architectures used to separate concerns in an application. Usage in Android: MVVM


is widely adopted with Jetpack libraries.

You might also like