변수와 메서드

생성일
속성 
태그 

클래스가 가질수 있는 변수에대해서 알아보자 😃

클래스가 가질 수 있는 변수의 종류

클래스가 가질 수 있는 변수는 총 3개로 나뉠수가 있다,

  • 멤버변수
    • 클래스 변수 static이 붙음
    • 인스턴스 변수 static 붙지 않음
  • 지역변수 → 메서드 안에 있는 변수

이들은 선언 위치에 따라서 역할이 구분된다. 그러므로 어떤 변수인지 파악하기 위해서는

선언된 위치를 눈여겨 보면 좋다.

변수의 종류와 특징

변수의 종류 선언 위치 생성시기
클래스변수 클래스 영역 클래스가 메모리에 올라갈 때
인스턴스 변수 클래스 영역 인스턴스가 생성되었을 때
지역 변수 클래스 영역 이외의 영역 변수 선언문이 수행되었을 때

이중 지역변수는 자주들어봤을 텐데 클래스 변수와 인스턴스 변수는 처음들었을 것이다.

이들의 특징은 다음과 같다.

인스턴스변수

인스턴스 변수는 클래스의 인스턴스를 생성할 때 만들어진다.

인스턴스는 독립적인 저장공간을 가지므로 서로 다른 값을 가질 수 있다.

클래스 변수

클래스 변수는 인스턴스 변수안에 static을 붙인것 이다.

static을 사용했기 때문에 공통된 저장공간을 공유하게 된다.

각 인스턴스가 생성되어도 이값은 각 인스턴스마다 같다.

또한, 인스턴스를 생성하지 않아도 클래스이름.클래스변수와 같이 .을 사용하여 접근 할 수 있다.

결국 static이 붙었기 때문에 전역변수 취급을 받는다.

메서드

메서드(method)는 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것이다.

메서드를 사용하는 이유

  1. 높은 재사용성메서드는 한번 만들어 놓으면 몇번이든 재호출 할 수 있으며 다른프로그램에서도 사용할 수 있다.
  2. 중복된 코드의 제거프로그램을 구성하면 반복되는 코드가 있기 마련이다. 이러한 코드들을 메서드를 만들어 재사용 한다면 코드의 양이 줄어들어 오류가 발생할 가능성이 줄어드는 이점이 있다.
  3. 프로그램의 구조화메서드를 만들어 main 메서드 안에서 모든 문장을 넣는 식으로 프로그램을 작성할 필요가 없다.
  4. 각각의 작업단위를 쪼개서 필요한 클래스를 만들어 그 클래스에 여러 개의 메서드를 담아서 프로그램의 구조를 단순화 시킨다면 나중에 문제가 있을 때 쉽게 찾아 문제를 해결 할 수 있는 장점이 있다.

메서드의 선언

메서드는 선언부(header)구현부(body)로 나뉘어져 있다. 사실 함수를 선언하는 것과 비슷한다.

반환타입 매서드이름 (매개변수){
    //매서드의 코드
}

//예시
int sum (int a, int b){
    return a + b;
}

메서드에서 는 반환타입이 void가 아닌 이상 항상 값을 return해줘야 한다.

메서드에서 반환된 값은 반환 타입과 일치하거나 혹은 자동 형변환을 메서드가 알아서 해준다.

또한, 반환값은 반드시 하나인것을 명시해야 한다.

그리고 메서드는 return을 하면 항상 종료된다 중간에 다른코드가 있거나 밑에 다른코드가 있더라도

값을 반환하면 종료가 된다.

메서드의 호출

메서드는 호출되면 스택과 같은 구조로 쌓인다.

이를 자세히 알기 위해서는 JVM의 메모리 구조에대해서 알아야한다

JVM은 프로램이 실행 되면 프로그램을 수행하는데 필요한 메모리를 할당받는다.

이러한 메모리들은 용도에 따라 달라진다. 보통 다음과 같은 구조에 메모리를 할당한다.

  1. 메서드 영역메서드 영역에서는 클래스파일을 읽고 클래스 데이터를 이곳에 저장한다. 또한, 클래스 변수도 함께 저장한다
  2. 힙은 보통 인스턴스가 생성되는 공간이다 보통의 인스턴스 변수들이 생성된다.
  3. 보통 Stack을 뺀 모든 변수들이 이곳에서 생성이 된다.
  4. Call Stack(호출스택)호출스택은 메서드 작업에 필요한 메모리 공간을 제공한다. 메서드가 호출 될 떄 마다 메서드를 위한 메모리 공간이 할당되며 이러한 메서드의 지역변수연산의 중간결과등을 저장한다.호출스택의 제일위에 있는 메서드는 자신을 실행시킨 메서드이다. 바로 아래에 있는 메서드는 위의 메서드를 호출한 메서드이다.
  5. Call stack 말처럼 stack처럼 쌓이면서 저장되고 작업을 마치면 stack 위에 있던 메서드가 사용한 공간이 반환되며 비워진다.

Stack을 배웠다면 이해하기가 쉬울 것이다.

매개변수의 특징

보통 매개변수는 지역변수취급을 당한다고 생각하면 편하다.

매개변수가 들어와서 작업을 행했을 때 값이 바뀌어도 원래 호출하였던 매개변수의 값은 변하지 않는다.

C/C++ 언어에서는 포인터를 사용하여 Call by Reference를 사용하여 바꿀 수 있지만 자바에서는 포인터가 존재하지 않는다.

하지만 자바에서도 참조형 매개변수가 있다. 이는 매개변수의 타입이 참조형인 매개변수를 뜻한다.

이는 값이 변하면 원본에 영향을 미칠 수 있다.

class Book {int pageNumber;}

public static void main(String[] args){
    Book book = new Book();
  book.pageNumber = 1;
  System.out.printf("pageNumber = %d",book.pageNumber); // 1출력
  nextPage(book);
  System.out.printf("pageNumber = %d",book.pageNumber); // 2출력 -> 값이 변함
}

static void nextPage(Book book){
    book.pageNumber += 1;
}

또한, 이뿐만이 아니라 배열을 매개변수로 이용해도 똑같은 결과를 얻을 수 있다.

그렇기 때문에 밑의 예제와 같이 결과값을 저장하고 싶을때 배열을 매개변수로 사용 할 수 있다.

void add (int a, int b, int[] result){
    result[0] = a + b;
}

참조형의 반환

이뿐만이 아니라 참조형은 반환타입에서도 특별하게 사용된다,

보통 return을 하면 값을 반환하는데 참조형을 반환하면 특별하게 주소를 반환한다,

그렇기 때문에 호출결과를 저장하는 타입의 일치가 필요하다.

재귀 호출

보통 코딩테스트나 백트레킹 기술에 사용되는 기술이다. 영어로는 Recursive call이라 한다.

이는 자기 자신을 메소드에서 호출하는 것이다.

위에서 메서드는 Stack처럼 쌓인다. 라고하였다 이러한 Stack 을 이용하여 쉽게 유추 할 수 있다.

재귀호출을 사용할 때에는 반드시 종료조건을 명시 해줘야한다.

단순히 반복문을 사용해도 되는데 재귀호출을 사용하는 이유는

간혹 몇겹의 반복문을 작성하는 것 보다 재귀호출이 비효율적이더라도 쉽게 알아보기 편하게 작성할 수 있기 떄문이다.

예시로 펙토리얼피보나치 가 있다.

클래스 메서드 & 인스턴스 메서드

변수에도 클래스 변수, 인스턴스 변수가 있듯이 함수에도 존재한다.

변수와 마찬가지로 static이 붙으면 클래스메서드 붙지 않으면 인스턴스 메서드이다.

인스턴스 메서드는 메서드 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드 이다.

클래스 메서드는 메서드 중 인스턴스와 관계없는 메서드를 클래스 메서드라고 정의한다.

하지만 인스턴스를 사용하지 않는다고 해서 반드시 클래스 메서드를 사용해라라는 것은 아니다.

하지만 사용하는 것을 권장한다 왜냐하면 인스턴스를 생성할 때마다 static이 없으면 메서드를 찾는 과정이 추가적으로 필요하기 때문에 static 유무에 시간이 더걸리거나 덜 걸린다.

또한, 클래스 메서드에는 중요한 조건이 있는데 클래스 메서드는 인스턴스 변수를 사용할 수 없다.

단순히 생각하면 쉽다. 클래스 메서드static이라 인스턴스 호출전에 사용이 가능한데

인스턴스 변수는 인스턴스가 생성되지 않으면 존재하지 않을 수도 있기 때문이다.

오버로딩

오버로딩은 같은 클래스 내에 같은 이름의 메서드를 여러 개 정의 하는 것을 말한다.

오버로딩을 하기 위해서는 다음과 같은 조건을 만족해야한다.

  1. 매서드 이름이 같아야한다.
  2. 매개변수의 개수 또는 타입이 달라야 한다.

또한, 주의 해야할 점이 매개변수의 개수 또는 타입이 달라야하는 거지 리턴 타입만 다른 경우는

포함 되지 않는다.

오버로딩은 내가 원하는 같은 동작을 매개변수가 달라져도 똑같이 구현이 가능하다는 장점이 있다.

다음과 같은 예를 보자.

int sum(int a, int b){
    return a+b;
}

float sum(float a, float b){
    return a+b;
}

이런식으로 나는 실수와 정수를 똑같은 sum()이라는 매서드를 통해 구별없이 계산하고 싶다.

만약, 오버로딩이 없다면 이를 sumInt() 라는 메서드와 sumFlaot()라는 각기의 메서드로 만들어야 할 것이다.

이뿐 만이 아니라 다른 타입을 구현하고 싶을 떄도 타입의 개수에 따라 엄청나게 같은기능을 하는 이름이 다른 메서드들이 늘어날 것이다.

이는 너무 비효율적이다.

가변인자 & 오버로딩

기존에는 내가 매개변수를 100개를 생성하려면 일일히 100개를 다 적어야했다.

이는 너무 비효율적이다. 이를 해결하기 위해서 JDK 1.5버전부터 매개변수를 동적으로 지정할 수 있게 되었다. 이를 가변인자라고 한다.

예시로 문자열을 합쳐주는 메서드를 만든다고 가정한다. 매개변수가 2개일 경우는 다음과 같다.

String concat(String str1, String str) {};

하지만 만약 매개변수의 갯수가 4개만 되더라도 많이 복잡해진다.

String concat(String str1, String str2, String str3, String str4) {};

이럴 때 가변인자를 사용하면 매개변수를 한번만 써서 구현이 가능하다.

String concat(String... str) {};

이렇게 가변인자로 구현을 한다면 매개변수의 갯수에 구애 받지 않게 할 수 있다.

또한, 배열을 넘겨줄수도 있다.

가변인자를 사용할 때 주의 할점이 있는데 항상 가변 인자는 매개변수의 에 위치해야한다.

String concat(String hello, String... str) {}; -> (o)

String concat(String... str, String hello) {}; -> (x) 

또한, 배열을 매개변수로 넣어준다고 하였는데 허용되지 않는 것도 있다.

String concat (String... str) {}; 

concat(new String[] { "Hello", "world"} -> (o)

concat({"Hello","World"}) -> (X)

제일 밑과 같이 저런 형식으로는 사용이 불가능 하다 배열을 생성하고 넣어주는 것은 괜찮다.

또한, 가변인자를 사용한 메서드의 오버로딩매개변수의 변화를 쉽게 컴파일러가 못알기 때문에

가변인자를 사용했으면 오버로딩을 사용하지 않는 것이 좋다.

이렇게 생각하면 결국 배열을 매개변수로 메서드를 생성하는 것도 가능하지 않을까? 하는 의문점이 들 수있다.

물론 맞는 소리지만 배열을 매개변수로 매서드를 생성했을 때는 반드시 인자를 지정해 줘야한다 이러한 추가적인 불편함이 있기 때문에 가변인자를 사용한다.

Reference

  • 자바의 정석

'Java > Java' 카테고리의 다른 글

[Java/Study] 오버라이드  (0) 2021.09.07
[Java/Study] 상속  (0) 2021.09.07
[Java/Study] 생성자  (0) 2021.09.07
[Java/Study] 클래스와 객체  (0) 2021.09.06
[Java/Study] 자료형  (1) 2021.09.05

클래스와 객체

클래스객체를 정의해놓은 것이다 클래스를 사용하여 객체를 만든다.

보통 클래스는 못들어봤어도 객체라는 단어에는 익숙할 것이다.

객체는 말 그대로 '실제로 존재하는 것' 사물이 될수도 있고 혹은 무형의 어떤것이 될 수 도 있다.

이러한 객체는 클래스를 사용하여 만든다.

예시를 들어보자 우리가 사용하는 책이라는 것은 유형의(실제로 존재하는) 객체이다.

이를 만들기위해서는 책을 만드는 기계가 필요할 것이다. 이게 바로 클래스라는 존재이다.

객체지향이론 관점에서는 클래스로부터 객체를 만드는 과정을 클래스의 인스턴스화 라고 한다.

그리고 클래스로부터 만들어진 객체인스턴스라 한다.

즉, 객체는 책 그것을 만들기 위해 사용되는 것은 클래스는 책을 만드는기계이고

클래스(책을 만드는기계)로부터 만들어진 객체(책)은 인스턴스라하고, 이 과정을 인스턴스화라하고한다.

객체의 구성

객체는 두가지로 구성된다

  • 속성(property): 멤버변수, 특성, 필드...
  • 기능(function) : 메서드 , 함수 ...

속성은 예시로 들어서 설명하자면 객체를 구성하는 요소라고도 볼 수 있다.

예를들어서 책을 구성하는 종이 일 수 도있고, 책을 보호하는 북커버 이러한 것들이 속성이다

기능은 말 그대로 기능이다. 책을 예시로 들면 책장을 넘기는 것, 혹은 책갈피를 넣는것 이런것들이 된다.

// 예시

//속성-> 맴버변수(variable)
int pageNumber; // 총 몇 페이지인지?

//기능 -> 매서드
nextPage(); // 다음장으로 넘기는 매서드

//클래스의 예시

class Book {
    // 속성 -> 맴버변수들
    int pageNumber; // 페이지의 총수
    int nowPage; // 현재 페이지

    // 기능 -> 매서드
    void open(); // 책을 열기
    void close(); // 책을 닫기
    void nextPage(); // 다음장으로
}

인스턴스 생성 방법

위에처럼 class Book 즉 Book 이라는 클래스를 만든것은 기계를 만든것과 같다.

사용하기 위해서는 이책이 무엇인지 인스턴스화를 진행해야한다. 인스턴스화를 하는 방법은 다음과 같다.

클래스명 변수명 = new 클래스명();

Book onepice = new Book(); 

이러한 과정을 하면 Book클래스의 인스턴스가 메모리의 빈 공간에 생성이된다.

이러한 것들은 각 자료형에 해당하는 기본값으로 초기화 된다.

혹은 생성자를 만들어서 내가 원하는 값으로 초기화하거나 할 수도 있다.

빈공간이 생성되면서 onepice라는 참조변수에 생성된 객체의 주소값이 전달이 된다.

객체의 멤버변수나 매소드에 접근하기 위해서는 이제 참조변수.맴버변수처럼 .을 사용해야한다.

주의할점으로 같은 클래스로 인스턴스를 생성하면 값이 같은거라고 생각하는데 차이가 있다.

// book1 생성
Book book1 = new Book();

// book2 생성
Book book2 = new Book(); 

이때 book1과 book2의 pageNumber은 각각 다를 수 밖에 없다

왜냐하면 new를 통해서 새로운 메모리에 두번 생성했기 때문에

각각의 맴버변수는 다른 주소를 가지고 있기 때문이다.

객체 배열

많은 수의 객체를 다뤄야할 때 객체를 배열로 다룰수도 있다

// book1, book2, book3 생성
Book book1, book2, book3; 

// 배열을 통해 책 3권생성
Book[] bookArr = new Book[3];

이와같이 여러가지 객체가 많아진다면 생성하기가 힘들다.

이러한 객체를 배열을 통해서 생성하고 다룰수 있다.,

이러한 객체를 배열에 저장할때는 주의할 점이 있다.

사실 객체를 생성하였지만 객체를 생성한것이 아니라 객체 배열을 생성한 것이다

그렇기 때문에 각각의 bookArr[0], bookArr[1], bookArr[2]에 대해서는 객체가 생성되지 않았다.

그렇기 때문에 객체를 생성해서 배열의 각 요소에 저장해주는 과정을 더해줘야 한다.

//객체 배열 생성
Book[] bookArr = new Book[3];

// 방법 1
bookArr[0] = new Book();
bookArr[1] = new Book();
bookArr[2] = new Book();

// 방법 2
Book[] bookArr = {new Book(), new Book(), new Book()};

// 방법 3
for(int i = 0 ;i < bookArr.length; i++){
    bookArr[i] = new Book();
}

Reference

자바의 정석

'Java > Java' 카테고리의 다른 글

[Java/Study] 오버라이드  (0) 2021.09.07
[Java/Study] 상속  (0) 2021.09.07
[Java/Study] 생성자  (0) 2021.09.07
[Java/Study] 변수와 메서드  (0) 2021.09.07
[Java/Study] 자료형  (1) 2021.09.05

Chapter2

생성일: 2021년 9월 5일 오전 11:47

변수

변수란 단 하나의 값을 저장할 수 있는 메모리 공간.

변수의 초기화

변수를 사용하기 전에는 항상 변수를 초기화 해주어야 한다. (클래스 변수인스턴스 변수는 초기화를 생략할 수 있다.)

변수의 명명규칙

필수 규칙

  • 대소문자가 구분되며 길이의 제한이 없다. (True ≠ true) ac ≠ AC
  • 예약어(ex. if)를 사용할 수 없다
  • 숫자로 시작해서는 안된다
  • 특수문자는 _$ 만 허용한다.

권장 규칙

  • 클래스 이름의 첫 글자는 항상 대문자로 한다
  • 여러 단어로 이루어진 이름은 단어의 첫 글자를 대문자로 한다.
    • 카멜 케이스 : lastIndexOf (첫글자만 소문자 이후 단어마다 대문자로 시작)
    • 스네이크 케이스: last_index_of (단어마다 _를 사용)
    • 파스칼 케이스: LastIndexOf (모든 단어의 시작이 대문자)
  • 상수의 이름은 모두 대문자로 한다. 여러단어일 경우는 _를 사용하여 구분한다. (MAX_NUMBER)
  • 패키지 이름은 소문자로 한다

변수의 타입

변수의 타입은 크게 2가지로 나뉜다.

  • 기본형(primitive type)
    • 논리형(boolean), 문자형(char), 정수형(byte,short,int,long), 실수형(float,double) 계산을 위한 실제 값을 저장
  • 참조형(reference type)
    • 객체의 주소를 저장한다. 기본형을 제외한 나머지 타입 (변수 타입이 클래스)
    • 참조변수는 null 또는 객체의 주소를 값으로 가진다.
// 참조형의 선언
**클래스이름** 변수이름; -> 주소할당이전

// 참조형의 초기화
Date today = new Date(); // Date객체 생성후 주소를 today에 저장

기본형

상수(Constant) & 리터럴(literal)

상수란?

변수와 마찬가지로 '값을 저장할 수 있는 공간' 이지만 한번 값을 저장하면 다른 값으로 변경 불가능

상수를 사용하기 위해서는 final을 붙여주면 된다

final int MAX_SPEED = 10; 

MAX_SPEED = 11; -> (x)

상수를 사용할 때는 선언과 동시에 초기화를 항상 해줘야한다.

또한, 상수의 이름은 모두 대문자로 하는 것이 암묵적 관례이다.

리터럴(literal)이란?

그 자체로 값을 의미하는 것이다.

기본적으로 상수는 숫자 (1,221,123) 또는 문자 ('a','B')같이 그 자체로 값인 것을 의미 하는데 ****

프로그래밍에서의 상수는 따로 의미가 있기 때문에 리터럴이라는 단어를 사용하여 기본 상수의 의미를 구별하기로 하였다.

리터럴의 접미사

리터럴을 사용할 때는 항상 접미사를 붙여줘야한다.

// 정수형 접미사 사용 예제
long number = 10; // (x) -> 실행이 되긴함 권장 x
Long number = 10; // (x) -> 실행이 안됨
long number = 10L; // (o)
long number = 10_000L; // (o) JDK 1.7부터

//실수형 접미사 사용 예제
float pi = 3.14; // (x) 실수형의 기본 접미사는 double의 D이다
float pi = 3.14f; // (o)
float pu = 3.14F; // (o)

double rate = 1.618; // (o)
double rate = 1.168D; // (o)
double rate = 1.168d; // (o)

접미사 예제

타입이 불일치 할때

기본적으로 리터럴의 타입은 변수의 타입과 일치하는 것이 보통이지만 타입이 달라도 저장범위가 넓은 타입에 좁은 타입의 값을 저장하는 것은 허용이 된다.

// 모두 큰 범위
int i = 'A'; // 65가 저장
long l = 123; 
double d = 3.14f

문자 리터럴 , 문자열 리터럴

  • 문자 리터럴
    • 작은 따옴표 (``)로 문자 하나를 감싼 것
    • 무조건 작은 따옴표 안에 적어도 하나의 문자를 넣어야한다
  • 문자열 리터럴
    • 큰 따옴표 ("")로 두 문자 이상 감싼것
    • 큰 따옴표 안에 문자가 없어도 된다
String str = ""; // 내용이 없는 빈 문자열
char ch = ''; // (x) 적어도 하나의 문자가 있어야한다
char ch = ' '; // 공백이 있기 때문에 (o)

String의 클래스 선언

String은 클래스 입으로 객체를 생성 할 때 new를 사용 해야하지만 그냥 할당도 특별히 허용된다

String name = new String("java"); 뿐만아닌 String name = "java" 도 허용한다.

문자열의 덧셈

문자열은 기본적으로 기본형과 참조형의 구별 없이 어떤 타입의 변수도 문자열과 덧셈 연산을 수행하면 문자열이 된다.

그렇기 때문에 문자열로 형변환을 시켜줄 때 ""만 더해줘도 문자열이 된다.

문자열 + Any Type = 문자열

// 예시
String name = "java";
String str = name + 0.8; // "java0.8"

int temp = 10;

Printf()

자바에서의 출력은 C언어와 비슷하다.

System.out.printf();를 사용하여 출력을 진행한다

지시자

Printf 예제

// 지시자 사용 예제
int age = 20;
System.out.printf("age:%d", age);

// 간격 맞추는법
System.out.printf("[%5d]",age); // [   20]
System.out.printf("[%05d]",age); // [00020]
System.out.printf("[%-5d]",age); //[20   ]

화면에서 입력받기

C언어에서 scanf를 사용하는것과 같이 자바에는 Scanner라는 객체가 있다.

사용하기 위해서는 import java.util.*; 를 import해야한다

그 후 Scanner 객체를 생성하고 nextLine()매소드를 호출하면 받을 수 있다.

// 사용 예제
import java.util.*; 
// 또는
import java.util.Scanner;

Scanner scanner = new Scanner(System.in); // 객체생성

String input = scanner.nextLine(); // input에 입력받는 내용 저장 문자열로 저장
int num = Integer.parseInt(input); // 입력받은 내용을 num에 int 타입으로 변환
// 숫자만 입력했을때 변환가능

//입력받자마자 변환 없이 정수로 받는법
int num = scanner.nextInt();

//입력 받자마자 실수로 받는법
float num = scanner.nextFloat();

//공백으로 받는법
String num = scanner.next(); 
int num = scanner.next(); // (x)반환형이다름

nextInt()nextFloat()매서드를 사용해 입력을 받으면 연속적인 값을 얻기 힘들기 때문에

nextLine()을 사용해서 받고 변환하여 사용하는 것을 책에서는 권장하고 있다.

진법 변환

  • 2의보수법을 사용하여 진법 변환을 한다.
  • 실수의 진법 변환
    • 10진 소수에 2를 곱한다
    • 위의 결과에서 소수부만 가져와서 다시 2를 소수부가 0이 될때까지 곱한다.
    • 나온 결과에서 정수부만 위에서 아래로 순서대로 적고 0.을 붙인다.
0.625를 변환

0.625 *2 = 1.25
0.25 * 2 = 0.5
0.5 * 2 = 1.0

0.101이 된다.

바이트 와 비트 와 워드

  • 8bit를 1Byte라 한다.
  • 1bit는 한자리의 2진수를 나타낸다.
  • 워드는 Cpu가 한번에 처리 할 수있는 데이터의 크기를 의미한다.
  • 32비트 컴퓨터의 워드는 4바이트이다.

문자형에서 유니코드 사용법

// 3 문장 다 '가'를 나타낸다.
char hch = '가';
char hch = 0xAC00;
char hch = '\uAc00';

// 특수문자 다룰 때는 c언어와 같다

// 2 문장은 같다
char ch = 'A';
char ch = 65;

오버플로우

  • 타입이 표현할 수 있는 값의 범위를 넘어서면 Overflow가 발생하면 제일 낮은값이 나온다.
  • 예를들어 2진수 0000에서 1을 뺴면 1111이 된다. 2의보수법으로 고쳐 표현하면 제일 낮은 값이 나온다.
  • 최대값 + 1 → 최소값 / 최소값 - 1 → 최대값

실수형에서의 오버플로우

  • 실수형은 저장할 수 있는 범위를 넘어나면 오버플로우가 발생하는데 정수형과 달리 변수의 값이 무한대가 된다.
  • 또한 언더플로우가 정수형과 달리 존재한다. → 자바에서 언더플로우 C언어랑
  • 실수형으로 표현할 수 없는 아주 작은 값을 넣었을 때의 변수의 값은 0이 된다.
  • float7자리 까지 double15자리 까지 표현이 가능하다.

실수형의 값 저장 방식

실수형은 값을 저장하기 위해서 부동소수점형태로 값을 저장한다.

부동소수점은 부호지수가수로 이루어져있다.

  • 부호
    • 1 bit를 차지하고 0이면 양수, 1이면 음수를 나타낸다
  • 지수
    • 부호가 있는 정수라고 생각하면 된다. 지수의 범위는 10의 n승 할때 제곱을 의미한다
    • flaot는 -127128까지 double은 -10231024까지 나타낸다.
  • 가수
    • 실제 값을 저장하는 부분으로 정밀도를 저장할 수 있다.
    • float는 2진수 23자리를 저장할 수 있다 = 약 7자리 (10진수로 고쳤을때)
    • double은 2진수 52자리를 저장할 수 있다. 약 15자리 (10진수로 고쳤을 때)

부동소숫점의 오차

  • 부동소수점은 기본적으로 2진수 이기 때문에 오차가 발생 할 수있다.
  • 파이 같은 무한소수를 정확하게 나타낼 수 없다.
  • 또는 예를들면 float같은 경우 7자리 수까지 밖에 나타내지 못하는데 7자리를 넘어가는 유한소수 일 경우에 오차가 발생 할 수 있다.

형변환(casting) 이란?

  • 형변환은 변수 또는 상수의 타입을 다른 타입으로 변환하는 것이다.

형변환을 하기 위해서는 변수나 리터럴 앞에 변환하고자 하는 타입을 괄호화 함께 붙여주면 명시적 형변환이 가능하다

double d = 85.4;
int score = (int)d; // 명시적 형변환

// 2진 정수로 변환한 문자열 얻는 법
Integer.toBinaryString(int i);

// 상수를 보다 작은 타입으로 변환 했을 때
double d = 1.0e100;
float f = (float)d; // INFINITY가 출력된다

double d = 1.e-50;
float f = (float)d; // 0.0이 출력된다.

// 실수형과 정수형의 변환
float f = 1.666;
int i = (int)f; // 1 **반올림이 되지 않는다**

자동형변환

서로 다른 타입간의 대입이나 연산을 할 때, 형변환으로 타입을 이치시키는 것이 원칙이지만 편의상 형변환을 생략할 수 있다. 이때 컴파일러가 이를 자동적으로 형변환 해주는 것을 자동형변환 이라고 한다.

자동 형변환은 기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환 한다. 즉 표현 범위가 좁은 타입에서 넓은 타입으로 형변환이 된다.

int i = 3;
double d = 1.0 + i; // i 가 3.0으로 자동형변환 된다. 

Reference

자바의 정석

'Java > Java' 카테고리의 다른 글

[Java/Study] 오버라이드  (0) 2021.09.07
[Java/Study] 상속  (0) 2021.09.07
[Java/Study] 생성자  (0) 2021.09.07
[Java/Study] 변수와 메서드  (0) 2021.09.07
[Java/Study] 클래스와 객체  (0) 2021.09.06

+ Recent posts