2. 유용한 클래스


2-1 javja.util.Objects클래스

isNull()은 해당 객체가 널인지 확인해 null이면 true를, 아니면 false를 반환한다.

static boolean isNull(Object obj)


nonNull()은 반대의 역할을 한다.

static boolean nonNull(Object obj)


compare()는 두 비교대상이 같으면 0, 크면 양수, 작으면 음수를 반환한다.

static int compare(Object a, Object b, Comparator c)

이 메서드는 a,b두 객체를 비교하는데, 여기서 사용할 비교 기준이 c다.


equals()의 내부에서 a와 b가 같은지 비교한다. Object의 equals와 다른 점은 null검사를 하지 않아도 되는데 있다. a와 b가 모두 null인 경우 참을 반환한다.

static boolean equals(Object a, Object b)


deepEquals()는 객체를 재귀적으로 비교하기 때문에 다차원 배열의 비교도 가능하다.

String[][] str2D = new String[][]{{"aaa","bbb"},{"AAA","BBB"}};

String[][] str2D2 = new String[][]{{"aaa","bbb"},{"AAA","BBB"}};

System.out.println(Objects.equals(str2D, str2D2)); // false

System.out.println(Objects.deepEquals(str2D, str2D2));  // true

위와 같이 두 2차원 문자열 배열을 비교할 때, equals로는 반복문을 사용해야 했지만, deepEquals()로는 간단히 끝난다.


toString()도 equals처럼 내부적으로 널 검사를 하는 것 빼고는 같은 작용을 한다.


hashCode()도 내부적으로 널 검사를 한 후에 Object클래스의 hashCode()를 호출할 뿐이다. 널일 떄는 0을 반환한다.

static int hashCode(Object o)

static int hash(object.. values)


Objects와 Object의 메서드중 이름이 같은 것들은 컴파일러가 구분을 못하므로 충돌이 난다. 

클래스 이름을 붙여주도록 하자.


2-2 java.util.random클래스

int num = (int)(Math.random()*6) + 1;

int num = new Random().nextInt(6) + 1; // nextInt(6)은 0~6사이의 정수를 반환

Random은 Math.random()과 다르게 종자값(seed)를 설정할 수 있다. 종자값이 같은 랜덤 인스턴스들은 항상 같은 난수를 같은 순서대로 반환한다. 


Random클래스의 생성자와 메서드

p.500 참조


스캐너,토크나이저,빅

Posted by Hearthole
,

1. java.lang패키지

 

1-1 Object클래스

Object클래스는 모든 클래스의 최고조상이기 때문에 Object클래스의 멤버들은 모든 클래스에서 바로 사용 가능하다.

 Object클래스의 메서드  설     명
 protected Object clone() 객체 자신의 복사본을 반환한다. 
public boolean equals (Object obj)  객체 자신과 obj가 같은 객체인지 알려준다. (같으면 true) 
 protected void finalize() 객체가 소멸될 때 가비지 컬렉터에 의해 자동적으로 호출된다. 이 때 수행되어야하는 코드가 있을 때 오버라이딩 한다. (거의 사용 안함) 
 public Class get Class() 객체 자신의 클래스 정보를 담고 있는 Class인스턴스를 반환한다. 
public int hashCode()  객체 자신의 해시코드를 반환한다. 
public void notify()  객체 자신을 사용하려고 기다리는 쓰레드를 하나만 깨운다. 
public void notifyAll()  객체 자신을 사용하려고 기다리는 모든 쓰레드를 깨운다. 
 public String toString() 객체 자신의 정보를 문자열로 저장한다. 
public void wait()
public void wait(long timeout)
public void wait(long timeout, int nanos) 
 다른 쓰레드가 notify()나 notifyAll()을 호출할 때까지 현제 쓰레드를 무한히 또는 지정된 시간(time out, nanos)동안 기다리게 한다. (timeout은 천 분의 1초, nanos는 10^9분의 1초)

 

Object클래스는 멤버변수는 없고 오직 11개의 메서드만 가지고 있다.

 

얕은 복사와 깊은 복사

clone()은 단순히 객체에 저장된 값을 그대로 복제할 뿐, 객체가 참조하고 있는 객체까지 복제하지는 않는다. 이를 완전한 복제라고 보기는 어려우므로 이러한 복제를 '얕은 복사(shallow copy)'라고 한다. 얕은 복사에서는 원본을 변경하면 복사본도 영향을 받는다.

 반면에 원본히 참조하고 있는 객체까지 복제하는 것을 '깊은 복사(deep copy)'라고 하며, 깊은 복사에서는 원본과 복사본이 서로 다른 객체를 참조하기 때문에 원본의 변경이 복사본에 영향을 미치지 않는다.

 

 

1-2 String클래스

 

변경불가능한(immutable) 클래스

한번 생성된 String 인스턴스가 갖고 있는 문자열은 읽어 올 수만 있고, 변경할 수는 없다.

문자열간의 결합이나 추출 등 문자열을 다루는 작업이 많이 필요한 경우에는 String클래스 대신 StringBuffer클래스를 사용하는 것이 좋다.

 

문자열의 비교 

문자열을 만들 때눈 두 가지 방법 문자열 리터럴을 지정하는 방법과 String클래스의 생성자를 사용해서 만드는 방법이 있다.

 

String str1 = "abc"; // "abc"의 주소가 str1에 저장됨. (이미 존재하는 것 재사용)

String str2 = new String("abc"); // 새로운 String인스턴스를 생성 (새 메모리 할당)

 

문자열 리터럴

자바 소스파일에 포함된 모든 문자열 리터럴은 컴파일 시에 클래스 파일에 저장된다. 이때 같은 내용의 문자열 리터럴은 한번만 저장된다. 문자열 리터럴도 String인스턴스이고, 한번 생성하면 내용을 변경할 수 없으니 하나의 인스턴스를 공유하면 되기 때문이다.

 

빈 문자열(empty string)

길이가 0인 배열도 존재 할 수 있다.

 

String s =""; // 빈 문자열로 초기화

char c = ' '; // 공백으로 초기화 

 

String클래스의 생성자와 메서드

p.468 참고

 

join()과 StringJoiner

join()은 여러 문자열 사이에 구분자를 넣어 결합한다. 구분자로 문자열을 자르는 split()와 반대의 작업을 한다.

String animals = "dog,cat,bear";

String[] arr = animals.split(","); // 문자열을 ','구분자로 나눠서 배열에 저장

String str = String.join("-",arr); // 배열의 문자열을 '-'로 구분해서 결합

System.out.println(arr); // dog-cat-bear

 

String.format()

printf()와 사용법이 완전히 같다.

 

기본형 값을 String 문자열로 변환

간단히 숫자에 빈문자열 ""을 더해주면 된다. 이 외에 valueOf()를 사용하는 방법도 있다. 성능은 이쪽이 더 좋으나 방법은 전자가 더 간단하기에 성능향상이 필요한 경우에만 사용하자.

 

int i = 100;

String str1 = i+"";

String str2 = String.valueOf(i);

 

String을 기본형 값으로 변환

valueOf()를 쓰거나 parseInt()를 사용하면 된다.

int i = Integer.parseInt("100"); 

int i2 = Integer.valueOf("100");

실제로 valueOf()의 반환타입은 int가 아닌 integer이지만, 이는 오토박싱에 의해 자동 변환된다.

 

 

1-3 String클래스와 StringBuilder클래스

String클래스는 인스턴스를 생성할 때 지정된 문자열을 변경할 수 없지만 StringBuffer클래스는 변경이 가능하다.

 

StringBuffer의 생성자

StringBuffer클래스의 인스턴스를 생성할 때, 적절한 길이의 char형 배열이 생성되고, 이 배열이 문자열을 저장하고 편집하기 위한 공간(Buffer)로 사용된다.

크기를 별도로 지정하지 않으면 버퍼의 크기는 16이 된다.

 

StringBuffer의 변경

String과 달리 StringBuffer는 자신의 주소를 반환한다.

append()는 반환타입이 StringBuffer인데 자신의 주소를 반환한다. 아래와 같은 문장이 수행되면 sb에 새로운 문자열이 추가되고 sb자신의 주소를 반환하여 sb2에는 sb의 주소가 저장된다.

 

StringBuffer sb2 = sb.append("ZZ"); // sb의 내용뒤에 "ZZ"를 반환한다.

System.out.println(sb); // abc123ZZ

System.out.println(sb2); // abc123ZZ

 

sb와 sb2가 모두 같은 StringBuffer인스턴스를 가리키고 있으므로 같은 내용이 출력된다.

 

sb.append("123").append("ZZ");

따라서 이러한 표현도 가능하다. 밑줄 친 부분이 sb이기 때문이다.

 

StringBuffer의 비교

String클래스에서는 equals메서드를 오버라이딩해서 문자열의 내용을 비교하도록 되어있지만, StringBuffer클래스는 그렇지 않아서 StringBuffer클래스의 equals를 사용해도 등가비교연산자(==)로 비교한것과 같은 결과를 얻는다.

반면에 toString()은 오버라이딩되어 있어서 StringBuffer인스턴스에 toString()을 호출하면, 담고있는 문자열을 String으로 반환한다. 따라서 StringBuffer인스턴스의 문자열 비교를 위해서는 toString()을 호출해서 String인스턴스를 얻은 후, 두 값을 equals메서드로 비교해야한다. 

 

String s = sb.toString();

String s2 = sb2.toString();

 

System.out.println(s.equals(s2)); // true출력

 

StringBuffer클래스의 생성자와 메서드

p.480 참조

 

StringBuilder란?

StringBuffer클래스는 멀티쓰레드에 안전하도록 동기화되어 있는데, 멀티쓰레드로 작성된 프로그램이 아닌 경우, 동기화는 불필요하게 성능만 떨어뜨린다.

StringBuilder는 StringBuffer에서 동기화 기능만만 뺀 클래스이며, 나머지 기능은 모두 같다. 

 

 

1-4 Math클래스

Math클래스는 기본적인 수학계산에 유용한 메서드로 구성되어 있다.

 

올림, 버림, 반올림

소수점 n번째 자리에서 반올림한 값을 얻기 위해서는 round()를 사용해야 하는데, 이 메서드는 항상 소수점 첫째자리에서 반올림해서 정수값(long)을 돌려준다.

 원하는 자리 수에서 반올림된 값을 얻기 위해서는 간단히 10의 n제곱으로 곱한 후 다시 곱한 수로 나눠주기만 하면 된다.

 

1. 원래 값에 100을 곱한다.

90.7552*100 -> 9075.52

2. 위의 결과에 Math.round()를 사용한다.

Math.round(9075.52) -> 9076

3. 위의 결과를 다시 100.0으로 나눈다.

9076 / 100.0 -> 90.76

9076 / 100 -> 90 // 정수형 계산에서는 반올림이 이루어지지 않음.

 

짝수 반올림

rint()는 짝수반올림 메서드인데, 주로 반올림 오차를 줄이는데 이용한다.

 

예외를 발생시키는 메서드

메서드 이름에 'Exact'가 포함된 메서드들이 JDK1.8부터 추가되었다. 이들은 정수형 연산에서 발생할수 있는 오버플로우(overflow)를 감지하기 위한 것이다.

연산자는 단지 결과를 반환할 뿐, 오버플로우의 발생여부에 대해 알려주지 않는데, 위의 메서드들은 오버플로우가 발생하면 예외를 발생시킨다.

 

삼각함수와 지수,로그

자세한 내용은 JavaAPI 참조.

 

StrictMath클래스

OS별로 계산값이 다를수 있는 Math클래스의 대안으로 작성되었다. 다만 성능은 다소 떨어진다.

 

Math클래스의 메서드

 p.489 참조

 

 

1-5 래퍼(wrapper) 클래스

객체지향 개념에서 모든 것은 객체로 다루어져야 한다. 그러나 자바에서는 8개의 기본형을 객체로 다루지 않는다. 

 다만, 때로는 기본형(primitive type) 변수도 어쩔 수 없이 객체로 다뤄야 할 때가 있는데, 예를 들면 매개변수로 객체를 요구할 때, 기본형 값이 아닌 객체로 저장해야할 때, 객체간의 비교가 필요할 때 등등의 경우에는 기본형 값들을 객체로 변환하여 작업을 수행해야 한다.

 이 때 사용되는 것이 래퍼(wrapper)클래스이다. 8개의 기본형을 대표하는 8개의 래퍼클래스가 있는데, 이 클래스들을 이용하면 기본형 값을 객체로 다룰 수 있다. 

 

boolean - Boolean

char - Character

byte - Byte

short - Short

int - Integer

long - Long

float - Float

double - Double

 

래퍼클레스의 생성자는 매개변수로 문자열이나 각 자료형의 값들을 인자로 받는다.

 

Number클래스

이 클래스는 추상클래스로 내부적으로 숫자를 멤버변수로 갖는 래퍼클래스들의 조상이다. 기본형 중에서 숫자와 관련된 래퍼클래스들은 모두 Number클래스의 자손이라는 것을 알 수 있다.

Number클래스의 자손으로 BigInteger와 BigDecimal 등이 있는데, BigInteger는 long으로도 다룰 수 없는 큰 범위의 정수를, BigDecimal은 double로도 다룰 수 없는 큰 범위의 부동 소수점수를 처리하는데 사용한다.

 

문자열을 숫자로 변환하기

 

기본형 반환값

타입.parse타입(String s)

Integer.parseInt("100");

 

래퍼타입 반환값

타입.valueOf( )

Integer.valueOf("100");

 

16진법변환

Integer.parseInt("FF",16);

 

오토박싱 & 언박싱(autoboxing & unboxing)

JDK 1.5 이전에는 기본형과 참조형 간의 연산이 불가능해 래퍼클래스로 기본형을 객체로 만들어서 연산해야 했다. 그러나 이제는 기본형과 참조형의 덧셈이 가능하다. 자바 언어의 규칙이 바뀐 것은 아니고 컴파일러가 자동으로 변환코드를 넣어준다.

이처럼 기본형 값을 래퍼클래스의 객체로 자동변환하는 것을 오토박싱(autoboxing), 반대로 변환하는 것을 언박싱(unboxing)이라 한다.

 

 

Posted by Hearthole
,

8. 내부 클래스(inner class)

클래스 내에 선언된다는 점을 제외하고는 일반적인 클래스와 다르지 않으며, 몇가지 특징만이 별도로 존재한다.


8-1 내부 클래스란?

내부 클래스는 클래스 내에 선언된 클래스이다. 두 클래스가 서로 긴밀한 관계에 있을 때 이렇게 선언할 것을 고려한다.


내부 클래스의 장점

-내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 잇다.

- 코드의 복잡성을 줄일 수 있다(캡슐화).


8-2 내부 클래스의 종류와 특징

내부 클래스의 종류는 변수의 선언위치에 따른 종류와 같다. 내부 클래스는 마치 변수를 선언하는 것과 같은 위치에 선언할 수 있으며, 변수의 선언위치에 따라 구분되는 것과 같이 내부 클래스도 다음과 같이 구분되어 진다. 여러모로 변수와 유사하다.


내부 클래스

특   징

인스턴스 클래스

(instance class)

 외부 클래스의 멤버변수 선언위치에 선언하며, 외부 클래스의 인스턴스 멤버처럼 다루어진다. 주로 외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용될 목적으로 선언된다.

스태틱 클래스

(static class) 

 외부 클래스의 멤버변수 선언위치에 선언하며, 외부 클래스의 static멤버처럼 다루어진다. 주로 외부 클래스의 static멤버, 특히 static메서드에서 사용될 목적으로 선언된다.

 지역 클래스

(local class)

 외부 클래스의 메서드나 초기화블럭 안에 선언하며, 선언된 영역 내부에서만 사용될 수 있다.

 익명 클래스

(anoymous class)

 클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스 (일회용)


8-3 내부 클래스의 선언

변수가 선언된 위치에 따라 타입이 나뉘듯이 내부 클래스도 이와 마찬가지로 선언된 위치에 따라 나뉜다.


8-4 내부 클래스의 제어자와 접근성

인스턴스클래스와 스태틱 클래스는 외부 클래스와 멤버변수(인스턴스변수와 클래스변수)와 같은 위치에 선언되며, 또한 멤버변수와 같은 성질을 갖는다. 따라서 내부 클래스가 외부 클래스의 멤버와 같이 간주되고, 인스턴스멤버와 static멤버 간의 규칙이 내부 클래스에도 똑같이 적용된다. 그리고 내부 클래스도 클래스이기 때문에 abstract나 final과 같은 제어자를 사용할 수 있을 뿐만 아니라, 멤버변수들처럼 private, protected와 접근제어자도 사용이 가능하다.


내부 클래스와 외부 클래스에 선언된 변수의 이름이 같을 땐 변수 앞에 'this' 또는 '외부 클래스명.this'를 붙여 서로 구별할 수 있다.


8-5 익명 클래스(anonymous class)

다른 내부 클래스들과는 달리 이름이 없다. 클래스의 선언과 객체의 생성을 동시에 하기 때문에 단 한번만 사용 될 수 있고 오직 하나의 객체만을 생성할 수 있는 일회용 클래스이다.

생성자를 가질 수 없으며, 하나의 클래스를 상속받는 동시에 인터페이스를 구현하거나 둘 이상의 인터페이스도 구현할 수 없다. 단 하나의 클래스를 상속받거나 인터페이스를 구현할 수 있다.


Posted by Hearthole
,

7. 인터페이스(interface)


7-1 인터페이스란?

인터페이스는 일종의 추상클레스이다. 추상클래스처럼 추상메서드를 갖지만 추상클래스보다 추상화 정도가 높아서 몸통을 갖춘 일반메서드 또는 멤버변수를 구성원으로 가질 수 없다. 오직 추상메서드와 상수만을 멤버로 가질 수 있으며, 그 외의  다른 어떠한 요소도 허용하지 않는다.


추상클래스 - 미완성 설계도

인터페이스 - 기본 설계도


7-2 인터페이스의 작성

인터페이스를 작성하는 것은 클래스를 작성하는 것과 같다. 다만 키워드로 class대신 interface를 사용한다는 것만 다르다. 클래스와 같이 접근제어자로 public 또는 default를 사용할 수 있다.


interface 인터페이스이름{

public static final 타입 상수이름 = 값;

public abstract 메서드이름(매개변수목록);

}


일반적인 클래스의 멤버들과 달리 인터페이스의 멤버들은 다음과 같은 제약사항이 있다.

- 모든 멤버변수는 public static final 이어야 하며, 이를 생략할 수 있다.

- 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다.

[단, static메서드와 디폴트 메서드는 예외 (JDK1.8부터) ]

인터페이스에 정의된 모든 멤버에 예외없이 적용되는 사항이기 때문에 제어자를 생략할 수 있는 것이며, 편의상 생략하는 경우가 많다. 생략된 제어자는 컴파일러가 자동적으로 추가해준다.


원래는 모든 메서드는 추상메서드여야 했는데, JDK1.8부터 인터페이스에 static메서드와 디폴트 메서드(default method)의 추가를 허용하는 방향으로 변경되었다. 실무에서는 아직 JDK1.8을 사용하지 않는 곳이 많기에 JDK1.8이전과 이후의 규칙을 모두 알고 있어야 한다.


7-3 인터페이스의 상속

인터페이스는 인터페이스로부터만 상속받을 수 있으며, 클래스와는 달리 다중상속, 즉 여러개의 인터페이스로부터 상속을 받는 것이 가능하다.

클래스와 마찬가지로 자손인터페이스는 조상인터페이스에 정의된 멤버를 모두 상속받는다.

[인터페이스는 클래스와 달리 Object클래스와 같은 최고조상이 없다.]


7-4 인터페이스의 구현

인터페이스도 추상클래스처럼 그 자체로는 인스턴스를 생성할 수 없으며, 추상클래스가 상속을 통해 추상메서드를 완성하는 것처럼, 인터페이스도 자신에 정의된 추상메서드의 몸통을 만들어주는 클래스를 작성해야 한다. 클래스의 확장 키워드 'extends'처럼 인터페이스는 구현한다는 키워드 'implements'를 사용한다.

만일 구현하는 인터페이스의 메서드 중 일부만 구현한다면 abstract를 붙여 추상클래스로 선언해야 한다. 상속과 구현을 동시에 할 수 도 있다.

인터페이스의 메소드에는 'public abstract'가 생략되었을 뿐, 항상 붙어있으니 이를 오버라이딩 시 접근 제어자를 반드시 public으로 해줘야 한다.


7-5 인터페이스를 이용한 다중상속

자바는 다중상속을 허용하지 않는다는 것이 단점으로 부각되는 것의 대응으로 '자바도 인터페이스를 이용하면 다중상소깅 가능하다' 라는 것일 뿐, 인터페이스가 다중상속을 위해서 존재하는 것은 아니다. 오히려 자바에서 인터페이스로 다중상속을 구현하는 경우는 거의 없다. 

 만일 두 개의 클래스로부터 상속을 받아야 할 상황이라면, 두 조상클래스 중에서 비중이 높은 쪽을 선택하고 다른 한쪽은 클래스 내부에 멤버로 포함시키는 방식으로 처리하거나 어느 한쪽의 필요한 부분을 뽑아 인터페이스로 만든 다음 구현하도록 한다.

인터페이스를 새로 작성하지 않고 클래스를 내부에 포함시키는걸로 충분하지만, 인터페이스를 이용하면 다형적 특성을 이용할 수 있다는 장점이 있다.


7-6 인터페이스를 이용한 다형성

인터페이스 역시 클래스의 조상이라 할 수 있으므로 해당인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있으며, 인터페이스 타입으로의 형변환도 가능하다.

 

 인터페이스 Fightable을 클래스 Fighter가 구현했을 때, 다음과 같이 Fighter인스턴스를 Fightable타입의 참조변수로 참조하는 것이 가능하다.

Fightable f = (Fightable)new Fighter();

또는

Fightable f = new Fighter();


리턴타입이 인터페이스라는 것은 메서가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 것을 의미한다.


7-7 인터페이스의 장점


인터페이스를 사용하는 이유와 장점

-개발시간을 단축시킬 수 있다.

-표준화가 가능하다.

-서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.

-독립적인 프로그래밍이 가능하다.


7-8 인터페이스의 이해


-클래스를 사용하는 쪽(User)과 제공하는 쪽(Provider)이 있다.

-메서드를 사용(호출)하는 쪽(User)에서는 사용하려는 메서드(Provider)의 선언부만 알면 된다.(내용은 몰라도 된다.)



7-9 디폴트 메서드와 static메서드


디폴트 메서드

디폴트 메서드는 앞에 default를 붙이며, 추상 메서드와 달리 일반 메서드처럼 몸통{}이 잇어야 한다. 디폴트 메서드 역시 접근 제어자가 public이며, 생략 가능하다.


새로 추가된 디폴트 메서드가 기존 메서드와 이름이 중복되어 충돌하는 경우

1. 여러 인터페이스의 디폴트 메서드 간의 충돌

- 인터페이스를 구현한 클래스에서 메서드를 오버라이딩해야 한다.

2. 디폴트 메서드와 조상클래스의 메서드 간의 충돌

- 조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.

 





Posted by Hearthole
,

6. 추상클래스(abstract class)


6-1 추상클래스란?

미완성 메서드(추상메서드)를 포함하고 있는 클래스이다. 인스턴스를 생성할 수 없으며, 상속을 통해서 자손클래스에 의해서만 완성될 수 있다.

키워드 'abstract'를 붙이기만 하면 된다. 이렇게 하면 클래스 선언부의 'abstract'를 보고 이클래스에는 추상메서드가 있으니 상속을 통해서 구현해주어야 한다는 것을 쉽게 알 수 있다.

또한 추상클래스는 추상메서드를 포함하고 있다는 것을 제외하고는 일반클래스와 전혀 다르지 않다. 추상클래스에도 생성자가 있으며, 멤버변수와 메서드도 가질 수 있다.


6-2 추상메서드(abstract method)

선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것이 추상메서드이다. 즉, 설계만 해놓고 실제 수행될 내용은 작성하지 않았기 때문에 미완성 메서드인 것이다.


/* 주석을 통해 어떤 기능을 수행할 목적으로 작성하였는지 설명한다 */

abstract 리턴타입 메서드이름();


추상클래스로부터 상속받는 자손클래스는 오버라이딩을 통해 조상인 추상클래스의 추상메서드를 모두 구현해주어야 한다. 만일 조상으로부터 상속받은 추성메서드 중 하나라도 구현하지 않는다면, 자손클래스 역시 추상클래스로 지정해 주어야 한다.



6-3 추상클래스의 작성

여러 클래스에 공통적으로 사용될 수 있는 클래스를 바로 작성하기도 하고, 기존의 클래스의 공통적인 부분을 뽑아서 추상클래스로 만들어 상속하도록 하는 경우도 있다.


상속이 자손 클래스를 만드는데 조상 클래스를 사용하는 것이라면, 이와 반대로 추상화는 기존의 클래스의 공통부분을 뽑아내서 조상클래스를 만드는 것이라고 할 수 있다. 서로 반대되는 개념으로 이해하면 편하다.


추상화 - 클래스간의 공통점을 찾아내서 공통의 조상을 만드는 작업

구체화 - 상속을 통해 클래스를 구현, 확장하는 작업



Posted by Hearthole
,

5. 다형성(polymorphism)


5-1 다형성이란?

'여러 가지 형태를 가질 수 있는 능력'을 의미한다.

구체적으로는 '조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 하였다는 것'이다.


- 조상타입의 참조변수로 자손타입의 인스턴스를 참조할 수 있다.

- 반대로 자손타입의 참조변수로 조상타입의 인스턴스를 참조할 수는 없다.


5-2 참조변수의 형변환

참조변수도 형변환이 가능하다. 단, 서로 상속관계에 있는 클래스사이에서만 가능하기 때문에 자손타입과 조상타입 서로간의 형변환만 가능하다.


자손타입 -> 조상타입(up-casting)    : 형변환 생략가능

조상타입 -> 자손타입(down-casting) : 형변환 생략불가


형변환은 참조변수의 타입을 반환하는 것이지 인스턴스를 변환하는 것은 아니기 때문에 참조변수의 형변환은 인스턴스에 아무런 영향을 미치지 않는다.

 단지 참조변수의 형변환을 통해서, 참조하고 있는 인스턴스에서 사용할 수 잇는 멤버의 범위(개수)를 조절하는 것 뿐이다.


서로 상속관계에 잇는 타입간의 형변환은 양방향으로 자유롭게 수행될 수 있으나, 참조변수가 가리키는 인스턴스의 자손타입으로 형변환은 허용되지 않는다. 그래서 참조변수가 가리키는 인스턴스의 타입이 무엇인지 확인하는 것이 중요하다.


5-3 instanceof연산자

참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 사용한다.

주로 조건문에 사용되며, instanceof의 왼쪽에는 참조변수를 오른쪽에는 타입(클래스명)이 피연산자로 위치한다. 그리고 연산의 결과로 true, false 둘 중 하나를 boolean타입으로 반환한다.


어떤 타입에 대한 instanceof연산의 결과가 true라는 것은 검사한 타입으로 형변환이 가능하다는 것을 뜻한다.


5-4 참조변수와 인스턴스의 연결

조상 클래스에 선언된 멤버변수와 같은 이름의 인스턴스변수를 자손 클래스에 중복으로 정의했을 때, 조상타입의 참조변수로 자손인스턴스를 참조하는 경우와 자손타입의 참조변수로 자손인스턴스를 참조하는 경우는 서로 다른 결과를 얻는다.

메서드의 경우 조상 클래스의 메서드를 자손의 클래스에서 오버라이딩한 경우에도 참조변수의 타입에 관계없이 항상 실제인스턴스의 메서드(오버라이딩된 메서드)가 호출되지만, 멤버변수의 경우 참조변수의 타입에 따라 달라진다.

참고) static메서드의 경우 참조변수가 아닌 '클래스이름.메서드()'로 호출한다.


5-5 매개변수의 다형성

참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다.


5-6 여러 종류의 객체를 배열로 다루기

조상타입의 참조변수 배열을 사용하면, 공통의 조상을 가진 서로 다른 종류의 객체를 배열로 묶어서 다룰 수 있다.

이 때 배열의 크기를 조정하는데 문제가 생길 수 있는데, 이 때 Vector를 이용하면 된다.


Vector는 동적으로 크기가 관리되는 객체배열이다.

메서드 / 생성자

 설 명

 Vector()

 10개의 객체를 저장할 수 있는 Vector인스턴스를 생성한다. 

10개 이상의 인스턴스가 저장되면, 자동적으로 크기가 증가된다. 

 boolean add(Object o)

 Vector에 객체를 추가한다. 추가에 성공하면 결과값으로 true, 실패하면 false를 반환한다. 

 boolean remove(Object o)

 Vector에 저장되어 있는 객체를 제거한다. 제거에 성공하면 true, 실패하면 false를 반환한다.

 boolean isEmpty()

 Vector가 비어있는지 검사한다. 비어있으면 true, 비어있지 않으면 false를 반환한다.

 Object get(int index)

 지정된 위치(index)의 객체를 반환한다. 반환타입이 Object타입이므로 적절한 타입으로의 형변환이 필요하다

int size() 

 Vector에 저장된 객체의 개수를 반환한다.




Posted by Hearthole
,

4. 제어자(modifier)


4-1 제어자란?

클래스, 변수 또는 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여한다. 크게 접근 제어자와 그 외의 제어자로 나뉜다.

 하나의 대상에 여러 제어자를 조합하여 사용하는것이 가능하지만, 접근 제어자는 한번에 네 가지중 하나만 사용할 수 있다.


접근 제어자 - public, protected, default, private

그         외 - static, final, abstract, native, transient, synchronized, volatile, strictfp


4-2  static - 클래스의, 공통적인

인스턴트변수는 하나의 클래스로부터 생성되었더라도 각기 다른 값을 유지하지만, 클래스변수(static멤버 변수)는 인스턴스에 관계없이 같은 값을 갖는다. 하나의 변수를 모든 인스턴스가 공유하기 때문이다.

 static이 붙은 멤버변수와 메서드, 초기화 블럭은 인스턴스를 생성하지 않고도 사용할 수 있다. 

 인스턴스메서드와 static메서드는 메서드 내에서 인스턴스 멤버를 사용하는가의 차이가 있다.


static이 사용될 수 있는 곳 - 멤버변수, 메서드, 초기화 블럭

static 멤버변수 - 모든 인스턴스에 공통적으로 사용되는 클래스변수가 된다.

   - 클래스 변수는 인스턴스를 생성하지 않고도 사용이 가능하다.

   - 클래스가 메모리에 로드될 때 생성된다.

static 메서드    - 인스턴스를 생성하지 않고도 호출이 가능해진다.

   - static메서드 내에서는 인스턴스멤버들을 직접 사용할 수 없다.  


4-3 final - 마지막의, 변경될 수 없는

거의 모든 대상에 사용될 수 있다.

 변수에 사용되면 상수가 되고, 메서드에 사용되면 오버라이딩이 불가해진다. 클래스에 사용되면 자손클래스로의 확장이 불가해진다.


final이 사용될 수 있는 곳 - 클래스, 메서드, 멤버변수, 지역변수


final 사용시

클래스 - 변경될 수 없는 클래스, 확장될 수 없는 클래스가 된다. 즉, 조상이 될 수 없다.

메서드 - 변경될 수 없는 메서드, 오버라이딩이 불가하다

멤버변수 - 값을 변경할 수 없는 상수가 된다.

지역변수 - 값을 변경할 수 없는 상수가 된다.


생성자를 이용한 final멤버 변수의 초기화

final 이 붙은 변수는 상수이므로 일반적으로 선언과 동시에 초기화하지만, 인스턴스변수의 경우 생성자에서 초기화되도록 할 수 있다.

 클래스 내에 메개변수를 갖는 생성자를 선언하여, 인스턴스를 생성할 때 final이 붙은 멤버변수를 초기화하는데 필요한 값을 생성자의 매개변수로부터 제공받는 것이다.


4-4 abstract - 추상의, 미완성의

메서드의 선언부만 작성하고 실제 수행내용은 구현하지 않은 추상 메서드를 선언하는데 사용된다.

또한 클래스에 사용되어 추상메서드 존재여부를 알 수 있게도 한다.


abstract 사용시

클래스 - 클래스 내에 추상 메서드가 선언되어 있음을 의미한다.

메서드 - 선언부만 작성하고 구현부는 작성하지 않은 추상메서드임을 알린다.


4-5 접근 제어자(access modifier)

멤버 또는 클래스에 사용되어, 해당하는 멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 한다. 이 때 default는 생략 가능하다.


접근 제어자가 사용될 수 잇는 곳 - 클래스, 멤버변수, 메서드, 생성자

private 같은 클래스 내에서만 접근가능

default 같은 패키지 내에서만 접근가능

protected 같은 패키지내에서, 그리고 다른 패키지의 자손클래스에서 접근이 가능하다.

public 접근 제한이 전혀 없다.


범위

public > protected > (default) > private


접근 제어자를 이용한 캡슐화

클래스나 멤버, 주로 멤버에 접근 제어자를 사용하는 이유는 클래스의 내부에 선언된 데이터를 보호하기 위해서이다.  데이터가 유효한 값을 유지하도록, 또는 비밀번호와 같은 데이터를 외부에서 변경하지 못하도록 외부로부터의 접근을 제한하는 것이 필요하다.

이것을 데이터 감추기(data hiding)라고 하며, 객체지향개념의 캡슐화(encapsulation)에 해당하는 내용이다.


접근 제어자를 사용하는이유

- 외부로부터 데이터를 보호하기 위해서

- 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해서


생성자의 접근 제어자

생성자에 접근 제어자를 사용함으로써 인스턴스의 생성을 제한할 수 있다.

보통 생성자의 접근 제어자는 클래스의 접근 제어자와 같지만, 다르게 지정할 수도 있다.


4-6 제어자(modifier)의 조합


대상에 따라 사용할 수 있는 제어자

 대상

사용가능한 제어자 

클래스 

public, (default), final, abstract 

메서드 

모든 접근 제어자, final, abstract, static 

멤버변수 

모든 접근 제어자, final, static 

지역변수 

final 


제어자를 조합해서 사용할 때 주의해야 할 사항

1. 메서드에 static과 abstract를 함께 사용 할 수 없다.

static메서드는 몸통이 있는 메서드에만 사용할 수 있기 때문이다.

2. 클래스에 abstract와 final을 동시에 사용할 수 없다.

클래스에 사용되는 final은 클래스를 확장할 수 없다는 의미이고 abstract는 상속을 통해서 완성되어야 한다는 의미이므로 서로 모순되기 때문이다.

3. abstract메서드의 접근 제어자가 private일 수 없다.

abstract메서드는 자손클래스에서 구현해주어야 하는데 접근 제어자가 private이면 자손클래스에서 접근할 수 없기 때문이다.

4. 메서드에 private과 final을 같이 사용할 필요는 없다.

접근 제어자가 private인 메서드는 오버라이딩될 수 없기 때문이다. 이 둘 중 하나만 사용해도 의미가 충분하다.














Posted by Hearthole
,

3. package와 import


3-1 패키지(package)


- 하나의 소스파일에는 첫 번째 문장으로 단 한번의 패키지 선언만을 허용한다.

- 모든 클래스는 반드시 하나의 패키지의 속해야 한다.

- 패키지는 점(.)을 구분자로 하여 계층구조로 구성할 수 있다.

- 패키지는 물리적으로 클래스 파일(.class)을 포함하는 하나의 디렉토리이다.


ex) java.lang.String에서 lang은 디렉토리 String이 클래스


3-2 패키지의 선언

소스파일에 다음과 같이 한줄만 적어주면 된다.
package 패키지명;



3-3 import문

클래스 작성 전에 import문으로 사용하고자 하는 클래스의 패키지를 미리 명시해주면 소스코드에 사용되는 클래스이름에서 패키지명은 생략할 수 있다.

컴파일 시 컴파일러는 import문을 통해 소스파일에 사용된 클래스들의 패키지를 알아 낸 다음, 모든 클래스이름 앞에 패키지명을 붙여 준다.

이클립스에서는 단축키 'ctrl+shift+o'를 누르면 자동으로 import문이 추가된다.


3-4 import문의 선언

모든 소스파일(.java)에서 import문은 package다음, 클래스 선언문 이전에 위치해야 한다.

package와 달리 여러 번 선언할 수 있다.


일반적인 소스파일(*.java)의 구성은 다음의 순서로 되어 있다.

1.package문

2.import문

3.클래스 선언


import문을 선언하는 방법은 다음과 같다.

import 패키지명.클래스명;

 또는

import 패키지명.*;

클래스이름을 지정해주는 대신 '*'을 사용하면, 컴파일러가 패키지에서 일치하는 클래스이름을 찾아 컴파일 시에 적용시킨다. 실행 시 성능상의 차이는 전혀 없다.


3-5 static import문

static멤버를 호출할 때 클래스 이름을 생략할 수 있다. 특정 클래스의 static멤버를 사용할때 좋다.


ex)

import static java.lang.Integer.*; // Integer클래스의 모든 static 메서드

import static java.lang.Math.random; // Math.random()만. 괄호 안붙임. -> random()

import static.java.lang.System.out; // System.out을 out만으로 참조가능 -> out


System.out.println(Math.random()); <-> out.println(random());


Posted by Hearthole
,

2. 오버라이딩(Overriding)


2-1 오버라이딩이란?

조상클래스로부터 상속받은 메서드의 내용을 변경하는 것


2-2 오버라이딩의 조건


자손클래스에서 오버라이딩하는 메서드는 조상클래스의 메서드와

1. 이름이 같아야 한다.

2. 매개변수가 같아야 한다.

3. 반환타입이 같아야 한다.

즉, 선언부가 일치해야 한다는 것이다.


접근제어자와 예외의 경우 제한된 조건 하에서 변경할 수 있다.

1. 접근제어자는 조상클래스의 메서드보다 좁은 범위로 변경 할 수 없다.

2. 조상 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.

3. 인스턴스메서드를 static메서드로 또는 그 반대로 변경할 수 없다.

(조상클래스에 있는 static메서드를 자손클래스에 선언하는것은 오버라이딩이 아니며, 완전히 별개의 static메서드를 새로 선언한 것이다. static멤버들은 자신이 정의된 클래스에 묶여있어야 한다.) 


ex1) O

Parent ... IOException, SQLException

Child ... IOException  

바르게 오버라이딩 되었다.


ex2) X

Parent ... IOException, SQLException

Child ... Exception

언듯 조상클래스에 정의된 메서드보다 적은 개수의 예외를 선언한 것 처럼 보이지만

Exception은 모든 예외의 최고조상이므로 가장 많은 개수의 예외를 가진 것이다.

단순히 예외메서드의 갯수만 보지 않도록 주의하자.


2-3 오버로딩 vs 오버라이딩

오버로딩(overloading) - 기존에 없는 새로운 메서드를 정의하는 것(new)

오버라이딩(overriding) - 상속받은 메서드의 내용을 변경하는 것(change, modify)


2-4 super

자손클래스에서 조상클래스로부터 상속받은 멤버를 참조하는데 사용하는 참조변수다.

상속받은 멤버와 자신의 클래스에 정의된 이름이 같을 때 super를 붙여서 구별할 수 있다.


2-5 super() - 조상클래스의 생성자

조상클래스의 생성자를 호출하는데 사용된다.


Object 클래스를 제외한 모든 클래스의 생성자 첫 줄에 생성자 this() 또는 super()를 호출해야 한다.

그렇지 않으면 컴파일러가 자동적으로 'super();'를 생성자의 첫 줄에 삽입한다.


인스턴스를 생성할 때는 클래스를 선택하는 것만큼 생성자를 선택하는 것도 중요하다.

1. 클래스 - 어떤 클래스의 인스턴스를 생성할 것인가?

2. 생성자 - 선택한 클래스의 어떤 생성자를 이용해서 인스턴스를 생성할 것인가?









Posted by Hearthole
,

객체지향 프로그래밍 II


1. 상속(inheritance)


1-1 상속의 정의와 장점

상속이란, 기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것이다.

코드의 재사용성을 높이고 코드의 중복을 제거한다.


조상 클래스 - 부모(Parent)클래스, 상위(super)클래스, 기반(base)클래스

자손 클래스 - 자식(child)클래스, 하위(sub)클래스, 파생된(derived)클래스


ex)

class Parent{}

class Child extends Parent{}


- 생성자와 초기화 블럭은 상속되지 않는다. 멤버만 상속된다.

- 자손 클래스의 멤버 개수는 조상클래스보다 항상 같거나 많다.

- 자손 클래스의 인스턴스를 생성하면 조상 클래스의 멤버와 자손 클래스의 멤버가 합쳐진 하나의 인스턴스로 생성된다.



1-2 클래스간의 관계 - 포함관계

클래스간의 포함관계를 맺어 주는 것은 한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것을 뜻한다.


ex)

class Point{

int x;

int y;

}


class Circle{

Point c = new Point();

int r;

}


Circle에 Point의 x,y좌표를 포함시켰다.


1-3 클래스간의 관계 결정하기

간단히 is-a 와 has-a 로 결정한다.


원(Circle)은 점(Point)이다. - Circle is a Point

원(Circle)은 점(Point)을 가지고 있다. - Circle has a Point


두번째 문장이 더 옳다는 것은 명백하다. 따라서 둘은 포함관계다.


상속관계 '~은 ~이다.(is~a)'

포함관계 `~은 ~을 가지고 있다.(has-a)' 


1-4 단일 상속(single inheritance)

다른 객체지향언어인 C++에서는 여러 조상으로부터 상속받는 것을 허용하지만 자바에서는 단일 상속만을 허용한다.

부모->자손1->자손2->자손3 O

부모1->자손1 && 부모2->자손1 X



1-5 Object클래스 - 모든 클래스의 조상

모든 클래스 상속계층도의 최상위에 있는 조상클래스이다.

컴파일러가 모든 클래스에 자동적으로 'extends Object'를 추가하여 Object클래스로부터 상속받도록 한다. 다만 이미 상속을 받는 클래스에는 추가되지 않으며, 조상의 조상을 거슬러 올라가다보면 최상위에 Object클래스가 나올 뿐이다.




Posted by Hearthole
,