오라클 실행 전 기억 해 둘 환경 설정

 

▶ 도구 - 환경 설정 - 환경 - 인코딩(E): UTF-8 설정
▶ 워크 시트 만드는 방법 : 시스템 계정 우클릭 - SQL 워크시트 열기 클릭 
▶ 주석 처리 : -- (슬래쉬 두번), /**/ 도 가능하다.
▶ SQL은 대소문자를 구분하지않는다. 일반적으로 대문자 작성
▶ 수업 내용 보존을 위해 파일로 저장해야 한다.
▶ GRANT CONNECT, RESOURCE TO C##EMPLOYEE;
    → 방금만든 파일에 연결할 수 있는, 리소스를 다양하게 다룰 수 있는 권한을 준다
    → 권한을 주는 것은 시스템 계정이 하는 일, 일반계정은 권한 부며 능력이 없다.
▶ 저장 : CTRL + S
▶ 실행 : CTRL + ENTER
▶ DROP USER : 지운다는 의미
▶ 워크시트에 행번호 표시 : 워크 시트 -> 우클릭 -> 행 번호 토글

 

 

 

 

▶시스템 계정에 다음과 같이 적는다.

-- 계정 생성 (CREAT USER)
CREAT USER C##EMPLOYEE IDENTIFIED BY EMPLOYEE;
-- 권한부여 (GRANT)​

 

▶직원 관리 계정에 다음 파일을 가져온다. 

직원계정.sql
0.02MB

 

 

 

 

 

 

 

 

 

 

 

DML(SELECT)

 

 

 

주요 용어

① 행(Row), 튜플
② 컬럼, 도메인
③ 기본키(Primary Key)
④ 외래키(Foreign Key)
⑤ Null
⑥ 컬럼값, 속성값

 

 

 

 

 

 

 

 

SQL(Structured Query Language)
  • 관계형 데이터베이스에서 데이터를 조회하거나 조작하기 위해 사용하는 표준 검색언어이다.
    원하는 데이터를 찾는 방법이나 절차를 기술하는 것이 아닌 조건을 기술하여 작성한다.

 

분류 용도 명령어
DQL
(Data Query Language)
데이터 검색 SELECT
DML
(Data Manipulation Language)
데이터 조작 INSERT
UPDATE
DELETE
DDL
(Data Definition Language)
데이터 정의 CREATE
DROP
ALTER
TCL
(Transaction Control Language)
트랜젝션 제어 COMMIT
ROLLBACK

 

 

 

 

 

 

 

 

주요 데이터 타입 (1)

 

데이터 타입 하위 데이터 타입 설명
NUMBER   숫자
CHARACTER CHAR 고정길이 문자 (최대 2000 바이트)
VARCHAR2 가변길이 문자 (최대 4000 바이트)
LONG 가변길이 문자 (최대 2 기가 바이트)
DATE   날짜
LOB CLOB 가변길이 문자 (최대 4 기가 바이트)
BLOB Binary Data

 

 

 

 

 

 

 

주요 데이터 타입 (2)

 

NUMBER [ ( P [, S] ) ]
  • P : 표현할 수 있는 전체 숫자 자리수(1~38)
  • S : 소수점 이하 자리수 (-84 ~ -127)

 

 

 

 

 

 

 

주요 데이터 타입 (3)

 

CHAR ( SIZE [ Byte | char ] )
  • SIZE : 포함될 문자(열) 크기
  • 지정한 크기보다 작은 문자(열)이 입력되고 남는 공간은 공백으로 채운다.
  • 데이터는 ‘ ‘를 사용하여 표기하고, 대/소문자를 구분한다.

 

 

 

 

 

 

 

주요 데이터 타입 (4)

 

VARCHAR (SIZE [Byte | char ] )
  • SIZE : 포함될 문자(열) 크기
  • 지정한 크기보다 작은 문자(열)이 입력되고 남는 공간은 없앤다.
  • 데이터는 ‘’를 사용하여 표기하고, 대/소문자를 구분한다.

 

 

 

 

 

 

 

 

주요 데이터 타입 (5)

 

DATE
  • 일자(세기/년/월/일) 및 시간(시/분/초) 정보를 관리
  • 기본적으로 화면에 년/월/일 정보만 표기된다.
  • 날짜의 연산 및 비교가 가능하다.

 

 

 

 

 

 

 

 

SELECT


  • 데이터를 조회한 결과를 Result Set이라고 한다.
  • SELECT 구문에 의해 반환된 행들의 집합을 의미한다.
  • Result Set은 0개 이상의 행이 포함될 수 있다.
  • Result Set은 특정한 기준에 의해 정렬될 수 있다.
  • 특정 컬럼이나 특정 행 혹은 특정 행/특정 컬럼을 조회할 수 있으며,
     여러 테이블의 특정 행/컬럼을 조회할 수도 있다.

 

 

 

 

 

 

SELECT 기본 작성법
[ 표현식 ]
SELECT
	   컬럼명
	[,  컬럼명, … ]
	 ,  컬럼명
FROM 	테이블명
WHERE 	조건식;

 

[ 구문 설명 ]
· SELECT : 조회하고자 하는 컬럼명을 기술한다.
	여러 컬럼을 조회하는 경우 컬럼은 쉼표로 구분하고,
	마지막 컬럼 다음은 쉼표를 사용하지 않는다.
	모든 컬럼을 조회 시 컬럼명 대신 ‘*’기호로 사용가능하다.
	조회 결과는 기술한 컬럼명 순으로 표시된다.

· FROM : 조회 대상 컬럼이 포함된 테이블명을 기술한다.

· WHERE : 행을 선택하는 조건을 기술한다.
	여러 개의 제한조건을 포함할 수 있으며,
	각각의 제한 조건은 논리 연산자로 연결한다.
	제한조건을 만족시키는 행들만 Result Set에 포함한다.

 

 

 

 

 

SELECT 사용 예시 -기본
  • 직원들의 사번과 이름을 조회하는 SELECT 구문

 

 

 

SELECT * FROM EMPLOYEE; 이렇게 한 줄로 적어도 문제가 없으나 

SELECT         *     
FROM    EMPLOYEE; 이와 같이 적기로 약속한다.

 *  : 모든 컬럼이라는 의미

 

 

 

 

 

SELECT 사용 예시 -기본
  • 방법 1) 직원들의 모든 정보를 조회하는 SELECT 구문

 

 

-- SELECT 기본 문법 및 연산자

-- 모든 행 모든 컬럼 조회
-- EMPLOYEE 테이블에서 모든 정보 조회

SELECT 
        * 
    FROM EMPLOYEE;

 

 

-- 원하는 컬럼 조회
-- EMPLOYEE테이블의 사번, 이름 조회

SELECT  
        EMP_ID
      , EMP_NAME
  FROM EMPLOYEE;

 

 

-- 원하는 행 조회
-- EMPLOYEE 테이블에서 부서코드가 D9인 사원 조회

SELECT
        *
  FROM EMPLOYEE
 WHERE DEPT_CODE = 'D9';

 

 

 

 

-- EMPLOYEE 테이블에서 직급 코드가 J1인 사원 조회

SELECT
        *
  FROM EMPLOYEE
 WHERE JOB_CODE = 'J1';

 

 

 

-- 원하는 행과 컬럼 조회
-- EMPLOYEE 테이블에서 급여가 300만원 이상인 사원의
-- 사번, 이름, 부서코드, 급여를 조회하시오

SELECT
        EMP_ID
      , EMP_NAME
      , DEPT_CODE
      , SALARY
  FROM EMPLOYEE
 WHERE SALARY > 3000000;

 

 

 

 

 

 

방법 2) 직원들의 모든 정보를 조회하는 SELECT 구문

 

 

 

 

 

 

SELECT 사용 예시 – 컬럼 값 산술 연산
  • 컬럼 값에 대해 산술 연산한 결과를 조회할 수 있다.

 

 

 

SELECT 사용 예시 – 컬럼 별칭
  •  ‘AS + 원하는 별칭‘ 을 기술하여 컬럼 별칭을 부여할 수 있다.

 

 

 -- 컬럼에 별칭 짓기
 -- AS + 별칭을 기술하여 별칭을 지을 수 있다.
 SELECT
        EMP_NAME AS 이름
      , SALARY * 12 "1년 급여(원)" 
      -- 숫자와 숫자가 붙어서 생기는 문제는 쌍따옴표로 감싸기
      , (SALARY + (SALARY * BONUS)) * 12 
      , (SALARY + (SALARY * NVL(BONUS, 0))) * 12 AS "총 소득(원)"
   FROM EMPLOYEE;

 

 

 

 

 

 

 

 

SELECT 사용 예시 – 리터럴
  • 임의로 지정한 문자열을 SELECT 절에 사용하면, 테이블에 존재하는 데이터 처럼 사용할 수 있다.

 

 

 

-- 임의로 지정한 문자열을 SELECT 절에서 사용할 수 있다.

SELECT
        EMP_ID
      , EMP_NAME
      , SALARY
      , '원' AS 단위
    FROM EMPLOYEE;

 

 

 

 

 

 

 

 

SELECT 사용 예시 – DISTICT
  •  컬럼에 포함된 중복 값을 한번씩만 표시하고자 할 때 사용한다

 

 

-- DISTINCT 키워드는 중복 된 컬럼 값을 제거하여 조회한다.    

SELECT
        DISTINCT JOB_CODE
  FROM EMPLOYEE;
  
  
  
-- DISTINCT 키워드는 SELECT절에 딱 한번만 쓸 수 있다.
-- 여러개의 컬럼을 묶어서 중복을 제외시킨다.
  
  SELECT
        DISTINCT JOB_CODE
      , /* DISTINCT */ DEPT_CODE
    FROM EMPLOYEE;

 

 

 

 

 

 

 

 

SELECT 사용 예시 – WHERE절
  • 검색할 컬럼의 조건을 설정하여 행을 결정한다.

 

  • 여러 개의 조건 작성 시 AND/OR를 사용할 수 있다.

 

-- WHERE 절
-- 테이블에서 조건을 만족하는 값을 가진 행을 골라낸다.
-- 여러개의 조건을 만족하는 행을 골라 낼 때 AND 혹은 OR를 사용할 수 있다.

-- 부서코드가 D6이고 급여가 200만원을 초과하여 받은 직원의
-- 이름, 부서코드, 급여 조회

SELECT
        EMP_NAME
      , DEPT_CODE
      , SALARY
  FROM  EMPLOYEE
 WHERE  DEPT_CODE = 'D6'    
   AND SALARY > 2000000;

 

 

-- NULL 값 조회
-- 보너스를 지급받지 않는 사원의
-- 사번, 이름, 급여, 보너스를 조회하세요

SELECT
        EMP_ID
      , EMP_NAME
      , SALARY
      , BONUS
 FROM EMPLOYEE
WHERE BONUS IS NULL;

 

 

-- NULL이 아닌 값 조회
-- 보너스를 지급받는 사원의
-- 사번, 이름, 급여, 보너스를 조회하세요

SELECT
        EMP_ID
      , EMP_NAME
      , SALARY
      , BONUS
  FROM EMPLOYEE
 WHERE BONUS IS NOT NULL;

 

 

 

 

 

 

 

 

 

 

연결 연산자
  • 연결 연산자인 ‘||’를 사용하여 여러 컬럼을 하나의 컬럼인 것처럼 연결하거나,
    컬럼과 리터럴을 연결할 수 있다.

 

컬럼과 컬럼을 연결한 경우

 

 

컬럼과 리터럴을 연결한 경우

 

 

-- 연결 연산자를 이용해여 여러 컬럼을 하나의 컬럼인 것처럼
-- 연결할 수 있다. (||)

-- 컬럼과 컬럼 연결

SELECT
        EMP_ID || EMP_NAME || SALARY
    FROM EMPLOYEE;

 

 

 

-- 컬럼과 리터럴 연결

SELECT
        EMP_NAME || '의 월급은 ' || SALARY || '원 입니다.'
  FROM  EMPLOYEE;

 

 

 

 

 

 

논리 연산자
  • 여러 개의 제한 조건 결과를 하나의 논리결과로 만들어준다.

 

 

 

 

비교 연산자
  • 표현시 사이의 관계를 비교하기 위해 사용하고,
  • 비교 결과는 논리 결과 중에 하나(TRUE/FALSE/NULL)가 된다.
  • 단, 비교하는 두 컬럼 값/표현식은 서로 동일한 데이터 타입이어야 한다.

 

 

 

-- 비교 연산자
-- = 같다, > 크다, < 작다, >= 크거나 같다, <= 작거나 같다.
-- !=, ^=, <> 같지않다. (세가지 버전)

SELECT
        EMP_ID
      , EMP_NAME
      , DEPT_CODE
  FROM  EMPLOYEE
  
 -- WHERE  DEPT_CODE != 'D9';
 -- WHERE  DEPT_CODE ^= 'D9';
 WHERE  DEPT_CODE <> 'D9';

 

 

 

-- EMPLOYEE 테이블에서 퇴사 여부가 N인 직원을 조회하고 
-- 근무 여부를 별칭으로 하여 재직중이라는 문자열을 결과집합에 포함하여 조회한다.
-- 사번, 이름, 입사일, 근무여부 조회

SELECT
        EMP_ID
      , EMP_NAME
      , HIRE_DATE
      , '재직중' 근무여부
 FROM EMPLOYEE
WHERE ENT_YN = 'N';

 

 

 

-- EMPLOYEE 테이블에서 급여를 350만원 이상
-- 550만원 이하를 받는 직원의 사번, 이름, 부서코드, 직급코드를 조회하세요

SELECT
        EMP_ID
      , EMP_NAME
      , DEPT_CODE
      , JOB_CODE
 FROM EMPLOYEE
WHERE SALARY >= 3500000
  AND SALARY <= 5500000;

 

 

 

 

 

 

비교 연산자 – BETWEEN AND
  • 비교하려는 값이 지정한 범위(상한 값과 하한 값의 경계도 포함)에 포함되면 TRUE를 리턴하는 연산자이다.
[ 급여를 350만원보다 많이 받고 600만원보다 적게 받는 직원 이름과 급여 조회 ]

1,2 번은 표현식만 다를 뿐 동일한 결과를 출력한다

 

 

-- BETWEEN AND 사용
-- 컬럼명 BETWEEN 하한값 AND 상한값
-- :  하한값 이상, 상한값 이하의 값

SELECT
        EMP_ID
      , EMP_NAME
      , DEPT_CODE
      , JOB_CODE
 FROM EMPLOYEE
WHERE SALARY BETWEEN 3500000 AND 5500000;

 

 

 

 

-- 반대로 급여를 350만원 미만, 또는 550만원을 초과하는
-- 직원의 사번, 이름, 부서코드, 급여를 조회하세요. 

SELECT
        EMP_ID
      , EMP_NAME
      , DEPT_CODE
      , JOB_CODE
 FROM EMPLOYEE
-- WHERE /*NOT*/ SALARY NOT BETWEEN 3500000 AND 5500000;
WHERE SALARY /*NOT*/ BETWEEN 3500000 AND 5500000;

-- NOT (1) 컬럼명 앞 (2) 컬럼명 뒤(=BETWEEN 앞)

 

 

 

 

 

 

-- LIKE 연산자 : 문자 패턴이 일치하는 값을 조회할 때 사용
-- 컬럼명 LIKE '문자패턴'
-- 문자 패턴 : '글자%' (글자로 시작하는 값),
--            '%글자%' (글자가 포함된 값),
--            '%글자' (글자로 끝나는 값)

-- EMPLOYEE 테이블에서 성이 김씨인 직원의
-- 사번, 이름, 입사일 조회
SELECT
       EMP_ID
     , EMP_NAME
     , HIRE_DATE
  FROM EMPLOYEE
 WHERE EMP_NAME LIKE '김%';

 

 

-- EMPLOYEE 테이블에서 성이 김씨가 아닌 직원의
-- 사번, 이름, 입사일 조회
SELECT
       EMP_ID
     , EMP_NAME
     , HIRE_DATE
  FROM EMPLOYEE
-- WHERE NOT EMP_NAME LIKE '김%';
 WHERE EMP_NAME NOT LIKE '김%';
 

-- EMPLOYEE 테이블에서 '하'가 이름에 포함된
-- 직원의 이름, 주민번호, 부서코드 조회
SELECT 
       EMP_NAME
     , EMP_NO
     , DEPT_CODE
  FROM EMPLOYEE
 WHERE EMP_NAME LIKE '%하%';

 

 

 

-- EMPLOYEE 테이블에서 전화번호 국번이 9로 시작하는
-- 직원의 사번, 이름, 전화번호를 조회하세요
-- 와일드 카드 사용 : _(글자 한 자리), %(0개 이상의 글자)
SELECT
       EMP_ID
     , EMP_NAME
     , PHONE
  FROM EMPLOYEE
 WHERE PHONE LIKE '___9%';

 

-- EMPLOYEE 테이블에서 전화번호 국번이 4자리이면서
-- 9로 시작하는 직원의 사번, 이름, 전화번호를 조회하세요
SELECT
       EMP_ID
     , EMP_NAME
     , PHONE
  FROM EMPLOYEE
 WHERE PHONE LIKE '___9_______';

 

-- EMPLOYEE 테이블에서 _앞글자가 3자리인 이메일 주소를 가진
-- 사원의 사번, 이름, 이메일 주소 조회
SELECT
       EMP_ID
     , EMP_NAME
     , EMAIL
  FROM EMPLOYEE
 WHERE EMAIL LIKE '___#_%' ESCAPE '#';
 
-- 이씨성이 아닌 직원의 사번, 이름, 이메일 주소 조회
SELECT 
       EMP_ID
     , EMP_NAME
     , EMAIL
  FROM EMPLOYEE
 WHERE EMP_NAME NOT LIKE '이%';

 

 

-- 부서코드가 'D6'이거나 'D8'인 직원의
-- 이름, 부서, 급여를 조회하세요
-- IN 연산자 : 비교하는 값 목록에 일치하는 값이 있는지 확인
SELECT
       EMP_NAME
     , DEPT_CODE
     , SALARY
  FROM EMPLOYEE
 WHERE DEPT_CODE IN('D6', 'D8');
 
 
-- 부서코드가 'D6'이거나 'D8'인 직원을 제외한 나머지 직원의
-- 이름, 부서, 급여를 조회하세요
SELECT
       EMP_NAME
     , DEPT_CODE
     , SALARY
  FROM EMPLOYEE
 WHERE DEPT_CODE NOT IN('D6', 'D8');

 

 

-- 연산자 우선순위
/*
1. 산술연산자
2. 연결연산자
3. 비교연산자
4. IS NULL/IS NOT NULL, LIKE/NOT LIKE, IN/NOT IN
5. BETWEEN AND/NOT BETWEEN AND
6. NOT(논리연산자)
7. AND
8. OR
*/

 

 

 

-- J2 직급의 급여 200만원 이상 받는 직원이거나
-- J7 직급인 직원의 이름, 급여, 직급코드 조회
SELECT
       EMP_NAME
     , SALARY
     , JOB_CODE
  FROM EMPLOYEE
 WHERE JOB_CODE = 'J7'
    OR JOB_CODE = 'J2'
   AND SALARY >= 2000000;


-- J7 직급이거나 J2 직급인 직원들 중
-- 급여가 200만원 이상인 직원의
-- 이름, 급여, 직급코드 조회
SELECT
       EMP_NAME
     , SALARY
     , JOB_CODE
  FROM EMPLOYEE
 WHERE (JOB_CODE = 'J7'
    OR JOB_CODE = 'J2')
   AND SALARY >= 2000000;

 

 

 

 

 

 

 

'Programming > ORACLE' 카테고리의 다른 글

서브 쿼리 ( Subquery)  (0) 2022.01.21
JOIN  (0) 2022.01.19
GROUP BY & HAVING  (0) 2022.01.19
함수(Function)  (0) 2022.01.18
데이터 베이스 개요  (0) 2022.01.17

 

 

 

Git / GitHub

 

 

 

 

 

버전 관리란?


(혼자서 작업한다면 버전 관리 시스템이 없어도 괜찮지만) 팀 프로젝트의 소스 코드는 버전 1에 대해서 팀원 A와 B가 동시에 수정을 하여 각각의 버전 2 를 만든 경우 어떤 것이 최종 업데이트 파일인지 확인할 수 없는경우가 발생한다. 따라서 협업 프로젝트는 버전 관리가 필요하다고 할 수 있다.

 

 

 

 

 

Git



원하는 시점마다 깃발을 꽂고 깃발이 꽂힌 시점으로 자유롭게 이동 가능한 소스코드 버전 관리 시스템. 개인 컴퓨터에 저장한다면 혼자 사용할 수 있고 usb에 저장하면 휴대하고 사용할 수 있다. 구글 드라이브와 같은 서버에 올리면 팀원들과 함께 인터넷을 통한 버전 관리 가능하다.

 

 

 

 

 

 

GitHub



git 호스팅 사이트 중 하나이며 시간과 공간의 제약 없이 협업 가능하다. 공개 저장소로 만들 시 모르는 사람과도
협업이 가능하다. 누구든지 기여할 수 있는 공개저장소 프로젝트 => 오픈소스, GitLab, BitButcket등 다양한 호스팅 사이트가 있음

 

 

 

 

 

 

 

 

GitHub 가입하기


 

 

github.com에 접속하여 sign up 진행

 

 

 

 

 

 

필요한 정보 입력 후 create account, join a free plan, complete set up 클릭

 

 

 

 

 

 

기입한 email 주소로 발송 된 메일 확인하여 verify email address 클릭하면 가입 완료

 

 

 

 

 

 

 

 

 

 

 

Git - local repository

 

 

 

Git 설치
  • git 다운로드 검색하여 git-scm.com/download/에 접속
  • OS에 맞는 최신 버전의 git 다운로드

 

 

 

 

 

  • 다운로드 된 파일 실행하면 아래와 같은 창이 뜬다.
  • 기본 설정으로 next 및 install 버튼을 클릭해서 설치 진행 후 finish 버튼을 클릭하면 설치는 완료 되었다고 할 수 있다.

 

 

 

 

 

 

 

  • 검색을 통해 설치 확인을 하도록 한다.
  • Git Bash 실행 후 $ 옆에 git 입력
  • 아래와 같이 기본 명령어에 대한 안내가 나오면 설치가 완료된 걸 확인할 수 있다.

 

 

 

 

 

 

 

 

 

 

로컬 저장소(local repository) 만들기

 

 

  • 바탕 화면 > gitLocalTest > test 경로에 README.txt 파일 만들기
  • txt 파일 열어 아래와 같이 적고 저장 후 닫기

 

 

 

 

 

 

 

 

  • 해당 경로에서 우클릭하여 Git Bash Here 클릭
  • $ 옆에 git init 입력하여 'Initialized empty Git repository' 나오면 초기화 성공
  • .git 폴더 자동 생성 (Git으로 생성한 버전 정보, 원격 저장소 주소 등이 들어있는 로컬 저장소)

 

원하는 파일에 우클릭을 하면 Git Bash를 확인할 수 있다.

 

git init

 

숨김항목 체크시 다음과같이 확인할 수 있다.

 

 

 

 

 

 

 

로컬 저장소(local repository)에 commit 만들기


 

  • GitHub에 등록한 email, username을 사용하여 아래와 같은 명령어 입력
  • $git config --global user.email "GitHub이메일"

 

 

  • $git config --global user.name "GitHub이름"

 

 

  • commit에 추가할 파일 선택
  • $ git add README.txt 입력

 

 

 

  • 커밋에 "first commit"이라는 상세 설명을 적어 첫번째 커밋하기 (-m : message)
  • 입력 : $ git commit -m "first commit"
  • 1 file changed, 1 insertion(+) 확인되면 첫번째 버전 생성 완료

 

 

 

 

 

  • README.txt 파일을 수정한다.

 

  • 입력1 : $ git add README.txt

 

  • 입력2 : $ git commit -m "updated"

 

 

 

 

 

 

 

로컬 저장소(local repository)의 다른 커밋으로 이동하기

 

 

  • $ git log 명령어로 지금까지 만든 두 개의 커밋 확인한다.
  • first commit의 앞 7자리 커밋 아이디를 복사하여 checkout 명령어와 함께 입력시, 해당 커밋으로 코드를 되돌릴 수 있다. 아래 코드에서 확인 해 보자.

 

 

  • 입력 : $ git checkout 2739ecd
  • "HEAD is now at 2739ecd first commit" 확인

 

 

 

 

  • README.txt 파일 확인 하면 first commit 상태로 돌아가 있다.
  • $ git checkout - 를 입력하여 다시 최신 커밋인 두 번째 커밋으로 돌아갈 수 있다.
  • README.txt 파일 확인하면 updated 상태로 돌아가 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

Git - remote repository

 

 

 

원격 저장소(remote repository)에 커밋 올리기
  • GitHub에서 new repository를 클릭한다.
  • repository 이름 입력 후 옵션 선택한 뒤
  • create repository 클릭

 

 

 

 

 

 

 

 

 

 

 

 

  • 깃배쉬에 다음과 같이 입력한다.
  • $ git remote add origin https://github.com/kh-bl/gitRemoteTest.git
  • 로컬 저장소에 원격 저장소 주소를 입력 후 
  • $ git push origin master 입력 시 GitHub 로그인 창이 뜬다.
  • email과 password 입력하여 로그인한다.

 

 

 

 

 

 

  • GitBash에서 아래와 같은 화면 확인 후 GitHub에서 저장소 확인

 

 

 

 

 

 

 

 

 

 

 

 

 

▶ 원격 저장소의 커밋을 로컬 저장소에 내려받기

 

  • 바탕 화면 > gitLocalTest > test2 경로 만들고 우클릭하여 Git Bash Here 클릭
  • $ git clone https://gitlab.com/test-group-22011712/test-project.git .
  • 원격 저장소 주소 뒤의 마침표의 의미는 현재 폴더를 뜻한다.
  • README.txt 파일과 .git 폴더가 보이면 clone에 성공 한 것이다.

 

 

 

 

 

 

 

 

 

 

  • README.txt 파일을 수정하고 저장 (확인을 위함)
  • $ git add README.txt (README.txt 파일 커밋)
  • $ git commit –m “test2 first commit” (커밋에 메시지로 설명 추가)
  • $ git push origin master (원격 저장소에 push)

 

깃발꽂기

 

push 하여 원격 저장소에 업데이트 하기

 

 

 

 

 

  • GitHub의 원격 저장소에 들어가 “test2 first commit” 올라와 있는 것을 확인할 수 있다.

 

 

 

 

 

  • 바탕 화면 > gitLocalTest > test 경로의 README.txt 파일은 “test2 first commit” 변경 사항이 반영되어
    있지 않으므로 원격 저장소에서부터 변경사항을 반영한다.
  • 해당 경로에서 우클릭 Git Bash Here 클릭하여
  •  입력 : $ git pull origin master (원격 저장소의 새로운 커밋을 로컬 저장소로 받아옴)

 

 

 

 

  • 바탕 화면 > gitLocalTest > test 경로의 README.txt 파일을 열어 변경 사항 확인

 

 

 

 

 

 

 

 

 

 

용어 정리

  • Git : 버전 관리 시스템
  • GitHub : Git으로 관리하는 프로젝트를 올려둘 수 있는 사이트
  • Git Bash : CLI 방식으로 Git을 사용할 수 있는 환경
  • CLI(Command Line Interface) - 명령어를 입력하는 방식. GUI(Graphic User Interface) - 마우스로 클릭하는 방식.
  • Commit : 버전 관리를 통해 생성 된 파일, 혹은 그 행위.
  • Log : 지금까지 만든 커밋을 모두 확인하는 명령어.
  • Checkout : 원하는 지점으로 파일을 되돌림.
  • Local repository : 로컬 저장소. Git으로 버전 관리하는 내 컴퓨터 안의 폴더를 의미함.
  • Remote repository : 원격 저장소. GitHub에서 협업하는 공간을 의미함.
  • Push : 로컬 저장소의 커밋(버전 관리한 파일)을 원격 저장소에 올리는 것.
  • Pull : 원격 저장소의 커밋을 로컬 저장소에 내려 받는 것.

 

 

 

 

 

 

Database란?

한 조직에 필요한 정보를 여러 응용 시스템에서 공용할 수 있도록 논리적으로 연관된 데이터를 모으고, 중복되는 데이터를 최소화하여 구조적으로 통합/저장해 놓은 것이다.

 

 

Database의 정의
1. 운영 데이터(Operational Data) : 조직의 목적을 위해 사용되는 데이터를 의미
2. 공용 데이터(Shared Data) : 공동으로 사용되는 데이터를 의미
3. 통합 데이터(Integrated Data) : 중복을 최소화하여 중복으로 인한 데이터 불일치 현상 제거
4. 저장 데이터(Stored Data) : 컴퓨터 저장 장치에 저장된 데이터를 의미

 

 

 

Database의 특징

 

1. 실시간 접근성(Real Time Accessibility)
- 사용자가 데이터를 요청하면 실시간으로 결과를 서비스한다.
2. 계속적인 변화(Continuous Change)
- 데이터 값은 시간에 따라 항상 바뀐다.
3. 동시 공유(Concurrent Sharin)
- 데이터베이스는 서로 다른 업무 또는 여러 사용자에게 동시 공유된다.
4. 내용에 따른 참조(Reference By Content)
- 데이터베이스에 저장된 데이터는 데이터의 물리적 위치가 아니라 데이터 값에 따라 참조된다.

 

 

 

DBMS(DataBase Management System)란?

 

- 데이터베이스에서 데이터를 추출,조작,정의,제어 등을 할 수 있게 해주는 데이터베이스 전용 관리 프로그램이다.

 

 

 

 

 

 

DBMS의 기능

 

데이터 추출
(Retrieval)

사용자가 조회하는 데이터 혹은 응용 프로그램의 데이터를 추출함

 

데이터 조작
(Manipulation)

데이터를 조작하는 소프트웨어(응용 프로그램)가 요청하는 데이터의 삽입, 수정, 삭제 작업을 지원함

 

데이터 정의
(Definition)

데이터의 구조를 정의하고 데이터 구조에 대한 삭제 및 변경 기능을 수행함

 

 

데이터 제어
(Control)

데이터베이스 사용자를 생성하고 모니터링하며 접근을 제어함.
백업과 회복, 동시성 제어 등의 기능을 지원함

 

 

 

 

DBMS의 사용 이점

 

1 데이터 독립화

데이터와 응용 프로그램을 분리시킴으로써 상호 영향 정도를 줄일 수 있다.

 

2데이터 중복 최소화
데이터 무결성 보장

-중복되는 데이터를 최소화 시키면 데이터 무결성이 손상될 가능성이 줄어든다.
-중복되는 데이터를 최소화시키면 필요한 저장공간의 낭비를 줄일 수 있다.

 

 

 

3 데이터 보안 향상

-응용프로그램은 DBMS를 통해 DBMS가 허용하는 데이터에만 접근할 수 있다.
-권한에 맞게 데이터 접근을 제한하거나 데이터를 암호화시켜 저장할 수 있다.

 

 

 

4 관리 편의성 향상

-다양한 방법으로 데이터를 백업할 수 있다.
-장애 발생 시 데이터를 복구할 수 있다.

 

 

 

 

 

 

 

 

Database의 유형

 

 

계층형 데이터베이스

트리 형태의 계층적 구조를 가진 데이터베이스
최상위 계층의 데이터부터 검색하는 구조

 

 

네트워크형 데이터베이스

하위 데이터끼리의 관계까지 정의할 수 있는
구조를 가진 데이터베이스
설계/구현이 너무 복잡하고 어려움

 

 

 

Database의 유형

 

관계형 데이터베이스

- 모든 데이터를 2차원 테이블 형태로 표현하고, 테이블 사이의 비즈니스적 관계를 도출하는 구조를 가진 데이터베이스 유형
- 데이터의 중복을 최소화 할 수 있으며, 업무 변화에 대한 적응력이 우수함

 

 

 

 

Database의 유형 : 객체-관계형 데이터베이스

1. 사용자 정의 타입을 지원한다.
- 사용자가 임의로 정한 데이터 유형을 말하며, 기본형 데이터 타입을 뛰어 넘어 다양한
형태의 데이터를 다룰 수 있다.
2. 참조(reference)타입을 지원한다.
- 객체들로 이루어진 객체 테이블의 경우,
하나의 레코드가 다른 레코드를 참조할 수 있는 것을 말한다.
3. 중첩 테이블을 지원한다.
- 테이블을 구성하는 로우(Row)자체가 또 다른 테이블로 구성되는 테이블을 지원하여
조금 더 복잡하고 복합적인 정보 표현이 가능하다.
4. 대단위 객체의 저장, 추출이 가능하다.
- 이미지, 오디오, 비디오 등 을 저장하기 위한 대단위 객체(LOB)를 지원한다.
5. 객체간의 상속관계를 지원한다.
- 오라클의 경우 OBJECT 타입을 지원함으로써 상속기능을 구현하고 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'Programming > ORACLE' 카테고리의 다른 글

서브 쿼리 ( Subquery)  (0) 2022.01.21
JOIN  (0) 2022.01.19
GROUP BY & HAVING  (0) 2022.01.19
함수(Function)  (0) 2022.01.18
DML(SELECT)  (0) 2022.01.17

 

 

 

 

 

 

보조 스트림

 

 

  • 스트림의 기능을 향상시키거나 새로운 기능을 추가하기 위해서 사용
  • 보조 스트림은 실제 데이터를 주고 받는 스트림이 아니기 때문에 입출력 처리가 불가능
  • 기반 스트림을 먼저 생성한 후 이를 이용하여 보조 스트림을 생성

 

 

 

 

 

 

 

 

보조 스트림의 종류

 

  • 입출력 성능(BufferedInputStream/BufferedOutputStream)
  • 기본 데이터 타입 출력(DataInputStream, DataOutputStream)
  • 객체 입출력(ObjectInputStream/ObjectOutputStream) 등의 기능을 제공하는 보조스트림이 있다

 

EX)
FileInputStream fis = new FileInputStream("sample.txt"); //기반 스트림 생성
BufferedInputStream bis = new BufferedInputStream(fis); //보조스트림 생성
bis.read(); //보조스트림으로부터 데이터 읽어옴

 

 

 

 

 

 

성능 향상 보조 스트림

 

  • 느린 속도로 인해 입출력 성능에 영향을 미치는 입출력 소스를 이용하는 경우 사용
  • 입출력 소스와 직접 작업하지 않고 버퍼에 데이터를 모아 한꺼번에 작업을 하여 실행 성능을 향상
    (입출력 횟수를 줄임)

 

  • BufferedInputStream/Reader

 

 

 

 

  • BufferedOutputStream/Writer

 

 

 

 

 

 

 

 

 

 

형변환 보조 스트림

 

  • 기본 스트림이 byte 기반 스트림이고, 보조 스트림이 char 기반 스트림인 경우에 사용
  • 형변환 보조 스트림의 종류
System.in : 콘솔로부터 데이터를 입력 받음
System.out : 콘솔로 데이터를 출력
System.err : 콘솔로 데이터를 출력

 

  • ex : 
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));


System.in을 InputStreamReader로 변환하여 바이트기반 스트림을 문자 기반 스트림으로 변환 후 버퍼를 이용한
보조스트림과 연결

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

 

 

 

 

Application1
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Application1 {

	public static void main(String[] args) {

		/* java.io 패키지의 입출력 스트림은 기본 스트림과 
		 * 필터 스트림으로 분류할 수 있다.
		 * 기본 스트림은 외부데이터에 직접 연결이 되는 스트림이고
		 * 필터 스트림은 외부 데이터에 직접 연결하는 것이 아니라
		 * 기본 스트림에 추가로 사용할 수 있는 스트림이다.
		 * 주로 성능을 향상 시키는 목적으로 사용되며 생성자를 보면
		 * 구분이 가능하다.
		 * 생성자 쪽에 매개변수로 다른 스트림을 이용하는 클래스는
		 * 필터 스트림이라고 볼 수 있다.  */
		
		
		
		
		/* 버퍼를 이용해서 성능 향상을 시키는 보조스트림 */
		/* BufferedInputStream/BufferedOutputStream */
		/* BufferedReader/BufferedWriter */
		
		
		
		
		/* BufferedWriter 인스턴스 생성 */
		BufferedWriter bw = null;	//임포트 필요
		
		
		
		
		
		try {
			/* IOException e 핸들링 */
			bw = new BufferedWriter(new FileWriter("src/com/greedy/section03/filterstream/testBuffered.txt"));

			bw.write("안녕하세요\n");
			bw.write("반갑습니다\n");
			
			/* 버퍼를 이용하는 경우 버퍼가 가득 차면 자동으로 내보내기를하지만
			 * 버퍼가 가득 차지않은 상태에선 강제로 내보내기 해야한다.
			 * 이때 flush()를 해주면 파일에 기록된다. */
			
			bw.flush();
			
//			안녕하세요
//			반갑습니다
			
			
			
		} catch (IOException e) {
			e.printStackTrace();
			
		} finally {
			
			/* close()를 호출하면 내부적으로 flush()를 하고나서 
			 * 자원을 반납한다. */
			
			
			if (bw != null) {
				
				try {
					/* close도 try-catch 구문으로 IOException을 
					 * 핸들리 해 주어야 한다. */
					bw.close();
					
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		
		
		
		
		
		
		/* BufferedReader
		 * 버퍼에 미리 읽어온 후 한 줄 단위로 읽어들이는 기능을 제공하며
		 * 기본 스트림보다 성능을 개선시킨다.
		 *  */
		
		
		BufferedReader br = null;
		
		
		
		try {
			br = new BufferedReader(new FileReader("src/com/greedy/section03/filterstream/testBuffered.txt"));

			/* readLine() 메소드를 추가로 제공한다.
			 * 버퍼의 한 줄을 읽어와서 문자열로 반환한다. */
			
			String temp;
			while((temp = br.readLine()) != null ) {	
				// 더이상 읽을값이 없으면 null 반환
				System.out.println(temp);
				
			}
			
			
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		

	}

}

 

 

Application2
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Application2 {

	public static void main(String[] args) {

		/* 형변환 보조 스트림
		 * 기본 스트림이 byte 기반 스트림이고, 
		 * 보조스트림이 char 기반스트림인 경우에 사용된다. 
		 * 중간에서 변환을 해주는 용도이다.
		 * */
		
		
		/* 표준 스트림
		 * 자바에서는 콘솔이나 키보드 같은 표준 입출력 장치로부터
		 * 데이터를 입출력하기 위한 스트림을 표준 스트림 형태로 
		 * 제공하고 있다. System 클래스의 필드 in,out,err가
		 * 대상 데이터의 스트림을 의미한다.
		 * 
		 * System.in (InputStream) : 콘솔로부터 데이터를 입력받는다.
		 * System.out (PrintStream) : 콘솔로 데이터를 출력한다.
		 * System.err (PrintStream)  : 콘솔로 데이터를 출력한다.
		 * 	
		 * 즉, 자주 사용되는 자원에 대해 미리 스트림을 생성해두었기 때문에
		 * 개발자가 별도로 스트림을 생성하지 않아도 된다.
		 * 
		 * */
		
		
		/* 이런 표준 스트림 중 콘솔로부터 읽어오는 기반 스트림이 InputStream인데
		 * Buffer를 이용해서 성능을 향상 시키고 싶은 경우에 
		 * 형변환 보도스트림을 사용할 수 있다. 
		 * 
		 * */
		
		
		
		
		
		/* 보조 스트림을 통해 기반 스트림을 '형변환' 해주어야 보조스트림과 연결할 수 있다. */
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		
		/* readLine() : '한줄씩' 입력받음 */
		
		try {
			System.out.println("문자열 입력 : ");
			String value = br.readLine();
			System.out.print("value : " + value);			
			
		} catch (IOException e) {

			e.printStackTrace();
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
			}
		} 
		
		
			
			System.out.println();
			
		
		/* 출력을 위한 것도 동일한 방식으로 사용할 수 있다. */
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
			
		try {
			bw.write("java oracle jdbc");
		} catch (IOException e) {
			e.printStackTrace();
			
		} finally {
			if (bw != null) {
				try {
					bw.close();
				} catch (IOException e) {
					e.printStackTrace();
			}
		} 
			
		}
			
	}
	}
	
}

 

 

Application3
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Application3 {

	public static void main(String[] args) {


		/* 외부 데이터로부터 읽어오는 데이터를 바이트형으로만 읽어오면
		 * 정수, 문자, 문자열 등 여러 데이터 타입을 취급하는 경우 
		 * 별도로 처리를 해주어야 한다.
		 * 
		 * 예) 정수 입력 받아 처리하려면 parsing을 해주어야 한다.
		 *  */
		
		
		
		/* 데이터 자료형 별로 처리하는 기능을 추가한 보조 스트림을 제공하고 있다.
		 * DataInputStream/DataOutputStream */
		
		
		
		
		/* DataOutputStream
		 * 데이터 형 별로 파일에 기록하는 DataOutputStream 인스턴스 생성 */
		
		
		
		DataOutputStream dout = null;
		
		
		
		try {
			// 보조 스트림이므로 기반 스트림 필요
			dout = new DataOutputStream(new FileOutputStream("src/com/greedy/section03/filterstream/score.txt"));

			
			
			
			/* 파일에 자료형별로 기록 */
		
			dout.writeUTF("김영희");	//문자열을 입력하려면 writeUTF 이용
			dout.writeInt(95);
			dout.writeChar('A');
			dout.writeUTF("김철수");
			dout.writeInt(87);
			dout.writeChar('B');
			dout.writeUTF("홍길동");
			dout.writeInt(73);
			dout.writeChar('C');
			

			
			
			
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			
			
		}
				
			catch (IOException e) {
				e.printStackTrace();
		} finally {
			if (dout != null) {
				try {
					dout.close();
				} catch (IOException e) {
					e.printStackTrace();
			}
		} 
			
		}
		


		/* text 파일에 int 부분이 제대로 해석 되지않고 결과가나옴
		 * 데이터로 읽어와서 다시 사용해야
		 *  */
		
		
		
		/* 데이터형 별로 읽어오는 DataInputStream 인스턴스 작성 */
		DataInputStream din = null;
		
		
		try {
			
			din = new DataInputStream(new FileInputStream("src/com/greedy/section03/filterstream/score.txt"));

			
			
				
				/* 파일에 기록한 순서대로 타입을 읽어와야한다. utf -> int -> char */
				/* 만약 순서를 임의로 바꿀 시 올바르게 데이터를 읽어오지 못한다. */
			
				System.out.println(din.readUTF() + ", " + din.readInt() + ", " + din.readChar());
				System.out.println(din.readUTF() + ", " + din.readInt() + ", " + din.readChar());
				System.out.println(din.readUTF() + ", " + din.readInt() + ", " + din.readChar());
				
				
				/* 무한루프로 읽어들이게 되면 파일에 더이상 읽을 것이 없는 경우
				 * EOFException을 발생시킨다.
				 * catch 블럭에 EOFException을 핸들링하는 코드를 추가한다.
				 *  */
				
				
				
				
			
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (din != null) {
				try {
					din.close();
				} catch (IOException e) {
					e.printStackTrace();
			}
		} 
			
		}
		
		
		
	}

}

 

 

 

 

 

 

 

 

 

 

 

 

 

기본 데이터 타입 보조 스트림

 

기본 자료형 별 데이터를 읽고 쓰기 가능하도록 기능을 제공

(단, 입력된 자료형의 순서와 출력 될 자료형의 순서는 일치해야 함)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

직렬화와 역직렬화

 

 

직렬화(serialization)
  • Serializable인터페이스를 implements하여 구현

 

serialVersionUID 필드
  • 직렬화된 클래스와 같은 클래스임을 알려주는 식별자
컴파일 시 JVM이 자동으로 serialVersionUID 정적필드를 추가해 주기 때문에 별도로 작성하지 않아도
오류는 나지 않지만 자동 생성 시 역질력화에서 예상하지 못한 InvalidClassException을 유발할 수
있으므로 명시해 줄 것을 권장

 

ex)
private static final long serialVersionUID = -6423919775137290062L;

 

 

 

 

Application4
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import com.greedy.section03.filterstream.dto.MemberDTO;




public class Application4 {

	public static void main(String[] args) {
			
		
		
		
		/* 객체단위로 입출력을 하기 위한 
		 * ObjectInputStream/ObjectOutputStream 을 살펴보자
		 *  */

		
		
		
		MemberDTO[] outputMembers = {
				new MemberDTO ("user01", "pass01", "김영희", "young7777.com", 25, '여', 1250.7),
				new MemberDTO ("user02", "pass02", "김철수", "chul999.com", 27, '남', 1221.6),
				new MemberDTO ("user03", "pass03", "유관순", "yoo123.com", 18, '여', 1234.3)			
		};
		
		
		
		
		ObjectOutputStream objOut = null;
		
		
		
		try {
			
			
			objOut = new ObjectOutputStream(new BufferedOutputStream
					(new FileOutputStream("src/com/greedy/section03/filterstream/testObjectStream.txt")));

			
			
			for(int i = 0; i < outputMembers.length; i++) {
				objOut.writeObject(outputMembers[i]);
				
				
		}
			
			
			
		objOut.flush();
		
			
		
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();

		} catch (IOException e) {
			e.printStackTrace();
			
		} finally {
			if (objOut != null) {
				try {
					objOut.close();
				} catch (IOException e) {
					e.printStackTrace();
			}
				
			}
		}
		
		
		
		
		/*  오류발생 : NotSerializableException 
		 *  이는 직렬화 처리를 해주지않아서 발생하는 에러이다.
		 *  
		 *  직렬화란?
		 *  자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부에서도 사용할 수 있도록
		 *  바이트(byte) 형태로 데이터를 변환하는 기술을 말한다.
		 *  
		 *  반대로 바이트로 변환 된 데이터를 다시 객체로 변환하는 기술을 역직렬화라고 한다.
		 *  
		 *  
		 *  */
		
		
		
		MemberDTO[] inputMembers = new MemberDTO[3];
		
		ObjectInputStream objIn = null;
		
		try {
			objIn = new ObjectInputStream(new BufferedInputStream(new FileInputStream("src/com/greedy/section03/filterstream/testObjectStream.txt")));

			
			/* 읽어온 object가 해당하는 class가 없을 경우 ClassNotFoundException
			 * 이 발생할 수 있다. */
//			while(true) {
//			System.out.println(objIn.readObject());
//		}
			
			for (int i = 0; i < inputMembers.length; i++) {
				inputMembers[i] = (MemberDTO) objIn.readObject();
			}
			
		
		
		
		
		
		} catch (FileNotFoundException e) {
			e.printStackTrace();
//		} catch (EOFException e) {
//			System.out.println("파일을 모두 읽어왔습니다.");
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (objIn != null) {
				try {
					objIn.close();
				} catch (IOException e) {
					e.printStackTrace();
			}
				
			}
		}
		
		
		
		
		for (MemberDTO member : inputMembers) {
			System.out.println(member);
		}
		
		
		/* 직렬화 처리한 클래스에서 transient 된 point 필드는 숨김처리 되었다. */
//		MemberDTO [id=user01, pwd=pass01, name=김영희, email=young7777.com, age=25, gender=여, point=0.0]
//		MemberDTO [id=user02, pwd=pass02, name=김철수, email=chul999.com, age=27, gender=남, point=0.0]
//		MemberDTO [id=user03, pwd=pass03, name=유관순, email=yoo123.com, age=18, gender=여, point=0.0]
		

		
		
		
	}

}

 

 

class MemberDTO implements java.io.Serializable


/* 객체로 입출력을 하기 위해서는 반드시 직렬화 처리를 해야한다. 
 * java.io.Serializable 라는 인터페이스를 상속받아야 한다.
 * 
 * 직렬화 대상 클래스에 Serializable 인터페이스만 구현하면
 * 직렬화가 필요한 상황인 경우 해당 인터페이스를 상속받았을시 데이터를 직렬화 처리한다.
 * 
 * */



/* 노란줄이 간 이유 : does not declare a static final serialVersionUID field of type long */
public class MemberDTO implements java.io.Serializable {

	/* 직렬화 시의 id와 역직렬화시의 id가 불일치하면 역직렬화에 실패한다.
	 * 명시적으로 작성해두지 않으면 jvm이 자동 생성하므로 수정사항 발생 시 id도 변경된다.
	 * 따라서 명시적으로 작성해두는 것을 권장한다.  */
	private static final long serialVersionUID = 7171399052371122105L;
	
	
	
	
	/* 회원 정보를 관리하기 위한 용도의 DTO 클래스 */

	
	/* 필드 선언 */
	private String id;
	private String pwd;
	private String name;
	private String email;
	private int age;
	private char gender;
	/* 직렬화 대상에서 제외하고 싶은 필드의 경우 transient키워드를 이용할 수 있다. */
	private transient double point; 	// 입출력의 대상에서 제외하겠다는 뜻
	
	
	
	
	/* 기본 생성자 */
	public MemberDTO() {}


	/* 매개변수 생성자 */
	public MemberDTO(String id, String pwd, String name, String email, int age, char gender, double point) {
		super();
		this.id = id;
		this.pwd = pwd;
		this.name = name;
		this.email = email;
		this.age = age;
		this.gender = gender;
		this.point = point;
	}


	
	
	/* 게터세터 생성 */
	public String getId() {
		return id;
	}


	public void setId(String id) {
		this.id = id;
	}


	public String getPwd() {
		return pwd;
	}


	public void setPwd(String pwd) {
		this.pwd = pwd;
	}


	public String getName() {
		return name;
	}


	public void setName(String name) {
		this.name = name;
	}


	public String getEmail() {
		return email;
	}


	public void setEmail(String email) {
		this.email = email;
	}


	public int getAge() {
		return age;
	}


	public void setAge(int age) {
		this.age = age;
	}


	public char getGender() {
		return gender;
	}


	public void setGender(char gender) {
		this.gender = gender;
	}


	public double getPoint() {
		return point;
	}


	public void setPoint(double point) {
		this.point = point;
	}


	
	
	
	/* toString() 오버라이드 */
	@Override
	public String toString() {
		return "MemberDTO [id=" + id + ", pwd=" + pwd + ", name=" + name + ", email=" + email + ", age=" + age
				+ ", gender=" + gender + ", point=" + point + "]";
	}
	
	
	
}

 

 

 

 

 

 

 

 

 

 

 

예외처리 방법

 

예외 처리 방법1) finally로 예외 처리
  • 예외 처리 구문과 상관 없이 반드시 수행해야 하는 경우 작성
  • (보통 사용한 자원을 반납할 목적)

 

 

 

 

 

 

예외 처리 방법2) try~with~resource로 예외 처리
  • 자바7에서 추가된 기능으로 finally에서 작성했던 close처리를 try문에서 자동으로 close처리

 

 

 

 

 

 

 

Application1
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Application1 {

	public static void main(String[] args) {


		
		
		/* 위에서 배운 예외처리를 가장 많이 활용하는 것이 io(input/output)
		 * 이다. 아직 io를 배우지 않았지만 io문법보다는 try-catch 블럭의
		 * 실제 사용과 흐름에 집중해서 살펴보자. */
		
		
		
		/* FileNotFoundException 발생 */
		// BufferedReader in = new BufferedReader(new FileReader("test.dat"));

		
		
		
		BufferedReader in = null;
		/* try 블럭 내부와 finally 블럭 내부에서 모두 사용하기위해
		 * 지역변수가 아닌 전역 변수로 선언
		 * 즉, finally 블럭에서 사용하려면 레퍼런스 변수를 try 블럭
		 * 밖에서 선언해야 한다. */
		
		
		
		try {
			/* FileReader라는 클래스의 생성자에 예외를 throws해놓았다.
			 * 사용하는 쪽에서 반드시 예외 처리를 해야하기 때문에 try-catch
			 * 블럭안에서 생성자를 호출하여 인스턴스를 생성해야 한다. */
			
			in = new BufferedReader(new FileReader("test.dat"));
			// FileNotFoundException: test.dat 
			// (지정된 파일을 찾을 수 없습니다)
			
			String s;
			
			
			
			
			/* readLine메소드도 IOException을 throws 하므로
			 * catch 블록을 추가해서 예외처리 구문을 작성해야 한다. */
			
			while ((s = in.readLine()) !=null) {
				System.out.println(s);
			}
			
			
			
			
			/* FileNotFoundException와 EOFException 을
			 * 동시에 처리할 수 있다. 
			 * 같은 레벨의 자손을 한 번에 처리할 수 있다.
			 *  */
		} catch (FileNotFoundException | EOFException e) {

			e.printStackTrace();
		} catch (IOException e) {
			
			
			
			
			
			/*입출력에 관한 추상화 된 예외 클래스이다.
			 * FileNotFoundException와 EOFException은 IOException의 후손이다.
			 * 
			 * catch 블럭은 여러개를 작성할 시 상위 타입이 하단에 오고 
			 * 후손 타입이 먼저 작성되어야 한다.
			 * 
			 * */
			e.printStackTrace();
			
			
			
			
		} finally {
			
			/* 파일을 스트림 해왔다면 반드시 닫아주는 작업이 필요
			 * 예외 처리 구문과 상관없이 반드시 수행해야하는 경우 작성하며
			 * 보통 사용한 자원을 반납할 목적으로 사용하게 된다.
			 *  */
			
			try {
				
				/* 입출력에 사용한 스트림을 닫아주는 메소드이다.
				 * IOException을 위임한 메소드이기 때문에 finally 블럭
				 * 안이더라도 예외처리를 중첩으로 해주어야 한다. */	
				
				
				
				/* 그냥 실행하면 NullPointerException이 발생한다.
				 * 파일을 찾지 못해 객체를 생성하지 못하고 
				 * 레퍼런스 변수는 null 값을 가지고 있는데
				 * null 을 참조하는 상태에서 참조연산자 사용시 발생하는 예외이다.
				 * NullPointerException은 uncheckedException이므로
				 * try-catch로 처리하기 보다는 
				 * 보통은 if-else 구문으로 해결가능하다.
				 *  */
				// in.close();
				// java.lang.NullPointerException
				
				if(in != null) 
					in.close();
				
				
				
			} catch (IOException e) {

				e.printStackTrace();
				
			} 	// IOException 발생
			
		}
		
		
	}

}

 

 

Application2
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Application2 {

	public static void main(String[] args) {

		
		/* try-with-resource */
		/* JDK 1.7에서 추가된 문법이다.
		 * close 해야 하는 인스턴스의 경우 try 옆에 괄호안에서 생성하면
		 * 해당 try-catch 블럭이 완료될 때 자동으로 close 처리 해준다.
		 *  */
		
		
		/* 소괄호 안에서 스트림을 읽어온다. */
		try (BufferedReader in = new BufferedReader(new FileReader("test.dat"))) {
			 
			String s;
			while ((s = in.readLine()) != null) {
				System.out.println(s);
			}
			
		} catch (FileNotFoundException e) {

			e.printStackTrace();
			
		} catch (IOException e) {

			e.printStackTrace();
		}

		
	}

}

 

 

 

 

 

Exception과 오버라이딩
  • 오버라이딩 시 throws하는 Exception의 개수와 상관없이 같거나 후손 범위여야 함

Exception &lt;- IOE &lt;- EOFE &lt;- FileNotFound 순...

 

 

 

 

 

class SuperClass
import java.io.IOException;

public class SuperClass {

	
	/* 예외를 던지는 메소드를 하나 작성한다. */
	public void method() throws IOException {}
	
	
	
}

 

 

class SubClass extends SuperClass
import java.io.FileNotFoundException;
import java.io.IOException;

public class SubClass extends SuperClass {

			/* 예외없이 오버라이딩 할 수 있다. */
		//	@Override
		//	public void method() {}
	
	
//			/* 같은 예외를 던져주는 구문으로 오버라이딩 할 수 있다. */
//			@Override
//			public void method() throws IOException {}
	
	
			/* 부모의 예외 처리 클래스보다 상위의 예외로는 
			 * 후손클래스를 오버라이딩 할 수 없다. */
//			@Override
//			public void method() throws Exception {}
	
	
	
			/* 하지만 부모의 예외처리 클래스보다 더 하위에 있는 예외
			 * (즉, 더 구체적인 예외상황)인 경우에는 오버라이딩 할 수 있다. */
			@Override
			public void method() throws FileNotFoundException {}
	
	
	
}

 

 

 

 

 

 

입출력

 

 

 

 

File 클래스
  • 파일 시스템의 파일을 표현하는 클래스
  • 파일크기, 파일 속성, 파일 이름 등의 정보와 파일 생성 및 삭제 기능을 제공

 

 

File 인스턴스 생성
File file = new File(“file path");
File file = new File("C:/data/fileTest.txt");

 

 

 

 

파일/디렉토리 생성 및 삭제 메소드

 

 

 

 

 

 

파일/디렉토리 생성 및 삭제 메소드

 

 

 

Application
import java.io.File;
import java.io.IOException;

public class Application {

	public static void main(String[] args) {


		/* File을 이용한 스트림을 사용하기 앞서 
		 * File 클래스의 기본사용법을 확인 해보자. */
		
		/* jdk 1.0 부터 지원하는 API로 파일 처리를 수행하는 대표적인 클래스이다.
		 * 대상 파일에 대한 정보로 인스턴스를 생성하고
		 * 파일의 생성, 삭제 등등의 처리를 수행하는 기능을 제공하고 있다.  */
		
		
		/* 파일 클래스를 이용해서 인스턴스를 생성한다.
		 * 대상 파일이 존재하지 않아도 인스턴스를 생성할 수 있다.
		 * 메모리상에 인스턴스를 생성하기만 했기 때문 */
		File file = new File("src/com/greedy/section01/file/test.txt");
		
		/*실제로 만들어보자*/
		 try {
			/* createNewFile을 통해 파일을 생성할 수 있고 성공실패여부를
			 * boolean 으로 반환한다. */
			boolean createSuccess = file.createNewFile();
			
			/* 제대로 생성이 됐는지 확인 */
			/* 최초 실행시 새롭게 파일이 만들어지므로 true 가 반환
			 * 하지만, 파일이 한번 생성 되고 난 이후는 새롭게 파일을 만들지
			 * 않기 때문에 false를 반환한다. */
			System.out.println("createSuccess : " + createSuccess);
			// true (refresh 선행 필수)
			
		} catch (IOException e) {
			
			e.printStackTrace();
		}
		
		
		
		 
		 /* 생성한 파일의 정보 */
		 System.out.println("파일의 크기 : " + file.length() + "byte");
		 System.out.println("파일의 경로 : " + file.getPath());
		 System.out.println("현재 파일의 상위 경로 : " + file.getParent());
		 
		 /* 절대 경로란 최상위 루트 위치로부터의 경로를 의미한다. */
		 System.out.println("파일의 절대 경로 : " + file.getAbsolutePath());
		 
//		 파일의 크기 : 0byte
//		 파일의 경로 : src\com\greedy\section01\file\test.txt
//		 현재 파일의 상위 경로 : src\com\greedy\section01\file
//		 파일의 절대 경로 : D:\dev\1_java\workspace\chap14-io\src\com\greedy\section01\file\test.txt
		 
		 
		 
		 /* 파일 삭제 */
		 /* 삭제 후 성공 여부를 boolean 으로 반환한다.
		  *  */
		 
		 boolean deleteSuccess = file.delete();
		 
		 /* 지워졌는지 여부 확인 */
		 System.out.println("deleteSuccess : " + deleteSuccess);
//		 deleteSuccess : true
		 
		 

	}

}

 

 

 

 

 

 

 

 

 

 

입출력

 

 

 

입출력(IO)란?
  • Input과 Output의 약자로 컴퓨터 내부 또는 외부 장치와 프로그램 간의 데이터를 주고 받는 것
  • 장치와 입출력을 위해서는 하드웨어 장치에 직접 접근이 필요한데 다양한 매체에 존재하는 데이터들을
    사용하기 위해 입출력 데이터를 처리 할 공통적인 방법으로 스트림을 이용

 

 

 

 

 

 

 

 

 

 

 

스트림

 

 

스트림(Stream)이란?
  • 입출력 장치에서 데이터를 읽고 쓰기 위해서 자바에서 제공하는 클래스
  • 모든 스트림은 단반향이며 각각의 장치마다 연결할 수 있는 스트림 존재
  • 하나의 스트림으로 입출력을 동시에 수행할 수 없으므로 동시에 수행하려면 2개의 스트림이 필요

 

 

 

 

 

스트림 종류

 

기반 스트림이란? 실제 데이터가 전송되는 스트림, 보조스트림이란? 기반 스트림에 종속해 기능적인 역할을 하는 스트림

 

 

 

 

 

 

 

 

Application1
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Application1 {

	public static void main(String[] args) {

		
		/* 입출력과 관련된 API는 java.io 에서 제공하고 있다.
		 * API 문서에서 목록을 확인해보면 대부분 
		 * InputStream/OutputStream & Reader/Writer 로 끝난다.
		 * 이 중 InputStream과 Reader 는 데이터를 읽어오는 입력스트림이고
		 * OutputStream과 Writer는 데이터를 내보내는 출력스트림이다.
		 * 
		 * 또한 InputStream과 OutputStream은 데이터를 1바이트 단위로
		 * 입/출력을 하고 Reader와 Writer는 문자 (2 or 3바이트) 단위로
		 * 작업을 한다. 
		 * 
		 * 자바 프로그램과 연결되는 외부 데이터의 타입이 무엇인지는 클래스
		 * 이름을 보고 유추가 가능하다.
		 * InputStream/OutputStream & Reader/Writer 를 빼고 
		 * 남은 단어가 바로 외부 데이터의 타입이다.
		 * 
		 * ex : FileInputStream 은 InputStream을 제거하고 남은단어가
		 * File 이므로 외부 데이터는 File임을 알 수 있다.
		 * 
		 *  */
		
		
		
		/* FileInputStream */
		
		FileInputStream fin = null;
		
		try {
			
			/* 대상 파일이 존재하지 않는 경우 발생하는 
			 * FileNotFoundException 에 대해서 핸들링 해야 한다. */
			/* 인스턴스만 생성한 후 실행해보면 예외가 발생한 것을 볼 수 있다. */
			/* 파일을 직접 생성한 뒤 다시 실행 하면 예외가 발생하지 않는데 
			 * 스트림인스턴스가 정상적으로 생성되었기 때문이다.  */
			fin = new FileInputStream("src/com/greedy/section02/stream/testInputStream.txt");
			/* 파일 생성 : 해당 폴더 우클릭 - new - file - 하위 폴더 선택후 - 
			 * 파일이름.txt 입력 */
		
			int value;
			
			/* read()는 throw IOException이므로 
			 * 'add catch clause to surrounding try '
			 * 눌러서 catch block 추가
			 * read() : 파일에 기록 된 값을 순차적으로 읽어오고 더이상
			 * 읽어올 데이타가 없는 경우 -1반환
			 *  */
//			while ((value = fin.read()) != -1) {
//				
//				/* 값을 정수로 읽어온다. */
//				System.out.println(value);
//				
//				/* 문자로 출력하고 싶은 경우 형변환 하면 된다. */
//				System.out.println((char) value);
//			}
			
	/* 출력 */		
//			97
//			a
//			98
//			b
//			99
//			c
//			100
//			d
//			101
//			e
			
			
	/* 1byte 씩 읽어와야 하는 경우도 존재하긴 하지만 대부분의 경우 비효율적이다.
	 * byte 배열을 이용해서 한 번에 데이터를 읽어오는방법도 제공한다.
	 *  */
			
	/* File 클래스의 length()로 파일의 길이를 알 수 있다. */
	System.out.println("파일의 길이 : " + new File("src/com/greedy/section02/stream/testInputStream.txt").length());
			
	/* File의 길이만큼의 byte 배열을 만든다. */		
			
	int fileSize = (int) new File("src/com/greedy/section02/stream/testInputStream.txt").length();
	byte[] bar = new byte[fileSize];
	
	
	
	
	/* read() 메소드의 인자로 생성한 byte 배열을 넣어주면
	 * 파일의 내용을 읽어서 byte 배열에 기록해준다. */
	fin.read(bar);
	
	
	/* 해당 스트림은 파일의 끝까지 다 읽어들인 스트림이기 때문에 
	 * 위에 1바이트씩 읽어온 while 반복문을 주석해야 정상적으로 동작한다. */
	for (int i=0; i < bar.length; i++) {
		System.out.print((char) bar[i]);
	}
	
//	파일의 길이 : 5
//	abcde
	

			/* 한글 값을 입력하는 경우 한글이 깨져서 나온다.
			 * 한글은 한 글자에 3byte 이기 때문에 3byte 데이터를 
			 * 1byte로 읽어오면 글자가 깨지게 된다. */
			
			
	
	
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			
		} catch (IOException e) {
			e.printStackTrace();

		} finally {
			
			/* fin 인스턴스가 null 이 아닌 경우 자원 반납을 해야한다. */
			if (fin != null) {
				
				 try {
					 /* 자원해제를 하는 경우에도 IOException을 핸들링 해야한다.
					  * 이미 자원이 반납 된 경우 발생하는 Exception이다.
					  *  */
					 
					 /* 자원 반납을 해야하는 경우
					  * 
					  * 1. 장기간 실행 중인 프로그램에서 스트림을 닫지않는 경우
					  * 다양한 리소스에 누수(leak)가 발생한다.
					  * 2. 뒤에서 배우는 버퍼를 이용하는 경우 마지막에 flush()로
					  * 버퍼에 있는 데이터를 강제로 전송해야 한다.
					  * 만약 잔류 데이터가 남은 상황에서 추가로 스트림을 사용한다면
					  * 데드락(deadlock)상태가 된다.
					  * 판단하기 어렵고 의도하지 않은 상황에서도 이런 현상이 발생할 수 있기
					  * 때문에 마지막에는 flush()를 무조건 실행해주는 것이 좋다.
					  * close() 메소드는 자원을 반납하며 flush() 를 해주기 때문에 
					  * close() 만 제대로 해주어도 된다.
					  *  */
					 
					fin.close();
					
					
				} catch (IOException e) {

					e.printStackTrace();
				}
			}
			
		}
		
	}

}

 

 

Application2
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Application2 {

	
	public static void main(String[] args) {


		
		
		
		/* FileReader */
		/* FileInputStream과 사용하는 방법이 거의 동일하다.
		 * 단, byte 단위가 아닌 character 단위로 읽어들이는 부분이 차이점이다.
		 * 따라서 2바이트던 3바이트던 글자단위로 읽어오기 때문에 
		 * 한글을 정상적으로 읽어올 수 있는 방식이다. */
		
		
		
		
		FileReader fr = null;
		
		
		
		
		try {
			/* 파일이 존재하지 않는 경우 파일을 찾지 못한다는 예외가 발생하므로
			 * 파일을 추가해서 정상적으로 스트림이 생성되게 한다.  */
			fr = new FileReader("src/com/greedy/section02/stream/testReader.txt");
			// testReader.txt (지정된 파일을 찾을 수 없습니다)
			/* 파일 생성 : 패키지에 대고 우클릭 - new - file - 해당패키지 재 클릭 -
			 * 파일명.txt 입력 */
			
			
			
			
			/* 파일 내용을 읽어오는 것도 동일하다. */
			/* 한글 값을 입력해도 하나의 글자 단위로 읽어온다. */
//			int value;
//			
//			while((value = fr.read()) != -1) {
//				System.out.print((char) value);
//			}
			// 안녕하세요 출력
			
			
			
			
			
			
			/* 단 byte 배열로 읽어오면 한글은 깨지게 되므로
			 * char 배열로 내용을 읽어오는 기능을 제공하고 있다.
			 *  */
			
			/* 배열의 길이를 구하기 위한 과정 */
			char[] carr = new char[(int) new File("src/com/greedy/section02/stream/testReader.txt").length()];
			
            /* 위에서 길이를 구했다면 이번엔 내용을 읽어줘야함 */
			fr.read(carr);
			
            /* 길이만큼 반복을 돌며 읽어와 char로 형변환 한 carr의 인덱스를 출력함 */
			for(int i = 0; i < carr.length; i++) {
				System.out.print(carr[i]);
			}
			
			
		
			
			
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			
		} catch (IOException e) {
			e.printStackTrace();
			
			
	/* 사용이 끝났다면 반드시 닫아주어야 함 */
			
		} finally {
			if (fr != null) {
				try {
					fr.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

InputStream
  • 바이트 기반 입력 스트림의 최상위 클래스로 추상 클래스
  • 추상클래스이므로 객체를 생성할 수 없다.

 

 

 

 

 

 

 

 

 

 

 

OutputStream
  • 바이트 기반 출력 스트림의 최상위 클래스로 추상 클래스
  • 추상클래스이므로 객체를 생성할 수 없다.

 

 

 

 

 

 

Reader
  • 문자 기반 입력 스트림의 최상위 클래스로 추상 클래스

 

 

 

 

 

 

 

 

Writer
  • 문자 기반 입력 스트림의 최상위 클래스로 추상 클래스

 

 

 

 

 

 

 

 

Application3
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Application3 {

	public static void main(String[] args) {

		/* FileOutputStream */
		
		/* 프로그램의 데이터를 파일로 내보내기 위한 용도의 스트림이다.
		 * 1바이트 단위로 데이터를 처리한다.
		 *  */
		
		
		
		FileOutputStream fout = null;
		
		
		
		
		try {
			
			/* 스트림으로 길을 만들고 도착지가될 파일을 괄호속에 입력한다. */
			/* FileNotFoundException을 핸들링해야하는 것은 동일하지만
			 * 실행해도 예외가 발생하지 않고 인스턴스가 잘 생성된다.
			 * 파일을 수동으로 만들어줘야하는 InputStream과 달리,
			 * OutputStream의 경우 대상 파일이 존재하지않으면 파일을 자동으로 
			 * 생성해준다. 
			 * 
			 * 단, 만약 지정할 경로의 스펠링을 틀린다면()오류가 발생한다.
			 * 경로가 정확한 상태에서 파일만 없는 것은 자동으로 만들어 주는 것이다.
			 * FileNotFoundException이 핸들링하는 부분은 경로 
			 * => (지정된 경로를 찾을 수 없습니다.)
			 * 
			 * */
			
			
			
			/* 두번째 인자로 true를 전달하면 이어쓰기가 된다.
			 * 전달하지 않으면 (false) 덮어쓰기가 된다.
			 *  */
			
			
			fout = new FileOutputStream("src/com/greedy/section02/stream/testOutputStream.txt");

			
			
			
			/* 이어쓰기 해보자 */
			fout = new FileOutputStream("src/com/greedy/section02/stream/testOutputStream.txt" /*, true*/);
			
			
			
			
			/* write() 메소드는 IOException을 핸들링 해야한다. */
			fout.write(97);
			// IOException 이 발생할 가능성이 있기에 catch 블록 작성
			
			
			
			
			/* byte 배열을 이용해서 한 번에 기록할 수도 있다.
			 * 10 : 개행문자 (엔터)
			 * */
			
			
			
			
			/* byte 배열을 이용해서 한 번에 기록할 수도 있다. */
			byte[] bar = new byte[] {98, 99, 100, 101, 102, 10, 103, 104, 105};
			fout.write(bar);
			
			
			
			
			/* bar의 1번 인덱스부터 3의 길이만큼 파일에 내보내기 */
			fout.write(bar, 1, 3); // 1번인덱스부터 3의 길이만큼 
			
			
			
			
			
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (fout != null) {
				try {
					/* IOException를 핸들링 해 주어야 한다. */
					fout.close();
					
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}

}

 

 

Application4
import java.io.FileWriter;
import java.io.IOException;

public class Application4 {

	public static void main(String[] args) {

		/* FileWriter */
		/* 프로그램의 데이터를 파일로 내보내기 위한 용도의 스트림이다.
		 * 1글자 단위로 데이터를 처리한다.
		 *  */
		
		FileWriter fw = null;
		
		
		try {
			
			/* IOException을 핸들링 해주기 위해 try-catch 구문실행 */
			/* 단, 경로를 잘못 입력하면 FileNotFoundException 
			 * 에러가 발생한다. Writer의 경우 대상파일이 존재하지 않으면 
			 * 파일을 자동으로 생성해준다.
			 * */
			
			
			
			/* 두번째 인자로 true 전달시 내용을 이어쓰기가 된다.
			 * 인자를 전달하지 않으면 (또는 false) 덮어쓰기가 된다. */
			fw = new FileWriter("src/com/greedy/section02/stream/testWriter.txt", true);

		
			
			/* write() 메소드도 IOException을 핸들링 해야 한다. */
			/* true 가 두번째 인자로 전해져있기 때문에 새로고침을 누를 수록
			 * a가 이어써서 늘어난다. */
			fw.write(97);
			
			
			
			/* 문자 단위 출력도 내부 버퍼를 사용하므로 쌓여있는 데이터를
			 * flush()로 내보내 줘야 최종적으로 파일에 출력되는 
			 * 모습을 확인 할 수 있다. 또는 close()로 자원을 반납하면
			 * 반납 전에 flush()가 호출되므로 파일에 출력되는 모습을
			 * 확인할 수 있다. 
			 * */
			
			// fw.flush();
			
			
			
			
			/* 문자 기반 스트림은 직접 char 자료형으로 내보내기도 가능하다. */
			fw.write('A');
			
			
			/* 혹은 char 배열도 가능하며 */
			fw.write(new char[] {'a', 'p', 'p', 'l', 'e'});
			
			
			/* 문자열도 가능하다. */
			fw.write("우리나라 대한민국");
			
			// 이어쓰는 상황이므로 새로고침시 같은 내용이 한번 더 출력된다.
// 출력 : 	aaaaAapple우리나라 대한민국
			
			
			
		} catch (IOException e) {
			e.printStackTrace();
			
			
		} finally {
			/* 1 바이트가 아닌 데이터를 다룰 때는 내부적으로
			 * 데이터를 쌓아서 다 차면 내보내기 때문에 의도한다면 
			 * 자체적으로 닫아서 내보내기 해주어야 한다. 
			 * 그게 flush와 close이다. */
			try {
				fw.close();
			} catch (IOException e) {
				e.printStackTrace();
				
			}
		}
		
		
		}

}

 

 

 

 

 

 

 

 

 

 

FileInputStream

 

  • 파일로부터 바이트 단위로 읽을 때 사용하며, 그림, 오디오,비디오,텍스트 파일 등 모든 종류의 파일 읽기 가능
  • InputStream의 하위 클래스로 InputStream의 메소드를 그대로 사용 가능
  • FileInputStream 인스턴스 생성
  • FileInputStream객체가 생성될 때 파일과 직접 연결
  • 만약 파일이 존재하지 않으면 FileNotFoundException이 발생하므로 예외처리 필수
FileInputStream fis = new FileInputStream("C:/data/test.txt");

 

 

 

 

 

 

 

FileReader

 

  • 텍스트 파일로부터 Byte 단위가 아닌 character 단위로 읽어 들임
    (2바이트이던 3바이트이던 글자 단위로 읽어 오기 때문에 한글을 정상적으로 읽어올 수 있음)
  • FileInputStream과 사용하는 방법이 거의 동일
  • Reader의 하위 클래스로 Reader의 메소드를 그대로 사용 가능

 

  • FileReader 인스턴스 생성
1. FileReader객체가 생성될 때 파일과 직접 연결 됨
2. 만약 파일이 존재하지 않으면 FileNotFoundException이 발생하므로 예외처리 필수
FileReader fr = new FileReader("C:/data/test.txt");
FileReader fr = new FileReader(new File("C:/data/test.txt"));

 

 

 

 

 

 

 

 

FileOutputStream

 

  • 파일로부터 바이트 단위로 출력할 때 사용하며, 그림, 오디오,비디오,텍스트 파일 등 모든 종류의 파일 읽기 가능
  • OutputStream의 하위 클래스로 OutputStream의 메소드를 그대로 사용 가능
  • FileOutputStream 인스턴스 생성
FileOutputStream객체가 생성될 때 파일과 직접 연결
만약 파일이 존재하지 않으면 자동으로 생성하지만 이미 파일이 존재하는 경우 파일을 덮어쓰는 단점이 있음
FileIOutputStream fis = new FileOutputStream("C:/data/test.txt");

 

  • 만일 기존 파일에 이어서 계속 추가 작성하고 싶다면 아래와 같이 작성
FileIOutputStream fis = new FileOutputStream("C:/data/test.txt", true);

 

 

 

 

 

 

 

FileWriter

 

  • 텍스트 파일에 Byte 단위가 아닌 character 단위로 출력
    (FileReader와 마찬가지로 글자 단위로 데이터를 처리)
  • FileOutputStream과 사용하는 방법이 거의 동일
  • Writer의 하위 클래스로 Writer의 메소드를 그대로 사용 가능
  • FileWriter 인스턴스 생성
FileWriter객체가 생성될 때 파일과 직접 연결 됨
만약 파일이 존재하지 않으면 자동으로 생성하지만 이미 파일이 존재하는 경우 파일을 덮어쓰는 단점이 있음
FileWriter fw = new FileWriter("C:/data/test.txt");

 

  • 만일 기존 파일에 이어서 계속 추가 작성하고 싶다면 아래와 같이 작성
FileWriter fw = new FileWriter("C:/data/test.txt", true);

 

 

 

 

 

 

 

 

 

 

보조 스트림

 

 

  • 스트림의 기능을 향상시키거나 새로운 기능을 추가하기 위해서 사용
  • 보조 스트림은 실제 데이터를 주고 받는 스트림이 아니기 때문에 입출력 처리가 불가능
  • 기반 스트림을 먼저 생성한 후 이를 이용하여 보조 스트림을 생성

 

 

 

 

 

 

 

 

보조 스트림의 종류

 

  • 입출력 성능(BufferedInputStream/BufferedOutputStream)
  • 기본 데이터 타입 출력(DataInputStream, DataOutputStream)
  • 객체 입출력(ObjectInputStream/ObjectOutputStream) 등의 기능을 제공하는 보조스트림이 있다

 

EX)
FileInputStream fis = new FileInputStream("sample.txt"); //기반 스트림 생성
BufferedInputStream bis = new BufferedInputStream(fis); //보조스트림 생성
bis.read(); //보조스트림으로부터 데이터 읽어옴

 

 

 

 

 

'Programming > JAVA' 카테고리의 다른 글

자바의 정석 ch13-3~6 : 쓰레드의 구현과 실행  (1) 2023.04.10
입출력 (I/O) 2  (0) 2022.01.14
예외 처리  (0) 2022.01.11
컬렉션  (0) 2022.01.10
제네릭과 컬렉션  (0) 2022.01.07

 

 

 

Map

 

Map인스턴스란?
  • 키(key/구분값)와 값(value)으로 구성되어 있으며, 키와 값은 모두 인스턴스이다.
  • 키는 중복 저장을 허용하지 않고(Set방식), 값은 중복 저장 가능(List방식)
  • 키가 중복되는 경우, 기존에 있는 키에 해당하는 값을 덮어 씀
  • 키와 값을 합친 덩어리를 Entry라 부른다.
  • 구현 클래스 : HashMap, HashTable(HashMap의 이전버전), LinkedHashMap, Properties, TreeMap

 

 

 

 

 

 

Map 계열 주요 메소드

 

 

 

 

 

 

Application1
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class Application1 {

	public static void main(String[] args) {

		/* Map 인터페이스의 특징 */
		/* Collection 인터페이스와는 다른 저장 방식을 가진다.
		 * 키(key)와 값(value)을 하나의 쌍으로 저장하는 방식을 사용한다.
		 * 
		 *  키(key)란?
		 *  값(value)을 찾기 위한 이름 역할을 하는 객체를 의미한다.
		 *  
		 *  1. 요소의 저장 순서를 유지하지 않는다.
		 *  2. 키는 중복을 허용하지 않지만, 키가 다르면 중복 되는 값은 저장 가능하다.
		 *  
		 *  
		 *  HashMap, HashTable, TreeMap 등의 대표적인 클래스가 있다.
		 *  HashMap이 가장 많이 사용 되며 HashTable은 jdk 1.0부터 제공되며
		 *  HashMap과 동일하게 동작 된다. 하위 호환을 위해 남겨놓았기 때문에 
		 *  가급적이면 HashMap을 사용하는 것이 좋다. 
		 *  
		 *  */
		
		
		
		
		/* HashMap 인스턴스 생성 */
		
		HashMap hmap = new HashMap();
		// Map hmap2 = new HashMap();;
		
		
		
		
		/* 키와 값 쌍으로 저장한다.
		 * 키와 값 둘다 반드시 객체여야 한다.
		 *  */
		hmap.put("one", new Date());
		hmap.put(12, "red apple");
		hmap.put(33, 123);
		
		/* 기본자료형은 오토박싱 처리된다. : int => Integer */
		
		/* 저장 순서 유지하지 않음 */
		System.out.println("hmap : " + hmap);
//		hmap : {33=123, one=Tue Jan 11 09:25:59 KST 2022, 12=red apple}
		
		
		
		
		
		/* 키는 중복 저장 되지 않음 (set방식) : 최근 값으로 덮어쓰기 */
		hmap.put(12, "yellow banana");
		System.out.println("hmap : " + hmap);
		
//		hmap : {33=123, one=Tue Jan 11 09:25:59 KST 2022, 12=yellow banana}
		
		
		
		
		/* 키가 다르면 값 객체 저장은 중복으로 가능함 */
		hmap.put(11, "yellow banana");
		System.out.println("hmap : " + hmap);
//		hmap : {33=123, one=Tue Jan 11 09:26:24 KST 2022, 11=yellow banana, 12=yellow banana}
		
		
		
		
		/* 값 객체의 내용을 가져올 때 */
		System.out.println("키 11에 대한 객체 : " + hmap.get(11));
		// 키값을 전달시 value값을 리턴한다.
		// 키 11에 대한 객체 : yellow banana
		
		
		
		
		/* 키 값을 가지고 삭제를 처리할 때 */
		hmap.remove(11);
		System.out.println("hmap : " + hmap);
//		hmap : {33=123, one=Tue Jan 11 09:28:43 KST 2022, 12=yellow banana}
		
		
		
		
		/* 저장 된 객체 수를 확인할 때 */
		System.out.println("hmap에 저장된 객체 수 : " + hmap.size());
//		hmap에 저장된 객체 수 : 3
		
		
		
		
		
		/* 노란줄이 생기는 이유? 제네릭을 사용하지 않았기 때문 */

		
		/* 제네릭 설정한 HashMap 인스턴스 생성 */
		HashMap<String, String> hmap2 = new HashMap<>();
		
		
		hmap2.put("one", "java");
		hmap2.put("two", "oracle");
		hmap2.put("three", "jdbc");
		hmap2.put("four", "html");
		hmap2.put("five", "css");
		
		
		
		
		
		
		/* 방법 1. ketset()을 이용해서 키만 따로 set 으로 만들고,
		 * iterator()로 키에 대한 목록을 만든다.
		 *  */
//		Set<String> keys = hmap2.keySet();
//		Iterator<String> keyIter = key.iterator();
		// ㄴ 한줄로 만들기
		
		Iterator<String> keyIter = hmap2.keySet().iterator();
		
		
		while(keyIter.hasNext()) {
			String key = keyIter.next();
			String value = hmap2.get(key);
			System.out.println(key + " = " + value);
			
//			four = html
//			one = java
//			two = oracle
//			three = jdbc
//			five = css
			
		}
		
		
		
		
		/* 방법2. 저장 된 value 객체들만 values()로 Collection으로 만든다. */
		
		Collection<String> values = hmap2.values();
		
		
		/* 2-1. iterator()로 목록 만들어서 처리 */
		Iterator<String> valueIter = values.iterator();
		while(valueIter.hasNext()) {
			System.out.println(valueIter.next());
		}
		
		
		
		/* 2.2 배열로 만들어서 처리 */
		Object[] valueArr = values.toArray();
		for (int i = 0; i < valueArr.length; i++) {
			System.out.println(i + " : " + valueArr[i]);
			
//			0 : html
//			1 : java
//			2 : oracle
//			3 : jdbc
//			4 : css
		}
		
		
		
		/* 방법3. Map의 내부 클래스인 EntrySet을 이용 : entrySet */
		Set<Map.Entry<String, String>> set = hmap2.entrySet();
		Iterator<Map.Entry<String, String>> entryIter = set.iterator();
		
		while(entryIter.hasNext()) {
			Map.Entry<String, String> entry = entryIter.next();
			System.out.println(entry.getKey() + " : " + entry.getValue());
			
//			four : html
//			one : java
//			two : oracle
//			three : jdbc
//			five : css
		}
		
		
		
	}
	

}

 

 

 

 

 

 

 

Properties
  • 키와 값을 String 타입으로 제한한 Map 컬렉션 - 문자열로만 받음
  • 주로 Properties는 프로퍼티(*.properties)파일을 읽어 들일 때 주로 사용
프로퍼티(*.properties)파일
- 옵션정보, 데이터베이스 연결정보, 국제화(다국어)정보를 기록하여 텍스트 파일로 활용
- 애플리케이션에서 주로 변경이 잦은 문자열을 저장하여 관리하기 때문에 유지보수를 편리하게 만들어 줌
- 키와 값이 ‘=‘기호로 연결되어 있는 텍스트 파일로 ISO 8859-1 문자셋으로 저장되고, 한글은 유니코드(Unicode)로 변환되어 저장

 

 

 

 

 

Properties 메소드

가져오기, 저장, 저장(property), 저장(xml), 읽어오기, 읽어오기, 읽어오기(xml)

 

 

 

Application2
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class Application2 {

	public static void main(String[] args) {

		/* Properties */
		/* 설정 파일의 값을 읽어서 어플리케이션에 적용할 때 사용한다. */
		
		Properties prop = new Properties();
		
		prop.setProperty("driver", "oracle.jdbc.driver.OracleDriver");
		prop.setProperty("url", "jsbc:oracle:this:@127.0.0.1:1521:xe");
		prop.setProperty("user", "student");
		prop.setProperty("password", "student");
		
		System.out.println(prop);
// {password=student, driver=oracle.jdbc.driver.OracleDriver, user=student, url=jsbc:oracle:this:@127.0.0.1:1521:xe}
		
		
		
		/* prop -> 문서화 하겠다 */
		try {
			prop.store(new FileOutputStream("driver.dat"), "jdbc driver");
			prop.store(new FileWriter("driver.txt"), "jdbc driver");
			prop.storeToXML(new FileOutputStream("driver.xml"), "jdbc driver");
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
		
		
		/* 파일로부터 읽어와서 Properties에 기록한다. */
		Properties prop2 = new Properties();
		
		// prop2.load(new FileInputStream("driver.dat"));
		
		try {
			// prop2.load(new FileInputStream("driver.dat"));
			// prop2.load(new FileReader("driver.txt"));
			prop2.loadFromXML(new FileInputStream("driver.xml"));
			
			
			/* Properties의 모든 키 값 목록을 대상 스트림에 내보내기 한다. */
			prop2.list(System.out);
			
			System.out.println(prop2.getProperty("driver"));
			System.out.println(prop2.getProperty("url"));
			System.out.println(prop2.getProperty("user"));
			System.out.println(prop2.getProperty("password"));
			
//			oracle.jdbc.driver.OracleDriver
//			jsbc:oracle:this:@127.0.0.1:1521:xe
//			student
//			student
			
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
		
	}

}

 

 

 

 

 

 

 

 

 

 

 

예외처리

 

 

 

 

 

 

오류와 에러

시스템 상에서 프로그램에 심각한 문제가 발행해서 실행중인 프로그램이 영향을 받는 것은 오류와 예외로
구분할 수 있음

 

오류(Error)
  • 시스템 상에서(물리적) 프로그램에 심각한 문제를 발생하여 실행중인 프로그램이 종료되는 것

 

예외(Exception)
  • 오류와 마찬가지로 비정상적으로 종료시키지만 미리 예측하고 처리할 수 있는 미약한 오류
  • 소프트웨어 개발자로서의 관심영역은 예외쪽에 있다.

 

 

 

 

예외 클래스 계층 구조
  • Exception과 Error 클래스 모두 Throwable클래스의 자손이다.
  • 예외 클래스들의 최상위 클래스는 Exception 클래스이다.
  • 예외처리를 해야하는 Checked Exception과 해주지 않아도 되는 Unchecked Exception으로 나뉜다.

 

IOException은 반드시 체크해야하는 예외처리의 종류이다. 즉, Checked Exception이다.

 

 

 

 

 

 

 

 

예외처리

 

예외는 예외처리를 통해 코드의 흐름을 컨트롤 가능

 

 

예외 처리 방법
  •   1. thorws로 위임 (Exception 처리를 호출한 메소드에게 위임)
메소드 선언 시 throws ExceptionName문을 추가하여 호출한 상위 메소드에게 처리를 위임

 

 

  • 2. try-catch로 처리 (Exception이 발생한 곳에서 직접 처리)
- try : exception 발생할 가능성이 있는 코드를 안에 기술
- catch : try 구문에서 exception 발생 시 해당하는 exceptio에 대한 처리 기술
       여러 개의 exception처리가 가능하나 exception간의 상속 관계 고려
- finally : exception 발생 여부와 관계없이 꼭 처리해야 하는 로직 기술
       중간에 return문을 만나도 finally구문은 실행되지만
       System.exit();를 만나면 무조건 프로그램 종료
       주로 java.io나 java.sql 패키지의 메소드 처리 시 이용

 

 

 

 

 

 

Throws로 예외 던지기

위임은 완전한 해결책은 아니다.

 

 

 

 

 

try~cathch로 예외 처리

 

 

 

 

 

Application1
public class Application1 {

	public static void main(String[] args) throws Exception {

		
		
		
		/* 예외처리
		 * 
		 *  오류(Error)
		 *  시스템 상에서 프로그램에 심각한 문제를 발생하여 실행중인 프로그램이 
		 *  종료되는 것을 말한다.
		 *  이러한 오류는 개발자가 미리 예측하여 처리하는 것이 불가능하며,
		 *  오류에 대한 처리는 할 수 없다.
		 *  
		 *  예외(Exceptrion)
		 *  오류와 마찬가지로 실행 중인 프로그램을 비정상적으로 종료시키지만
		 *  발생할 수 있는 상황을 미리 예측하고 처리할 수 있는 미약한 오류를 말한다.
		 *  개발자는 이러한 예외에 대해 예외 처리를 통해 예외상황을 적절히 처리하여
		 *  코드의 흐름을 컨트롤 할 수 있다. 
		 *  
		 *  
		 *  */
		
		
		
		
		
		/* 예외처리 방법
		 * 
		 *  1. throws로 위임 : 나를 호출한 상위클래스로 던짐
		 *  2. try-catch로 처리 : 그자리에서 바로 처리
		 *  */
		
		
		
		
		/* 1. throws로 위임 */
		ExceptionTest et = new ExceptionTest();
		
		
		
		
		// et.checkEnoughMoney(10000, 50000);
		// 빨간줄의 원인? : 호출시 반드시 예외처리 해주어야 하기 때문
		// 1. throw, 2. try-catch
		
		
		
		
		/* 상품가격 10000원, 가진돈 50000원 -> 정상수행 */
		et.checkEnoughMoney(10000, 50000);
		// throws 선택시 메소드 위로 오류가 위임된다, 동시에 정상동작확인
		
//		가지고 계신 돈은 50000원 입니다.
//		상품을 구입하기 위한 금액이 충분합니다.
//		즐거운 쇼핑 하세요~
		
		
		/* 상품가격 50000원, 가진돈 10000원 -> 정상수행  */
		et.checkEnoughMoney(50000, 10000);
		/* 에러 발생 구문 이하 구문은 동작하지 않고 되돌아온다.
		 * 메인 메소드 또한 예외를 처리하지 않고 위임했다.
		 * 따라서 프로그램은 비정상적으로 종료되고 아래 구문은 출력되지않음 */
		
		System.out.println("프로그램을 종료합니다.");
		/* 예외 발생시 두번째 구문은 발동되지않음, 게다가 위임한 코드조차
		 * 예외에 대처하고 있지않으므로 에러 구문을 출력시킨다. */
		
		
	}

}

 

 

 Application2
public class Application2 {

	public static void main(String[] args) {


		/* 2. try-catch 를 이용한 방법 (예외 발생하지 않음) */
		
		ExceptionTest et = new ExceptionTest();
		
		
		
		
		/* 상품 가격 10000원, 가진 돈 50000원 */
		
		// et.checkEnoughMoney(10000, 50000);
		// 호출시 무조건 핸들링하라고 하는 오류가 발생한다.
		
		try {
			/* 예외 발생 가능성이있는 메소드는 try블럭안에서 호출한다. */
			/* 상품 가격 10000원, 가진 돈 50000원 */
			//et.checkEnoughMoney(10000, 50000);
			
			/* 상품 가격 50000원, 가진 돈 10000원 */
			et.checkEnoughMoney(50000, 10000);
			
			
			System.out.println("=======상품 구입 가능=======");
			
			
			
		} catch (Exception e) {
			/* Exception이 발생했을경우 catch 블럭쪽 코드가 실행된다.
			 * 예외발생없이 정상출력될 경우 catch 블럭쪽 코드는 실행되지않는다.
			 * 즉 위의 메소드 호출시 예외가 발생한 경우 catch블럭코드를 실행한다.
			 * 이때 예외 발생한 위치의 하단 코드는 동작하지않는다. */
			System.out.println("=======상품 구입 불가=======");
		}
		
		/* 프로그램 종료 확인 */
		System.out.println("프로그램을 종료합니다.");
		
		
		
		
		/* 예외 발생하지않을시 콘솔출력 - try */
//		가지고 계신 돈은 50000원 입니다.
//		상품을 구입하기 위한 금액이 충분합니다.
//		즐거운 쇼핑 하세요~
//		=======상품 구입 가능=======
//		프로그램을 종료합니다.
		
		
		/* 예외 발생시 콘솔출력 - catch */
//		가지고 계신 돈은 10000원 입니다.
//		=======상품 구입 불가=======
//		프로그램을 종료합니다.
		
		
	}

}

 

 

ExceptionTest
public class ExceptionTest {

	/* 예외를 발생시키는 메소드를 하나 작성한다. */
	public void checkEnoughMoney(int price, int money) throws Exception {
		
		System.out.println("가지고 계신 돈은 " + money + "원 입니다.");
		
		if (money >= price) {
			System.out.println("상품을 구입하기 위한 금액이 충분합니다.");
		} else {
			
			/* 강제로 예외 발생 
			 * 예외가 발생한다는것 = 어딘가에 해당 객체가 생성된다는 것
			 * 예외를 발생시킨 뒤 헤드에 throws 구문을 추가한다.
			 * 예외를 발생시킨 쪽에서는 throws로 예외에 대한 책임을 
			 * 위임해서 해당 예외에 대한 처리를 강제화 시킨다.
			 *  */
			throw new Exception();	 // throw = 발생한다로 해석
			// Unhandled exception type Exception
			// add throws Exception 클릭시 상위메소드에 처리를 넘김
		}
		
		/* 예외가 발생하지 않는 경우에만 실행한다. */
		System.out.println("즐거운 쇼핑 하세요~");
		
		
		
		
	}
	
	
	
}

 

 

 

 

 

 

 

 

 

사용자 정의 예외
  • Exception 클래스를 상속받아 예외 클래스를 작성하는 것

 

 

 

 

 

 

RuntimeException 후손 클래스

예외처리가 강제화 되어있지않다.

 

후손 클래스 설명
ArithmeticException 0으로 나누는 경우 발생
if문으로 나누는 수가 0인지 검사
NullPointerException Null인 참조 변수로 객체 멤버 시도 시 발생
객체 사용 전에 참조 변수가 null인지 확인
NegativeArraySizeException 배열 크기를 음수로 지정한 경우 발생
배열 크기를 0보다 크게 지정
ArrayIndexOutOfBoundsException 배열의 index범위를 넘어서 참조하는 경우
배열명.length를 사용하여 배열의 범위 확인
Class CastException Cast연산자 사용 시 타입 오류
instanceof연산자로 객체 타입 확인 후 cast연산

 

 

 

 

 

 

 

예외처리 방법

 

finally로 예외 처리
  • 예외 처리 구문과 상관 없이 반드시 수행해야 하는 경우 작성 (보통 사용한 자원을 반납할 목적)

 

 

 

 

 

 

 

NegativeException extends Exception
public class NegativeException extends Exception {

	/* 사용자 정의 예외를 만드려면 Exception을 상속받아야 함 */
	
	
	/* 기본 생성자 */
	public NegativeException() {}
	
	/* 매개변수 생성자 */
	public NegativeException(String message) {
		super(message);
	}
	
}

 

 

NotEnoughMoneyException extends Exception
public class NotEnoughMoneyException extends Exception {

	/* 사용자 정의 예외 클래스를 만들기 위해서는 Exception 클래스를 
	 * 상속 받으면 된다. Exception 클래스는 Throwable 클래스를 상속받아
	 * 구현되어 있다.
	 * 
	 *  Throwable은 Error 와 Exception 두 가지를 추상화 해서 만들었다.
	 *  예외처리는 Exception을 가장 최상휘 클래스로 여긴다.
	 *  */
	
	
	/* 기본생성자 */
	public NotEnoughMoneyException () {}
	
	
	/* 문자열을 부모 생성자 쪽으로 전달하며 초기화 하는 생성자 */
	public NotEnoughMoneyException (String message) {
		
		/* 예외 인스턴스 생성 시점에 예외 메세지를 부모 생성자 쪽으로
		 * 전잘해서 인스턴스를 생성한다. */
		super(message);
	}
	
	
	/* money와 price가 각각 음수로 입력되는 경우 일반적인 상식에서 벗어나는 
	 * 프로그램이 된다. 만약 각각 음수로 입력 되는 경우 발생시킬 예외를 
	 * NegativeException 으로 정의한다.
	 * 
	 * 그리고 이를 상속받는 PriceNegativeException과 
	 * MoneyNegativeException을 정의한다.
	 *  */
	
	
	
}

 

 

MoneyNegativeException extends NegativeException
public class MoneyNegativeException extends NegativeException{

	/* 앞서 정의한 사용자 정의 예외처리 클래스를 상속받게 한다.
	 * Throwable - Exception - NegativeException - MoneyNegativeException
	 * 의 상속관계가 된다. */
	
	/* 기본 생성자 */
	public MoneyNegativeException () {}
	
	/* 매개변수 생성자 */
	public MoneyNegativeException (String message) {
		
		super(message);
	}
}

 

 

PriceNegativeException extends NegativeException
public class PriceNegativeException extends NegativeException {

	/* 앞서 정의한 사용자 정의 예외처리 클래스를 상속받게 한다.
	 * Throwable - Exception - NegativeException 
	 * - MoneyNegativeException & PriceNegativeException
	 * 의 상속관계가 된다. */
	
	/* 기본 생성자 */
	public PriceNegativeException () {}
	
	/* 매개변수 생성자 */
	public PriceNegativeException (String message) {
		
		super(message);
	}
}

 

 

Application1
import com.greedy.section02.userexception.exception.MoneyNegativeException;
import com.greedy.section02.userexception.exception.NotEnoughMoneyException;
import com.greedy.section02.userexception.exception.PriceNegativeException;

public class Application1 {

	public static void main(String[] args) /*throws PriceNegativeException, MoneyNegativeException, NotEnoughMoneyException*/ {


		
		/* 사전에 정의 되어 있는 Exception의 종류는 굉장히 많이 있다.
		 * 하지만 RuntimeException의 후손 대부분은 예외처리를 강제화 하지 않는다.
		 * 간단한 조건문 등으로 처리가 가능하기 때문에 따로 강제화 하지않는다. */
		
		
		/* 사전에 정의 된 예외 클래스 외에 개발자가 우너하는 명칭의 
		 * 예외 클래스를 작성하는 것이 가능하다.
		 * extends Exception 으로 예외처리 클래스를 상속받아 더 구체적인
		 * 예외 이름을 정의하는 것이다.
		 * 
		 *  */
		
		

		
		ExceptionTest et = new ExceptionTest();
		
		
		/* 상품가격보다 가진 돈이 적은 경우 */
		//et.checkEnoughMoney(50000, 30000);
		/* 실행시 오류가 발생한다. 실행한 오류의 내용은 다음과 같다.
		 * 직접 설정한 오류가 출력됨을 확인할 수 있다. 
		 * 
		 * com.greedy.section02.userexception.
		 * exception.NotEnoughMoneyException: 
		 * 가진 돈 보다 상품 가격이 더 비쌉니다.*/
		
		
		
		
		
		
		/* try-catch 블럭으로 확인하기 */
		/* 정상적인 프로그램의 흐름을 만들기 위해서는 try-catch 블럭을 작성하는게 좋다. */
		
		
		try {
			/* 상품 가격보다 가진 돈이 적을 경우 (에러가 발생할 가능성있는 메소드를 넣는다.)*/
			/* 실행해보면 예외 종류와 에러 메세지가 출력된다. */
			// et.checkEnoughMoney(50000, 30000);
// 출력 : 	NotEnoughMoneyException: 가진 돈 보다 상품 가격이 더 비쌉니다.
			
			
			
			/* 상품가격을 음수로 입력한 경우 */
			// et.checkEnoughMoney(-50000, 50000);
// 출력 : 	PriceNegativeException: 상품가격은 음수일 수 없습니다.
			
			
			/* 가진 돈을 음수로 입력한 경우 */
			// et.checkEnoughMoney(50000, -50000);
// 출력 : 	MoneyNegativeException: 가지고 있는 돈은 음수일 수 없습니다.
			
			
			/* 정상적으로 구매가 가능한 돈을 가진 경우 */
			/* 위의 코드들을 주석하지 않으면 이 코드는 동작하지 않는다. 
			 * catch 블록으로 가는 것이다. */
			et.checkEnoughMoney(30000, 50000);
// 출력 : 	가진 돈이 충분합니다. 즐거운 쇼핑하세요~			
			
			
			
		} catch (Exception e) {	// 다형성을 이용해 상위개념 Exception으로 받음
			e.printStackTrace();
		}
		
		
		/* exception이 발생한 경우 catch 블록에 잡히기 때문에 if문 하위의 출력문은 출력되지 않는다. */
		

	}

}

 

 

ExceptionTest
import com.greedy.section02.userexception.exception.MoneyNegativeException;
import com.greedy.section02.userexception.exception.NotEnoughMoneyException;
import com.greedy.section02.userexception.exception.PriceNegativeException;

public class ExceptionTest {

	public void checkEnoughMoney(int price, int money) 
			throws PriceNegativeException, MoneyNegativeException, NotEnoughMoneyException{
			// throws Exception {
		/* 3개의 예외 클래스는 모두 Exception 클래스의 후손이다.
		 * (throws의 공통된 조상은 Exception이다.) 
		 * 그러므로 Exception만으로도 처리할 수 있다. */
		
		
		/* 아까는 Exception으로 예외를 발생시켰지만, 그건 그냥 '예외'
		 * 라는 의미이다. 예외 클래스의 이름만으로 어떠한 예외가 발생했는지
		 * 알 수 있도록 하기 위해서는 명명이 중요하다.
		 * 사용자 정의 예외 클래스를 추가할 것이다.
		 *  */
		
		/* 먼저 상품 가격이 음수인지 확인하고, 음수인 경우 예외를 발생시킨다. */
		if (price < 0) {
			throw new PriceNegativeException("상품가격은 음수일 수 없습니다.");
		}
		
		
		
		
		/* 가진 돈도 음수인지 확인하고, 음수인 경우 예외를 발생시킨다. */
		if(money < 0) {
			throw new MoneyNegativeException("가지고 있는 돈은 음수일 수 없습니다.");
			/* PriceNegativeException, MoneyNegativeException
			 * 둘 중 하나를 발생시킬 수 있는 메소드가 됨 */
		}
		
		/* 위의 두 값이 정상 입력 되었더라도 상품 가격이 가진 돈보다 큰 경우 예외 발생 */
		if (money < price) {
			throw new NotEnoughMoneyException ("가진 돈 보다 상품 가격이 더 비쌉니다.");
		}
		
		
		
		/* 모든 조건을 만족하는 경우 정상적으로 물건 구입 가능 */
		System.out.println("가진 돈이 충분합니다. 즐거운 쇼핑하세요~");
		
	}
	
	
}

 

 

Application2
import com.greedy.section02.userexception.exception.MoneyNegativeException;
import com.greedy.section02.userexception.exception.NotEnoughMoneyException;
import com.greedy.section02.userexception.exception.PriceNegativeException;

public class Application2 {

	public static void main(String[] args) {

		ExceptionTest et = new ExceptionTest();
		
		
		/* 이 메소드를 입력시 컴파일 에러가 뜨고 해결책을 누르면 아래와같이 뜬다. */
		// et.checkEnoughMoney(20000, 30000);
		
		
		
		try {
			
			/* 예외 발생 가능성이있는 메소드 호출 */
			et.checkEnoughMoney(30000, 50000);
			
			
			/* 예외 발생별로 catch 블럭을 따로 작성해서 처리할 수 있다. */
			
		} catch (PriceNegativeException e) {
			
			/* 예외 인스턴스 생성 시 전달한 메세지를 getMessage()로 가져올 수 있다. */
			System.out.println("PriceNegativeException 발생!");
			System.out.println(e.getMessage());
			
		} catch (MoneyNegativeException e) {
			System.out.println("MoneyNegativeException 발생!");
			System.out.println(e.getMessage());
			
		} catch (NotEnoughMoneyException e) {
			System.out.println("NotEnoughMoneyException 발생!");
			System.out.println(e.getMessage());
			
			
		} finally {
			
			/* 예외 발생 여부와 상관없이 실행할 내용 */
			/* finally 블록은 무조건 동작한다. */
			System.out.println("finally 블럭의 내용이 동작함");
			
		}
		
		/* 프로그램을 종료하는지 확인 */
		System.out.println("프로그램을 종료합니다.");
		
		
		
		
		
		
		/* 다음과 같이 예외사항이 처리됨을 확인할 수 있다. */
		
//		et.checkEnoughMoney(-20000, 30000); 인 경우 
//		PriceNegativeException 발생!
//		상품가격은 음수일 수 없습니다.
		
		
//		et.checkEnoughMoney(20000, -30000);
//		MoneyNegativeException 발생!
//		가지고 있는 돈은 음수일 수 없습니다.
		
//		et.checkEnoughMoney(50000, 30000);
//		NotEnoughMoneyException 발생!
//		가진 돈 보다 상품 가격이 더 비쌉니다.
		

//		et.checkEnoughMoney(30000, 50000);
//		가진 돈이 충분합니다. 즐거운 쇼핑하세요~
		
		
		
		
		
		/* finally 블럭 삽입시 다음과 같이 실행된다.  */
		
//		et.checkEnoughMoney(-30000, 50000);
//		PriceNegativeException 발생!
//		상품가격은 음수일 수 없습니다.
//		finally 블럭의 내용이 동작함
//		프로그램을 종료합니다.
		
//		et.checkEnoughMoney(30000, 50000);
//		가진 돈이 충분합니다. 즐거운 쇼핑하세요~
//		finally 블럭의 내용이 동작함
//		프로그램을 종료합니다.
		
		
		
	}

}

 

 

Application3
import com.greedy.section02.userexception.exception.MoneyNegativeException;
import com.greedy.section02.userexception.exception.NotEnoughMoneyException;
import com.greedy.section02.userexception.exception.PriceNegativeException;

public class Application3 {

	public static void main(String[] args) {


		/* multi-catch */
		/* jdk 1.7에서 추가된 구문으로
		 * 동일한 레벨의 다른 타입의 예외를 하나의 catch 블럭으로 다룰 수 있다.
		 *  */
		
		ExceptionTest et = new ExceptionTest();
		
		
		/* 예외 발생 가능성이 있는 메소드 호출 */
		/* et.checkEnoughMoney(20000, 10000); 입력 후 multi-catch 클릭 */
		
		
		try {
			et.checkEnoughMoney(20000, 10000);
			
		} 
		/* catch 블럭을 나열하는 경우 각 Exception의 상속관계를 고려해서 나열한다.
		 * Exception은 모든 타입의 Exception의 부모이기 때문에 먼저 동작하면 아래 catch 블록은
		 * 동작하지 않는다.
		 *  */
		
		catch (PriceNegativeException | MoneyNegativeException | NotEnoughMoneyException e) {
		
			/* 예외 클래스명, 예외 발생 위치, 예외 메세지 등을 
			 * stack 호출 역순으로 빨간색 글씨를 이용해서 
			 * 로그 형태로 출력해주는 기능 */
			e.printStackTrace();
			
			System.out.println(e.getClass() + "발생!");
			System.out.println(e.getMessage());
			
		} catch(Exception e) {	// 모든 타입의 Exception 의 부모
			System.out.println("모든 종류의 Exception 발생!");			
			
			/*PriceNegativeException , MoneyNegativeException 
			 * , NotEnoughMoneyException 외에서 발생한 예외를 처리하는 catch 블록이다.
			 * 이상태에서 문제가 없지만 만약 첫번째 catch 블럭 위로 올라가게 된다면
			 * 컴파일 에러가 발생한다.
			 * 
			 * 순서가 바뀔경우 다형성에 의해서 첫번째 캐치구문만 검사하고 
			 * 아래 블럭은 검사하지 않는다. -> 컴파일 에러
			 * 즉, catch 블럭은 여러개 나열될 수 있지만 가장 맨 위에 와야하는 것은
			 * 자식 catch 블럭이다. 
			 * 
			 * */
			
			
		}
		finally {
			System.out.println("finally 블럭의 내용이 동작함");
		}
		
		System.out.println("프로그램을 종료합니다.");

		
		
		/* 다음과같이 에러메세지가 콘솔창에 출력된다. */
//		NotEnoughMoneyException: 가진 돈 보다 상품 가격이 더 비쌉니다.
//		class com.greedy.section02.userexception.exception.NotEnoughMoneyException발생!
//		가진 돈 보다 상품 가격이 더 비쌉니다.
//		finally 블럭의 내용이 동작함
//		프로그램을 종료합니다.
		
		
		
	}

}

 

 

 

 

 

 

 

 

 

'Programming > JAVA' 카테고리의 다른 글

입출력 (I/O) 2  (0) 2022.01.14
입출력 (I/O)  (0) 2022.01.12
컬렉션  (0) 2022.01.10
제네릭과 컬렉션  (0) 2022.01.07
자바 API  (0) 2022.01.06

 

 

 

 

 

 

컬렉션

 

 

 

 

컬렉션(Collection)이란?
  • 여러 개의 다양한 데이터들을 쉽고 효과적으로 처리할 수 있도록 표준화 된 방법을 제공하는 클래스들의 집합
  • 데이터를 효율적으로 저장하는 자료구조와 데이터를 처리하는 알고리즘이 미리 구현되어 있음
  • Java.util 패키지하위 포함

 

 

 

자료구조란?
  • 데이터(자료)를 메모리에서 효율적으로 저장하기 위한 방법론

 

 

 

컬렉션의 주요 인터페이스

 

  • List 와 Set 인터페이스가 Collection 인터페이스를 상속

 

 

 

 

 

 

List

 

자료들을 순차적으로 나열한 자료구조로 인덱스로 관리되며, 중복해서 인스턴스 저장이 가능
  • 구현 클래스 : ArrayList, Vector, LinkedList

 

 

중간 삭제가 필요하다면 삭제할 인덱스 뒤의 데이터들을 앞으로 땡겨주는 작업이 필요하다. 중간 삽입 역시 뒤로 한칸씩 밀어주는 방식이 필요하다.

 

 

 

List 계열 주요 메소드

 

 

 

 

 

 

 

ArrayList

 

 

가장 많이 사용되는 컬렉션 클래스
  • 내부적으로 배열을 이용하여 요소(element, 값)를 관리하며, 인덱스를 이용해 배열 요소에 접근 가능
  • * 동기화 : 하나의 자원(데이터)에 대해 여러 스레드가 접근 하려 할 때 한 시점에서 하나의 스레드만
    사용할 수 있도록 하는 것

 

제네릭형식을 사용한다면 매번 타입을 형변환 해주어야하는 번거로움을 덜 수 있다.

 

 

 

 

 

배열의 문제점
  • 한번 크기를 지정하면 변경할 수 없음
    (저장할 공간의 크기가 부족 시 에러 발생 -> 할당 시 넉넉한 크기로 할당 (메모리 낭비)
    필요에 따라 공간을 늘리거나 줄이기 힘듬)
  • 배열에 기록된 데이터에 대한 중간 위치의 추가, 삭제가 불편
    (추가, 삭제 할 데이터부터 마지막 기록된 데이터까지 하나씩 뒤로 밀어내고 추가 (복잡한 알고리즘)
  • 한 타입의 데이터만 저장 가능

 

 

 

ArrayList의 특징
  • 저장하는 크기의 제약이 없음
  • 추가, 삭제, 정렬 등의 기능 처리가 간단하게 해결
    (자료구조가 내장되어 있어 따로 복잡한 알고리즘 불필요)
  • 여러 타입의 데이터가 저장 가능
    (기본적으로 제네릭을 붙여 사용하기 때문에 여러타입을 사용하는 경우는 잘 없다. 다만 인스턴스만 저장할 수 있기 때문에 기본 자료형을 저장해야 할 경우 Wrapper 클래스 사용)

 

 

 

 

 

Comparable, Comparator

 

 

 Collections.sort()
  • Collections.sort(List<T> list) 
: T인스턴스에 Comparable을 상속받아 compareTo 메소드 재정의를 통해 정렬 구현
(단 한가지 기준의 정렬)

 

  • Collections.sort(List<T> list, Comparator<T> c) 
: 지정한 Comparator클래스에 의한 정렬 (여러 기준의 정렬)

 

  • LinkedList
인접 참조를 링크해서 체인처럼 관리, 앞뒤로 서로의 링크를 참조한다.
(특정 인덱스에서 인스턴스를 제거하거나 추가하게 되면 바로 앞/뒤 링크만 변경하면 되기 때문에 인스터스
삭제와 삽입이 빈번하게 일어나는 곳에서는 ArrayList보다 성능이 뛰어남)

 

 

 

 

 

 

 

Application1
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

public class Application1 {

	public static void main(String[] args) {

		/* List 인터페이스를 구현한 모든 클래스는 요소의 저장 순서가 유지되며,
		 * 중복 저장을 허용한다.
		 * ArrayList, LinkedList, Vector, Stack이 있다.
		 * 
		 *  */
		
		/* ArrayList 
		 * 가장 많이 사용되는 컬렉션 클래스이다.
		 * JDK 1.2부터 제공된다.
		 * 내부적으로 배열을 이용하여 요소를 관리하며, 인덱스를 이용해 
		 * 배열요소게 빠르게 접근할 수 있다.
		 * 
		 *  ArrayList는 배열의 단점을 보완하기 위해 만들어졌다.
		 *  배열은 크기를 변결할 수 없고, 요소의 추가, 삭제, 정렬들이 복잡
		 *  하다는 단점을 가지고 있다.
		 *  
		 *  ArrayList는 크기변경 (새로운 더 큰 배열을 만들고 데이터 옮기기)
		 *  , 요소의 추가, 삭제, 정렬기능등을 미리 메소드로 구현해서 제공하고있다.
		 *  자동적으로 수행되는 것이지 속도가 빨라지는 것은 아니다. 
		 *  
		 *  */
		
		
		
		
		/* ArrayList는 인스턴스를 생성하게 되면 내부적으로 10칸까지
		 * 배열을 생성해서 관리한다.
		 *  */
		ArrayList alist = new ArrayList();
		
		
		
		
		/* 다형성을 적용하여 상위 레퍼런스로 ArrayList 객체를 만들수도 있다.
		 * ArrayList는 List인터페이스를 상속받기 때문이다.
		 * List인터페이스 하위의 다양한 구현체들로 타입변경이 가능하기 때문에
		 * 레퍼런스 타입은 List로 해 두는 것이 더 유연한 코드를 작성하는 것이다.
		 *  */
		List list = new ArrayList();
		
		
		
		
		
		/* 더 상위 타입인 Collection 타입을 사용할 수도 있다. 
		 * Collection 타입은 Array 와 List의 상위타입이기 때문
		 * */
		
		Collection clist = new ArrayList();
		
		
		
		
		
		/* ArrayList는 저장 순번이 유지되며 index(순번)이 적용된다.
		 * ArrayList는 Object 클래스의 하위타입 인스턴스를 모두 
		 * 저장할 수 있다.  */
		alist.add("apple");   //String
		alist.add(123);  	  //int
		// 객체만 저장가능, autoBoxing 처리해서 기본자료형들을 자동으로 변환 해준다.
		alist.add(45.67);   	//double
		alist.add(new Date());
		
		
		/* toString 메소드가 오버라이딩 되어있다.
		 * 출력 해 보면 저장 순서를 유지하고 있다.
		 *  */
		System.out.println("alist : " + alist);
		
//		alist : [apple, 123, 45.67, Mon Jan 10 10:23:25 KST 2022]
		
		
		
		
		
		/* size()메소드는 배열의 크기가 아닌 요소의 갯수를 반환한다.
		 * 내부적으로 관리되는 배열의 사이즈는 외부에서 알 필요가 없기
		 * 때문에 기능을 제공하지 않는다.  */
		System.out.println("alist의 size : " + alist.size());
		
//		alist의 size : 4
		
		
		/* 내부 배열에 인덱스가 지정되어 있기 때문에 for문으로 접근 가능하다. */
		for (int i = 0; i < alist.size(); i++) {
			/* 인덱스에 해당하는 값을 가져올 때는 get(인덱스전달값)
			 * 메소드를 사용한다. */
			System.out.println(i + " : " + alist.get(i));
		}
		
//		0 : apple
//		1 : 123
//		2 : 45.67
//		3 : Mon Jan 10 10:25:35 KST 2022

		
		
		
		/* ArrayList는 데이터의 중복 저장을 허용한다.
		 * 배열과 같이 인덱스로 요소들을 관리하기 때문에 인덱스가
		 * 다른 위치에 동일한 값을 저장하는 것이 가능하다.
		 *  */
		alist.add("apple");	// apple 인덱스를 추가한다.
		System.out.println("alist : " + alist);
		
// alist : [apple, 123, 45.67, Mon Jan 10 10:26:59 KST 2022, apple]
		
		
		
		
		
		/* 원하는 인덱스 위치에 값을 추가할 수도 있다.
		 * 값을 중간에 추가하는 경우 인덱스 위치에 덮어쓰는 것이 아니고
		 * 새로운 값이 들어가는 인덱스 위치에 값을 넣고 이후 인덱스는
		 * 하나씩 뒤로 밀리게 된다.
		 *  */
		alist.add(1, "banana");
		System.out.println("alist : " + alist);
		
// alist : [apple, banana, 123, 45.67, Mon Jan 10 10:28:58 KST 2022, apple]		
		
		
		
		
		
		
		/* 지정된 값을 삭제할 때는 remove() 메소드를 사용한다.
		 * 중간 인덱스의 값을 삭제하는 경우 자동으로 인덱스를 하나씩 앞으로 당긴다.
		 *  */
		alist.remove(2);
		System.out.println("alist : " + alist);
		
// alist : [apple, banana, 45.67, Mon Jan 10 10:31:04 KST 2022, apple]
		
		
		
		
		
		/* 지정된 위치의 값을 수정할 때에도 인덱스를 활용할 수 있으며
		 * set() 메소드를 사용한다.
		 *  */
		alist.set(1, true);
		System.out.println("alist : " + alist);
		
// alist : [apple, true, 45.67, Mon Jan 10 10:32:00 KST 2022, apple]
		
		
		
		
		
		
		/* 코드 작성중 노란줄이 많이가는 이유? 
		 * : 모든 컬렉션 프레임 워크 클래스는 제네릭 클래스로 작성 돼 있다. */
		List<String> stringList = new ArrayList<>();   // 타입 추론이 가능하기에 생략 가능
		/* 스트링 타입만 저장하는 객체이다, 라는 의미 */
		
		/* 제네릭 타입을 지정하면 지정한 타입 외의 인스턴스는 저장하지 못한다.  */
		stringList.add("apple");
		//stringList.add(123);		// int 타입은 컴파일 에러
		stringList.add("banana");
		stringList.add("orange");
		stringList.add("mango");
		stringList.add("grape");
		
		System.out.println("stringList : " + stringList);
//		stringList : [apple, banana, orange, mango, grape]
		
		
		
		
		
		
		/* 저장 순서를 유지하고 있는 stringList를 오름차순 정렬해보자 */
		/* Collection 인터페이스가 아닌 Collections 클래스이다.
		 * Collection 에서 사용되는 기능들을 static 메소드로 구현한 클래스이며
		 * 인터페이스명 뒤에 s가 붙은 클래스들은 관례상 비슷한 방식으로 작성 된 클래스를 의미하게 된다. 
		 *  */
		Collections.sort(stringList);
		
		/* sort 메소드를 사용하면 list가 오름차순 정렬 처리 된 후 정렬 상태가 유지된다.
		 * 즉, 원본에 영향을 미친다. 
		 *  */
		System.out.println("stringList : " + stringList);
		
//		stringList : [apple, banana, grape, mango, orange]  // 오름차순정렬
		
		
		
		
		/* 조금 복잡하지만 내림차순 정렬을 할 수도 있다.
		 * 하지만 기본적으로 ArrayList에는 역순으로 정렬하는 기능은 제공되지않는다.
		 * 역순 정렬은 LinkedList에 정의되어있는데 현재 사용하는 ArrayList를
		 * LinkedList로 변경할 수 있다. 둘다 Collection을 상속받고 있다. 
		 * */
		
		stringList = new LinkedList<>(stringList);  //arrayList -> LinkedList
		
		
		
		
		
		
		/* Iterator 반복자 인터페이스를 활용해서 역순으로 정렬한다.
		 * 제네릭 적용하는 것이 좋다.
		 * LinkedList 타입으로 형변환 한 후  descendingIterator()메소드를 사용하면
		 * 내림차순으로 정렬 된 Iterator 타입의 목록으로 반환해준다.
		 * 
		 * Iterator란?
		 * Collection 인터페이스의 Iterator() 메소드를 이용해서 인스턴스를 생성할 수 있다.
		 * 컬렉션에서 값을 읽어오는 방식을 통일된 방식으로 제공하기 위해서 사용한다.
		 * 반복자라고 불리우며 반복문을 이용해서 목록을 하나씩 꺼내는 방식으로 사용하기 위함이다.
		 * 인덱스로 관리되는 컬렉션이 아닌 경우에는 반복문을 사용해서 요소에 하나씩 접근할 수 없기 때문에
		 * 인덱스를 사용하지 않고도 반복문을 사용하기 위한 목록을 만들어주는 역할이라고 보면 된다. 
		 * descendingIterator() - 내림차순
		 * 
		 * hasNext() : 다음 요소를 갖고 있는 경우 true, 더 이상 요소가 없는 경우 false를 반환
		 * next() : 다음요소를 반환
		 * */
		
		Iterator<String> dIter = ((LinkedList<String>)stringList).descendingIterator();
		
		while(dIter.hasNext()) {
			System.out.println(dIter.next());
		}
		
//		orange
//		mango
//		grape
//		banana
//		apple
		
		/* 한번 출력한 뒤엔 다시 출력할 수 없다. */
//		while(dIter.hasNext()) {
//			System.out.println(dIter.next());
//		}
//		
		
		
		
		
		/* 역순으로 정렬 된 결과를 저장하기 위해서는 새로운 ArrayList를 만들어
		 * 저장 해 두면 된다.
		 *  */
		List<String> descList = new ArrayList<>();
		
		while(dIter.hasNext()) { 
			descList.add(dIter.next());
		}
		
		System.out.println("descList : " + descList);
		
		

	}

}

 

 

 

 Application2
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import com.greedy.section01.list.comparator.AscendingPrice;
import com.greedy.section01.list.dto.BookDTO;

public class Application2 {

	public static void main(String[] args) {


		
		
		/* 여러 권의 책 목록을 관리할 ArrayList 인스턴스 생성 */
		List<BookDTO> bookList = new ArrayList<>();
		
		
		
		/* 도서 정보 추가, BookDTO 타입만 받아야 하기때문에 String 타입으로 작성할 수 없다. */
		bookList.add(new BookDTO(1, "홍길동전", "허균", 50000));
		bookList.add(new BookDTO(2, "목민심서", "정약용", 30000));
		bookList.add(new BookDTO(3, "동의보감", "허준", 40000));
		bookList.add(new BookDTO(4, "삼국사기", "김부식", 46000));
		bookList.add(new BookDTO(5, "삼국유사", "일연", 58000));
		
		
		
		/* 정렬 전 책 리스트 출력 */
		for(BookDTO book : bookList) {
			System.out.println(book);
		}
		
//		BookDTO [number=1, title=홍길동전, author=허균, price=50000]
//		BookDTO [number=2, title=목민심서, author=정약용, price=30000]
//		BookDTO [number=3, title=동의보감, author=허준, price=40000]
//		BookDTO [number=4, title=삼국사기, author=김부식, price=46000]
//		BookDTO [number=5, title=삼국유사, author=일연, price=58000]

		
		
		
		
		/* 제네릭의 타입 제한에 의해 Comparable 타입을 가지고 있는 경우에만 
		 * sort가 가능하다. 즉, 사전에 기준이 필요하다. */
		// Collections.sort(bookList);  // 정렬되지 않는다.
		
		
		
		
		/* 가격 순으로 오름차순 정렬 - AscendingPrice 추가 */
		
		/* Comparator 인터페이스를 상속받아 정렬 기준을 정해준 뒤
		 * List의 sort() 메소드의 인자로 정렬 기준이 되는 인터페이스를 넣어주게 되면
		 * 내부적으로 우리가 오버라이딩 한 메소드가 동작하여 그것을 정렬기준으로 삼는다.
		 *  */
		bookList.sort(new AscendingPrice());
		
		
		System.out.println("가격 오름차순 정렬 -------------------");
		for(BookDTO book : bookList) {
			System.out.println(book);
		}
		
//		가격 오름차순 정렬 -------------------
//		BookDTO [number=2, title=목민심서, author=정약용, price=30000]
//		BookDTO [number=3, title=동의보감, author=허준, price=40000]
//		BookDTO [number=4, title=삼국사기, author=김부식, price=46000]
//		BookDTO [number=1, title=홍길동전, author=허균, price=50000]
//		BookDTO [number=5, title=삼국유사, author=일연, price=58000]
		
		
		
		
		/* 인터페이스를 구현할 클래스를 재사용 하는 경우 AscendingPrice 클래스처럼 작성하면 되지만
		 * '한번만 사용'하기 위해서는 조금 더 간편한 방법을 이용할 수 있다.
		 * 즉, 재사용하지않는 목적에 한 해서 익명 클래스를 이용한 방법이다. 
		 * 
		 * 익명클래스는 뒤에 {}를 만들어서 마치 Comparator 인터페이스를 상속받은 클래스인데
		 * 이름이 없다고 생각하고 사용하는 것이다.
		 * 
		 *  */
		bookList.sort(new Comparator<BookDTO> () {

			@Override
			public int compare(BookDTO o1, BookDTO o2) {
				/* 여기에 내림차순 정렬 조건을 넣어주면 된다.
				 * 아까와는 반대로 오름차순 정렬 된 상태인 경우 순서를 바꿔야한다.
				 * 양수를 반환해서 순서를 바꾸라는 플래스로 이용했었다.
				 * 
				 * 양수값이 반환되면 바꿀필요없으며, 음수가 반환되면 순서를 바꾸고, 
				 * 같을시 0반환
				 *  */
				return o2.getPrice() - o1.getPrice();
			}
			
			
		});
		
		
		System.out.println("가격 내림차순 정렬 -------------------");
		for(BookDTO book : bookList) {
			System.out.println(book);
		}
		
//		BookDTO [number=5, title=삼국유사, author=일연, price=58000]
//				BookDTO [number=1, title=홍길동전, author=허균, price=50000]
//				BookDTO [number=4, title=삼국사기, author=김부식, price=46000]
//				BookDTO [number=3, title=동의보감, author=허준, price=40000]
//				BookDTO [number=2, title=목민심서, author=정약용, price=30000]

		
		
		/* 제목 순 오름차순 정렬 */
		bookList.sort(new Comparator<BookDTO>() {

			@Override
			public int compare(BookDTO o1, BookDTO o2) {
				
				/* 문자열은 대소비교를 할 수 없다.
				 * 문자 배열로 변경 후 인덱스 하나하나를 비교해서 어느 것이 더 큰 값인지 확인해야하는데
				 * String  클래스의compareTo() 메소드에서 이미 정의 해 놓았다.
				 *  */
				
				/* 앞의 값이 더 작은 경우 음수 반환,
				 * 같으면 0반환
				 * 앞의 값이 더 큰 경우 양수반환 (즉, 바꿔야 하는 경우) */
				
				
				return o1.getTitle().compareTo(o2.getTitle());
			}
			
			
		});
		
		System.out.println("제목 오름차순 정렬 -------------------");
		for(BookDTO book : bookList) {
			System.out.println(book);
		}
		
		
		
		
		
		
		/* 제목 내림차순 정렬 */
		bookList.sort(new Comparator<BookDTO> () {

			@Override
			public int compare(BookDTO o1, BookDTO o2) {
				// 위 오름차순 순서와 반대되는 값을 반환해야 한다.
				// 값이 반전될 수 있게 하는 처리가 필요하다.
				return o2.getTitle().compareTo(o1.getTitle());
			}
		
		});
		
		System.out.println("제목 내림차순 정렬 -------------------");
		for(BookDTO book : bookList) {
			System.out.println(book);
		}
		
//		제목 내림차순 정렬 -------------------
//		BookDTO [number=1, title=홍길동전, author=허균, price=50000]
//		BookDTO [number=5, title=삼국유사, author=일연, price=58000]
//		BookDTO [number=4, title=삼국사기, author=김부식, price=46000]
//		BookDTO [number=2, title=목민심서, author=정약용, price=30000]
//		BookDTO [number=3, title=동의보감, author=허준, price=40000]
		
	}

	
	/* Vector의 경우 스레드 동기화 처리가 된다는 점만 다르고 ArrayList와 동일하게 동작한다.
	 * 그래서 따로 작성하지 않을 것이다.
	 * JDK 1.0부터 사용하긴 했지만 하위 호환을 위해 남겨놓았고 성능 문제로 현재는 사용하지 않는다.
	 * 가급적이면 ArrayList를 사용하면 된다.  */
	
	
	
}

 

 

BookDTO
public class BookDTO {

	
	/* 필드 */
	private int number;
	private String title;
	private String author;
	private int price;
	
	/* 필드뒤에오는건 기본 생성자 */
	public BookDTO() {}

	
	/* 필드뒤에오는건 매개변수를 가지는 생성자 */
	public BookDTO(int number, String title, String author, int price) {
		super();
		this.number = number;
		this.title = title;
		this.author = author;
		this.price = price;
	}


	/* 게터 세터 */
	public int getNumber() {
		return number;
	}



	public void setNumber(int number) {
		this.number = number;
	}



	public String getTitle() {
		return title;
	}



	public void setTitle(String title) {
		this.title = title;
	}



	public String getAuthor() {
		return author;
	}



	public void setAuthor(String author) {
		this.author = author;
	}



	public int getPrice() {
		return price;
	}



	public void setPrice(int price) {
		this.price = price;
	}


	
	/* toString */
	@Override
	public String toString() {
		return "BookDTO [number=" + number + ", title=" + title + ", author=" + author + ", price=" + price + "]";
	}
	
	
}

 

 

AscendingPrice implements Comparator<BookDTO>
import java.util.Comparator;

import com.greedy.section01.list.dto.BookDTO;


public class AscendingPrice implements Comparator<BookDTO> {

	/* 목적 :  정렬기준 설정해주기 */
	
	
//	@Override
//	public int compare(Object o1, Object o2) {
//		// 오브젝트 타입에서는 접근 불가능함, 다운캐스팅 필요
//		return 0;
//	}
	
	
	@Override
	public int compare(BookDTO o1, BookDTO o2) { // 임포트 필요
		// TODO Auto-generated method stub
		


		/* sort()에서 내부적으로 사용하는 메소드이다.
		 * 인터페이스를 상속받아서 메소드 오버라이딩하는 것을 강제화 해놓았다.
		 *  */
		
		
		/* 정렬 기준/판단기준 설정, 비교 대상 두 인스턴스의 가격이 오름차순 정렬이 되기 위해서는
		 * 앞의 가격이 더 작은 가격이어야 한다.
		 * 만약, 뒤의 가격이 더 작은 경우 두 인스턴스의 순서를 바꿔야 한다.
		 * 그 때 두 값을 바꾸라는 신호로 양수를 보내주게 되면 정렬 시 순서를 바꾸는 조건으로 사용 된다. 
		 * (음수는 바꾸지X)
		 *  */
	
		
		
		/* 양수, 음수 형태로 두 비교 값이 순서를 바꿔야 하는지를 알려주기 위한 용도의 변수 */
		int result = 0;
		
		if (o1.getPrice() > o2.getPrice()) {
			/* 오름차순을 위해 순서를 바꿔야 하는 경우 양수반환 */
			result = 1;
			
		} else if (o1.getPrice() < o2.getPrice()) {
			/* 이미 오름차순 정렬로 되어 있는 경우 음수를 반환 */
			result = -1;
			
		} else {
			/* 두 값이 같은 경우 0을 반환*/
			result = 0;
		
		return 0;
		}
		
		return result;
		
		/* 정렬의 기준을 작성 해 놓은것이다. 상황에 따라 1, -1, 0이 반환되게끔. */
	}
	

	
}

 

 

 

Application3
import java.util.LinkedList;
import java.util.List;

public class Application3 {

	public static void main(String[] args) {
		
		/* LinkedList
		 * ArrayList가 배열을 이용해서 발생할 수 있는 성능적인 단점을 보환하고자 고안되었다.
		 * 내부는 이중 연결리스트로 구현되어 있다.
		 * 
		 * 단일 연결 리스트
		 * : 저장한 요소가 순서를 유지하지 않고 저장되지만 이러한 요소들 사이를 링크로 연결하여
		 *   구성하며 마치 연결 된 리스트 형태인 것처럼 만든 자료구조이다.
		 *   요소의 저장과 삭제 시 다음 요소를 가리키는 참조 링크만 변경하면 되기 때문에 
		 *   요소의 저장과 삭제가 빈번히 일어나는 경우 ArrayList보다 성능면에서 우수하다.
		 *   단, 다음값만 가지고 있기 때문에 이전값으로 역순이동 하려는 경우엔 어려움을 겪어
		 *   이러한 단점을 보완하기위해 이중연결 리스트가 고안되었다.
		 * 
		 * 이중 연결 리스트(LinkedList)
		 * : 단일 연결 리스트는 다음 요소만 링크하는 반면 이중 연결 리스트는 이전 요소도 링크하여
		 *   이전 요소로 접근하기 쉽게 고안된 자료구조이다.
		 * 
		 * 
		 * 하지만 내부적으로 요소를 저장하는 방법에 차이가 있는것이다.
		 * 각 컬렉션 프레임 뭐크 클래스들의 특징을 파악하고 그에따라 적합한 자료구조를 구현한
		 * 클래스를 선택하는 것이 좋다.
		 * 
		 * 
		 *  
		 *  */
		
		
		
		
		
		/* LinkedList 인스턴스 생성 */
		List<String> linkedList = new LinkedList<>();
		
		
		
		
		/* 요소를 추가할 때는 add를 이용한다. */
		linkedList.add("apple");
		linkedList.add("banana");
		linkedList.add("orange");
		linkedList.add("mango");
		linkedList.add("grape");
		
		
		
		
		/* 저장된 요소의 갯수는 size() 메소드를 이용한다. */
		System.out.println(linkedList.size());
// 콘솔창 출력 : 5
		
		
		
		
		
		
		/* for문과 size()를 이용해서 반복문을 활용할 수도 있다.
		 * 요소를 꺼내올 때는 get()을 사용하며, 
		 * 인자로 전달하는 정수는 인덱스처럼 사용하면 된다.
		 *  */
		for (int i = 0; i < linkedList.size(); i++) {
			System.out.println(i + " : " + linkedList.get(i));
		}
		
//		0 : apple
//		1 : banana
//		2 : orange
//		3 : mango
//		4 : grape
		
		
		
		
		
		/* 요소를 제거할 때는 remove 메소드를 이용하며 인덱스를 활용한다. */
		linkedList.remove(1);
		
		/* 향상된 for문도 사용가능하다. */
		for (String s: linkedList) {
			System.out.println(s);
		}
		
//		apple
//		orange
//		mango
//		grape
		
		
		
		
		/* set() 메소드를 이용해서 요소를 수정할 수도 있다. */
		linkedList.set(0, "pineapple");
		
		
		/* toString 메소드가 오버라이딩 돼 있어서 모든 요소 정보를 쉽게 볼 수 있다. */
		System.out.println(linkedList);
		
//	출력: [pineapple, orange, mango, grape]
		
		
		
		
		
		/* isEmpty() 메소드를 이용해서 list 가 비어있는지 확인할 수 있다. */
		System.out.println(linkedList.isEmpty());
		
//		false : 비어있지 않으므로 출력
		
		
		
		/* 리스트 내 요소를 모두 제거하는 clear() 메소드를 이용할 수도 있다. */
		linkedList.clear();
		System.out.println(linkedList.isEmpty());
		
//		true : clear() 메소드로 비웠으므로 true
		
		
	}

}

 

 

 

 

 

 

Stack

 

 

stack은 List에서 파생되었다.
  • stack은 제한적으로 접근할 수 있는 나열 구조로 데이터를 저장
  • 쌓아나간다고 생각, 넣을때는 바닥부터, 꺼낼때는 위에 쌓인 것 부터
  • 후임선출(LIFO - Last Input First Out)방식의 자료 구조 -  마지막에 넣은것이 가장 처음 나온다

 

 

 

 

Application4
import java.util.Stack;

public class Application4 {

	public static void main(String[] args) {
		
		
		/* Stack */
		/* Stack은 리스트 계열 클래스의 Vector 클래스를 상속받아 구현되었다.
		 * 스택메모리 구조는 선형 메모리 공간에 데이터를 저장하며
		 * 후입선출 (LIFO - Last Input First Out) 방식의 자료구조라 부른다. 
		 * */
		
		
		/* Stack 인스턴스 생성 */
		Stack<Integer> integerStack = new Stack<>();	// 임포트
		
		
		/* Stack에 값을 넣을 때는 push() 메소드를 이용한다.
		 * 벡터의 기능을 상속받았으므로 add() 이용이 가능하긴 하지만 
		 * push()를 이용하는 것이 좋다.
		 *  */
		integerStack.push(1); 	// 오토 박싱이 되므로 그냥 인트값을 넣어준다.
		integerStack.push(2);    	
		integerStack.push(3);    	
		integerStack.push(4);    	
		integerStack.push(5);    	
		
		
		/* 값을 출력할때는 순서대로 나온다. */
		System.out.println(integerStack);
//		[1, 2, 3, 4, 5]
		
		
		
		/* Stack의 Search()메소드는 위에서부터의 순번을 찾아오는데,
		 * 스택의 자료구조는 아래서부터 쌓이는 방식이라고 했다. */
		
		/* 스택에서 요소를 찾을때 search를 이용할 수 있따.
		 * 인덱스가 아닌 위에서부터의 순번을 의미한다.
		 * 또한 가장 상단의 위치가 0이 아닌 1부터 시작한다. */
		
		System.out.println(integerStack.search(5));
		
// 콘솔 출력:	1
		
		
		/* Stack에서 값을 꺼내는 메소드는 크게 2가지로 볼 수 있다.
		 * peek():  해당 스택의 가장 마지막에 (상단에 있는) 요소반환
		 * pop() : 해당 스택의 가장 마지막에 있는 (상단에 있는) 요소 반환 후 
		 * 반환했던 요소를 제거
		 *  */
		
		System.out.println("peek() : " + integerStack.peek());
		System.out.println(integerStack);
		
//		peek() : 5
//		[1, 2, 3, 4, 5]
		
		
		
		System.out.println("pop() : " + integerStack.pop());
		System.out.println(integerStack);
		
//		pop() : 5
//		[1, 2, 3, 4]
		
		
		
		
		/* pop은 꺼내면서 요소를 제거학 때문에 스택이 비어있는 경우 에러가 발생할 수 있다. */
		System.out.println("pop() : " + integerStack.pop());
		System.out.println("pop() : " + integerStack.pop());
		System.out.println("pop() : " + integerStack.pop());
		System.out.println("pop() : " + integerStack.pop());
		System.out.println("pop() : " + integerStack.pop());
		
// 		모두 출력+ 제거후 더 이상 반환할 요소가 없을때 에러를 발생시킨다.
//		java.util.EmptyStackException 
		
		
		
	}
	
	
}

 

 

 

 

 

 

 

 

Queue

 

queue
  • queue는 선형 메모리 공간에 데이터를 저장
  • 선입선출(FIFO - First Input First Out)방식의 자료구조

 

 

 

Application5
import java.util.*;
import java.util.LinkedList;
import java.util.Queue;

public class Application5 {

	public static void main(String[] args) {
		
		
		
		
		/* Queue */
		/* Queue는 선형 메모리 공간에 데이터를 저장하는 
		 * 선입 선출(FIFO - First Input First Out) 방식의 자료구조이다.
		 * Queue 인터페이스를 상속받는 하위 인터페이스들은
		 * Deque, BlockingQueue, TransferQueue 등 다양하지만
		 * 대부분의 큐는 LinkedList를 이용한다.
		 *  */
		
		
		
		
		
		
		/* Queue자체로는 인터페이스이기 때문에 인스턴스 생성이 불가능하다. */
		// Queue<String> que = new Queue<>();
		// 생설할 수는 없는데 그 이유는 인터페이스 이기 때문
		
		
		
		
		
		
		/* LinkedList로 인스턴스 생성 */
		
		Queue<String> que = new LinkedList<>();
		
		
		
		
		
		/* 큐에 데이터를 넣을때에는 offer() 를 이용한다. */
		que.offer("first");
		que.offer("second");
		que.offer("third");
		que.offer("fourth");
		que.offer("fifth");
		
		System.out.println(que);
		
//		[first, second, third, fourth, fifth]
		
		
		
		
		
		
		/* 큐에서 데이터를 꺼낼때는 2가지 메소드가 있다.
		 * peek() :  해당 큐의 가장 앞에있는 요소 (먼저들어온 요소)를 반환한다.
		 * poll() : 해당 큐의 가장 앞에있는 요소 (먼저들어온 요소)를 반환하고 반환한 요소를 제거한다.
		 *  */
		
		System.out.println("peek() : " + que.peek());
		System.out.println(que);
		
//		peek() : first
//		[first, second, third, fourth, fifth]
		
		System.out.println("poll() : " + que.poll());
		System.out.println(que);
		
//		poll() : first
//		[second, third, fourth, fifth] // 출력된 데이터는 제거되었다.
		
		
	}

}

 

 

 

 

 

 

 

 

 

 

 

 

Set

 

 

set이란?
  • 저장 순서가 유지되지 않고, 중복 인스턴스도 저장하지 못하게 하는 자료구조
  • null값도 중복하지 않게 하나의 null만 저장 가능
  • 구현 클래스 : HashSet, LinkedHashSet, TreeSet

 

 

 

 Set 계열 주요 메소드

 

 

 

 

 

 

Iterator
  • 컬렉션에 저장된 요소를 접근하는데 사용되는 인터페이스
  • List와 Set계열에서만 사용
  • Map의 경우 사용할 수 없다. Map의 경우엔 Set 또는 List'화' 시켜서(바꿔서) iterator()를 사용

 

 

 

 

 

 

 

HashSet
  • Set에 인스턴스를 저장할 때 hash함수를 사용하여 처리 속도가 빠름
  • 동일 인스턴스 뿐 아니라 동등 인스턴스도 중복하여 저장하지 않음
동일 : 완전히 같은 인스턴스
동등 : 다른 인스턴스이지만 특정한 기준들의 속성 값이 같음

 

 

 

 

LinkedHashSet
  • HashSet과 거의 동일하지만 Set에 추가되는 순서를 유지함

 

 

 

 

TreeSet
  • 이진 트리를 기반으로 한 Set컬렉션으로, 왼쪽과 오른쪽 자식 노드를 참조하기 위한 두 개의 변수로 구성
  • 추가된 값이 기존 값(5)을 기준으로 큰지(7) 작은지(3) 판단하여 정렬된 형태(3-5-7)로 저장한다, 즉 기존값 기준 더 작은 것은 왼쪽에, 더 큰값은 오른쪽에

 

 

 

 

 

 

Applicaion1
import java.util.HashSet;
import java.util.Iterator;

public class Applicaion1 {

	public static void main(String[] args) {


		/* Set 인터페이스를 구현한 Set 컬렉션 클래스의 특징 
		 * 1. 요소의 저장 순서를 유지하지 않는다.
		 * 2. 같은 요소의 중복 저장을 허용하지 않는다.
		 * 	  (null값도 중복되지않아 하나의 null만 저장한다.)
		 * 
		 * */
		
		
		/* HashSet 클래스
		 * Set 컬렉션 클래스에서 가장 많이 사용 되는 클래스 중 하나이다.
		 * JDK 1.2 부터 제공되고 있으며 해시 알고리즘을 사용하여 검색 속도가 
		 * 빠르다는 장점을 가진다.
		 *  
		 *  */
		
		/* HashSet 인스턴스 생성 */
		HashSet<String> hset = new HashSet<>();

		/* 다형성을 적용하여 상위 인터페이스를 타입으로 사용가능 */
//		Set hset2 = new HashSet();
//		Collection hset3 = new HashSet();
		
		hset.add(new String("java"));
		hset.add(new String("oracle"));
		hset.add(new String("jdbc"));
		hset.add(new String("html"));
		hset.add(new String("css"));
		
		
		
		
		/* toString 이 오버라이딩 되어 있다. 
		 * 저장 순서 유지 안됨*/
		System.out.println(hset);
		
//		[css, java, oracle, jdbc, html]
		//저장한 순서와 담겨있는 순서는 같지않다.
		
		
		
		
		
		/* 중복 데이터 저장 허용 안됨 */
		hset.add(new String("java"));
		System.out.println(hset);
		
//		[css, java, oracle, jdbc, html]
		// 원래 저장돼있기때문에 추가 저장은 안됨
		
		
		
		
		System.out.println("저장 된 객체 수 : " + hset.size());
//		저장 된 객체 수 : 5
		
		System.out.println("포함 여부 확인 : " + hset.contains(new String("oracle")));
//		포함 여부 확인 : true
		
		
		
		
		
		/* 저장 된 객체를 하나씩 꺼내는 기능이 없음 */
		
		/* 반복문을 이용한 연속 처리 하는 방법 */
		/* 1. toArray()로 배열로 변경한 뒤 for loop 사용 */
		
		Object[] arr = hset.toArray();
		for (int i = 0; i < arr.length; i++) {
			System.out.println(i + " : " + arr[i]);
		}

//		0 : css
//		1 : java
//		2 : oracle
//		3 : jdbc
//		4 : html
		
		
		
		
		
		/* 2. iterator()로 목록 만들어 연속 처리 */
		Iterator<String> iter = hset.iterator();
		
		while(iter.hasNext()) {
			System.out.println(iter.next());
		}
		
//		css
//		java
//		oracle
//		jdbc
//		html
		
	
		
	
		
		/* 지우는 방법 */
		hset.clear();
		System.out.println("empty? : " + hset.isEmpty());
//		empty? : true
		
		
		
	}

}

 

 

 Application2
import java.util.LinkedHashSet;
import java.util.TreeSet;

public class Application2 {

	public static void main(String[] args) {

		/* LinkedHashSet 클래스 */
		/* HashSet이 가지는 기능을 모두 가지고 있고
		 * 추가적으로 저장 순서를 유지하는 특징을 가지고 있다.
		 * JDK 1.4부터 제공하고 있다. */
		
		LinkedHashSet<String> lhset = new LinkedHashSet<>();
		
		lhset.add("java");
		lhset.add("oracle");
		lhset.add("jdbc");
		lhset.add("html");
		lhset.add("css");
		
		
		/* 저장된 순서를 유지하고있다. */
		System.out.println("lhset : " + lhset);
//		lhset : [java, oracle, jdbc, html, css]
		
		
		
		
		
		
		/* 만들어진 링크드해쉬셋을 가지고 트리셋으로 객체를 생성하면
		 * 같은 타입의 객체를 자동으로 비굑하여 오름차순으로 정렬한다.
		 *  */
		
		TreeSet<String> tset = new TreeSet<>(lhset);
		
		System.out.println(tset);
//		[css, html, java, jdbc, oracle]
		
		
		
		
		
	}

}

 

 

Application3
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

public class Application3 {

	public static void main(String[] args) {


		/* TreeSet 클래스 */
		/* TreeSet 클래스는 데이터가 정렬 된 상태로 저장 되는 이진 검색 트리의
		 * 형태로 요소를 저장한다.
		 * 이진 검색 트리는 데이터를 추가하거나 제거하는 등의 기본동작 시간이 매우 빠르다.
		 * jdk 1.2 부터 제공되고 있으며
		 * Set 인터페이스가 가지는 특징을 그대로 가지지만 정렬 된 상태를 유지한다는 것이 
		 * 다른 점이다.
		 *  */
		
		
		TreeSet<String> tset = new TreeSet<>();
		// Set<String> tset2 = new TressSet<>();
		// 다형성을 이용하여 상위타입으로 선언하는 것도 가능하다.
		
		tset.add("java");
		tset.add("oracle");
		tset.add("jdbc");
		tset.add("html");
		tset.add("css");
		
		
		
		/* 자동 오름차순 정렬 */
		System.out.println(tset);
		
//		[css, html, java, jdbc, oracle]
		
		
		
		
		
		/* 목록 만들어서 하나씩 대문자로 변경해서 출력처리 */
		Iterator<String> iter = tset.iterator();
		
		while(iter.hasNext()) {
			System.out.println(iter.next().toUpperCase());
		}
			
//		CSS
//		HTML
//		JAVA
//		JDBC
//		ORACLE
		
		
		
		
		
		
		/* 배열로 바꾸어 연속 처리하기 */
		Object[] arr = tset.toArray();
		
		for(Object obj : arr) {
			System.out.println(((String)obj).toUpperCase());
		}
		// 그냥 오브젝트에서는 대문자변환이 불가능하므로 
		// 오브젝트를 참조형인 스트링으로 강제 타입 변환 해준다.
		
		
		
		
		/* 로또번호 발생기 (TreeSet의 이용) */
		Set<Integer> lotto = new TreeSet<>();
		
		while(lotto.size() < 6) {
			lotto.add((int)(Math.random() * 45) +1);
		} // add가 중복을 막아줌, 정렬역시 treeset이 해주므로 정렬도 필요없음
		
		System.out.println("lotto : " + lotto);
		
//		lotto : [8, 11, 13, 34, 35, 43]
		

	}

}

 

 

 

 

 

 

 

 

'Programming > JAVA' 카테고리의 다른 글

입출력 (I/O)  (0) 2022.01.12
예외 처리  (0) 2022.01.11
제네릭과 컬렉션  (0) 2022.01.07
자바 API  (0) 2022.01.06
다형성  (0) 2022.01.05

 

 

 

 

 

 

Wrapper

 

Primitive Data Type을 인스턴스화 해주는 클래스
  • 기본자료형은 객체가 아니지만, 필요에 따라 기본자료형을 객체로 다루어야 할때 사용한다.
  • 기본자료형을 일종의 클래스 형태로 감싸 정의시켜주는 것
  • java.lamg하위에 있으므로 별도의 임포트는 필요하지 않다. 

 

Primitive Data Type Wrapper Class
boolean Boolean
byte Byte
char Character
short Short
int Integer
long Long
float Float
double Double

 

 

 

 

Wrapper : String을 기본자료형으로 바꿀 시
byte b = Byte.parseByte("1");
short s = Short.parseShort("2");
int i = Integer.parseInt("3");
long l = Long.parseLong("4");
float f = Float.parseFloat("0.1");
double d = Double.parseDouble("0.2");
boolean bool = Boolean.parseBoolean("true");
char c = "abc".charAt(0);

 

 

 

Wrapper : 기본자료형을 String으로 바꿀 시
String b = Byte.valueOf((byte)1).toString();
String s = Short.valueOf((short)2).toString();
String i = Integer.valueOf(3).toString();
String l = Long.valueOf(4L).toString();
String f = Float.valueOf(0.1f).toString();
String d = Double.valueOf(0.2).toString();
String bool = Boolean.valueOf(true).toString();
String ch = Character.valueOf('a').toString();

 

 

 

 

 

 

 

 Application1
public class Application1 {

	public static void main(String[] args) {


		/* Wrapper 클래스 */
		/* 상황에 따라 기본 타입의 데이터를 인스턴스화 해야 하는 경우들이 발생한다.
		 * 이때 기본 타입 데이터를 먼저 인스턴스로 변환 후 사용해야 하는데
		 * 8가지에 해당하는 기본 타입의 데이터를 인스턴스화 할 수 있도록 해주는 
		 * 클래스를 래퍼(Wrapper)클래스라고 한다.
		 *  */
		
		/* Boxing 과 UnBoxing */
		/* 기본타입을 래퍼클래스의 인스턴스로 인스턴스화 하는 것을 박싱이라고 하며,
		 * 래퍼 클래스 타입의 인스턴스를 기본 타입으로 변경하는 것을 언박싱이라고 한다. */
		
		int intValue = 20;
		Integer boxingNumber1 = new Integer(intValue);		
		// 인스턴스화 - 박싱(Boxing) // 생성자 이용
		// The constructor Integer(int) is deprecated since version 9
		// 자바 9 버전부터는 안될 수 있으므로 사용하지 않을것을 권장
		
		Integer boxingNumber2 = Integer.valueOf(intValue);	
		// static 메소드 이용
		
		int unBoxingNumber1 = boxingNumber1.intValue();
		// 언박싱 (unBoxing) // intValue() 이용
		
		
		/* 오토 박싱(Auto Boxing)과 오터 언박싱(Auto UnBoxing) 
		 * JDK 1.5 부터는 박싱과 언박싱이 필요한 상황에서 자바 컴파일러가 이를
		 * 자동으로 처리해 준다. 이런 자동화 된 박싱과 언박싱을 오토 박싱, 오토 언박싱
		 * 이라고 한다. 굳이 메소드를 이용한 방식을 취하지 않아도 된다. 
		 *  */
		
		
		
		Integer boxingNumber3 = intValue;
		// 자동변환, 오토 박싱 
		
		int unBoxingNumber2 = boxingNumber3;
		// 오토 언박싱
		
		
		
		
		
		/* Wrapper 클래스 값 비교 */
		int inum = 20;
		Integer integerNum1 = new Integer(20);
		Integer integerNum2 = new Integer(20);
		Integer integerNum3 = 20;
		Integer integerNum4 = 20;
		
		
		
		
		
		/* 기본 타입과 래퍼 클래스 타입은 == 연산으로 비교 가능하다. */
		System.out.println("int와 Integer 비교 : " + (inum == integerNum1));
		System.out.println("int와 Integer 비교 : " + (inum == integerNum3));
		
//		int와 Integer 비교 : true
//		int와 Integer 비교 : true

		
		
		
		/* 생성자를 이용해 생성한 인스턴스의 경우 ==로 비교하지 못한다. (주소값 비교) 
		 * 단, 오토 박싱을 이용해서 생성한 값은 == 비교가 가능하다.
		 * */
		System.out.println("Integer와 Integer 비교 : " + (integerNum1 == integerNum2));
		System.out.println("Integer와 Integer 비교 : " + (integerNum1 == integerNum3));
		System.out.println("Integer와 Integer 비교 : " + (integerNum3 == integerNum4));
		
//		Integer와 Integer 비교 : false
//		Integer와 Integer 비교 : false
//		Integer와 Integer 비교 : true
		
		
		//new 생성자로 인스턴스가 새로 성성돼어 서로 다른 주소값을 참조하고있으므로 false가 출력된다.
		
		
		
		
		
		
		
		
		/* 래퍼클래스 타입의 인스턴스의 주소값이 아닌 "값"을 비교할때는 equals()를 사용한다. */
		System.out.println("equals() : " + (integerNum1.equals(integerNum2)));
		System.out.println("equals() : " + (integerNum1.equals(integerNum3)));
		System.out.println("equals() : " + (integerNum3.equals(integerNum4)));
		
//		equals() : true
//		equals() : true
//		equals() : true
		
		
		
		

	}

}

 

 

Application2
public class Application2 {

	public static void main(String[] args) {


		/* parsing : 문자열(String)값을 기본 자료형 값으로 
		 * 변경하는 것을 parsing이라고 한다. 
		 * 래퍼클래스 내부에 정의 돼있는 기능이다.
		 * */
		
		byte b = Byte.parseByte("1");
		System.out.println("b : " + b);		// b : 1
		
//		byte b1 = Byte.parseByte("g");
//		System.out.println("b1 : " + b1);		
		// b1 : java.lang.NumberFormatException 에러가 발생한다.
		
		
		short s = Short.parseShort("2");
		System.out.println("s : " + s);		// s : 2
		
		
		int i =Integer.parseInt("4");
		System.out.println("i : " + i);		// i : 4
		
		long l = Long.parseLong("8");
		System.out.println("l : " + l);		// l : 8

		float f = Float.parseFloat("4.0");
		System.out.println("f : " + f);		// f : 4.0

		double d = Double.parseDouble("8.0");
		System.out.println("d : " + d);		// d : 8.0
		
		boolean bl = Boolean.parseBoolean("true");
		System.out.println("bl : " + bl);	// bl : true
		

		
		
		/* Character는 parsing 기능을 제공하지 않는다. */
		char c = "abc".charAt(0);
		System.out.println("c : " + c);		// c : a
			
		
		
	}

}

 

 

Application3
public class Application3 {

	public static void main(String[] args) {

		
		
		/* parsing 과 반대로 기본 자료형 값을 문자열로 변경하는 경우도 필요하다 */
		
		/* valueOf() : 기본자료형 값을 Wrapper 클래스 타입으로 변환시키는 메소드
		 * toString() : 필드 값을 문자열로 반환하는 메소드
		 * 
		 *  
		 *  */
		
		
		
		String b = Byte.valueOf((byte)1).toString();
		System.out.println("b : " + b);
		// toString은 객체가 가진 필드값을 문자열로 반환해주는 메소드
		// 문자열 타입 b : 1
		
		String s = Short.valueOf((short)2).toString();
		System.out.println("s : " + s);
		
		String i = Integer.valueOf(4).toString();	// i : 4
		System.out.println("i : " + i);
		
		String l = Long.valueOf(8L).toString();
		System.out.println("l : " + l);				// l : 8
		
		String f = Float.valueOf(4.0f).toString();		// f : 4.0
		System.out.println("f : " + f);	
		
		String d = Double.valueOf(8.0).toString();		// d : 8.0
		System.out.println("d : " + d);	
		
		String bl = Boolean.valueOf(true).toString();	// bl : true
		System.out.println("bl : " + bl);	
		
		String c = Character.valueOf('a').toString();	//c : a
		System.out.println("c : " + c);	
		
		
		
		
		
		
		/* String 클래스의 valueOf 메소드를 사용할 수도 있다. */
		/* 위에서 기본자료형을 래퍼 클래스로 바꿔주는 과정보다 조금 더 간단한 과정 
		 * 모든 데이터 타입에 대하여 오버로딩 되어있다.
		 * String.valueOf() 괄호 속 기본자료형 -> String 으로 바꿔준다.
		 * */
		
		String str = String.valueOf(10);
		System.out.println("str : " + str);			// str : 10
		
		
		
		
		
		/* 문자열 합치기를 이용해 String으로 변환할 수도 있다. */
		String str2 = 123 + "";
		System.out.println("str2 : " + str2);		// str2 : 123
		
		

	}

}

 

 

 

 

 

 

 

Date

 

시스템으로부터 현재 날짜, 시간 정보를 가져와서 다룰 수 있게 만들어진 클래스
  • 생성자 2개만 사용하고 나머지는 모두 deprecated
  • deprecated는 향후 버전이 업데이트 되면서 사라지게 될 기능이니 가급적이면 사용을 권장하지 않는다는 것을 의미

 

Date today = new Date();
//시스템으로부터 현재 날짜, 시간 정보를 가져와 기본 값으로 사용

Date when = new Date(123456798L);
//long형 정수 값을 가지고 날짜 시간 계산
//1970년 1월 1일 0시 0분 0초를 기준으로 함

 

 

 

 Application1
import java.util.Date;

public class Application1 {

	public static void main(String[] args) {


		/* Date 클래스 */
		/* JDK 1.0 부터 날짜를 취급하기 위해 사용되던 Date 클래스는
		 * 생성자를 비롯하여 대부분의 메소드가 Deprecated 되어있다. (API 문서참조) 
		 * */
		
		
		
		/* Date는 java.sql.Date 와 java.util.Date가 존재한다.
		 * 한 클래스에서 두개의 타입을 전부 사용하게 되면 import를 하더라도 사용하는
		 * 타입이 어느 패키지에 있는 Date 클래스인지에 대한 모호성이 발생하여
		 * import를 하더라도 풀 클래스 이름을 작성해 주어야 한다.
		 * 단, 여기에서는 java.util.Date 만 사용할 것이다.
		 *  */
		
		
		
		
		
		
		
		/* 1. 기본생성자 사용하는 방법 */
		/* 기본생성자로 인스턴스를 생성하면 운영체제의 날짜/시간 정보를 이용해서 
		 * 인스턴스를 만들게 된다.
		 *  */
		
		java.util.Date today =  new java.util.Date();
		
		
		/* toString 메소드가 오버라이딩 되어 있어서 쉽게 필드 값을 출력해 볼 수 있다. */
		System.out.println(today);
		
//		 Fri Jan 07 10:29:36 KST 2022,  실행 당시의 시간 출력
		
		
		
		
		
		
		
		
		
		/* 2. Date(long date) 사용하는 방법 */
		/* getTime() : 1970년 1월 1일 0시 0분 0초 이후 지난 시간을 millisecond
		 * 로 계산해서 long타입으로 반환한다. 
		 *  */
		System.out.println(today.getTime());
		// 1641519153289 출력
		
	/*		Returns the number of milliseconds since January 1, 1970, 00:00:00 
	 * GMTrepresented by this Date object.Returns:the number of milliseconds 
	 * since January 1, 1970, 00:00:00 GMTrepresented by this date.
	 */
		
		
		Date time = new Date (1641519153289L);
		// import java.util.Date; 임포트
		
		/* 방금 실행했을때의 시간이 나오게 된다. */
		System.out.println(time);
		
		
		/* 지금 이 순간은 시간으로 추출할 수 있지만 
		 * 특정 일자를 의도적으로 출력하기는 어렵다는 한계가 있다. */
		
		
	}

}

 

 

 

 

 

 

 

Calendar와 GregorianCalendar

 

Calendar
  • Calendar 클래스는 추상클래스 이기 때문에 new 연산자를 통해 인스턴스 생성이 불가능
  • getInstance( )메소드를 통해서 인스턴스를 생성
Calendar calendar = Calendar.getInstance();

 

 

 

GregorianCalendar
  • Calendar 클래스를 상속받은 클래스로 인스턴스 생성이 가능
Calendar gregorianCalendar = new GregorianCalendar();

 

 

Calendar today = Calendar.getInstance();
int year = today.get(Calendar.YEAR);
int month = today.get(Calendar.MONTH) + 1;
int date = today.get(Calendar.DATE);
int ampm = today.get(Calendar.AM_PM);
int hour = today.get(Calendar.HOUR);
int min = today.get(Calendar.MINUTE);
int sec = today.get(Calendar.SECOND);
String ampmString = (ampm == Calendar.AM) ? "오전" : "오후";

 

 

 

 

Application2
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

public class Application2 {

	public static void main(String[] args) {


		/* java.util.calendar 클래스 사용 */
		/* 추상클래스이므로 객체생성이 불가능 하다, new Calendar불가
		 * API문서를 살펴보면 Calendar 클래스는 abstract 클래스로 작성 돼있다.
		 * 따라서 Calendar 클래스를 이용해서 인스턴스를 생성하는 것이 불가능하다.
		 *  
		 *  */
		
		
		
		/* Calendar 클래스를 이용한 인스턴스 생성 방법에는 두가지가 있다.
		 * 1. getInstance() static 메소드를 이용해서 인스턴스를 반환하는 방법
		 * 2. 후손 클래스인 GregorianCalendar클래스를 이용해서 인스턴스를 
		 * 생성하는 방법 
		 * */
		
		
		
		/* 1. getInstance() static 메소드 이용 */
		Calendar calendar = Calendar.getInstance();		// java.util 임포트 필요
		
		/* toString 이 오버라이딩 되어 있어서 모든 필드의 값을 확인할 수 있다.
		 * Date 클래스에 비해 매우 많은 필드들이 값을 가지고 있다.
		 * 또한 생성 된 인스턴스 타입이 후손 클래스 타입인 GregorianCalendar 
		 * 타입인 것을 확인할 수 있다.
		 * 이 방식으로 인스턴스를 생성하게 되면 운영체제의 날짜/시간 정보를 이용해서 
		 * 인스턴스를 생성하게 된다. 
		 *  */
		
		System.out.println(calendar);
		
		// java.util.GregorianCalendar[time=1641519600946,areFieldsSet=true,
		//출력 시 수많은 필드와 그레고리안 메소드로 인스턴스로 생성된 것이 보인다.
		//
		
		
		
		
		
		
		
		/* 특정 날짜/시간 정보를 이용해서 인스턴스를 생성하는 방법을 GregorianCalendar
		 * 의 생성자로 제공한다. */
		
		/* 2. GregorianCalendar 이용하는 방법 */
		/* 2-1. 기본 생성자 사용 */
		Calendar gregorianCalendar = new GregorianCalendar();
		// import java.util.GregorianCalendar; 임포트 필요
		
		System.out.println(gregorianCalendar); // 현재 실행되는 시스템의 시간
		
		
		
		
		
		
		/* 2-2. 년, 월, 일, 시, 분, 초 정보를 이용해서 인스턴스를 생성 */
		/* 2014년 9월 18일 16:42:00 */
		int year = 2014;
		int month = 8;
		// month 유의할 점 : 인덱스 처럼 0부터 월을 세기 때문에 범위가 0부터 11이다. 
		// 즉 8은 9월을 의미한다.
		int dayOfMonth = 18;
		int hour = 16;
		int min = 42;
		int second = 0;
		
		Calendar birthday = new GregorianCalendar (year, month, dayOfMonth, hour, min, second);
		
		System.out.println(birthday);
		
		
		/* 상황에 따라 특정 일자를 기준으로 한 Date 타입의 인스턴스가 필요한 경우도 있다.
		 * 먼저 GregorianCalendar를 이용해서 특정 날짜/시간 정보로 인스턴스를 생성한 후 
		 * 1970년 1월 1일 0시 0분 0초를 기준으로 지난 시간을 millisecond 로 계산해서
		 * long형으로 반환하는 메소드가 있다.
		 *  */
		
		
		
		System.out.println(birthday.getTimeInMillis());
		// 1411026120000
		// Long 타입의 getTimeInMillis()
		
		
		/* 출력된 정수로 인스턴스를 생성하면 해당 날짜/시간 정보를 가지는 
		 * Date 인스턴스가 된다. */
		Date date = new Date(birthday.getTimeInMillis()); // 임포트 필요
		
		System.out.println(date);
		// Thu Sep 18 16:42:00 KST 2014
		
		
		
		
		
		/* 실제 사용시 이런 형태로 만드는 경우가 많다. */
		Date date2 = new Date(new GregorianCalendar(year, month, dayOfMonth, 
				hour, min, second).getTimeInMillis());
		System.out.println(date2);
		// Thu Sep 18 16:42:00 KST 2014
		
		
		
		
	
		
		
		
		/* 생성 된 인스턴스의 필드 정보를 Calendar 클래스에 있는 get() 메소드를 사용하여
		 * 반환 받을 수 있다.
		 *  */
		int birthYear = birthday.get(1);
		int birthMonth = birthday.get(2);
		int borthDayOfMonth = birthday.get(5);
		
		System.out.println(birthYear);
		System.out.println(birthMonth);
		System.out.println(borthDayOfMonth);
		
//		2014
//		8		// 9월이지만 0부터 고려되기 때문에 8로 나온다.
//		18
		
		
		
		
		
		
		
		/* birthday.get(1)의 1,2,5는 무엇을 의미할까? 
		 * 년, 월, 일의 의미를 담아서 상수필드에 지정한 것이다. */
		
		/* 인자로 전달하는 정수에 따라 필드 값을 반환 받을 수 있다.
		 * 하지만 이렇게 사용하게 되면 각 필드에 매칭되는 정수를 다 외워야 사용이
		 * 가능 해 진다. 따라서 해당값들을 상수필드 형태로 제공하고 있다. */
		System.out.println(Calendar.YEAR);
		System.out.println(Calendar.MONDAY);
		System.out.println(Calendar.DATE);
		
//		1
//		2
//		5
		
		
		
		
		/* 그러면 우리는 get() 메소드의 인자로 정수 대신 각 상수 필드값을 호출하는 
		 * 식으로 코드를 개선하면 보다 의미 전달이 쉬운 코드가 된다.
		 * 참조변수.get(Calendar.YEAR/MONTH/DATE)
		 *  */
		
		
		
		
		
		System.out.println("year : " + birthday.get(Calendar.YEAR));
		System.out.println("month : " + birthday.get(Calendar.MONTH));
		System.out.println("dayOfMonth : " + birthday.get(Calendar.DATE));
		/* 요일(일(1), 월(2), 화(3)... 토(7)의 의미이다.) */
		System.out.println("dayOfWeek : " + birthday.get(Calendar.DAY_OF_WEEK));
		
//		year : 2014
//		month : 8
//		dayOfMonth : 18
//		dayOfWeek : 5
		
		
		
		
		
		String day = "";
		switch (birthday.get(Calendar.DAY_OF_WEEK)) {
		
		case Calendar.SUNDAY : day = "일"; break;
		case Calendar.MONDAY : day = "월"; break;
		case Calendar.TUESDAY : day = "화"; break;
		case Calendar.WEDNESDAY : day = "수"; break;
		case Calendar.THURSDAY : day = "목"; break;
		case Calendar.FRIDAY : day = "금"; break;
		case Calendar.SATURDAY : day = "토"; break;
		
		}
		
		System.out.println("요일 : " + day);
		
		// 요일 : 목
		
		
		
		
		
		System.out.println("ampm : " + birthday.get(Calendar.AM_PM)); 
		//0은 오전 1은 오후
		
		System.out.println(birthday.get(Calendar.AM_PM) 
										== Calendar.AM ? "오전" : "오후");
		// 오후 출력
		
		
		
		
		System.out.println("hourOfDay : " + birthday.get(Calendar.HOUR_OF_DAY));
		// 24시간 체계
		System.out.println("hourOfDay : " + birthday.get(Calendar.HOUR));
		// 12시간 체계
//		hourOfDay : 16
//		hourOfDay : 4
		
		
		
		System.out.println("min : " + birthday.get(Calendar.MINUTE));
		System.out.println("min : " + birthday.get(Calendar.SECOND));
//		min : 42
//		min : 0
		
		
		
	}

}

 

 

 

 

 

 

 

 

 

제네릭

 

 

 

 

 

 

제네릭(Generic)이란?
  • 데이터의 타입을 일반화 한다는 것을 의미
  • 제네릭을 활용하면 타입 변환 및 타입 검사에 들어가는 코드 생략이 가능

 

타입을 특정화 하는게 아닌 일반화 해둔다

 

 

 

 

 

 제네릭 클래스에 extends 키워드를 사용해 타입 제한 가능

 

 

 

 

 

 

 

 

 

GenericTest<T>
public class GenericTest<T> {

		/* 제네릭 설정은 클래스 선언부 마지막 부분에 다이아몬드 연산자
		 * 를 이용하여 작성하게 된다. 다이아몬드 연산자 내부에 작성하는 
		 * 영문자는 관례상 대문자로 작성한다.
		 *  */	


		/* 다이아몬드 연산자 내부에 작성한 T는 타입변수라고 부른다.
		 * 타입 변수를 자료형 대신 사용할 것인데, 가상으로 존재하는 타입이며
		 * T가 아닌 영문자를 사용해도 무방하다.
		 * 또한 여러개의 타입변수를 작성할 때는 ,를 이용하여 여러개를
		 * 기술 할 수도 있다.
		 * 사용하는 쪽에서 작성한 제네릭 클래스를 이용할 시 
		 * 실제 사용할 타입을 타입변수자리에 맞춰서 넣어주게 되면
		 * 컴파일 시점에서 타입이 결정되게 된다. 
		 * 
		 *  */
		
		
	
		/* 현재 해당 필드는 타입이 결정되지 않은 상태이다. */
		private T value;
		
		/* setter/getter 작성시에도 구체적인 타입 대신 T를 이용할 수 있다. */
		public void setValue(T value) {
			this.value = value;
		}
		
		public T getValue() {
			return this.value;
		}
		
		
}

 

 

 

Application 
public class Application {

	public static void main(String[] args) {

		/* 제네릭(generic) */
		/* 제네릭의 사전적인 의미는 일반적인 이라는 의미이다.
		 * 자바에서 제네릭이란 데이터의 타입을 일반화한다는 의미를 가진다.
		 * 
		 *  제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에
		 *  지정하는 방법을 말한다.
		 *  컴파일시에 미리 타입 검사를 시행하게 되면 클래스나 메소드 내부에서 사용되는 객체의
		 *  타입안정성을 높일 수 있으며, (잘못된 타입인 경우 컴파일 에러를 발생시킴)
		 *  반환 값에 대한 타입 변환 및 타입 검사에 들어가는 코드 생략이 가능해진다.
		 *  (instanceof비교 및 다운 캐스팅 작성 불필요)
		 *  
		 *  
		 *  JDK 1.5 버전부터 추가된 문법이다. 
		 *  
		 *  */
		
		
		
		/* 타입을 Integer로 인스턴스를 생성하는 경우 */
		GenericTest<Integer> gt1 = new GenericTest<Integer>();
		
		
		
		/* 메소드의 인자 및 반환 값 모두 Integer 타입인 것을 알 수 있다. */
		gt1.setValue(10);
		System.out.println(gt1.getValue());
		System.out.println(gt1.getValue() instanceof Integer);
		
//		10
//		true
		
		
		
		
		
		/* 타입을 String 으로 인스턴스를 생성하는 경우 */
		GenericTest<String> gt2 = new GenericTest<String>();
		gt2.setValue("홍길동");
		System.out.println(gt2.getValue());
		System.out.println(gt2.getValue() instanceof String);		
		
		
		
		
		
		/* JDK 7부터 타입 선언시 타입변수가 작성되면 타입 추론이 가능하기 때문에
		 * 생성자 쪽의 타입을 생략하고 사용할 수 있게 한다.
		 *  */
		GenericTest<Double> gt3 = new GenericTest<>();  
		// GenericTest<> 타입을 추론할 수 있는 기능 : 더블을 썼으니 더블일 것이다.
		gt3.setValue(0.5);
		System.out.println(gt3.getValue());
		System.out.println(gt3.getValue() instanceof Double);		
		
		
	}

}

 

 

 

 

 

 

 

 

 

 

 

 

 

와일드카드

 

제네릭 클래스 타입의 객체를 메소드의 매개변수로 받을 때 그 객체의 타입을 제한 가능
  • <?> : 제한 없음
  • <? Extends Type> : 와일드카드의 상한 제한 (Type과 Type의 후손을 이용해 생성한 객체만 매개변수로
    사용 가능)
  • <? super Type> : 와일드카드 하한 제한 (Type과 Type의 부모를 이용해 생성한 객체만 매개변수로 사용 가능)

 

 

//NewAvante이거나 그 후손 타입으로 만들어진 자동차만 매개변수로 사용 가능

 

//NewAvante이거나 그 부모 타입으로 만들어진 자동차만 매개변수로 사용 가능

 

 

 

 

 

 

 

 

Application1
import com.greedy.section02.extend.Bunny;
import com.greedy.section02.extend.DrunkenBunny;
import com.greedy.section02.extend.Rabbit;
import com.greedy.section02.extend.RabbitFarm;

public class Application1 {

	public static void main(String[] args) {

		
		/* 제네릭 클래스 작성 시 extends 키워드를 이용하면
		 * 특정 타입만 사용하도록 제한을 걸 수 있다.  */
		
		
		
		
		/* 토끼의 후손이거나 토끼인 경우에만 타입으로 사용 가능하다.
		 * 그 외의 타입으로 타입 지정 시 컴파일 단계에서 에러를 발생시킨다. */
		
		
		/* Animal 타입으로는 제네릭 클래스 인스턴스 생성이 불가능하다. */
		// RabbitFarm <Animal> farm1 = new RabbitFarm<> () ;	
		// 다른 패키지 이므로 임포트 필요
		
		/* Mammal 타입으로는 제네릭 클래스 인스턴스 생성이 불가능하다. */
		// RabbitFarm <Mammal> farm1 = new RabbitFarm<> () ;	
		
		/* 전혀 다른 타입인 Snake 타입으로는 제네릭 클래스 인스턴스 생성이 불가능하다. */
		// RabbitFarm <Snake> farm1 = new RabbitFarm<> () ;	
		
		
		
		
		
		
		
		/* Rabbit 타입이나 Rabbit의 후손으로는 인스턴스 생성이 가능하다. */
		RabbitFarm<Rabbit> farm1 = new RabbitFarm<> () ; // 임포트 필요
		RabbitFarm<Bunny> farm2 = new RabbitFarm<> () ; // 임포트 필요
		RabbitFarm<DrunkenBunny> farm3 = new RabbitFarm<> () ; // 임포트 필요
		
		
		
		
		
		
		/* 제네릭을 사용해서 올바른 타입을 타입 변수로 지정하는 경우에는 
		 * 인스턴스 내부에 있는 타입 자체가 Rabbit 타입을 가지고 있는 것이
		 * 보장되어 있기 때문에 형변환 생략이 가능하다. 
		 *  */
		
		farm1.setAnimal(new Rabbit());
		((Rabbit)farm1.getAnimal()).cry();  // 굳이 타입캐스팅하지않아도 된다.
		farm1.getAnimal().cry();
//		토끼가 울음 소리를 냅니다. 끾끾!

	
		farm2.setAnimal(new Bunny());
		farm2.getAnimal().cry();
//		바니바니 바니바니 당근 당근
		
		
		farm3.setAnimal(new DrunkenBunny());
		farm3.getAnimal().cry();
//		봐니봐니 봐니봐니 당근! 당귿@!#$@
		
		
		
	}

}

 

 

 Application2
import com.greedy.section02.extend.Bunny;
import com.greedy.section02.extend.DrunkenBunny;
import com.greedy.section02.extend.Rabbit;
import com.greedy.section02.extend.RabbitFarm;
import com.greedy.section02.extend.WildCardFarm;

public class Application2 {

	public static void main(String[] args) {


		/* 와일드 카드(WildCard) 
		 * 제네릭 클래스 타입의 객체를 메소드의 매개변수로 받을 때,
		 * 그 객체의 타입변수를 제한 할 수 있다.
		 * 
		 * 
		 * <?> : 제한 없음
		 * <? extends Type> :  와일드 카드의 상한 제한, 상속받은 클래스만 사용가능
		 * 		(Type 과 Type의 후손을 이용해 생성한 인스턴스만 인자로 사용가능)
		 * <? super Type> : 와일드 카드의 하한 제한, 상속하는 상위 클래스만 사용가능
		 * 		(Type 과 Type의 부모를 이용해 생성한 인스턴스만 인자로 사용가능)
		 * 
		 * */
		
		
		
		
		/* WildCardFarm 객체생성 */
		
		WildCardFarm wildCardFarm = new WildCardFarm(); //임포트 필요
		
		
		
		
		/* 농장 생성 자체가 불가능 한 것은 매개변수로 사용할 수 없다. */
		// wildCardFarm.anyType(new RabbitFarm<Mammal>(new Mammal()));
		
		
		
		
		
		
		/* 매개변수의 타입 제한이 없는 경우 */
		
		wildCardFarm.anyType(new RabbitFarm<Rabbit>(new Rabbit()));
//		토끼가 울음 소리를 냅니다. 끾끾!
		
		wildCardFarm.anyType(new RabbitFarm<Bunny>(new Bunny()));
//		바니바니 바니바니 당근 당근
		
		wildCardFarm.anyType(new RabbitFarm<DrunkenBunny>(new DrunkenBunny()));
//		봐니봐니 봐니봐니 당근! 당귿@!#$@
		
		
		
		
		
		
		
		/* Bunny 이거나 Bunny의 후손 토끼 농장만 매개변수로 사용이 가능한 경우 */
		
//		wildCardFarm.extendsType(new RabbitFarm<Rabbit>(new Rabbit()));
// 에러 : in the type WildCardFarm is not applicable for the arguments (RabbitFarm<Rabbit>)
//Bunny 이거나 Bunny의 후손만 가능한데 Rabbit은 그 상위 타입이기 때문
		
		wildCardFarm.extendsType(new RabbitFarm<Bunny>(new Bunny()));
//		바니바니 바니바니 당근 당근
		
		wildCardFarm.extendsType(new RabbitFarm<DrunkenBunny>(new DrunkenBunny()));
//		봐니봐니 봐니봐니 당근! 당귿@!#$@
		
		
		
		
		
		/* Bunny 이거나 Bunny의 상위 토끼 농장만 매개변수로 사용이 가능한 경우 */
		
		wildCardFarm.superType(new RabbitFarm<Rabbit>(new Rabbit()));
		
		wildCardFarm.superType(new RabbitFarm<Bunny>(new Bunny()));
//		바니바니 바니바니 당근 당근
		
//		wildCardFarm.superType(new RabbitFarm<DrunkenBunny>(new DrunkenBunny()));
// 에러:	in the type WildCardFarm is not applicable for the arguments (RabbitFarm<DrunkenBunny>)
// Bunny 이거나 Bunny의 부모만 가능한데 DrunkenRabbit은 그 하위 타입이기 때문
		
		
		

	}

}

 

 

interface Animal
public interface Animal {

	/* 해당 인터 페이스를 상속받는 Mammal(포유류) 클래스를 만들자 */
	
	
}

 

Bunny extends Rabbit

/* 바니도 한종류의 토끼이다. Rabbit을 상속받는다. */
public class Bunny extends Rabbit {

	/* cry() 메소드를 오버라이딩하자 */
	
	@Override
	public void cry () {
		System.out.println("바니바니 바니바니 당근 당근");
	}
	
	/* Bunny 를 상속 받는 DrunkenBunny를 만들자 */

	
}

 

DrunkenBunny extends Bunny
/* DrunkenBunny는 Bunny를 상속받는다. */
public class DrunkenBunny extends Bunny {


	@Override
	public void cry() {
		System.out.println("봐니봐니 봐니봐니 당근! 당귿@!#$@");
	}
	
	
	/* 이제 제네릭을 이용한 클래스를 하나 만들자
	 * RabbitFarm (토끼 농장) */
	
	
	
}

 

Mammal implements Animal
/* 포유류도 동물이기 때문에 Animal 인터페이스를 상속받는다. */
public class Mammal implements Animal{

	/* 파충류 클래스도 만든다. (Reptile) */
	
}

 

Rabbit extends Mammal
/* Mammal 클래스를 상속받는다. */
public class Rabbit extends Mammal {

	public void cry() {
		System.out.println("토끼가 울음 소리를 냅니다. 끾끾!");
	}
	
	
	
	/* Reptile 클래스를 상속받는 Snake 클래스를 만들자 */
}

 

RabbitFarm <T extends Rabbit>
	
	/* 타입변수는 아직 어떤 토끼가 될 지 모른다. 
	 * 단, 토끼이거나 토끼의 후손만 가능하다.
	 *  */
	
	private T animal ;
	
	/* 생성자 */
	public RabbitFarm() {}
	
	public RabbitFarm (T animal) {
		this.animal = animal;
	}
	
	
	/* 세터 게터 */
	public void setAnimal (T animal) {
		this.animal = animal;
	}
	
	public T getAnimal () {
		return this.animal;
	}
	
	
}

 

Reptile implements Animal
/* 파충류도 동물이기 때문에 Animal 인터페이스를 상속받는다. */
public class Reptile implements Animal{

	/* Mammal 클래스를 상속받는 Rabbit 클래스를 만들자 */

}

 

 Snake extends Reptile
/* Reptile을 상속받는다. */
public class Snake extends Reptile{

	/* Rabbit 클래스를 상속받는 Bunny 클래스를 만들자. */
	
	
}

 

WildCardFarm
public class WildCardFarm {

	/* 매개변수로 전달 받는 토끼농장을 구현할 때 사용한 
	 * 타입변수에 대해 제한 할 수 있다. 
	 * 
	 * */
	
	
	/* 토끼 농장에 있는 토끼가 어떤 토끼던 상관없다. */
	public void anyType(RabbitFarm<?> farm) {
		farm.getAnimal().cry();
		
	}
	

	
	
	/* 토끼 농장의 토끼는 Bunny 이거나 그 후손 타입으로 만들어진 
	 * 토끼농장만 매개변수로 사용 가능 */
	public void extendsType(RabbitFarm<? extends Bunny> farm) {
		farm.getAnimal().cry();
		
	} // bunny를 상속받은 친구만 가능하다는 뜻  // 상한을 둠(상위방향에 한계를 둠)
	
	
	
	
	
	/* 토끼 농장의 토끼는 Bunny 이거나 그 부모 타입으로 만들어진 
	 * 토끼농장만 매개변수로 사용 가능 */
	public void superType(RabbitFarm<? super Bunny> farm) {
		farm.getAnimal().cry();
		
	} // bunny를 상속받은 친구만 가능하다는 뜻  // 하한을 둠 (아래방향에 한계를 둠)
	
	
	
}

 

 

 

 

 

 

 

 

 

'Programming > JAVA' 카테고리의 다른 글

예외 처리  (0) 2022.01.11
컬렉션  (0) 2022.01.10
자바 API  (0) 2022.01.06
다형성  (0) 2022.01.05
상속  (0) 2022.01.04

 

 

 

 

 

 

 

API

 

 

 

 

API(Application Programming Interface)란?
  • 응용 프로그램에서 사용할 수 있도록 운영체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든
    인터페이스
  • 이전에 배운 인터페이스와는 다른 개념이다.
  • API는 패키지 별로 묶여있다.

 

 

자바 API
  • 자바 플랫폼 위에서 동작하는 애플리케이션 개발 시 활용 (유용한 클래스 및 인터페이스 제공)
  • JDK를 설치하면 시스템을 제어하거나 편의 기능을 위한 API를 제공

 

 

 

 

 

Object

 

모든 클래스는 Object 클래스의 후손
  • java.lang 패키지에 존재
  • Obejct 클래스가 가진 메소드 중 관례상 많이 오버라이딩 해서 사용하는 메소드들이 존재
    ex) toString(), equals(), hashCode()
  • java.lang 패키지는 자동으로 임포트 되기 때문에 따로 임포트 해 줄 필요없다.

 

  • 제공하는 메소드
toString( ) 문자열로 변환
인스턴스 생성 시 사용한 full class name, @, 그리고 16진수 해쉬코드가 문자열로 반환
equals( )  매개변수로 전달 받은 인스턴스와 == 연산하여 true 또는 false를 반환
동일 인스턴스인지를 비교, '같은지'를 물어보는데 '주소값'을 기준으로 물어보는 것
(동일 객체 : 주소가 동일한 인스턴스)
(동등 객체 : 주소가 다르더라도 필드 값이 동일한 인스턴스)
hashCode( )  인스턴스의 주소값을 변환하여 생성한 인스턴스의 고유 값을 반환

 

 

 

 

class Book
public class Book {

	/* 필드생성 */
	private int number;
	private String title;
	private String author;
	private int price;
	
	
	
	
	/* 기본생성자 */
	public Book() {
		super();
	}
	
	
	
	
	/* 매개변수 생성자 */
	public Book(int number, String title, String author, int price) {
		super();
		this.number = number;
		this.title = title;
		this.author = author;
		this.price = price;
	}
	
	
	
	
	/* 게터와 세터 */
	public int getNumber() {
		return number;
	}
	public void setNumber(int number) {
		this.number = number;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}




	
	
	/* 우클릭 - source - Generate toString() 생성 */
	@Override
	public String toString() {
		return "Book [number=" + number + ", title=" + title + ", author=" + author + ", price=" + price + "]";
	}





	
	
	
	/* toString()에 대해서 오버라이딩 */
//	@Override
//	 public String toString() {
//	        return "Book [number=" + this.number
//	        		+ ", title=" + this.title
//	        		+ ", author=" + this.author
//	        		+ ", price=" + this.price
//	        		+ "]";
//	    }
	
	
	
	
	
	/* equals------------------------------------------------ */
	
	/* equals()에 대해서 오버라이딩 */
	
	

	@Override
	public boolean equals(Object obj) {
		
		/* 두 인스턴스의 주소가 같으면 이후 다른 내용을 비교할 것 없이 
		 * true 반환, 즉 주소가 동일한 인스턴스(동일 객체)인지 확인 */
		if (this == obj)
			return true;
		
		
		/* this는 인스턴스가 생성되면 주소값이 저장된다. null일 수 없다.
		 * 따라서 전달 받은 레퍼런스 변수에 null값이 저장 돼 있다면 
		 * 비교하려는 두개의 인스턴스는 서로 다른 인스턴스이다.
		 *  */
		if (obj == null)
			return false;
		
		
		
		
		/* 동일한지의 여부를 묻고싶은 것이므로 
		 * this와 obj의 클래스가 같지 않다면 필드값을 비교할 필요가 없다. */
		if (getClass() != obj.getClass())
			return false;
		
		
		
		
		/* 전달 받은 레퍼런스 변수를 Book 타입으로 
		 * (강제)형변환하여 각 필드별로 비교를 시작한다. */
		Book other = (Book) obj;
		
		
		
		
		/* String 타입의 경우 null여부 먼저 확인 */
		if (author == null) {
			if (other.author != null)
				return false;		// this상 null other는 not null이므로 false
			
			
			
		/* this가 null이 아닌 경우 String 클래스의 equals를 호출해서 값 비교 */
		} else if (!author.equals(other.author))
			return false;
		
		
		
		
		
		
		/* 숫자값은 비교적 쉽게 바로 값 비교 가능 */
		if (number != other.number)
			return false;
		if (price != other.price)
			return false;
		
		
		
		
		
		
		
		/* title도 String 타입이므로 author와 동일 */
		if (title == null) {
			if (other.title != null)
				return false;	// null
		} else if (!title.equals(other.title))
			return false;
		
		
		
		
		/* 모든 조건을 통과하면 두 인스턴스의 모든 필드는 같은 값을
		 * 가지므로 true 반환 */
		return true;
	}
	
	
	/* 객체의 동등성을 비교하기 위해서 equals를 오버라이딩 한다. */
//	두 인스턴스의 == 연산비교 : false
//	두 인스턴스의 == 연산비교 : true

	

	
	
	
	
	
	
	/*  hashCode------------------------------------------------ */
	

	@Override
	public int hashCode() {
		
		
		/* 필드마다 곱해줄 소수값 선언
		 * 31은 소수이기 때문에 연산 시 동일한 hashCode 값이 나오지않을 확률을
		 * 증가시킨다. 
		 * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
		 * 
		 * 31이 통상 적인 관례이며 String 클래스의 hashCode에도 사용한 값이다. 
		 * 아주 낮은 확률로 같은 수가 나오는 경우가 있을 수 있지만 소수값은 
		 * 그 확률을 최소화 시킨다. 
		 * 
		 * */
		
		
		/* 필드값이 같으면 동일 해쉬코드를 반환한다 : 를 확인하기 위한 목적 */
		final int prime = 31;
		
		
		/* prime(31)과의 곱셉 연산을 result에 누적시킨 값 선언 */
		int result = 1;
		
		
		
		/* String 클래스의 hashCode메소드는 이미 재정의 되어있다.
		 * 같은 값을 가지는 문자열은 동일한 hashCode값을 반환한다.
		 *  */
		result = prime * result + ((author == null) ? 0 : author.hashCode());
		result = prime * result + number;
		result = prime * result + price;
		result = prime * result + ((title == null) ? 0 : title.hashCode());
		
		
		/* 동등 객체는 동일한 hashCode값을 반환하게 된다. */
		return result;
		
		
//		book1의 hashCode : 2010084336
//		book2의 hashCode : 2010084336
	}


	
	
}

 

 

class Application1
import com.greedy.section01.object.book.Book;

public class Application1 {

	public static void main(String[] args) {


		
		Book book1 = new Book(1, "홍길동전", "허균", 50000);
		Book book2 = new Book(2, "목민심서", "정약용", 30000);
		Book book3 = new Book(3, "칭찬은 고래를 춤추게 한다", "고래", 40000);
		
		System.out.println("book1.toString : " + book1.toString());
		System.out.println("book2.toString : " + book2.toString());
		System.out.println("book3.toString : " + book3.toString());

		
		
		
		
		/* java.lang.Object 클래스의 toString()메소드는
		 * 인스턴스가 생성될 때 사용한 full class name과 @ 그리고 16진수 해쉬코드가
		 * 문자열로 반환된다. 16진수 해쉬코드는 인스턴스의 주소를 가리키는 값으로 
		 * 인스턴스마다 모두 다르게 반환된다. */
		
//  return getClass().getName() + "@" + Integer.toHexString(hashCode());		
//		book1.toString : com.greedy.section01.object.book.Book@4926097b
//		book2.toString : com.greedy.section01.object.book.Book@39ed3c8d
//		book3.toString : com.greedy.section01.object.book.Book@71dac704
		


		
		
		/*(+)
		 * 레퍼런스 변수만 출력하는 경우도 동일한 결과가 나온다.
		 * 이 경우도 자동으로 toString()메소드를 호출한다.
		 * 이러한 점을 이용해서 toString() 메소드를 재정의해서 사용하게된다. */
		System.out.println("book1 : " + book1);
		System.out.println("book2 : " + book2);
		System.out.println("book3 : " + book3);
		
//		book1 : com.greedy.section01.object.book.Book@4926097b
//		book2 : com.greedy.section01.object.book.Book@39ed3c8d
//		book3 : com.greedy.section01.object.book.Book@71dac704
		
		
		
		
		
		
		/* toString을 오버라이딩 한 결과 */
//		book1 : Book [number=1, title=홍길동전, author=허균, price=50000]
//		book2 : Book [number=2, title=목민심서, author=정약용, price=30000]
//		book3 : Book [number=3, title=칭찬은 고래를 춤추게 한다, author=고래, price=40000]

		/* 상속관계이므로 Object의 모든 기능을 book도 이용할 수 있다.
		 * 오버라이드시 후손의 메소드를 호출하는 것이다.
		 * toString을 자식클래스에서 재정의했으므로 
		 * 부모클래스인 오브젝트의 toString 호출시 book에서 재정의한 결과가 나온다. */
		
		
		
		
		
	}

}

 

 

class Application2
import com.greedy.section01.object.book.Book;

public class Application2 {

	public static void main(String[] args) {


		
		
		/* java.lang.Object 의 equals는 매개변수로 전달받은 
		 * 인스턴스와 == 연산하여 true or false 를 반환한다. 
		 * 즉, 동일한 인스턴스인지 비교하는 기능을 한다.
		 * 
		 * 동일 객체와 동등객체
		 * 동일객체 : 주소가 동일한 인스턴스를 동일객체라고 한다.
		 * 동등객체  : 주소는 다르더라도 필드 값이 동일한 객체를 동등객체라고 한다. 
		 * 
		 * equals() 메소드의 기본 기능은 동일객체 판단을 한다고 볼 수 있다.(동일성 확인)
		 * 그러한 경우 equals()를 오버라이딩하여 각각의 필드가 동일한 값을 가지는기 확인하고
		 * 모든 필드값이 같은 값을 가지는 경우 true, 아닌 경우 false를 반환하도록 작성한다.
		 * 
		 * */
		
		
		Book book1 = new Book(1, "홍길동전", "허균", 50000);
		Book book2 = new Book(1, "홍길동전", "허균", 50000);
		
		System.out.println("두 인스턴스의 == 연산비교 : " + (book1 == book2));
		System.out.println("두 인스턴스의 == 연산비교 : " + (book1.equals(book2)));
		
		/* 동일객체 비교 */
//		두 인스턴스의 == 연산비교 : false
//		두 인스턴스의 == 연산비교 : false
		
		/* 오버라이딩 후 동등객체 비교 */
//		두 인스턴스의 == 연산비교 : false
//		두 인스턴스의 == 연산비교 : true
		
		
		
		

	}

}

 

 

class Application3
import com.greedy.section01.object.book.Book;

public class Application3 {

	public static void main(String[] args) {

		
		/* Object 클래스의 명세에 작성 된 일반 규약에 따르면 
		 * equals() 메소드를 재 정의하는 경우 반드시 hashCode() 메소드도
		 * 재정의하게 되어 있다.(hashCode와 equals는 같이 간다고 생각)
		 * 만약 hashCode()를 재정의하지 않으면 같은 값을 가지는 동등 객체는
		 * 같은 해시코드 값을 가져와야 한다는 규약을 위반하게 된다. 
		 * (강제성은 없지만 규약대로 작성하는 것이 좋음)
		 */
		
		/* 동등 객체 생성 후 hashCode를 출력하면
		 * java.lang.Object 는 인스턴스 주소이므로 다른값이 나온다.
		 * 오버라이딩해서 동등 객체의 경우 같은 hashCode 를 리턴하도록 한다.  */
		
		
		Book book1 = new Book(1, "홍길동전", "허균", 50000);
		Book book2 = new Book(1, "홍길동전", "허균", 50000);
		
		System.out.println("book1의 hashCode : " + book1.hashCode());
		System.out.println("book2의 hashCode : " + book2.hashCode());
		
		
		/* 출력시 필드값은 같은 동등객체임을 알 수 있다. 주소값은 다르다. */
//		book1의 hashCode : 1227229563
//		book2의 hashCode : 971848845
		
		
		/* 동등객체 판단을 위한 오버라이딩 */
		/* hashCode 오버라이딩 후 동등객체로 판단되어 같은 주소값을 반환한다. */
//		book1의 hashCode : 2010084336
//		book2의 hashCode : 2010084336
		

		

	}

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

String

Java.lang 패키지에 존재하는 클래스로 문자열을 처리하는 여러가지 메소드를 제공

 

  • 제공하는 메소드
charAt()  해당 문자열의 특정 인덱스에 해당하는 문자 반환
compareTo()  두 문자열이 같은지 다른지에 따라 int 값을 반환
compareToIgnoreCase() 대소문자를 구분하지 않고 비교 후 int 값을 반환
concat() 문자열에 인자로 전달 된 문자열을 합침
indexOf() 문자열을 앞에서부터 탐색하여 일치하는 위치의 인덱스를 int 값으로 반환
lastIndexOf() 문자열을 뒤에서부터 탐색하여 일치하는 위치의 인덱스를 int 값으로 반환
trim() 문자열의 앞 뒤 공백을 제거 후 문자열을 반환
toLowerCase()  모든 문자를 소문자로 변환 후 문자열을 반환
toUpperCase()  모든 문자를 대문자로 변환 후 문자열을 반환

 

 

 Application1
public class Application1 {

	public static void main(String[] args) {


		
		
		/* String 클래스의 자주 사용되는 메소드 */
		
		/* chatAt() : 해당 문자열의 특정 인덱스에 해당하는 문자를 반환한다.
		 * 인덱스는 0부터 시작하는 숫자 체계를 의미하며
		 * 인덱스를 벗어난 정수를 인자로 전달하는 경우에는 IndexOutOfBoundsException
		 * 이 발생한다. */
		String str1 = "apple";
		
		for (int i = 0; i < str1.length(); i++) {
			System.out.println("charAt(" + i + ")" + str1.charAt(i));
		}
		
//		charAt(0)a
//		charAt(1)p
//		charAt(2)p
//		charAt(3)l
//		charAt(4)e
		

		
		
		/* compareTo() : 인자로 전달된 문자열과 사전 순으로 비교를 하여
		 * 두 문자열이 같아면 0을 반환, 인자로 전달된 문자열보다 작으면 음수를,
		 * 크면 양수를 반환한다.
		 * 단, 이 메소드는 대소문자를 구분하여 비교한다.
		 *  */
		
		String str2 = "java";
		String str3 = "java";
		String str4 = "JAVA";
		String str5 = "oracle";
		
		
		
		
		/* 같으면 0을 반환한다. */
		System.out.println("compareTo() : " + (str2.compareTo(str3)));
//		compareTo() : 0
		
		
		
		/* 대문자와 소문자는 32만큼 차이가 난다. */
		System.out.println("compareTo() : " + (str2.compareTo(str4)));
		System.out.println("compareTo() : " + (str4.compareTo(str2)));
//		compareTo() : 32
//		compareTo() : -32
		
		
		/* j부터 o까지 5만큼 차이가 난다. */
		System.out.println("compareTo() : " + (str2.compareTo(str5)));
		System.out.println("compareTo() : " + (str5.compareTo(str2)));
//		compareTo() : -5
//		compareTo() : 5
		
		
		
		/* 목적 : 음수가 나오는지 양수가 나오는지를 
		 * 파악하여 어느값이 앞 뒤에있는지 판단하기 위함 
		 * 즉, 구체적으로 어떤 값이 나오는지보다 양수인지 음수인지를
		 * 판단할 목적으로 주로 사용된다. 
		 * */
		
		
		
		
		
		
		/* 대소문자를 구분하지않고 비교한다. */
		/* 대소문자를 비교하는 메소드 : compareToIgnoreCase() */
		System.out.println(str3.compareToIgnoreCase(str4));
//		0, 출력값 0, 즉 대소문자만 다른 java가 같은 값이란 얘기이다.
		
		
		
		
		
		/* concat() : 문자열에 인자로 전달 된 문자열을 합치기 
		 * 해서 새로운 문자열을 반환한다. 
		 * 단 합쳐진 이후, 원본 문자열에는 영향을 주지 않는다.
		 * */
		System.out.println("concat() : " + (str2.concat(str5)));
		System.out.println("str2 : " + str2);
//		concat() : javaoracle
//		str2 : java
		
		
		
		
		
		/* indexOf() : 문자열에서 특정 문자를 탐색하여 처음일치하는 
		 * 인덱스 위치를 정수형으로 반환한다.
		 * 단, 일치하는 문자가 없는 경우 -1을 반환한다.
		 *  */
		
		String indexOf = "java oracle";
		System.out.println("indexOf('a') : " + indexOf.indexOf('a'));
		System.out.println("indexOf('z') : " + indexOf.indexOf('z'));
		
//		indexOf('a') : 1
//		indexOf('z') : -1	// 인덱스로 존재할 수 없는 정수값
		
		
		
		
		
		/* lastIndexOf() : 문자열 탐색을 뒤에서부터 하고 
		 * 처음 일치하는 위치의 인덱스를 반환한다.
		 * 단, 일치하는 문자가 없는 경우 -1을 반환한다.
		 *  */
		System.out.println("lastIndexOf('a') : " + indexOf.lastIndexOf('a'));
		System.out.println("lastIndexOf('z') : " + indexOf.lastIndexOf('z'));
		
//		lastIndexOf('a') : 7
//		lastIndexOf('z') : -1
		
		
		
		
		
		/* trim() : 문자열 앞 뒤에 공백을 제거한 문자열을 반환한다.  */
		String trimStr = " java ";
		
		System.out.println("trimStr : #" + trimStr + "#");
		System.out.println("trim() : #" + trimStr.trim() + "#");
		
		/* 원본에 영향을 주지는 않는다. */
		System.out.println("trimStr : #" + trimStr + "#");
		
//		trimStr : # java #
//		trim() : #java#
//		trimStr : # java #
		
		
		
		
		
		
		/* toLowerCase() : 모든 문자를 소문자로 변환시킨다.
		 * toUpperCase() : 모든 문자를 대문자로 변환시킨다.
		 * 원본에는 영향을 주지 않는다.
		 * */
		
		String caseStr = "JavaOracle";
		System.out.println("toLowerCase() : " + caseStr.toLowerCase());
		System.out.println("toUpperCase() : " + caseStr.toUpperCase());
		System.out.println("caseStr : " + caseStr);
		
//		toLowerCase() : javaoracle
//		toUpperCase() : JAVAORACLE
//		caseStr : JavaOracle
		
		
		
		
		
		
		/* substring() : 문자열의 일부를 잘라내어 새로운 문자열을 반환한다.
		 * 원본에는 영향을 주지 않는다.
		 *  */
		String javaoracle = "javaoracle";
		
		System.out.println("substring(3,6) : " + javaoracle.substring(3,6));
		System.out.println("substring(3) : " + javaoracle.substring(3));
		System.out.println("javaoracle : " + javaoracle);
		
//		substring(3,6) : aor			// 인덱스 3,4,5 까지 추출한다는 의미
//		substring(3) : aoracle			// 시작인덱스 3부터 문자열의 끝까지 추출
//		javaoracle : javaoracle
		
		
		
		
		
		
		/* replace() : 문자열에서 대체할 문자열로 기존 문자열을 변경해서 반환한다.
		 * 원본에는 영향을 주지 않는다. */
		
		System.out.println("replace() : " + javaoracle.replace("java", "python"));
		System.out.println("javaoracle : " + javaoracle);
		
//		replace() : pythonoracle		// 자바를 파이썬으로 변경한다는 의미
//		javaoracle : javaoracle
		
		
		
		
		
		
		/* length() : 문자열의 길이를 정수형으로 반환한다. */
		System.out.println("length() : " + javaoracle.length());
		System.out.println("빈문자열길이 : " + ("".length()));
		
//		length() : 10
//		빈문자열길이 : 0
		
		
		
		
		
		/* isEmpty() : 문자열의 길이가 0이면 true를 반환, 아니면 false를 반환
		 * 길이가 0인 문자열은 null과는 다르다. */
		
		System.out.println("isEmpty() : " + "".isEmpty());
		System.out.println("isEmpty() : " + "abc".isEmpty());
		
//		isEmpty() : true
//		isEmpty() : false
		
		
		
	}

}

 

 

Application2
public class Application2 {

	public static void main(String[] args) {


		/* 문자열 객체 사용하는 방법 */
		
		/* "" 리터럴 형태 : 동일한 값을 가지는 인스턴스를 
		 * 단일 인스턴스로 관리한다. (singleton) 
		 * 즉, 같은 문자열에 대해선 더이상 인스턴스를 생성하지않는다.
		 * 
		 * new String("문자열") : 매번 새로운 인스턴스를 생성한다.
		 * 
		 * 즉 같은 리터럴이어도 생성 방식이 다르다.
		 * */
		
		
		String str1 = "java";
		String str2 = "java";
		String str3 = new String("java");
		String str4 = new String("java");
		
		/* 리터럴 형대로 만든 문자열 인스턴스는 동일한 값을 가지는 인스턴스는 하나의
		 * 인스턴스로 관리한다.
		 * 따라서 주소값을 비교하는 == 연산으로 비교시 서로 동일한 주소를 비교하여
		 * true를 반환한다. */
		System.out.println(" str1 == str2 " + ( str1 == str2 ));
		// 리터럴이 같은경우 더이상 인스턴스를 생성하지않는다. 주소값이 같다고 간주한다.
		
		
		
		
		
		/* new로 새로운 인스턴스를 생성하게 되면 기존 인스턴스를 두고 새로운 인스턴스를
		 * 할당했기 때문에 == 연산으로 비교 시 서로 다른 주소값을 가지게 되므로 
		 * false 를 반환한다.  */
		System.out.println(" str2 == str3 " + ( str2 == str3 ));
		
		
		
		
		
		/* 동일한 방식으로 인스턴스를 생성하고 값 또한 같더라도
		 * 새로운 인스턴스를 생성하는 방식은 서로 다른 주소를 가지기 때문에 
		 * false를 반환한다. */
		System.out.println(" str3 == str4 " + ( str3 == str4 ));
		
	
//		 str1 == str2 true
//		 str2 == str3 false
//		 str3 == str4 false
		
		
		
		
		
		
		/* 하지만 4개의 문자열은 모두 동일한 hashCode 값을 가진다.
		 * 동일한 문자열은 동일한 hashCode값을 반환하도록 재정의 되어있기 때문이다. */
		System.out.println("str1의 hashCode : " + str1.hashCode());
		System.out.println("str2의 hashCode : " + str1.hashCode());
		System.out.println("str3의 hashCode : " + str1.hashCode());
		System.out.println("str4의 hashCode : " + str1.hashCode());
		
//		str1의 hashCode : 3254818
//		str2의 hashCode : 3254818
//		str3의 hashCode : 3254818
//		str4의 hashCode : 3254818
		
		/* 실제 인스턴스는 다르지만 같은 값을 가지면 동일하다고 간주하도록
		 * 재정의가 되어있다. 같은 문자열일 경우 동일한 객체를 참조한다. */
		
		
		
		
		
		
		/* 문자열은 불변이라는 특징을 가진다.
		 * 기존 문자열에 + 연산자를 수행하는 경우 문자열을 수정하는 것이 아닌 
		 * 새로운 문자열을 할당하게 된다. 
		 * 한번 할당된 문자열은 더이상의 변경이나 수정이 불가능하며
		 * 새로 힙 영역에 만들어 참조하는 수 밖에 없다. 
		 * */
		str2 += "oracle";
		
		
		
		
		/* str 과 str2는 동일한 인스턴스였지만 수정 후에는 다른 인스턴스가 
		 * 된 것을 알 수 있다.  */
		System.out.println("str == str2 : " + (str1 == str2));
//		str == str2 : false
		
		
		
		
		
		
		
		/* equals() : String 클래스의 equals메소드는 인스턴스 비교(주소값)가 아닌
		 * 문자열값을 비교하여 동일한 값을 가지는 경우 true, 다른 값을 가지는 경우
		 * false를 반환하도록 Object의 equals() 메소드를 재정의 해 두었다.
		 * 주소값 비교가 아닌 문자열 비교를 위해선 equals()를 써야한다.
		 * 인스턴스 생성방식과는 상관없이 문자열만을 비교한다.
		 *  */
		
		System.out.println("str1.equals(str3) : " + str1.equals(str3));
		System.out.println("str1.equals(str4) : " + str1.equals(str4));
//		str1.equals(str3) : true
//		str1.equals(str4) : true
		
		
		
		/* 참고로 Scanner 의nextLine() 등을 이용해 문자열을 읽어온 경우
		 * substring으로 잘라내기 해서 새로운 문자열을 생성 후 반환하기 때문에
		 * new String() 으로 인스턴스를 생성한 것과 동일한 것으로 볼 수 있다.
		 * 따라서 Scanner로 입력받은 문자열을 비교할 때에는 equals()를 써야한다.
		 * 구분하기 힘들면 그냥 문자열은 다 equals()로 비교하는 것이 가장 좋은 방법이다.
		 *  */
		
		
		

	}

}

 

 

 

 

 

 

 

 

 

 

 

String

 

String 메소드 
  • 문자열을 특정 구분자로 분리하는 방법

 

  • 제공하는 메소드
spilit() 정규표현식을 이용하여 문자열을 분리하며 속도가 느림
String str1 = "변수/연산자/메소드/제어문";
String[] strArr = str1.split("/");
StringTokenizer 문자열의 모든 문자들을 분리하며 split보다 속도가 빠름
구분자를 생략하는 경우 기본 구분자는 공백
String str2 = "배열/객체/상속/다형성";
StringTokenizer st = new StringTokenizer(str2, "/");

while(st.hasMoreTokens()) {
System.out.println(st.nextToken());
}

 

 

 

class Application3
import java.util.StringTokenizer;

public class Application3 {

	public static void main(String[] args) {


		/* split()과 StringTokenizer */
		
		
		
		
		/* 각 문자열의 의미는 사번/이름/주소/부서 를 의미한다. */
		String emp1 = "100/홍길동/서울/영업부";		// 모든 값 존재
		String emp2 = "200/유관순//총무부";		// 주소 없음
		String emp3 = "300/이순신/경기도/";		// 부서 없음
		
		
		
		
		/* 먼저 split을 이용해서 3명의 문자열을 정보별로 분리한다. */
		String[] empArr1 = emp1.split("/");
		String[] empArr2 = emp2.split("/");
		String[] empArr3 = emp3.split("/");
		
		for (int i = 0; i < empArr1.length; i++) {
			System.out.println("empArr1 [" + i + "] : " + empArr1[i]);
		}	//정상출력
		
		for (int i = 0; i < empArr2.length; i++) {
			System.out.println("empArr2 [" + i + "] : " + empArr2[i]);
		}	// 중간 값 빈 문자열
		
		for (int i = 0; i < empArr3.length; i++) {
			System.out.println("empArr3 [" + i + "] : " + empArr3[i]);
		}	// 마지막 값 출력 안됨
		
		
		
		
//		empArr1 [0] : 100
//		empArr1 [1] : 홍길동
//		empArr1 [2] : 서울
//		empArr1 [3] : 영업부
//		empArr2 [0] : 200
//		empArr2 [1] : 유관순
//		empArr2 [2] : 		// 슬래쉬가 두번 들어가서 비워둔 부분
//		empArr2 [3] : 총무부
//		empArr3 [0] : 300
//		empArr3 [1] : 이순신
//		empArr3 [2] : 경기도

		
		
		
		/* 한계점 : 값을 비워두자 인덱스가 하나 적게 출력 */
		/* 마지막 구분자 사이에 값이 존재하지 않는 경우 이후 값도 추출하고 싶을때
		 * 몇 개의 토큰으로 분리 할 것인지 한계치를 두번째 인자로 넣어줄 수 있다.
		 * 이때 음수를 넣게 되면 마지막 구분자 뒤의 값이 존재하지 않는 경우
		 * 빈 문자열로 토큰을 생성한다.
		 *  */
		
		String[] empArr4 = emp3.split("/", -1);
		// 뒤의 리밋 숫자대로 '줄 수'로 출력 돼 나온다.
		
		for (int i = 0; i < empArr4.length; i++) {
			System.out.println("empArr4 [" + i + "] : " + empArr4[i]);
		}	
		
		
		
		
		
		
		
		/* 반면 StringTokenizer의 경우 공백으로 존재하는 값을 무시해버린다. */
		StringTokenizer st1 = new StringTokenizer(emp1, "/");
		StringTokenizer st2 = new StringTokenizer(emp2, "/");
		StringTokenizer st3 = new StringTokenizer(emp3, "/");
		// java.util 에 있으며 임포트 해준다. 
		
		
		while (st1.hasMoreTokens()) {
			System.out.println("st1 : " + st1.nextToken());		
		}
		
		while (st2.hasMoreTokens()) {
			System.out.println("st2 : " + st2.nextToken());
		}
		
		while (st3.hasMoreTokens()) {
			System.out.println("st3 : " + st3.nextToken());
		}
		
		
		/* nextToken()으로 토큰을 꺼내면 해당 StringTokenizer의 
		 * 토큰을 재사용하는 것이 불가능하다. */
		while (st1.hasMoreTokens()) {
			System.out.println("st1 : " + st1.nextToken());		
		}
		
		
		
		
		
		/* nextToken으로 인해 토큰은 다음 커서로 이동하고 
		이전 토큰은 출력된다.
		*/
		
		
		
		
		/* 공백에 대해서는, 중복된 반복문은 무시된 결과를 확인할 수 있다. */
//		st1 : 100
//		st1 : 홍길동
//		st1 : 서울
//		st1 : 영업부
//		st2 : 200
//		st2 : 유관순
//		st2 : 총무부
//		st3 : 300
//		st3 : 이순신
//		st3 : 경기도
		
		
		
		
		
		
		
		/* split()과 StringTokenizer의 차이점 */
		/* split은 정규표현식 이용(문자열 패턴), 
		 * StringTokenizer는 구분자 문자열 이용 */
		
		String colorStr = "red*orange#blue/yellow green";
		
		/* "*#/ " 이라는 문자열이 구분자로 존재하지 않아서 에러 발생함 */
		// String[] colors = colorStr.split("*#/ ");
		
		
		/* 대괄호로 묶은 문자열은 문자열이 아닌 각 문자들의 패턴으로 볼 수 있다.
		 * 따라서 순서 상관없이 존재하는 문자들을 이용해서 구분자로 사용할 수 있다.
		 * */
		String[] colors = colorStr.split("[*#/ ]");
		
		for (int i = 0; i < colors.length; i++) {
			System.out.println("colors[" + i + "] : " + colors[i]);
		}
		
//		colors[0] : red
//		colors[1] : orange
//		colors[2] : blue
//		colors[3] : yellow
//		colors[4] : green
		
		
		
		
		
		
		/* StringTokenizer의 두번째 인자 문자열 자체는 연속 된 문자열이
		 * 아닌 하나하나를 구분자로 이용하겠다는 의미이다. */
		
	StringTokenizer colorStringTokenizer = new StringTokenizer(colorStr, "*#/ ");
		
	while (colorStringTokenizer.hasMoreTokens()) {
		System.out.println(colorStringTokenizer.nextToken());
	}
		
//	red
//	orange
//	blue
//	yellow
//	green
		
		

	}

}

 

 

 

 

 

이스케이프(escape) 문자
  • 문자열 내에서 사용하는 문자 중 특수문자를 표현하거나 특수기능을 사용할 때 사용하는 문자

 

특수문자 문자 리터럴 비고
tab \t 정해진 공간만큼 띄어쓰기
new line \n 출력하고 다음 라인으로 옮김
역슬래시 \\ 특수문자 사용지 백슬래시넣고 특수문자를 넣어야함
작은 따옴표 \'
큰 따옴표 \"
유니코드 \u 유니코드 표시할 때 사용

 

 

 

 

Application4
public class Application4 {

	public static void main(String[] args) {

		
		
		/* 개행문자 */
		System.out.println("안녕하세요. \n저는 홍길동입니다.");
		
//		안녕하세요. 
//		저는 홍길동입니다.
		

		
		
		/* 탭문자 */
		System.out.println("안녕하세요. \t저는 홍길동입니다.");
		
//		안녕하세요. 	저는 홍길동입니다.
		
		
		
		
		
		/* 홑따옴표 문자 */
		System.out.println("안녕하세요. 저는 '홍길동'입니다."); // 이스케이스 쓰지않아도 됨
		// System.out.println(''');						// 홑따옴표 문자와 문자리터럴 기호가 중복됨
		System.out.println('\'');						// 이스케이프 문자를 사용해서 구분해 주어야함

//		안녕하세요. 저는 '홍길동'입니다.
//		'	
		
		
		
		
		/* 쌍따옴표 문자 */
		//System.out.println("안녕하세요. 저는 "홍길동"입니다.");
		// 문자열 리터럴과 기호가 중복 됨
		
		System.out.println("안녕하세요. 저는 \"홍길동\"입니다.");
		
//		안녕하세요. 저는 "홍길동"입니다.
		
		
		
		
		
		/* 역슬래쉬 문자 사용 */
		System.out.println("안녕하세요. 저는 \\홍길동\\입니다.");
		
		// 역슬래쉬를 하나만 작성할 시 이스케이프 문자의 예약문자와 겹친다.
//		안녕하세요. 저는 \홍길동\입니다.
		
		
		
		/* 이러한 특수문자나 특수한 기능을 표현하는 문자를 이스케이프 문자라고 한다. */
		
		
		
		
		/* split시 이스케이프 문자를 사용해야하는 특수한 문자도 존재한다. */
		/* 이스케이프 문자 사용 안하는 특수문자
		 * ~ ` ! @ # & % - _ = ; : ' \ " , < > /
		 * 
		 * 이스케이프 문자 사용 하는 특수문자
		 * $ ^ * ( ) + | { } [ ] . ?
		 *  
		 *  */
		
		String str = "java$oracle$jdbc";
		String[] sarr = str.split("\\$");
		
		for (String s : sarr) {
			System.out.println(s);
			
		}
		
		//split("$") 사용시 다음과같이 출력된다. java/oracle/jdbc
		// split("\\$") 사용시 정상적으로 잘 구분되어 출력된다. 
//		java
//		oracle
//		jdbc
		
		
        
		
	}

}

 

 

 

 

 

 

 

 

 

 

 

 

 

StringBuilder와 StringBuffer

 

 

StringBuilder와 StringBuffer란?
  • String과 유사하지만 String이 불변이라면 StringBuilder나 StringBuffer는 가변이라는 차이점이 있다
  • StringBuilder와 StringBuffer는 기능적으론 거의 유사하다.
  • StringBuilder : 스레드 동기화 기능을 제공하지 않음
  • StringBuffer : 스레드 동기화 기능 제공
    (스레드 동기화 유무의 차이 말고는 두 클래스가 의미하는 바가 동일함)

 

  • 제공하는 메소드
capacity() 용량(현재 버퍼의 크기)을 int 값으로 반환 (문자열 길이 + 16이 기본 용량)
append() 인자로 전달 된 값을 문자열로 변환 후 기존 문자열의 마지막에 추가
delete() 시작 인덱스와 종료 인덱스를 이용해서 문자열에서 원하는 부분의 문자열 제거
insert() 인자로 전달된 값을 문자열로 변환 후 지정한 인덱스 위치에 추가
reverse()  문자열 인덱스 순번을 역순으로 재배열

 

 

Application1
public class Application1 {

	public static void main(String[] args) {
		
	
	
	/* String과 StringBuilder */

	/* String : 
	 *   불변이라는 특성을 가지고 있다.
	 *   문자열에 + 연산으로 합치기 하는 경우, 기존 인스턴스를 수정하는 것이 아닌 
	 *   새로운 인스턴스를 반환한다.
	 *   따라서 문자열 변경이 자주 일어나는 경우 성능 면에서 좋지않다.
	 *   (매번 새로운 인스턴스를 만들어야 하기 때문)
	 *   하지만 변하지 않는 문자열을 자주 읽어들이는 경우에는 좋은 성능을 기대할 수 있다.
	 * 
	 * StringBuilder : 
	 *   가변이라는 특성을 가지고 있다. 
	 *   문자열에 append() 메소드를 이용하여 합치기 하는 경우
	 *   기존 인스턴스를 수정하기 때문에 새로운 인스턴스를 생성하지 않는다.
	 *   따라서 잦은 문자열 변경이 일어나는 경우 String보다 성능이 높다.
	 *   (새로 만드는게 아닌 기존것을 수정하기 때문)
	 * 
	 * 	 단, JKD 1.5 버전부터 문자열의 + 연산이 StringBuilder의 append()로 컴파일 된다.
	 * 	 따라서 성능에 큰 차이를 보이지는 않는다.
	 * 	 하지만 반복문 에서 문자열의 + 연산을 수행하는 경우 
	 * 	 StringBuilder 인스턴스를 반복루프시 루프 마다 생성하기 때문에 
	 * 	 역시 성능에는 좋지않은 영향을 준다. 
	 * 	
	 * 
	 *  */
	
	/* 원본 코드 */
//	String str1 = "java";
//	String str2 = "oracle";
//	
//	String str3 = str1 + str2;
//	String str4 = "";
//	
//	for (int i = 0; i < 10; i++) {
//		str4 += str1;
//	}
	
	
	/* JKD  1.4이하 
	 * - 새로운 인스턴스를 매번 생성해서 할당 */
	
	/* JKD  1.5이상 */
//	String str1 = "java";
//	String str2 = "oracle";
//	
//	String str3 = new StringBuilder(str1).append(str2).toString();
//	String str4 = "";
//	
//
//	for (int i = 0; i < 10; i++) {
//		str4 += new StringBuilder(str4).append(str1).toString();
//	}
//	
	
	
	
		
		
	/* StringBuilder 인스턴스 생성 */
	StringBuilder sb = new StringBuilder("java");
	
	
	
	
	
	/* toString이 오버라이딩 되어 있다. */
	System.out.println("sb : " + sb/*.toString()*/ );
	System.out.println("sb의 hashCode : " + sb.hashCode() );
	
	/* hashCode는 오버라이딩 되어 있지 않다.
	 * 즉, 동일한 값을 가지는 경우 같은 해쉬코드를 반환하는 것이 아닌,
	 * 인스턴스가 동일해야 같은 해쉬코드를 반환한다. 
	 *  */
	
//	sb : java
//	sb의 hashCode : 1101288798
	
	
	
	
	
	
	/* 문자열 수정 */
	sb.append("oracle");
	
	System.out.println("sb : " + sb);
	System.out.println("sb의 hashCode : " + sb.hashCode() );
	/* hashCode를 다시 출력하면 기존 인스턴스와 동일한 것을 확인할 수 있다.
	 * 즉, 문자열을 변경했다고 해서 새로운 인스턴스가 생성된 것은 아니다. */
	
	
//	sb : javaoracle
//	sb의 hashCode : 1101288798
// 주소값이 똑같다는 의미? : 문자열을 추가했지만 새로운인스턴스가 생기지 않았다는 것
	
	
	
	
	
	
	}
	
	
}

 

 

Application2
public class Application2 {

	public static void main(String[] args) {


		/* StringBuilder의 자주 사용되는 메소드 */
		
		/* StringBuilder 기본 생성자로 인스턴스 생성 */
		StringBuilder sb1 = new StringBuilder();
		
		
		/* capacity() : 용량 (현재 버퍼의 크기)을 정수형으로
		 * 반환하는 메소드 (문자열 길이 + 16이 기본 용량) */
		
		System.out.println(sb1.capacity());
//		예) 인자값으로 java 전달시 20 출력
		
		
		
		
		/* append() : 인자로 전달 된 값을 문자열로 변환 후 
		 * 기존 문자열의 마지막에 추가한다. 
		 * 기본 용량을 초과하는 경우 :
		 * (기존 문자열 +1 ) * 2를 하여 용량을 확장 시킨다.
		 * */
		for (int i = 0; i < 50; i++) {
			sb1.append(i);
			
			System.out.println("sb1 : " + sb1);
			System.out.println("capacity : " + sb1.capacity());
			System.out.println("hashCode : " + sb1.hashCode());
			
			// 출력시 동일 인스턴스임을 알 수 있다.
			// 스트링빌더는 처음부터 끝까지 
			// '동일한 인스턴스 안에서' 변화하고 있음을 관찰할 수 있다.
		}
		
		
		
		
		
		
		/* 새로운 StringBuilder 인스턴스 생성 */
		StringBuilder sb2 = new StringBuilder("javaoracle");
		
		/* delete() : 시작인덱스와 종료인덱스를 이용해서 문자열에서 원하는
		 * 부분의 문자'열'을 제거한다. 
		 * deleteCharAt : 문자열 인덱스를 이용해서 문자 딱 하나를(at) 제거한다.
		 * 둘 다 원본에 영향을 미친다. 
		 * 
		 * */
		
		System.out.println("delete() : " + sb2.delete(2, 5));
		System.out.println("delete() : " + sb2.deleteCharAt(0));
		System.out.println("sb2 : " + sb2);
//		delete() : jaracle
//		delete() : aracle
		
		
		
		
		
		/* insert() : 인자로 전달 된 값을 문자열로 변환 후 지정한 
		 * 인덱스 위치에 추가한다.
		 * 원본에 영향을 미친다.
		 * */
		
		System.out.println("insert() : " + sb2.insert(1, "vao"));
		// 인덱스 1자리에 넣겠다는 의미 
//		insert() : avaoracle
		
		System.out.println("insert() : " + sb2.insert(0, "j"));
//		insert() : javaoracle

		System.out.println("insert() : " + sb2.insert(sb2.length(), "jdbc"));
//		insert() : javaoraclejdbc
		
		System.out.println("sb2 : " + sb2);
//		sb2 : javaoraclejdbc
		
		
		
		
		
		/* reverse() : 문자열 인덱스 순번을 역순으로 재배열한다. 
		 * 원본에 영향을 미친다.
		 * */
		System.out.println("reverse() : " + sb2.reverse());
		System.out.println("sb2 : " + sb2);
		
//		reverse() : cbdjelcaroavaj
//		sb2 : cbdjelcaroavaj
		
		
		
		
		/* String 클래스와 동일한 메소드도 있다.
		 * charAt(), indexOf(), lastIndexOf(), length(), replace(), 
		 * substring(), 
		 *  */
		
		
		
	}

}

 

 

 

 

 

 

 

 

 

 

 

 

 

Wrapper

 

Primitive Data Type을 인스턴스화 해주는 클래스

 

Primitive Data Type Wrapper Class
boolean Boolean
byte Byte
char Character
short Short
int Integer
long Long
float Float
double Double

 

 

 

 

 

 

 

Wrapper : String을 기본자료형으로 바꿀 시
byte b = Byte.parseByte("1");
short s = Short.parseShort("2");
int i = Integer.parseInt("3");
long l = Long.parseLong("4");
float f = Float.parseFloat("0.1");
double d = Double.parseDouble("0.2");
boolean bool = Boolean.parseBoolean("true");
char c = "abc".charAt(0);

 

 

 

Wrapper : 기본자료형을 String으로 바꿀 시
String b = Byte.valueOf((byte)1).toString();
String s = Short.valueOf((short)2).toString();
String i = Integer.valueOf(3).toString();
String l = Long.valueOf(4L).toString();
String f = Float.valueOf(0.1f).toString();
String d = Double.valueOf(0.2).toString();
String bool = Boolean.valueOf(true).toString();
String ch = Character.valueOf('a').toString();

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'Programming > JAVA' 카테고리의 다른 글

컬렉션  (0) 2022.01.10
제네릭과 컬렉션  (0) 2022.01.07
다형성  (0) 2022.01.05
상속  (0) 2022.01.04
객체 배열  (0) 2022.01.03

 

 

 

 

 

 

 

 

다형성

 

 

 

 

 

다형성이란
  • 하나의 인스턴스가 여러가지 타입을 가질 수 있는 것을 의미
  • 다형성은 객체지향 프로그래밍의 3대 특징(캡슐화, 상속, 다형성) 중 하나이다.
  • 상속에서 멤버외에 타입 또한 상속을 받음으로서 다형성의 토대가 된다고 배웠다.
  • 다형성은 상속을 기반으로 한 기술
상위(부모) 타입으로 하위(자식)타입의 객체를 사용할 수 있음.
Parent p = new Child( );

 

 

 

 

 

다형성의 특징
  • 여러 타입의 객체를 하나의 타입으로 관리할 수 있으므로 유지보수성생산성이 증가 됨
  • 상속 관계에 있는 모든 객체는 동일한 메시지(=메소드)를 수신할 수 있음 
  • 확장성이 좋은 코드 작성 가능
  • 결합도를 낮춰 유지보수성을 증가시킬 수 있음

 

 

 

 

 

 

 

 

동적바인딩

 

동적바인딩이란?
  • 컴파일 당시에는 해당 타입의 메소드와 연결되어 있다가, 런타임 당시 실제 객체가 가진 오버라이딩 된
    메소드로 바인딩이 바뀌어 동작하는 것을 의미

 

동적바인딩 성립 조건
  • 상속 관계로 이루어져 다형성이 적용된 경우, 메소드 오버라이딩이 되어 있어야 함

 

 

 

 

 

 

 

 

 

Instanceof 연산자

 

 

Instanceof 연산자란?
  • 현재 레퍼런스 변수가 어떤 클래스 타입의 객체 주소를 참조하고 있는지를 확인할 때 사용
    클래스 타입이 맞으면 true, 맞지 않으면 false를 반환
if (레퍼런스 instanceof 클래스타입) {

 

true일때 처리할 내용, 해당 클래스 타입으로 down casting



 

 

 

 

 

 

클래스 형변환

클래스 형변환은 업캐스팅다운캐스팅으로 구분할 수 있음

 

 

업캐스팅(up-casting)이란?
  • 상위(부모) 타입으로 형변환하는 것, 자동형변환, 묵시적 형변환이라고 한다.
  • 묵시적 형변환 : up-casting의 경우 묵시적 형변환이 적용 됨 (코드구현시 형변환 생략 가능)

 

 

다운캐스팅(down-casting)
  • 하위(자식) 타입으로 형변환, 강제형변환, 명시적 형변환이라고 한다.

메소드를 호출하기전 먼저 형변환이 이루어 져야 하기 때문에 소괄호를 매소드 호출 이전에 둘어줘야 한다.



 

 

코드예시 : class Application
public class Application {

	public static void main(String[] args) {

		
		/* 다형성
		 * 다형성이란 [하나의 인스턴스가 여러가지 타입을 가질 수 있는 것]을 의미한다.
		 * 그렇기 때문에 하나의 타입으로 여러타입의 인스턴스를 처리할 수 있기도 하고
		 * 하나의 메소드 호출로 객체별로 각각 다른 방법으로 동작하게 할 수도 있다. 
		 * 
		 * */
		
		

		System.out.println("Animal 생성--------------------");
		
		Animal animal = new Animal();
		animal.eat();
		animal.run();
		animal.cry();
		
//		Animal 생성--------------------
//		동물이 먹이를 먹습니다.
//		동물이 달려갑니다.
//		동물이 울음소리를 냅니다.
		
		
		
		System.out.println("Rabbit 생성--------------------");
		
		Rabbit rabbit = new Rabbit();
		rabbit.eat();
		rabbit.run();
		rabbit.cry();
		rabbit.jump();
		
//		Rabbit 생성--------------------
//		토끼가 풀을 뜯어먹고 있습니다.
//		토끼가 달려갑니다. 깡총~ 깡총~
//		토끼가 울음소리를 냅니다. 끼익~ 끼익~ 
//		토끼가 점프합니다. 점프!!!
		
		
		
		
		System.out.println("Tiger 생성--------------------");
		
		Tiger tiger = new Tiger();
		tiger.eat();
		tiger.run();
		tiger.cry();
		tiger.bite();
		
//		Tiger 생성--------------------
//		호랑이가 고기를 뜯어 먹습니다.
//		호랑이는 웬만해서 달리지 않습니다. 어슬렁~ 어슬렁~
//		호랑이가 울부짖습니다. 어흐응~!!!! 
//		호랑이가 물어뜯습니다. 앙~
		
		
		
		
		/* Rabbit은 Rabbit타입이기도 하면서 Animal타입이기도 함 
		 * Tiger은 Tiger타입이기도 하면서 Animal타입이기도 함
		 * 자식객체를 부모타입으로 참조할 수 있다.
		 * */

		Animal a1 = new Rabbit();
		Animal a2 = new Tiger();
		
		
		
		
		
		/* 하지만 반대로 Animal은 Animal일뿐 Rabbit, Tiger가 될 수 없다.
		 * 그래서 반대로 작성할 시 에러가 발생한다. */
		
//		Rabbit r = new Animal();
//		Tiger t = new Animal();
		
		
		
		
		System.out.println("동적 바인딩 확인 --------------------");
		
		/* 컴파일 당시에는 해당 타입의 메소드와 연결되어 있다가 (애니멀)
		 * 런타임 당시 실제 객체가 가진 오버라이딩 된 메소드로 (토끼, 호랑이) 
		 * 바인딩이 바뀌어 동작한다.  */
		
		a1.cry();	//Animal.cry로 연결되어 있다. "동물이 울음소리를 냅니다."
		a2.cry();	//Animal.cry로 연결되어 있다. "동물이 울음소리를 냅니다."
		
//		동적 바인딩 확인 --------------------
//		토끼가 울음소리를 냅니다. 끼익~ 끼익~ 	// Rabbit.cry로 연결돼 있다.
//		호랑이가 울부짖습니다. 어흐응~!!!! 	// Tiger.cry로 연결돼 있다.
		
		
		
		
		
		
		/* 하나의 메소드 호출로 각기 다른 객체의 다른 메소드를 동작시키게 한다. */
		
		/* 현재 레퍼런스 변수의 타입은 Animal 이기 때문에
		 * Rabbit과 Tiger가 가지고있는 고유한 기능을 동작시키지 못한다.
		 *  */
		
//		a1.jump();	//The method jump() is undefined for the type Animal
//		a2.bite();	//The method jump() is undefined for the type Animal
		
		
		

		
		
		System.out.println("클래스 형변환 확인 --------------------");
		
		/* 객체별로 고유한 기능을 동작시키기 위해서는 레퍼런스 변수를 형변환하여 
		 * Rabbit과 Tiger로 변경해야 메소드 호출이 가능하다.
		 * class type casting : 클래스 형변환
		 * 타입 형변환시 실제 인스턴스와 타입이 일치하지 않는 경우에는 
		 * ClassCastException이 발생할 수 있다.
		 * 
		 *  */
		
		((Rabbit)a1).jump();
		// 타입캐스팅이 먼저일어난 후 그 안의 기능을 수행해야하기 때문에 
		// 소괄호를 먼저 적용한 후 .로 메소드를 호출해야 한다.
		
		((Tiger)a2).bite();
		
//		클래스 형변환 확인 --------------------
//		토끼가 점프합니다. 점프!!!
//		호랑이가 물어뜯습니다. 앙~
		
		
		
		
		
		/* 타입 형변환을 잘못하는 경우
		 * 컴파일시에는 문제가 되지 않지만 런타임시 Exception이 발생한다. */
		
//		((Tiger)a1).bite();	
		
//		토끼 인스턴스(a1)는 호랑이(Tiger)가 될 수 없다.
// 		에러이유:	java.lang.ClassCastException 발생
		
		
		
		
		
		/* 레퍼런스 변수가 참조하는 실제 인스턴스가 원하는 타입과 맞는지 
		 * 비교하는 연산자 instanceof */
		System.out.println("instanceof 확인 --------------------");
		System.out.println("a1이 Tiger타입인지 확인 : " + (a1 instanceof Tiger));
		System.out.println("a1이 Rabbit타입인지 확인 : " + (a1 instanceof Rabbit));
		System.out.println("a2이 Tiger타입인지 확인 : " + (a2 instanceof Tiger));
		System.out.println("a2이 Rabbit타입인지 확인 : " + (a2 instanceof Rabbit));
		
//		instanceof 확인 --------------------
//		a1이 Tiger타입인지 확인 : false
//		a1이 Rabbit타입인지 확인 : true
//		a2이 Tiger타입인지 확인 : true
//		a2이 Rabbit타입인지 확인 : false
		
		
		
		
		/* 상속받은 타입도 함께 가지고 있다. (다형성) */
		System.out.println("a1이 Animal타입인지 확인 : " + (a1 instanceof Animal));
		System.out.println("a2이 Animal타입인지 확인 : " + (a2 instanceof Animal));
		
//		a1이 Animal타입인지 확인 : true
//		a2이 Animal타입인지 확인 : true
		
		
		
		
		/* 모든 클래스는 Object의 후손이다. */
		System.out.println("a1이 Object타입인지 확인 : " + (a1 instanceof Object));
		System.out.println("a2이 Object타입인지 확인 : " + (a2 instanceof Object));
		
//		a1이 Object타입인지 확인 : true
//		a2이 Object타입인지 확인 : true
		
		
		
		
		/* instanceof연산자를 이용해서 해당 타입이 맞는 경우에만 클래서 형변환을 적용한다. */
		
		if (a1 instanceof Rabbit) {
			((Rabbit)a1).jump();
		}
		
		if (a2 instanceof Tiger) {
			((Tiger)a2).bite();
		}
		
		
		
		
		
		
		
		/* 클래스 형 변환은 up-casting과 down-casting으로 구분할 수 있다. 
		 * up-casting : 상위 타입으로 형 변환
		 * down-casting : 하위 타입으로 형 변환
		 * 
		 * 
		 * */
		
		
		
		
		/* 묵시적 형 변환 */
		/* up-casting의 경우 묵시적 형변환이 적용된다. */
		
		Animal animal1 = (Animal) new Rabbit();	// up-casting 명시적 형변환
		Animal animal2 = new Rabbit();			// up-casting 묵시적 형변환
		
		
		
		Rabbit rabbit1 = (Rabbit) animal1;		// down-casting 명시적 형변환
//		Rabbit rabbit2 = animal2;				// down-casting 묵시적 형변환 불가
		
		
		
		
		
		/* 효과 : 코드를 통일시키고 animal이라는 같은 방식으로 
		 * rabbit과 tiger를 다뤄줄 수 있다.
		 * 반대의 경우에는 형변환을 이용하면 되며, 
		 * 형변환에는 업캐스팅과 다운캐스팅이 있고 
		 * 업캐스팅은 명시, 묵시적 형변환이 가능하고
		 * 다운 캐스팅은 명시적형변환만이 가능하다.
		 * 형변환을 확인하는 연산자로는 instanceof 메소드가 있다.
		 */
		
	}

}

 

 

class Animal
public class Animal {

	/* 동물은 기본적으로 먹는 행동과 뛰는 행동, 우는 행동을 할 수 있다. */
	
	public void eat() {
		System.out.println("동물이 먹이를 먹습니다.");
	}
	
	public void run() {
		System.out.println("동물이 달려갑니다.");
	}
	
	public void cry () {
		System.out.println("동물이 울음소리를 냅니다.");
	}
	
	
	
}

 

 

class Rabbit extends Animal
public class Rabbit extends Animal {

	/* 동물이 하는 행동을 조금 구체화 하여 행동할 수 있도록
	 * Rabbit 클래스에 Animal클래스의 메소드를 오버라이딩 한다. */
	
	
	@Override
	public void eat() {
		System.out.println("토끼가 풀을 뜯어먹고 있습니다.");
	}
	
	@Override
	public void run() {
		System.out.println("토끼가 달려갑니다. 깡총~ 깡총~");
	}
	
	@Override
	public void cry() {
		System.out.println("토끼가 울음소리를 냅니다. 끼익~ 끼익~ ");
	}

	
	
	/* 추가적으로 토끼는 점프를 뛸 수 있다. */
	public void jump () {
		System.out.println("토끼가 점프합니다. 점프!!!");
	}
	
	
	
}

 

 

class Tiger extends Animal
public class Tiger extends Animal {

	
	@Override
	public void eat() {
		System.out.println("호랑이가 고기를 뜯어 먹습니다.");
	}
	
	@Override
	public void run() {
		System.out.println("호랑이는 웬만해서 달리지 않습니다. 어슬렁~ 어슬렁~");
	}
	
	@Override
	public void cry() {
		System.out.println("호랑이가 울부짖습니다. 어흐응~!!!! ");
	}

	
	/* 호랑이는 추가적으로 물어뜯기를 할 수 있다. */
	public void bite() {
		System.out.println("호랑이가 물어뜯습니다. 앙~");
	}
	
	
	
}

 

 

 

 

 

 

 

 

다형성과 객체배열

다형성과 객체배열을 이용하면 여러 인스턴스를 하나의 레퍼런스 변수로 연속 처리할 수 있음

 

car[i]는 동적바인딩이 되어 자식객체들의 메소드가 실행된다.

 

 

 

Application2
public class Application2 {

	public static void main(String[] args) {


		
		
	/* 다형성과 객체배열을 이용해서 여러 인스턴스를 연속 처리할 수 있다. */
		
	/* 상위 타입의 '레퍼런스 배열'을 만들고 각 인덱스에 인스턴스들을 생성해서 대입한다. */
		
		Animal[] animals = new Animal[5];	// 레퍼런스배열
		
		animals[0] = new Rabbit();
		animals[1] = new Tiger();
		animals[2] = new Rabbit();
		animals[3] = new Tiger();
		animals[4] = new Rabbit();

		
		
		
		
		
		
	/* Animal클래스가 가지는 메소드를 오버라이딩한 메소드 호출시 동적바인딩을 이용할 수 있다. */
		
		for (int i = 0; i<animals.length; i++) {
			animals[i].cry();
			// 컴파일시에는 animal (ctrl+annimal클릭) 정적 바인딩 되어있음
			
//			 실제 실행시에는 동적바인딩이 되어 출력된다.
			
//			토끼가 울음소리를 냅니다. 끼익~ 끼익~ 
//			호랑이가 울부짖습니다. 어흐응~!!!! 
//			토끼가 울음소리를 냅니다. 끼익~ 끼익~ 
//			호랑이가 울부짖습니다. 어흐응~!!!! 
//			토끼가 울음소리를 냅니다. 끼익~ 끼익~ 
		}
		
		
		
		
		
		
		
		
	/* 각 클래스별 고유한 메소드를 동작시키기 위해서는 down-casting을 
	 * 명시적으로 해주어야 하는데 에러를 방지하기 위해서 instanceof 연산자를 이용해야 한다.
	 * */
		
		for (int i = 0; i<animals.length; i++) {
			
			if (animals[i] instanceof Rabbit) {
				((Rabbit)animals[i]).jump();
				
			} else if (animals[i] instanceof Tiger) {
				((Tiger)animals[i]).bite();
				
			} else {
				System.out.println("호랑이나 토끼가 아닙니다.");
			}

		}
		
//		토끼가 점프합니다. 점프!!!
//		호랑이가 물어뜯습니다. 앙~
//		토끼가 점프합니다. 점프!!!
//		호랑이가 물어뜯습니다. 앙~
//		토끼가 점프합니다. 점프!!!
		
		
		
		
		
	}

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

매개변수에 쓰이는 다형성

 

묵시적 형변환을 이용해서 매개변수가 다양한 자식클래스 자료형을 받아줄 수 있음

 

코드를 훨씬 줄일 수 있다.

 

 

* buy 메소드에 생성자를 매개변수로 보낸다는 것 
	=자식인스턴스를 부모 레퍼런스로 참조

* 자식인스턴스(new Sonata)를 부모메소드의 매개변수(Car c)로 넘김 
	= 매개변수의 다형성

	Car c = new Sonata( );
	Car c = new Avante( );
	Car c = new Grandure( );

 

 

 

class Application3
public class Application3 {

	public static void main(String[] args) {

		/* 매개변수에도 다형성을 활용할 수 있다. */
		/* 아래에 메소드 하나를 추가한다.  */
		
		
		Application3 app3 = new Application3();
		
		
		
		
		
		/* animal 타입의 토끼와 호랑이 인스턴스를 만들어서 먹이를 준다. */
		
		Animal animal1 = new Rabbit();	// 동일한 타입이기 때문에 가능함
		Animal animal2 = new Tiger();
		
		
		app3.feed(animal1); 
		app3.feed(animal2);
		
	//	Application3의 feed 메소드를 호출하며 Rabbit/tiger 의 참조변수 전달
		
//		토끼가 풀을 뜯어먹고 있습니다.
//		호랑이가 고기를 뜯어 먹습니다.

		
		
		
		
	/* Rabbit/Tiger 타입의 토끼와 호랑이 인스턴스를 만들어서 먹이를 준다. */
		
		Rabbit animal3 = new Rabbit();
		Tiger animal4 = new Tiger();
		
		app3.feed((Animal)animal3); 	// 명시적 형변환
		app3.feed((Animal)animal4); 	// 명시적 형변환
		
		app3.feed(animal3); 			// 묵시적 형변환
		app3.feed(animal4); 			// 묵시적 형변환
		
//		토끼가 풀을 뜯어먹고 있습니다.
//		호랑이가 고기를 뜯어 먹습니다.
//		토끼가 풀을 뜯어먹고 있습니다.
//		호랑이가 고기를 뜯어 먹습니다.
		
		
		
		
		
		
		
	/* 인스턴스를 생성하여 바로 묵시적으로 형변환을 이용해 전달할 수도 있다. */
		
		 app3.feed(new Rabbit());	//new Rabbit() = animal3
		 app3.feed(new Tiger());	//new Tiger() =animal4
		
		
		
		 
		 
		 
		 
	/* 다형성을 적용하지 않았다면 호랑이에게 먹이를 주는 메소드와 토끼에게 먹이를 주는 
	 * 메소드를 별도로 작성해야 했을 것이다. */	 
		 
		 
		
		
		
	}

	
		/**
		 * <pre>
		 * 동물에게 먹이를 주기 위한 용도의 메소드
		 * </pre>
		 * 
		 * @param animal 먹이를 줄 동물
		 * 
		 *  */
		
	
		public void feed(Animal animal) {
			animal.eat();
		}
		
	
	
	
}

 

 

 

 

 

 

 

 

 

 

 

리턴 타입에 쓰이는 다형성

묵시적 형변환을 이용해서 메소드에서 리턴되는 다양한 자식클래스 자료형을 받아줄 수 있음

 

 

 

 

 

Application4
public class Application4 {

	public static void main(String[] args) {

		
		
		/* 리턴타입에도 다형성을 적용할 수 있다. */
		
		Application4 app4 = new Application4();	
		// static 메소드를 만들지 않았으므로 객체 생성
		
		Animal randomAnimal = app4.getRandomAnimal();
		// getRandomAnimal 메소드를 호출하며 그것을 Animal타입변수에 담음
		// 왜? getRandomAnimal()에서 반환되는 것은 Animal(부모타입) 을 상속한
		// Rabbit() or Tiger() (자식타입) 이기 때문 // 묵시적 형변환 발생
		
		randomAnimal.cry();
		// Animal 타입에 담긴 randomAnimal 속 
		// randomAnimal = Rabbit or Tiger 자식타입 클래스 내 cry 메소드 호출
		// 동적 바인딩되어 Animal 의 cry는 출력되지 않음
		
		
		
		/* 다형성을 적용하지않고 변환 받으려면 호랑이를 리턴받는 메소드와 
		 * 토끼를 리턴받는 메소드를 따로 만들어야 한다. */
		


	}

	
	
	
	
	
	public Animal getRandomAnimal() {
		
		int random = (int) (Math.random() * 2); 
			//0또는 1만을 반환, Math.random은 double 타입이므로 강제형변환
		
		return random == 0 ? new Rabbit() : new Tiger();
			// 랜덤값이 0이면 토끼를, 1이면 호랑이를 리턴값 Animal 타입으로 반환
		
	}
	
	
	
	
}

 

 

 

 

 

 

 

 

 

 

 

추상클래스

 

 

추상메소드를 0개 이상 포함하는 클래스
  • 추상메소드를 0개 이상 포함하는 클래스 = 미완성된 클래스
  • 추상클래스로는 인스턴스를 생성할 수 없음
  • 추상클래스를 사용하려면 추상클래스를 상속받은 하위 클래스를 이용해서 인스턴스를 생성
    (다형성을 활용)

 

 

 

추상클래스의 사용 목적
  • 추상클래스의 추상메소드는 오버라이딩에 대한 강제성이 부여 됨
  • 원하는 필수 기능을 정의하여 강제성을 부여해 개발 시 일관된 인터페이스를 제공
  • 즉, 추상클래스의 목적은 인스턴스 생성이아닌 가이드라인을 제공하는데에 있음

 

Animal animal = new Animal( );   (X)
Animal a1 =  new Tiger( );          (O)
Animal a2 =  new Rabbit( );        (O)

 

 

 

 

 

 

추상메소드

 

메소드의 선언부만 있고 구현부가 없는 메소드
  • 반드시 예약어 자리에 abstract 키워드를 메소드 헤드에 작성 하여야 함

 

 

접근제한자와 반환형 사이에 abstract를 넣는다.

 

 

 

 

추상메소드를 0개 이상 포함해야한다 -> 0개 이상의 의미
보통은 추상메소드를 1개라도 포함하면 추상클래스라도 명시해줘야하지만,
때로는 추상메소드가 0개 이더라도 가이드라인이 목적이라면 abstract을 의도적으로 붙여줄 수도 있다.
abstract class (추상클래스)

 

 

class Application
public class Application {

	public static void main(String[] args) {


		/* 추상클래스는 인스턴스 생성이 불가능하다. */
		
		// Product product = new Product();
		// 추상클래스인 Product는 객체를 생성할 수 없다.
		
		
		
		/* 추상클래스를 상속받은 객체를 이용해야 한다.. */
		SmartPhone smartPhone = new SmartPhone();
		
		
		
		/* SmartPhonedms SmartPhone 타입이기도 하지만 Product타입이기도하다. */
		System.out.println(smartPhone instanceof SmartPhone);   //  true
		System.out.println(smartPhone instanceof Product);		//  true
		

		
		
		/* 따라서 다형성을 적용해서 추상클래스를 레퍼런스 타입으로 활용할 수 있다. */
		Product product = new SmartPhone();
		// 객체생성은 안되지만 자식객체가 참조하는 변수는 생성이 가능하다.
		
		
		
		
		
		/* 작성한 메소드 세가지 모두 호출 */
		/* 동적 바인딩에 의해 SmartPhone의 메소드가 호출된다. */
		product.absMethod();
//		Product 클래스의 absMethod를 오버라이딩한 메소드 호출함...
		

		
		/* 추상 클래스가 가진 메소드도 호출할 수 있다.  */
		product.nonStaticMethod();
		
		
	
		/* static 메소드는 그냥 사용이 가능하다. (인스턴스 생성불필요) */
		// 클래스명.메소드명	
		Product.staticMethod();
		
		
		
		
		
		/* 추상클래스를 사용하는 이유? 오버라이딩에대한 강제화, 필수기능 강제구현
		 * 추상클래스의 추상 메소드는 "오버라이딩에 대한 강제성"이 부여된다.
		 * 따라서 여러 클래스들을 그룹화하여
		 * 가져야만하는 필수기능을 정의하여 -> 강제성을 부여해 
		 * 개발 시 일관된 인터페이스(GUI)를 제공할 수 있다. 
		 * 이 뒤에 배우는 인터페이스와는 다른 의미이다 (주의)
		 * 
		 * 기능을 이용할 수 있는 방법이자 통로 : 인터페이스
		 * GUI : Graphic User Interface
		 *  - 사용자에게 편리를 주기위해 그래픽으로 작성된 인터페이스
		 * CLI : cmd를 떠올리면 된다. 
		 * 
		 * 
		 * 하지만 다른 클래스를 상속받고있는 클래스를 작성할 시에는 
		 * 추상클래스를 추가로 상속받을 수 없다. 
		 * 그래서 추상클래스보다 더 강제성이 강한 인터페이스(interface)라는 
		 * 매커니즘을 제공하고 있다. 
		 * 
		 *  */
		
		
		
		
	}

	
	
	
	
}

 

 

 

abstract class Product
public abstract class Product {

	
	
	
	/* 추상클래스는 필드를 가질 수 있다. */
	
	/* 필드선언 */
		private int nonStaticField;
		private static int staticField;
	
	
	
	
	
	
	/* 추상클래스는 생성자도 가질 수 있다.
	 * 하지만 직접적으로 인스턴스를 생성할 수는 없다. */
	
		public Product() {}
	
	
	
	
	
	
	
	/* 추상클래스는 일반적인 메소드를 가질 수 있다. */
	
		public void nonStaticMethod( ) {
			System.out.println("Product 클래스의 nonStaticMethod 호출함...");
		}
		
		public static void staticMethod( ) {
			System.out.println("Product 클래스의 staticMethod 호출함...");
		}
	
	
	
	
	
	/* 미완성 클래스인 이유 : 미완성 메소드를 가지고있기 때문 */
	/*  -> 나를 상속해서 완성해주세요 */
	/* 추가적으로 미완성 메소드(추상메소드) 또한 만들 수 있다.
	 * 추상 메소드가 0개인 경우 선택적으로 클래스에 abstract 키워드
	 * 작성하여 인스턴스 생성을 막을 수 있다.
	 *  */
	
		public abstract void absMethod();
	// 접근제한자 abstract 반환  메소드명  	 {} 구현부없음
		
	// 추상메소드가 하나라도 있다면 클래스앞엔 반드시 abstract을 붙여줘야한다. 
	// 그렇지 않으면 에러가 발생
		
	
	
	
	
}

 

 

 

class SmartPhone extends Product
public class SmartPhone extends Product {
	
	
	//  컴파일 에러 구문 : 
	//	The type SmartPhone must implement the inherited 
	//  abstract method Product.absMethod()
	
	//  해결방법 :  미완성된 추상메소드 구현
	
	
	
	
	
	
	/* SmartPhone 클래스는 Product 클래스를 상속받아서 구현한다.
	 * 추상클래스가 가지는 추상메소드를 반드시 오버라이딩 해야한다. (강제성 부여)
	 * extends 키워드로 클래스를 상속 받을 때 두 개 이상의 클래스는 상속하지
	 * 못한다. (모호성 방지)
	 *  */
	
	
	
	
	@Override
	public void absMethod() {
		System.out.println("Product 클래스의 absMethod를 오버라이딩한 메소드 호출함...");
		
	}
	

	
	
	
	
	/* 추가적으로 메소드도 작성할 수 있다. */
	public void printSmartPhone() {
		System.out.println("SmartPhone 클래스의 printSmartPhone 메소드 호출함...");
	
	}
	
	
	
	
}

 

 

 

 

 

 

 

 

 

 

 

 

인터페이스

 

 

인터페이스란?
  • 추상메소드와 상수 필드만 가질 수 있는 클래스의 변형체
  • 바꿔말하면 일반적인 메소드와 일반적인 필드를 가질 수 없다. 

 

사용 목적
1. 표준화 : 추상클래스와 비슷하게 필요한 기능을 공통화 해서 강제성을 부여할 목적 
2. 다중 상속 : 자바의 단일상속의 단점을 극복

 

 

인터페이스는 클래스 다이어그램에서 점선으로 표현된다. (상속관계는 실선)

 

 

 

 

 

 

추상클래스와 인터페이스

 

 

- 단, 인터페이스와 인터페이스 간의 상속에 있어서는 extends 키워드를 쓴다. 
- 추상 클래스는 명시적으로 abstract를 작성해 줘야하지만 인터페이스는 작성하지않아도 자동으로 추가된다.
- 둘 다 참조타입으로서 다형성의 이점들을 활용 해 볼 수 있다. 

 

 

 

 

 

 

 

Application
public class Application {

	public static void main(String[] args) {
	
		
		/* 인터페이스
		 * 여기서 다루게 되는 인터페이스는 자바의 클래스와 유사한 형태지만
		 * 추상 메소드와 상수필드만 가질 수 있는 클래스의 변형체를 말한다.  
		 * 추상클래스보다 더 강한 강제성을 지닌다. 
		 * */
		
		
		
		/* 인스턴스를 생성하지 못하고, 생성자 자체가 존재하지 않는다.  */
//		InterProduct interProduct = new InterProduct();
		
		
		
		/* 레퍼런스 타입으로만 사용이 가능하다. */
		interProduct InterProduct = new Product();
		
		
		
		
		
		/* 인터페이스의 추상메소드 오버라이딩한 메소드로 동적 바인딩에 의해 호출됨 */
		InterProduct.nonStaticMethod();
		// 정적으로는 interProduct의 추상메소드로 연결된다. 
		InterProduct.absMethod();
		// 정적으로는 interProduct의 추상메소드로 연결된다. 
		
// 		동적바인딩으로 인해 Product의 추상메소드로 연결된다. 		
//		InterProduct의 nonStaticMethod 오버라이딩한 메소드 호출됨...
//		InterProduct의 absMethod 오버라이딩한 메소드 호출됨...
		
		
		
		
		
		
		/* 오버라이딩 하지 않으면 인터페이스의 default 메소드로 호출됨 */
		InterProduct.dafaultMethod();
		// 정적으로는 interProduct의 추상메소드로 연결된다. 
		
		
		
		
		/* static 메소드는 인터페이스명.메소드명();으로 호출한다. */
		interProduct.staticMethod();
		
		
		
		
		
		/* 상수 필드(public static final) 접근도 
		 * 인터페이스명.필드명으로 접근한다. */
		System.out.println(InterProduct.MAX_NUM);
		System.out.println(InterProduct.MIN_NUM);
		
		
		
		
	}

}

 

 

 

interface interProduct extends java.io.Serializable
public interface interProduct extends java.io.Serializable /*, java.util.Comparator*/ {

	
	/* 인터페이스 생성 -> NEW -> interface */
	/* 인터페이스 끼리 상속 받을 때에는 extends 키워드를 이용하며
	 * 이때도 여러 인터페이스를 다중상속 받을 수 있다. */
	
	
	
	/* 인터페이스는 일반 필드는 가질 수 없으나 상수필드는 가질 수 있다. 
	 * public static final 제어자 조합을 상수필드라고 부른다.
	 * 반드시 선언과 동시에 초기화 해줘야 한다.
	 * 
	 * */
	 
	public static final int MAX_NUM = 100;
	
	
	/* 상수필드만을 가질 수 있기 때문에 모든 필드는 묵시적으로 
	 * public static final이다. 즉, 써주지 않아도 자동으로 처리된다.
	 *  */
	int MIN_NUM = 10;
	// = public static final int MIN_NUM = 10;
	
	
	
	
	
	
	/* 인터페이스는 생성자를 가질 수 없다. */
	// public InterProduct() {}
	
	
	
	
	
	/* 인터페이스는 구현부( {} )가 있는 non-static 메소드를 가질 수 없다. 
	 * (추상 메소드는 구현부가 없어야 한다.)
	 * */
	// public void nonStaticMethod(){}
	
	
	
	
	
	
	/* 추상메소드만 작성이 가능하다. */
	public abstract void nonStaticMethod();
	
	
	
	
	
	/* 인터페이스 안에 작성한 메소드는 묵시적으로 
	 * public abstract 의 의미를 가진다. 
	 * 따라서 인터페이스의 메소드를 오버라이딩 하는 경우
	 * 반드시 접근 제한자를 public 으로 해야 오버라이딩이 가능하다.
	 * 인터페이스는 내용을 정의하는게 아니라 규칙을 정하는 공간이므로 
	 * 접근이 자유로워야 한다.
	 *  */
	
	void absMethod();
	// = public abstract void absMethod();
	
	
	
	
	
	
	/* 하지만 static 메소드는 작성이 가능하다. (jdk 1.8에 추가된 기능)
	 * static 메소드는 정적인 메모리 영역에 할당되는 것이기 때문에 
	 * 객체가 될 수 없는 인터페이스가 객체가 되어야하는 상황과 아무런
	 * 관련이 없다.
	 *  */
	public static void staticMethod() {
		System.out.println("InterProduct 클래스의 staticMethod 호출됨...");
		
	}
	
	
	
	
	
	
	/* 또한 default 키워드를 사용하면 non static method 메소드도 
	 * 작성이 가능하다. (jdk 1.8에 추가된 기능) 
	 * 원론적으로 인터페이스는 몸체없는 추상메소드만 작성하기 위한공간이다. 
	 * static 메소드와 default 메소드는 예외적인 부분이 첨가된 것이다. 
	 * 예외가 필요한 이유는 자바 API에서 다룰 것이다. 
	 * */
	public default void dafaultMethod() {
		System.out.println("InterProduct 클래스의 dafaultMethod 호출됨...");
		
	}
	
	
	
	
	
	
}

 

 

 

 

 

class Product extends java.lang.Object implements interProduct, java.io.Serializable
public class Product extends java.lang.Object implements interProduct, java.io.Serializable {

	
	
	/* InterProduct cannot be resolved to a type
	 * 
	 * 클래스에서 인터페이스를 상속 받을 때에는 implements 키워드를 사용한다.
	 * - extends는 클래스를 상속 받을 때 사용 하였고
	 * - 인터페이스끼리 상속 받을 때에는 extends 키워드를 이용했다.
	 * 
	 * 또한 인터페이스를 여러개를 상속받을 수 있으며,
	 * extends로 다른 클래스를 상속 받는 경우에도 그것과 별개로 인터페이스도 
	 * 추가상속이 가능하다. 
	 * 단, extends 키워드를 앞에 작성하고 implements를 뒤에 작성한다. 
	 *  
	 *  */
	
	/* InterProduct를 상속받으면 오버라이딩 해야 하는 메소드의 강제성이 부여되기 때문에
	 * 인터페이스에 작성한 추상 메소드를 전부 오버라이딩 해야한다. */
	
	
	

		
	

	@Override
	public void absMethod() {
		System.out.println("InterProduct의 absMethod 오버라이딩한 메소드 호출됨...");
		
	}

	@Override
	public void nonStaticMethod() {
		System.out.println("InterProduct의 nonStaticMethod 오버라이딩한 메소드 호출됨...");
		
	}
	
	
	
	
	
	
	
	/* 스태틱 메소드는 오버라이딩 할 수 없다. 
	 * 인터페이스 안에서 구현 완료했기 때문 */
//	@Override
//	public static void staticMethod() {
//		System.out.println("InterProduct 클래스의 staticMethod 호출됨...");
//		
//	}
	
	
	
	
	/* Default메소드는 인터페이스 안에서만 작성 가능하다.  */
//	@Override
//	public default void dafaultMethod() {
//		System.out.println("InterProduct 클래스의 dafaultMethod 호출됨...");
//		
//	} // Default methods are allowed only in interfaces.
	
	
	
	
	
	
	
	
	/* 하지만 위의 메소드에서 Default 키워드를 제외하면 오버라이딩 가능하다. */
	
	public void dafaultMethod() {
	System.out.println("InterProduct 클래스의 dafaultMethod() 호출함");
		
		
	}
	
	
	
	
}

 

 

 

 

 

 

 

 

 

 

'Programming > JAVA' 카테고리의 다른 글

제네릭과 컬렉션  (0) 2022.01.07
자바 API  (0) 2022.01.06
상속  (0) 2022.01.04
객체 배열  (0) 2022.01.03
클래스와 객체(3)  (0) 2021.12.30

+ Recent posts