Java - Memory / 래퍼런스 타입 String 메서드

김지원·2022년 7월 22일
0

JAVA 총 정리

목록 보기
2/11

Memory

new : 참조타입의 변수를 새로 객체화 하기 위해서 사용하는 키워드

  • textA"Hello"textB"Hello" 는 내용이 같다.

정수의 비교는 같다 라고 출력이 되었고
동일한 내용의 문자열 두개의 비교는 다르다 라고 출력이 되었다.

  • new String : 객체화를 하지 않으니 같다 라고 나온다.

변수를 선언하면 그 변수는 변수가 가르키는 메모리 주소값을 가지고 다닌다.

int numA = 5; : @0x00을 준 후 @0x00에 5라는 값을 집어넣는다.
int numB = 5; : @0x01 준 후 @0x01에 5라는 값을 집어넣는다.

if ( numA == numB ) { ... }
: @0x00이 @0x01과 같은지에 대한 여부를 물어보는 것이다.
@0x00에 있는 값을 가져오면 5가나오고 @0x01도 5가 나온다.
이 둘을 비교하면 같다. => true가 나온다.


STACK 메모리(영역)

변수를 선언헀을때 변수의 값이 들어가는 곳을 stack메모리(영역)이라고 한다.

String textA = new String("Hello"); : 0x02
hello가 직접들어가는 것이 아닌 아래의 칸에 순차적으로 Hello를 집어넣는다.

Stack에는 1x00~ 1x04까지의 메모리 주소를 가진다.
즉 , Stack에서 1x00~ 1x04까지에 대한것을 쳐다보고 있다.

String textB = new String("Hello"); : 0x03
new 로 객체화를 햇으니 새로은 hello가 만들어진다.
0x03은 0x05 ~ 0x09 까지의 값을 가지게 된다.

if(textA == textB) { ... } 이렇게 물어봤다는건
0x02 == 0x03 을 물어본거고
1x00~ 1x041x05~ 1x09 가 같냐고 묻는거랑 똑같다.
메모리 주소 값 그 자체가 같냐고 물어보는거랑 같다. 완전 다르다!
그래서 두개의 비교값이 다르다고 출력이 되는 것이다.


HEAP 메모리 영역

그런데 int는 stack에 값이 바로들어오고 string은 왜 heap에 가서 저장이 되고 stack에는 메모리 값만 저장이 될까?
일종의 규칙이다.

기초타입은 그 값이 스택 영역에 바로 저장됨으로 동등(==)등의 연산을 하여도 무관하다.

참조타입은 그 값이 힙 영역에 저장되고, 스택에는 힙이 가지는 주소값을 가짐으로 동등(==) 등의 연산을 하면 안된다.

String textA = "Hello";String textB = "Hello"; 비교를 했을시에 같다라고 한다.
다른 변수지만 heap영역 내의 동일한 주소를 (같은 곳을 쳐다본다.) 가르키고 있음으로 1x00~1x041x00~1x04는 같기 때문에 같다라는 결과가 출력이 된다.
문자열만 그렇다! 그런데 문자열을 명시적으로 객체화 할 일은 잘 없다.

동일한 내용을 가지는 문자열을 만들면 힙 영역 내의 이미 존재하는 값에 대한 주소를 가지는 스택이 생긴다. 단, 명시적으로 객체화 (new)하면 이러한 '메모리 아끼기' 행동을 하지 않는다.

  • 이만큼을 메서드로 빼서 메인에서 호출을 하고싶은데 왜 안될까?
  • Non-static method 'compareStrings()' cannot be referenced from a static context
    정적인 메서드에서 비정적 메서드를 참조할 수 없다고 한다.

어떠한 클래스가 가지는 비정적인 것을 호출을 하려면 그 클래스를 객체화해야한다.
=> Memory를 객체화해야한다.

비정적인 것은 우리가 만들어주기 전까진 메모리에 올라가있지 못해서 마음대로 호출을 할 수 없다.

참조타입은 값이 heap영역에 저장이 되고 stack은 heap이 가지는 주소값을 가진다.

  • 멤버변수도 str도 그렇고 메서드compareStrings 와 같은 비정적인 것들을 가지는 메서드가 자체가 객체화가 되지않으면 이 세상에 존재하지 않는다.


compareStrings()메서드가 {} 종료가 되어서 선언한 textA,B가 남겨지게 되었다.
textA,B는 어디에서도 접근할 수 없으며 어디서도 사용할 수 없는 상태이다.
단지 stack에 남아있을 뿐인데 그것은 메모리 낭비이다.
Java에서는 GC가 지워준다.

GC : Garbage Collecotor

: 더 이상 사용될 수 없는 변수를 알아서 정리해 메모리를 확보해줌.
연결점이 유실된 변수가 유실된 채 일정시간이 지난채 방치가 되면 지나가면서 슥 지워준다. 메모리를 효과적으로 아낀다.

GC는 프로그램이 실행되는데 가상의 한경을 필요로하는 Java(등) 언어의 특징이다.
프로그램이 돌아가는데 GC가 이 안에있으면 안된다.
GC는 독립된 채로 전지적인 시점 3인칭으로 쳐다보게 된다.
어느 메서드에 어느 변수가 사용되지 못하는지 파악 후 삭제해준다.
GV는 JVM에 존재한다. JAVA도 GC도 JVM안에서 실행이 된다.

 | GC  | JAVA(PROGRAM) |
------------------------
		  JVM

void 일 때 -> 반환타입이 없을 때 return; 을 적어주면 그 자리에서 메서드 종료가 된다.(중괄호 자체가 멈추는게 아니라 메인메서드가 종료 되는 것이다)


래퍼런스 타입 String 메서드

"Hello World!"는 String타입의 객체이다.

문자열 합치기(String Concatenation)

: 문자열과 문자열 혹은 문자열이 아닌 다른 타입의 변수와 더하여(+) 이어 붙이는 것.

  • 문자열 합치기(+)는 과거 특정 JDK 버전 이후 부터 속도 문제가 해결되어 내부적으로 String.concat() 과 동일한 방식으로 작동한다. ( 과거에는 Recurrence(회귀)로 인해 속도 이슈가 있었다. )

  • 이 때 가능하다면 다른 타입인 것이 문자열로 변하기 때문에 가령 문자열과 숫자를 더한다면 숫자가 문자열로 변함으로 실제 연산이 발생하는 것이 아니라 둘다 "5"라는 문자열로 작동을 하고, 이가 붙여져 "55"가 됨.

  • 그렇기 때문에 이렇게 적어도 오류가 발생하지 않는다. 5출력!

charAt

: 호출 대상이되는 문자열에서 잔달 인자인 순번에 있는 문자를 반환한다.

  • 오른쪽에있는 char 은 반환타입을 의미한다.
    charAt을 호출하면 char타입의 변수를 준다.
  • int index : 매개변수의 구조

-> charAt

  • System.out.println( s.charAt(4) ); : o
  • 4는 전달인자가 된다.
    줄때는 전달인자라고 하니 전달인자를 쓴다. 받을 때는 매개변수이다.
H e l l o _ W o r l d  !
0 1 2 3 4 5 6 7 8 9 10 11 
  • 인덱스 번호로 매긴다.
char c = s.charAt(11);
  • !를 뽑아와서 c라는 변수에 넣고 싶을 때는 이렇게 작성한다.
  • 반환타입에 맞게 받으면 문제가 생기지 않는다.

concat

: 호출 대상이되는 문자열과 전달 인자인 문자열을 이어붙여 새로운 문자열을 반환한다.

  • 반환타입 : string
  • 매개변수 타입 : string
  • 문자열 두개가 합쳐서 출력이 된다.

그렇다면 두개의 문자열 사이를 띄우고 싶을 때는 어떻게 할까?

  • 이렇게 하면 될까? 안된다!
  • I'm someone 이 출력되지도 않는다.
    concat이라는 메서드가 호출한 객체(t)가 가진 문자열의 전달인자를 갖다 붙여주는 것이 아니라 갖다 붇인 새로운 문자열을 받은 것이다. t는 t고 n은 n이다.
    t랑 n이 붙은 새로운 문자열을 받아줘야한다.
  • 지금 한 것은 마치 int a =5; int b = 3; -> a+b 만 해놓는 것과 같다.
  • 따라서 이렇게 만들어 줘야한다.

concat이라는 메서드는 String 타입의 객체에 있으며 concat의 반환타입은 string이다. 따라서 concat뒤에 concat이 또 가능하다.

❗️concat을 호출하는 타입도 string이며 반환하는 타입도 string이라서 가능한 일인 것이다!

  • 순서는 앞에서 부터 실행된다.

result!!!
String t = s.concat(" " ).concat(n);
=> Hello World! I'm someone.


toLowerCase

: 호출 대상이라는 문자열이 포함하는 대문자를 전부 소문자로 치환한 것을 반환한다.

  • 반환타입 : string -> 새로운 문자열로 반환을 하게 된다.

toUpperCase

: 호출 대상이라는 문자열이 포함하는 소문자를 전부 대문자로 치환한 것을 반환한다.


equals : 문자열 비교

: 대상 문자열과 전달 인자인 문자열의 (실제) 내용이 같은가에 대한 여부를 반환한다.


length

: 문자열의 길이를 반환한다.

배열에서 사용하던 Length랑 현재 사용하는 차이는 ()의 유무차이다.
지금 length는 메서드라고 한다.

❗️문자열의 길이를 구할때는 length 메서드며 배열의 길이는 length 속성을 사용하는 것이다.


split

: 문자열을 전달 인자인 정규표현식으로 나누어 문자열 배열로 반환한다.

  • 반환타입 : string 배열
  • 김씨,이씨,박씨,최씨라는 문자열 한개를 , 단위로 나누어서 문자열 배열 4개로 나누고자할때 사용하는 것이다.


startsWith

: 어떠한 문자열이 전달 인자인 문자열로 시작하는가에 대한 여부를 반환한다.

  • starts의 원형은 start이다.
    반환타입이 boolean인 경우에는 3인칭 단수형을 쓰는 경우가 많다.

endsWith

: 어떠한 문자열이 전달 인자인 문자열로 끝나는가에 대한 여부를 반환한다.

  • startsWith, endsWith 둘다 단어단위로 일치해야하는 것은 아니다.

substring

: 문자열의 어느 부분부터 (어느 부분까지) 잘라 새로운 문자열을 반환한다.

  • 전달인자인 인덱스 번호부터 문자열 끝까지 반환

  • 첫번째 전달인자인 인덱스 번호부터 두번쨰 전달인자인 인덱스 까지.
  • substring은 여러 언어에서 다르게 쓰인다. (가지수가 되게 많은데 java는 그렇지 않다.)

[정적] valueOf

: 주어진 값을 문자열로 반환하여 반환한다.

  • 되지 않는다.

정적인 것에 접근하려면 클래스 이름으로 접근 해야한다.
문자열 타입의 클래스 이름은 String임으로 String 으로 접근을 해야한다.

  • 클래스로 접근했으니 .을 하고 뜨는 것들은 정적인 메서드들이다.
  • static은 이미 메모리에 올라가 있기 떄문에 객체화하지 않아도 뜬다.

  • 객체에 .을 해보니 비정적인 애들이 나온다.



[정적] format

: 주어진 형식으로 문자열을 만들어 반환한다.

  • toPrint 에 모든 정보를 넣어서 한 문장으로 만들자.

  • 여기서 삼항식의 우선순위가 가장 높으며 앞에는 논리값이 와야하는데 "이다. " + pService 이것의 결과가 논리값이 아님으로 오류가 발생한다.
  • 괄호를 해주면 괜찮다.

참고 )

  • int는 long을 담을 수 없기에 오류가 발생한다.
  • 군필 혹은 미필 둘 중에 하나가 꼭 나옴으로 string타입으로 받아줘야한다.

-> format 사용 전 문자열 합치기로 먼저 문장을 만들어 보자.

  • 가독성이 떨어지고 사용하기 힘들다.

그래서 사용하는게 string.format이다.

string.format

%s : String / 문자열
%d : Decimal (:10진수의) / 정수형(byte, short, int, long)
%f : Float / 실수형 (double, float)


System.out.print() : 개항하지 않고 출력함.
System.out.printf() : print에 String.format 합친거. 마찬가지로 개행하지 않음.
  • ln은 (line) 자동으로 개행으로 해준다.

  • String.formatprintf 는 비슷하게 작동한다.
  • ln으로 쓴 것과 f 로 작성한 것의 차이를 보면 printf 는 개행을 해주지 않는다. 즉, 엔터를 쳐주지 않는다.

\n

  • \n을 추가해주면 개행이 된다.

%xd

: x자리에 맞게 우측 정렬하여 수를 표시한다.

%-xd

: x자리에 맞게 좌측 정렬한다. 이때 %d와의 차이는 우측에 남는 공간을 공백( )으로 채우는 것이다.

%0xd

: x자리에 맞게 부족한 자리 수 만큼 앞을 0으로 채운다.

%,d

: ,를 알아서 찍어준다.


❗️ format의 반환타입은 반듯이 문자열이다.


Q) 전달받은 정수형 변수 a와 b의 몫인 실수(double)를 반환하는 함수 div 를 만드세요. (강제 형반환 사용 금지)

정수와 정수의 연산 결과는 정수이다. 즉 소수점이 반올림되는 것이 아닌 버려지게 된다.
Long타입을 사용해야한다. ( L )

5L이면 int의 5가 아닌 long의 5가 된다.

5 + 5L   => 10L 
5 + " "  => "5"
  • 더 큰 아이로 연산된다.

  • 전체연산의 결과는 더블이 되지만 연산 순위가 나누기가 먼저가 되어서 의미가 없다.

  • 또 다른 방법

강제 형변환

(원하는 타입)변수;

  • b라는 변수의 타입이 변하는 것이 아닌 b의 값 자체가 명시적으로 변하는 것이다.

0개의 댓글