우선 큐에 대해 학습하기 전에 자바의 클래스와 친숙해 지고자 중첩 클래스에 대해 알아보겠다
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
저버애서 큐는 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 |