Skip to content

Commit 3b836b3

Browse files
Update README.md
1 parent cb123c7 commit 3b836b3

1 file changed

Lines changed: 289 additions & 1 deletion

File tree

README.md

Lines changed: 289 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,289 @@
1-
# java-interface-lesson
1+
# Java Interface
2+
Interface in Java is actually easy to be understood but my very big question the very
3+
first time I encountered this: why use interface when you can define and declare
4+
methods in concrete classes?
5+
6+
It is actually for abstraction and polymorphism.
7+
8+
Consider this scenario:
9+
10+
> *Say, you are programming a robot with a color sensor. Depending on the color,
11+
it has a specific behavior to be expressed.*
12+
>
13+
> *Without an interface, you will normally write separate codes to handle
14+
each color. The process (detect the color then decide depending on that color
15+
the behavior of the robot)
16+
is being repeated for each color but the logic is the same:
17+
the color sensor is the interface to trigger different behaviors. Why not just declare
18+
a common method signature and implement this depending on the color? This simplifies
19+
the situation. This preserves the logic of the program.*
20+
21+
So, interface is there for you to separate a class interface from its implementation.
22+
That is separating the logic from the actual codes. Knowing the interface, you can
23+
easily understand the classes that implemented the interface, just like
24+
a concrete class that implemented an abstract class.
25+
Don't you know that for security reasons, some classes in Java only show the
26+
abstract superclass and hide the concrete subclasses? And even if you don't see the
27+
actual implementation of each concrete subclass, you can use them as long as you understood
28+
its superclass. That's the power of **abstraction**. For example, in `java.net`, `URLConnection`
29+
is abstract, its subclasses are all abstract and the actual
30+
implementations that depend on a lot of factors are actually hidden but once you understand
31+
those abstract classes, you can easily use them.
32+
33+
But the main difference is that an abstract class is tied to its class hierarchy
34+
but an interface is detached from any class hierarchy.
35+
36+
## Method Resolution at Run Time
37+
Another important thing: interface was made available to support
38+
dynamic method resolution at run time.
39+
That is, one method signature for multiple implementations.
40+
41+
For example, there are three classes with overloaded methods.
42+
`C` extends `B` and `B` extends `A`. What is the effect? During run time,
43+
in order for `C` to successfully extend `B`, `B` should be present and `A` also.
44+
`A` is needed for `B` to successfully extend it.
45+
Meaning, you simply put these three classes in the same directory.
46+
47+
Now, say, `C` calls a method from `A`. `B` should still
48+
be present because it is an extension of `C`.
49+
50+
Then, say, `C` calls a method from `B`. `A` should still be
51+
present because it is an extension of `B`.
52+
53+
Try to not place them in the same directory and the run time environment
54+
will return an error because it cannot decide which is which. But, say, both `A` and
55+
`B` is in the same directory and `C` is in another location, once your IDE opened
56+
`A`, it can now locate `B` without opening it because the run time environment
57+
now knows the directory of `B`. The formal way we do this is through `import` and
58+
Java `package`.
59+
60+
That is the nature how a method signature is being resolved
61+
at run time.
62+
63+
`A.java`
64+
65+
```
66+
//the root of this sample hierarchy
67+
class A {
68+
void sampleMeth1() {
69+
System.out.println("this is A class sampleMeth1()");
70+
}
71+
72+
void sampleMeth2() {
73+
System.out.println("this is A class sampleMeth2()");
74+
}
75+
}
76+
```
77+
78+
`B.java`
79+
80+
```
81+
class B extends A {
82+
//inherited from class A but overridden
83+
@Override
84+
void sampleMeth2() {
85+
System.out.println("this is B class sampleMeth2()");
86+
}
87+
88+
//not inherited from A
89+
void sampleMeth3() {
90+
System.out.println("this is B class sampleMeth3()");
91+
}
92+
}
93+
```
94+
95+
`C.java`
96+
97+
```
98+
class C extends B {
99+
//inherited from class B but overridden
100+
@Override
101+
void sampleMeth2() {
102+
System.out.println("this is C class sampleMeth2()");
103+
}
104+
105+
public static void main(String[] args) {
106+
C c = new C();
107+
System.out.println("All calls coming from " +
108+
"an instance of C:");
109+
System.out.println("");
110+
111+
//class C did not override sampleMeth3
112+
//class B did not override this method too
113+
//so, this will call the method in A
114+
System.out.println("sampleMeth1() was not overridden " +
115+
"by the two subclasses, so the result is:");
116+
c.sampleMeth1();
117+
System.out.println("");
118+
119+
//overridden from class B
120+
System.out.println("sampleMeth2() was overridden by C class, " +
121+
"so the result is:");
122+
c.sampleMeth2();
123+
System.out.println("");
124+
125+
//not overridden from class B
126+
System.out.println("sampleMeth3() was not overridden by C class, " +
127+
"so the result is:");
128+
c.sampleMeth3();
129+
130+
}
131+
}
132+
```
133+
134+
the result:
135+
136+
```
137+
> run C
138+
All calls coming from an instance of C:
139+
140+
sampleMeth1() was not overridden by the two subclasses, so the result is:
141+
this is A class sampleMeth1()
142+
143+
sampleMeth2() was overridden by C class, so the result is:
144+
this is C class sampleMeth2()
145+
146+
sampleMeth3() was not overridden by C class, so the result is:
147+
this is B class sampleMeth3()
148+
```
149+
150+
Again, in a regular class hierarchy,
151+
when your written code calls for a specific method in another class, both should
152+
be present at run time to check for its signature. That class may be a subclass
153+
of another class until such time it reaches the root of the class hierarchy.
154+
155+
That would mean,
156+
we rather declare everything as static methods to break the chain of the hierarchy,
157+
so as to call them in their shortest routes. But a member declared as
158+
static in a superclass cannot be overridden by a subclass,
159+
thereby breaking the extensibility nature of a class. If your subclass
160+
has the same method signature, it cannot override the static method from the superclass,
161+
the static method in the superclass still exists from the perspective
162+
of an instance of the subclass. This will be not so helpful in a multi-level hierarchy
163+
when you can't tell the origin of a specific method.
164+
165+
Another way is for the
166+
superclass to declare every possible method so that each will be available
167+
for its subclasses. This is also problematic, since a class hierarchy will start from
168+
a general idea to specific. Again, this will break the extensibility nature
169+
of a class: a subclass cannot remove an inherited method that it does not need.
170+
It can only override it with a blank body but this is not the concept of inheritance.
171+
172+
This is where Java interface comes in. Method signatures will be
173+
available through an interface detached from the class hierarchy. You can group several
174+
unrelated methods to define the behavior of a class and a class can implement several
175+
interfaces.
176+
177+
## Interface Reference Variable
178+
With interface reference variable, an object of a class that implemented an interface
179+
can reference this name and call the method. The effect is that it's just like you are
180+
using the interface directly but generates different results depending on the situation.
181+
182+
Let us have a simple implementation of the mentioned scenario a while ago. Take note,
183+
this is for demonstration purposes only not an actual programming of a robot in Java.
184+
185+
`interface RobotColorSensor.java`
186+
187+
```
188+
//for demonstration purposes only,
189+
//a very simple example
190+
interface RobotColorSensor {
191+
void detectColor();
192+
}
193+
```
194+
195+
An example class that implements RobotColorSensor interface:
196+
197+
`RedColorReading.java`
198+
199+
```
200+
class RedColorReading
201+
implements RobotColorSensor {
202+
public void detectColor() {
203+
System.out.print("color is red: ");
204+
System.out.println("backward movement.");
205+
}
206+
}
207+
```
208+
209+
Another example class that implements RobotColorSensor interface:
210+
211+
`GreenColorReading.java`
212+
213+
```
214+
class GreenColorReading
215+
implements RobotColorSensor {
216+
public void detectColor() {
217+
System.out.print("color is green: ");
218+
System.out.println("forward movement.");
219+
}
220+
}
221+
```
222+
223+
Now, we run them in main method:
224+
225+
```
226+
class MainMethod {
227+
228+
public static void main(String[] args) {
229+
//interface reference variable
230+
RobotColorSensor sensor;
231+
System.out.println("interface reference variable is `sensor`");
232+
233+
//an instance of RedColorReading
234+
RedColorReading redDetected = new RedColorReading();
235+
sensor = redDetected;
236+
237+
System.out.print("`sensor.detectColor()` says ");
238+
sensor.detectColor();
239+
240+
//an instance of GreenColorReading
241+
GreenColorReading greenDetected = new GreenColorReading();
242+
sensor = greenDetected;
243+
244+
System.out.print("`sensor.detectColor()` says ");
245+
sensor.detectColor();
246+
247+
}
248+
}
249+
```
250+
251+
the result:
252+
253+
```
254+
> run MainMethod
255+
interface reference variable is `sensor`
256+
`sensor.detectColor()` says color is red: backward movement.
257+
`sensor.detectColor()` says color is green: forward movement.
258+
```
259+
260+
See the importance of an interface? This is **run-time polymorphism**:
261+
one interface for a general class of actions.
262+
263+
## Interface Default Methods
264+
Back then, an interface only holds the method signature (without body).
265+
Now, an interface can have a method with body. We call this as *default method*.
266+
So, it's almost correct to say that through this, there can be multiple inheritance.
267+
But it is not actually the purpose of this default method.
268+
269+
Rather, it is the solution for an interface to be updated later
270+
without breaking the codebase of any project that implemented it.
271+
Remember that the rule for interface is that all defined methods must be implemented
272+
or else a class that partially implements an interface should be declared abstract.
273+
With default methods, the rule has not changed. It is just already implemented
274+
from the very start.
275+
276+
In the above example, say, `RobotColorSensor` is updated with a new method
277+
`detectColorHue()`. Without default method,
278+
every class that implemented this interface should override this new
279+
method. Imagine the pain of doing so. This is truly problematic for large-scale projects.
280+
281+
## Multiple Inheritance through Interface
282+
As was mentioned, with interface default method, it is almost correct
283+
(but still not correct) to say that it also
284+
enables multiple inheritance. Multiple inheritance is quite an obscure concept.
285+
What if a certain class implemented two interfaces with the same method name?
286+
It may be resolved by the run time environment but will return unexpected results.
287+
288+
Rather, always remember that an interface does **define** (not inherit)
289+
the behavior of a class.

0 commit comments

Comments
 (0)