A class consists of fields and methods. Fields are the class object's characteristics and methods are its function/skills.
public class Car {
String company;
String model;
String color;
double price;
double speed;
char gear;
boolean lights;
public Car() {} // default constructor
double gasPedal(double kmh) {
speed = kmh;
return speed;
}
double brakePedal() {
speed = 0;
return speed;
}
char changeGear(char type) {
gear = type;
return gear;
}
boolean onOffLights() {
lights = !lights;
return lights;
}
void horn() {
System.out.println("빵빵");
}
}
It is possible to modify and access the fileds of the class when they are not declared to be public. When it is not specified private or public, the default is public. Note that here the color of the car can be set to red and called by the print function.
car1.color = "red";
System.out.println(car1.color); // output: red
Every class needs a constructor but if a constructor does not do anything, its called a default constructor and simply no declration of a constructor is needed.
Arbitrary aruguments means that the number of parameter that will be passed in the function is undefined.
void carSpeeds(double ... speeds) {
for (double v : speeds) {
System.out.println("v = " + v);
}
}
// Java Program to Implement
// Method Overloading
import java.io.*;
class MethodOverloadingEx {
static int add(int a, int b) { return a + b; }
static int add(int a, int b, int c)
{
return a + b + c;
}
// Main Function
public static void main(String args[])
{
System.out.println("add() with 2 parameters");
// Calling function with 2 parameters
System.out.println(add(4, 6));
System.out.println("add() with 3 parameters");
// Calling function with 3 Parameters
System.out.println(add(4, 6, 7));
}
}
public class Main {
// Base Class
static class Animal
{
void eat() {
System.out.println("Animal is eating.");
}
}
// Derived Class
static class Dog extends Animal
{
void eat()
{
System.out.println("Dog is eating.");
}
// Method to call the base class method
void eatAsAnimal()
{
super.eat();
}
}
public static void main(String[] args)
{
Dog d1 = new Dog();
Animal a1 = new Animal();
// Calls the eat() method of Dog class
d1.eat();
// Calls the eat() method of Animal class
a1.eat();
// Polymorphism: Animal reference pointing to Dog object
Animal animal = new Dog();
// Calls the eat() method of Dog class
animal.eat();
// To call the base class method, you need to use a Dog reference
((Dog) animal).eatAsAnimal();
}
}
Output
Dog is eating.
Animal is eating.
Dog is eating.
Animal is eating.
When an attribute of a class is set to static, you can access and modify it direclty via calling its class.
static String company;
public class Main {
public static void main(String[] args) {
Car.company = "hello world";
System.out.println(Car.company);
Car myCar = new Car();
System.out.println(myCar.company);
myCar.company = "good bye world";
System.out.println(myCar.company);
}
}
Output
hello world
hello world
good bye world
Note that after setting the Car class's company to 'hello world', the company name of the newly created Car objects also have the default comapny name of 'hello world'. This, however, can be modified.
💡 The concept of a static variable/function is similar to that of a global variable and a non-static variable/function is similar to that of a local variable.💡
'this' key word is used when you need refer to current class you are writing your code in. Then, it is a general convention to use this.attribute_name naming. Below is an example of the Car class having multiple constructors via method overloading.
public Car(String model) {
this.model = model;
this.color = "Blue";
this.price = 50000000;
}
public Car(String model, String color) {
this.model = model;
this.color = color;
this.price = 50000000;
}
public Car(String model, String color, double price) {
this.model = model;
this.color = color;
this.price = price;
}
You can notice that there are repetitive lines due to the similarities between the three constructors. 'this()' can come in handy to simplify the code. We based the 'this()' function based on the constructors with the most number of parameters (which is inclusive of the other two).
public Car(String model) {
this(model, "Blue", 5000);
}
public Car(String model, String color) {
this(model, color, 5000);
}
public Car(String model, String color, double price) {
this.model = model;
this.color = color;
this.price = price;
}
We can see that for the parameters of 'this()' in the very first constructor is given as variable and values. The parameter of the first constructor ('model') is given as the variable and the others are given as values. Same happens for the second constructor.
💡In the second constructor the attributes of color and price will be set to "Blue" and 5000. Applies similarly for the first constructor. 💡
⚠️ Note that when using this() in a method, it must be the very execution of the method ⚠️
⚠️ Writing the code like below will give you an error! ⚠️public Car(String model) { System.out.println("model = " + model); this(model, "Blue", 50000000); }
public class Example {
protected String protectField = "I am protected";
protected void protectedMethod() {
System.out.println("Protected method can be accessed within the same package and by subclasses.");
}
}
class Subclass extends Example {
public void accessProtected() {
System.out.println(protectedField); // attribute is accessible
protectedMethod(); // method is accessible
}
}
public class Main {
public static void main(String[] args) {
Subclass subclass = new Subclass();
subclass.accessProtected(); // Accessible through subclass
}
}
💡 package = folder = directory 💡
Car class from pk1 package is imported and another Car class from pk2 package is called by its directory address. For importing you cannot import both Car classes because they have the same name but you can both call them by addressig.
package oop.main;
import oop.pk1.Car;
public class Main {
public static void main(String[] args) {
Car car = new Car(); // import
car.horn(); // pk1
oop.pk2.Car car2 = new oop.pk2.Car(); // address
car2.horn(); // pk2
}
}
'super' used to call fields and methods from the super/parent class in the child class.
public void setCarInfo(String model, String color, double price) {
super.model = model; // sets the parent class' model
super.color = color; // sets the parent class' color
this.price = price; // sets the child class' model
}
Child class constructor below uses the 'super(...)' to initialize its fileds.
public SportsCar(String model, String color, double price, String engine) {
super(model, color, price);
this.engine = engine;
}
The above code is identical to the following but just better for encapstulation and code maintainability:
public SportsCar(String model, String color, double price, String engine) {
this.model = model;
this.color = color;
this.price = price;
this.engine = engine;
}
Given that Mammal is the parent and Whale is the child class, in the code below, the we see that the object is called by the Whale constructor but its data type is a Mammal. The given syntax automatically converts the object to a Mammal type.
Mammal m1 = new Whale();
m1.feeding(); // output: "whale is eating!"
Whale whale = (Whale) mammal;
whale.swimming();
An abstract class is a class that cannot be instantiated on its own and may contain abstract methods, which are methods declared without an implementation that must be defined by subclasses. Note that abstract methods do not have '{}' that contains the body of the methods/functions.
// here is an abstract class
public abstract class Car {
String company;
String color;
double speed;
public double gasPedal(double kmh) {
speed = kmh;
return speed;
}
public double brakePedal() {
speed = 0;
return speed;
}
// this is an abstract method
public abstract void horn();
}
When other subclasses use the abstract class, it is written like below:
public class GenesisCar extends Car {
@Override
public void horn() {
System.out.println("Zenesis 빵빵");
}
}
The key word 'extend' is used to represent the relationship between the two classes. The subclass is instantiated in the Main as below:
public class Main {
public static void main(String[] args) {
Car myCar = new GenesisCar();
myCar.horn();
}
}
public interface myInterface {
public static final char A = 'A';
static char B = 'B';
final char C = 'C';
char D = 'D';
void turnOnLight (); // public abstract void turnOnLight();
}
Key word 'implements' is used when classes use interfaces. Inheretence between interfaces are called with the key word 'extends'.
💡Note that interfaces can inherite from more than one interface! 💡
// the Main class is inheriting from class D and implementing interface C.
public class Main extends D implements C {
@Override
public void a() {
System.out.println("A");
}
@Override
public void b() {
System.out.println("B");
}
@Override
void d() {
super.d(); // get the d() from the superclass D
}
public static void main(String[] args) {
Main main = new Main();
main.a();
main.b();
main.d();
}
}
interface A {
void a();
}
interface B {
void b();
}
// C is inheriting from A and B
interface C extends A, B {
}
class D {
void d() {
System.out.println("D");
}
}
Default methods must have a function body unlike abstract methods.
Default method must also be public, but will be set to public even if not stated so no need to write it.
❓ When does the default method come in handy ❓
💡 Default functions come in very handy when used in interfaces because when a class implements an interface, it needs to override all the methods in the interface.
💡This can be very time consuming if you wanted add a new method to 5 out of the 20 classes that have implemented the interface because now you would have to write an overriding method for the 15 classes that do not need this new method.
💡 If you make a default method you can not only use the newly created default method from the interface in those 5 classes but also override them as needed.
public class Main implements A {
@Override
public void a() {
System.out.println("A");
}
public static void main(String[] args) {
Main main = new Main();
main.a();
// default method is called!
main.aa();
}
}
interface A {
void a();
default void aa() {
System.out.println("AA");
}
}
Static methods are allowed to be called without instantiating the object. Notice that aaa() is called by simply refering to interface A.
public class Main implements A {
@Override
public void a() {
System.out.println("A");
}
public static void main(String[] args) {
Main main = new Main();
main.a();
main.aa();
System.out.println();
// static method aaa() is called.
A.aaa();
}
}
interface A {
void a();
default void aa() {
System.out.println("AA");
}
static void aaa() {
System.out.println("static method");
}
}
interface Animal {
void makeSound();
}
class Dog implements Animal {
public void makeSound() {
System.out.println("Dog barks");
}
}
class Cat implements Animal {
public void makeSound() {
System.out.println("Cat meows");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog(); // Polymorphism
Animal myCat = new Cat(); // Polymorphism
myDog.makeSound(); // Outputs: Dog barks
myCat.makeSound(); // Outputs: Cat meows
}
}