자바 4. 연산자, 출력문과 클래스 및 메소드 생성자 패키지 임포트문 만드는 형식 영역 구분법 그리고 초기화 블록

Bluewiz_YSH·2022년 6월 28일
0

1. 연산자

저번 장에서 자바에서 어떤 숫자나 문자 혹은 문자열 값을 저장하는 형식과 자료형을 배웠다면, 이번 연산자에서는 그런 값들을 더하고 빼고 곱하고 나누고 하는 기본 사칙 연산은 물론 더 어려운 연산법까지 배우는 기회가 될것이다.

(연산자의 정의는 연산의 대상이 되는 피연산자 (Operand)를 연산처리하기 위한 기호, 즉 Operator다.)

일단 순서는 가장 먼저 처리해야하는것부터 가장 위에 두면서 가장 나중에 처리해야하는 것들을 맨 아래에 두었다.

(1) 괄호 연산자

우리가 흔히 산수나 수리 문제를 풀때 보고 쓰던 소괄호 ( ), 중괄호 { }, 대괄호 [ ]가 바로 이것이다.

즉, 어떤 수식이나 값 혹은 변수 등이 특히 소괄호에 싸여있다면 그것부터 먼저 계산 처리를 해야한다.

(2) 단항 연산자

단항 연산자는 항, 식이 하나인 수식에서 쓰이는 연산자이다. ex) int x = 3;

단항 연산자는 여러 연산자들을 내포하고 있는데 아래 설명과 같다.

논리 연산자 : 단항 연산자에서 논리 연산자는 ! (부정, NOT)밖에 없다. 참인 값을 거짓으로 바꾸고 거짓인 값을 참 값으로 바꾼다. ex) boolean tf = !(5>3); //true => false 값 저장

비트 연산자 : 반전 연산자, ~이 해당된다. 이진수로 이뤄진 값의 모든 자리수를 반대로 바꾼다. (1은 0으로, 0은 1로) ex int num2 = ~num1

증가/감소 연산자 中 전위 연산자 : ++,-- 변수값 앞에 위치하며 문장을 종료하는 ; 세미콜론이 끝나기전에 연산자를 받은 변수에 1을 더하거나 빼서 그걸 원래 변수에 다시 저장한다. 수식으로 풀어서 쓰면 다음과 같다 : int a; => ++a => a = a+1; (1 증가된 값을 초기 a에 대입) => a = a (초기 a를 새로운 a에 대입) -- 또한 빼기 처리만 다르지 과정은 같다.

접근 연산자: . 주로 클래스명(객체명).메소드명 혹은 .변수명으로 해당 클래스(객체)의 메소드(기능)이나 변수를 불러올때 중간 다리 역할로 사용한다.

부호 연산자: +,- 값의 양수 음수 부호 역할을 한다.

(3) 이항 연산자

이항 연산자는 항(식)이 두개인 수식에서 쓰이는 연산자이다. ex) num1 + num2;

이 또한 여러 연산자들을 이용한다.

결합 연산자 : +, 문자열을 결합할때 주로 사용한다. ex) "안녕" + "하세요"

산술 연산자 : +,-,/(나누기의 몫),%(나누기의 나머지) 기본 사칙연산의 연산자이다.

비교(관계) 연산자 :
==
(equal, 왼쪽 항과 오른쪽 항이 동일하다는 표시의 연산자),
!=
(not equal, 왼쪽 항과 오른쪽 항이 동일하지 않다는 표시의 연산자),
>
(왼쪽 값이 오른쪽 값보다 크다),
<
(왼쪽 값이 오른쪽 값보다 작다),
>=
(왼쪽 값이 오른쪽 값과 같거나 크다),
<=
(왼쪽 값이 오른쪽 값과 같거나 작다),
instanceof
(클래스 객체가 어떤 클래스형으로 생성된건지 인스턴스 비교),
결과 값은 true 아니면 false로 반환한다.

비트 연산자: 이진수로 이뤄진 왼쪽 항의 값, 오른쪽 항의 값이 있는 상태에서
논리곱 & 두 값의 각각 자리수가 모두 1일때 1, 나머지 경우 모두 0 반환
ex) 0&1 = 0; 1&0 = 0; 1&1 = 1;
논리합 | 두 값의 각각 자리수가 하나라도 1일때 1, 모두 0이면 0 반환
ex) 0|0 = 0; 0|1 = 1; 1|0 = 1;
XOR exclusive OR 배타적 논리합 ^ 두 값의 각각 자리수가 같은 값을 가진다면 0, 다른 값을 가진다면 1 반환
ex) 0^0 = 0; 0^1 = 1; 1^0 = 1;
그외에도 부등호 방향으로 자리수를 이동시키는 비트 이동 연산자도 있다.
(>> << >>> <<<)

논리 연산자 :
논리곱 &&
왼쪽 항의 조건과 오른쪽 항의 조건 모두 참일때 참,
논리합 ||
왼쪽 항의 조건과 오른쪽 항의 조건 모두 거짓일때 거짓.
결과 값으로 true 혹은 false 반환, 왼쪽항 오른쪽항 모두 조건식 사용한다.
ex) boolean bool = (5 > 3) && (4 > 2) => true 값 반환
또한, 단축연산이라 그래서 논리곱 연산자는 왼쪽 항이 false 일 경우 그리고 논리합 연산자는 왼쪽 항이 true일 경우 결과값이 각각 무조건 false, true이기 때문에 오른쪽 항을 연산 처리하지 않는다.

(4) 삼항 연산자

삼항 연산자는 항(식)이 세 개인 수식에서 쓰이는 연산자이다. 현재 자바에서 쓰이는 삼항 연산자 예시는 딱 하나밖에 없다. 바로 조건 연산자이다.

조건 연산자 : 조건식 ? 참일 경우 반환하는 결과 값 : 거짓일 경우 반환하는 결과 값
ex) int score = 80; Char grade = (score >= 75) ? 'B' : 'C';

(5) 대입 연산자 & 복합 대입 연산자

대입 연산자는 = 인데 (왼쪽과 오른쪽 값 둘다 동일하다는 표시의 연산자는 ==) 복합 대입 연산자는 대입 연산자에다가 다른 연산자를 합친 연산자라고 보면 된다.

대입 연산자 = : 오른쪽 값을 왼쪽 변수/객체/클래스/인스턴스/배열...에 대입하는 연산자.

복합 대입 연산자 :
+= 두 항 값을 더해서 왼쪽에 대입하는 연산자
ex) num1 += 2; => num1 = num1 + 2;
-= 왼쪽 항에서 오른쪽 항의 값을 빼서 나온 결과를 왼쪽 항에 대입하는 연산자
ex) num1 -= 2; => num1 = num1 - 2;
*= 두 항을 곱해서 왼쪽에 대입하는 연산자
ex) num1 *= 2; => num1 = num1 * 2;
/= 왼쪽 항을 오른쪽 항으로 나누어 그 몫을 왼쪽에 대입하는 연산자
ex) num1 /= 2; => num1 = num1 / 2;
%= 왼쪽 항을 오른쪽 항으로 나누어 그 나머지를 왼쪽에 대입하는 연산자
ex) num1 %= 2; => num1 = num1 % 2;
(이외에도 비트 연산자와 결합해 @= |= ^= <<= >>= <<<= >>>= 복합 대입 연산자들이 있다.)

(6) (증감 연산자 中) 후위 연산자

후위 연산자는 전위 연산자와 다르게 문장의 종료를 표시하는 ; 세미콜론이 지나고 나서 변수에 값에 1을 더하거나 빼서 변수에 저장한다.

후위 연산자 : ++,-- 변수값 뒤에 위치하며 문장을 종료하는 ; 세미콜론이 끝난 후에 연산자를 받은 변수에 1을 더하거나 빼서 그걸 원래 변수에 다시 저장한다. 수식으로 풀어서 쓰면 다음과 같다 : int a; => a++ => a = a; (초기 a를 다시 a에 대입) => a = a+1 (문장 수식 처리가 다 끝난 뒤 세미콜론 ;이 지나고 나서 a+1을 a에 대입) -- 또한 빼기 처리만 다르지 과정은 같다.

결국, 이런 모든 연산자들은 우선순위가 있는데 단항이 제일 높고 이항 그 다음 삼항 연산자 순위이며 후위 연산자를 제외하면 대입 연산자 순위가 가장 낮으며 산술 관계 논리 대입 순으로 우선순위가 낮아진다. 또한, ( ) 쳐져있는 수식은 우선순위가 가장 높다. 이 모든걸 종합하자면 아래와 같다.

괄호 => 단항(! ++ -- 전위 연산자 + -) => 이항 (산술 곱하기 나누기 먼저 덧셈 뺄셈 그다음 => 비교(관계) => 비트 => 논리) => 삼항 연산자 조건 => 대입 (=> 후위연산자 ++ --)\

아래는 main 부분에 들어갈 연산자 예시 코드단이다. 입력하고 실행해보자.

		boolean bl = true;
		byte b = 1;
		char c = 'B';
		short s = 10;
		int i = 12;
		long l = 80l;
		float f = 4.5f;
		double d = 12.3;
		
		System.out.println(bl);
		System.out.println(b);
		
		System.out.println("하나"+c+"둘");
		System.out.println(s);
		System.out.println(i);
		System.out.println(l);
		System.out.println(f);
		System.out.println(d);

		System.out.println("============\n");		
		
		int a = 1;
		int e = 2;
		int g = a*e*(a+5);
		System.out.println(g);
		System.out.println("============\n");
		
		boolean t = true == !false;
		System.out.println(t);
		System.out.println("============\n");
		
		System.out.println(a);
		System.out.println(a++);
		System.out.println(a);
		
		System.out.println("============\n");	
		
		int a1 = 10;
		int b1 = a1;
		System.out.println(b1);
		
		b1 += a1;
		System.out.println(b1);
		
		b1 -= a1;
		System.out.println(b1);
		
		b1 *= a1;
		System.out.println(b1);
		
		b1 /= a1;
		System.out.println(b1);
		
		b1 %= a1;
		System.out.println(b1);
		
		System.out.println("============\n");	
		
		//단축연산(논리연산인 경우 무시되는 부분이 발생)
		int value1 = 3;
		
		//논리연산 논리곱(=AND =&&) 전위연산자 우선순위 무시
		System.out.println("논리연산 논리곱 &&");
		//System.out.println(++value1 > 6 && false);
		System.out.println(false && ++value1 > 6);
		System.out.println(value1);
		System.out.println(true && ++value1 > 6);
		System.out.println(value1);
		System.out.println("================\n");
		
		//논리연산 논리합(=OR =||) 후위연산자 무시
		System.out.println("논리연산 논리합 ||");
		int value2 = 5;
		System.out.println(true || value2++ > 6);
		System.out.println(value2);
		System.out.println(false || value2++ > 6);
		System.out.println(value2);
		System.out.println("================\n");
		
		//비트연산 AND
		System.out.println("비트연산 AND");
		System.out.println(0&0);
		System.out.println(0&1);
		System.out.println(1&0);
		System.out.println(1&1);
		System.out.println("===============\n");
	
		//비트연산 OR
		System.out.println("비트연산 OR");
		System.out.println(0|0);
		System.out.println(0|1);
		System.out.println(1|0);
		System.out.println(1|1);
		System.out.println("================\n");
		
		//비트연산 XOR(배타적논리합과 동일)
		System.out.println("비트연산 XOR");
		System.out.println(0^0);
		System.out.println(0^1);
		System.out.println(1^0);
		System.out.println(1^1);
		System.out.println("================\n");
		
		int a2 = 5;
		final int A = 5;
		a2 = 7;
		// A = 7;
		
		System.out.println("============\n");	
		
		int a3 = 10;
		int b3 = 5;
		
		System.out.println("a3==b3 : " + (a3 == b3));
		System.out.println("a3 > b3 : " + (a3 > b3));
		System.out.println("a3 >= b3 : " + (a3 >= b3));
		System.out.println("a3 < b3 : " + (a3 < b3));
		System.out.println("a3 <= b3 : " + (a3 <= b3));
		System.out.println("a3 != b3 : " + (a3 != b3));
		
		System.out.println("============\n");	

그러면 아래 사진과 같이 우리가 앞서 배운 연산자 활용이 잘 된 결과들이 쭉 나온다.

(각각 연산자가 어떤것이고 어떤 기능을 하는지 기억하는것도 중요하지만 특히, 전위/후위 연산자와 논리곱의 단축 연산 그리고 연산자들끼리 우선순위도 중요하다.)

+) 자바에서 쓰이는 기타 특수문자들 용어 이름

& 앰퍼센트 Ampersand

* 아스테리스크 ASTERISK

| (shift + 원화 \ 백슬래시) 수직바 버티컬바 Vertical Bar

^ 캐럿 caret

/ 슬래시 slash

\ 백슬래시 역슬래시 backslash

2. 출력문

우리가 자바를 배우면서 여태까지 반복적으로 쓴 코드문이 있다, 그건 바로 System.out.println();.

이 코드는 출력문이며 콘솔창에 () 안쪽으로 받은 변수,객체,문자열 등을 출력해준다.

앞으로도 가장 많이 쓸 코드문이기에 중요하기에 아래 코드단을 main 부분에 입력후 실행하면서 연습해보았다.

		//println()
		System.out.println("안녕하세요");
		System.out.println("안녕" + "하세요");
		System.out.println();
		
		System.out.println(2 + 4);
		System.out.println("문자" + (1 + 2));
		System.out.println("문자" + 1 + 2); // 맨 처음이 문자열 => 뒤에 + 모두 결합연산자
		System.out.println(1 + 2 + "문자"); // 맨 처음이 숫자 => 산술연산자 더하기 취급
		System.out.println();
		
		int a = 5;
		String b = "하세요"; //문자열을 의미하는 자료형 "" 공백없어도 됨 (char와 반대)
		// 클래스 급 이상 참조 자료형 변수(주소값 저장), static/stack/heap 메모리 영역(static선언+main메소드+자바기본패키지들+클래스들/메소드+지역변수 (LIFO, 임시저장소)/객체 인스턴스)
		System.out.println(a);
		System.out.println(b);
		System.out.println("안녕"+b);
		System.out.println(a + "안녕" + b);
		System.out.println();
		
 		//print()
		System.out.print("반갑");
		System.out.print("습니다");
		System.out.print("7");
		System.out.print("\n");
		System.out.print("\n");
		//System.out.print(); //매개변수가 없으면 안됨

 		//printf(): 포맷관련
		//%d 10진수 %o 8진수 %x X 16진수 %s %S 문자열 %f 실수형 float (소문자 대문자)
		System.out.printf("%d\n", 10);
		System.out.printf("%o\n", 10);
		System.out.printf("%x\n", 10);
		System.out.printf("%X\n", 10);
		System.out.printf("%s\n", "문자열 출력");
		System.out.printf("%S\n", "abc");
		System.out.printf("%f\n", 3.2582); //디폴트 최대 6자리까지 출력
		System.out.printf("%s %f\n", "여러개 출력", 3.2582);
		System.out.printf("%10.2f\n", 3.2582); // %와 포맷 양식 사이 실수 => 10.2 양수 오른쪽 10칸 생성후 오른쪽 정렬 + 소수점 이후 2자리만 남기고 반올림 칸보다 데이터가 길어도 정상출력 가능 (공간 칸 자동 생성)
		System.out.printf("%-10d과 %.4f\n", 10, 3.2582); // 음수 왼쪽 10칸 생성후 왼쪽 정렬 + 소수점 4자리만 남기고 반올림
		//System.out.printf(); 매개변수가 없으므로 에러
		
		int c = 3;
		++c;
		System.out.println(c);
		c--;
		System.err.println(c); //빨간 글씨+우선순위 미지정 실행할때마다 출력 순서 달라짐 보통 에러표시 출력때 사용

그러면 아래 사진과 같이 실행 결과가 나오는데 위에서부터 천천히 보면 ""로 감싼 안녕하세요는 문자열이고 따로 따로 감싼 안녕과 하세요도 문자열이다. 이들 문자열을 결합할땐 우리가 연산자에서 배웠던 결합 연산자 +를 이용한다. 또한, 숫자 + 숫자 혹은 숫자 + 숫자 + 문자열, 문자열 + (숫자 + 숫자)일 경우 숫자들은 더하기 산술 처리가 되어 계산이 되지만, 문자열 + 숫자 + 숫자의 경우 이는 뒤의 숫자는 문자열로 간주되어 나오는 결과값은 문자열이 되어버린다.

이런 문자열을 가리키는 자료형은 String인데, 나중에 String 내용에서 보겠지만 String은 ""(Double Quotation, 큰따옴표, char형은 Single Quatation 작은따옴표)로 하나 혹은 다수의 문자 나열을 감싸며 표현한다.안의 문자열이 문자 하나만 있어도 되고, 숫자가 들어가도 되고 (대신 문자열 처리) 공백이 있어도 되고 공백이 없어도 된다.(char는 공백이든 뭐든 문자값이 들어가야함) 또한 println()과 같이 괄호안에 들어가는 변수 값이 없어도 된다. (이럴 경우 한줄 바꿈)

println()과 달리 print()은 줄바꿈 없이 한 줄 안에 모든걸 출력한다. 그래서 print()를 사용시 한줄 안에 띄어쓰기 없이 모든 값을 연달아 출력하는데, 다만 "\n"을 넣을 경우 줄 바꿈이 된다.

printf()는 출력 포맷을 중시한 출력문으로 주석과 같이 %문자에 따라 주어진 값을 다르게 출력시킬수 있다. 그리고 System.out이 아닌 System.err로 print 출력문을 입력후 실행하면 빨간 글씨와 함께 해당 값이 실행할때마다 위치가 변경된다. (err는 에러의 의미로 긴급할때 바로 나오게끔 하도록 기능이 설정되어있다)

3. 클래스와 메소드 만드는 형식 Syntax

(1) 클래스

클래스(Class)란 한 개 이상의 메소드(=기능 )과 한 개 이상의 멤버 필드(변수)(=요소 =속성 =attribute =property, 메소드안이 아닌 클래스 내부에 선언되는 클래스의 속성. 선언은 변수와 같이 자료형 멤버 변수명;이다. 선언하면 자동으로 값이 초기화된다. => 기본 숫자 자료형은 0 혹은 0.0(실수형), String이나 객체는 값을 주소를 담고 있는데 이 경우에는 알수 없다는 의미의 null로 자동 초기화된다.)로 이뤄진 집합체이며 후일 배우겠지만 객체를 만들기 위한 최소 단위이다.

형식은 아래와 같다: ([ ] 표시는 생략 가능)
[접근제어자] =>public으로 일단 생각하자 class 클래스명 {
멤버변수 field 여러개 가능
.
.
.
[생성자]
.
.
.
메소드 method 여러개 가능
.
.
.
}

여기서 클래스명을 지을때 규칙이 있다. 클래스 이름 첫 글자는 _언더바 기호 $달러 기호 영어대문자만 가능하다. 그리고 첫 글자에 숫자는 올수 없으며 클래스 이름의 첫 글자는 되도록이면 영어 대문자가 와야하고 나머지는 영어 소문자면 된다. 그리고 공백이 있으면 안되며 자바 기본 프로그램에서 미리 지정한 단어인 키워드 예약어로는 클래스이름 지정이 안된다.

변수와 같이 클래스명도 전체적인 표기법이 있는데 바로 파스칼 기법(카멜 표기법)과 스네이크 표기법이 있다. 파스칼 기법은 클래스명이 의미 단위로 여러 단어로 이뤄진 복합 단어라고 했을때 첫 글자를 대문자로하고 나머지 소문자로 적다가 의미 단위로 끊어서 다음 단어의 첫 글자를 대문자로 넣어 구분을 짓는 표기법이다. ex)PascalWriting 스네이크 표기법은 의미 단위 사이에 _언더바 기호를 넣어 구분 짓는 표기법이다. ex) Snake_writing

(2) 메소드

메소드(Method)는 클래스에서 보다시피 기능의 역할을 수행한다. ( ex) 더하기 곱하기 나누기 계산, 어떤 문자열을 콘솔에 출력...등등) 이런 메소드도 형식이 있는데 일단 선언문과 호출문으로 나뉘어진다. (메소드를 사용하기 위해선 '어떻게 사용해야하는지' 알려주는 선언문과 사용하기 위해서 클래스에서 따로 '호출'을 해야한다.)

메소드 선언문 형식은 다음과 같다: ([ ] 표시는 생략 가능)

[접근제어자] public [기타제어자] => 일단 static으로 생각하자 리턴받을 값의 자료형 (=> 기본 자료형, 클래스형, 배열 등) (리턴값이 없으면 void) 메소드명(매개변수/매개인자){

실행문(출력문, 조건문, 제어문/반복문, 지역변수, 지역 객체...

return 반환할 값; (없으면 생략 가능)

}

이렇게 보면 우리가 항상 클래스를 생성하면서 체크했던 public static void main(String[] args){} 부분을 보면 이것이 main 메소드임을 단박에 알아차릴수 있을것이다.

public : 접근 제어자, 나중에 보겠지만 프로젝트 전체에서 사용이 가능하다는 표시이다.

static : 기타 제어자, 나중에 보겠지만 프로그램을 키자마자 메모리에 활성화되어 언제든지 쓸수 있다는 표시이다.

void : 메소드를 실행하고 결과에 대해서 반환할 값이 없다는 표시이다.

main : 메소드명이다. 중요한점은 자바에서 항상 '실행'이 되는 부분은 'main' 메소드 밖에 없다.

String[] args : 문자열 String 형태로 이뤄진, 여러 값으로 나열된 집합체 배열([ ])을 매개 변수로 받고 이 매개변수 이름이 args이다. 매개변수(arguments, args)란 어떤 실행의 원인이 되는 변수이며 독립변수-종속변수에서 독립변수를 생각하면 된다.

+) main 메소드가 없으면 일반 클래스, 있으면 메인 클래스로 한다.

그럼 이제 main 메소드를 제외한 나머지 메소드는 main 메소드 안에서 직접 호출을 해야한다. 아래와 같은 호출문 형식을 가지고서 말이다.

메소드 호출문 형식 : 메소드명(매개변수); <= 같은 클래스 안에 메소드가 있을 경우에만 가능 그리고 메소드 호출로 나온 결과값은 메소드 호출문이 있던 자리에 반환/저장된다.

만약 다른 클래스 혹은 패키지까지 다른 경우 접근 제어자 .을 써서 패키지명.클래스명.메소드명()까지 해야한다.

(+다른 패키지면 import문도 필요 => 임포트문은 코드 영역 최상단에 쓰는 코드문으로 다른 패키지의 클래스나 변수 등을 끌어오기 위해 클래스 내부 코드 영역 전에 입력하는 코드문이다. ex) import OtherPackage.OtherClass;)

(3) 생성자

생성자(Constructor)는 클래스의 객체를 생성하는 동시에 new 키워드 예약어와 같이 오면서 클래스의 멤버 변수를 초기화 할때 쓰는 코드를 뜻한다.

(여기서 가장 중요한게 우리가 여태까지 자바에서 객체 지향적 특성이 잘 나타난다고 했는데, 객체란 우리가 현실에서도 실존한다고 생각하는것(포유류, 인간, 식물, ...)이며 자바에서는 이것들을 멤버 변수와 메소드로 프로그램화 구현한 것을 객체, 클래스라고 한다.)

앞서 한 클래스, 메서드, 생성자는 모두 영어 대소문자를 구별하긴 하지만 생성자에서 특히나 중요한것은 객체를 생성할때 그 객체의 클래스명과 생성자명이 꼭 일치해야한다는것이다.

일단 형식은 다음과 같다 ([ ] 표시는 생략 가능):

접근제어자 public 생성자명([매개변수]){

멤버 변수 초기화 코드문;

혹은 여타 다른 실행문;

}

특히나 메소드와 다른 점은 리턴할 타입이 없다는것이고 만약 클래스를 만들었는데 이 클래스의 생성자를 따로 선언하지 않았다면 이땐 자바에서 자동적으로 디폴트 생성자를 만들어 숨겨놓는다. (매개변수도 없고 중괄호 안 실행문도 무엇도 아무것도 없는 그냥 기본적인 형태의 생성자)

만약 생성자를 따로 선언하거나 매개변수까지 설정해놨을 경우 이는 디폴트 생성자를 없애는 결과를 낳기에 디폴트 생성자를 호출해 객체를 생성할수 없다. 디폴트 생성자를 굳이 쓰고 싶다면 따로 디폴트 생성자를 클래스 안에 명시해서 선언해줘야 한다.

또한, 생성자를 이용한 객체 생성은 그 객체의 클래스 내용을 그대로 복사 하여 어떤 공간(Heap)을 할당하여 그 공간에 넣고 그것을 사용하기 위해 변수 대입까지 해준것이며 이것은 실제 객체를 생성하고 어떤 특정 객체의 사례를 만든것이기에 인스턴스(instance) 생성이라고 부른다.

다만, 만약 어떤 객체를 생성자를 사용하지 않고 그대로 다른 변수에 대입해 집어넣었다면 그건 생성자를 이용한 객체 생성을 하는 방식인, 새로운 공간을 만들고 원본 클래스 내용을 복사해 새로 객체를 만든게 아니라 원래 있던 객체를 그대로 다른 변수에 대입해 집어넣은것이므로 새로운 인스턴스 생성이 아니다.

기본적인 클래스 메소드 생성자에 대한 설명과 만들고 호출까지 하는 형식 설명은 끝났고 그럼 클래스, 메소드, 생성자까지 모두 모은 아래 코드단 예시를 한번 입력해보고 실행해보자.

add 메소드를 담고 있는 AddClass와 객체를 생성하고 add 메소드를 실행할 예정인 MainClass가 있다. a는 5, b는 10이라 할때 add(a,b)의 결과값을 콘솔창에 출력해보시오. (AddClass와 MainClass 모두 같은 패키지 선상에 있다)

  • AddClass
public class AddClass
{
	int x = 0; // 멤버 변수, 선언만 해도 자동 초기화가 가능하다, 클래스 안에서 확실히 존재
	
	public int add (int a, int b) { // add 메소드 선언문, int 자료형 a,b를 매개변수로 받음
		return a+b; // return 값 int a+b를 반환 받음
	}
}
  • MainClass
public class MainClass //main 메소드가 있으면 main 클래스
{

	public static void main(String[] args)
	{
		int a = 5, b = 10; //지역 변수 (선언 & 자동 초기화 x, 메소드 내에서만 존재, 선언시 반드시 초기화까지 해야함)
		
		AddClass ac = new AddClass(); // AddClass형 객체 ac 생성 (new + AddClass(); 생성자 이용)
		
		int addResult = ac.add(a, b); // 객체 ac가 AddClass 클래스형을 띄기 때문에 AddClass의 메소드 add 메소드 호출해 결과값을 addResult에 대입
		
		System.out.println(addResult); //콘솔에 addResult 출력
		
		
	}
	
}
//
//class AddClass // 원래는 따로 public class AddClass로 클래스 파일을 따로 생성해야하지만 public을 지우면 한 파일안에 양립 가능
//			// 다만 클래스 확장자 파일은 컴파일은 클래스 단위로 됨 자바 파일은 하나지만 클래스 파일은 2개 생성
//{	
//	int x = 0;
//	
//	public int add (int a, int b) {
//		
//		return a+b;
//	}
//}

주석에 다 써있지만 그래도 중요한것만 말하자면 객체를 생성하고 add 메소드를 실행하고 결과값을 출력하는 클래스(객체)는 MainClass이며 안에는 add 메소드 실행을 위한 지역 변수 (멤버 변수와 대척되는 존재로서 메소드 안에 존재하는 속성, 변수이며 선언만 한다고 자동 초기화가 안되기에 꼭 선언하면서 초기화를 해줘야 한다. 그리고 메소드가 다 실행되고 끝나면 메모리에서 값이 사라진다.) a와 b가 있으며 그 다음으로는 new + AddClass 생성자를 이용해 객체 ac를 생성하는 코드문이 있다.

그리고 객체 ac를 접근 제어자 .을 이용하여 참조해서 AddClass가 가진 add 메소드를 호출, 매개 변수는 미리 지정한 지역 변수 a와 b를 넣고 실행해 나온 결과 값은 다시 int 자료형을 띈 addResult에 대입하고 마지막으로 addResult를 콘솔에 출력하는 출력문까지 이 모든게 MainClass의 내용이다.

AddClass는 주석처럼 public을 빼면 MainClass 아래에 연달아 적을수 있지만, 따로 클래스 파일을 만드는 기준으로 보면 int 자료형의 멤버 변수 x를 가지면서 int 자료형 a와 b(이때의 a와 b는 MainClass의 a와 b 지역 변수와는 다르다)를 매개 변수로 가지고 a + b 산술 결과를 리턴하는 add 메소드를 선언하여 가지고 있다. 또한, 생성자는 따로 없으므로 디폴트 생성자만 있는것이다.

+) 덧붙여 위 사례에서 생성한 객체 ac는 정확하게는 값을 저장하는게 아니고 값을 저장한 공간의 주소를 가지고 있으며 우리는 이 주소와 자바에서 미리 짜여진 매커니즘이 적절히 조화가 되어 실질적인 값을 꺼내오고 수정할수 있는것이다.

(정확히 객체 ac의 실질적인 값을 저장하는 공간은 힙 Heap 메모리이며 객체 ac의 값을 품고 있다. 보통 객체 또는 인스턴스를 저장하는 공간은 Heap이며 자바에서는 그 외 static과 stack 영역이 있는데

static은 프로그램이 실행되자마자 메모리에 올려져 바로 사용할수 있는 값들이 있는 곳이며, (<= 보통 우리가 앞서 배운 상수 풀 리터럴과 자바 기본 패키지들 및 static 선언한 변수 및 메소드들 (main 메소드)이 여기에 있다)

stack 영역은 각 클래스마다 선언하고 호출한, static 선언이 되지 않은 메소드 및 그 메소드들의 변수 지역 변수들을 품고 있다.(<= stack 영역의 메소드 및 지역 변수들은 바깥쪽에 있는것들이 먼저 처리된다고 하여 LIFO Last in First out 특성을 띄고 있으며 메소드 및 지역 변수들 처리가 끝나면 자동적으로 없어진다) 후일에 이 자바의 메모리 특성 3개에 대해 후술할 시간이 있다면 후술하겠다)

(4) 패키지와 Import문

패키지(Package)는 클래스와 후일에 배울 인터페이스를 집합해놓은 집합체로, 형식은 다음과 같다:

package 패키지명; // 클래스 시작전 최상단 위치

특히나 현재 우리가 앞서 지금까지 썼던 출력문들은 자바 기본 패키지(정확히는 System 패키지의 out 객체의 println 메소드를 불러온것)에서 직접 불러온것으로 자바가 실행될때나 컴파일될때 자동적으로 java.lang 패키지에서 불러나온것이다.

이런 패키지는 클래스와 클래스 사이의 구분 영역이라고 볼수도 있고 클래스가 할수 있는 기능 즉, 객체 단위로 구분을 지어 프로젝트 내 관계 구조를 만드는데 필요한 시스템이라고 볼수 있다.

패키지를 만드는 법은 이클립스 화면에서 Package Explorer - 해당 프로젝트의 src 폴더 오른쪽 클릭 - New - package - name에 패키지명 넣고 finish 하면 된다.

또한, 패키지안에 또 패키지를 만들고 싶다면 finish전에 name을 입력하는 칸에 패키지1.패키지2로 입력후 만들면 된다. 언뜻 패키지가 따로 만들어진거 같지만 프로젝트 폴더 - src 폴더에 가보면 패키지1 폴더 안에 패키지2 폴더가 생성되어있다.

일단 패키지 설명은 그렇고 이런 패키지와 자주 쓰이는게 import문인데, 이 임포트는 쉽게 말하자면 다른 위치 영역에 있는 클래스나 인터페이스를 끌고 와 직접 사용하기 위해 필요한 키워드라고 보면 된다.

임포트문 형식은 다음과 같다:

import 패키지명.클래스명;
//혹은 import 패키지명.* <= 패키지 아래에 있는 모든 클래스 및 인터페이스를 끌고 온다
// 임포트문도 패키지와 같이 최상단에 위치해야한다. 보통 패키지명 다음 아래 코드에 선언된다

만약 임포트로 끌어오려는 클래스명이 임포트를 받는, 메인 메소드가 있는 메인 클래스명과 동일하다면 임포트문 대신에 패키지명.클래스명을 main 메소드 안에서 입력해 직접 패키지명까지 언급하면서 사용해야한다.

다르다면 패키지명.클래스명을 사용하는 방법 또는 임포트문 둘다 가능하다.

그럼 일단 아래 코드단을 이클립스에서 구현후 실행해보자.

  • Ex_Arrays 클래스
package first;

public class Ex_Arrays
{
	public int[] test() {
		int a = 5, b = 10;
		
		int [] irr = new int [2];
		
		irr [0] = a;
		
		irr [1] = b;
		
		return irr;
	}
}
  • New_Array_Ex03 클래스
package first;

import java.util.Arrays;

public class New_Array_Ex03
{

	public static void main(String[] args)
	{
		Ex_Arrays es = new Ex_Arrays();
		
		int[] irr = es.test();
		
		System.out.println(Arrays.toString(irr));

	}

}

//System (클래스명) .out (객체) .println() (println 메소드를 호출하라)

그러면 아래 사진과 같이 결과값이 나오는데 일단 Ex_Arrays는 int 자료형 배열을 반환하는 test 메소드를 가지고 있다. (배열은 후일에 더 자세히 보겠지만 같은 자료형을 가진 값들의 순차적 나열이라고 보면 된다)

여기에 New_Array_Ex03 클래스에서 main 메소드 안에서 new 생성자를 이용한 Ex_Arrays형 객체 es를 인스턴스 생성하고 es에서 test 메소드를 호출, 호출 후 반환값은 int 자료형 irr에 담아 이걸 Arrays.toString 메소드의 매개 변수로 넣고 이 모든걸 통째로 출력문으로 출력하는게 바로 위 코드단의 흐름이다. 그래서 미리 test 메소드로 정해진 a와 b값이 [] 대괄호로 감싸여진 배열 형태로 나온것이다.

그렇다면, Arrays 클래스의 toString 메소드는 어디서 나온걸까? 바로 New_Array_Ex03 클래스의 바로 위 최상단 부근에 임포트문 import java.util.Arrays; 코드가 있는것을 알 수 있을것이다.

그렇다, 최상단에서 임포트문을 이용해 java.util 패키지의 Arrays 클래스를 불러와 main 메소드 안에서 Arrays.toString 메소드를 쓸수 있도록 한것이다. 이것이 바로 임포트문 사용의 대표적인 예이다.

아래 또다른 코드단 사례를 해보자.

  • second 패키지 안 same_name 패키지 아래 Ex01 클래스
package second.same_name;

public class Ex01
{

	public static void main(String[] args)
	{
		// TODO Auto-generated method stub

	}

}
  • first 패키지 안 same_name 패키지 아래 Ex01 클래스
package first.same_name;

// import second.same_name.Ex01; 에러남 왜? 클래스 이름이 서로 같은 경우 임포트 구문은 서로 충돌이 남

// 클래스 이름이 서로 다르다면 위의 임포트 구문을 사용하면 됨

public class Ex01
{

	public static void main(String[] args)
	{
		second.same_name.Ex01 ex01 = new second.same_name.Ex01();
		
		// 만약 클래스 이름이 동일할 경우 임포트문 대신에 위 코드처럼 객체 생성할때 직접 패키지명.을 앞에 적어주면 오류가 나지 않음
		
		// 클래스 이름이 서로 다를때 임포트 혹은 위 코드처럼 패키지명. 객체 생성 둘 다 가능
		
		// 다만 둘다 끌어오려는 해당 클래스의 접근 제어자를 꼭 확인하고 할것. (default면 다른 패키지에서 접근 불가)

	}

}

보다시피 두 클래스 모두 다 패키지 안 패키지를 품고 있고, 클래스명 또한 같다. 이럴 경우 만약 first 패키지 쪽 Ex01에서 second 패키지 쪽 Ex01을 임포트해 객체를 만드려면 어떻게 해야할까?

답은 우리가 위에서 봤던것처럼 main 메소드 아래 객체 생성을 할때 패키지명.클래스명 객체명 = new 패키지명.클래스명.객체명();으로 일일이 패키지명부터해서 써주는것이다.

이러면 그냥 임포트로 first.same_name을 끌어올때 나타나는 오류가 생기지 않는다.

(다만, first.same_name.Ex01 클래스의 접근 제어자가 default면은 안된다. 이 내용은 정보 은닉 접근제어자 할때 다루겠다.)

(5) 영역 구분법

여태까지 봤던 클래스, 메소드를 보면 다 중괄호, 즉 주요 내용인 실행문이 괄호로 쳐져있다. 이 중괄호는 클래스와 메소드가 존재하는 영역을 구분짓는 기호이며 이 중괄호를 벗어나는 작업이 이뤄지면 그 즉시 클래스와 메소드는 존재하지 않는다.(메모리에서 아예 사라져 더이상 접근하지 못한다는 의미이다)

아래 코드단을 한번 입력해보자.

package first;

public class RangeVariable { ①

	public static void main(String[] args) { ②
		int value1 = 3;
		{ ③
			int value2  = 5;
			System.out.println(value1);
			System.out.println(value2);
		} ④

		System.out.println(value1);
		// System.out.println(value2); value1 메인메소드 안에서만! value2 메소드 안 중괄호에서만!
	} ⑤

} ⑥

RangeVariable 클래스의 영역은 가장 첫 포문을 연 ①부터 ⑥까지이다. main 메소드는 ②부터 ⑤까지이며 여기서는 멤버 변수 value1이 존재한다. ③부터 ④까지는 value1은 물론 value2이 존재하는 영역이다.

다만, ②~⑤ 그리고 ③과 ④ 사이의 영역에서 value1은 멤버 변수이기에 존재하지만 value2는 ③과 ④를 넘어섰기에 존재하지 않아 출력문으로 출력하려고 해도 출력되지 않고 오류가 뜬다.

(6) 초기화 블록

클래스 안 멤버 변수를 따로 초기화 하는 식이 없거나 관련 메소드가 없는데 멤버 변수들을 한꺼번에 초기화 하고 싶을때 (혹은 미리 클래스에 앞으로 써야할 툴/라이브러리 클래스를 로딩하고 싶을때, 이 부분은 jdbc에서 후술하겠다.)

중괄호 {}를 이용해 멤버 변수들을 한꺼번에 초기화 하는 초기화 블록을 사용할수 있다.

예를 들면 아래 코드문처럼 말이다:

public class TestInitialization01 {

int a;

double b;

char c;

{

a = 4;

b = 2.0;

c = 'C';

}

	public static void main(String[] args) {
		
		TestInitialization01 ti = new TestInitialization01 ();

		System.out.println(ti.a);

		System.out.println(ti.b);

		System.out.println(ti.c);

	}

}

그러면 이렇게 초기화 블록대로의 값이 콘솔에 출력이 잘 됨을 확인할수 있다.

이렇게 연산자, 출력문, 클래스, 메소드, 생성자, 패키지, 임포트문, 영역 구분, 초기화 블록까지 자바 코드 구성의 기본이 되는 요소들을 봤으니 자바에서 많이 쓰이는 실행문인 조건문 제어문 반복문을 다음장에서 알아보겠다.

0개의 댓글