All abstract methods of implemented interfaces must be overridden (or the class is abstract).
Default method conflicts: if two interfaces provide default methods with same signature, the implementing class must override (compile error otherwise).
A class that implements an interface is a subtype of that interface.
interfaceA{defaultStringname(){return"A";}}interfaceBextendsA{defaultStringname(){return"B";}}classCimplementsA,B{// Must override to resolve conflict (or not — B is more specific and wins here)// In this case B overrides A, so C inherits B's default@OverridepublicStringname(){returnB.super.name();}// explicit super call}
classPerson{Stringname;intage;Person(Stringname,intage){this.name=name;this.age=age;}Person(Stringname){this(name,0);// chains to two-arg constructor}Person(){this("Unknown");// chains to one-arg constructor}}
abstractclassVehicle{protectedStringbrand;Vehicle(Stringbrand){// abstract class CAN have constructorthis.brand=brand;}abstractvoidmove();}classCarextendsVehicle{Car(Stringbrand){super(brand);// must call abstract class constructor}@Overridevoidmove(){System.out.println(brand+" car is moving");}}
recordRange(intlo,inthi){Range{// compact constructor — no parameter list neededif(lo>hi){thrownewIllegalArgumentException("lo > hi");}// lo and hi are implicitly assigned from components}}
// Example 1: Classes, Inheritance, Polymorphism// File: OopBasics.javapublicclassOopBasics{// Abstract superclassabstractstaticclassShape{protectedStringcolor;Shape(Stringcolor){this.color=color;}abstractdoublearea();abstractdoubleperimeter();@OverridepublicStringtoString(){return"%s[color=%s, area=%.2f]".formatted(getClass().getSimpleName(),color,area());}}// Concrete subclassstaticclassCircleextendsShape{privatefinaldoubleradius;Circle(Stringcolor,doubleradius){super(color);// call superclass constructorthis.radius=radius;}@Overridepublicdoublearea(){returnMath.PI*radius*radius;}@Overridepublicdoubleperimeter(){return2*Math.PI*radius;}}staticclassRectangleextendsShape{privatefinaldoublewidth,height;Rectangle(Stringcolor,doublewidth,doubleheight){super(color);this.width=width;this.height=height;}@Overridepublicdoublearea(){returnwidth*height;}@Overridepublicdoubleperimeter(){return2*(width+height);}}publicstaticvoidmain(String[]args){Shape[]shapes={newCircle("red",5.0),newRectangle("blue",4.0,6.0),newCircle("green",3.0)};for(Shapes:shapes){System.out.println(s);// polymorphic toString and area()}// Pattern matching with sealed typesfor(Shapes:shapes){Stringdesc=switch(s){caseCirclec->"Circle with radius "+c.radius;caseRectangler->"Rect "+r.width+"x"+r.height;default->"Unknown shape";};System.out.println(desc);}}}
// Example 2: Interfaces with Default Methods// File: InterfaceDemo.javaimportjava.util.Comparator;publicclassInterfaceDemo{// Interface with abstract and default methodsinterfacePrintable{voidprint();// abstractdefaultvoidprintTwice(){// defaultprint();print();}staticPrintableof(Stringmsg){// static factoryreturn()->System.out.println(msg);}}interfaceSaveable{voidsave();defaultStringdescribe(){return"Saveable";}}// Class implementing multiple interfacesstaticclassDocumentimplementsPrintable,Saveable{privatefinalStringcontent;Document(Stringcontent){this.content=content;}@Overridepublicvoidprint(){System.out.println("Doc: "+content);}@Overridepublicvoidsave(){System.out.println("Saving: "+content);}@OverridepublicStringdescribe(){return"Document";}// resolves ambiguity}interfaceSortable<T>extendsComparable<T>{defaultbooleanisLessThan(Tother){returncompareTo(other)<0;}}staticclassVersionimplementsSortable<Version>{finalintmajor,minor;Version(intmajor,intminor){this.major=major;this.minor=minor;}@OverridepublicintcompareTo(Versionother){intcmp=Integer.compare(this.major,other.major);returncmp!=0?cmp:Integer.compare(this.minor,other.minor);}@OverridepublicStringtoString(){returnmajor+"."+minor;}}publicstaticvoidmain(String[]args){Documentdoc=newDocument("Hello, Java!");doc.printTwice();doc.save();System.out.println(doc.describe());// Static factory method on interfacePrintablep=Printable.of("From static factory");p.print();// Interface type variableVersionv1=newVersion(2,0);Versionv2=newVersion(1,9);System.out.println(v2+" < "+v1+": "+v2.isLessThan(v1));// true}}
// Example 3: Encapsulation with Accessors and Mutators// File: Encapsulation.javaimportjava.util.Objects;publicclassEncapsulation{staticclassBankAccount{privatefinalStringaccountId;privatedoublebalance;privateStringowner;BankAccount(StringaccountId,Stringowner,doubleinitialBalance){this.accountId=Objects.requireNonNull(accountId,"accountId cannot be null");this.owner=Objects.requireNonNull(owner,"owner cannot be null");if(initialBalance<0)thrownewIllegalArgumentException("Initial balance must be >= 0");this.balance=initialBalance;}// Accessor (getter)publicStringgetAccountId(){returnaccountId;}publicdoublegetBalance(){returnbalance;}publicStringgetOwner(){returnowner;}// Mutator (setter)publicvoidsetOwner(Stringowner){this.owner=Objects.requireNonNull(owner,"owner cannot be null");}// Business logic methodspublicvoiddeposit(doubleamount){if(amount<=0)thrownewIllegalArgumentException("Deposit must be positive");balance+=amount;}publicvoidwithdraw(doubleamount){if(amount<=0)thrownewIllegalArgumentException("Withdrawal must be positive");if(amount>balance)thrownewIllegalStateException("Insufficient funds");balance-=amount;}@OverridepublicStringtoString(){return"Account[%s, owner=%s, balance=%.2f]".formatted(accountId,owner,balance);}}publicstaticvoidmain(String[]args){BankAccountaccount=newBankAccount("ACC-001","Alice",1000.00);System.out.println(account);account.deposit(500.00);System.out.println("After deposit: "+account.getBalance());account.withdraw(200.00);System.out.println("After withdrawal: "+account.getBalance());try{account.withdraw(2000.00);}catch(IllegalStateExceptione){System.out.println("Error: "+e.getMessage());}}}
// Example 4: Records and Sealed Classes (Java 21)// File: ModernOop.javapublicclassModernOop{// Sealed interface hierarchysealedinterfaceResult<T>permitsSuccess,Failure{}recordSuccess<T>(Tvalue)implementsResult<T>{}recordFailure<T>(Stringerror,Exceptioncause)implementsResult<T>{Failure(Stringerror){this(error,null);}}// Enum with methods and fieldsenumPlanet{MERCURY(3.303e+23,2.4397e6),VENUS(4.869e+24,6.0518e6),EARTH(5.976e+24,6.37814e6),MARS(6.421e+23,3.3972e6);privatefinaldoublemass;// kgprivatefinaldoubleradius;// metersPlanet(doublemass,doubleradius){this.mass=mass;this.radius=radius;}staticfinaldoubleG=6.67300E-11;doublesurfaceGravity(){returnG*mass/(radius*radius);}doublesurfaceWeight(doubleotherMass){returnotherMass*surfaceGravity();}}// Generic utility with sealed resultstaticResult<Integer>safeDivide(inta,intb){if(b==0)returnnewFailure<>("Division by zero");returnnewSuccess<>(a/b);}static<T>TunwrapOrDefault(Result<T>result,TdefaultValue){returnswitch(result){caseSuccess<T>s->s.value();caseFailure<T>f->{System.err.println("Error: "+f.error());yielddefaultValue;}};}publicstaticvoidmain(String[]args){// RecordsResult<Integer>r1=safeDivide(10,2);Result<Integer>r2=safeDivide(10,0);System.out.println(unwrapOrDefault(r1,-1));// 5System.out.println(unwrapOrDefault(r2,-1));// -1 (with error logged)// Enum usagedoubleearthWeight=75.0;doublemass=earthWeight/Planet.EARTH.surfaceGravity();for(Planetp:Planet.values()){System.out.printf("Weight on %s: %.2f%n",p,p.surfaceWeight(mass));}}}
// Example 5: Complete OOP Design — Strategy Pattern// File: StrategyPattern.javaimportjava.util.Arrays;importjava.util.Comparator;importjava.util.List;publicclassStrategyPattern{// Interface (strategy)@FunctionalInterfaceinterfaceSortStrategy<T>{List<T>sort(List<T>items);}// Concrete strategiesstatic<TextendsComparable<T>>SortStrategy<T>naturalOrder(){returnitems->items.stream().sorted().toList();}static<T>SortStrategy<T>by(Comparator<T>comparator){returnitems->items.stream().sorted(comparator).toList();}// Context classstaticclassDataProcessor<TextendsComparable<T>>{privatefinalList<T>data;privateSortStrategy<T>strategy;DataProcessor(List<T>data){this.data=List.copyOf(data);this.strategy=naturalOrder();// default strategy}voidsetStrategy(SortStrategy<T>strategy){this.strategy=strategy;}List<T>process(){returnstrategy.sort(data);}}recordEmployee(Stringname,intage,doublesalary){}publicstaticvoidmain(String[]args){List<Employee>employees=List.of(newEmployee("Charlie",35,80000),newEmployee("Alice",28,95000),newEmployee("Bob",42,70000));DataProcessor<String>nameProcessor=newDataProcessor<>(employees.stream().map(Employee::name).toList());// Default: natural orderSystem.out.println("Names sorted: "+nameProcessor.process());// Custom strategy: reverse ordernameProcessor.setStrategy(by(Comparator.reverseOrder()));System.out.println("Names reversed: "+nameProcessor.process());// Strategy using method referenceList<Employee>byAge=employees.stream().sorted(Comparator.comparingInt(Employee::age)).toList();byAge.forEach(e->System.out.printf("%s: %d%n",e.name(),e.age()));// Pattern matching for recordsfor(varemp:employees){switch(emp){caseEmployee(Stringn,intage,doublesal)whensal>85000->System.out.println(n+" is a high earner");caseEmployee(Stringn,_,_)->System.out.println(n+" is a regular employee");}}}}