우선 큐에 대해 학습하기 전에 자바의 클래스와 친숙해 지고자 중첩 클래스에 대해 알아보겠다
1. 중첩 클래스는 왜 쓰는가?
- 클래스들의 논리적인 그룹을 나타낼 때 쓴다. 주로 model 객체에서 상위모델과 하위모델이 있을 떄 쓰는거 같다. (Static Nested Class를 많이 씀)
- 향상된 캡슐화
- 좋은 가독성과 유지 보수성
2. 중첩 클래스의 종류
3. 내부 클래스 (Inner Class)
- 내부클래스로서 일반클래스 내부에 생성된다. Non-Static Nested Class라고도 불린다.
- 밖에 있는 클래스는 내부클래스를 멤버변수처럼 사용할 수 있다. 사용하려면 new로 인스턴스를 만들어야 한다.
- 내부클래스는 자신의 밖에 있는 클래스의 자원을 직접 사용할 수 있다.
모양새
// src$Outer.java
public class Outer {
int outerAge;
String outerName;
Outer(int age, String name) {
this.outerAge = age;
this.outerName = name;
}
public class Inner {
int innerAge;
String innerName;
Inner(int age, String name) {
this.innerAge = age;
this.innerName = name;
}
}
}
객체 생성
// src/main.java
public class main {
// mainMethod
public static void main(String[] args) {
Outer outer = new Outer(20, "Hyunseo");
Outer.Inner inner = outer.new Inner(21, "Hyunseo2");
System.out.println("outer_age >> " + outer.outerAge);
System.out.println("outer_name >> " + outer.outerName);
System.out.println("Inner_age >> " + inner.innerAge);
System.out.println("Inner_name >> " + inner.innerName);
}
}
// outer_age >> 20
// outer_name >> Hyunseo
// Inner_age >> 21
// Inner_name >> Hyunseo2
클래스 파일 생성
컴파일 하면 각각 아래와 같이 생긴다\
- Outer.class
- Outer$Inner.class
4. 정적 중첩클래스 (Static Nested Class)
- 위의 내부클래스와 비슷하나, static으로 선언한다. 정확히는 Static Nested Class라고 한다.
- 밖에 있는 클래스의 변수와 메소드 중에 static이 붙은 것들은 사용할 수 있다
내부클래스와 차이
- 내부클래스는 밖에 있는 클래스의 자원을 마음대로 사용할 수 있지만, 중첩클래스는 static 키워드가 안붙었다면 사용할 수 없다.
- Outer클래스의 객체가 없어도 Inner클래스의 객체 생성이 가능하다.
모양새
// Static Nested Class
// src/Outer.java
public class Outer {
static int outerAge;
static String outerName;
// innerClass
public static class Inner {
int innerAge;
String innerName;
Inner(int age, String name){
this.innerAge = age;
this.innerName = name;
}
}
Outer(int age, String name) {
this.outerAge = age;
this.outerName = name;
}
}
객체 생성
// src/Main.java
public class main {
public static void main(String[] args) {
Outer outer = new Outer(20, "Hyunseo");
Outer.Inner inner = new Outer.Inner(21, "Hyunseo2");
System.out.println("outer_age >> " + outer.outerAge);
System.out.println("outer_name >> " + outer.outerName);
System.out.println("Inner_age >> " + inner.innerAge);
System.out.println("Inner_name >> " + inner.innerName);
}
}
// outer_age >> 20
// outer_name >> Hyunseo
// Inner_age >> 21
// Inner_name >> Hyunseo2
클래스 파일 생성
컴파일 하면 각각 아래와 같이 생긴다\
- Outer.class
- Outer$Inner.class
5. 지역 클래스(Method Local Inner Class)
- 메소드 내부에 클래스를 정의하는 경우이다. 마치 메소드 내의 지역변수처럼 쓰인다
- 메소드 내부에서 new 한 뒤 사용해야 한다. 메소드 밖에서 사용할 수 없다.(지역변수 룰)
// src/Outer.java
public class Outer {
// field
static int outerAge;
static String outerName;
// method
public void outerMethod() {
// Method Local Inner CLass
class Inner {
int innerAge;
String innerName;
Inner(int age, String name){
this.innerAge = age;
this.innerName = name;
}
}
Inner inner = new Inner(20, "Hyunseo");
System.out.println("inner_age >> " + inner.innerAge);
System.out.println("inner_name >> " + inner.innerName);
}
// constructor
Outer(int age, String name) {
this.outerAge = age;
this.outerName = name;
}
}
객체 생성
// src/main.java
public class main {
public static void main(String[] args) {
Outer outer = new Outer(20, "Hyunseo");
outer.outerMethod();
}
}
// inner_age >> 20
// inner_name >> Hyunseo
클래스 파일 생성
컴파일 하면 각각 아래와 같이 생긴다\
- Outer.class
- Outer$숫자Inner.class
6. 익명 클래스(Anonymous Inner class)
- 익명클래스는 인스턴스 이름이 없다. new와 동시에 부모클래스를 상속받아 내부에서 오버라이딩 해서 사용한다.
- 매개변수로 사용할 수도 있다.
- 익명 클래스 내부의 변수나 메소드는 익명클래스의 밖에서 사용이 불가능하다.
- 주로 익명클래스는 이럴때 사용 : 상속은 받아야하지만, 한번만 사용할 것이라서 extends 문법을 굳이 사용안함
- 익명클래스 내부에 생성자 x
- 익명클래스 외부의 자원은 final키워드가 붙은 것만 사용할 수 있다
- 아래 모양새에서 보듯이 Inner클래스가 이미 선언되어있어야만 한다. Inner 클래스를 바로 상속받고 오버라이딩 해서 쓰는 구조이다.
Class Inner {
변수;
메소드;
}
class Outer {
변수;
메소드1;
메소드2() {
지역변수;
new Inner() {
override된 내용들..
}
}
}
클래스 파일 생성
컴파일 하면 각각 아래와 같이 생긴다\
- Outer.class
- Outer$숫자.class
7. Queue
알아둘 용어
- Enqueue: 큐에 데이터를 넣는 기능
- Dequeue: 큐에서 데이터를 꺼내는 기능
- Visualgo 사이트에서 시연해보며 이해하기 (enqueue/dequeue 만 클릭해보며): https://visualgo.net/en/list
VisuAlgo - Linked List (Single, Doubly), Stack, Queue, Deque
VisuAlgo is free of charge for Computer Science community on earth. If you like VisuAlgo, the only payment that we ask of you is for you to tell the existence of VisuAlgo to other Computer Science students/instructors that you know =) via Facebook, Twitter
visualgo.net
저버애서 큐는 LinkedList를 활용하여 생성해야 한다. 그렇기에 Queue와 LinkedList가 다 import되어 있어야 한다
<참고 - Java Interface>
- 인터페이스란? 극단적으로 동일한 목적 하에 동일한 기능을 보장하게 하기 위함
- 자바의 다형성을 이용하여 개발코드 수정을 줄이고 유지보수성을 높인다.
public interface 인터페이스명 {
// 상수
타입 상수명 = 값;
// 추상 메소드
타입 메소드명(매개변수, ...);
// 디폴트 메소드
default 타입 메소드명(매개변수, ...) {
// 구현부
}
// 정적 메소드
static 타입 메소드명(매개변수) {
// 구현부
}
}
상수 : 인터페이스에서 값을 정해줄테니 함부로 바꾸지 말고 제공해주는 값만 참조해라. (절대적)
추상메소드 : 가이드만 줄테니 추상메소드를 오버라이딩해서 재구현해라. (강제적)
디폴트메소드 : 인터페이스에서 기본적으로 제공해주지만, 맘에 안들면 각자 구현해서 써라. (선택적)
정적메소드 : 인터페이스에서 제공해주는 것으로 무조건 사용해라. (절대적)
<Interface 관련 예제>
// src/comp.company/Bank/Bank.java
// Bank Interface
package com.company.Bank;
public interface Bank {
// 상수 (최대 고객에게 인출해 줄 수 있는 금액 명시)
public int MAX_INTEGER = 1000000;
// 추상메소드 (인출하는 메소드)
void withDraw(int price);
// 추상메소드 (입금하는 메소드)
void deposit(int price);
// 고객의 휴면계좌 찾아주는 메소드 : 선택사항
default String findDormancyAccount(String cusId) {
System.out.println("**금융개정법안 00이후 고객의 휴면계좌 찾아주기 운동**");
System.out.println("**금융결제원에서 제공하는 로직**");
return "00은행 000-0000-0000-00";
}
// 블록체인 인증을 요청하는 메소드
static void BCAuth(String bankName) {
System.out.println(bankName + " 에서 블록체인 인증을 요청합니다.");
System.out.println("전 금융사 공통 블록체인 로직 수행;");
}
}
Bank 구현부
// src/com.company/Bank/KBBank.java
// implement Bank.java
package com.company.Bank;
public class KBBank implements Bank{
@Override
public void withDraw(int price) {
System.out.println("KB은행만의 인출 로직...");
if(price < Bank.MAX_INTEGER) {
System.out.println(price+ " 원을 인출한다.");
} else {
System.out.println(price + " 원을 인출실패.");
}
}
@Override
public void deposit(int price) {
System.out.println("KB은행만의 입금 로직..." + price + " 원을 입금한다.");
}
}
r
// src/com.company/Bank/SHBank
// implement Bank.java
package com.company.Bank;
public class SHBank implements Bank{
@Override
public void withDraw(int price) {
System.out.println("SH은행만의 인출 로직...");
if(price < Bank.MAX_INTEGER) {
System.out.println(price+ " 원을 인출한다.");
} else {
System.out.println(price + " 원을 인출실패.");
}
}
@Override
public void deposit(int price) {
System.out.println("SH은행만의 입금 로직..." + price + " 원을 입금한다.");
System.out.println("SH은행은 별도의 후행처리 작업을 따로 한다.");
}
@Override
public String findDormancyAccount(String cusId) {
System.out.println("**금융개정법안 00이후 고객의 휴면계좌 찾아주기 운동**");
System.out.println("*SH금융결제원에서 제공하는 로직**");
return "00은행 000-0000-0000-00";
}
}
Main 부분
// src/com.company/Main.java
package com.company;
import com.company.Bank.Bank;
import com.company.Bank.KBBank;
import com.company.Bank.SHBank;
public class Main {
public static void main(String[] args) {
Bank bank = new KBBank();
bank.withDraw(100);
bank.deposit(100);
bank.findDormancyAccount("763231");
Bank.BCAuth("KBBANK");
System.out.println("\n*****************인스턴스 교체!!******************");
bank = new SHBank();
bank.withDraw(100);
bank.deposit(100);
bank.findDormancyAccount("763231");
Bank.BCAuth("KBBANK");
}
}
// KB은행만의 인출 로직...
// 100 원을 인출한다.
// KB은행만의 입금 로직...100 원을 입금한다.
// **금융개정법안 00이후 고객의 휴면계좌 찾아주기 운동**
// **금융결제원에서 제공하는 로직**
// KBBANK 에서 블록체인 인증을 요청합니다.
// 전 금융사 공통 블록체인 로직 수행;
// *****************인스턴스 교체!!******************
// SH은행만의 인출 로직...
// 100 원을 인출한다.
// SH은행만의 입금 로직...100 원을 입금한다.
// SH은행은 별도의 후행처리 작업을 따로 한다.
// **금융개정법안 00이후 고객의 휴면계좌 찾아주기 운동**
// *SH금융결제원에서 제공하는 로직**
// KBBANK 에서 블록체인 인증을 요청합니다.
// 전 금융사 공통 블록체인 로직 수행;
// Queue 사용을 위해, LinkedList 클래스를 사용하므로, 두 클래스 모두 import 해야 함
import java.util.LinkedList;
import java.util.Queue;
// 자료형 매개변수를 넣어서, 큐에 들어갈 데이터의 타입을 지정해야 함
Queue<Integer> queue_int = new LinkedList<Integer>(); // Integer 형 queue 선언
Queue<String> queue_str = new LinkedList<String>(); // String 형 queue 선언
// 데이터 추가는 add(value) 또는 offer(value) 를 사용함
queue_int.add(1);
queue_int.offer(2);
// 출력에 true 라고 출력되는 부분은 offer() 메서드가 리턴한 값으로,
// 셀의 맨 마지막에 함수를 넣을 경우, 변수가 변수값이 출력되는 것처럼 함수는 함수 리턴값이 출력되는 것임
// Queue 인스턴스를 출력하면, 해당 큐에 들어 있는 아이템 리스트가 출력됨
System.out.println(queue_int)
// [1, 2]
// poll() 은 큐의 첫 번째 값 반환, 해당 값은 큐에서 삭제
queue_int.poll();
// poll() 과 마찬가지로, 첫 번째 값 반환하고, 해당 값은 큐에서 삭제
queue_int.remove()
어디에 큐가 많이 쓰일까?
- 멀티 태스킹을 위한 프로세스 스케쥴링 방식을 구현하기 위해 많이 사용됨 (운영체제 참조)
큐의 경우에는 장단점 보다는 (특별히 언급되는 장단점이 없음), 큐의 활용 예로 프로세스 스케쥴링 방식을 함께 이해해두는 것이 좋음
연습해보기
- JAVA ArrayList 클래스를 활용해서 큐를 다루는 enqueue, dequeue 기능 구현해보기
- dequeue 기능 호출 시, 큐에 데이터가 없을 경우, null 을 리턴하도록 함
- 다양한 데이터 타입을 다룰 수 있도록, Java Genric 타입 문법을 활용해보기
public class MyQueue<T> {
private ArrayList<T> queue = new ArrayList<T>();
public void enqueue(T item) {
queue.add(item);
}
public T dequeue() {
if (queue.isEmpty()) {
return null;
}
return queue.remove(0);
}
public boolean isEmpty() {
return queue.isEmpty();
}
public static void main(String[] args) {
MyQueue<Integer> mq = new MyQueue<Integer>();
mq.enqueue(1);
mq.enqueue(2);
mq.enqueue(3);
System.out.println(mq.dequeue());
System.out.println(mq.dequeue());
System.out.println(mq.dequeue());
}
}
MyQueue.main(new String[0]);
// 1
// 2
// 3
'Algorithm > Algorithm-Java' 카테고리의 다른 글
Java-자료구조 (Linked-List) (0) | 2021.11.17 |
---|---|
Java-자료구조 (Stack) (0) | 2021.11.17 |
Java-자료구조(Array) (0) | 2021.11.16 |
Java 를 Jupyter 환경에서 구축 (0) | 2021.11.15 |
Java 환경 준비 (0) | 2021.11.15 |