• Home
  • LLMs
  • Docker
  • Kubernetes
  • Java
  • All
  • About
Java | Methods
  1. Instance Methods vs. Static Methods
  2. Method Return Types and Return Values
  3. Method Parameters and Types
  4. Varargs (Variable-Length Argument Lists)
  5. Local Variables Within Methods
  6. Local Variable Type Inference (var keyword)

  1. Instance Methods vs. Static Methods
    • An instance method is only accessible when an instance has been created.

    • A static method (a.k.a. class method) can be accessed even if no instance of the class has been created.

    • A static method is declared using the static keyword.

    class ClassA {
        public void instanceMethod() { }
    
        public static void staticMethod() { }
    
        public void doSomething() {
            // Accessing instance methods
            (new ClassA()).instanceMethod(); // OK
            (new ClassA()).staticMethod(); // OK - Warning: The static method staticMethod() from the type ClassA should be accessed in a static way
    
            // Accessing static methods
            ClassA.staticMethod(); // OK
            ClassA.instanceMethod(); // Compiler error: Cannot make a static reference to the non-static method instanceMethod() from the type ClassA
        }
    }
    • The code inside an instance method can access all attributes (instance or static) and call all methods (instance or static).

    • The code inside a static method can only access static attributes and only call static methods.

    class ClassA {
        int var1 = 1;
        static int var2 = 1;
    
        public Integer instanceMethod() {
            return var1 * var2; // OK
        }
    
        public static Integer staticMethod() {
            Integer localVar1 = var2; // OK
            Integer localVar2 = instanceMethod(); // Compiler error: Cannot make a static reference to the non-static method instanceMethod() from the type ClassA
            return var1; // Compiler error: Cannot make a static reference to the non-static field var1
        }
    }
  2. Method Return Types and Return Values
    • The return type can be a primitive or a reference type (including classes, interfaces, and arrays).
      The returned value (or variable) must be the same type as the one declared for the method.
      int doReturnPrimitiveType() {
          int var1 = 0;
          return var1;
      }
      Object doReturnReferenceType() {
          Object obj = new Object();
          return obj;
      }
    • You can return a value (or variable) that can be implicitly cast to the declared return type.
      int doImplicitCastPrimitiveType() {
          return 'c';
      }
      Object doImplicitCastReferenceType() {
          return Integer.valueOf(10);
      }
    • You can return a value (or variable) that can be explicitly cast to the declared return type.
      int doExplicitCastPrimitiveType() {
          double var1 = 12.5;
          return (int) var1;
      }
      Integer doExplicitCastReferenceType() {
          Integer temp = Integer.valueOf(10);
          Object obj = temp;
          return (Integer) obj;
      }
    • You can return null, but only if the return type is a reference type.
      Object doReturnNullValue() {
          return null;
      }
    • The void type indicates that the method does not return any value.
      void doReturnVoid() {
      }
      You can also use the return keyword to explicitly indicate the method returns nothing:
      void doReturnVoid() {
          return;
      }
  3. Method Parameters and Types
    A method can declare multiple parameters, each with its own type.
    A parameter's type can be a primitive or reference type (including classes, interfaces, and arrays).

    Notes :
    • Parameters: The names declared in the method signature, used to match values passed in when the method is called.

    • Arguments: The actual values (or variables) passed in between the parentheses during a method call.

    public class ClassA {
        void foo(int param1, Integer param2, Object param3) {
        }
    
        void bar() {
            int arg1 = 0;
            Integer arg2 = 1;
            Object arg3 = this;
    
            foo(arg1, arg2, arg3);
        }
    }
    Here are the rules for arguments to be accepted by the compiler:

    • The number of arguments used in the method call must match the number of parameters.
      void bar() {
          int arg1 = 0;
          Integer arg2 = 1;
      
          foo(arg1, arg2); // Compiler error: The method foo(int, Integer, Object) in the type ClassA is not applicable for the arguments (int, Integer)
      }
    • Each argument must be of the same type as its corresponding parameter.
      void bar() {
          String arg1 = "0";
          Integer arg2 = 1;
          Object arg3 = this;
      
          foo(arg1, arg2, arg3); // Compiler error: The method foo(int, Integer, Object) in the type ClassA is not applicable for the arguments (String, Integer, Object)
      }
    • The argument type can differ from the parameter type as long as it can be implicitly converted to match.
      void bar() {
          Integer arg1 = 0; // OK: Integer --> int
          int arg2 = 1; // OK: int --> Integer
          String arg3 = "my String"; // OK: String is a subclass of Object
      
          foo(arg1, arg2, arg3);
      }
  4. Varargs (Variable-Length Argument Lists)
    Sometimes, you want a method to accept a variable number of arguments.
    For example, a method that sums all values passed in.
    To do this, follow the parameter type with three dots (...)
    public class ClassA {
        static int doSumArgs(int... varParams) { // method accepts a variable number of int arguments
            int total = 0;
    
            for (int param : varParams) { // loop through all arguments
                total += param;
            }
    
            return total;
        }
    
        public static void main(String[] args) {
            System.out.println(doSumArgs(1, 2)); // Method call with two arguments
            System.out.println(doSumArgs(1, 2, 3)); // Method call with three arguments
        }
    }
    You can mix regular parameters with varargs.
    However, varargs must be declared last.
    Only one vararg is allowed per method.
    void foo(String param1, Integer param2, int... varParams) { // OK
    }
    
    void bar(String param1, int... varParams, Integer param2) { // Compiler error: The variable argument type int of the method bar must be the last parameter
    }
    
    void multiVarArgs(int... varParams1, int... varParams2) { // Compiler error: The variable argument type int of the method multiVarArgs must be the last parameter
    }
    Note :
    The syntax for declaring and calling varargs is not part of the core Java language—it’s just "syntactic sugar";
    This means the compiler transforms the code into something else when generating bytecode.

    For example, this code:
    public class ClassA {
        void foo(int... varParams) {
        }
    
        void bar() {
            foo(1, 2, 3);
        }
    }
    Will be transformed by the compiler into:
    public class ClassA {
        void foo(int[] varParams) {
        }
    
        void bar() {
            foo(new int[] { 1, 2, 3 });
        }
    }
    You’ll notice that the vararg declaration int... varParams becomes an array declaration int[] varParams.
    And the argument list 1, 2, 3 becomes an anonymous array new int[] { 1, 2, 3 }.

    The most important thing to remember about varargs is that they are actually just arrays under the hood.
  5. Local Variables Within Methods
    Local variables are variables declared inside a method, constructor, or block. They are created when the method is invoked and destroyed when the method exits.

    • Local variables must be declared and initialized before use. They do not have default values, so the compiler will throw an error if they are accessed without initialization.

    • Local variables are only accessible within the method or block where they are declared (i.e., they have method scope).

    • Local variables cannot have access modifiers like public, private, or protected.

    • Local variables can shadow instance variables and static variables with the same name within the method.

    public class ClassA {
        int instanceVar = 10;
    
        void foo() {
            int localVar = 5; // Local variable declaration
    
            System.out.println(localVar); // OK
            System.out.println(instanceVar); // OK - accessing instance variable
    
            int instanceVar = 20; // This local variable shadows the instance variable
            System.out.println(instanceVar); // Refers to the local instanceVar, not the instance field
        }
    
        void bar() {
            int localVar;
            System.out.println(localVar); // Compiler error: The local variable localVar may not have been initialized
        }
    }
    Notes :
    • Local variables are stored on the stack and are not part of the object’s state. They are recreated each time the method is called.

    • You can declare final local variables if you want to prevent reassignment:
      void foo() {
          final int localVar = 3;
          localVar = 4; // Compiler error: The final local variable localVar cannot be assigned. It must be blank and not using a compound assignment
      }
  6. Local Variable Type Inference (var keyword)
    The var keyword can be used for local variable type inference. This allows you to declare local variables without explicitly specifying their type— the compiler infers the type from the initializer expression (the value assigned during declaration).

    • var cannot be used without an initializer (e.g., var x;).

    • var cannot be used for instance variables, static variables, method parameters, or return types.

    • var cannot be used with arrays declared using bracket notation (e.g., var x[];).

    • Once declared with var, the variable's type is fixed and cannot be changed.

    class ClassA {
        // var cannot be used for instance/static variables
        var instanceVar1 = 1; // Compiler error: 'var' is not allowed here
        static var staticVar1 = 1; // Compiler error: 'var' is not allowed here
    
        void doSomething() {
            var var1 = "abc"; // Inferred as String
            var var2 = 1; // Inferred as int
            var var3 = new int[] { 1, 2, 3 }; // inferred as int[]
    
            var var4 = new ArrayList<String>(); // Inferred as ArrayList<String>
            var var5 = Map.of("a", "b"); // Inferred as Map<String, String>
    
            var2 = "xyz"; // Compiler error: Type mismatch: cannot convert from String to int
    
            var var6; // Compiler error: Cannot use 'var' on variable without initializer
            var var7 = null; // Compiler error: Cannot infer type for local variable y
    
            // var cannot be used with arrays declared using bracket notation
            var var8[] = { 1, 2, 3 }; // Compiler error: 'var' is not allowed as an element type of an array
            var[] var9 = { 1, 2, 3 }; // Compiler error: 'var' is not allowed as an element type of an array
        }
    
        // var cannot be used for return types
        var doReturnVar() { // Compiler error: 'var' is not allowed here
            return 42;
        }
    
        // var cannot be used for method parameters
        void doUseParamVar(var param) { // Compiler error: 'var' is not allowed here
        }
    }

    Note that var is a reserved type name but you can still use it as a variable name: int var = 1;
© 2025  mtitek