Comparable & Comparator Interface

import java.util.*;

class Person implements Comparable<Person> {
    private static int count = 0; // static (class) field
    protected String name; // instance field
    protected int age; // instance field

    public Person() {
        //System.out.println("Person Constructor"); // this("", 0); error: call to this must be first statemenht in constructor
        this("", 0);
    }

    public Person(String name, int age) {
        count++;
        this.name = name;
        this.age = age;
    }

    public Person(Person other) {
        this(other.name, other.age);
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void set(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void set(Person other) {
        this.name = other.name;
        this.age = other.age;
    }

    public Person clone() {
        Person p = new Person(this.name, this.age);
        return p;
    }

    @Override
    public boolean equals(Object other) { // Object.equals overriding
        if (other instanceof Person) {
            Person that = (Person) other;
            return that.canEqual(this) && this.getName().equals(that.getName()) && this.getAge() == that.getAge();
        }
        return false;
    }

    @Override
    public int hashCode() {
        return (41 * getName().hashCode() + getAge());
    }

    public boolean canEqual(Object other) {
        return (other instanceof Person);
    }

    @Override
    public String toString() { // Object.toString() overriding
        return "Person Name: " + name + " Age: " + age;
    }

    public void print() { // instance methods
        System.out.println("Person Name: " + name + " Age: " + age);
    }

    public static void printCount() { // static (class) methods
        System.out.println("Person Count: " + count);
    }

    public static int getCount() {  // static (class) methods
        return count; 
    }

    public static void setCount(int value) { // static (class) methods
        count = value; 
    } 

    public int compareTo(Person other) {
        String thisName = this.getName().toUpperCase();
        String otherName = ((Person)other).getName().toUpperCase();
        //ascending order
        return thisName.compareTo(otherName);
        //descending order
        //return otherName.compareTo(thisName);
    }

    public static Comparator<Person> AgeComparator = new Comparator<Person>() {
        public int compare(Person p1, Person p2) {
            int age1 = p1.getAge();
            int age2 = p2.getAge();
            //ascending order
            return age1 – age2;
            //descending order
            //return age2 – age1;
        }
    };
}

///////////////////////////////////////////////////////////////////////////////////////
class Student extends Person {
    private static int count = 0; // static (class) field
    protected int id;

    public Student() {
        id = 5208;
    }

    public Student(String name, int age, int id) {
        super(name, age);
        this.id = id;
        count++;
    }

    public int getID() {
        return id;
    }

    public void setID(int id) {
        this.id = id;
    }

    public void set(String name, int age, int id) {
        super.set(name, age);
        this.id = id;
    }

    public void set(String name, int age) {
        super.set(name, age);
    }

    public void set(Student other) {
        this.set(other.name, other.age, other.id);
    }

    public void set(Person other) {
        if (other instanceof Person)
            super.set(other);
        else
            this.set((Student)other);
    }

    public Student clone() {
        Student s = new Student(this.name, this.age, this.id);
        return s;
    }

    @Override
    public boolean equals(Object other) { // Object.equals overriding
        if (other instanceof Student) {
            Student that = (Student) other;
            return that.canEqual(this) && this.getName().equals(that.getName()) && this.getAge() == that.getAge() && this.getID() == that.getID();
        }
        return false;
    }

    @Override
    public int hashCode() {
        return (41 * super.hashCode() + getID());
    }

    public boolean canEqual(Object other) {
        return (other instanceof Student);
    }

    @Override
    public String toString() { // Object.toString() overriding
        return "Student Name: " + name + " Age: " + age + " ID: " + id;
    }

    public void superPrint() {
        super.print();
    }

    public void print() { // Person.print() method overriding
        System.out.println("Student Name: " + name + " Age: " + age + " ID: " + id);
    }

    public static void printCount() { // static (class) methods
        System.out.println("Student Count: " + count);
    }

    public static int getCount() { // static (class) methods
        return count; 
    } 
    public static void setCount(int value) { // static (class) methods
        count = value; 
    }

    public int compareTo(Student other) {
        String thisName = this.getName().toUpperCase();
        String otherName = ((Student)other).getName().toUpperCase();
        //ascending order
        return thisName.compareTo(otherName);
        //descending order
        //return otherName.compareTo(thisName);
    }

    public static Comparator<Student> AgeComparator = new Comparator<Student>() {
        public int compare(Student p1, Student p2) {
            int age1 = p1.getAge();
            int age2 = p2.getAge();
            //ascending order
            return age1 – age2;
            //descending order
            //return age2 – age1;
        }
    };

    public static Comparator<Student> IDComparator = new Comparator<Student>() {
        public int compare(Student p1, Student p2) {
            int id1 = p1.getID();
            int id2 = p2.getID();
            //ascending order
            return id1 – id2;
            //descending order
            //return id2 – id1;
        }
    };
}

class PersonStudentTest {

    public static void print(Object[] array) {
        for(Object o : array) {
            System.out.println(o);
        }
    }

    public static void main(String[] args) {
///////////////////////////////////////////////////////////////////////
        Student[] sList = new Student[3];
        sList[0] = new Student("Kevin", 0, 222);
        sList[1] = new Student("Jason", 1, 333);
        sList[2] = new Student("John", 2, 111);

        System.out.println("STUDENT SORT BY NAME (DEFAULT)!!!");
        Arrays.sort(sList);
        print(sList);

        System.out.println("STUDENT SORT by AGE!!!");
        Arrays.sort(sList, Student.AgeComparator);
        print(sList);

        System.out.println("STUDENT SORT by ID!!!");
        Arrays.sort(sList, Student.IDComparator);
        print(sList);

///////////////////////////////////////////////////////////////////////
        Student[] sList2 = new Student[3];
        sList2[0] = new Student("Kevin", 0, 222);
        sList2[1] = new Student("Jason", 1, 333);
        sList2[2] = new Student("John", 2, 111);

        System.out.println("STUDENT SORT BY NAME (anonymous method)!!!");
        Arrays.sort(sList2, new Comparator<Student>() {
            public int compare(Student s1, Student s2) {
                return s1.getName().toUpperCase().compareTo(s2.getName().toUpperCase());
            }
        });
        print(sList2);

        System.out.println("STUDENT SORT by AGE (anonymous method)!!!");
        Arrays.sort(sList2, new Comparator<Student>() {
            public int compare(Student s1, Student s2) {
                return s1.getAge() – s2.getAge();
            }
        });
        print(sList2);

        System.out.println("STUDENT SORT by ID (anonymous method)!!!");
        Arrays.sort(sList2, new Comparator<Student>() {
            public int compare(Student s1, Student s2) {
                return s1.getID() – s2.getID();
            }
        });
        print(sList2);

///////////////////////////////////////////////////////////////////////
        Student[] sList3 = sList2;

        System.out.println("STUDENT SORT BY NAME (lambda)!!!");
        Arrays.sort(sList3, (Student ss1, Student ss2) ->
                            ss1.getName().compareTo(ss2.getName())
        );
        Arrays.stream(sList3).forEach((s) -> System.out.println(s));

        System.out.println("STUDENT SORT by AGE (lambda)!!!");
        Arrays.sort(sList3, (Student ss1, Student ss2) ->
                            Integer.compare(ss1.getAge(), ss2.getAge())
        );
        Arrays.stream(sList3).forEach((s) -> System.out.println(s));

        System.out.println("STUDENT SORT by ID (lambda)!!!");
        Arrays.sort(sList3, (Student ss1, Student ss2) ->
                            Integer.compare(ss1.getID(), ss2.getID())
        );
        Arrays.stream(sList3).forEach((s) -> System.out.println(s));

///////////////////////////////////////////////////////////////////////
        List<Student> sList4 = new ArrayList<Student>();
        sList4.add(new Student("Kevin", 0, 222));
        sList4.add(new Student("Jason", 1, 333));
        sList4.add(new Student("John", 2, 111));

        System.out.println("STUDENTLIST SORT BY NAME (lambda)!!!");
        sList4.sort((Student ss1, Student ss2) ->
                    ss1.getName().compareTo(ss2.getName())
        );
        sList4.forEach((s) -> System.out.println(s));

        System.out.println("STUDENTLIST SORT by AGE (lambda)!!!");
        sList4.sort((Student ss1, Student ss2) ->
                    ss1.getAge() – ss2.getAge()
        );
        sList4.forEach((s) -> System.out.println(s));

        System.out.println("STUDENTLIST SORT by ID (lambda)!!!");
        sList4.sort((Student ss1, Student ss2) ->
                    ss1.getID() – ss2.getID()
        );
        sList4.forEach((s) -> System.out.println(s));
    }

}

Midterm Extra +10

중간고사 문제를 다시 풀어본다. (Due 5/1 12:00pm)
중간고사 예제 + 본인 예제 프로그램 (문제 하나당 비슷한 예제) + 문제풀이 보고서 제출 (제출하면 +10점. 중간점수 없음)
Midterm_학번_이름.zip 압축한 후 e-learning으로 제출
보고서는 출력해서 수업시간에 제출한다.

Lab5

Lab5 프로젝트 디렉토리 안에 모든 파일(src/*.java & bin/*.class)와 보고서 (2~3장)를 넣고 Lab5_학번_이름.zip 압축한 후 e-learning으로 제출 (due by 5/7)

Lab5 Inheritance (추상클래스, 추상메소드 활용)

본인이 작성한 Lab4를 상속관계를 갖는 객체지향적인 프로그램으로 바꾼다.
java1-lab5

Abstract Class & Abstract Method & Polymorphism

Abstract Class (추상 클래스)는 하나 이상의 abstract method(추상메소드)를 가지거나, 추상메소드가 없지만 abstract으로 선언한 클래스. 추상클래스는 객체를 생성할 수 없다.

Abstract Method (추상 메소드)는 선언은 되어 있으나 구현 내용이 없는 메소드이다.

추상클래스를 상속받은 하위클래스는 반드시 추상 메소드를 재정의(method override) 구현해야한다.

Polymorphism (다형성)은 프로그램 실행(run-time execution)시 형(type)이 변화되는 객체.

다형성에 따라서, 클래스 상속관계(Inheritance)에서 메소드 재정의(Method overriding)된 것이 동적 바인딩(dynamic binding)으로 호출되었을 시, 해당 객체에 맞는 재정의된 메소드가 호출되는 것이다.

Shape 추상클래스 has-a ShapeType, ShapeColor, ShapeRect

Shape 추상클래스를 상속받은 Triangle, Rectangle, Square, Circle 클래스는 추상메소드인 area()를 반드시 구현해야한다.

https://www.cs.usfca.edu/~wolber/SoftwareDev/OO/abstractInterfacesIntro.htm

Static vs Instance Initializer Block

Static Initializer Block

  • class 로딩 시 호출
  • instance variable이나 method에 접근 못함
  • static variable 초기화에 사용
public class StaticIntializerBlockTest {
    private static int id = 5;
    static {
        if (id <10) id = 20;
        else id = 100;
    }

    public static int getId() {
        return id;
    }

    public static void print() {
        System.out.println("StaticIntializerBlockTest.id=" + getId());
    }
}

public class StaticInstanceInitializerBlockTest {

    public static void main(String[] args) {
        StaticIntializerBlockTest.print();
    }
}

StaticIntializerBlockTest.id=20 // static block 이 호출되면서 20으로 셋팅

Instance Initializer Block

  • 객체 생성시 호출
  • super 생성자 이후에 실행하고, 생성자보다 먼저 실행
  • instance variable이나 method에 접근 가능
  • 모든 생성자의 공통 부분을 instance initializer block에 넣어줌
class InstanceInitializerBlockSuper {
    public InstanceInitializerBlockSuper() {
        System.out.println("InstanceInitializerBlockSuper");
    }
}

public class InstanceInitializerBlockTest extends InstanceInitializerBlockSuper {
    private int id = 5;
    {
        if (id <10) id = 20;
        else id = 100;
    }

    public InstanceInitializerBlockTest() {
        System.out.println("InstanceInitializerBlockTest.id=" + this.id);
    }

    public InstanceInitializerBlockTest(int id) {
        System.out.println(“InstanceInitializerBlockTest.id=" + this.id);
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void print() {
        System.out.println("StaticIntializerBlockTest.id=" + getId());
    }
}

public class StaticInstanceInitializerBlockTest {
    public static void main(String[] args) {
        InstanceInitializerBlockTest i = new InstanceInitializerBlockTest();
        i.print();
        i = new InstanceInitializerBlockTest(30);
        i.print();
    }
}

InstanceInitializerBlockSuper // super 생성자 이후에 실행
InstanceInitializerBlockTest.id=20 // instance block 호출되면서 20으로 셋팅 
id=20
InstanceInitializerBlockSuper // super 생성자 이후에 실행
InstanceInitializerBlockTest.id=20 // instance block 호출되면서 20으로 셋팅된후 this.id = id를 통해서 30으로 셋팅
id=30

https://stackoverflow.com/questions/12550135/static-block-vs-initializer-block-in-java

Person Student Class Instance vs Static Method Overriding

PersonStudent-MethodOverriding2

/// Person
class Person {
    private static int count = 0; // static (class) field
    protected String name; // instance field
    protected int age; // instance field

    public Person() {
        //System.out.println("Person Constructor"); // this("", 0); error: call to this must be first statemenht in constructor
        this("", 0);
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        count++;
    }

    public static void printCount() { // static (class) method
        System.out.println("Person Count: " + count);
    }

    public static int getCount() {  // static (class) method
        return count; 
    }

    public String toString() { // Object.toString() overriding
        return "Person Name: " + name + " Age: " + age;
    }

    public void print() { // instance method
        System.out.println("Person Name: " + name + " Age: " + age);
    }
}

/// Student
class Student extends Person {
    private static int scount = 0; // static (class) variables
    protected int id;

    public Student() {
        this("", 0, 5208);
    }

    public Student(String name, int age, int id) {
        super(name, age);
        this.id = id;
        scount++;
    }

    public static void printCount() { // static (class) method overriding
        System.out.println("Student Count: " + scount);
    }

    public String toString() { // Object.toString() overriding
        return "Student Name: " + name + " Age: " + age + " ID: " + id;
    }

    public void print() { // Person.print() method overriding
        System.out.println("Student Name: " + name + " Age: " + age + " ID: " + id);
    }
}

class PersonStudentTest {
    public static void main(String[] args) {
        Person p1 = new Student("K", 20, 2018); // upcasting 1번째 Student 객체 생성
        p1.print(); // dynamic binding Student Name: K Age: 20 ID: 2018
        p1.name = "JAVA";
        p1.age = 1;
        //p1.id = 2017; // cannnot call id because p1 is Person type
        System.out.println(p1); // dynamic binding p1.toString() Student Name: JAVA Age: 1 ID: 1208
        p1.printCount(); // p1 is Person, Person.printCount() Person.count=1
        Person.printCount(); // Person.printCount() Person.count=1
        Student.printCount(); // Student.printCount() Student.scount=1
        System.out.println();

        Student s1 = (Student)p1; // downcasting
        s1.name = "JAVA2"; 
        s1.age = 2;
        s1.id = 2017; // can call id, because s1 is Student type
        s1.print(); // Student Name: JAVA2 Age: 2 ID: 2017
        s1.printCount(); // s1 is Student, Student.printCount() scount=1
        Person.printCount(); // Person.printCount() count=1
        Student.printCount(); // Student.printCount() scount=1
        System.out.println();

        Student s2 = new Student("S", 30, 1207); // 2번째 Student 객체 생성
        s2.print(); // Student Name: S Age: 30 ID: 1217
        s2.printCount(); // s2 is Student, Student.printCount() scount=2
        Person.printCount(); // Person.printCount() count=2
        Student.printCount(); // Student.printCount() count=2
        System.out.println();

        Person p2 = new Person("Park", 1); // 1번째 Person 객체 생성
        System.out.println(p2); // Person Name: Park Age: 1
        p2.printCount(); // p2 is Person, Person.printCount() count=3
        Person.printCount(); // Person.printCount() count=3
        Student.printCount(); // Student.printCount() scount=2
        System.out.println();

        Person p3 = new Person(); // 2번째 Person 객체 생성
        System.out.println(p3); // Person Name: Age: 0
        p3.printCount(); // p3 is Person, Person.printCount() count=4
        Person.printCount(); // Person.printCount() count=4
        Student.printCount(); // Student.printCount() scount=2
        System.out.println();

        System.out.println("Number of Person: " + Person.getCount()); // Person.getCount() count=4
    }
}

Car Sedan Class

CarSedan-PublicProtectedPrivate

public class Car {
    // member field
    private boolean disel; // private은 파생 클래스에서 사용하지 못함
    protected boolean gasoline; // protected은 파생 클래스에서 사용 가능하나 외부(다른 패키지)에서는 호출하지 못함
    protected int wheel = 4;

    // constructor
    protected Car() { 
        disel = true; 
        gasoline = true; 
    }
    protected Car(int wheel) { 
        this.wheel = wheel; 
        disel = false; 
        gasoline = false; 
    }

    // method
    protected void move() {
        if (disel) System.out.println("Disel Car");
        System.out.println("Move wheel=" + wheel);
    }
}

public class Sedan extends Car {
    // member field
    private boolean gasoline; // 파생 클래스에서 기반클래스에 멤버필드명이 같다면 default는 자신의 멤버부터 호출, 즉, this.gasoline 부터 사용

    // constructor
    public Sedan() { // 내부적으로 super() 호출, 즉 super.gasoline=true 
        gasoline = false; 
    } 
    public Sedan(int wheel) { // super(int wheel)를 호출, 즉 super.gasoline=false (protected 생성자는 파생클래스에서 호출 가능)
        super(wheel); 
        gasoline = true; 
    } 
    // method
    public void sedanMove() {
        // base의 gasoline과 this의 gasoline을 구분해야하는 경우
        if (super.gasoline) System.out.print("Gasoline Car ");
        if (this.gasoline) System.out.print("Gasoline SedanCar ");
        System.out.println("move wheel=" + wheel);
    }

    public static void main(String[] args) {
        Car myCar = new Car(); // protected 생성자 같은 패키지 내에 사용가능.
        myCar.move(); // protected 메소드 호출 가능
        System.out.println("myCar wheel=" + myCar.wheel); // protected 필드 호출 가능

        // 바퀴 4개 디젤 자동차
        Sedan myCar1 = new Sedan(); // public 생성자 호출 가능
        myCar1.move(); // protected 메소드 호출 가능
        myCar1.sedanMove(); // public 메소드 호출가능

        // 바퀴 6개 가솔린 자동차
        Sedan myCar2 = new Sedan(6); // public 생성자 호출 가능
        myCar2.move(); // protected 메소드 호출 가능
        myCar2.sedanMove(); // public 메소드 호출가능
    }
}

BankAccount CheckingAccount SavingAccount Class

BankAccount-InstanceStatic – instance vs static member field & method
BankAccount


public class BankAccount {
    protected String name; // instance field
    protected double balance; // instance field 
    protected static double interestRate; // static field

    public BankAccount() { // default constructor
        this(1000, "JAVA17");
    }

    public BankAccount(String name, double balance) {
        this.name = name;
        this.balance = balance;
        BankAccount.interestRate = 1.0;
    }

    public void deposit(double amount) { // instance method
        balance += amount;
    }

    public void withdraw(double amount) { // instance method
        balance -= amount;
    }

    public void transfer(double amount, BankAccount other) { // instance method
        withdraw(amount);
        other.deposit(amount);
    }

    public double getBalance() { // instance method
        return balance + balance * interestRate * 0.01;
    }

    public void print() { // instance method
        System.out.println(name + " balance=" + getBalance());
    }

    @Override // Object.toString() method override
    public String toString() { // instance method
        return name + " balance=" + getBalance();
    }

    public static void setInterestRate(double interestRate) { // static method
        BankAccount.interestRate = interestRate;
    }
}

public class CheckingAccount extends BankAccount {
    private double overdraftLimit; 

    public CheckingAccount(String name, double balance, double overdraftLimit) { 
        super(name, balance);
        interestRate = 2.0;
        setOverdraftLimit(overdraftLimit); 
    }
	
    public void setOverdraftLimit(double overdraftLimit) {  
        this.overdraftLimit = overdraftLimit;  
    }  

    public double getOverdraftLimit() {  
        return overdraftLimit;  
    }

    @Override // BankAccount.withdraw(double amount) method override 
    public void withdraw(double amount) {  
        if(getBalance() - overdraftLimit < amount)
            System.out.println("CheckingAccount::withdraw Cannot be withdrawn due to overdraftLimit"); 
        else
            super.withdraw(amount);  		
    }

    @Override // BankAccount.print() method override 
    public void print() {
        System.out.println("CheckingAccount: " + name + " balance=" + getBalance());
    }
}

public class SavingAccount extends BankAccount {
    public SavingAccount(String name, double balance) { 
        super(name, balance);
        interestRate = 5.0;
    }

    @Override // BankAccount.withdraw(double amount) method override
    public void withdraw(double amount)  {
        if (getBalance() < amount)  
            System.out.println("SavingAccount::withdraw Amount is larger than current balance.");  
        else
            super.withdraw(amount);
    }

    @Override // BankAccount.print() method override 
    public void print() {
        System.out.println("SavingAccount: " + name + " balance=" + getBalance());
    }
}

public class BankAccountTest {
    public static void main(String[] args) {
        BankAccount b1 = new BankAccount("P", 0);
        b1.deposit(3000);
        b1.withdraw(1000);
        b1.print(); // P balance=2020.0

        BankAccount b2 = new BankAccount("K", 0);
        b1.print(); // K balance=0.0

        System.out.println("transfer 1000 money from b1 to b2");
        b1.transfer(1000, b2);
        System.out.println("b1: " + b1); // b1: P balance=1010.0
        System.out.println("b2: " + b2); // b2: K balance=1010.0

        BankAccount c1 = new CheckingAccount("Checking1", 1000, 500);
        BankAccount c2 = new CheckingAccount("Checking2", 1000, 500);
        c1.withdraw(700); // CheckingAccount::withdraw Cannot be withdrawn due to overdraftLimit
        c2.withdraw(800); // CheckingAccount::withdraw Cannot be withdrawn due to overdraftLimit
        c1.print(); // CheckingAccount: Checking1 balance=1020.0
        c2.print(); // CheckingAccount: Checking1 balance=1020.0

        BankAccount s1 = new SavingAccount("Saving1", 1000);
        s1.deposit(5000);
        s1.withdraw(1000);
        s1.print(); // SavingAccount: Saving1 balance=5250.0

        BankAccount s2 = new SavingAccount("Saving2", 1000);
        s2.withdraw(2000); // SavingAccount::withdraw Amount is larger than current balance.
        s2.print(); // SavingAccount: Saving2 balance=1050.0
    }
}