달거북씨 첫 자바수업 그 마지막 정리

 


 

프로그램

아직 실행되지 않은 상태

소스코드로 잘 짜여진 틀

 

 

프로세스

실행중인 프로그램으로 자원과 쓰레드로 구성되어 있다.

 

 

1. 쓰레드

프로세스 내에서 실제 작업처리 경로

모든 프로세스는 최소 하나의 쓰레드를 가지고 있다.

 

 

단일 쓰레드

1) 하나의 작업에 문제가 발생하더라도 다른 작업에는 영향을 끼치지 않는다.

2) 설계도가 멀티 쓰레드에 비해 단순하다.

3) 처리경로가 하나로 직렬적이기 때문에 동시에 많은 양을 처리하기 힘들다.

 

 

멀티 쓰레드

1) 여러 개의 쓰레드(처리경로)를 가질 수 있다.

2) 한 개의 처리 경로를 여러 개로 나누어 동시 작업이 가능해진다.

3) 대부분의 프로그램이 멀티 쓰레드로 작성되어 있다.

4) 처리량 증가, 효율성 증가, 처리 비용 감소의 장점이 있다.

5) 프로그래밍을 할 대 고려해야 할 사항들이 많기 때문에 설계 방식이 굉장히 어렵다.

6) 하나의 쓰레드 문제 발생 시 모든 쓰레드에 문제가 발생하게 된다.

 

 

단일 쓰레드와 멀티 쓰레드 비교

하나의 새로운 프로세스를 생성하는 것보다(→ 단일 쓰레드) 하나의 새로운 쓰레드를 생성하는 것이 더 적은 비용이 든다(→ 멀티 쓰레드) >> 하나의 프로세스를 가지고 더 많은 사용자의 요청을 처리할 수 있게 된다.

ex. 카카오톡에서 파일을 전송했을 때,

      - 단일 쓰레드일 경우 파일 전송이 완료될 때까지 다음 작업을 수행하지 않는다.

      - 멀티 쓰레드일 경우 파일 전송이 완료되는 동안 다음 작업도 동시에 수행 가능하다.

 

 

쓰레드의 생성방법 2가지

1) Thread 클래스 상속

class MyThread extends Thread{
	public void run(){
    	// 쓰레드 작업 내용
    }
}
MyThread t = new MyThread();
t.start();

   ① Thread를 상속받은 후 run() 메소드를 오버라이딩한다.

   ② 사용 시 쓰레드의 객체를 생성하고, start() 메소드를 통해 쓰레드를 실행한다.

 

2) Runnable 인터페이스 지정 후 Thread에 넘겨주기

class MyRunnable implements Runnable{
	public void run(){
    	// 쓰레드 작업 내용
    }
}
MyRunnable r = new MyRunnable();
Thread t = Thread(r);	// Thread(Runnable r)
t.start();

   ① Runnable 인터페이스를 지정받은 클래스에 추상메소드 run()을 구현한다. 

   ② 사용시 Runnable 인터페이스를 구현한 클래스의 객체를 생성한다.

   ③ Thread 클래스 객체를 생성하여 Thread의 생성자의 매개변수에 ②에서 구현한 객체를 넘겨준다.

       > 즉, 외부에서 매개변수로 받은 Runnable 객체로 run()이라는 메소드의 구현체를 받아옴

   ④ Thread의 객체로 start() 메소드를 호출하여 쓰레드를 실행한다.

       > 외부에서 제공한 run()을 Thread에서 호출

 

 

메소드 

- run() : main(){작업내용}을 적는 것과 같이 run()에 쓰레드의 작업 내용을 작성한다.

- start() : JVM에 쓰레드를 스케줄링 해주는 역할로 호출해야 쓰레드가 작업을 시작한다. 즉, start()를 하면 실행 준비

             상태가 되는 것이기 때문에 언제 실행될 지는 OS 스케줄러가 실행순서를 결정한다.

- join() : 특정 쓰레드 종료 시까지 다른 쓰레드들을 멈추게 한다.

- sleep() : 현재 쓰레드를 지정된 시간동안 흐름을 멈추게 한다.

 

 

예제

하트 출력 시간을 줄이기 위해 10개씩 출력되도록 수정해서 출력

 


 

2. 파일 입출력

Writer(입력)

FileWriter > BufferedWriter > 파일에 입력

 

FileWriter fw = new FileWriter();

- FileWriter : 경로에 있는 파일 가져오기

  * 파일이 없는 경우에는 그 이름대로 파일을 생성

  * 하지만 경로가 이상한 경우에는 예외가 발생(IOException)

- new FileWriter("파일경로") : 덮어쓰기 모드

- new FileWriter("파일경로", true) : 추가모드(true) 또는 덮어쓰기(false)도 가능

 

BufferedWriter bw = new BufferedWriter();

- bw.write("문자열") : 버퍼에 문자열 쓰기

- bw.close() : 파일에 적용

                     버퍼에 있는 데이터들을 파일에 써주면서 버퍼 닫기

 

 

Reader(출력)

FileReader > BufferedReader > 파일에서 읽어와 출력

 

FileReader fr = new FileReader();

- FileReader : 경로에 있는 파일 가져오기(읽기 위해)

  * 파일이 없으면 예외발생(IOException)

- new FileReader("파일경로")

 

BufferedReader br = new BufferedReader();

- BufferedReader : 버퍼를 이용해서 파일 읽기

- br.readLine() : 파일에 있는 니용 판 줄 읽어오기

                           * 파일이 끝이라면 null을 반환

 

 

버퍼(buffer)

1) 데이터를 한 곳에서 다른 한 곳으로 전송하는 동안 일시적으로 그 데이터를 보관하는 임시 메모리 영역

2) 외부 파일의 입력소스를 직접 입출력하는 것보다 버퍼를 이용하는 쪽이 훨씬 빠르고 작업의 효율이 높아진다.

    > 버퍼를 사용하여 외부의 파일에 데이터를 입력할 대 데이터를 모아 문자로 묶어서 한 번에 전송하게 된다.

    > 또한 외부의 파일을 읽어올 때(출력), 데이터를 읽어와 버퍼에 저장한 후 읽어온다.

 

 

예제

 


 

실습

문제
부모클래스
Dog 클래스
Cat 클래스
Pig 클래스
Ground 클래스(메인 메서드)

728x90

총 10일짜리 자바수업 중 9일차에 해당하는 내용

거의 끝부분인데 다 이해했냐고 묻는다면 비밀!!!

확실한 건 국비수업 들을 때 이해에 도움은 된다 하핳

 

16. 컬렉션 내용에서 이어진다.

2022.03.19 - [이론/자바 기초] - JAVA 그게 뭐야? 16. 컬렉션프레임워크, ArrayList, <>Generic제네릭

 

JAVA 그게 뭐야? 16. 컬렉션프레임워크, ArrayList, <>Generic제네릭

1. 컬렉션 프레임 워크(Collection FrameWork) 많은 데이터(객체)들을 효과적으로 관리할 수 있는 표준화된 프로그래밍 방식 다수의 데이터(객체)를 편리하게 다룰 수 있는 클래스 및 인터페이스의 집

turtlemoon.tistory.com

 


 

1. HashSet

HashSet hash = new HashSet();

Set 인터페이스를 수현한 대표적인 컬렉션 클래스

순서x, 중복x

 

1) 저장된 값들은 인덱스가 없기 때문에 순서가 없다.

2) 값의 유무 검사에 특화되어 있는 자료구조

3) 해시코드로 유무검사가 진행되고 속도가 상대적으로 좋다(주소값으로 비교)

4) HashSet은 객체를 저장하기 전에 기존에 같은 객체가 있는지 확인한다.

    같은 객체가 없으면 저장하고, 있으면 저장하지 않는다.(중복되지 않기 때문에)

 

 

생성자

HashSet()

HashSet(Collection c)

 

 

주요 메소드

boolean add(Object o) : 요소 추가

boolean remove(Object o) : 요소 제거

boolean contains(Object o) : 요소 포함 여부를 알려줌

 

 

HashSet? ArrayList?

Set은 검사의 목적이 있기 때문에 데이터의 순서를 관리할 필요가 없고, 데이터 크기에 상관없이 검색에 걸리는 시간이 매우 짧다. 반면 ArrayList는 데이터의 index를 관리해야 하기 때문에 상대적으로 시간이 오래 걸린다.

즉, 기능적 차이가 없다면 HashSet 사용

 

 

***HashSet에 객체를 추가할 때 주의할 점!

boolean add(Object o) 메소드는 저장할 객체의 equals()와 hashCode()를 호출한다. 따라서 우리가 만든 클래스의 객체를 HashSet에 저장할 때, 반드시 equals()와 hashCode()를 재정의한 후 추가(add)해야 한다.

 

만약 equals()와 hashCode()가 오버라이딩 되어있지 않을 경우, 객체의 주소값으로 기존에 같은 객체가 있는지 확인한 후 저장하기 때문에 중복된 값을 넣을 수가 없다.

(객체를 구별하는 기준은 iv. 따라서 HashSet에서 iv가 중복되면 안됨)

 

 

예제

중복이 안되기 때문에 중복값을 제외하고 fruitSet에 저장됨 / 순서도 없음

 


 

2. Iterator

컬렉션에 저장된 데이터를 읽기 위해서 사용되는 인터페이스

 

 

Iterator 사용 이유

1) Iterator는 컬렉션마다 저장된 요소를 읽어오는 방법을 표준화시킨 것.
    List나 Set 같은 경우 서로 읽어오는 방법이나 메소드가 다르기 때문에 만약 List가 Set으로 바뀔 경우 읽어오는 방법도

    바껴야 한다. 하지만 Iterator를 사용할 경우, 컬렉션을 바꿔도 읽어오는 방법은 바꾸지 않아도 된다.

2) 순서가 없는 객체에 순서를 부여하거나, 순서가 있어도 Iterator 방식으로 데이터를 읽어올 때 사용

 

 

Iterator 사용 방법

컬렉션에 iterator()를 호출해서 Iterator를 구현한 객체를 얻어서 사용한다.

 

ArrayList arrList = new ArrayList();
Iterator it = arrList.iterator();		// Iterator 객체 반환

*** Iterator는 '1회용'이기 때문에 순서를 다 돌면 다시 새로운 Iterator 객체를 얻어야 한다.

 

 

Iterator 메소드

boolean hasNext() : 읽어올 데이터가 남았는지 확인하여 true, false 반환

Object next() : 다음에 오는 데이터를 읽어오며 값을 가져온다. 따라서 next()를 호출하기 전 hasNext()를 호출하여 읽어올 데이터가 있는지 확인해야 한다.

 

 

예제 (HashSet 예제에서 이어짐 - Iterator 사용하기)

 

 

예제 (ArrayList 사용하기)

▶️ ArrayList(Collection c) > set을 매개변수로 컬렉션 타입에 넘기면(ArrayList(set)) ArrayList로 반환해준다.

 


 

실습1

 

 

실습2(Generic에 담을 객체를 직접 생성해서 Hashset 사용하기)

Student 클래스
HashSet 사용
equals()와 hashCode() 재정의

 


 

3. HashMap

HashMap map = new HashMap();

데이터를 key와 value 한쌍으로 저장하며 검색의 목적을 가지고 있다.

순서x, 중복x(value는 중복가능)

key value
fly 날다
walk 걷다
run 뛰다
run 작동하다

entry(한 쌍)

fly - 날다, walk - 걷다, run - (뛰다 > 작동하다로 수정됨)

 

1) key에 중복된 값을 넣으면 value가 최근 값으로 수정되고 중복되지 않은 값을 넣으면 새롭게 추가된다.

2) value는 수정이 가능하다.

3) Map에는 iterator()가 없기 때문에 keySet(), entrySet(), values()를 호출해 값을 가져온다.

 

 

생성자

HashMap()

HashMap(Map m) : Map을 HashMap으로 변환

 

 

주요 메소드

Object get(Object key) : key 값을 통해 value 값 가져오기

Object put(Object key, Object value) : 데이터 추가 또는 value 값 수정

Set entrySet() : Map에 저장된 데이터 한 쌍씩 모두 읽어오기

Set keySet() : Map에 저장된 key값 모두 가져오기

Collection values() : Map에 지정된 모든 value 값 가져오기

 

 

HashMap의 iterator()

Map map = new HashMap();

                  ...

map.entrySet().iterator   // map.entrySet()은 iterator의 객체

                     ↓

Set eSet = map.entrySet();

Iterator it = eSet.iterator();

 

 

예제

 

 

실습 (저번 시간보다 쉬운 회원가입 폼 만들기)

 


 

4. 빠른 for문(forEach문, 향상된 for문)

for(자료형 변수명 : 컬렉션 or 배열){
	// 컬렉션이나 배열에서 요소를 하나씩 꺼내오면서 반복
}

단순하게 모든 값들을 순회할 때 사용하는 것이 좋다.

순서가 중요한 경우에는 (몇 번째에 어떤 요소가 있는지 알 필요가 있는 경우) 기존의 for문을 사용한다.

 

 

예제

 


 

실습

 

 

 

728x90

1. 컬렉션 프레임 워크(Collection FrameWork)

많은 데이터(객체)들을 효과적으로 관리할 수 있는 표준화된 프로그래밍 방식

다수의 데이터(객체)를 편리하게 다룰 수 있는 클래스 및 인터페이스의 집합

컬렉션프레임워크 계층구조

 

 

List extends Colletion(인터페이스)

순서가 있는 데이터의 집합으로 데이터의 중복을 허용한다. ex) 대기표

구현 클래스

  • ArrayList : 인덱스로 데이터를 관리(new)
  • LinkedList : 배열의 요소가 불연속적으로 연결되어 있음
  • Vector : 처리속도↓, 용량관리 필요(old, 옛날 버전이라 거의 사용되지 않는다.)

 

 

Set extends Colletion(인터페이스)

순서가 없는 데이터의 집합으로 데이터의 중복을 허용하지 않는다. ex) 중식메뉴판 > 짜장면, 탕수육, 짬뽕, ...

구현 클래스

  • HashSet
  • TreeSet

 

 

Map 인터페이스

 key와 value가 한쌍(entry)으로 이루어진 데이터의 집합

순서가 없으면 key는 중복을 허용하지 않고, value는 중복 허용. ex) key아이디-value비밀번호, key메뉴판-value가격            

구현 클래스

  • HashSet
  • TreeSet

 


 

2. ArrayList

컬렉션 클래스 중 가장 많이 사용되는 클래스

객체배열을 이용해서 값을 저장한다.

순서o, 중복o

 

ArrayList arrList = new ArrayList();

 

 

ArrayList의 장단점

배열은 처음에 몇 칸을 할당할 지 고정해서 쓰지만, ArrayList는 값을 넣는 만큼 자동으로 늘어난다.

인덱스를 이용해서 각 배열 요소에 빠르게 접근 가능하지만, 크기를 늘릴 경우 새로운 배열을 생성하고 줄일 경우 기존의 값들을 옮겨야 하므로 느리다.

 

 

생성자

ArrayList() : 기본생성자

ArrayList(Collection c) : 매개변수로 컬렉션 타입을 넘기면 ArrayList로 반환

 

 

주요 메소드

boolean add(object o) : 객체를 넘기면 ArrayList에 추가

int indexOf(object o) : 객체를 넘기면 해당 객체의 index를 반환. 못 찾을 경우 -1 반환

object get(int index) : 특정 위치를 넘기면 해당 객체를 반환(읽기)

object set(int index, Object element) : 특정 위치에 있는 객체 변경

boolena remove(Object o) : 객체를 넘기면 ArrayList 삭제

object remove(int index) : 특정 위치를 넘기면 ArrayList에서 삭제

 

 

예제 1

 

 

예제 2

&lt;&gt;제네릭에 대히선 아래에서 조금 더 설명할 예정

 

 

실습 1. 

 

 

*** 컬렉션 사용시 주의할 점

컬렉션에서는 값들을 비교할 때 요소 타입의 equals()나 hashCod()로 비교한다.

우리가 만든 클래스에 위의 메소드들을 재정의하지 않을 경우, 객체의 주소값으로 비교를 하기 때문에 같은 값(iv)을 제대로 찾아올 수 없다.

따라서 비교하고자 하는 요소들의 값(iv)을 올바르게 비교하도록 equals()와 hashCode()를 재정의해서 사용한다.

 

 

컬렉션 예시

메인 클래스
부모 클래스(equals 재정의)
자식 클래스

 

 

실습 1. 책 목록 만들기

책 목록 만들기
나가기는 if로, 책 등록, 삭제, 목록은 switch문으로 작성
북 클래스에서 멤버변수 들을 만들어준다.

 

 


 

3. <> Generic 제네릭

컴파일 시 타입을 체크해주는 기능

1) 타입을 체크해줌으로써 객체의 타입 안정성을 높인다.

2) 형변환을 생략할 수 있기 때문에 코드가 간결해진다.

3) 런타임 에러가 날 뻔한 코드를 제네릭스를 사용하여 컴파일 에러를 발생할 수 있게 한다. (강제종료 방지)

4) JDK 1.5 이후부터 Object를 포함한 클래스는 제네릭과 함께 사용해야 한다.(ArrayList, Set, Map)

 


 

실습 2. 회원가입 폼 만들기

User 정보에 대한 멤버변수 만들기
실습 1과 달리 이번엔 if문으로 번호 받아줌 / for문을 통해 기존 회원정보와 비교해 아이디가 중복되는지 확인
조건문 마다 for문을 돌려서 일치하는 id가 있는지 확인해준다.

 

728x90

와우 5시간씩 꾹꾹 눌러 배워서 정리가 안 끝나는 매직...★ 살려주세오...

 


 

1. 예외처리

컴파일 에러 : 컴파일 할 때 문법적으로 오류가 발생

런타임 에러 : 실행은 되지만 프로그램에서 문제가 발생

  • 에러(error) : 코딩으로 해결할 수 없는 심각한 오류
    ex. OOME(Out Of Memory Error) > 메모리 부족으로 인한 에러
  • 예외(exception) : 코딩으로 해결할 수 있는 오류

컴파일 에러는 빨갛게 표시가 되고, 런타임 에러는 실행은 되지만 에러가 남(콘솔창에 에러 이유가 출력됨)

 

 

예외처리를 사용하는 이유?

1) 프로그램이 강제종료 되는 것을 막기 위해

2) 제어문으로는 처리할 수 없는 경우

 

 

Exception 클래스

모든 예외들의 부모클래스

사용자의 실수와 같은 외적인 요인이 발생하는 예외

어떤 예외가 발생하든지 Exception 타입으로 잡을 수 있다.

 

 

RuntimeException 클래스

프로그래머의 실수로 발생하는 예외

컴파일러가 예외처리 여부를 체크하진 않지만, 실행 시 프로그램 종료

 

 

Exception 계층도

 

 

try ~ catch ~ finally

try {

         예외가 발생할 수 있는 문장

} catch(예외클래스명 객체명) {

         예외가 발생시 수행할 문장

} catch(예외클래스명 객체명) {

         예외 발생 시 수행할 문장

         (catch블럭은 여러 개 사용 가능)

}

...

finally {

         예외 발생 유무에 상관없이 무조건 실행할 문장(생략가능)

        ***주로 외부 장치와 연결했을 경우 다시 닫을 때 사용한다.

         ex. printWrite open()과 close()

}

 

 

try에서 예외가 발생했을 경우

1) 해당 예외와 일치하는 catch로 가서 예외처리를 한다. 만약 일치하는 catch가 없다면 예외처리가 되지 않고 프로그램이 비정상 종료된다.
2) catch에 있는 전체 문장을 수행한 후, try ~ catch문을 탈출하여 나머지 로직을 수행한다. 따라서 try에 예외발생한 문장 이후의 나머지 문장이 남아있어도 수행되지 않는다. finally를 사용하여 나머지 문장을 실행하면 된다

 

 

try에서 예외가 발생하지 않았을 경우

catch를 거치지 않고 try ~ catch문을 탈출하여 나머지 로직을 수행한다.

 

 

예제

 

 

실습

▶ try ~ catch문으로 실행해 언제 예외가 발생하는지 확인한다.

▶ 예를 들어, num1 = 10, num2 = 5를 입력하면 정상적으로 출력되지만 num1 = 10, num2 = 0을 입력하면 런타임에러 중 ArithmeticException이 발생한다.(나눗셈에서 0으로 나누는 것은 불가능하기 때문)

예외처리

▶ 예외 찾는 과정을 계속한다.

▶ 정수가 아닌 것을 입력했을 때 예외 발생(InputMismatchException) > 입력받는 과정 역시 예외가 발생할 수 있다는 걸 알 수 있다.

예외가 발생할 수 있는 문장들을 try ~ catch문 안으로 옮겨주고, 예외처리(InputMismatchException은 import처리 필수)&amp;nbsp;
더 이상 어떤 에러가 나올지 모르겠으므로 혹시 에러가 발생할 때를 대비해 Exception 사용

▶ 나가기 기능 추가하기

 

 

throws

메소드 실행 시 발생할 수 있는 예외를 선언하여 호출하는 쪽에 알리는 것

직접 예외처리를 하지 않고 메소드 호출한 곳으로 떠넘겨서, 메소드를 호출한 곳에서 예외처리를 하겠다는 뜻

throw와 전혀 다름

 

리턴타입 메소드명() throws 예외1, 예외2, ...{

         // 메소드 내용

}

 

 

throws 예제

 


 

2. API

개발에 필요한 주요 기능들을 제공하는 라이브러리들의 집합

선배 개발자들이 JAVA에서 코딩을 쉽게 할 수 있도록 미리 만들어 놓은 부품들

 

 

JAVA API

자바 시스템을 제어하기 위해서 자바에서 제공하는 기능(명령어)

JDK 설치 시 제공해주는 기본 API

 

 

java.lang

자바 프로그래밍을 위한 가장 기본적인 패키지와 핵심적인 클래스들을 포함

 

 

외부 API

선배 개발자들이 개발한 패키지 및 클래스들을 의미

보통 jar파일로 배포하며 자바 프로젝트에 import하여 사용할 수 있다.

 

 

*** API의 종류는 굉장히 많고 다양하기 때문에 모두 외우는 것은 절대 불가능하다.

그래서 처음 보는 API라도 설명을 잘 읽고 맞는 목적으로 사용하는 방법을 알아야 한다. ***

 

 

javadocs

클래스, 메소드에 대한 도움말 문서

java API 문서는 JAVADOCS 프로그램으로 만들어진 문서로 볼 수 있다.

 

 

API 사용하는 이유?

개발 비용과 시간이 획기적으로 줄어든다.

누군가 만들어 놓은 API를 이용하면 해당 서비스가 구현되는 원리는 모르더라도 API를 통해 서비스를 그대로 사용이 가능하다.

 

 

어노테이션 주석

/*

    내부에 javadocs 문서에 대한 내용을 작성한다.

 */

@author        개발자

@param        메소드에서의 매개변수

@return        메소드에서의 리턴값

@exception   메소드에서 발생하는 예외

@throws        throws에 대한 설명

@see             참고할만한 링크

@since          사용 가능한 JDK버전

@version       클래스의 버전 정보

 


 

3. Object 클래스

모든 클래스들의 최상위 클래스

 

toString() : 객체를 문자열로 바꿔서 반환해주는 메소드

                  주로 오버라이딩을 통해 인스턴스의 정보를 알기 쉽게 출력하기 위해 사용

 

equals() : 두 객체의 주소값을 비교하는 메소드(boolean)

                equals()를 오버라이딩할 경우 주소값이 아닌 인스턴스 변수(iv)를 비교할 수 있도록 한다.

 

hashCode() : 객체의 해시값(주소값과 관련된 어떤 값)을 int로 바꿔서 반환하는 메소드

 

*** equals를 재정의하면 hashCode()도 재정의 해야한다.

equals()와 hashCode() 모두 초기에는 객체의 주소값으로 작업을 하는 공통점이 있다.

만약 equals()가 재정의를 통해 인스턴스변수(iv)로 작업을 한다면, hashCode()도 마찬가지로 iv를 이용해서 작업하도록 오버라이딩 해야한다.

따라서 equals()의 결과가 true라면 두 객체의 hashCode()도 같다.

 

 

예제1

▶️toString이 주소값 보는 용도가 아니기 때문에 오버라이딩 해준다.

우리가 만들지 않은 메소드이지만 최상위클래스인 Object의 메소드이기 때문에 가져다 쓸 수 있다
toString() 오버라이딩 후 data값 초기화 뒤 "Hello" 출력

 

 

예제2

user1과 user2의 주소값이 다르기 때문에 equals 비교에서 false 출력
user name끼리 비교했으므로 true 출력됨

▶️ equals가 true인데 hashCode의 주소값은 다름으로 false인 상태 > 즉, 모순되는 상황이다.

▶️ 따라서 equals를 재정의해주면 hashCode도 재정의 해주어야 한다.

주소값도 같아짐

 

 

실습

 


 

4. String 클래스

char[]과 관련 메소드들로 이루어져 있다.

내용을 변경할 수 없는 불변 클래스

 

String data1 = "pine"

String data2 = "apple"

data1 = data1 + data2   // pineapple

> pineapple이라는 새로운 문자열 객체가 생기고 문자열 값끼리 비교한다.

 

equals() : String 클래스 안의 equals는 Objects 클래스의 equals와 다름. 매개변수로 받은 문자열과 비교하기 때문에 문자열 값끼리 비교한다. 따라서 문자열이 다르거나 매개변수가 String이 아닐 경우 false 반환

 

 

예제

문자열 리터럴과 String 객체의 주소값이 다른 이유

 


 

5. Wrapper Class(래퍼 클래스)

기본 자료형 값을 클래스로 감싸는 것

기본형 타입의 값을 객체로 다뤄야 할 때, 객체로서 사용 가능하게 해주는 클래스

 

ing > Integer

char > Character

double > Double

boolean > Boolean

 

 

boxing

기본형을 클래스형으로 바꿔주는 것

 

 

unboxing

클래스형을 기본형으로 바꿔주는 것

 

 

예제

int를 Integer로 바꿔줌으로써 객체로 다룰 수도 있고 Integer 클래스 안의 메소드들을 사용가능하다는 이점이 있다.

 

수동

Wrapper 클래스명 참조변수 = new Wrapper생성자(기본형 값)   // 박싱

기본자료형 변수명 = 객체.형타입Value();   // 언박싱

 

 

자동

jdk 1.5버전부터는 오토를 지원하기 때문에 컴파일러가 자동으로 형변환을 해준다.

Wrapper클래스명 참조변수 = 기본자료형 값;   // 오토박싱

기본자료형 변수명 = 객체;   // 오토언박싱

 

 

Wrapper 클래스 사용 이유?

1) 기본형 타입의 값을 객체로 다루어야 할 때

2) 매개변수로 객체를 넘길 때(특히 Object에는 객체를 넘겨주어야 하므로 래퍼클래스 사용)

3) 기본 자료형 타입을 (오토)박싱하면 래퍼클래스의 다양한 메소드를 사용 가능하다.

 

 

실습

 

728x90

1. 접근 권한 제어자

다른 패키지 혹은 다른 클래스에서 해당 필드에 접근할 수 있는 범위(권한)을 설정해주는 키워드들

접근 제어자 4개 중 하나만 사용 가능

 

같은 클래스 < 같은 패키지 < 다른 패키지의 자손 클래스 < 전체

제어자 같은 클래스 같은 패키지 자손 클래스 전체
public O O O O(접근제한 없음)
protected O O O 다른 패키지에 있으면 X
default O O 같은 클래스, 같은 패키지에서만 사용 가능
private O 같은 클래스에서만 사용 가능(사용 범위가 가장 좁음)

 

접근 제어자의 역할

1) 외부로부터 데이터를 보호하기 위해

2) 외부에 불필요한 정보를 노출시키지 않고 내부적으로만 사용되는 부분을 감추기 위해

3) 따라서 접근 제어자의 범위는 좁을수록 좋다.

 

private?

접근 제어자가 private로 설정된 필드는 직접 접근할 방법이 하나도 없기 때문에 무조건 public으로 설정된 getter(), setter() 메소드를 통해서 간접 접근한다. (값 사용 : getter(), 값 대입 : setter())

private를 이용하여 외부에서 직접 접근을 못하도록 막고 setter를 통해 간접 접근한다.

 


 

2. 추상클래스

구현이 안된 메소드가 선언되어 있는 클래스

구현이 안된 메소드를 추상메소드라고 부르며, 추상메소드는 바디{}가 없고, 리턴타입에 abstract를 붙인다.

ex. public abstract class Electronics{   // 추상클래스 

               abstract void on();   // 추상메소드 > ()뒤에 {}가 없음

               abstract void off();   // 추상메소드

}

추상클래스에 abstract를 붙여 추상메소드를 가지고 있다는 표시를 한다.

추상메소드가 하나라도 있으면 추상클래스이다.

 

 

추상 클래스 선언

abstract class 클래스명 {

         abstract 리턴타입 메소드명(매개변수, ...);

         * 일반메소드도 선언 가능

}

1) 일반메소드도 추상클래스 내부에 선언 가능

2) 추상클래스는 미구현 클래스이기 때문에 구현 후 객체화를 할 수 있다.

3) 따라서 상속을 통해 자식클래스에서 반드시 재정의해야 객체를 생성할 수 있다.

4) abstract 키워드가 붙으면 자식클래스에서 꼭 필수적으로 재정의해야 한다.

 

 

추상 메소드의 사용 목적

1) 꼭 필요하지만 자식마다 다르게 구현할 것이라고 예상되는 경우

2) 기존 클래스의 공통 부분만 뽑아내서 추상클래스를 만드는 경우

> 선언부는 같고 구현부가 다를 경우 추상메소드를 만들어 코드의 중복을 제거한다.

 

 

예제

메소드 선언
자식클래스에서 추상메소드 재정의
자식클래스에서 추상메소드 재정의2
새로운 클래스에서 객체 생성

 

 

실습

추상클래스(추상메소드, 일반메소드) 생성
추상메소드 구현1
추상메소드 구현2
추상메소드 구현3
새로운 클래스에서 객체 사용(doSomething();은 자식클래스에 있기 때문에 다운캐스팅 하여 사용)

 


 

3. 인터페이스(interface)

추상메소드의 집합으로 오직 "추상메소드"만 존재한다.

따라서 구현된 것이 아무것도 없는 틀이다.

 

 

인터페이스의 선언

interface 인터페이스명{

         public static final 타입 상수명 = 값;

         public abstract 리턴타입 메소드이름(매개변수, ...);

}

1) 인터페이스의 모든 메소드는 public이고, abstract이므로 전부 생략 가능

2) 마찬가지로 모든 상수는 public, static, final이므로 전부 생략 가능

 

 

인터페이스의 구현

class 클래스명 implements 인터페이스명{

         // 인터페이스에서 선언한 추상메소드 전부 구현

}

1) implements 키워드를 사용해 다른 클래스에 인터페이스를 지정하여 구현시킨다.

2) 지정받은 클래스는 인터페이스가 가지고 있는 모든 추상 메소드를 반드시 재정의 해야한다.

3) 인터페이스도 타입으로 구현된 클래스의 부모역할을 한다.

 

 

추상클래스와 인터페이스의 차이?

1) 추상클래스는 인스턴스 멤버와 생성자를 가질 수 있다. 인터페이스는 오로지 추상메소드(+상수)만 가질 수 있다.

2) 추상클래스는 상속(extends)을 통해 추상메소드를 구현시킨다. 인터페이스는 implements를 통해 추상메소드를 구현시킨다.

3) 공통점 : 추상클래스와 인터페이스 모두 추상메소드를 가지고 있다.

 

 

interface 강제성 소멸 : Adapter

인터페이스를 클래스에 바로 지정하면 모든 메소드에 강제성이 부여되어 전부 다 구현해야 한다.

하지만 일반적인 상황에서는 모든 것이 아닌 필요한 메소드만 골라서 재정의 해야하는 경우가 생긴다.

이때 특정 클래스에 인터페이스를 지정한 후 바디만 만들어 놓아 구현시켜서 강제성을 소멸시킨다.

그럼 다른 클래스들은 Adapter클래스를 상속받아서 필요한 메소드만 골라서 재정의 할 수 있게 된다.

 

 

인터페이스의 장점

1) 선언과 구현이 분리되어 있기 때문에 코드가 유연해진다.

     > 만약 변경사항이 생길 경우 선언과 구현이 분리되어 있기 때문에 구현부분만 바꿔주면 된다.

2) 관계없는 클래스들을 서로 관계를 맺어줄 수 있다.

3) 다중상속처럼 사용이 가능하다.

 

 

예제

인터페이스 구현
Adapter 클래스
Adapter 클래스 지정 -필요한 메소드만 재정의
인터페이스 지정 - 모든 메소드에 강제성 부여
인터페이스 지정 - 모든 메소드에 강제성 부여

 

 

다중상속

여러 부모 클래스를 상속하는 것

java는 모호성 때문에 다중상속을 지원하지 않는다.

하지만 인터페이스는 여러 개를 지정할 수 있기 때문에 다중상속이 가능하다.

 

 

모호성

하나의 자식이 여러 부모를 상속 받을 때 부모 필드에 동일한 이름의 필드가 있으면 어떤 부모의 필드인지 알 수가 없다.

class A{int data = 100;}

class B{int data = 200;}

class child extends A, B{}

Child ch = new Child();

ch.data; > A의 data인지 B의 data인지 판별불가

 

 

인터페이스는 다중상속처럼 사용 가능한 이유

인터페이스의 메소드는 전부 추상메소드이기 대문에 선언부만 있고 구현부가 없다.

만약 두 개의 인터페이스가 같은 이름과 같은 매개변수 개수의 메소드를 가지고 있어도 두 개의 인터페이스를 모두 구현한 클래스에서는 해당 메소드를 재정의하기 때문에 충돌이 나지 않는다.

 

 

모호성 해결 예제

인터페이스 A
인터페이스 B
인터페이스 A와 B에 동일하게 있는 printData()의 재정의를 통해 모호성 해결

 

 

default 메소드(=인스턴스 메소드)

JDK1.8버전부터는 인터페이스에 dfault 메소드 선언가능

why? 인터페이스를 구현한 클래스들이 있을 때, 인터페이스에 새로운 메소드를 추가하게 되면 기존에 구현한 클래스들도 모두 새로 추가한 메소드를 구현해야 한다. 하지만 디폴트 메소드는 구현부가 있기 때문에 기존에 구현한 클래스들에게 영향을 끼치지 않는다. 인터페이스에서 디폴트 메소드를 사용할 경우 꼭 default 키워드를 붙여야 한다.

위에서 만든 인터페이스A에 default 메소드를 추가한 모습

 

 

마커인터페이스(marker interface)

클래스들을 하나의 카테고리처럼 그룹화하기 위한 목적으로 사용한다.

인터페이스는 지정한 클래스의 부모나 다름없고, 다형성으로 모든 자식은 부모의 타입이다.

그래서 마커인터페이스를 지정받은 클래스들이 하나의 타입으로 묶이게 된다.

부모클래스 Movie
인터페이스 Action
자식클래스 Venom이 부모클래스만 상속받은 상태
자식클래스 Venom이 Action으로 그룹화됨
자식클래스 SpiderMan도 Movie를 상속하면서 Action으로 그룹화됨

 


 

4. 내부 클래스(inner class)

클래스 안에 클래스가 있는 중첩클래스

밖에 있는 클래스를 '외부 클래스', 안에 선언된 클래스를 '내부 클래스'라고 한다.

외부 클래스가 먼저 메모리에 할당되어야 내부 클래스를 객체화 할 수 있다.

 

 

내부 클래스의 장점

내부 클래스는 외부 클래스의 필드이기 때문에 외부 클래스의 필드를 자신의 필드처럼 가져다 사용할 수 있다.

class A{

         ...

         class B{

                  ...

         }

}

1) class B 안에서 class A의 멤버에 쉽게 접근 가능(객체 생성 없이도 A의 멤버 접근)

2) class B는 class A의 멤버이다.

3) 캡슐화 : 외부 클래스가 없다면 내부 클래스도 존재할 수 없기 때문에 다른 클래스에서 접근하지 못하도록 내부 클래스를 숨길 수 있다.(캡슐화 용도로 많이 쓰임)

4) 코드의 복잡성을 줄일 수 있다.

 

 

내부 클래스의 사용

외부클래스명 외부참조변수 = new 외부클래스 생성자();

외부클래스명.내부클래스명 내부참조변수 = 외부참조변수.new 내부클래스 생성자();

 

 

예제

클래스 세 개 생성. 객체를 생성해서 자유롭게 다른 클래스 필드 사용 가능
다른 클래스 안에 넣어줘서 내부클래스로 만들어줌(캡슐화)

 


 

5. 익명 클래스

이름이 없는 클래스로 딱 한 번만 사용할 클래스. 사용하면 사라진다(일회용)

클래스의 구현과 객체생성을 동시에 한다.

어떤 클래스를 상속받거나 인터페이스를 구현해야지 익명 객체 생성이 가능하다.

 

class Child extends Parents{...}   // 구현

Child ch = new Child();   // 객체 생성

             ↓(위 두 과정을 동시에)

new Parents(){...};   // 구현 + 객체 생성

 

class Rabbit implements Animals{...}   // 구현

Rabbit ra = new Rabbit();   // 객체 생성

                 ↓

new Animal(){...};   // 구현 + 객체 생성

 

 

익명 클래스 사용

new 부모클래스이름(){

         // 구현(인스턴스 멤버 선언)

};

 

new 구현인터페이스이름(){

         // 구현(인스턴스 멤버 선언)

};

 

 

예제

인터페이스 생성
new 구현인터페이스이름(){} 통째로 객체. 방법 1처럼 '.'으로 필드 사용가능하고 방법 2처럼 참조변수도 사용 가능

 

 

실습

인터페이스 생성
익명 클래스 사용

728x90

+ Recent posts