8. 다운 캐스팅과 instanceof
다운 캐스팅
- 업 캐스팅된 클래스를 다시 원래의 타입으로 형 변환
- 하위 클래스로 형 변환은 명시적으로 해야함
Customer vc = new VIPCustomer(); // 묵시적
VIPCustomer vCustomer = (VIPCustomer)vc; // 명시적
instanceof를 이용하여 인스턴스의 형 체크
- 원래 인스턴스의 형이 맞는지 여부를 체크하는 키워드가 맞으면 true 아니면 false 반환
AniamlTest.java
package ch08;
import java.util.ArrayList;
class Animal {
public void move() {
System.out.println("동물이 움직입니다.");
}
}
class Human extends Animal {
@Override
public void move() {
System.out.println("사람이 두 발로 걷습니다.");
}
public void readBook() {
System.out.println("사람이 책을 읽습니다.");
}
}
class Tiger extends Animal {
@Override
public void move() {
System.out.println("호랑이가 네 발로 뜁니다");
}
public void hunting() {
System.out.println("호랑이가 사냥을 합니다.");
}
}
class Eagle extends Animal {
@Override
public void move() {
System.out.println("독수리가 하늘을 납니다");
}
public void flying() {
System.out.println("독수리가 양 날개를 쭉 펴고 날아다닙니다");
}
}
public class AnimalTest {
public static void main(String[] args) {
Animal hAnimal = new Human();
Animal tAnimal = new Tiger();
Animal eAnimal = new Eagle();
AnimalTest test = new AnimalTest();
ArrayList<Animal> animalList = new ArrayList<>();
animalList.add(hAnimal);
animalList.add(tAnimal);
animalList.add(eAnimal);
for ( Animal animal : animalList ) {
animal.move();
}
test.testDownCasting(animalList);
}
public void testDownCasting(ArrayList<Animal> list) {
for(int i=0; i<list.size(); i++) {
Animal animal = list.get(i);
if ( animal instanceof Human ) {
Human human = (Human)animal;
human.readBook();
}
else if ( animal instanceof Tiger ) {
Tiger tiger = (Tiger)animal;
tiger.hunting();
}
else if ( animal instanceof Eagle ) {
Eagle eagle = (Eagle)animal;
eagle.flying();
} else {
System.out.println("unsupported type");
}
}
}
public void moveAnimal(Animal animal) {
animal.move();
}
}
웬만하면 쓰지 않는게 좋다고 한다..~ 어렵네
9. 추상 클래스 ( abstract class ) 구현
추상 클래스란
- 구현 코드없이 메서드의 선언만 있는 추상 메서드를 포함한 클래스
- 메서드 선언 ( declaration ): 반환타입, 메서드 이름, 매개변수로 구성
- 메서드의 정의 ( defintion ) : 메서드 구현과 동일한 의미 구현부(body)를 가짐 {{ }}
- ex) int add(int x, int y); //선언
int add(int x, int y){} // 구현부가 있음, 추상 메서드 X - abstract 예약어를 사용
- 추상 클래스는 new를 할 수 없음 ( 인스턴스화 불가 )
추상 클래스 구현하기
- 메서드에 구현 코드가 없으면 abstract로 선언
- abstract로 선언된 메서드를 가진 클래스는 abstract로 선언
- 모든 메서드가 구현 된 클래스라도 abstract로 선언되면 추상 클래스로 인스턴스화 할 수 없음
- 추상 클래스의 추상 메서드는 하위 클래스가 상속하여 구현
- 추상 클래스 내의 추상 메서드 : 하위 클래스가 구현해야 하는 메서드
- 추상 클래스 내의 구현 된 메서드 : 하위 클래스가 공통으로 사용하는 메서드 (필요에 따라 하위 클래스에서 재정의 함)
Computer.java
public abstract class Computer {
// 상속받는 하위 클래스가 알아서 기능을 구현해라.
public abstract void display();
public abstract void typing();
// 공통으로 사용할 메서드는 구현
void turnOn() {
System.out.println("전원을 켭니다");
};
void turnOff() {
System.out.println("전원을 끕니다");
}
}
DeskTop.java
public class DeskTop extends Computer {
@Override
public void display() {
System.out.println("DeskTop Display");
}
@Override
public void typing() {
System.out.println("DeskTop Typing");
}
@Override
void turnOff() {
System.out.println("DeskTop turnOff");
}
}
NoteBook.java
public abstract class NoteBook extends Computer {
@Override
public void display() {
System.out.println("NoteBook Display");
}
}
MyNoteBook.java
public class MyNoteBook extends NoteBook {
@Override
public void typing() {
System.out.println("MyNoteBook typing");
}
}
ComputerTest.java
public class ComputerTest {
public static void main(String[] args) {
Computer desktop = new DeskTop();
desktop.display();
desktop.typing();
desktop.turnOn();
desktop.turnOff();
}
}
10. 추상 클래스의 응용 - 템플릿 메서드 패턴
템플릿 메서드
- 추상 메서드나 구현된 메서드를 활용하여 코드의 흐름을 정의하는 메서드
- final로 선언하여 하위 클래스에서 재정의를 할 수 없게 함
- 프레임워크에서 많이 사용되는 설계 패턴
- 추상 클래스로 선언된 상위 클래스에서 템플릿 메서드를 활용하여 전체적인 흐름을 정의하고 하위 클래스에서
다르게 구현되어야하는 부분은 추상 메서드로 선언하여 하위 클래스에서 구현 하도록 함
템플릿 메서드 예제
Car.java
public abstract class Car {
public abstract void drive();
public abstract void stop();
public void startCar() {
System.out.println("시동을 켭니다.");
}
public void turnOff() {
System.out.println("시동을 끕니다.");
}
final public void run() {
startCar();
drive();
stop();
turnOff();
}
}
AiCar.java
public class AiCar extends Car{
@Override
public void drive() {
System.out.println("자율 주행을 합니다.");
System.out.println("자동차가 스스로 방향을 바꿉니다.");
}
@Override
public void stop() {
System.out.println("장애물 앞에서 스스로 멈춥니다.");
}
}
ManualCar.java
public class ManualCar extends Car{
@Override
public void drive() {
System.out.println("사람이 운전을 합니다.");
System.out.println("사람이 핸들을 조작합니다.");
}
@Override
public void stop() {
System.out.println("장애물 앞에서 브레이크를 조작합니다.");
}
}
CarTest.java
public class CarTest {
public static void main(String[] args) {
Car aiCar = new AiCar();
aiCar.run();
System.out.println("===================");
Car mCar = new ManualCar();
mCar.run();
}
}
final 예약어
- final 변수 : 값이 변경될 수 없는 상수
public static final double PI = 3.14; - final 메서드 : 하위 클래스에서 재정의 할 수 없는 메서드
- final 클래스 : 상속할 수 없는 클래스
11. 인터페이스 ( interface )
인터페이스란?
- 모든 메서드가 추상 메서드로 선언됨 public abstract
- 모든 변수는 상수로 선언됨 public static final
interface 인터페이스 이름{
public static final float pi = 3.14;
public void makeSomthing();
}
- 자바8부터 디폴트 메서드(defalut method)와 정적 메서드(static method)기능의 제공으로 일부 구현 코드가 있다
인터페이스 정의와 구현
Calc.java
public interface Calc {
double PI = 3.14;
int ERROR = -999999999;
int add(int num1, int num2);
int substract(int num1, int num2);
int times(int num1, int num2);
int divide(int num1, int num2);
}
Calculator.java
public abstract class Calculator implements Calc {
@Override
public int add(int num1, int num2) {
return num1 + num2;
}
@Override
public int substract(int num1, int num2) {
return num1 - num2;
}
}
ComplaeteCalc.java
public class CompleteCalc extends Calculator{
@Override
public int times(int num1, int num2) {
return num1 * num2;
}
@Override
public int divide(int num1, int num2) {
if(num2 == 0)
return ERROR;
return num1/num2;
}
public void showInfo() {
System.out.println("모두 구현했습니다.");
}
}
CalculaterTest.java
public class CalculaterTest {
public static void main(String[] args) {
int num1 = 10;
int num2 = 2;
Calc calc = new CompleteCalc();
System.out.println(calc.add(num1, num2));
System.out.println(calc.substract(num1, num2));
System.out.println(calc.times(num1, num2));
System.out.println(calc.divide(num1, num2));
}
}
인터페이스 구현과 형 변환
- 인터페이스를 구현한 클래스는 인터페이스 형으로 선언한 변수로 형 변환이 가능함
Calc calc = new CompleteCalc(); - 상속에서의 형 변환과 동일한 의미
- 클래스 상속과 달리 구현 코드가 없으므로 여러 인터페이스를 구현할 수 있음 ( cf.extends )
- 형 변환되는 경우 인터페이스에 선언된 메서드만을 사용이 가능하다
12. 인터페이스가 쓰이는 이유
인터페이스가 하는 일
- 클래스나 프로그램이 제공하는 기능을 명시적으로 선언
- 일종의 클라이언트 코드와 약속이며 클래스나 프로그램이 제공하는 명세(sepcification)
- 클라이언트 프로그램은 인터페이스에 선언된 메서드 명세만 보고 이를 구현한 클래스를 사용할 수 있음
- 어떤 객체가 하나의 인터페이스 타입이라는 것은 그 인터페이스가 제공하는 모든 메서드를 구현했다는 의미임
- 인터페이스를 구현한 다양한 객체를 사용함 - 다형성
- ex) JDBC 인터페이스
13. 인터페이스를 활용한 다형성 구현 ( DAO 구현 )
인터페이스와 다형성
- 하나의 인터페이스를 여러객체가 구현하게 되면 클라이언트 프로그램은 인터페이스의 메서드를 활용하여 여러객체의 구현을 사용할 수 있음
- 여러가지 예
인터페이스를 활용한 DAO 구현
- DB에 회원 정보를 넣는 DAO(Data Access Object)를 여러 DB 제품이 지원될 수 있게 구현
- 환경파일(db.properties)에서 database의 종류에 대한 정보를 읽고
그 정보에 맞게 dao 인스턴스를 생성하여 실행될 수 있게 함
Userinfo.java
package ch13.domain.userinfo;
public class UserInfo {
private String userId;
private String password;
private String userName;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
mysql.UserInfo.java
package ch13.domain.userinfo.dao.mysql;
import ch13.domain.userinfo.UserInfo;
import ch13.domain.userinfo.dao.UserInfoDao;
public class UserInfoMysqlDao implements UserInfoDao {
@Override
public void insertUserInfo(UserInfo userInfo) {
System.out.println("Insert into Mysql DB userID = " + userInfo.getUserId());
}
@Override
public void updateUserInfo(UserInfo userInfo) {
System.out.println("Update into Mysql DB userID = " + userInfo.getUserId());
}
@Override
public void deleteUserInfo(UserInfo userInfo) {
System.out.println("Delete from Mysql DB userID = " + userInfo.getUserId());
}
}
oracle.UserInfo.java
package ch13.domain.userinfo.dao.oracle;
import ch13.domain.userinfo.UserInfo;
import ch13.domain.userinfo.dao.UserInfoDao;
public class UserInfoOracleDao implements UserInfoDao{
@Override
public void insertUserInfo(UserInfo userInfo) {
System.out.println("Insert into Oracle DB userID = " + userInfo.getUserId());
}
@Override
public void updateUserInfo(UserInfo userInfo) {
System.out.println("Update into Oracle DB userID = " + userInfo.getUserId());
}
@Override
public void deleteUserInfo(UserInfo userInfo) {
System.out.println("Delete from Oracle DB userID = " + userInfo.getUserId());
}
}
UserInfoDao.java
package ch13.domain.userinfo.dao;
import ch13.domain.userinfo.UserInfo;
public interface UserInfoDao {
void insertUserInfo(UserInfo userInfo);
void updateUserInfo(UserInfo userInfo);
void deleteUserInfo(UserInfo userInfo);
}
UserInfoClient.java
package ch13.web.userInfo;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import ch13.domain.userinfo.UserInfo;
import ch13.domain.userinfo.dao.UserInfoDao;
import ch13.domain.userinfo.dao.mysql.UserInfoMysqlDao;
import ch13.domain.userinfo.dao.oracle.UserInfoOracleDao;
public class UserInfoClient {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("db.properties");
Properties prop = new Properties();
prop.load(fis);
String dbType = prop.getProperty("DBTYPE");
UserInfo userInfo = new UserInfo();
userInfo.setUserId("12345");
UserInfoDao userInfoDao = null;
if( dbType.equals("ORACLE")) {
userInfoDao = new UserInfoOracleDao();
} else if( dbType.equals("MYSQL")) {
userInfoDao = new UserInfoMysqlDao();
} else {
System.out.println("db error");
return;
}
userInfoDao.insertUserInfo(userInfo);
userInfoDao.updateUserInfo(userInfo);
userInfoDao.deleteUserInfo(userInfo);
}
}
14. 인터페이스의 여러가지 요소
상수
- 모든 변수는 상수로 변환됨 public static final
double PI = 3.14;
int ERROR = -99999999999;
추상 메서드
- 모든 선언된 메서드는 추상 메서드 public abstract
디폴트 메서드 ( 자바8 이후 )
- 구현을 가지는 메서드, 인터페이스를 구현하는 클래스들이 공통으로 사용할 수 있는 기본 메서드
- default 키워드 사용
defalut void description(){
System.out.println("정수 계산기를 구현합니다.");
myMethod();
}
- 구현하는 클래스에서 재정의 할 수 있음
@Override
public void description(){
Sytsem.out.println("ComplteCalc에서 재정의한 default 메서드");
//super.description();
}
- 인터페이스를 구현한 클래스의 인스턴스가 생성 되어야 사용 가능함
정적 메서드 ( 자바8 이후 )
- 인스턴스 생성과 상관 없이 인터페이스 타입으로 사용할 수 있는 메서드
static int total(int[] arr) {
int total = 0;
for(int i: arr) {
total += i;
}
mystaticMethod();
return total;
}
private 메서드 ( 자바9 이후 )
- 인터페이스를 구현한 클래스에서 사용하거나 재정의 할 수 없음
- 인터페이스 내부에서만 사용하기위해 구현하는 메서드
- default나 static 메서드에서 사용 가능함
private void myMethod() {
System.out.println("private method");
}
private static void mystaticMethod() {
System.out.println("private static method");
}
15. 여러 인터페이스 구현하기, 인터페이스의 상속
여러 인터페이스 구현
- 자바의 인터페이스는 구현 코드가 없으므로 하나의 클래스가 여러 인터페이스는 구현할 수 있음
- 디폴트 메서드가 중복되는 경우는 구현하는 클래스에서 재정의 해야함
- 여러 인터페이스를 구현한 클래스는 인터페이스 타입으로 형 변환되는 경우
해당 인터페이스에서 선언된 메서드만 사용가능
Buy.java
public interface Buy {
void buy();
default void order() {
System.out.println("buy order");
}
}
Sell.java
public interface Sell {
void sell();
default void order() {
System.out.println("sell order");
}
}
Customer.java
public class Customer implements Buy, Sell {
@Override
public void sell() {
System.out.println("Customer sell");
}
@Override
public void buy() {
System.out.println("Customer buy");
}
@Override
public void order() {
System.out.println("customer order");
}
public void hello() {
System.out.println("Hello");
}
}
CustomerTest.java
public class CustomerTest {
public static void main(String[] args) {
Customer customer = new Customer();
customer.buy();
customer.sell();
customer.order();
customer.hello();
// 재정의
Buy buyer = customer;
buyer.buy();
buyer.order();
Sell seller = customer;
seller.sell();
seller.order();
}
}
인터페이스의 상속
- 인터페이스 사이에도 상속을 사용할 수 있음
- extends 키워드를 사용
- 인터페이스는 다중 상속이 가능하고 구현 코드의 상속이 아니므로 타입 상속이라고 함
X.java
public interface X {
void x();
}
Y.java
public interface Y {
void y();
}
MyClass.java
public class MyClass implements MyInterface {
@override
public void X {
System.out.println("x()");
}
@override
public void Y {
System.out.println("y()");
}
@override
public void myMethod {
System.out.println("myMetohd()");
}
}
MyClassTest.java
public class MyClassTset {
public static void main(String[] args) {
X xClass = mClass;
xClass.x();
Y yClass = mClass;
yClass.y();
MyClass iClass = mClass;
iClass.x();
iClass.y();
iClass.myMethod();
}
}
어떤 인터페이스 타입으로 선언되느냐에 따라 변수가 사용할 수 있는 메소드들은 한정이된다.
클래스 상속과 인터페이스 구현 함께 쓰기
- 실무에서 프레임워크나 오픈소스와 함께 연동되는 구현을 하게되면 클래스 상속과
인터페이스의 구현을 같이 사용하는 경우가 많다
- 책이 순서대로 대여가 되는 도서관 구현
- 책을 보관하는 자료 구조가 Shelf에 구현됨 ( ArrayList)
- Queue 인터페이스를 구현함
- Shelf 클래스를 상속 받고 Queue를 구현
Shelf.java
import java.util.ArrayList;
public class Shelf {
protected ArrayList<String> shelf;
public Shelf() {
shelf = new ArrayList<String>();
}
public ArrayList<String> getShelf() {
return shelf;
}
public int getCount() {
return shelf.size();
}
}
Queue.java
public interface Queue {
void enQueue(String title);
String deQueue();
int getSize();
}
BookShelf.java
public class BookShelf extends Shelf implements Queue {
@Override
public void enQueue(String title) {
shelf.add(title);
}
@Override
public String deQueue() {
return shelf.remove(0);
}
@Override
public int getSize() {
return getCount();
}
}
BookShelfTest.java
public class BookShelfTest {
public static void main(String[] args) {
Queue bookQueue = new BookShelf();
bookQueue.enQueue("토지1");
bookQueue.enQueue("토지2");
bookQueue.enQueue("토지3");
bookQueue.enQueue("토지4");
bookQueue.enQueue("토지5");
System.out.println(bookQueue.getSize());
System.out.println(bookQueue.deQueue());
System.out.println(bookQueue.deQueue());
System.out.println(bookQueue.deQueue());
System.out.println(bookQueue.deQueue());
System.out.println(bookQueue.deQueue());
}
}
16. 복습
예제1 추상 클래스와 템플릿 메서드
Player가 있고 Player는 GameLevel 속성을 가집니다. 각 GameLevel 단계 마다 run(), jump(), turn() 세 가지 기능이 업그레이드 됩니다.
초보자 레벨 : 천천히 달립니다. run() 만 가능
중급자 레벨 : 빠르게 달리고, 점프할 수 있습니다. run(), jump() 가능
고급자 레벨 : 엄청 빠르게 달리고, 높게 점프하고, 턴할 수 있습니다. run(), jump(), turn() 가능
Player는 한번에 하나의 레벨 상태만을 가질 수 있습니다.
Player가 play() 중에 레벨에 있는 go(int count) 라는 메서드를 호출하면 run() 하고 count 횟수 만큼 jump() 하고 turn() 합니다. 다음 클래스 다이어그램을 참고하여 각 레벨에서 go() 가 호출 될때 다음과 같이 출력 되도록 하세요
PlayerLevel.java
public abstract class PlayerLevel {
public abstract void run();
public abstract void jump();
public abstract void turn();
public abstract void showLevelMessage();
public void go(int count) {
run();
for(int i=0; i<count; i++) {
jump();
}
turn();
}
}
BeginerLevel.java
public class BeginnerLevel extends PlayerLevel {
@Override
public void run() {
System.out.println("천천히 달립니다.");
}
@Override
public void jump() {
System.out.println("초보자는 점프를 할 수 없습니다.");
}
@Override
public void turn() {
System.out.println("초보자는 턴을 할 수 없습니다.");
}
@Override
public void showLevelMessage() {
System.out.println("======== 초급자 레벨 입니다. =========");
}
}
AdvancedLevel.java
public class AdvancedLevel extends PlayerLevel{
@Override
public void run() {
System.out.println("빨리 달립니다.");
}
@Override
public void jump() {
System.out.println("중급자는 높이 점프합니다.");
}
@Override
public void turn() {
System.out.println("중급자는 턴을 할 수 없습니다.");
}
@Override
public void showLevelMessage() {
System.out.println("======== 중급자 레벨 입니다. =========");
}
}
SuperLevel.java
public class SuperLevel extends PlayerLevel {
@Override
public void run() {
System.out.println("아주 빨리 달립니다.");
}
@Override
public void jump() {
System.out.println("고급자는 아주 높이 점프합니다.");
}
@Override
public void turn() {
System.out.println("턴을 할 합니다.");
}
@Override
public void showLevelMessage() {
System.out.println("======== 고급자 레벨 입니다. =========");
}
}
Player.java
public class Player {
private PlayerLevel level;
public Player() {
level = new BeginnerLevel();
level.showLevelMessage();
}
public PlayerLevel getLevel() {
return level;
}
public void upgradeLevel( PlayerLevel level ) {
this.level = level;
level.showLevelMessage();
}
public void play(int count) {
level.go(count);
}
}
Main.java
public class Main {
public static void main(String[] args) {
Player player = new Player();
player.play(1);
AdvancedLevel aLevel = new AdvancedLevel();
player.upgradeLevel(aLevel);
player.play(1);
SuperLevel sLevel = new SuperLevel();
player.upgradeLevel(sLevel);
player.play(1);
}
}
예제2 인터페이스를 활용한 정책 프로그래밍
고객 센터에 전화 상담을 하는 상담원들이 있습니다. 일단 고객에게서 전화가 오면 대기열에 저장되고 각 상담원에게 배분이 됩니다.
배분이 되는 정책은 크게 세 가지가 있습니다.
1. 모든 상담원이 동일한 상담 건수를 처리하도록 상담원 순서대로 배분합니다.
2. 쉬고 있거나 상담원에게 할당된 통화 수가 가장 적은 상담원에게 배분합니다.
3. 고객의 등급에 따라 등급이 높은 고객은 업무능력이 우수한 상담원에게 배분합니다.
세 가지 정책은 필요에 따라 바뀌어 운영될 수 있습니다. 다음 클래스 다이어그램을 참고하여 각 배분 규칙이 적용되도록 구현해 보세요
Main.java
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
System.out.println("전화 상담원 할당 방식을 선택하세요");
System.out.println("R: 한명씩 차례대로");
System.out.println("L: 대기가 적은 상담원 우선");
System.out.println("P: 우선순위가 높은 고객우선 숙련도 높은 상담원");
int ch = System.in.read();
Scheduler scheduler = null;
if ( ch == 'R' || ch == 'r') {
scheduler = new RoundRobin();
}
else if ( ch == 'L' || ch == 'l' ) {
scheduler = new LeastJob();
}
else if ( ch == 'P' || ch == 'p' ) {
scheduler = new PriorityAllocation();
} else {
System.out.println("지원하지 않는 기능입니다.");
return;
}
scheduler.getNextCall();
scheduler.sendCallToAgent();
}
}
Scheduler.java
public interface Scheduler {
public void getNextCall();
public void sendCallToAgent();
// 자바가 시키는대로 했는데 이렇게도 됨..
//public default void getNextCall() {}
//public default void sendCallToAgent() {}
}
LeastJob.java
public class LeastJob implements Scheduler {
@Override
public void getNextCall() {
System.out.println("상담 전화를 순서대로 대기열에서 가져옵니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("다음 순서의 상담원에게 배분합니다.");
}
}
RoundRobin.java
public class RoundRobin implements Scheduler {
@Override
public void getNextCall() {
System.out.println("상담 전화를 순서대로 대기열에서 가져옵니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("다음 순서의 상담원에게 배분합니다.");
}
}
PrioriryAllocation.java
public class PriorityAllocation implements Scheduler {
@Override
public void getNextCall() {
System.out.println("상담 전화를 순서대로 대기열에서 가져옵니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("다음 순서의 상담원에게 배분합니다.");
}
}
Test 코드가 있어서 이클립스가 시키는대로 만들어 봤는데 .. 잘 됐다
정답이랑 다른부분이 있어서 왜인지 다시 생각해보는 시간을 가짐.
복습을 많이 해야겠다 ㅠ
'Java' 카테고리의 다른 글
자바와 자료구조 / 배열, 스택, 큐 (0) | 2022.11.29 |
---|---|
자바의 유용한 클래스 / Object, String, StringBuilder, StringBuffer, textblock, Class 클래스 (0) | 2022.11.22 |
Java 객체 지향 핵심 / 상속, 형 변환, 재정의(override), 다형성 (0) | 2022.11.17 |
Java 객체지향 입문 / 배열, 객체 배열, 2차원 배열, ArrayList (0) | 2022.11.16 |
Java 객체지향 입문 / static 변수, static 매서드, singleton 패턴 (0) | 2022.11.16 |