Certification and technical interviews will check if you know your OOP principles and can apply them. Even in level one Java Oracle certification, there are lots of questions to test if you know how to protect or give access to methods, members, classes… and extensive exercises on inheritance. Not the easiest topics.
That’s were you can prove you’re not only good at remembering technical stuff by heart but can also produce clean, well organized applications. That’s also to my opinion the most difficult part when you learn programming.
In this article I’ll give facts on the methods access in Java, talk about overriding methods, instance and static ones, parameters… In next article, I’ll dive into class design and inheritance. One step at a time.
This series of articles are meant for people who already know the basics of Java, that is grammar and vocabulary, and knowledge of OOP. The topics covered correspond to OCA Programmer I level and relate to Java 8 version. If you need to learn the basics, I can recommend the JetBrains Academy Java developer track.
Methods access modifiers
It’s super important to know which modifiers have wider or lower accessibility compared to each other. Pretty sure you’ll get at least one question about it in the certification for example, either in a theoretical or practical way.
In Java, access modifiers go like explained below, from more widely accessible to less accessible. This is applicable for simple classes! Interfaces and Enums would work differently for example!
Because this post covers OCA level matters, it doesn’t take into account modular applications (OCP). Modular applications in Java allow to encapsulate classes and packages, therefore make accessibility rules a bit more complex. I’ll cover that in a coming article. This doesn’t either cover nested class, which are also OCP level topic, and will also be covered in a separated post.
public
Easiest access modifier to remember from all: public methods can be called from any class in the project, even in other packages.
protected
Protected is trickier. You probably know that protected has to do with inheritance, but not only. A protected method can be call by any subclass of its class (otherwise said, a class that inherits from its class, and be careful with N-levels inheritance…) AND any class in the same package!
(default)
You’re said to use the “default” access modifier when you don’t put an explicit modifier in front of a method (or a class). It’s a bit more restrictive than protected because you only give access to classes in the same package, period.
Some tricks to pay attention to:
- you cannot write “default”, because default is an access modifier for methods in interfaces and not in classes, and it has nothing to do with what’s being talked here; I cover that later in this post;
- sometimes default modifier is not the default modifier, for example in interfaces; if you don’t write the modifier, the methods default to public;
- in the certification exam they sometimes put code from several packages in the same snippet: it’s written but you have to pay attention, otherwise you could miss it and misuse the modifiers.
private
Pretty simple one, the method is only accessible inside the class.
So really, the difficulty is with protected (and wait, we haven’t been through inheritance on its whole yet) and default modifiers.
Writing a method signature
A method is written like:
<access modifier> <optional specifier> return-type method-name(<parameters>) <throws Exception> { method body }
Optional specifiers and access modifier can be switched. The optional specifiers can be:
- abstract (in which case the method doesn’t have a body and the signature ends with ; !!!)
- final
- static
- static final
- final static
Return type is mandatory: if the method returns nothing, it has to be “void”. In case it returns something, there must be a return statement of the corresponding type (or covariant). Each case (if there are conditions or loops) must return something, otherwise you’ll get compile-time error. If the method returns void, it is allowed but not mandatory to use “return;”, which makes the program exit the method. In any case, the return statements cannot be followed by any code since it’s not reachable and will cause compile-time error.
Static
The understanding of static vs instance fields is really important in OOP and sometimes hard to get at first. A static field doesn’t require an instance to be called. It’s shared among all users of the class. You call static fields using the class name (although you may call it with an instance of the class, in which case the class is deducted from the instance).
A static method cannot call an instance method or use instance variables, but instance methods can use static fields. Static fields cannot manipulate instance fields because instance fields do need an instance to be handled, they’re related to a single instance, while static fields are not.
Inside the defining class, the static fields can directly be called by their name without being prefixed by the class name.
In classes, static is not implied static final.
When running a Java program, any reference to a static field will cause the initialization of the class that declares it, even if it’s called by a child (which is not itself initialized).
Passing data as parameter
It’s important to make the different between value and reference types. The type of the variables passed as parameters influence on their behavior and the way to handle them.
Anyway, when you pass a parameter, it is passed by value: you get a copy of the variable, whatever it’s type (so you get either a plain copy of the value or a copy of the reference). There’s a phenomenon called “parameter immutability” which is often tested (it definitely is in the Java certification!).
Any modification done on the parameter’s value (either plain value or reference) has no effects outside the method! If you change the value of a value type, or the reference of a reference type, you’ll have to return the new value and assign it to use it. (A side note, which won’t help you much during certifications but big time when you work on a project, IntelliJ IDEA gives you warnings when you do changes inside the method body that are not seen outside.)
BUT, reference types often have fields, which you can modify: in that case, the modifications are effective outside the method body.
Also be careful with shadowing, that is manipulating local variables that have the same name as a global one!
Overloading methods
An overloaded method is a method with different parameters requirement but same name. When the method is called, the compiler will choose the best match according to parameters passed in the call (if there is at least one match, otherwise it will error).
Overloaded methods must have the exact same name, but different parameters number and/or type(s). The return type doesn’t matter!
The best match is chosen, in order:
- On exact same match if exists
- On larger primitive type or more abstract reference
- On autoboxed type (primitive wrapper) of corresponding primitive type (remember the 1-step conversion rule, only direct box type will work!)
- On varargs of corresponding type
- On Object type
Constructor
The constructor is a special method of the class called on instantiation of an object of that class.
It can have all access modifiers, but using private as modifier would prevent from creating new objects by using “new” outside the class (which is used in some design patterns as Singleton or Factory, and is the mechanism implemented in the LocalDate/Time classes of Java.
The constructor’s name must be exactly the class name (beware of lower/upper case!) and cannot have a return type, even void! If the method has a return type, it’s a plain method, even if it’s called after the class name. That’s a trick they literally LOVE in the Java certification! So pay extra attention when you read the method definition.
Constructors can be overloaded. Every class has a default constructor without parameters that does literally nothing (I mean no body). You can rewrite that constructor. If you decide to write an overloaded constructor (with parameters), remember the non-args constructor doesn’t exist anymore, so you might choose to write it explicitly to keep the possibility to called non-args constructor.
this(); calls the default/non-args constructor of the class. It must be the first line of the block. You can call this(args) to make a call to an overloaded constructor (same rule applies).
The very first line of a constructor is always this() or super() (which calls parent class constructor). Implicitly, first line is always super() (except in the Object constructor I guess, since it’s the parent of all and has no parent itself).
Final methods
Final methods cannot be overridden outside the class (by child classes). Overriding is talked about in next post about Class design.
Special methods in interfaces: default and static
Since Java 8, interfaces can hold methods that are not abstract, thus have a body.
Default method
A method in an interface preceded by keyword “default” has nothing to do with the default access modifier previously mentioned. Default method allows to write a method body that will be used as default behavior if method is not overridden. So overriding becomes optional.
The reason behind this new possibility is to allow to change application design of existing projects without having to rewrite tons of code. That is for example, creating an interface and implementing it without forcing every single class in the hierarchy to create its own definition of the method if not needed. It makes the code a little less strict and should be used with caution, but that’s more of a design and architectural debate than a question for the certification (well, maybe you’ll be asked in interviews so always good to think about it).
The default methods cannot be static, final, abstract nor private or protected. It’s implicitly public.
Default methods can cause conflicts if you implement two interfaces with a default method that has exactly the same signature: in that case, the implementing concrete class must override it. On the other hand, if you extend a class with a method that has the same signature as a default method in implemented interface(s), the class method will always be taken into account and shadow the interface methods. Thanks Java for single inheritance. Also, if interfaces are implemented on several levels (for example the class implements IA, which extends IB), if both A and B have a default implementation for the same method, the lower level (A) will be used.
public interface Black {
default void getColor() {
System.out.println("Black");
}
}
public interface Green extends Black {
default void getColor() {
System.out.println("Green");
}
}
public interface Yellow {
static void getColor() {
System.out.println("Yellow");
}
}
public class Colors implements Green, Black, Yellow {
public static void main(String[] args) {
Colors colors = new Colors();
colors.getColor(); // prints "Green", because Green extends Black, lower level (subclass) prevails
}
Also, default methods can be made abstract by subclasses (including interfaces implementing an interface with default method).
Interfaces don’t replace abstract classes even though they can now implement a method body: they still don’t store the state of an instance, they still don’t have instance fields, and they don’t inherit from Object.
public interface Test {
int anInt = 5;
default void increase(int inc) {
anInt += inc; // doesn't compile! because interfaces only have static final fields
}
}
public interface TheInterface {
int number = 1;
abstract void method();
}
public abstract class TheClass {
int number = 2;
abstract void method();
}
public class TheConcrete extends TheClass implements TheInterface {
/* so far so good, "number" is an instance field in the class and a static field in the interface, and "method()" is abstract in both cases so it needs to be overridden in the concrete class */
void method() { /* this fails to compile! interface access level is "public" and implementing classes cannot lower it when overriding the methods */
// implementation
}
Interface static method
A static method isn’t inherited by implementing classes or extending interfaces. You access it with the interface name (TheInterface.theStaticMethod();).
It’s implicitly public (which means “default modifier” is public, thus public can be written but can be omitted). It can be set to private (for internal use) but not protected.
It must have a body, because it can’t be inherited therefore can’t be overridden.
There’s not way it creates conflicts because it’s called with the interface name (there are no interface instances, so it’s not like a class static method which can be called by an instance).
The static methods can be called without implementing the interface.
Don’t hesitate to play with methods and OOP concepts to really understand all subtleties because it’s really trick material, but also a major topic if you want to code in Java. Learning a language isn’t the difficult part really, it’s all about clean coding, architecture and organization. Once you get it, OOP is great, really.
Read the previous posts about Java certification topics and subscribe so you don’t miss coming articles.
2 thoughts on “Methods – OOP | Preparing for Java Oracle Associate Certification (OCA) / Java basic technical tests”