반응형

[학습일지] Java & SpringBoot로 시작하는 웹 프로그래밍 : 자바 인강 7주차


 

7주차 학습내용

 

객체지향

디자인 패턴

 


객체지향

 

현실에 존재하는 물체를 모델링하기 위한 방법론이다.

절차 지향적인 프로그래밍 방법을 객체지향적인 프로그래밍 방법으로 발전시켰다.

 

물체를 객체로 정의하기 위해 해당 객체가 가지고 있는 특성을 분석하여

속성(변수)과 기능(메서드)으로 분리하여 모델링한다.

객체는 실체화된 개념일 수 있고, 추상적인 개념일 수도 있다.

 

상태 유지(속성)

객체는 해당 상태를 저장할 수 있어야 하고 그 상태를 유지해야 한다.

기능 제공(메서드)

객체는 다른 객체와 협력하기 위해 기능을 제공해야 한다.

고유 식별자

객체는 고유한 값을 갖고, 다른 객체와 식별될 수 있어야 한다.

 


 

객체지향의 4대 특성

 

캡슐화

객체의 상태인 속성은 기능을 통해 변경되어야 한다.

무의미한 값을 저장하지 않도록 무결성을 유지할 수 있다.

상속

객체를 구조화할 수 있다. 유지보수가 향상된다.

추상화

객체 간의 특성을 추출하여 추상화시킬 수 있다.

다형성

하나의 인스턴스가 여러 형태로 변화할 수 있다.

코드의 재사용성이 향상된다.

 


 

객체지향 설계의 5원칙(SOLID)

 

객체 간의 의존성은 낮추고, 책임지고 있는 기능에 집중해야 한다.

결합도는 낮추고, 응집도는 높인다.

 

단일 책임 원칙

하나의 객체가 여러 기능을 부담하지 않고, 객체가 하나의 기능에 집중하도록 분리해야 한다.

 

개방 폐쇄 원칙

변경되어야 하는 부분은 폐쇄적이어야 하고, 확장에는 개방되어야 한다.

인터페이스를 사용하면 손쉬운 확장이 가능하고, 클라이언트 코드의 변경도 없다.

 

리스 코프 치환 원칙

부모의 인스턴스가 사용되던 자리에 자식의 인스턴스가 사용된다면

기존의 부모 인스턴스가 갖고 있던 규칙을 자식이 위반하면 안된다. (오버라이딩시 위배가능성)

 

인터페이스 분리 원칙

인터페이스의 기능들을 하나의 인터페이스에 통합하지말고

인터페이스를 분리해서 구현체가 필요한 메서드를 가진 인터페이스만을 구현받도록 분리해야 한다.

 

의존 역전 원칙

의존 객체를 구체적인 구현체가 아닌 상위 추상적인 개념을 의존하게끔 설계해야한다.

 

 


디자인 패턴

 

싱글톤

 

 

생성자를 private로 만들어서 생성할 수 없게 한다.

싱글톤 패턴은 자기 자신을 속성으로 갖고 있다. getInstance 메서드를 통해 자기 자신인 속성을 가져온다.

getInstance가 static이므로 getInstance에서 이용해야 하는 자기 자신인 속성도 static으로 선언된다.

 


 

어댑터

 

 

관련이 없는 두 인터페이스를 중간에서 어댑터가 바꿔치기하여 연결시켜주는 디자인 패턴이다.

기존 인터페이스가 A이고, A 인터페이스를 사용하는 위주로 클라이언트 코드가 작성되었다고 할 때

B 인터페이스 새로 사용해야 한다면 B 인터페이스를 A 인터페이스로 중간에서 교체하는 어댑터를 만들어 줄 수 있다.

 

어댑터는 A 인터페이스를 구현하고, B 인터페이스를 속성으로 받아

A 인터페이스들의 메서드를 호출하면, A메서드를 오버라이딩해서 B 인터페이스 메서드를 대신해서 호출시켜주면 된다.

 


 

프록시

 

 

스프링 프레임워크에서 AOP로 프록시 패턴을 사용한다.

프록시가 인터페이스인 GameInterface를 구현하고, 실제 구현체인 GameService를 속성으로 갖는다.

 

클라이언트 코드에서 직접 GameService를 사용하지 않고 Proxy를 통해 사용한다.

Proxy는 GameService의 메서드를 호출을 하는데, 이때 앞과 뒤로 추가적인 작업이 가능해진다.

 


 

데코레이터

 

상속관계를 통해 super키워드를 이용하여 부모의 메서드를 호출하여

실행 결과를 반환받는 디자인 패턴이다.

 

호출은 (자식 -> 부모) 순으로 호출되며

실행은 (부모 -> 자식)으로 나오게 된다.

 

 


 

옵저버

 

 

변화가 일어날 때 등록해둔 옵저버(인스턴스)들에게 모두 알려주는 것이다.

옵저버를 등록시키고, 특정 함수가 동작할 때 옵저버의 기능이 동작하도록 한다.

 


 

파사드

 

클라이언트 코드가 복잡한 (여러 클래스)들의 기능을 일련의 과정으로 사용할 때

(클라이언트 코드)와 (여러 클래스) 사이에 (파사드 객체)를 두어

파사드 객체가 각 클래스들이 복잡하게 호출되는 일련의 과정을 메서드로 제공한다.

 

클라이언트 코드는 파사드 객체가 제공하는 간단한 메서드를 사용하게 하는 방식이다.

 


 

전략

 

가장 보편적으로 사용되는 패턴으로 

클라이언트 코드단에서 인터페이스를 구현한 구현체 부분을 전략으로 선택하여

선택한 전략 구현체를 사용하는 방법이다.

 

생성자를 인수를 인터페이스로 지정하여 내부 동작들은 인터페이스의 메서드를 사용하여구현체인 인스턴스의 메서드로 동작시키는 것

 

 


 

반응형
반응형

문자열 함수

 

문자열 함수에서 인자가 여러 개일 때 적용대상 @column 위치는 거의 맨 앞이다.

 

concat

select concat(@column, " ", @column) from books;

 

concat_ws

select concat("구분자", @column, @column) from books;

 

substr

substring

substring(@column, start, end) 앞 ~ 뒤 [모두 포함]

substring(@column, start) 앞부터 count

substring(@column, -start) 뒤부터 count

 

replace

replace(@column, "바뀌기 전 문자", "바뀐 후 문자")

 

reverse

reverse(@column)

 

char_length

char_length(@column)

 

upper

대문자로 변경

 

lower

소문자로 변경

 

LPAD

lpad(@column, 총길이, 채울 문자)

 

RPAD

rpad(@column, 총길이, 채울 문자)

 

Binary

binary(@column)  대소문자를 구분한다.

@sql 

where binary(name) like "%C%"

 

 


 

형 변환

cast(@column as type)

type - unsigned, signed, decimal, char, date, datetime

 


숫자 함수

 

ABS(숫자) : 절댓값

 

CEIL(숫자) : 값보다 큰 정수 중 가장 작은 정수 // 4.7 -> 5

FLOOR(숫자) : 값보다 작은 정수 중 가장 큰 정수 // 4.7 -> 4

ROUND(숫자, 자릿수) : 자릿수 기준 반올림 

TRUNCATE(숫자, 자릿수) : 자릿수 기준 버림

 

POW(X, Y)  : 제곱

SQRT(숫자) : 제곱근

MOD(분자, 분모) : 나머지

 

GREATEST(숫자1, 숫자2, ...) : 가장 큰 수

LEAST(숫자1, 숫자2, ...) : 가장 작은 수

 


날짜 함수

 

year(), month(), day(), hour(), minute(), second()

 

date(), time()

 

date_format(@column , '% H')

문자를 얻을 땐 % 대문자

숫자를 얻을 땐 % 소문자

 

date_diff(@column , INTERVAL 1 MONTH)

date_add(@column , INTERVAL 1 MONTH)

 

 

datetime +- INTERVAL expr unit

 

@sql

  • SELECT DATE_ADD(birthdt, INTERVAL 1 MONTH) FROM people
  • SELECT DATE_ADD(birthdt, INTERVAL 10 SECOND) FROM people;
  • SELECT DATE_ADD(birthdt, INTERVAL 3 QUARTER) FROM people;
  • SELECT birthday + INTERVAL 1 MONTH FROM people;
  • SELECT birthday - INTERVAL 5 MONTH FROM people;

 

https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-format

 

MySQL :: MySQL 8.0 Reference Manual :: 12.7 Date and Time Functions

12.7 Date and Time Functions This section describes the functions that can be used to manipulate temporal values. See Section 11.2, “Date and Time Data Types”, for a description of the range of values each date and time type has and the valid formats

dev.mysql.com

 

 

 


랭크

 

rank() over (order by @column [asc or desc]) // 중복, 순위 밀림 => 1, 1, 1, 4 ...

dense_rank() over (order by @column [asc or desc]) // 중복, 순위 밀리지 않음 => 1, 1, 1, 2, 2 ...

row_number() over (order by @column [asc or desc])  //  순서대로

select 절에서 만들어지기 때문에 Oracle rownum처럼 추가로 view로 만들어서 정렬할 필요가 없다.

 


문법

 

distinct 

중복 행 제거 (컬럼이 아닌, 행 전체 기준)

 

order by

[option] asc, desc 

 

limit

0부터 N까지 조회

특이한 점은 전체를 조회할 때 N을 큰 숫자로 지정함

ex) limit 0, 19221032181328091

 

like, not like

where @column like '% 문자%' // 모든 문자, % 자리에 어떠한 문자도 없어도 조회

where @column like '_문자' // 한 개, 숫자 자릿수도 가능

 

between

@column between 3 and 15 // 3 이상 15 이하

 

if(조건식, true일 경우, false일 경우)

 

ifnull(@column, null일 경우)

 


집계 group by

 

mysql5 -> mysql8 변경사항

 

 

select min(stock_quantity), title

from books

group by released_year;

min(stock_quantity)는 집계 함수인 반면

title은 집계 함수의 결과가 아니고, group by의 대상도 아니라서

여러 값이 존재해서 오류를 일으키거나, 임의의 값을 가져오게 된다.

 

 

select min(stock_quantity)title 

from books

group by title;

title이 group by의 대상이라서, 대표 값이 명확히 있기 때문에 가능하다.

 

 

group by 이후에 min(stock_quantitiy) 행을 보고자 할 때 서브 쿼리를 활용

select * 

from books 

where stock_quantity 

in  (select min(stock_quantity)

       from books

       group by released_year);

 

 

group by 

select집계 함수, group by 대상만 사용 가능

 

집계 함수

count(), min(), max(), avg(), sum()

집계함수는 중첩할 수 없다. max(count(@Column)) 불가능

 

 

null 값을 집계 함수에 포함시키려면 IFNULL, CASE를 사용하면 된다.

EX) SUM(IFNULL(<COLUMN>, 1)

 


분기문

 

if (조건식) then

     명령문

elseif (조건식) then

     명령문

else

     명령문

end if

 


 

case

      when (조건식) then 명령문

      when (조건식) then 명령문

      when (조건식) then 명령문

      else

end case

 


 

while(조건식) do

    명령문

end while

 

 

 


조인

 

join(기본 조인), inner join(내부 조인), equi join(동등 조인)은 전부 다 같다.

natural join - join을 수행한다. (단, 조인에 사용한 열은 한 번만 추출)

 

마찬가지로

left outer join과 left join의 차이는 없다.

 

명시하는 방법 때문에 종류가 많아 보이지만 사실 같은 것이 많다. 헷갈리지 말자.

 

조인 종류 

inner join

 

left join

right join

full outer join [mysql 에선 지원하지 않는다.]

 

self join

 

cross join

 


@sql

SELECT g1.pg, g1.af, b.title FROM
(select max(pages) as pg, author_fname as af
 from books group by author_fname) g1
JOIN books b
ON g1.pg = b.pages AND g1.af = b.author_fname;

 

  • from 부속 질의로 필요한 테이블을 만들고 조인하면 유용하다.
  • join 조건에 and를 사용하여 더 분명하게 join 해줄 수 있다.

 

ON table.col BETWEEN 10 AND 20

 

  • join 조건에 between으로 범위 조인도 가능하다.

 


 

UNION

관계없는 테이블을 합칠 수 있음

필드명(as 가능)과 데이터 타입이 같아야 함

중복 값은 기본적으로 제거되지만 필요한 경우 UNION ALL

 

@sql

(select city, char_length(city) from station order by char_length(city) asc, city asc limit 1)
union
(select city, char_length(city) from station order by char_length(city) desc, city asc limit 1);

 


부속 질의

 

select

scalar 부속 질의 (단일행, 단일열)

 

from

inline-view (가상의 테이블을 일시적 생성)

 

where

중첩 부속 질의 

단일 행 단일 열 - 비교 연산자

다중 행 단일 열 - all, any

다중 행 다중 열 - in, exists

 

 


 

단일 행 단일 열 

비교 연산자, select에서도 사용 가능한 scalar 부속 질의

 

다중 행 단일 열   ALL, ANY

any는 부속 질의의 결과가 하나라도 만족하면 true가 된다.

단일 열 이어야 한다.

 

다중 행 다중 열  IN, EXISTS

select * from students s 
join papers p 
on s.id = p.student_id 
where (p.grade, p.student_id) in ( (60, 1), (75, 1) );    # 괄호 필수

 

 

 

 

 

 

 

 

 

 

 

 


 

SQL 프로그래밍

 

delimiter를 변경해주는 이유는 선언 시에 세미콜론이 문장의 끝이 아님을 알려줘야 하므로 변경을 해준다.

 

변수 선언과 대입

set @변수명 = 대입값;

 

 

프로시저

프로시저를 create할 때는 종료 문자 delimiter 변경해주어야 한다.

프로시저 안에서 사용되는 변수 선언 declare 변수명 타입 [default n]

변수의 값 변경은 set

 

 

drop procedure if exists testProcedure;
delimiter $$
create procedure testProcedure(
    in num1 int,           // input
    in num2 int,
    out num3 int,       // output
    out num4 int

)
begin 

   declare num5 int default 5;    // 변수 선언

   set @num10 = 10;    // 변수 선언 대입


    set num3 = num1 + num2;        // 값 변경
    set num4 = num1 - num2;
end $$
delimiter ;

set @add = 0;
set @sub = 0;


call testProcedure(5, 10, @add, @sub);

 

 

 


 

함수

프로시저와의 차이점은 파라미터 in, out 이 없다. 입력만 가능하다.

return 에 반환 데이터 형식을 지정해야 한다.

함수 호출은 select 문장 안에서 호출한다.

함수 내부에서 select 사용이 불가능하다.

 

 


 

커서

 

# 프로시저 내부

 

declare EOR boolean default false;   // 행의 끝을 알릴 변수 

declare 커서명 cursor for (select sql)   // 커서 선언

declare CONTINUE HANDLER for not found set EOR = true;   // 더 읽을 행이 없을 때 동작할 명령어

 

open 커서명

 

cursor_loop  : loop

    fetch 커서명 into 저장할 변수 // 커서 선언 -> 결과 sql 칼럼 개수에 맞게 변수 설정

 

    if EOR then leave cursor_loop   // 더 읽을 행이 없으면 true

    end if

 

    set sum = sum + 결과 변수

end loop cursor_loop

 

close 커서명

 

 

mysql, rownum 만들기
select @rownum:= @rownum +1 as rownum, t.* 
from table1 t, (select @rownum := 0) r;

 

 


 

트리거

삽입, 삭제, 갱신이 일어나면 자동으로 작동되는 개체

삽입, 삭제, 갱신 이전 테이터를 저장 등을 할 수 있다.

after 트리거와 before 트리거 가 있다.

 

create trigger 트리거명 

    after DELETE // 삭제 이후

    on 테이블 // 트리거를 부착할 테이블

    for each row // 각 행마다 적용

begin

    동작할 명령어

end 

 

 

 


create view 뷰네임 as 쿼리

필요한 정보만 노출시켜 보안에 도움이 된다.

복잡한 쿼리를 뷰로 미리 생성해놓고 단순한 쿼리로 조회, 사용할 수 있다.

 

 


인덱스

 

검색 속도가 향상된다.

추가적인 공간이 10% 정도 필요하다.

변경 작업이 자주 발생할 경우 오히려 성능이 낮아진다.

 

 

클러스터드 인덱스 

테이블당 하나만 생성 가능

영어사전처럼 정렬을 인덱스에 맞춰서 해놓는다.

기본키를 지정하면 기본키 정렬에 맞게 클러스터드 인덱스가 자동 생성된다.

클러스터드 인덱스는 기본키에 unique not null 칼럼보다 우선 적용된다.

 

보조 인덱스 (비 클러스터드 인덱스와 비슷한 개념)

여러 개 생성 가능

책의 찾아보기처럼 별도로 존재한다.

칼럼을 unique null로 지정하면 보조 인덱스가 자동 생성된다.

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
반응형

[GOORM.IDE]

 

경로이동 : cd node_modules/mysql/sqls
mysql 실행 : mysql
sql file 실행 : source 파일명.sql

 

 

오류: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'

명령어 : sudo service mysql restart

 

 


[WORK BENCH]

 

reverse engineer / table -> erd

forward engineer / erd -> table

 

반응형
반응형

오류 모음

 

Caused by: java.sql.SQLException: Incorrect string value: ...
원인: 한글깨짐
CONFIG FILE characterEncoding=UTF-8 // database UTF-8

 

class file for jakarta.persistence.EntityManager not found
원인: implementation 'org.springframework.boot:spring-boot-starter-data-jpa:2.6.7를 해놓고
hibernate를 따로 implementation하여 생긴 오류

 

Value too long for column "WRITER CHARACTER VARYING(20)":
원인 1 : database varchar(길이) 보다 입력길이가 길어서 나는 오류
varchar길이를 늘린다.

원인 2 : 인코딩 설정이 잘못되서 문자를 길게 받아들이는 오류
application.property
server.servlet.encoding.charset=utf-8
server.servlet.encoding.force=true
추가

 

Neither BindingResult nor plain target object for bean name 'command' available as request attribute
원인: jsp form 태그 안에서 전달받은 model.addAttribute 를 못알아내고 기본 값인 command로 인식
contoller에서 model.addAttribute("name",new dto()) 라고 했다면 jsp form 태그 시작에 modelAttribute="name"를 지정해줘야한다

controller ### model.addAttribute("name", new dto());
jsp ### <form:form method="POST" action="/update" modelAttribute="name">

 

redirect에 path variable 추가시 한글이 깨지는 문제
https://ivvve.github.io/2019/01/20/java/Spring/redirect_URL_encoding/

 

 

 

 


 

반응형

' > 오류 모음' 카테고리의 다른 글

[DataBase] 오류  (0) 2022.06.29
[H2] 오류  (0) 2022.05.05
반응형

[학습일지] Java & SpringBoot로 시작하는 웹 프로그래밍 : 자바 인강 6주차


6주차 학습내용

 

자료구조

 

제네릭

 

컬렉션과 맵

 


자료구조

 

 

데이터를 효과적으로 저장하고 사용하기 위한 여러 가지 방법이 있다.

이러한 방법들을 정리한 것이 자료구조이며 데이터의 사용 방식에 따라 정의된다.

 

배열: 메모리 공간에 연속적으로 배치하여 관리한다. 물리적, 논리적 위치가 같으므로 접근이 빠르다.

연속적인 배치 구조로 내부가 변경된다면 요소들을 재배치하는 과정이 필요하므로 내부가 변경된다면 비효율적이다.

연결 리스트: 자료들을 연결된 형태로 배치한 것이다. 한쪽의 자료가 다른 쪽의 참조 위치를 알고 있다. 양쪽을 연결할 수도 있다.

배열과는 다르게 내부가 변경되어도 좌우 참조값을 변경해주면 되기 때문에 변경에 유리하다.

 

스택: FILO 구조로 쌓듯이 저장하는 자료구조이다.

: FIFO 구조로 먼저 들어간 자료가 먼저 나오는 구조이다.

 

트리: 부모와 자식으로 이루어진 자료구조이다. 보통 이진트리로 사용한다.

이진 검색 트리: 부모 노드보다 작다면 왼쪽 자식으로, 부모 노드보다 크다면 오른쪽 자식으로 배치하여 검색에 효과적인 자료구조이다.

 

그래프: 정점과 간선의 형태로 이루어진 자료구조이다. 간선의 방향이 있다면, 방향 그래프이다.

 

해싱: 검색을 효과적으로 하기 위한 자료구조이다. 기본적으로 배열과 같은 논리로, key의 해시 함수 결과로 bucket에 저장된

value를 알 수 있으므로 시간 복잡도를 줄일 수 있다.

 

 


제네릭

 

 

제네릭: 클래스 내부에서 사용하는 자료형을 미리 정의해두지 않고, 자료형의 변경에 유리하도록 하는 기능

 

부모가 될 Animal 클래스

 

 

Animal의 구현체인 Dog

 

 

Animal의 구현체인 Cat

 

 

위에서 정의한 구현체를 클래스 내부 자료형으로 사용할 UseClass

(T extends Animal을 사용하면 Animal을 상속받은 클래스만 자료형으로 사용하도록 범위를 줄일 수 있다.)

 

 

최종적으로 제네릭을 사용한 Main 클래스

 

 

 


컬렉션과 맵

 

Collection - List, Set을 이용하도록 정의해둔 인터페이스

구현체 - ArrayList, LinkedList, HashSet, TreeSet..

 

List - 순서가 있고, 중복을 허용한다.

Set - 순서가 없고, 중복을 허용하지 않는다.

 


 

Map - Map을 이용할 수 있도록 정의해둔 인터페이스

구현체 - HashMap, TreeMap

 

Map - Key-Value 쌍으로 정의된 자료구조, Key는 중복을 허용하지 않는다.

 

 

 


 

반응형
반응형

IoC 컨테이너 - 객체가 자신이 의존할 객체를 직접 생성하지 않는다. 사용할 객체의 생성과 바인딩을 외부에 넘긴다.

의존할 객체의 결정권을 객체에 두지 않고, 스프링 프레임워크에 둔다.

 

DI - 두 클래스가 의존 관계에 있을 때 인터페이스를 사이에 두고 다형성을 통해 필요한 구현체(bean)를 외부에서 주입시킨다.

(스프링 IoC 컨테이너에 있는 Bean을 주입받는다.)

 


 

IOC 컨테이너에 클래스를 등록하여 관리하고 싶을 때 Bean을 생성하는 방식은 두 가지가 있다.

(어노테이션 이용)

  • @Bean을 사용하는 방법
  • @Component를 사용하는 방법

 

@Component

@Component는 클래스에 지정한다.

Component Scan에 의해 해당 클래스가 bean으로 생성되어 IoC 컨테이너에 등록된다.

DI를 클래스 내부에서 @Autowired를 사용해서 setter주입, 생성자 주입, field주입 등으로 의존 관계를 만들어주어야 한다.

 

 

@Bean 

@Bean은 @Configuration클래스의 메서드에 지정한다.

수동으로 bean을 생성하는 방식이다. 

직접 설계한 클래스가 아니면 @Component 지정이 불가능하기 때문에 외부 라이브러리 클래스를 bean으로 등록할 때 사용한다.

 


 

반응형
반응형

데이터 베이스 설계시 기본키 설정 조건

 

  • null값은 허용하지 않는다.
  • 유일해야 한다.
  • 변해선 안 된다.

 

 

과거에는 자연 키를 기본 키로 설정하는 것이 정석이었지만, 최근에는 변할 가능성이 적은 대리 키 방식을 선호

 


 

https://www.inflearn.com/questions/27694

 

테이블 설계 관련 문의 및 MongoDB JPA 관련 - 인프런 | 질문 & 답변

안녕하세요 영한님, 며칠 전 복합키 관련 질문을 올렸고,  원하는 답변을 얻을 수 있었습니다. 그리고 추가 질문이 있어서 다시 문의드립니다. 1. 테이블 PK 관련.. 설계를 진행하면서 사수 분 생

www.inflearn.com

 

 


 

반응형
반응형

[학습일지] Java & SpringBoot로 시작하는 웹 프로그래밍 : 자바 인강 5주차


 

5주차 강의 학습내용

 

interface
자바의 유용한 클래스
자료구조

 


interface

 

객체지향의 4가지 특징으로 가장 중요하다고 여겨지는 것은 다형성이다.

다형성을 더 효과적으로 사용하는 것을 목적으로 만들어진 것이 인터페이스이다.

 

기본적으로 인터페이스는 클래스가 아니며, 추상 메서드를 갖고 있다고 생각하면 된다.

전에 학습한 추상 클래스는 기본적인 클래스의 틀을 유지하면서 추가적으로 추상 메서드를 갖고 있다.

 

반면, 인터페이스는 추상 메서드만을 갖는다.

추상 메서드 외에 static 메서드나 default 메서드도 갖는 것이 가능하지만

추상 메서드가 가장 중요하다.

 

인터페이스를 구현하게 되면 클래스를 작성하기 이전에 미리 어떠한 함수를 구현해야 하는지 알 수 있으며

해당 인터페이스를 구현했다면 인터페이스에서 작성한 모든 추상 메서드를 구현한 것이 된다.

 

인터페이스를 구현한 클래스가 여러 종류라면 그중 원하는 인스턴스로 교체해주면 간단히 다형성을 사용할 수 있다.

인터페이스에서 구현할 메서드들을 추상 메서드로 미리 명시해줬기 때문에 함수의 반환 타입, 함수명, 매개변수는 같아진다.

이렇듯 인터페이스를 사용하면 다형성을 효과적으로 이용할 수 있기 때문에 사용부의 코드 변경이 굉장히 축소된다.

Property에 key value형태로 value만 바꿔주며 사용부의 코드 변경을 전혀 하지 않게 만들 수도 있다.

 

또한 자바에서 상속은 단일 상속으로 제한이 있기 때문에 직접적인 부모-자식 관계가 아닌

연관성이 적은 클래스들에서는 상속을 받기 어려울 수 있다.

하지만 인터페이스는 이러한 제한이 없기 때문에 연관이 없었던 클래스들의 공통 기능을 만들어 줄 수 있다.

 

 

 


자바의 유용한 클래스

 

Object

toString() : 객체의 참조변수를 참조값이 아닌 String을 반환하도록 재정의 할 수 있다.

equals() : 객체의 참조주소를 비교한다.

hashcode() : hash를 사용하는 Collection에서 문제가 없도록 equals와 같이 재정의 한다.

 

Class

 

 

로컬에 클래스가 없는 경우 해당 클래스의 멤버를 사용할 수 없다.

 

class 클래스는 컴파일된 class 파일 정보를 불러와 동적 로딩 시킨 후 사용할 수 있게끔 도와준다.

Reflection programming으로 활용할 수 있다.

 


자료구조

 

(Stack)

Stack = new Stack

(Queue)

Queue = new LinkedList

(Array)

ArrayList = new ArrayList

(Linked List)
LinkedList = new LinkedList

 

(Hash)
HashSet = new HashSet
HashMap = new HashMap

 

(Heap)

Queue = new PriorityQueue

(BinarySearch Tree)
TreeSet
TreeMap

 

 

 

 


 

반응형
반응형

https://www.acmicpc.net/problem/14501

 

14501번: 퇴사

첫째 줄에 백준이가 얻을 수 있는 최대 이익을 출력한다.

www.acmicpc.net


 

문제를 풀고 나서 다른 사람들의 풀이를 보니 뒤에서부터 생각해서 푸는 경우도 있던데

막상 시험장이라면 생각해내지 못할 가능성이 많아 보인다.

하던데로 앞에서 푸는 방식으로 해결하는 게 연습하기는 좋을 것 같다.

 

여태까지 풀어왔던 DP방식은 INDEX를 현재 시점으로 두고 이전에 구해논 DP 값으로 비교해서 구하는 경우가 많은데

이 문제는 특이하게 구한 수익을 다음 INDEX+N 방식으로 넘겨주면서 풀어야 해서 생각하기 쉽지 않았던 것 같다.

 

그리고 주의할 점은 미래 수익을 정의하기 이전에

현재 시점의 DP 값이 이전 - 1의 DP 값보다 작으면 이전 DP로 갱신해줘야

계속 최대 수익 값이 이어지면서 원하는 날짜의 최대 수익 값을 구할 수 있다.

 

문제 해결 포인트

 

최대 수익을 이어가기

if dp[i] < dp[i-1] {

   dp[i] = dp[i-1] }

 

 


코드 구현

 

import java.io.*;
import java.util.*;
import java.util.function.*;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 
    static int[] dp = new int[10001];
    static int[] days = new int[10001];
    static int[] costs = new int[10001];
 
    public static void main(String[] args) throws IOException {
        int line = Integer.parseInt(br.readLine());
        int D_day = line + 1;
 
        StringTokenizer st;
        int idx = 1;
        while(line-- > 0){
            st = new StringTokenizer(br.readLine());
            int day =Integer.parseInt(st.nextToken());
            int cost = Integer.parseInt(st.nextToken());
            days[idx] = day;
            costs[idx] = cost;
            idx++;
        }
 
        for(int i = 1; i<=1002; i++){
            int day = days[i]; // 현재에서 부터 진행할 날짜
            int cost = costs[i]; // 마감시 얻는 비용
 
            if(dp[i] < dp[i-1])
                dp[i] = dp[i-1];
 
            if(dp[i+day] < costs[i] + dp[i]) { // 비용 + 현재 최대치 를 미래에 입력
                dp[i + day] = costs[i] + dp[i];
            }
        }
        System.out.println(dp[D_day]);
    }
}
cs

 


 

반응형
반응형

[알고리즘] 다익스트라 최단 경로 알고리즘 (Dijkstra Algorithm)


다익스트라 알고리즘은 출발지 -> 경유지 -> 목적지를 이용하여 최단 경로를 구하게 된다.

이 과정을 반복하게 되면 고정된 출발지에서 모든 edge의 최단 경로를 구할 수 있다.

 

 

필요 사항

우선 순위 큐 (순서대로 확인하는 것이 아닌, 거리가 가장 짧은 것부터 수행하기 때문에 수행 시간을 단축)

고정된 출발지에서 목적지까지의 경로 값 저장 배열

 


 

최소 비용을 만들기 위해 필요한 Node의 개수는 항상 3개라고 생각해야 한다. [출발, 경유, 목적]

 

출발지 -> 경유지, 경유지 -> 목적지로 따로 생각해야 한다.

경유지를 반복문을 돌리므로 목적지는 복수개다.

 

주목할 부분은 경유지 -> 목적지 인 부분이다.

목적지였던 부분이 다음부터 경유지로 사용이 되어

경유지가 향하는 모든 edge의 비용을 확인한다.

 

퍼져나가는 방식으로 최종적으로 모든 노드의 최소 비용을 알 수 있다.

 

round 1 = 경유지 -> 목적지

round 2 = 경유지 -> 목적지 

round 3 = 경유지 -> 목적지

 

[목적지가 최소 경로 비용으로 처리되면 다음부터는 목적지가 경유지로 쓰임]

 

BFS 동작 방식과 유사하다.

 


 

동작 예시

 

 

다익스트라 알고리즘은 경유지로 가장 먼저 자기 자신을 기준으로 update 한다.

1번 노드에서 3, 4번 노드를 update 시켜줄 수 있다.

[1 -> 1 -> 3]     [1 -> 1 -> 4]

dist배열 = [INF, 0, INF, 6, 3, INF]  // 0번은 편의를 위해 사용하지 않는다.

 

3, 4번 노드가 update 되고,

큐에 3, 4번 노드가 들어갔다.

 

 

 

 

4번 노드의 가중치가 가장 작으므로 우선순위 큐에 의해 가장 먼저 나온다.

4번 노드에서 2, 3번 노드를 update 시켜줄 수 있다.

[1 -> 4 -> 2]      [1 -> 4 -> 3]

dist배열 = [INF, 0, 4, 4, 3, INF] 

 

2, 3번 노드가 update 되고,

큐에 2, 3번 노드가 들어갔다.

 

현재 큐에 3번 노드가 두 번 들어갔다.

이 경우는 먼저 들어간 3번 노드는 가중치가 6으로 dist [3]의 값보다 크므로 사용되지 않고 버려진다.

1 -> 1 -> 3 경로보다 1 -> 4 -> 3 경로가 최소 비용이므로 1 -> 4 -> 3을 사용하면 되기 때문이다.

(update 된 거리보다 크다면, update 한 노드는 큐에 들어간 것이므로 최소가 보장. 버려도 되는 이유)

 

 

 

이 같은 방식으로 시작 노드를 기준으로 퍼져나가며 모든 노드의 최소 비용을 계산한다.

다익스트라 알고리즘은 방향 그래프여야 하며, 거리가 음수면 안된다.

거리가 음수, 그리고 사이클이 존재한다면 거리를 계속 줄이는 음수 사이클이 발생. -무한대 형성

 

 


 

 

public class Dijkstra {
    static int[] dist;
    static int[] path; // 자신의 앞 경로를 갖고 있다. ** 모든 경로를 확인할 수 있다.

    static List<List<Node>> list = new ArrayList<>(); // 간선들

    static final int edgeCount = 5 + 1;
    static final int vCount = 7;

    public static void main(String[] args) {
        //노드 5개
        dist = new int[edgeCount]; // 0 사용안함.
        path = new int[edgeCount];
        //간선 7개
        for(int i = 0; i<=vCount; i++) {
            list.add(new ArrayList<>());
        }

        // (1 - > 5) 2000 쓰는 경로
        list.get(1).add(new Node(4, 2000));
        list.get(1).add(new Node(5, 2000));

        // (1 -> 5) 10 쓰는 경로
        list.get(1).add(new Node(2, 5));
        list.get(2).add(new Node(5, 5));

        // (1 -> 5) 3 쓰는 경로
        list.get(1).add(new Node(3, 1));
        list.get(3).add(new Node(4, 1));
        list.get(4).add(new Node(5, 1));

        
        // TODO: 이 부분 주의 자신은 0으로 만들어야함
        // 자기 자신 빼고 나머지 INF 로 초기화
        Arrays.fill(dist, 100_000_000);
        dist[1] = 0; // 시작

        
        dijk();

        // 결과
        System.out.println(Arrays.toString(dist));
        // 경로
        System.out.println(Arrays.toString(path));
    }

    // TODO: 출발지 1번은 계속 고정
    public static void dijk(){
        Queue<Node> q = new PriorityQueue<>((o1,o2) -> o1.w - o2.w);
        q.add(new Node(1, 0)); // 경유지, 비용 (1 -> 1 -> n)

        while(!q.isEmpty()) { // TODO: 경유지 뽑기 // 1 -> M
            Node mid = q.poll(); // 1과 연결된 경유지
            
            // 과거 ,  현재
            if(mid.w > dist[mid.dest]) // update 된 거리보다 큐에서 뽑은게 더 크면 사용 안하고 버림
                continue;

            // TODO: 경유 -> 도착 꺼내는 부분
            for(Node d : list.get(mid.dest)){
                if(dist[d.dest] > dist[mid.dest] + d.w){ // 갱신이 되는 부분.
                    dist[d.dest] = dist[mid.dest] + d.w;
                    // 갱신이 된 것. 1->n , n->M
                    // (1 -> 도착지)  [[ (1 -> 경유(테이블)  + 경유(테이블) - > 도착지 ]]
                    // 계속 갱신       계속 생신

                    // TODO: 현재 목적지가 다음부터는 경유지로 쓰인다.
                    q.offer(new Node(d.dest, dist[d.dest]));
                    // 갱신된 (1 -> 목적지) 를 넣어준다.
                    // 갱신된걸 넣지 않으면 for 부분을 또 확인하기 때문에 갱신된 값을 넣어주는게 좋다.

                    path[d.dest] = mid.dest; // 길찾기 용도 (자신의 앞 노드)
                }
            }
        }
    }
}

// 경유지로도 쓰고, 목적지로도 쓰임
class Node{
    int dest; // 도착지
    int w; // 가중치

    Node(int dest, int w){
        this.dest = dest;
        this.w = w;
    }

    public String toString(){
        return this.dest + " " + this.w;
    }
}

 

 

 

 

 

 

 

 

 

 


 

 

 

반응형

+ Recent posts