본문 바로가기

JAVA/JAVA 기초

자바 기본형 참조형 클래스 관련

반응형

기본형

숫자값을 취급하는 리터렐에서는 언더스코어를 사용하여 구분표기를 할수 있다.(자바7이후)

@Test

public void longConvertTest() {

long amount = 123_456_789L;

System.out.println(amount);

}


확장변환(widening conversion) / 축소변환(narrowing conversion)

자바는 타입이 서로 일치하지 않는 경우에도 타입끼리 서로 호환성이 있으면 자동적으로 변환

short타입은 16비트의 정수 int 32bit 정수

short shortNum = 100;

int intNum = shortNum; //확장(short -> int)


int 타입의 값을 short 타입의 값으로 취급경우 short타입으로 나타낼수 있는 값의 범위를 넘을 경우

변활할수 없어서 컴파일 에러

명시적으로 지정함으로써 타입을 변환(캐스트)할 수 있다.

int intNum = 1;

short shortNum = intNum; //컴파일 에러


int intNum = 32767 + 1;

short shortNum = (short) intNum; //축소변환



참조형

변수나 메서드를 모은 틀이 클래스이다.

이 클래스라는 틀로부터 만든 실제 객체가 인스턴스다.

생성된 인스턴스를 사용하려면 그 인스턴스를 특정하는 정보(주소와 같은 것)을 알아 둘 필요가 있다.

그 정보를 참조(포인터)라고 부른다.

그리고 참조라는 값을 보관하는 타입을 참조형이라고 한다.


String 클래스


String name = new String("Eunyoo");

System.out.println(name.length());


name은 String형의 변수다. new 키우더를 사용하므로써 String 클래스로부터 문자열 "Eunyoo"을 값으로 갖는 String 클래스의 인스턴스를 생성

name에는 클래스 인스턴스로의 참조가 값으로 대입

이후로 변수 name을 이용하여 String 클래스의 메서드를 호출할 수 있다.

String 클래스는 자바 프로그램 안에서 비번하게 이용하는 클래스로 System.out.println(name);

실제로는 String 클래스의 인스턴스로 참조를 건네고 있을 뿐 값 그 자체를 건네고 있는건 아니다.

String 클래스로부터 값인 문자열을 추출해 표시하고 있기 때문에 결과로 "Eunyoo"가 표시되고 있다.


문자열 리터럴

클래스로부터 인스턴스를 생성하려면 new 키워드를 사용하는데 String 클래스의 경우는 문자열 리터럴를 사용해 간략하게 인스턴스를 생성한다.


String name ="Eunyoo";

System.out.println(name.length());



null 리터럴

참조형에 관련하는 리터럴로 문자열 리털럴 이외에 null 리터럴이 있다.

null 리터럴은 객체의 참조가 없는 상태를 나타내는 특수한 리터럴

참조형에 null이 들어 잇는 상태로는 메서드를 호출할수 없기 때문에 주의가 필요하다.

객체의 메서드를 호출할 때 참조형의 변수에 null이 들어갈 가능성이 있는 경우 null이 들어 있는지 체크한다.

null 체크라고 한다.


String nullStr = null;

if(nullStr != null)

System.out.println(nullStr.length());

else

System.out.println("nullStr은 null이다");



래퍼클래스

기본형은 객체가 아니라 단순히 값이며 그 자신은 메서드를 갖지 않는다.

기본형의 값에 대한 조작(문자열과 상호교환 등)이 필요하게 되는 상황이 많다.

그래서 자바는 기본형을 내포하여 해당 기본형의 값을 조작하는 기능을 마련한 "래퍼 클래스"를 제공한다.


byte / java.lang.Byte

short / java.lang.Short

int / java.lang.Integer

long / java.lang.Long

char / java.lang.Character

float / java.lang.Float

double / java.lang.Double

boolean / java.lang.Boolean


래퍼클래스의 상수

SIZE  / 비트수

BYTES / 바이트수(JAVA8)

MAX_VALUE / 최대값

MIN_VALUE / 최소값


System.out.println("Byte: { SIZE(bit) : " + Byte.SIZE

+", BYTES: " + Byte.BYTES

+", MIN: " + Byte.MIN_VALUE

+", MAX: " + Byte.MAX_VALUE

+ " }");


Byte: { SIZE(bit) : 8, BYTES: 1, MIN: -128, MAX: 127 }


래퍼클래스의 메서드

valueOf(기본현의 값) / 기본형으로부터 래퍼클래스의 객체로 변환

valueOf(String s) / 문자열로부터 래퍼클래스의 객체로 변환

valueOf(String s, int radix) / 진수를 지정해서 문자열로부터 래퍼 클래스의 객체로 변환

parseXxx(String s) /  문자열로부터 기본형의 값으로 변환

parseXxx(String s, int radix) / 진수를 지정해 문자열로부터 기본형의 값으로 변환

toString(기본형의 값) / 기본형에서 문자열로 변환

toString(기본형의 값, int radix) / 진수를 지정해 기본형에서 문자열로 변환



기본형에서 래퍼클래스로의 변환에는 생성자를 이용하는 방법도 있지만 valueOf 메서드를 사용하는 권한다.

생성자를 이용할 경우는 반드시 새로운 객체가 생성되지만 valueOf 메서드를 이용하는 경우 -127부터 128범위라면 사전에 생성된 객체를 이용할수 있기 때문에 객체를 생성하지 않아 메모리 소비하지 않는다.


래퍼클래스가 기본형과 다른점은 초기값이다.

int를 선언하는 경우 초기값은 0

Integer선언하는 경우 초기값은 null



이 때문에 0과 데이터가 없는 상태(빈 상태)를 구별하고 싶은 경우는 래퍼형을 준비할 필요가 있음을 알수 있다.

예) HTTP 통신으로 취득한 값이나 설정파일로부터 읽어들인 값을 보관할 경우 값을 취득할수 없는 경우가 있다.

그럴 때 레퍼형을 이용하고 있다면 값을 취득할 수 없을 경우 null, 값을 취득한 경우 그 값을 지정할 수 있다.

그러나 기본형을 이용하고 있으면 값을 취득할 수 없는 경우에는 0(초기값)이 되기 때문에 값이 지정되지 않아서 0인지 값으로 0이 지정된 것인지 구별할 수 없다.

통신이나 파일 등으로부터 읽어들인 변수를 래퍼형으로 선언할 것을 추천한다.

수치계산에 이용하는 변수는 기본형을 사용하는 것이 좋다.

null 체크 등이 불필요하며 대량의 계산이 필요한 경우에는 래퍼형에서 기본형으로의 변환에 걸리는 시간도 무시할수 없기 때문이다.



오토박싱 언박싱

기본형의 데이터와 참조형인 래퍼클래스의 객체는 타입이 다르므로 서로의 연산이나 대입은 기본적으로 할수 없다.

그러나 java 5.0부터는 기본형과 래퍼클래스 간의 자동변환이 실시되어 서로 간의 대입이나 연산이 가능하다.

기본형에서 래퍼클래스로 자동변환을 오토박싱

래퍼클래스에서 기본형으로 변환을 언박싱


int num = 10;

Integer numInt = 10; //컴파일시 Integer.valueOf(10)으로 자동변환(오토박싱)


Integer sum =- num + numInt; //numInt가 numInt.intValue()의 int로 자동변환(언박싱), 연산결과를 다시 오토박싱


자동변환에는 굳이 변환처리를 작성하지 않아도 된다는 장점


Integer num1 = new Integer(3);

Integer num2 = new Integer(3);


System.out.println(num1 == num2); //false

System.out.println(num1.equals(num2)); // true

 

오토박싱은 래퍼형의 valueOf 메서드를 사용하여 실시한다.

-128~127의 범위 값에는 사전에 생성된 객체가 이용되도록 되어 있다.

그 때무넹 -128~127의 값을 오토박싱한 객체는 항상 동일 객체가 된다.

그 범위 밖의값을 오토박싱한 경우는 서로 다른 객체가 된다.


Integer int1 = 127;

Integer int2 = 127;

System.out.println(int1 == int2); //true


Integer int1 = 128;

Integer int2 = 128;

System.out.println(int1 == int2); //false



이러한 동작 사양이나 단점을 이해하지 않을 채 래퍼 클래스나 자동변환을 남용하면 코드의 흐름속에서 어디가 기본형이고 래퍼인지 알수 없게 되어 버그의 원인


- 원칙적으로 오토박싱, 언박싱 이용하지 않고 명시적인 변환을 실시

- 파일이나 데이터페이스, HTTP 요청등을 유지하는 값은 래퍼 래퍼클래스를 사용한다.

- 수치 연산에 사용하는 변수는 기본형으로 한다.

- 코딩량의 감소에 효과적인 경우에 한하여 오토박싱, 언박싱을 이용한다.


접근제한자 (클래스)

public / 다른 모든 클래스로부터 참조가능

(지정없음) / 동일패키지 내의 클래스로부터 참조가능(패키지 프라이빗)


접근제한자 (필드, 메서드)

public / 다른 모든 클래스로부터 참조가능

protected / 자식 클래스 및 동일 패키지 내의 클래스로부터 참조가능

(지정없음) / 동일 패키지내의 클래스로부터 참조가능(패키지 프라이빗)

private / 자기 자신의 클래스 안에서만 액세스 가능(자식 클래스로부터 참조 불가능)


상속

클래스를 정의할때 특정 클래스를 베이스를 해서 해당 클래스를 확장하는 식으로 새로운 클래스를 정의

클래스를 상속하면 자식 클래스는 부모 클래스의 기능을 이용할 수 있다.


package com.eeswk.domain;


public class SuperClass {


public SuperClass() {

}

public void superMethod() {

}

}


package com.eeswk.domain;


public class SubClass extends SuperClass {


public SubClass() {

super();

}

public static void main(String... args) {

SubClass subClass = new SubClass();

subClass.superMethod(); //SuperClass의 메서드를 사용가능

}

}



SubClass() 생성자의 안에 있는 super는 부모 클래스를 가르키는 키워드로 super()로 부모클래스의 생성자를 호출하게 된다.

단 디폴트 생성자(인수가 없는 생성자)는 자동으로 호출되기 때문에 일반적으로 super()를 생략한다.

super.메서드명으로 부모 클래스의 메서드를 호출할 수 있다.

오버라이드하고 있는 않는(부모클래스에서만 존재하는) 메서드를 호출할 때 일반적으로 super를 생략한다.

오버라이드하고 있는 메서드의 부모 메서드를 호출하고 싶은 경우 super를 붙이면 된다.


@Override

public void superMethod() {

System.out.println("Override Method");

//super.superMethod();

}

public void subMethod() {

super.superMethod();

}

public static void main(String... args) {

SubClass subClass = new SubClass();

subClass.superMethod(); //SuperClass의 메서드를 사용가능

subClass.subMethod();

}


추상클래스

추상클래스는 상속될 것을 전제로 한 클래스이다.

클래스에 abstract 수식자를 지정함으로써 추상 클래스를 정의

추상 클래스는 공통적인 기능을 구현하는 등 클래스의 모형으로서 자주 이용된다.


추상클래스는 추상메서드라는 구현하지 않는 메서드를 정의

추상클래스를 상속한 서브 클래스측에서는 이 추상 메서드를 반드시 구현해야한다.

추상메서드는 추상 클래스의 다른 메서드로부터 호출할 수 있기 때문에 처리의 일부를 추상 메서드로 작성함으로써 추상클래스 측에서 처리 전체를 구현하고 상속한 자식 클래스에서 처리의 일부만을 구현하는 식으로 처리를 분담할 수 있다.


package com.eeswk.domain;


public abstract class AbstractItem {


protected String name;

public AbstractItem(String name){

this.name = name;

}

public abstract void print(String parentPath);

}



package com.eeswk.domain;


import java.io.File;


public class FileItem extends AbstractItem {

public FileItem(String name) {

super(name);

}


@Override

public void print(String parentPath) {

System.out.println(parentPath + File.separator + name);

}


}



package com.eeswk.domain;


import java.io.File;

import java.util.List;


public class DirectoryItem extends AbstractItem {


public List<AbstractItem> children;

public DirectoryItem(String name, List<AbstractItem> children) {

super(name);

this.children = children;

}

@Override

public void print(String parentPath) {

for(AbstractItem child : children) {

child.print(parentPath + File.separator + name);

}


}


}


추상메서드를 하나라도 갖는 클래스는 추상 클래스가 되므로 abstract의 지정이 필요하다.



인터페이스

구체적인 구현을 잘라내서 확장성을 높이기 위해 자바에는 객체의 동작(메서드)만을 규정하는 인터페이스


package com.eeswk.domain;


public interface Foo {

String say();

}


package com.eeswk.domain;


public class DefaultFoo implements Foo {


private String message;

public DefaultFoo(String message) {

this.message = message;

}

@Override

public String say() {

return message;

}

public static void main(String... args){

Foo foo = new DefaultFoo("Hello Foo!");

System.out.println(foo.say());

}


}


인터페이스에는 메서드뿐만 아니라 상수를 정의하는 것도 가능하다.


package com.eeswk.domain;


import org.springframework.scheduling.config.Task;


public interface TaskHandler {

public static final int TASK_TYPE_PRIVATE = 0;

public static final int TASK_TYPE_WORK = 1;

public boolean handle(Task task);

}


public interface TaskHandler {

int TASK_TYPE_PRIVATE = 0;

int TASK_TYPE_WORK = 1;

public boolean handle(Task task);

}


public static final도 생략 가능


익명클래스

이름이 없는 클래스로

클래스의 정의와 인스턴스화를 한번에 작성한다.


주로 인스턴스를 구현한 처리나 추상클래스를 상속한 처리를 국소적으로 사용하고 싶은 경우에 익명 클래스를 사용


package com.eeswk.domain;


public class AnonymousClass {


public static void main(String[] args) {

TaskHandler taskHandler = new TaskHandler() {

@Override

public boolean handle(Task task) {

return false;

}

};

Task myTask = new Task();

taskHandler.handle(myTask);

}


}


TaskHandler의 구현 클래스는 익명 클래스를 사용하지 않고 일반적인(이름 있는)클래스를 정의하여 인스턴스를 생성해도 동일하다.

다만 클래스를 특정한 곳에서만 사용하는 경우 이름이 있는 클래스를 정의하는 것보다는 익명 클래스를 사용하는 편이 보다 코드를 간결하게 해준다는 장점

자바 8에서 도입된 람다식은 익명 클래스와 밀접한 관련성 있어 자주 사용되고 있다.



nested class

클래스 안에 다시 클래스를 정의할 수 있는데 이것을 nested class라고 한다.

필드로 정의하는 static 멤버 클래스와 nostatic 멤버 클래스

메서드 안에 정의하는 익명 클래스와 로컬 클래스


nested class는 일시적으로 사용하고 싶은 클래스의 정의 등에서 편리하게 이용할수 있는 클래스다.

출처: 자바 마스터북


반응형

'JAVA > JAVA 기초' 카테고리의 다른 글

예외 관련  (0) 2018.10.21
자바 컬렉션관련  (0) 2018.10.13
자바 배열관련  (0) 2018.10.13
자바 타입관련  (0) 2018.10.13
자바 기초 작성법  (0) 2018.10.12