티스토리 뷰
1. 참조타입
- 종류 : 배열타입, 열거타입, 클래스. 인터페이스, 레코드
- 참조타입은 그릇 안에 진짜 값을 저장하는 것이 아니라 주소를 저장한다.
- 이러한 주소를 레퍼런스라고 부른다.
- 참조타입은 객체(object)를 찾아갈 수 있는 주소를 저장하게 된다.
- 자바는 ‘OOP : Object–Oriented Programming’라고 불린다.
- 이는 객체 지향 언어라고 불리기도 하는데, 이는 여러 부품을 만들고 조립하는 것이다. 이때 부품을 객체라고 생각하면 편하다.
- 기본 타입변수는 실제 값을 변수 안에 저장하게 되지만,
- 참조 타입변수는 주소를 통해 객체 참조를 하게 된다.
- Ex : 기본타입 변수 - int = age; , double price = 100.5;
- EX : 참조타입 변수 - String name = “신용권”; , String hobby = “독서”;
- 여기서 힙(heap) 영역에는 신용권과 독서가 저장이 되고. (****)
- 스택(stack) 영역에는 name과 hobby와 함께 신용권과 독서의 주소가 저장되게 된다.
- 스택 영역에는 기본타입과 참조타입 모두 저장되는 곳이다.
- 기본타입에서는 정수타입보다 실수타입보다 작은 것처럼 크기가 정해져있는데, 참조타입도 이처럼 크기가 서로 다양하다.
- 주소를 찾아가는 행위를 ‘참조’라고 한다.
2. JVM이 사용하는 메모리 영역 ***
- OS에서 할당 받은 메모리 영역을 RDA라고 부르는데, 이를 3개의 영역으로 구분한다.
- 3개의 영역 : 1. 메소드 영역 2. 힙 영역 3. 스레드 영역
- 자바소스파일 ( . java ) -> 컴파일 ( javac.exe ) -> ( .class ) 생성 -> 실행 ( java.exe ) -> JVM 구동
- 매소드 영역 : class에 관한 모든 정보를 저장하고 있다. 클래스 단위로 구분되어 있다. ( .class에서 읽은 내용 모두 저장 )
- 메소드 영역에 저장된 객체 : .class 파일의 바이트 코드를 저장하고 있는 객체 ( -> Clazz 객체 )
- .Class 파일은 bin파일 속에 저장되어 있다.
- 요약 1. 참조타입 변수에는 객체의 “주소”를 저장
- 요약 2. 참조타입 변수의 초기값을 Null로 사용이 가능하지만, Null은 객체의 주소를 가지고 있지 않다!!
3. 참조 변수의 == , != 연산
- 기본타입에서는 변수의 값이 같은지 다른지 확인해 보는 것이지만,
4. Null과 Null pointer Exception
- Null(널) : 변수가 참조하는 객체가 없을 경우 초기값으로 사용이 가능하다.
- 참조타입의 변수에서만 저장이 가능하다.
- Null로 초기화된 참조 변수는 스택 영역에 생성되게 된다.
- String reVar1 = null; 이라고 하면 reVar1과 null 모두 스택영역에 생성된다.
- == , != 연산이 가능하다.
- Null pointer Exception : 참조타입의 변수가 null값을 가지고 있을 때, 객체의 필드나 메소드를 사용하려고 헸을 때 발생
5. String 타입
- String은 문자열을 저장하는 클래스 타입이다.
- 붕어빵으로 비교하면 붕어빵 틀은 클래스, 붕어빵은 객체라고 할 수 있다.
- 이처럼, 클래스는 객체를 생성하는 틀이다.
- Ex . String name = “김민철”;
- Name은 String에서 찍어낸 문자열 객체의 주소를 보관하는 것이고, ‘김민철’은 String 객체이다. String은 클래스에 해당된다.
- 요약 3. 클래스란?
- 1) “붕어빵 틀”이다!!
- 2) 그리고 1)에서 찍어낸 “붕어빵”이 바로 “객체”이다.
- 3) 그리고 이 붕어빵 틀 중에 “문자열 객체”를 찍어내는 틀이 String이다.
- 변수의 이름이 String name1 , String name2처럼 서로 다르더라도 문자열 리터럴이 “김민철”로 서로 같다면 1번만 생성되고 주소를 서로 공유한다.
- New 연산자를 이용하여 String 객체를 생성할 수 있다.
- 단, NEW를 사용하게 되면 같은 김민철이라는 문자 리터럴을 가지고 있더라도 각자 생성되게 되어, name1, name2에 각자 다른 주소를 가지게 된다.
- String name1 = new String(“김민철”);
6. 배열 – 코딩테스트에 자주 활용
- 배열은 같은 타입의 데이터를 연속된 공간에 저장하는 자료구조이다.
- 자료구조는 여러 데이터를 보관하기 위한 특별한 구조를 의미한다.
- 각 데이터 저장 위치는 인덱스(번호)를 부여해 접근한다.
- 인덱스는 0부터 시작하게 된다. ( 첫번째 데이터는 0번이다. )
- 배열선언 : 배열을 사용하기 위해서는 우선 배열 변수 선언을 해야 한다,
- 배열선언 -> 타입 [ ] 변수; 로 사용하거나 타입 변수 [ ]; 로 사용한다.
- 배열선언 ex. Int[ ] intArray; OR int intArray[ ];
- 하지만 타입 변수 [ ]; 형태는 잘 사용하지는 않는다.
- 배열의 원소는 배열안에 들어가 있는 데이터를 말하는 것이며, 타입이 원소의 타입을 결정하게 해준다.
- 배열변수는 null로 초기화가 가능하다.
- 값 목록으로 배열 생성하는 방법
- -- > 데이터타입 [ ] 변수 = { 값0, 값1, 값2, 값3 . . . };
- [ ] 안에 인덱스 번호를 넣으면 해당 데이터를 찾을 수 있다.
- 배열은 new를 활용하여 선언 후, 값 목록을 대입할 수 있다.
- Ex. 데이터타입 [ ] 변수;
- -> 변수 = new 타입 [ ] { 값0, 값1, 값2, 값3, . . . . };
- Scores.length => 참조타입명.속성명 : 이는 참조타입의 주소에 해당하는 객체의 속성에 접근하는 방법이다.
- 이때 ‘ . ‘는 객체맴버참조연산자이다.
- New 연산자로 배열 생성
- : 배열 생성시 값 목록을 가지고 있지 않아야 한다.
- : 값 목록이 뭐가 나올지 모를 때, 배열을 미리 생성해두고 싶을 때 사용한다.
- Ex. 타입 [ ] 변수 = new 타입 [ 길이 ];
- Ex. 타입 [ ] 변수 = null;
- - > 변수 = new 타입 [ 길이 ];
- Ex. Int [ ] intArray = new int [ 5 ];
01. 과제 2 - 3
public class Sample59 { // 과제 2 - v.3
public static void main (String[] args) {
//1. 여러분이 길을 걸어가다가, 동굴에 빠졌습니다.
//2. 동굴의 깊이는 100미터입니다.
//3. 하루동안 열심히 올라가면 20미터를 올라갑니다.
//4. 자는 동안에는 5미터를 다시 미끄러져 내려갑니다.
// 과제 : 과연 동굴에서 빠져나오기 위해서는, 몇 일이 걸릴까요?
// 기준값 : 동굴 100미터, 하루동안 올라가는 20미터, 미끄러져 내려가는 5미터
// 주의 : 몇일에 걸쳐 올라갔는데, 내가 동굴에서 빠져 나왔는지, 아닌지를 언제 판단해야 하느냐?
// 주의2 : 만일 딱 100미터 올라왔다고 합시다! 그러면, 이거리를 동굴을 빠져나왔다고 생각할 수 있느냐?
// 101미터 부터
// 낮에 파악한다면 낮과 밤을 구분해야 하는건가..?
int a = 0; // 거리
int b = 0; // 날짜
for ( a = 20; a <= 150; a+=20) {
b++; // b++;만 해준 이유는 위에 미리 a의 값을 1일차 낮 값으로 선언해주었기 때문이다.
System.out.println(b + "일째 올라온 거리 " + a + "m");
if( a> 100 ) {
System.out.println("동굴을 탈출했습니다.");
break;
} else {
System.out.println("동굴을 탈출하지 못했습니다.");
a -= 5; // else로 한 이유는 굳이 100m가 넘었는데 밤에 미끄러질 이유가 없기 때문이다.
} // if else
} // for
} // main
} // end class
02. 과제 2 - 4
public class Sample60 {
public static void main (String[] args) { // 과제 2- v.4
//1. 여러분이 길을 걸어가다가, 동굴에 빠졌습니다.
//2. 동굴의 깊이는 100미터입니다.
//3. 하루동안 열심히 올라가면 20미터를 올라갑니다.
//4. 자는 동안에는 5미터를 다시 미끄러져 내려갑니다.
// 과제 : 과연 동굴에서 빠져나오기 위해서는, 몇 일이 걸릴까요?
// 기준값 : 동굴 100미터, 하루동안 올라가는 20미터, 미끄러져 내려가는 5미터
// 주의 : 몇일에 걸쳐 올라갔는데, 내가 동굴에서 빠져 나왔는지, 아닌지를 언제 판단해야 하느냐?
// 주의2 : 만일 딱 100미터 올라왔다고 합시다! 그러면, 이거리를 동굴을 빠져나왔다고 생각할 수 있느냐?
// 101미터 부터
// 낮에 파악한다면 낮과 밤을 구분해야 하는건가..?
int i = 20; // 올라온 높이 <--- 1일차 낮에 올라간 높이를 미리 선언하였다.
int day = 1; // 날짜
while(i<100) { // 조건이 참일때는 반복, 거짓일 때는 탈출!
System.out.println(day + "일째");
System.out.println(i + "M 탈출불가");
i -= 5; // 하루가 지나 -5m가 되었다.
day++;
i += 20; // 다시 하루동안 20m를 올라간다.
} // while
System.out.println(day + "일째");
System.out.println(i + "m 탈출 성공!");
} // main
} // end class
03. 과제 2 - 수정버전
public class Sample61 {
public static void main (String[] args) { // my 수정버젼
//1. 여러분이 길을 걸어가다가, 동굴에 빠졌습니다.
//2. 동굴의 깊이는 100미터입니다.
//3. 하루동안 열심히 올라가면 20미터를 올라갑니다.
//4. 자는 동안에는 5미터를 다시 미끄러져 내려갑니다.
// 과제 : 과연 동굴에서 빠져나오기 위해서는, 몇 일이 걸릴까요?
// 기준값 : 동굴 100미터, 하루동안 올라가는 20미터, 미끄러져 내려가는 5미터
// 주의 : 몇일에 걸쳐 올라갔는데, 내가 동굴에서 빠져 나왔는지, 아닌지를 언제 판단해야 하느냐?
// 주의2 : 만일 딱 100미터 올라왔다고 합시다! 그러면, 이거리를 동굴을 빠져나왔다고 생각할 수 있느냐?
// 101미터 부터
// 낮에 파악한다면 낮과 밤을 구분해야 하는건가..?
final int climb = 20;
final int slide = -5;
final int cave = -100;
int move = 0;
int days = 0;
while( true ) { // 실행문 // 조건을 좀 더 효율적으로 할 필요가 있다. // 배운 것을 활용해 보자....ㅎ
move += climb;
days++;
System.out.println("날짜 : "+ days + "일"); // 오늘의 날짜 확인
System.out.println("현재 올라온 거리 : "+move + "m"); // 낮에 올라간 후의 현재 거리 확인
if((move+cave)<=0) {
move += slide;
System.out.println("미끄러지고 난 후의 거리 : "+move + "m"); // 밤에 미끄러진 현재 거리 확인
} else {
break;
}// if else - 밤
} // while 탈출하기까지
System.out.println("탈출입니다!");
System.out.println("동굴에서 빠져나오는데 걸린 날짜는 총 " + days + "일 입니다."); // 총 몇일 걸렸는지 확인
} // main // 탈출하고 난 후에 실행될 것들
} // end class
04. String 타입
public class Sample62 {
public static void main (String[] args) {
// String 타입의 2개의 문자열 객체가 있을때,
// 이 두개의 문자열 객체의 주소를 저장하고 있는, 참조변수 2개가
// 같은 주소를 가지고 있는지, 아닌지 확인하는 예제
String strVar1 = "신민철";
String strVar2 = "신민철";
String strVar99 = "김민철";
// '신민철'이라는 객테는 힙 영역에 1번만 저장되기 때문에
// strVar1는 strVar2 같은 주소를 가지고 가게 된다.
// 자바에서 동일한 "문자열" 리터럴은 JVM RDA의 HEAP영역에 한번만 생성되는 객체로 (*****)
// 자기의 주소를 공유한다. (*****)
// 물론 신민철과 김민철로 되어있어 서로 다른 문자열 리터럴은 서로 다르게 생성이 된다.
if (strVar1 == strVar2) {
System.out.println("strVar1과 strVar2는 참조가 같다."); // --> 실행결과 : 참조가 같다고 나온다.
}else {
System.out.println("strVar1과 strVar2는 참조가 다르다.");
} // if else
if (strVar1 == strVar99) {
System.out.println("strVar1과 strVar99는 참조가 같다.");
}else {
System.out.println("strVar1과 strVar99는 참조가 다르다."); // ----> 실행결과 : 참조가 다르다고 나온다.
} // if else
// 동등연산자를 기본타입에서 사용할 때는 값을 비교하게 되지만, 참조타입에서 사용하게 되면 변수 안에 있는 주소값을 비교하게 된다.
// ================================================================================
if(strVar1.equals(strVar2)) { // equals는 주소를 비교하는 것이 아니라 문자열 자페를 비교하게 된다.
System.out.println("strVar1과 strVar2는 서로 같다.");
} // if
} // main
} // end class
05. 객체의 주소와 null
public class Sample63 {
public static void main(String[] args) {
// 객체를 생성하고 객체의 주소도 눈으로 봐보자
// TTT라는 임시 .java파일을 생성하였다.
TTT ttt = new TTT();
// new는 객체를 생성하는 연선자이다.
// TTT라는 class 안에 ttt라는 객체를 생성하는 것이다.
System.out.println(ttt); // ttt의 주소를 볼 수 있게 출력하게 해준다.
// TTT@372f7a8d이라는 주소가 출력되게 되는데, @를 기준으로 오른쪽은 주소(물리적인 주소x 논리적인 주소o)를 보여주는 것이고
// 왼쪽은 어떤 타입인지 보여주는 것이다.
// @는 at이라고 부른다.
// 참조타입변수 안에 저장된 객체의 주소를 실무에서는, reference( 참조 )라고 부른다.
String name = null; // 객체의 주소가 없다는 의미이다.
// null은 아직 어떠한 객체의 주소도 담고 있지 않다는 의미이다.
// 정수나 실수 같은 기본타입변수에서는 null이 사용 불가이다!!
if( name == null ) {
System.out.println("null이 들어가 있습니다!"); // null은 값에 해당되기에 ==나 != 연산이 가능하다.
} // if
System.out.println(name); // null이 들어가 있기에 null이라는 값이 출력되게 된다.
} // main
} // end class
06. null Expression 오류
public class Sample64 {
public static void main (String[] args) {
String name = "Yoseph";
System.out.println(name.length()); // .length는 문자열의 길이를 카운트해서 알려준다.
String name1 = null;
System.out.println(name1.length());
// --> null pointer Exception 오류가 발생하게 되는데 객체 주소가 저장되어 있지 않은데,
// 저장되어 있는것처럼 사용하려고 해서 오류가 뜬 것이다.
} // main
} // end class
07. Integer 클래스
public class Sample65 {
public static void main (String[] args) {
Integer number = 100;
// Integer은 정수 객체를 생성하는 클래스이다.
// Integer number = new Integer(100);로 코딩해도 괜찮다.
// 그렇다면 Integer number에서 number은 100의 객채의 주소를 저장하게 된다.
} // main
} // end class
08. String 클래스 - new
public class Sample66 {
public static void main (String[] args) {
String name = "Yoseph";
String hobby = "Extreme sports";
// String str = new Integer(100);
// ---> 오류가 뜨게 되는데 이는 Lvalue와 Rvalue의 타입이 서로 다르기 때문이다.
String str = new String("Yoseph");
// new 연산자 : 객체생성연산자
// String 타입의 Yoseph를 생성하여 주소를 str에 저장한다.
String name1 = new String("신용권");
String name2 = new String("신용권");
// 이렇게 되면 new는 무조건 새로운 객체를 생성하기 때문에 같은 신용권이라는 문자 리터럴이라고 하더라도
// 각자 다른 객체와 주소를 가지게 된다.
} // main
} // end class
09. 배열
public class Sample67 {
public static void main(String[] args) { // 배열
// 배열이란? 같은 타입의 데이터를 0개 이상 저장할 수 있는
// 자료구조(Data Structure이자, 객체이다.
int[] scores = { 83, 90, 87 }; // 이것이 배열이다!!!
// 83은 0번 인덱스, 90은 1번 인덱스, 87은 2번 인덱스에 해당된다.
// int가 앞에 나왔다고 하여 int가 class로 바뀌는 것이 아니라
// int는 단순히 데이터의 타입을 결정해주는 것이다. 타입은 [ ] 배열이다.
// 배열의 원소의 타입은 기본/참조 타입 모두 가능하다!!
// 자바 언어에서 배열은 1번 생성하면 2가지를 바꿀 수 없다. (*******)
// 1. 배열원소의 타입 2.배열의 크기 / 배열의 길이 [ = 원소의 개수 ] 이 2가지는 변경이 불가능하다. (********)
// System.out.println("scores[3]" + scores[3]); // <--- 컴파일 오류는 뜨지 않지만 실행하면 오류가 뜬다.
// 배열의 인덱스가 범위를 벗어나는 오류는 컴파일러가 잡아내지는 못하지만 실행하면 콘솔창에 범위(길이)에서 벗어났다고 오류가 뜬다.
int[ ] scores2; // 배열변수의 선언
// scores = new int [ ] {1, 2, 3 };
// 배열은 이렇게 선언과 값목록 대입을 따로 할 수 있다.
scores2 = scores; // 이전의 만든 배열을 가지고 초기화하기 위해서는 대입으로만으로고 가능하다.
// 하지만 그렇지 않을때는 전부 int [ ] scores2;라고 선언 후 (****)
// scores2 = new int [ ] { 1, 2, 3 }; 형식으로 만들어야 한다. (***)
System.out.println("scores[0] : " + scores[0]); // 배열의 첫번째 원소 출력
System.out.println("scores[1] : " + scores[1]); // 배열의 두번째 원소 출력
System.out.println("scores[2] : " + scores[2]); // 배열의 세번쩨 원소 출력
System.out.println("scores: " + scores); // scores의 주소를 찍는 println
// ---> [I@4517d9a3 가 출력되게 되는데, 왼쪽의 [는 배열을 의미하고 I는 integer을 의미한다.
// 배열변수명 [ 인덱스 번호 ] => 배열의 요소에 접근하는 것을 "Indexing"이라고 한다.
// 배열의 생성 ================================================================
int sum = 0;
for(int i=0; i<= scores.length -1 ; i++) { // 배열이 저장하고 있는 모든 데이터의 합을 구하자!
// scores.length 뒤에 -1을 하는 이유는 인덱스가 0번째부터 시작하기 때문이다. (***)
sum += scores[i];
// sum에 scores배열에 있는 0번째부터 2번째까지 가져와서 더함으로써 총합을 구하는 식을 만들었다.
// i가 만약 배열의 길이에서 벗어난 조건식으로 작성이 되어있다면 ArrayIndexOutOfBoundsException라는 오류가 뜨는데
// 이는 인덱스 번호가 배열의 길이를 벗어났다는 이야기이다.
// 참조타입명.속성명 --> 참조타입의 주소에 해당하는 객테의 속성에 접근하는 코드이다.
// ' . ' : 객체맴버 참조연산자
} // for
System.out.println("총합 : " + sum);
double avg = (double) sum/3; // 배열의 데이터의 총합과 원소의 개수로 평균을 구하자!
// 평균의 경우에는 실수가 나올 수 있으므로 double로 타입을 정해준다.
// Lvalue와 Rvalue의 타입이 같아야 하기에 강제형변환시켜줬다.
System.out.println("평균 : " + avg);
} // main
} // end class
10. 배열 선언과 값목록 따로 생성하기
public class Sample68 {
public static void main(String[] args) {
int [ ] scores;
scores = new int[] {83, 90, 87};
int sum1 = 0;
for(int i=0; i<scores.length; i++) {
sum1 += scores[i];
} // for
System.out.println("총합 : " + sum1);
int sum2 = add(new int[] {83,90,87});
// int sum2 = add({83,90,87}); 는 불가능 하다.
System.out.println("총합 : "+ sum2);
System.out.println();
} // main
public static int add(int[] scores) {
int sum =0;
for(int i=0; i<3; i++) {
sum += scores[i];
} // for
return sum;
} //add
} // end class
'KH 정보교육원 [ Java ]' 카테고리의 다른 글
KH 09일차 - 클래스와 필드 (0) | 2022.03.09 |
---|---|
KH 08일차 - 배열과 열거 (0) | 2022.03.07 |
KH 06일차 - 조건문과 반복문 (0) | 2022.03.03 |
KH 05일차 - 연산자 및 조건문과 반복문 (0) | 2022.03.02 |
KH 04일차 - 타입변환 및 연산 (0) | 2022.02.28 |