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

Lab5

Lab5 프로젝트 디렉토리 안에 모든 파일(src/*.java & bin/*.class)와 보고서 (3~4장)를 넣고 JAVA20_Lab5_분반_학번_이름.zip 압축한 후 제출

Lab5 inheritance/abstract class
java1-lab5-2 (revision)

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 메소드 호출가능
    }
}

singleton design pattern vs static class

공용 데이터를 저장하여 사용하고자 할 때, singleton design pattern이나 inner static class를 사용한다.

싱글톤 패턴 (Singleton design pattern) -싱글톤 패턴이란 single instance object(해당 클래스의 인스턴스 하나)가 만들어지고, 어디서든지 그 싱글톤에 접근할 수 있도록 하기 위한 패턴

public final class SiteStructureSingletonPattern {
    private Object[] data = new Object[10];

    private static SiteStructureSingletonPattern instance = new SiteStructureSingletonPattern(); // private static member인 instance
    public static SiteStructureSingletonPattern getInstance() { // getInstance() 메소드를 사용하여 instance 객체 사용
        return instance;
    }
    private SiteStructureSingletonPattern() {
        System.out.println("SiteStructureSingletonPattern constructor");
        for(int i=0; i<10; i++) {
            data[i] = i+1;
        }
    }
    public void print() {
        System.out.print("SiteStructureSingletonPattern data=");
        for(int i=0; i<10; i++) {
            System.out.print(" " + data[i]);
        }
        System.out.println();
    }
}
public class SiteStructureStaticClass {
    private Object[] data = new Object[10];

    private static class SiteStructureStatic { // inner static class
        private static final SiteStructureStaticClass instance = new SiteStructureStaticClass();
    }
    public static SiteStructureStaticClass getInstance() {
        return SiteStructureStatic.instance;
    }
    private SiteStructureStaticClass() {
        System.out.println("SiteStructureStaticClass constructor");
        for(int i=0; i<10; i++) {
            data[i] = i+1;
        }
    }

    public void print() {
        System.out.print("SiteStructureStaticClass data=");
        for(int i=0; i<10; i++) {
            System.out.print(" " + data[i]);
        }
        System.out.println();
    }
}
public class StaticClassSingletonPatternTest {

    public static void main(String[] args) {
        SiteStructureSingletonPattern instance = SiteStructureSingletonPattern.getInstance();
        instance.print();
        instance = SiteStructureSingletonPattern.getInstance();
        instance.print();

        SiteStructureStaticClass instance2 = SiteStructureStaticClass.getInstance();
        instance2.print();
        instance2 = SiteStructureStaticClass.getInstance();
        instance2.print();
    }
}

Constructor usage guideline

// private constructor는 정적 메소드와 필드 (static method & field)만 있는 경우 사용함.

class Counter {
    private Counter() { }
    public static int currentCount;
    public static int IncrementCount() { return ++currentCount; }
}

class TestCounter {
    public static void main(String[] args) {
        // If you uncomment the following statement, it will generate
        // an error because the constructor is inaccessible:
        //Counter aCounter = new Counter(); // Error
        Counter.currentCount = 100;
        Counter.IncrementCount();
        System.out.println("count=" + Counter.currentCount); // count=101
    }
}

 

// protected constructor는 추상클래스 (abstract class)에서 사용을 권고함. 추상 클래스를 상속받는 파생클래스에서 파생 클래스 생성자가 부모 클래스 즉, 추상 클래스를 초기화 하기 위해 추상 클래스 생성자를 호출 할 수 있도록 지원함.

public abstract class Shape {
    protected Shape(String name) { 
        this.name = name;
    }
    private String name;
    public void print() { System.out.print(this.name); }
}

public class Rectangle extends Shape {
    private double width, height;
    public Rectangle(String name) { 
        super(name); 
        this.width = 2; 
        this.height = 3; 
    }
    @Override
    public void print() {
        super.print();
        System.out.printf(" 가로: %f 세로: %f\n", this.width, this.height);
    }
}

public class Triangle extends Shape {
    private double bottom, height;
    public Triangle(String name) { 
        super(name); 
        this.bottom = 1; 
        this.height = 1; 
    }
    @Override
    public void print() {
        super.print();
        System.out.printf(" 밑변: %f 높이: %f\n", this.bottom, this.height);
    }
}

class ShapeTest {
    public static void main(String[] args) {
        //Shape s1 = new Shape("도형"); // Error; Shape is abstract; cannot be instantiated
        Shape s = new Triangle("삼각형");
        s.print(); // 삼각형 밑변: 1 높이: 1
        s = new Rectangle("직사각형");
        s.print(); // 직사각형 가로: 2 세로: 3
    }
}

BankAccount Instance Static

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

import java.util.*;
public class BankAccount {
    private int balance;
    private static int interestRate; // (%)

    public BankAccount() { 
        balance = 0; 
        interestRate = 5; 
    }

    public void deposit(int amount) { 
        balance += amount;
    }
   
    public void withdrawl(int amount) { 
        balance -= amount; 
    }

    public void print() { 
        System.out.println("final balance=" + 
	        (balance + balance * interestRate * 0.01) +
		" balance=" +
		balance +
		" interest=" +
		(balance * interestRate * 0.01));
		printInterestRate(); 
    }

    public static void setInterestRate(int interestRate) { 
        BankAccount.interestRate = interestRate; 
    }

    public static void printInterestRate() { 
        System.out.println("interestRate=" +
        interestRate); 
    }

    public int getUserInputInt() {
        Scanner input = new Scanner(System.in);
        System.out.print("Please enter Integer value: ");
        int value = input.nextInt();
        return value;
    }

    public static void main(String[] args) {
        BankAccount b = new BankAccount();
        b.deposit(2000);
        b.withdrawl(1000);
        b.print();
        BankAccount.printInterestRate();

        int amount = b.getUserInputInt();
        b.deposit(amount);
        b.print();
    }
}