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
    }
}

Midterm Exam

중간고사

시험범위: 처음부터 – 배운데까지 (강의노트, 실습, 수업블로그)
주요내용: 기본문법, exception, enum, array, method, parameter passing, class, instance vs static, private/public/protected/default, inheritance, dynamic binding, abstract class, polymorphism, method overloading vs method overriding
일시 및 장소: 2019년 4월 24일 (수) 오전 9:00 – 10:30 (2공 105호)

이전 중간고사 답안지

Lab4

java1-lab4

Lab4 프로젝트 디렉토리 안에 모든 파일(src/*.java & bin/*.class)와 보고서 (2~3장)를 넣고 Lab4_학번_이름.zip 압축한 후 e-learning(http://lms.dankook.ac.kr/index.jsp)으로 제출 (due by 4/16)

Lab4 OOP (class 활용)

수업블로그에 클래스 OOP 참고하여, 본인이 작성한 Lab3를 객체지향적인 프로그램으로 바꾼다.
각 도형의 면적(area)과 둘레(perimeter)를 계산하는 클래스를 작성한다.
그리고 본인이 원하는 도형 클래스를 하나 더 추가 작성한다.
보고서는 출력해서 수업시작 전에 제출한다.
보고서의 내용은 기존 코드 분석과 이해한 내용 그리고 본인이 추가한 코드내용을 적는다.