Java common questions
1.
Okay, here are concise explanations for each of your requested comparisons:
-
Public vs Private access modifiers
Access modifiers in Java control the visibility of classes, interfaces, variables, and methods.Public-
Definition:Public: Members (variables,classes, methods,constructors) or classesvariables) declaredpublic
are accessible from any other class,regardless of the package they are in.anywhere. -
Purpose:To expose an API (Application Programming Interface) for other parts of the application or external libraries to use.
PrivateDefinition:Private: Members declaredprivate
are accessible only within thesameclass in which they are declared.TheyThisareisnotkeyvisiblefortoencapsulation.
subclassesor any other class in any package. -
-
Purpose:Encapsulation – to hide the internal implementation details of a class and protect its internal state. -
Definition:Static methods: Belong to the class itself, not toany specifican instance(object)of the class.They are calledCalled usingthe class name (ClassName.methodName()
). - Cannot
Memory:Only one copy of a static method exists in memory, shared among all instances of the class (and even accessible without any instance). Access:Can access only static variables of the class.Cannotdirectly access instance variables orinstance methods directly (because they don't operate on a specific instance).Cannot usethis
orsuperkeywords.
-
Purpose:Utility functions, factory methods, operations that are not tied to the state of a specific object. Definition:methods: Belong to an instance (object) of the class.TheyCalledareusingcalled on an object (objectReference.objectName.methodName()).Memory:Each instance has its own conceptual "copy" or access to these methods, which operate on that instance's data.Access:- Can access
both static andinstance variablesofand theclass. Can access both static and instance methods.Can usethis
(to refer to the current instance) andsuper(to refer to the superclass instance).reference.
- Can access
-
Purpose:To operate on or query the state (instance variables) of a specific object. -
Definition:Primitive data types:FundamentalBasic data typespredefined by Java. They are not objects. Types:byte,short,(int
,
,longcharboolean
,float
,double
,
,charbyte
,booleanshortlong
). Store actual values directly. Not objects, have no methods. Stored on the stack (for local variables).-
Storage:Store the actual binary value directly in the memory location where the variable is allocated (stack for local variables, or part of an object's memory on the heap). Default Value:Have default values (e.g.,0for numeric types,falseforboolean,\u0000forchar) if they are instance or static variables. Local primitive variables must be initialized.Behavior:Cannot have methods called on them. Operations are performed using operators (e.g.,+,-,*,/).Nullability:Cannot benull.Definition:Objects: Instances ofclassesclasses. Store references (user-definedmemoryoraddresses)built-intoliketheString,actualArrayList).data,Theywhichrepresentresidesmoreoncomplexthedataheap.structuresHaveand encapsulate datastate (fields) and behavior (methods).-
Default Value:The default value for an object reference isnullif it's an instance or static variable. Local object references must be initialized. Behavior:Have methods that can be called on them to perform operations or query their state.Nullability:Can benull, meaning the reference variable does not point to any object. This can lead toNullPointerExceptionif not handled.-
mixes two concepts slightly.Integeris a wrapper class for the primitiveint.Correction:String
is always anobject type,object, not aprimitive,primitive.andThenot a wrapperfor a primitivein the same wayIntegeris.
comparison ischarthe primitive for character data.Let's addressusuallyInteger
vsint
,.and -
briefly touch uponString.Wrapper
Classesclasses (e.g.,Integer
,Boolean
):vsObject representations of primitive types. Can benull
. Used in collections (which can only store objects). Provide utility methods. -
Primitive types (e.g.,
int
),Primitive Type (
):intboolean- Direct
Asvaluedescribedtypes.above: stores actual value, no methods, cannotCannot benull
,.moreMoreefficient.memory and performance efficient for simple operations.-
String
: Is always an object type in Java, immutable. It's not a primitive.
-
WrapperArrayClassvs(Integer):ListAn object that "wraps" or encapsulates a primitive value.java.langpackage provides wrapper classes for all primitives:Byte,Short,Integer,Long,Float,Double,Character,Boolean.Purpose:To use primitive values in contexts where objects are required (e.g., Java Collections likeArrayList<Integer>, Generics).To provide utility methods related to the primitive type (e.g.,Integer.parseInt(),Integer.MAX_VALUE).To allow primitive values to benull.
Behavior:Instances of wrapper classes are objects, so they are stored on the heap, can benull, and have methods.
String-
Stringis an Object Type:Array:It's a class (java.lang.String) representing a sequence of characters. It is not a primitive type. Immutable:Stringobjects are immutable in Java. Once created, their value cannot be changed.Special Treatment:Java provides special support for strings, such as the string pool (for string literals) and the+operator for concatenation.Not a Wrapper for a Primitive:While it deals with character data, it doesn't "wrap" a single primitivecharin the same wayIntegerwrapsint. An array ofchar(char[]) is closer to the rawFixed-size datathatstructure.Stringmanages.
Key Differences (intvsInteger)Featureint(Primitive)Integer(Wrapper Object)NaturePrimitive data typeObject (instance ofjava.lang.Integer)StorageActual valueReference to an object on the heap ornullCannot benullCan primitivesbestorenullMethodsNo methodsHas methods (e.g.,intValue(),compareTo())CollectionsCannot be directly used in collections likeArrayList(before Java 5 without autoboxing)Can be used in collections (ArrayList<Integer>)PerformanceGenerally faster, less memory overheadSlower, more memory overheadDefault Value0(if instance/static variable)null(if instance/static variable)Exampleimport java.util.ArrayList; import java.util.List; public class WrapperVsPrimitive { public static void main(String[] args) { // int (primitive) vs Integer (wrapper object) int primitiveInt = 100; Integer wrapperInt = Integer.valueOf(100); // Explicit boxing (older way) Integer autoBoxedInt = 100; // Autoboxing (Java 5+) System.out.println("Primitive int: " + primitiveInt); System.out.println("Wrapper Integer: " + wrapperInt); System.out.println("Autoboxed Integer: " + autoBoxedInt); // primitiveInt.compareTo(200); // ERROR: int has no methods System.out.println("Compare wrapperInt to 200: " + wrapperInt.compareTo(200)); // -1 Integer nullInteger = null; // int anotherPrimitive = nullInteger; // This would cause NullPointerException if unboxing is attempted List<Integer> numberList = new ArrayList<>(); numberList.add(primitiveInt); // Autoboxing: int to Integer numberList.add(wrapperInt); // List<int> primitiveList = new ArrayList<>(); // ERROR: Generic types must be reference types int unboxedInt = wrapperInt; // Auto-unboxing: Integer to int // String (Object) String strLiteral = "Java"; // String literal, often from string pool String strObject = new String("Java"); // Explicitly creates a new String object on heap char[] charArray = {'J', 'a', 'v', 'a'}; // Primitive char array String strFromChars = new String(charArray); System.out.println("String literal: " + strLiteral); System.out.println("String object: " + strObject); System.out.println("String from char array: " + strFromChars); // strLiteral is an object, it has methods System.out.println("Length of strLiteral: " + strLiteral.length()); } }5. Array vs ListArrayDefinition:A fixed-size, ordered collection of elementsobjects of the samedatatype.TheBasic,typelanguage-levelcanfeature.-
primitiveList (Interface): Part of the Java Collections Framework (e.g.,int[]) or object (e.g.,String[],MyObject[]). Size:Fixed at the time of creation. Cannot be changed dynamically.Type Safety:Strong type checking at compile time. Anint[]can only holdints.Performance:Generally faster for element access (using index) if the index is known, due to direct memory access.Features:Basic operations provided by language syntax (e.g.,array[index],array.length). No built-in methods for common data manipulations like add, remove (except by creating a new array).Generics:Cannot be used directly with generics in the way collections can (e.g., you can't haveArray<T>).
beList (Interface)Definition:An interface (java.util.List) representing an ordered collection of elements (also known as a sequence). Allows duplicate elements.Implementations:Common implementations includeArrayList
,LinkedList
,).Vector,DynamicallyStack.resizable. Stores only objects. Offers more methods and flexibility.
-
Size:Set vs ListDynamic. Lists can grow or shrink as elements are added or removed. -
TypeSetSafety:(Interface):UsesCollectiongenericsthatfordoestypenotsafetyallow duplicate elements. Order is not guaranteed (e.g.,List<String>HashSet,) or can be based on insertion (
) or natural/custom sorting (List<Integer>LinkedHashSetTreeSet
). -
Performance:Varies by implementation.ArrayListis generally fast for random access, whileLinkedListis faster for insertions/deletions in the middle. Features:Rich set of methods for adding, removing, searching, iterating, sorting, etc. (e.g.,add(),remove(),get(),size(),isEmpty()).Generics:Designed to work with generics.Definition:An orderedOrdered collectionofthatelements. Allowsallows duplicate elements.Order:Maintains the insertion order of elements (or can be sorted explicitly).Elementscan beare accessed by their integerindex (position).Duplicates:Allows duplicate elements. You can add the same element multiple times.Common Implementations:ArrayList,LinkedList,Vector.Use Case:When the order of elements matters, and duplicates are acceptable. E.g., a list of steps in a recipe, a sequence of user actions.Definition:A collection that contains no duplicate elements.Order:HashSet: Makes no guarantees as to the iteration order of the set; it may even change over time.LinkedHashSet: Maintains insertion order.TreeSet: Stores elements in a sorted order (natural order or by aComparator).index.
-
Duplicates:Does not allow duplicate elements. If you try to add an element that is already present (according to itsequals()method), theadd()method returnsfalseand the set remains unchanged. Common Implementations:HashSet,LinkedHashSet,TreeSet.Use Case:When you need to store unique items, and the primary concern is checking for the existence of an item. E.g., a collection of unique visitors to a website, distinct words in a document.-
Definition:Comparable (Interface):AnImplementedinterface (java.lang.Comparable) thatby a classcan implementto define its"naturalordering."ordering. Has one method:compareTo()
. The class itself decides how its instances should be sorted. -
Method:Comparator (Interface):ItImplementedhasas asingleseparate class to define custom or multiple orderings for objects of another class. Has one main method:
.int compareTo(T o)compare()- Useful
Returnswhenayounegativecan'tintegermodifyifthe
classthisobjectorisneedlessdifferentthansortingo.Returns zero ifthisobject is equal too.Returns a positive integer ifthisobject is greater thano.criteria.
-
Usage:Implemented by the class whose instances you want to sort.Used by sorting methods likeCollections.sort(List<T>)andArrays.sort(T[])by default if noComparatoris provided.Data structures likeTreeSetandTreeMapuse the natural ordering if noComparatoris specified.
Modification:Requires modifying the source code of the class itself.Ordering:Provides a single way of sorting (the natural order).Definition:An interface (java.util.Comparator) that can be implemented to define custom or multiple sorting orders for objects of a class.Method:It has a primary method:int compare(T o1, T o2).Returns a negative integer ifo1is less thano2.Returns zero ifo1is equal too2.Returns a positive integer ifo1is greater thano2.(Also has other default/static methods likethenComparing,reversed, etc., since Java 8).
Usage:Implemented in a separate class, or as an anonymous class, or a lambda expression.Passed as an argument to sorting methods (e.g.,Collections.sort(List<T>, Comparator<T>),Arrays.sort(T[], Comparator<T>)).Can be provided to constructors ofTreeSetandTreeMapto define a specific order.
Modification:Does not require modifying the source code of the class being sorted.Ordering:Allows defining multiple, different sorting strategies for the same class.-
Definition:Interface: Ablueprintcontractofspecifying methods aclass. It specifies a contract that implementing classesclass mustadhereimplement.to. Methods:Traditionally, interfaces could onlyCannot havepublicinstanceabstractmethodsvariables (method signatures without implementation) andonlypublic static final
constants.constants). JavaCan8 addedhavepublicdefaultmethods (with implementation, can be overridden)and
methods (publicstaticwith implementation, cannot be overridden by implementing classes).- Java
9 addedprivateandprivate staticmethods (helper methods for default/static methods within the interface)8+).
Variables:Can only declarepublic static finalvariables (constants). Instance variables are not allowed.Constructors:Cannot have constructors. Cannot be instantiated directly.Implementation:A classimplementsan interface.A class can implement multipleinterfacesinterfaces.(multipleDefinesinheritance"what"ofatype).class can do.-
AccessAbstractModifiers:class:All members are implicitlypublic. Methods are implicitlyabstract(unlessdefaultorstatic). Purpose:To define a contract, achieve multiple inheritance of type, achieve loose coupling. Good for defining capabilities (e.g.,Serializable,Runnable,Flyable).Definition:A class that cannotCannot beinstantiated directly and is meant to be subclassed. It can provide a partial implementation of a class.Methods:instantiated. Can haveabstract
methods(no implementation)unimplemented) and concretemethods(with implementation). Can also havestaticand
implemented) methods.finalVariables:Can have instancevariables (non-static) and staticvariables.They can have any access modifier (public,protected,private, default). Can also befinal.Constructors:Can have constructors. These are called when an instance of a concrete subclass is created (usually viasuper()call from subclass constructor).Implementation:A classextendsan abstract class.A class can extend only one abstractclassclass.(or any class).Access Modifiers:Members can have any access modifier.Purpose:To provideProvides acommonbaseclasswith somesharedcommoncode and some parts that subclasses must implement. Goodfunctionality for "is-a"relationships where subclasses share common state and behavior.finalvariable:Primitive:The value of the variable cannot be changed once assigned. It becomes a constant. Must be initialized at declaration or in the constructor (if it's an instance variable).Object Reference:The reference variable cannot be reassigned to point to a different object. However, the state of the object it points tocanbe changed (if the object itself is mutable).relationships.
-
Finalfinalmethod:vs Static keyword-
Final:
AVariable:final methodValue cannot be changed after initialization (constant).- Method: Cannot be overridden by subclasses.
UsedClass:toCannotpreventbesubclassessubclassedfrom(inheritedaltering critical behavior.from).
-
finalclass:Static:AVariable:finalClass-levelclass cannot be subclassed (extended).E.g.,String,Integerare final classes.Used for security or to ensure the immutability or specific behavior of the class cannot be compromised by subclassing.
statickeywordThestatickeyword indicates that a member (variable or method) or a nested class belongs to the class itself, rather than to instances of the class.staticvariable (class variable):There is only one copy of the static variablevariable, shared among all instances of the class.ItMethod:isClass-levelinitializedmethod,when the class is loaded.Can be accessed usingClassName.variableName.
staticmethod (class method):Cancan be called without creating an instance of theclass (ClassName.methodName()).class.CanBlock:only access static variables and call other static methods directly.Cannot usethisorsuper.
staticblock:A block of code that is executedExecuted once when the class isloaded into memory. Used for static initialization.
- Nested
staticnested class:A nested class declaredstatic. It does not have an implicit reference to an instance of the outer class. It can only access static members of the outer class directly.Class: Can be instantiated without an instance of the outer class.
-
Final:
-
areKeyTheyDifferencesorthogonal concepts
and FeaturefinalstaticPurposeTo restrict modification/extension/overriding. Creates constants.To associate a member with the class rather than an instance. Shared memory.Applicable toVariables, methods, classes.Variables, methods, blocks, nested classes.VariablesValue cannotcan bechangedused(for primitives); reference cannot be changed (for objects).Single copy shared by all instances. Belongs to the class.MethodsCannot be overridden.Belongs to the class, called viaClassName.method(). Nothis.ClassesCannot be subclassed.(For nested classes) Does not hold reference to outer class instance.MemoryDoes not directly impact memory model like static (except making references unchangeable).Static members are stored in a separate memory areatogether (e.g.,method area/metaspace).Example
)class MyMath { // final variable (constant)public static finaldouble PI = 3.14159; // 'static final' makes it a class constant // instance variable (can be final) private final int id; // Must be initialized in constructor or at declaration privateStringinstanceName; // static variable private static int instanceCount = 0; public MyMath(int id, String name) { this.id = id; // Initialize final instance variable this.instanceName = name; instanceCount++; } // final method (cannot be overridden) public final void printID() { System.out.println("ID: " + this.id); } // instance method public void printName() { System.out.println("Name: " + this.instanceName); } // static method public static int getInstanceCount() { // System.out.println(instanceName); // ERROR: Cannot access instance variable from static context // printName(); // ERROR: Cannot call instance method from static context return instanceCount; } // static block static { System.out.println("MyMath class loaded. Initial instance count: " + instanceCount); // PI = 3.14; // Can initialize static final here if not at declaration } } // final class (cannot be extended) final class ImmutablePoint { private final int x; private final int y; public ImmutablePoint(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } } // class TryingToExtend extends ImmutablePoint {} // ERROR: Cannot inherit from final ImmutablePoint class AdvancedMath extends MyMath { public AdvancedMath(int id, String name) { super(id, name); } // @Override // public final void printID() { // ERROR: Cannot override final method from MyMath // System.out.println("Advanced ID: " + super.id); // 'id' is private, but can be accessed if it were protected // } @Override public void printName() { // OK to override non-final method System.out.print("Advanced Math - "); super.printName(); } } public class FinalStaticExample { public static void main(String[] args) { System.out.println("Accessing static final constant: MyMath.PIMY_CONSTANT = "value";+ MyMath.PI); // MyMath.PI = 3.0; // ERROR: Cannot assign a value to final variable PI System.out.println("Initial instance count (static method): " + MyMath.getInstanceCount()); // 0 MyMath math1 = new MyMath(1, "MathObj1"); // math1.id = 2; // ERROR: Cannot assign a value to final variable id math1.printID(); // Calls final method math1.printName(); // Calls instance method MyMath math2 = new MyMath(2, "MathObj2"); System.out.println("Instance count after 2 objects (static method): " + MyMath.getInstanceCount()); // 2 AdvancedMath advMath = new AdvancedMath(3, "AdvMathObj1"); advMath.printID(); // Calls inherited final method advMath.printName(); // Calls overridden method in AdvancedMath ImmutablePoint p = new ImmutablePoint(10, 20); // p = new ImmutablePoint(30, 40); // This would be allowed if 'p' itself was not final. // Here, the object p refers to is immutable. final ImmutablePoint finalP = new ImmutablePoint(5,5); // finalP = new ImmutablePoint(1,1); // ERROR: finalP is a final reference. // The object finalP points to is also immutable due to its class design. } }10.==vsequals()methodThese are used for comparison in Java, but they compare different things.==operatorPrimitives:For primitive types (int,char,boolean, etc.),==compares their actualvalues.int a = 5; int b = 5;thena == bistrue.
-
Objects:== vs equals() methodFor-
reference types (String,ArrayList, custom objects, etc.),==
comparesoperator:their- For primitive types: Compares values.
- For objects: Compares memory addresses (references) .
String s1 = new String("hello"); String s2 = new String("hello");thens1 == s2isfalsebecauses1ands2refer to two different objects in memory, even though their content is the same.String s3 = "hello"; String s4 = "hello";thens3 == s4istruedue to String interning (string pool optimization for literals).MyObject o1 = new MyObject(); MyObject o2 = o1;theno1 == o2istruebecauseo2is assigned the same reference aso1.
It checksChecks if tworeference variablesreferences point to the exact sameobject in memory.
objectequals()methodDefinition:A method defined in thejava.lang.Objectclass. Its default implementation inObjectclass behaves exactly like==for objects (i.e., it compares references).public boolean equals(Object obj)
-
Overriding:Classes likeString,Integer,Date, and collection classes override theequals()
method to provide "logical" or "content" equality. They compare the actual content or state of the objects, not just their memory addresses.method:ForString,equals()compares the sequence of characters.ForInteger,equals()compares the wrapped integer value.
Custom Classes:If you don't override
Defined inequals()your custom class, it will inherittheObject
class's implementation, which means it will perform a reference comparisonclass (default implementation is==
).- Often
a common practice to overrideequals()(andhashCode())overridden incustomclassesif you need to define logical equality based on the object's attributes. Contract:When overridingequals(), you must also overridehashCode()to maintain the general contract: ifa.equals(b)is true, thena.hashCode() == b.hashCode()must be true.
It'sKey DifferencesFeature==Operatorequals()MethodTypeOperatorMethodPrimitivesCompares valuesNot applicable(cannot call methods on primitives)Objects (Default)Compares references (memory addresses)Compares references (defaultObject.equals()behavior)Objects (Overridden)Still compares referencesCompares content/state (if overridden appropriately,e.g.,inString
,Integer
)UsageValue comparison for primitives, reference comparison for objects.Content/logical comparison for objects (when properly overridden).Exampleclass Point { private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } // getters... // Without overriding equals() and hashCode(), Point instances // will be compared by reference using the default Object.equals(). @Override public boolean equals(Object o) { if (this == o) return true; // Same object reference if (o == null || getClass() != o.getClass()) return false; // Null or different class Point point = (Point) o; return x == point.x && y == point.y; // Compare content } @Override public int hashCode() { // A simple hash code implementation int result = x; result = 31 * result + y; return result; // Or use Objects.hash(x, y) from Java 7+ } } public class EqualsVsDoubleEqual { public static void main(String[] args) { // --- Primitives --- int a = 10; int b = 10; int c = 20; System.out.println("Primitives:"); System.out.println("a == b: " + (a == b)); // true (10 == 10) System.out.println("a == c: " + (a == c)); // false (10 == 20) // a.equals(b); // COMPILE ERROR: equals() cannot be called on primitives // --- Objects (String - special case with string pool) --- String s1 = "hello"; // String literal, goes into string pool String s2 = "hello"; // Another literal, reuses from string pool String s3 = new String("hello"); // Explicitly creates a new object on the heap String s4 = new String("hello"); // Explicitly creates another new object on the heap System.out.println("\nStrings:"); System.out.println("s1 == s2: " + (s1 == s2)); // true (both point to the same object in string pool) System.out.println("s1 == s3: " + (s1 == s3)); // false (s1 is in pool, s3 is a new heap object) System.out.println("s3 == s4: " + (s3 == s4)); // false (s3 and s4 are distinct heap objects) System.out.println("s1.equals(s2): " + s1.equals(s2)); // true (content is the same) System.out.println("s1.equals(s3): " + s1.equals(s3)); // true (content is the same) System.out.println("s3.equals(s4): " + s3.equals(s4)); // true (content is the same) // --- Objects (Custom Class Point) --- Point p1 = new Point(1, 2); Point p2 = new Point(1, 2); Point p3 = p1; // p3 now refers to the same object as p1 System.out.println("\nCustom Objects (Point):"); System.out.println("p1 == p2: " + (p1 == p2)); // false (p1 and p2 are different objects in memory) System.out.println("p1 == p3: " + (p1 == p3)); // true (p1 and p3 refer to the same object) // If Point did NOT override equals(), this would be false. // Since Point DOES override equals()to comparex and y, this is true. System.out.println("p1.equals(p2): " + p1.equals(p2)); // true (content isthesamecontentdueortologicaloverridden equals) System.out.println("p1.equals(p3): " + p1.equals(p3)); // true (same object, content also same) Object o = new Object(); Object o2 = new Object(); System.out.println("o.equals(o2) without override: " + o.equals(o2)); // false, default is == } }(The remaining answers will follow this detailed format. This is a lotequality ofinformation,objects,sonotI'lljustcontinuetheirinreferences. -
subsequentresponses -
avoid making one response excessively long.)Okay, continuing with the detailed explanations:11.Autoboxing vs Unboxing
These are convenience features introduced in Java 5 that allow automatic conversion between primitive types and their corresponding wrapper classes.Autoboxing-
Definition:Autoboxing:The automaticAutomatic conversionthatby the Java compilermakes betweenof a primitive typeandto its corresponding wrapper class objectwrapper class. For example, converting an(e.g.,int
toanInteger
, adoubleto aDouble, etc.). -
When it happens:Unboxing:- Automatic
Whenconversion by the Java compiler of aprimitivewrappervalueclassisobjectpassed as a parameterback toa method that expects an object of theits correspondingwrapper class.When aprimitivevalue is assigned to a variable of the corresponding wrapper class.When a primitive is added to a collection that expects objectstype (e.g.,
toArrayList<Integer>int
).
Unboxing-
Definition:The automatic conversion that the Java compiler makes from a wrapper class object to its corresponding primitive type. For example, converting anIntegerto anint, aDoubleto adouble, etc. When it happens:When an object of a wrapper class is passed as a parameter to a method that expects a value of the corresponding primitive type.When an object of a wrapper class is assigned to a variable of the corresponding primitive type.In arithmetic operations involving wrapper objects (the object is unboxed to a primitive before the operation).
Caution:Unboxing anullwrapper object will result in aNullPointerException.
Key DifferencesFeatureAutoboxingUnboxingConversionPrimitive type → Wrapper class objectWrapper class object → Primitive typeExampleint i = 10; Integer obj = i;Integer obj = new Integer(10); int i = obj;Potential IssueLess direct, slight performance overhead.NullPointerExceptionif wrapper object isnull.Exampleimport java.util.ArrayList; import java.util.List; public class AutoboxingUnboxingExample { public static void main(String[] args) { // --- Autoboxing --- // Primitive int to Integer object int primitiveInt = 10; Integer wrapperInt = primitiveInt; // Autoboxing: int -> Integer // Under the hood, this is like: Integer wrapperInt = Integer.valueOf(primitiveInt); System.out.println("Primitive int: " + primitiveInt); System.out.println("Autoboxed Integer: " + wrapperInt); List<Integer> integerList = new ArrayList<>(); integerList.add(20); // Autoboxing: int 20 -> Integer.valueOf(20) integerList.add(primitiveInt); // Autoboxing System.out.println("List of Integers: " + integerList); takesIntegerObject(30); // Autoboxing: int 30 -> Integer.valueOf(30) // --- Unboxing --- Integer anotherWrapperInt = Integer.valueOf(50); int anotherPrimitiveInt = anotherWrapperInt; // Unboxing: Integer -> int // Under the hood, this is like: int anotherPrimitiveInt = anotherWrapperInt.intValue(); System.out.println("\nUnboxed primitive int: " + anotherPrimitiveInt); int sum = anotherWrapperInt + 5; // Unboxing: anotherWrapperInt is unboxed to int before addition System.out.println("Sum (unboxing in expression): " + sum); int valFromList = integerList.get(0); // Unboxing: Element from list (Integer) to int System.out.println("Value from list (unboxed): " + valFromList); takesPrimitiveInt(anotherWrapperInt); // Unboxing: Integer -> int // --- Potential NullPointerException with Unboxing --- Integer nullInteger = null; try { // int problematicInt = nullInteger; // This would cause NullPointerException if (nullInteger != null && nullInteger > 0) { // Guarded unboxing System.out.println("This won't print"); } // Or more directly, to show the error: int npeInt = nullInteger.intValue(); // This is what unboxing effectively does } catch (NullPointerException e) { System.out.println("\nCaught NullPointerException during unboxing: " + e.getMessage()); } } public static void takesIntegerObject(Integer num) { System.out.println("Method takesIntegerObject received: " + num); } public static void takesPrimitiveInt(int num) { System.out.println("Method takesPrimitiveInt received: " + num); } }12.Checked exceptions vs Unchecked exceptionsJava's exception handling mechanism categorizes exceptions into these two main types, which differ in how the compiler enforces their handling. Both are subclasses ofjava.lang.Throwable.Erroris another subclass ofThrowablefor severe system issues, usually not handled by applications.Checked Exceptions-
Definition:Checked exceptions:Exceptions that the Java compilerchecksat compile-time. They represent exceptional conditions that a well-written application should anticipate and recover from. of:java.lang.Exception(but notjava.lang.RuntimeExceptionor its subclasses).Handling:A method that might throw a checked exception must either:Handle it using atry-catchblock.Declare it in itsthrowsclause, propagating the responsibility to the caller.
Examples:IOException,SQLException,FileNotFoundException,ClassNotFoundException.Purpose:To force programmers to deal with predictable, though exceptional, situations.
Unchecked Exceptions (Runtime Exceptions)Definition:Exceptions that the Java compiler doesnotcheck at compile-time. They usually indicate programming errors or unexpected conditions that are often unrecoverable or should have been prevented by better coding.Subclasses of:java.lang.RuntimeException(which itself is a subclass ofjava.lang.Exception).Errorand its subclasses are also unchecked, but typically not caught.Handling:The compiler does not require you to handle or declare them.Youcanstill usetry-catchblocks for them, but it's often a sign of fixing a symptom rather than the root cause (e.g., catchingNullPointerExceptioninstead of ensuring an object is not null).
Examples:NullPointerException,ArrayIndexOutOfBoundsException,IllegalArgumentException,ArithmeticException,ClassCastException.Purpose:To indicate bugs in the program logic or runtime issues that are generally not anticipated for recovery by the immediate calling code.
Key DifferencesFeatureChecked ExceptionsUnchecked Exceptions (Runtime Exceptions)Compiler CheckChecked at compile-time.Not checked at compile-time.HandlingMust be handled (try-catch) or declared (throws).Handling/declaring is optional. this.Parent ClassSubclassofException
(excludingRuntimeException
). enforcesSubclassMust be declared in thethrows
clause of a method or handled in aRuntimeException. (Errortry-catchisblock.alsoCompilerunchecked).Represent NatureExternal conditions, oftenanticipated, recoverable problems (e.g.,file not found, network error).Programming errors, internal logic flaws (e.g., null pointer, bad index).ExamplesIOException
,SQLException
).- Unchecked exceptions: Subclasses of
RuntimeException
orError
. Do not need to be declared or caught (though they can be). Usually indicate programming errors (e.g.,FileNotFoundExceptionNullPointerException
,ArrayIndexOutOfBoundsException
,ArithmeticExceptionExampleimport java.io.File; import java.io.FileReader; import java.io.IOException; // Checked exception import java.io.FileNotFoundException; // Checked exception, subclass of IOException public class CheckedUncheckedExceptions { // Method that might throw a checked exception (IOException) // It must declare it in the 'throws' clause) orhandleunrecoverableit.systempublic static void readFile(String fileName) throws FileNotFoundException, IOException { File file = new File(fileName); FileReader fr = new FileReader(file); // Might throw FileNotFoundException // ... read file ...issues (furtherOutOfMemoryError
). -
-
IOException) System.out.println("Successfully opened (but not read): " + fileName); fr.close(); // Might throw IOException } // Method that might cause an unchecked exception public static void processNumber(String numberStr, int divisor) { if (numberStr == null) { // This would lead to NullPointerException if not checked System.out.println("Input string is null, cannot parse."); return; } try { int number = Integer.parseInt(numberStr); // Might throw NumberFormatException (unchecked) int result = number / divisor; // Might throw ArithmeticException (unchecked if divisor is 0) System.out.println("Result: " + result); } catch (NumberFormatException e) { System.err.println("Unchecked Exception: Invalid number format - " + e.getMessage()); } catch (ArithmeticException e) { System.err.println("Unchecked Exception: Cannot divide by zero - " + e.getMessage()); } // No need to declare NumberFormatException or ArithmeticException in throws clause. } public static void main(String[] args) { // --- Handling Checked Exception --- System.out.println("--- Checked Exception Example ---"); try { readFile("existing_file.txt"); // Assume this file does not exist for demo // To make it work, create an empty "existing_file.txt" // readFile("non_existent_file.txt"); } catch (FileNotFoundException e) { System.err.println("Checked Exception Caught: File not found - " + e.getMessage()); } catch (IOException e) { System.err.println("Checked Exception Caught: IO Error - " + e.getMessage()); } finally { System.out.println("File reading attempt finished."); } // --- Triggering Unchecked Exceptions --- System.out.println("\n--- Unchecked Exception Example ---"); processNumber("100", 5); // Valid processNumber("abc", 5); // NumberFormatException processNumber("100", 0); // ArithmeticException processNumber(null, 5); // Handled null case inside processNumber // Example of an unhandled unchecked exception (if not caught inside method) // String text = null; // System.out.println(text.length()); // This would throw NullPointerException } } // To run the "readFile" part without error, create an empty file named "existing_file.txt" in the same directory.13.Thread vs Runnable
Both are used for creating and managing threads in Java for concurrent execution.Threadclass (java.lang.Thread)-
Definition:Thread (Class):AAnclassinstancethatofrepresentsThread
is a thread of execution. - You
Usage:extendExtendtheThread
:Create a subclass of
class and override itsThreadrun()
methodmethod. Limits a class todefinesingletheinheritance.-
theRunnablethread(Interface):will execute. Then create anAn instance ofthisasubclassclassand call itsstart()method. PassimplementingRunnable
tohas
aThreadconstructor:task(Morethatcommoncanandbeflexible) Create an instance of
executed byThreadpassinga
thread.RunnableobjectYouto its constructor.
task State:AThreadobject encapsulates the thread's state, priority, name, etc.Limitation:If you extendThread, your class cannot extend any other class (Java doesn't support multiple class inheritance).
Runnableinterface (java.lang.Runnable)Definition:A functional interface with a single abstract method:void run().Usage:Implementimplement theRunnable
interfacein a class and provide the implementation for the(itsrun()
method.method) Createand pass an instanceof this class (theRunnableobject).Createto aThread
object,constructor.passingMoretheflexible
asRunnableobjectittoallowsitsmultipleconstructor:inheritanceThreadoft = new Thread(myRunnable);.Callt.start()to begin execution.
Flexibility:Since it's an interface, your class can implement
interfaces andRunnablestill extend another class. This promotes better separation of concerns:separates the task(Runnable) is separatefrom the executionmechanismmechanism.(Thread).Generally preferred.
-
-
Reusability:The sameRunnableinstance can potentially be executed by multiple threads if itsrun()method is thread-safe or designed for it (though typically oneRunnableis passed to oneThreadfor a specific task). Decoupling:It separates the task (what to do) from the worker (the thread that does it).Flexibility:Your task class can still extend another class if needed, as Java does not support multiple inheritance of classes.Reusability:ARunnablecan be submitted to anExecutorServiceor other concurrency utilities more easily.Immutable. Every modification creates a newStringobject.Inefficient for frequent modifications (e.g., building a string in a loop).-
Definition:StringBuilder:A mutableMutable sequence of characters. Thread-Safety:Synchronized. Its methods (likeappend(),insert(),delete()) are synchronized, making it thread-safe. This means only one thread can access aStringBufferobject's methods at a time.Performance:Due to synchronization, it's slower thanStringBuilderin a single-threaded environment.Introduced:Java 1.0.Definition:A mutable sequence of characters.Thread-Safety:Not synchronized. Its methods are not synchronized, making it non-thread-safe.Performance:Faster thanStringBufferin a single-threaded environment because it doesn't have the overhead of synchronization.Introduced:Java 5, as a non-synchronized alternative toStringBuffer.-
PerformanceStringBuffer: StringBuilder:overhead. Usein most cases, especially in single-threaded applications orwhentheStringBuilderinstance is confined to a single thread (e.g., local variable within a method). This is the common recommendation.StringBuffer:Use only if you need a mutable string that will be accessed and modified bymultiple threadsconcurrently,mightandmodifyyoutheneedstring.-
String:Use for fixed string values or when immutability is desired. String concatenation with+is often optimized by the compiler to useStringBuilderunder the hood for simple cases, but explicitStringBuilderis better for loops. -
Definition:Synchronized methods:ALock the entire methoddeclared withusing the
object'ssynchronizedkeyword. Locking:Instance Method:When a synchronized instance method is called, the thread acquires the intrinsic lock forthat specific instancemonitor (thethis
object) of the class. No other thread can executeany other synchronizedfor instancemethodon thesame objectuntil the lock is released.Static Method:When a synchronized static method is called, the thread acquires the intrinsic lock formethods, theClass
objectassociatedforwithstaticthatmethods).class.SimplerNotootherimplementthreadbut canexecuteany other synchronized static methodin thesame classuntil the lock is released.
Scope:The entire method is synchronized. The lock is acquired when the method is entered and released when the method exits (either normally or duelead toanlowerunhandledconcurrencyexception).Granularity:Coarser-grained locking. Ifif only a small part of the method needssynchronization, the entire method still gets locked, potentially reducing concurrency.Definition:A block of code marked with thesynchronizedkeyword, followed by an object reference in parentheses.synchronized (objectReference) { // code to be synchronized }-
Locking:Synchronized blocks:TheAllowthreadfiner-grainedacquires the intrinsic lock for the object specified inobjectReference. No other thread can execute another synchronized blockon the same objectReferenceuntil the lock is released. Object for Locking:this: Lockslocking onthe current instance (similar to a synchronized instance method, but fora specificblock).object's - monitor
MyClass.class:forLocks on the Class object (similar toonly asynchronized static method, but for a specific block). Any other object: Can use a dedicated lock object (e.g.,private final Object lock = new Object();). This is often preferred for finer-grained control and to avoid unintended lock contention.
Scope:Only the code within the block is synchronized.Granularity:Finer-grained locking. Allows you to synchronize only thecriticalsections of code that access shared resources, leaving other parts of the method non-synchronized, potentially improving concurrency.-
Abstract class vs Concrete class
-
Abstract class: A class declared with the
abstract
keyword. Cannot be instantiated directly. May contain abstract methods (methods without a body, declared withabstract
) that must be implemented by concrete subclasses. Designed to be a base forinstanceothermethods,classes. - Concrete class: A regular class
ClassName.for static methods. -
Abstract class: A class declared with the
-
Method Overloading vs Method Overriding
-
Method Overloading (Compile-time Polymorphism): Defining multiple methods in the same
method.
-
Method Overloading (Compile-time Polymorphism): Defining multiple methods in the same
-
Method Overriding (Runtime Polymorphism): A subclass provides a specific implementation for a method
doesn'tthatneedissynchronization. -
Synchronized Method:Serialization:UseThewhenprocess of converting an object's state (its field values) into a byte stream, which can then be stored in a file, sent over a network, or stored in a database. The class must implement theentirejava.io.Serializable
logicmarkerof a method needs to be executed atomically with respect to other synchronized methods on the same object (or class for static methods). It's simpler to write.interface. -
Synchronized Block:Deserialization:- The
Usereversewhen only a partprocess ofa method needs synchronization.Use when you need to synchronize onreconstructing an objectotherfromthanits serialized byte stream representation.
-
HashMap vs TreeMap
-
HashMap: Implements
. Uses a hash table. Does not guarantee any order of iteration. Allows onethisMapnull
orkey and multiple
values. Offers averageClassName.classnullO(1)
time complexity forget
andput
. UsewhenTreeMap:differentImplementscriticalSortedMap
.sectionsUseswithina red-black tree. Stores entries sorted by their keys (natural order or by a providedComparator
). Does not allownull
keys (if using natural ordering). OffersO(log n)
time complexity forget
andput
.
-
HashMap: Implements
-
ArrayList vs LinkedList
-
ArrayList: Implements
List
using a dynamically resizable array. Fast random access (get(index)
isO(1)
). Slower for additions/removals in thesamemiddleclass(O(n)
) because elements need to beprotectedshifted. -
differentLinkedList:locksImplementsList
using a doubly-linked list. Slower random access (get(index)
isO(n)
). Faster for additions/removals at the beginning, end, or middle (if an iterator is positioned,O(1)
) as only pointers need to be updated. Higher memory overhead per element.
by -
ArrayList: Implements
-
HashMap vs Hashtable
-
HashMap: Not synchronized (not thread-safe). Allows one
null
key and multiplenull
values. Faster. Part of the Java Collections Framework. Preferred for non-concurrent use. -
Hashtable: Synchronized (thread-safe). Does not allow
morenull
concurrencykeys ornull
values (throwsNullPointerException
). Slower due to synchronization. A legacy class;ConcurrentHashMap
is generally preferred for thread-safe map operations.
-
HashMap: Not synchronized (not thread-safe). Allows one
-
Enum vs Constant variables
-
Constant variables (e.g.,
onepublic
): Provide fixed values but lack type safety (e.g., you could pass anyblockstaticlocksfinalonint RED = 1;lock1int,anotherwhereonalock2)color constant is expected). No intrinsic grouping or behavior. OftenpreferredEnum (Enumeration): A special data type that enables forbetteraperformancevariable to be a set of predefined constants. Type-safe (compiler checks values). Can have constructors, methods, andfinerimplementcontrol,interfaces.especiallyProvidesinbettercomplexreadabilityconcurrentandapplications.maintainability.
Usingprivate -
Constant variables (e.g.,
-
lockSingleton pattern vs Prototype pattern
- Singleton pattern (Creational): Ensures a class has only one instance and provides a global point of access to it. Useful for managing shared resources like database connections or logging.
-
Prototype pattern (Creational): Creates new objects by copying an existing object (
privatethefinalprototype).ObjectUsefullockwhen=objectnew Object();)creation isa good practice to avoid exposing locksexpensive andpotentialyoudeadlocksneedifmanyexternal code tries to lock on your publicsimilar objects.
-
ExampleGarbage
classCollectionCountervs{Manualprivatememoryintmanagementcount-
0;GarbageprivateCollectionint(GC):anotherCountAutomatic=process0;(e.g.,//inLockJava,objectC#) where the runtime environment reclaims memory occupied by objects that are no longer referenced by the program. Reduces risks of memory leaks and dangling pointers. -
Manual memory management: Programmer is responsible for
finer-grainedexplicitlysynchronization private final Object lock1 = new Object(); private final Object lock2 = new Object(); // Synchronized instance methodallocating (locksmalloc
,on 'this' object) public synchronized void incrementMethodSync(new
){and//deallocatingEntire(free
,methoddelete
) memory (e.g., in C, C++). Offers more control but issynchronizederror-prone.
=System.out.println(Thread.currentThread( -
-
Lambda expressions vs Anonymous classes
-
Lambda expressions (Java 8+)
.getName():+Concise" acquired locksyntax forincrementMethodSynccreatingoninstances"of+functionalthis); count++; try { Thread.sleep(10); } catchinterfaces (InterruptedException e) {} // Simulate work System.out.println(Thread.currentThread().getName() + " releasing lock for incrementMethodSync"); } // Synchronized static method (locks on 'Counter.class' object) private static int staticCount = 0; public static synchronized void incrementStaticMethodSync() { System.out.println(Thread.currentThread().getName() + " acquired lock for incrementStaticMethodSync on Counter.class"); staticCount++; try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println(Thread.currentThread().getName() + " releasing lock for incrementStaticMethodSync"); } // Method using synchronized block (locks on 'this' object) public void incrementBlockThisSync() { // Non-synchronized part System.out.println(Thread.currentThread().getName() + " executing non-sync part before block (incrementBlockThisSync)"); synchronized (this) { System.out.println(Thread.currentThread().getName() + " acquired lock for block on " + this); count++; try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println(Thread.currentThread().getName() + " releasing lock for block on " + this); } // Non-synchronized part System.out.println(Thread.currentThread().getName() + " executing non-sync part after block (incrementBlockThisSync)"); } // Method using synchronized blockinterfaces with adedicatedsinglelockabstract method). Focus on the "what to do" rather than "how to create an objectpublicthatvoiddoesincrementBlockDedicatedLock() { System.out.println(Thread.currentThread().getName() +it."executing(parameters)
non-sync->partexpressionbeforeorblock(
.incrementBlockDedicatedLock)"); synchronized (lock1) { System.out.println(Thread.currentThread().getName() + " acquired lock1"); anotherCount++; try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println(Thread.currentThread().getName() + " releasing lock1"); } } public void anotherOperationWithDifferentLock() { synchronized (lock2) { System.out.println(Thread.currentThread().getName() + " acquired lock2 for another operation"); // Perform some other critical operation on a different resource try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println(Thread.currentThread().getName() + " releasing lock2"); } } public int getCount() { return count; } public int getAnotherCount() { return anotherCount; } public static int getStaticCount() { return staticCount; } } public class SyncMethodVsBlockExample { public static void main(String[] args) throws InterruptedException { Counter c1 = new Counter(); Counter c2 = new Counter(); // Different instance // Test synchronized instance method // Threads will contend for lock on c1 if they call incrementMethodSync on c1 Thread t1 = new Thread(()parameters) -> {for(int i=0; i<3; i++) c1.incrementMethodSync();statements; } - Anonymous classes: A way to create an instance of an interface or subclass an existing class on the fly, without explicitly defining a new named class. More verbose. Can have state (fields) and multiple methods, which lambdas cannot directly. Lambdas are often syntactic sugar for simple anonymous classes implementing functional interfaces.
-
Lambda expressions (Java 8+)
-
Functional programming vs Object-oriented programming
- Functional Programming (FP): Paradigm that treats computation as the evaluation of mathematical functions. Emphasizes pure functions (no side effects), immutability, first-class functions, and declarative style.
-
Object-Oriented Programming (OOP): Paradigm based on the concept of "
T1-MethodSync-c1"objects," which bundle data (fields) and methods that operate on the data. Key principles are encapsulation, inheritance, and polymorphism. Models real-world entities.
-
Try-catch blocks vs finally blocks
- Try block: Encloses a section of code that might throw an exception.
-
Catch block: Follows a
try
block. Catches and handles a specific type of exception if it's thrown within thetry
block. -
Finally block: Follows a
try
block (and anycatch
blocks). Code within thefinally
block always executes, regardless of whether an exception was thrown or caught. Used for cleanup operations (e.g., closing resources).
-
Shallow Copy vs Deep Copy
- Shallow Copy: Creates a new object and copies the values of the fields from the original object. If a field is a reference to another object, only the reference (memory address) is copied, not the object itself. Both original and copy will point to the same referenced object.
- Deep Copy: Creates a new object and recursively copies all objects referenced by the original object. The copy and the original are completely independent; changes in one do not affect the other.
-
Stack vs Heap Memory Allocation
- Stack Memory: LIFO (Last-In, First-Out) data structure. Used for static memory allocation, storing primitive local variables and references to objects. Memory is allocated and deallocated automatically when a method is called and returns (method call stack frames). Fast access. Limited size.
-
Heap Memory: Used for dynamic memory allocation, storing objects (instances of classes) and arrays. Managed by the Garbage Collector in Java. Slower access compared to stack. Larger size. Can lead to
OutOfMemoryError
if not managed properly or if too many objects are created.
Key Differences
|
| |
---|---|---|
Example
// In package com.example
public class BankAccount {
public String accountNumber; // Public: accessible by anyone
private double balance; // Private: only accessible within BankAccount
public BankAccount(String accountNumber, double initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance;
}
// Public method to deposit money
public void deposit(double amount) {
if (amount > 0) {
this.balance += amount;
System.out.println("Deposited: " + amount);
}
}
// Public method to get balance (controlled access)
public double getBalance() {
// We could add security checks here before returning
return this.balance;
}
// Private helper method, not accessible outside
private void logTransaction(String message) {
System.out.println("LOG: " + message + " for account " + accountNumber);
}
public void withdraw(double amount) {
if (amount > 0 && amount <= this.balance) {
this.balance -= amount;
logTransaction("Withdrawal of " + amount); // Using private method
System.out.println("Withdrew: " + amount);
} else {
System.out.println("Withdrawal failed.");
}
}
}
// In another class, possibly another package
public class Main {
public static void main(String[] args) {
BankAccount acc1 = new BankAccount("12345", 1000.00);
System.out.println("Account Number: " + acc1.accountNumber); // OK, accountNumber is public
// System.out.println("Balance: " + acc1.balance); // ERROR! balance is private
acc1.deposit(500.00); // OK, deposit() is public
System.out.println("Current Balance: " + acc1.getBalance()); // OK, getBalance() is public
acc1.withdraw(200.00); // OK
// acc1.logTransaction("Manual log"); // ERROR! logTransaction() is private
}
}
2. Static methods vs Instance methods
Static methods
Instance methods
Key Differences
|
| |
---|---|---|
|
| |
|
|
|
Example
class Dog {
private String name; // Instance variable
private static int dogCount = 0; // Static variable
public Dog(String name) {
this.name = name;
dogCount++; // Increment static counter for each new dog
}
// Instance method
public void bark() {
System.out.println(name + " says Woof!"); // Accesses instance variable 'name'
}
// Instance method that can also access static members
public void displayInfo() {
System.out.println("My name is " + this.name + ". There are " + dogCount + " dogs in total.");
}
// Static method
public static int getDogCount() {
// System.out.println(name); // ERROR! Cannot access instance variable 'name' from a static context
// bark(); // ERROR! Cannot call instance method 'bark()' from a static context
return dogCount; // Accesses static variable 'dogCount'
}
// Static utility method
public static String getSpecies() {
return "Canis familiaris";
}
}
public class Main {
public static void main(String[] args) {
// Calling static method using class name
System.out.println("Species: " + Dog.getSpecies());
System.out.println("Initial dog count: " + Dog.getDogCount());
Dog dog1 = new Dog("Buddy");
Dog dog2 = new Dog("Lucy");
// Calling instance methods using object reference
dog1.bark(); // Buddy says Woof!
dog2.bark(); // Lucy says Woof!
dog1.displayInfo(); // My name is Buddy. There are 2 dogs in total.
// Calling static method (can also be called via an instance, but not recommended)
System.out.println("Current dog count: " + Dog.getDogCount()); // Prints 2
// System.out.println(dog1.getDogCount()); // Also works, but IDE might warn: "Static member accessed via instance reference"
}
}
3. Primitive data types vs Objects
Primitive data types
Objects
Key Differences
|
| |
| ||
|
|
Example
public class PrimitiveVsObject {
int instancePrimitiveInt; // Default value 0
String instanceObjectString; // Default value null
public static void main(String[] args) {
// Primitive types
int localPrimitiveInt = 10; // Stores the value 10
double localPrimitiveDouble = 20.5; // Stores the value 20.5
boolean localPrimitiveBoolean = true; // Stores the value true
char localPrimitiveChar = 'A'; // Stores the character 'A'
// int uninitializedLocalPrimitive;
// System.out.println(uninitializedLocalPrimitive); // COMPILE ERROR: variable might not have been initialized
System.out.println("Primitive int: " + localPrimitiveInt);
// localPrimitiveInt.toString(); // ERROR! Primitives don't have methods
// Objects
String objString1 = "Hello"; // objString1 stores a reference to "Hello" object on the heap
String objString2 = new String("World"); // objString2 stores a reference to a new "World" object
// String uninitializedLocalObject;
// System.out.println(uninitializedLocalObject.length()); // COMPILE ERROR: variable might not have been initialized (and then NPE if it was null)
String nullString = null;
// System.out.println(nullString.length()); // RUNTIME ERROR: NullPointerException
System.out.println("Object String 1: " + objString1);
System.out.println("Length of String 1: " + objString1.length()); // Objects have methods
PrimitiveVsObject pvo = new PrimitiveVsObject();
System.out.println("Instance primitive int default: " + pvo.instancePrimitiveInt);
System.out.println("Instance object String default: " + pvo.instanceObjectString);
}
}
4. Wrapper classes (Integer, String) vs Primitive types (int, String)
This
Key Differences
List (Interface) | ||
---|---|---|
|
| |
| ||
Example
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ArrayVsListExample {
public static void main(String[] args) {
// --- Array ---
System.out.println("--- Array ---");
// Declaration and initialization
String[] stringArray = new String[3]; // Fixed size of 3
stringArray[0] = "Apple";
stringArray[1] = "Banana";
stringArray[2] = "Cherry";
// stringArray[3] = "Date"; // ArrayIndexOutOfBoundsException
System.out.println("Array size: " + stringArray.length);
System.out.println("Element at index 1: " + stringArray[1]);
// Iterating an array
for (String fruit : stringArray) {
System.out.println(fruit);
}
int[] intArray = {1, 2, 3, 4, 5}; // Array of primitives
System.out.println("Int Array: " + Arrays.toString(intArray));
// --- List ---
System.out.println("\n--- List (ArrayList implementation) ---");
// Declaration and initialization (using ArrayList)
List<String> stringList = new ArrayList<>(); // Dynamic size
stringList.add("Dog");
stringList.add("Cat");
stringList.add("Elephant");
System.out.println("List size: " + stringList.size());
System.out.println("Element at index 1: " + stringList.get(1));
stringList.add("Fish"); // Size dynamically increases
System.out.println("New list size: " + stringList.size());
System.out.println("List elements: " + stringList);
stringList.remove("Cat");
System.out.println("After removing Cat: " + stringList);
// List of Integers (uses wrapper class)
List<Integer> integerList = new ArrayList<>();
integerList.add(10); // Autoboxing: int to Integer
integerList.add(20);
System.out.println("Integer List: " + integerList);
}
}
6. Set vs List
Both Set and List are interfaces in the Java Collections Framework, extending Collection.
List
Set
Key Differences
| ||
|
| |
|
|
|
|
|
Example
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class SetVsListExample {
public static void main(String[] args) {
// --- List Example (ArrayList) ---
System.out.println("--- List (ArrayList) ---");
List<String> fruitList = new ArrayList<>();
fruitList.add("Apple");
fruitList.add("Banana");
fruitList.add("Apple"); // Duplicate allowed
fruitList.add("Orange");
System.out.println("Fruit List: " + fruitList); // Order is maintained
System.out.println("Element at index 0: " + fruitList.get(0)); // Access by index
// --- Set Examples ---
System.out.println("\n--- Set (HashSet - unordered) ---");
Set<String> fruitHashSet = new HashSet<>();
System.out.println("Added Apple: " + fruitHashSet.add("Apple"));
System.out.println("Added Banana: " + fruitHashSet.add("Banana"));
System.out.println("Added Apple again: " + fruitHashSet.add("Apple")); // Duplicate not added, returns false
System.out.println("Added Orange: " + fruitHashSet.add("Orange"));
System.out.println("Fruit HashSet: " + fruitHashSet); // Order not guaranteed, no duplicates
// fruitHashSet.get(0); // COMPILE ERROR: No get(index) method
System.out.println("\n--- Set (LinkedHashSet - insertion order) ---");
Set<String> fruitLinkedHashSet = new LinkedHashSet<>();
fruitLinkedHashSet.add("Apple");
fruitLinkedHashSet.add("Banana");
fruitLinkedHashSet.add("Apple"); // Duplicate not added
fruitLinkedHashSet.add("Orange");
fruitLinkedHashSet.add("Grape");
System.out.println("Fruit LinkedHashSet: " + fruitLinkedHashSet); // Insertion order maintained, no duplicates
System.out.println("\n--- Set (TreeSet - sorted order) ---");
Set<String> fruitTreeSet = new TreeSet<>();
fruitTreeSet.add("Orange");
fruitTreeSet.add("Apple");
fruitTreeSet.add("Banana");
fruitTreeSet.add("Apple"); // Duplicate not added
fruitTreeSet.add("Grape");
System.out.println("Fruit TreeSet: " + fruitTreeSet); // Sorted order (natural string order), no duplicates
}
}
7. Comparable vs Comparator
Both are interfaces in Java used for sorting objects.
Comparable<T>
Comparator<T>
Key Differences
|
| |
---|---|---|
|
| |
|
| |
|
|
Example
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
// Class implementing Comparable for natural ordering (by age)
class Person implements Comparable<Person> {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person other) {
// Natural ordering: by age
return Integer.compare(this.age, other.age);
// If this.age < other.age, returns negative
// If this.age == other.age, returns zero
// If this.age > other.age, returns positive
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
// Comparator for sorting Person objects by name
class PersonNameComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
}
public class ComparableComparatorExample {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
people.add(new Person("Charlie", 35));
people.add(new Person("Diana", 25));
System.out.println("Original list: " + people);
// 1. Sorting using Comparable (natural order: by age)
Collections.sort(people); // Uses Person's compareTo() method
System.out.println("Sorted by age (Comparable): " + people);
// Reset list for next sort
people.clear();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
people.add(new Person("Charlie", 35));
people.add(new Person("Diana", 25));
// 2. Sorting using Comparator (custom order: by name)
Collections.sort(people, new PersonNameComparator());
System.out.println("Sorted by name (Comparator): " + people);
// 3. Sorting using Comparator (lambda expression for reverse age order)
// No need to reset list, just re-sort
Comparator<Person> reverseAgeComparator = (p1, p2) -> Integer.compare(p2.age, p1.age);
// Or use Java 8 Comparator helpers:
// Comparator<Person> reverseAgeComparator = Comparator.comparingInt((Person p) -> p.age).reversed();
Collections.sort(people, reverseAgeComparator);
System.out.println("Sorted by age descending (Lambda Comparator): " + people);
// 4. Sorting by name then by age (if names are same)
Comparator<Person> nameThenAgeComparator = Comparator
.comparing((Person p) -> p.name)
.thenComparingInt(p -> p.age);
Collections.sort(people, nameThenAgeComparator);
System.out.println("Sorted by name then age: " + people);
}
}
8. Interface vs Abstract class
Both are mechanisms for abstraction in Java, but they have different characteristics and use cases.
Interface
Abstract Class
Key Differences
| ||
|
| |
|
Example
// --- Interface ---
interface Playable {
// public static final String TYPE = "Playable"; // Implicitly public static final
String TYPE = "Playable"; // Same as above
void play(); // Implicitly public abstract
default void displayType() { // Default method (Java 8+)
System.out.println("This is of type: " + TYPE);
}
static String getCategory() { // Static method (Java 8+)
return "Entertainment";
}
}
interface Recordable {
void record();
void stopRecording();
}
// --- Abstract Class ---
abstract class MediaDevice {
protected String deviceName; // Instance variable (can be protected, private, etc.)
private boolean powerOn; // Instance variable
public MediaDevice(String deviceName) { // Constructor
this.deviceName = deviceName;
this.powerOn = false;
System.out.println(deviceName + " device created.");
}
public void powerOn() { // Concrete method
this.powerOn = true;
System.out.println(deviceName + " powered ON.");
}
public void powerOff() { // Concrete method
this.powerOn = false;
System.out.println(deviceName + " powered OFF.");
}
public boolean isPoweredOn() {
return powerOn;
}
public abstract void showStatus(); // Abstract method - must be implemented by subclasses
}
// --- Concrete Class ---
// Implements multiple interfaces and extends one abstract class
class SmartSpeaker extends MediaDevice implements Playable, Recordable {
public SmartSpeaker(String name) {
super(name); // Call superclass constructor
}
@Override
public void play() {
if (isPoweredOn()) {
System.out.println(deviceName + " is playing music.");
} else {
System.out.println(deviceName + " is off. Cannot play.");
}
}
@Override
public void record() {
if (isPoweredOn()) {
System.out.println(deviceName + " is recording audio.");
} else {
System.out.println(deviceName + " is off. Cannot record.");
}
}
@Override
public void stopRecording() {
if (isPoweredOn()) {
System.out.println(deviceName + " stopped recording.");
}
}
@Override
public void showStatus() {
System.out.println("Status for " + deviceName + ": Power " + (isPoweredOn() ? "ON" : "OFF"));
}
}
public class InterfaceAbstractExample {
public static void main(String[] args) {
SmartSpeaker alexa = new SmartSpeaker("Alexa Echo");
alexa.powerOn();
alexa.showStatus();
alexa.play(); // From Playable interface
alexa.record(); // From Recordable interface
alexa.stopRecording();
alexa.displayType(); // Default method from Playable interface
System.out.println("Category: " + Playable.getCategory()); // Static method from Playable
alexa.powerOff();
alexa.showStatus();
alexa.play();
}
}
9. Final vs Static keyword
These keywords serve very different purposes in Java.
final
keyword
The final keyword can be applied to variables, methods, and classes. Its meaning changes based on context.
Key Differences
|
| |
---|---|---|
|
| |
| ||
| ||
|
Example
// Approach 1: Extending Thread
class MyThread extends Thread {
private String threadName;
public MyThread(String name) {
super(name); // Set thread name via superclass constructor
this.threadName = name;
System.out.println("Creating " + threadName );
}
@Override
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", Count: " + i);
Thread.sleep(50); // Simulate work
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
}
// Approach 2: Implementing Runnable
class MyRunnable implements Runnable {
private String taskName;
private Thread thread; // Optional: to hold the thread that runs this runnable
public MyRunnable(String name) {
this.taskName = name;
System.out.println("Creating task " + taskName );
}
@Override
public void run() {
System.out.println("Running task " + taskName + " on thread " + Thread.currentThread().getName());
try {
for(int i = 4; i > 0; i--) {
System.out.println("Task: " + taskName + ", Count: " + i + " (Thread: " + Thread.currentThread().getName() + ")");
Thread.sleep(70); // Simulate work
}
} catch (InterruptedException e) {
System.out.println("Task " + taskName + " interrupted.");
}
System.out.println("Task " + taskName + " exiting.");
}
public void start() { // Convenience method to create and start the thread
System.out.println("Starting task " + taskName);
if (thread == null) {
thread = new Thread(this, taskName + "-Thread"); // Pass runnable and a name for the thread
thread.start();
}
}
}
public class ThreadVsRunnableExample {
public static void main(String[] args) {
System.out.println("--- Extending Thread ---");
MyThread thread1 = new MyThread("Thread-A (extends Thread)");
MyThread thread2 = new MyThread("Thread-B (extends Thread)");
thread1.start(); // Calls run() method of MyThread
thread2.start(); // Calls run() method of MyThread
// Wait for threads to finish before proceeding (optional, for cleaner output)
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("--- Finished Extending Thread Example ---");
System.out.println("\n--- Implementing Runnable ---");
MyRunnable runnableTask1 = new MyRunnable("Task-X (implements Runnable)");
MyRunnable runnableTask2 = new MyRunnable("Task-Y (implements Runnable)");
// Manually creating Thread objects for Runnable tasks
Thread t3 = new Thread(runnableTask1, "Thread-C (for Task-X)");
Thread t4 = new Thread(runnableTask2, "Thread-D (for Task-Y)");
t3.start(); // Calls run() method of MyRunnable (runnableTask1)
t4.start(); // Calls run() method of MyRunnable (runnableTask2)
// Or using the convenience start method in MyRunnable
// MyRunnable runnableTask3 = new MyRunnable("Task-Z (implements Runnable)");
// runnableTask3.start();
try {
t3.join();
t4.join();
// if (runnableTask3.thread != null) runnableTask3.thread.join();
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("--- Finished Implementing Runnable Example ---");
// Using Runnable with Lambda (Java 8+)
System.out.println("\n--- Runnable with Lambda ---");
Runnable lambdaTask = () -> {
System.out.println("Running lambda task on thread " + Thread.currentThread().getName());
try {
for(int i = 2; i > 0; i--) {
System.out.println("Lambda Task, Count: " + i + " (Thread: " + Thread.currentThread().getName() + ")");
Thread.sleep(60);
}
} catch (InterruptedException e) {
System.out.println("Lambda task interrupted.");
}
System.out.println("Lambda task exiting.");
};
Thread t5 = new Thread(lambdaTask, "Thread-E (for Lambda)");
t5.start();
try {
t5.join();
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("--- Finished Runnable with Lambda Example ---");
}
}
Why Runnable is generally preferred:
14. StringBuilder vs StringBuffer
Both StringBuilder and StringBuffer are mutable sequence of characters, used when you need to perform many modifications to strings (concatenation, insertion, deletion). The String class in Java is immutable.
String
(briefly, for context)
StringBuffer
StringBuilder
Key Differences
|
| |
---|---|---|
Not synchronized (not thread-safe) | .||
for single-threaded environments.
| Mutable sequence of characters. Synchronized (thread-safe). Slower due to synchronization | |
When to use which?
StringBuilder
Example
public class StringBuilderStringBufferExample {
public static final int ITERATIONS = 100000;
public static void main(String[] args) {
// --- String Concatenation (for comparison, less efficient in loops) ---
long startTime = System.nanoTime();
String str = "";
for (int i = 0; i < ITERATIONS / 10; i++) { // Reduced iterations for String due to slowness
str += "a"; // Creates new String object in each iteration
}
long endTime = System.nanoTime();
System.out.println("String concatenation time: " + (endTime - startTime) / 1_000_000.0 + " ms (for " + ITERATIONS/10 + " iterations)");
// --- StringBuffer ---
startTime = System.nanoTime();
StringBuffer sBuffer = new StringBuffer();
for (int i = 0; i < ITERATIONS; i++) {
sBuffer.append("a");
}
endTime = System.nanoTime();
System.out.println("StringBuffer append time: " + (endTime - startTime) / 1_000_000.0 + " ms");
// --- StringBuilder ---
startTime = System.nanoTime();
StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < ITERATIONS; i++) {
sBuilder.append("a");
}
endTime = System.nanoTime();
System.out.println("StringBuilder append time: " + (endTime - startTime) / 1_000_000.0 + " ms");
// --- Functionality (same for both StringBuilder and StringBuffer) ---
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // "Hello World"
sb.insert(5, ", Java"); // "Hello, Java World"
sb.delete(5, 11); // "Hello World" (deletes ", Java")
sb.reverse(); // "dlroW olleH"
String finalString = sb.toString();
System.out.println("\nFinal string from StringBuilder: " + finalString);
// --- Thread Safety Demo (Conceptual) ---
// To truly demonstrate thread-safety issues with StringBuilder vs StringBuffer,
// you'd need multiple threads modifying the same instance.
// StringBuffer (thread-safe)
StringBuffer sharedBuffer = new StringBuffer();
Runnable taskBuffer = () -> {
for (int i = 0; i < 1000; i++) {
sharedBuffer.append("X");
}
};
// StringBuilder (not thread-safe)
StringBuilder sharedBuilder = new StringBuilder();
Runnable taskBuilder = () -> {
for (int i = 0; i < 1000; i++) {
sharedBuilder.append("Y"); // Potential race condition
}
};
Thread t1 = new Thread(taskBuffer);
Thread t2 = new Thread(taskBuffer);
Thread t3 = new Thread(taskBuilder);
Thread t4 = new Thread(taskBuilder);
t1.start(); t2.start();
t3.start(); t4.start();
try {
t1.join(); t2.join();
t3.join(); t4.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("\nShared StringBuffer length (expected 2000): " + sharedBuffer.length());
// For StringBuilder, the length might not be 2000 due to race conditions.
// This simple append might not always show it, more complex operations would.
System.out.println("Shared StringBuilder length (potentially < 2000): " + sharedBuilder.length());
// To make StringBuilder safe in a multi-threaded context, you would do:
// synchronized(sharedBuilder) { sharedBuilder.append("Y"); }
}
}
Output for the performance part will show StringBuilder is generally faster than StringBuffer, and both are much faster than repeated String concatenation in a loop.
The thread-safety demo for length might consistently show 2000 for StringBuilder in simple appends because append(char) operations might be atomic enough on some JVMs/OSs for this trivial case. A more complex sequence of operations or more contention would more reliably show data corruption or incorrect lengths with StringBuilder in a concurrent setting without external synchronization.
15. Synchronized methods vs Synchronized blocks
Both are mechanisms in Java to control access to shared resources by multiple threads, preventing race conditions and ensuring data consistency. They work by acquiring an intrinsic lock (also called a monitor lock) associated with an object.
Synchronized Methods
Synchronized Blocks
Key Differences
|
| |
@Override |
Serialization
DeserializationWhenvs to use which?
Spring / Spring Boot Specifics:
-
@SpringBootApplication vs @Configuration
-
@SpringBootApplication
: A convenience annotation that combines@Configuration
,@EnableAutoConfiguration
, and@ComponentScan
with their default attributes. Typically used on the main application class. -
@Configuration
: A class-level annotation indicating that the class declares one or more@Bean
methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime.
-
-
@ComponentScan vs @EnableAutoConfiguration
-
@ComponentScan
: Tells Spring where to look for Spring-managed components (beans marked with@Component
,@Service
,@Repository
,@Controller
, etc.);.ThreadByt2default (when used with@SpringBootApplication
), it scans the package of the main application class and its sub-packages. -
@EnableAutoConfiguration
: Enables Spring Boot's auto-configuration mechanism, which attempts to automatically configure your Spring application based on the JAR dependencies you have added to the classpath.
-
-
@Configuration vs @Bean
-
@Configuration
: Class-level annotation. Declares that a class can contain bean definition methods. Spring processes such classes to create and manage beans. -
@Bean
: Method-level annotation. Used within a@Configuration
class. Indicates that the method produces a bean to be managed by the Spring container. The returned object from the method is registered as a bean.
-
-
@Autowired vs @Qualifier
-
@Autowired
: Marks a constructor, field, setter method, or config method to be autowired by Spring's dependency injection facilities. Spring attempts to resolve the dependency by type. If multiple beans of the same type exist, it can lead to ambiguity. -
@Qualifier("beanName")
: Used in conjunction with@Autowired
to specify which exact bean to inject when there are multiple beans of the same type. It resolves ambiguity by name.
-
-
@RestController vs @Controller
-
@Controller
: A specialization of@Component
. Marks a class as a Spring MVC controller. Handler methods typically return a view name (e.g., for Thymeleaf, JSP rendering) or redirect. -
@RestController
: A convenience annotation that combines@Controller
and@ResponseBody
. Marks a class as a controller where every handler method automatically serializes the return object into the HTTP response body (e.g., as JSON or XML). Primarily used for building RESTful APIs.
-
-
@RequestMapping vs @GetMapping
-
@RequestMapping
: A general-purpose annotation for mapping HTTP requests to handler methods. Can specify HTTP methods (GET, POST, etc.), path, headers, params. Can be used at class or method level. -
@GetMapping
: A shortcut annotation specifically for mapping HTTP GET requests. Equivalent to@RequestMapping(method = RequestMethod.GET)
. More concise for GET mappings.
-
-
@PathVariable vs @RequestParam
-
@PathVariable
: Binds a method parameter to a URI template variable. Used to extract values from the path of the URL (e.g.,/users/{id}
). -
@RequestParam
: Binds a method parameter to a web request parameter. Used to extract values from the query string of a URL (e.g.,/search?query=java
) or from submitted form data.
-
-
@PostMapping vs @PutMapping
-
@PostMapping
: A shortcut annotation specifically for mapping HTTP POST requests. Equivalent to@RequestMapping(method = RequestMethod.POST)
. Typically used for creating newThread(resources. -
@PutMapping
: A shortcut annotation specifically for mapping HTTP PUT requests. Equivalent to@RequestMapping(method = RequestMethod.PUT)
. Typically used for updating an existing resource completely (or creating it if it doesn't exist, making it idempotent).
-
-
PUT vs PATCH (HTTP Methods)
- PUT: An HTTP method used to replace an entire resource at a specific URI with the request payload. If the resource doesn't exist, PUT might create it. Idempotent (multiple identical requests have the same effect as a single one).
- PATCH: An HTTP method used to apply partial updates to a resource. Modifies only the specified fields in the request payload, leaving other fields unchanged. Not necessarily idempotent.
-
@ExceptionHandler vs @ControllerAdvice
-
@ExceptionHandler
: A method-level annotation within a controller (or@ControllerAdvice
class). Defines a method that handles specific types of exceptions thrown by request handler methods within that controller (or globally if in@ControllerAdvice
). -
@ControllerAdvice
: A class-level annotation that allows you to consolidate common controller-related concerns (like exception handling, model attributes, init binders) into a single, global component. Often used with@ExceptionHandler
methods for centralized error handling across multiple controllers.
-
-
@Primary vs @Qualifier
-
@Primary
: When multiple beans of the same type are eligible for autowiring, the bean marked with@Primary
is given preference and will be chosen by default if no other more specific criteria (like@Qualifier
)->are{used. -
i=0;@Qualifier("beanName")
:i<3;Usedi++)toc1.incrementMethodSync();explicitly},specify"T2-MethodSync-c1");which//namedThisbeanthreadtooperatesinject when multiple beans of the same type exist. It overrides@Primary
if both are present and a qualifier is used at the injection point.
for(int -
-
@Async vs @Scheduled
-
@Async
: Marks a method to be executed asynchronously in a separate thread, managed by Spring. The caller does not wait for the method to complete. Requires@EnableAsync
on adifferentconfigurationobjectclass. -
so@Scheduled
:itMarkswon'tacontendmethodwithtot1,bet2executedforatc1'sscheduledlockintervalsThreadort_c2fixed=timesnew Thread(() -> { for(int i=0; i<3; i++) c2.incrementMethodSync(); }e.g.,"T_MethodSync-c2");using//cronTestexpressions,synchronizedfixedblockrate, or fixed delay). Requires@EnableScheduling
on'this'aThreadconfigurationt3class.
c2,=new -
-
-> { for(int i=0; i<3; i++) c1.incrementBlockThisSync(); }, "T3-BlockThisSync-c1"); // Test synchronized block on dedicated lock // These two threads can run concurrently if they use different lock objects (lock1@Cacheable vs
lock2)@CacheEvict//-
if@Cacheable
:theyMarksoperateaonmethoddifferentwhoseCounterresultinstances.should//be cached. IfincrementBlockDedicatedLocktheandmethodanotherOperationWithDifferentLock areis calledonagainSAME c1 instance, // they can run concurrently because they use different locks (lock1, lock2). Thread t4 = new Thread(() -> { for(int i=0; i<3; i++) c1.incrementBlockDedicatedLock(); }, "T4-BlockLock1-c1"); Thread t5 = new Thread(() -> { for(int i=0; i<3; i++) c1.anotherOperationWithDifferentLock(); }, "T5-BlockLock2-c1"); // Test static synchronized method // Threads will contend for Counter.class lock Thread t6 = new Thread(() -> { for(int i=0; i<3; i++) Counter.incrementStaticMethodSync(); }, "T6-StaticSync"); Thread t7 = new Thread(() -> { for(int i=0; i<3; i++) Counter.incrementStaticMethodSync(); }, "T7-StaticSync"); System.out.println("--- Starting Method Sync Demo (on c1) ---"); t1.start(); t2.start(); t_c2.start(); t1.join(); t2.join(); t_c2.join(); System.out.println("c1.count after method sync: " + c1.getCount()); // Expected: 6 System.out.println("c2.count after method sync: " + c2.getCount()); // Expected: 3 c1.count = 0; // Reset for next test System.out.println("\n--- Starting Block 'this' Sync Demo (on c1) ---"); t3.start(); // Let's start another one to see contention Thread t3_contend = new Thread(() -> { for(int i=0; i<3; i++) c1.incrementBlockThisSync(); }, "T3_Contend-BlockThisSync-c1"); t3_contend.start(); t3.join(); t3_contend.join(); System.out.println("c1.count after block 'this' sync: " + c1.getCount()); // Expected: 6 System.out.println("\n--- Starting Block Dedicated Lock Demo (on c1, different locks) ---"); // t4 and t5 use different locks onwith the sameobjectarguments,c1,thesocachedtheyresult is returned directly without executing the method body. Requires@EnableCaching
and a cache manager. -
@CacheEvict
: Marks a method that should trigger cache eviction (removal of one or more entries from the cache). Typically used when data that might be cached is modified (e.g., after an update or delete operation).
or -
-
application.properties vs application.yml
- Both are files used in Spring Boot to externalize application configuration.
-
application.properties
: Uses standard Java properties file format (key=value pairs). Simple, flat structure. -
application.yml
(or.yaml
): Uses YAML (YAML Ain't Markup Language) format. More hierarchical and often considered more readable for complex configurations. Supports lists, maps, and more structured data representation. Spring Boot gives YAML precedence if both files exist for the same property.
-
Microservices architecture vs Monolithic architecture
-
Monolithic architecture: The entire application is built as a single, large, undecomposable unit. All modules are tightly coupled and deployed together. Simpler to develop and deploy initially, but can
runbecome hard to scale, maintain, and update. - Microservices architecture: The application is structured as a collection of small, independent, loosely coupled services. Each service focuses on a specific business capability and can be developed, deployed, and scaled independently. Offers better scalability, resilience, technology diversity, and team autonomy, but introduces complexity in management, deployment, and inter-service communication.
-
Monolithic architecture: The entire application is built as a single, large, undecomposable unit. All modules are tightly coupled and deployed together. Simpler to develop and deploy initially, but can
-
JAR vs WAR files
- JAR (Java Archive): Standard Java packaging format. Can contain compiled Java classes, resources, and a manifest file. Used for libraries, plugins, or executable Java applications (if it includes a main class and is marked as executable). Spring Boot typically produces executable JARs (fat JARs) that embed a servlet container.
-
WAR (Web Application Archive): Specifically for packaging Java web applications to be deployed on a standalone servlet container (e.g., Tomcat, Jetty, WebLogic). Contains web resources (HTML, CSS, JS), servlets, JSPs, Java classes (
WEB-INF/classes
), and libraries (WEB-INF/lib
).
-
Maven vs Gradle
- Both are build automation tools and dependency management tools for Java projects.
-
Maven: Uses XML for configuration (
pom.xml
). Emphasizes "convention over configuration." Well-established, large ecosystem. Can be verbose. Relies on a lifecycle of phases and goals. -
Gradle: Uses a Groovy or Kotlin-based DSL (Domain Specific Language) for build scripts (
build.gradle
). More flexible and expressive. Often offers better performance due to incremental builds and build caching. Can have a steeper learning curve for complex customizations.
-
Continuous Integration vs Continuous Deployment
- Continuous Integration (CI): A development practice where developers frequently merge their code changes into a central repository, after which automated builds and tests are run. Aims to detect integration issues early and often.
- Continuous Deployment (CD): Extends CI. Every code change that passes all stages of the CI pipeline (build, automated tests) is automatically deployed to a production environment. Aims for rapid and reliable releases. (Often, "Continuous Delivery" is a prerequisite, meaning every change is releasable, but the actual deployment to production might be a manual business decision).
-
Agile vs Waterfall methodologies
- Waterfall: A traditional, sequential software development methodology. Progress flows downwards through distinct phases: requirements, design, implementation, testing, deployment, and maintenance. Less flexible to changes once a phase is complete.
- Agile: An iterative and incremental approach to software development. Emphasizes collaboration, customer feedback, rapid delivery of working software in small increments (sprints/iterations), and adaptability to changing requirements. (Examples: Scrum, Kanban).
-
RESTful API vs SOAP API
- RESTful API (Representational State Transfer): An architectural style for designing networked applications. Uses standard HTTP methods (GET, POST, PUT, DELETE, etc.). Typically uses JSON or XML for data format over HTTP/HTTPS. Stateless, scalable, and simpler.
-
SOAP API (Simple Object Access Protocol): A protocol for exchanging structured information. Uses XML for its message format and usually relies on other application layer protocols (most notably HTTP or SMTP) for message negotiation and transmission. More rigid, has built-in standards for security (WS-Security), transactions, etc. Can be stateful. Generally more
concurrentlycomplext4.start();andt5.start();verboset4.join();thant5.join();REST.
System.out.println("c1.anotherCountafter -
dedicatedReactive
lock:programming vs Imperative programming-
Imperative programming: A paradigm where you write code that describes how to achieve results using a sequence of statements that change the program's state. Traditional procedural and most object-oriented programming falls into this category (e.g., "do
+this,c1.getAnotherCount(then do that, then update this variable"));. -
Expected:Reactive3programming:System.out.println("\n---AStartingdeclarativeStaticprogrammingMethodparadigmSync Demo ---"); t6.start(); t7.start(); t6.join(); t7.join(); System.out.println("Counter.staticCount after static sync: " + Counter.getStaticCount()); // Expected: 6 } }
change. You define data flows, and the system reacts to changes in those flows automatically. Asynchronous and event-driven. Focuses on what should happen when data arrives or changes (e.g., spreadsheets, UI event handling, Spring WebFlux).I will continueconcerned with data streams and thenext setpropagation ofquestions.
// -
Imperative programming: A paradigm where you write code that describes how to achieve results using a sequence of statements that change the program's state. Traditional procedural and most object-oriented programming falls into this category (e.g., "do