Improved software-development productivity:
Improved software maintainability:
Faster development:
Lower cost of development:
Higher-quality software:
They are used for initializing new objects.
Fields are variables that provides the state of the class and its objects.
And methods are used to implement the behavior of the class and its objects.
Note: There are various types of classes that are used in real time applications such as
nested classes
,anonymous classes
,lambda expressions
.
Example:
type name;
, it notifies the compiler that we will use this name to refer to data whose type is type.Dog tuffy;
Example:
public class Dog {
// Instance Variables
String name;
String breed;
int age;
String color;
// Constructor Declaration of Class
public Dog(String name, String breed, int age, String color){
this.name = name;
this.breed = breed;
this.age = age;
this.color = color;
}
// method 1
public String getName(){
return name;
}
// method 2
public String getBreed(){
return breed;
}
// method 3
public int getAge(){
return age;
}
// method 4
public String getColor(){
return color;
}
@Override
public String toString(){
return("Hi my name is "+ this.getName() + ".\nMy breed, age and color are " +
this.getBreed()+"," + this.getAge()+ ","+ this.getColor());
}
public static void main(String[] args){
// Initializing a Dog object
Dog tuffy = new Dog("tuffy","papillon", 5, "white");
System.out.println(tuffy.toString());
}
}
Output:
Hi my name is tuffy.
My breed,age and color are papillon,5,white
Dog tuffy = new Dog("tuffy", "papillon", 5, "white");
class DerivedClass extends BaseClass {
//methods and fields
}
class one {
public void print_geek() {
System.out.println("Geeks");
}
}
class two extends one {
public void print_for() {
System.out.println("for");
}
}
public class Main {
public static void main(String[] args) {
two g = new two();
g.print_for();
g.print_geek();
}
}
Output:
for
Geeks
// Java program to illustrate the concept of Multilevel inheritance
class one {
public void print_geek() {
System.out.println("Geeks 1");
}
public void print_hello() {
System.out.println("Hello from GrandParent");
}
}
class two extends one {
public void print_for() {
System.out.println("for");
}
}
class three extends two {
public void print_geek() {
System.out.println("Geeks 3");
}
}
public class Main {
public static void main(String[] args) {
three g = new three();
g.print_geek();
g.print_for();
g.print_hello();
}
}
Output:
Geeks 3
for
Hello from GrandParent
class Grandparent {
public void Print() {
System.out.println("Grandparent");
}
}
class Parent extends Grandparent {
public void Print() {
System.out.println("Parent");
}
}
class Child extends Parent {
public void Print() {
super.super.Print(); // Trying to access Grandparent's Print()
System.out.println("Child");
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
c.Print();
}
}
Output:
Compiler Error
super.super.print();
.class Grandparent {
public void Print() {
System.out.println("Grandparent");
}
}
class Parent extends Grandparent {
public void Print() {
super.Print();
System.out.println("Parent");
}
}
class Child extends Parent {
public void Print() {
super.Print();
System.out.println("Child");
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
c.Print();
}
}
Output:
Grandparent
Parent
Child
interface one {
public void print_geek();
}
interface two {
public void print_for();
}
interface three extends one, two {
public void print_geek();
}
class child implements three {
@Override
public void print_geek() {
System.out.println("Geeks");
}
public void print_for() {
System.out.println("for");
}
}
public class Main {
public static void main(String[] args) {
child c = new child();
c.print_geek();
c.print_for();
}
}
Output:
Geeks
for
// Overloaded sum with different number of parameters and differnt argument types
public class Sum {
public int sum(int x, int y) {
return (x + y);
}
public int sum(int x, int y, int z) {
return (x + y + z);
}
public double sum(double x, double y) {
return (x + y);
}
public static void main(String args[]) {
Sum s = new Sum();
System.out.println(s.sum(10, 20));
System.out.println(s.sum(10, 20, 30));
System.out.println(s.sum(10.5, 20.5));
}
}
Output:
30
60
31.0
class OperatorOVERDDN {
void operator(String str1, String str2) {
String s = str1 + str2;
System.out.println("Concatinated String - " + s);
}
void operator(int a, int b) {
int c = a + b;
System.out.println("Sum = " + c);
}
}
class Main {
public static void main(String[] args) {
OperatorOVERDDN obj = new OperatorOVERDDN();
obj.operator(2, 3);
obj.operator("joe", "now");
}
}
Output:
Sum = 5
Concatinated String - joenow
class Parent {
void show() {
System.out.println("Parent's show()");
}
}
class Child extends Parent {
// This method overrides show() of Parent
@Override
void show() {
System.out.println("Child's show()");
}
}
class Main {
public static void main(String[] args) {
// If a Parent type reference refers to a Parent object, then Parent's show is called
Parent obj;
obj = new Parent();
obj.show();
// If a Parent type reference refers to a Child object, then Child's show() is called.
// This is RUN TIME POLYMORPHISM.
// Also known as Dynamic Dispatch (here child's show() method, above parent's show() method)
obj = new Child();
obj.show();
}
}
Output:
Parent's show()
Child's show()
Note: In Java, we can override methods only, not the variables(data members), so runtime polymorphism cannot be achieved by data members.
class A {
int x = 10;
}
class B extends A {
int x = 20;
}
public class Test {
public static void main(String args[]) {
A a = new B(); // object of type B
// Data member of class A will be accessed
System.out.println(a.x);
}
}
Output:
10
class Parent {
// private methods are not overridden
private void m1() {
System.out.println("From parent m1()");
}
protected void m2() {
System.out.println("From parent m2()");
}
}
class Child extends Parent {
// new m1() method unique to Child class
private void m1() {
System.out.println("From child m1()");
}
// overriding method with more accessibility :- protected to public
@Override
public void m2() {
System.out.println("From child m2()");
}
}
class Main {
public static void main(String[] args) {
Parent obj1 = new Parent();
obj1.m2();
Parent obj2 = new Child();
obj2.m2();
}
}
Output:
From parent m2()
From child m2()
class Parent {
// Can't be overridden
final void show() {}
}
class Child extends Parent {
// This would produce error
void show() {}
}
class Parent {
void show() {
System.out.println("Parent's show()");
}
}
class Child extends Parent {
// This method overrides show() of Parent
@Override
void show() {
super.show();
System.out.println("Child's show()");
}
}
class Main {
public static void main(String[] args) {
Parent obj = new Child();
obj.show();
}
}
Below are two rules to note when overriding methods related to exception-handling.
class Parent {
void m1() {
System.out.println("From parent m1()");
}
void m2() {
System.out.println("From parent m2()");
}
}
class Child extends Parent {
@Override
// no issue while throwing unchecked exception
void m1() throws ArithmeticException {
System.out.println("From child m1()");
}
@Override
// compile-time error issue while throwing checked exception
void m2() throws Exception {
System.out.println("From child m2");
}
}
class Parent {
void m1() throws RuntimeException {
System.out.println("From parent m1()");
}
}
class Child1 extends Parent {
@Override
// no issue while throwing same exception
void m1() throws RuntimeException {
System.out.println("From child1 m1()");
}
}
class Child2 extends Parent {
@Override
// no issue while throwing subclass exception
void m1() throws ArithmeticException {
System.out.println("From child2 m1()");
}
}
class Child3 extends Parent {
@Override
// no issue while not throwing any exception
void m1() {
System.out.println("From child3 m1()");
}
}
class Child4 extends Parent {
@Override
// compile-time error issue while throwing parent exception
void m1() throws Exception {
System.out.println("From child4 m1()");
}
}
public class Encapsulate {
// private variables declared these can only be accessed by public methods of class
private String geekName;
private int geekRoll;
private int geekAge;
// get method for age to access private variable geekAge
public int getAge() {
return geekAge;
}
// get method for name to access private variable geekName
public String getName() {
return geekName;
}
// get method for roll to access private variable geekRoll
public int getRoll() {
return geekRoll;
}
// set method for age to access private variable geekage
public void setAge( int newAge) {
geekAge = newAge;
}
// set method for name to access private variable geekName
public void setName(String newName) {
geekName = newName;
}
// set method for roll to access private variable geekRoll
public void setRoll( int newRoll) {
geekRoll = newRoll;
}
}
public class TestEncapsulation {
public static void main (String[] args) {
Encapsulate obj = new Encapsulate();
// setting values of the variables
obj.setName("Harsh");
obj.setAge(19);
obj.setRoll(51);
// Displaying values of the variables
System.out.println("Geek's name: " + obj.getName());
System.out.println("Geek's age: " + obj.getAge());
System.out.println("Geek's roll: " + obj.getRoll());
// Direct access of geekRoll is not possible due to encapsulation
// System.out.println("Geek's roll: " + obj.geekName);
}
}
Output:
Geek's name: Harsh
Geek's age: 19
Geek's roll: 51
Situation Example:
abstract class Shape {
String color;
// these are abstract methods
abstract double area();
public abstract String toString();
// abstract class can have constructor
public Shape(String color) {
System.out.println("Shape constructor called");
this.color = color;
}
// this is a concrete method
public String getColor() {
return color;
}
}
class Circle extends Shape {
double radius;
public Circle(String color,double radius) {
// calling Shape constructor
super(color);
System.out.println("Circle constructor called");
this.radius = radius;
}
@Override
double area() {
return Math.PI * Math.pow(radius, 2);
}
@Override
public String toString() {
return "Circle color is " + super.color + "and area is : " + area();
}
}
class Rectangle extends Shape{
double length;
double width;
public Rectangle(String color,double length,double width) {
// calling Shape constructor
super(color);
System.out.println("Rectangle constructor called");
this.length = length;
this.width = width;
}
@Override
double area() {
return length*width;
}
@Override
public String toString() {
return "Rectangle color is " + super.color + "and area is : " + area();
}
}
public class Test {
public static void main(String[] args) {
Shape s1 = new Circle("Red", 2.2);
Shape s2 = new Rectangle("Yellow", 2, 4);
System.out.println(s1.toString());
System.out.println(s2.toString());
}
}
Output:
Shape constructor called
Circle constructor called
Shape constructor called
Rectangle constructor called
Circle color is Redand area is : 15.205308443374602
Rectangle color is Yellowand area is : 8.0
Property-1: An instance of an abstract class cannot be created, we can have references of abstract class type though.
abstract class Base {
abstract void fun();
}
class Derived extends Base {
void fun() { System.out.println("Derived fun() called"); }
}
class Main {
public static void main(String args[]) {
// Below line will cause compiler error as thetries to create an instance of abstract class.
// Base b = new Base();
// But we can have references of Base type.
Base b = new Derived();
b.fun();
}
}
Output:
Derived fun() called
Property-2: Constructor of abstract class is called when an instance of a inherited class is created.
abstract class Base {
Base() { System.out.println("Base Constructor Called"); }
abstract void fun();
}
class Derived extends Base {
Derived() { System.out.println("Derived Constructor Called"); }
void fun() { System.out.println("Derived fun() called"); }
}
class Main {
public static void main(String args[]) {
Derived d = new Derived();
}
}
Output:
Base Constructor Called
Derived Constructor Called
Property-3: We can have an abstract class without any abstract method, this allows to create classes that cannot be instantiated, but can only be inherited.
abstract class Base {
void fun() { System.out.println("Base fun() called"); }
}
class Derived extends Base { }
class Main {
public static void main(String args[]) {
Derived d = new Derived();
d.fun();
}
}
Output:
Base fun() called
Property-4: Abstract classes can also have final methods (methods that cannot be overridden).
abstract class Base {
final void fun() { System.out.println("Base fun() called"); }
}
class Derived extends Base {}
class Main {
public static void main(String args[]) {
Base b = new Derived();
b.fun();
}
}
Output:
Base fun() called
Basic Syntax:
interface <interface_name> {
// declare constant fields
// declare methods that are abstract by default.
}
Example:
interface In1 {
// public, static and final
final int a = 10;
// public and abstract
void display();
}
// A class that implements the interface.
class TestClass implements In1 {
// Implementing the capabilities of interface.
public void display() {
System.out.println("Geek");
}
public static void main (String[] args) {
TestClass t = new TestClass();
t.display();
System.out.println(a);
}
}
Output:
Geek
10
A real World Example:
interface Vehicle {
// all are the abstract methods.
void changeGear(int a);
void speedUp(int a);
void applyBrakes(int a);
}
class Bicycle implements Vehicle{
int speed;
int gear;
// to change gear
@Override
public void changeGear(int newGear){
gear = newGear;
}
// to increase speed
@Override
public void speedUp(int increment){
speed = speed + increment;
}
// to decrease speed
@Override
public void applyBrakes(int decrement){
speed = speed - decrement;
}
public void printStates() {
System.out.println("speed: " + speed + " gear: " + gear);
}
}
class Bike implements Vehicle {
int speed;
int gear;
// to change gear
@Override
public void changeGear(int newGear){
gear = newGear;
}
// to increase speed
@Override
public void speedUp(int increment){
speed = speed + increment;
}
// to decrease speed
@Override
public void applyBrakes(int decrement){
speed = speed - decrement;
}
public void printStates() {
System.out.println("speed: " + speed + " gear: " + gear);
}
}
class GFG {
public static void main (String[] args) {
// creating an inatance of Bicycle doing some operations
Bicycle bicycle = new Bicycle();
bicycle.changeGear(2);
bicycle.speedUp(3);
bicycle.applyBrakes(1);
System.out.println("Bicycle present state :");
bicycle.printStates();
// creating instance of the bike.
Bike bike = new Bike();
bike.changeGear(1);
bike.speedUp(4);
bike.applyBrakes(3);
System.out.println("Bike present state :");
bike.printStates();
}
}
Output:
Bicycle present state :
speed: 2 gear: 2
Bike present state :
speed: 1 gear: 1
Prior to Java 8, interface could not define implementation. We can now add default implementation for interface methods.
This default implementation has special use and does not affect the intention behind interfaces.
Suppose we need to add a new function in an existing interface. Obviously the old code will not work as the classes have not implemented those new functions. So with the help of default implementation, we will give a default body for the newly added functions. Then the old codes will still work.
interface In1 {
final int a = 10;
default void display() {
System.out.println("hello");
}
}
class TestClass implements In1 {
public static void main (String[] args) {
TestClass t = new TestClass();
t.display();
}
}
Output:
hello
We can now define static methods in interfaces which can be called independently without an object.
Note:- these methods are not inherited.
interface In1 {
final int a = 10;
default void display() {
System.out.println("hello");
}
}
class TestClass implements In1 {
public static void main (String[] args) {
In1.display();
}
}
Output:
hello
From Java 9 onwards, interfaces can contain following also
Both keywords are used when creating your own new class in the Java language.
Implements is for when we are implementing an interface.
Extends is for inheriting from a base class for extending something that already exists by adding more functionality to it or overriding something already existing.
To solve problem of multiple-inheritance in Java we can only have one super class, but we can implement multiple interfaces.