[ 앱 개발자 도전기 : 안드로이드 ]
안드로이드 앱 개발 위한 자바 문법 정리 - [1]
∇ 안드로이드 : 자바 문법 정리 - [1]
목 차
1. 자료형
2. Casting
3. final & static & statc final의 차이.
4. if(), switch()
5. for(), while(), do-while()
1. 자료형 [ Data Type ] : 기본 자료형 & 참조 자료형
※ 자료형은 변수에 어떤 형태의 변수를 넣을 것인지 정하는 것입니다.
◎ 기본 자료형 ( Value type / primitive data type )
- 변수가 데이터 자체를 의미하는 것 ! (실제 값을 가짐)
≒ 기본 타입 ≒ 원시 타입
- 자바 컴파일러에 의해서 해석되는 자료형.
- 실제 값을 갖는 자료형
- 자바에서 여러 형태의 타입을 미리 정의하여 제공.
- 논리 / 정수/ 문자 /실수 을 저장하는 자료형.
- 8가지의 자료형이 제공 [ boolean, byte, short, char, int, long, float, double ]
§ 기본자료형 특징.
§ 기본 자료형은 반드시 사용하기 전에 선언(Declared) 되어야 합니다.
§ OS(운영체제)에 따라서 자료형의 길이가 변하지 않습니다.
§ 비객체 타입입니다. = > null 값을 가질 수 없습니다.
--> 만일, 기본 자료형에 null을 넣고 싶다면 Wrapper Class를 활용해야 합니다.
§ 스택(Stack) 메모리에 저장됩니다.
※ 정리.
● 정수 표현 : byte, short, int, long
● 실수 표현 : float, double
● 문자 표현 : char
● 참과 거짓의 표현 : boolean
◎ boolean
- 논리형, 참과 거짓을 저장하는 타입.
- boolean의 기본값은 false
- 주로 yes - no , on - off 등의 논리 구현에 주로 사용되며, 두가지 값만 표현하므로 가장 작은 크기.
- boolean은 실제로 1bit이면 충부하지만, 데이터 활용 최소 단위가 1byte이므로, 메모리 크기는 1byte
◎ char
- 문자형, 2byte의 문자 하나를 입력하는 데이터형..
- ' 문자 1개 ' 를 저장하는 데이터 형.
- char 변수명 = "값";
◎ byte
- 정수형, 이진데이터를 다루는데 사용되는 타입 입니다.
◎ int
- 정수형 / 자바에서 정수 연산을 하기 위한 기본 타입입니다.
- byte 혹은 short의 변수가 연산을 하면 - > 연산의 결과는 int형이 됩니다.
◎ long
- 정수형 / 수치가 큰 데이터를 다루는 프로그램(은행 및 우주 관련 프로그램 등 ) 에서 주로 사용하는 타입.
- long 타입의 변수를 초기화 할 때는
정수값 뒤에 알파벳 'L'을 붙여서 long 타입( = 8byte) 의 정수 데이터임을 명시해줘야 합니다.
- 정수값이 int의 값의 저장 범위를 넘는 정수에서, 'L'을 붙이지 않는다면 컴파일-에러가 발생합니다.
long l = 2147483648; // 컴파일 에러 발생합니다.
long l = 2147483648L; // 컴파일 에러 발생하지 않습니다.
◎ float, double
- 실수형입니다.
- float(4바이트) / double(8바이트)
- 실수를 '가수' 와 '지수' 형식으로 저장하는 부동소수점 방식으로 저장됩니다.
- '가수' 를 표현하는데 있어서 double 형이 float 형보다 표현 가능 범위가 더 크므로
double형이 보다 정밀하게 표현 가능합니다.
- 자바에서 실수의 기본 타입은 double 형 !
- > float형에는 알파벳 'F' 를 붙여서 float형임을 명시해주어야 합니다.
float f = 1234.567; // 무조건 double 타입으로 이해하려고 하므로 컴파일 에러가 발생합니다.
float f = 1234.567F; // float type이라는 것을 표시해야 합니다. 컴파일 에러 발생하지 않습니다.
◎ 참조 자료형 ( reference data type )
≒ 참조 타입
§ 침조 자료형 특징.
- 기본형을 제외한 타입들이 모두 참조 자료형.
- 빈 객체를 의미하는 Null이 존재합니다.
-> 문법상에서는 에러가 없지만 실행시킬 경우에는 런타임 에러가 발생합니다.
== 객체나 배열을 Null값으로 받으면, NullPointException이 발생
== 따라서, 변수 값을 넣어줘야 합니다!
- 실제 값이 아닌 객체의 주소를 가지고 있는 자료형.
- 자바 라이브러이 API에서 제공되거나 개발자에 의해서 만들어진 클래스를 자료형으로 선언하는 경우.
- new를 활용하여 생성하는 것들은 메모리 영역인 Heap 영역에 생성을 하게되고
Garbage Collector가 돌면서, 메모리를 해제합니다.
- Heap 메모리에 생성된 '인스턴스'는 메소드나 각종 인터페이스에 접근하기 위해서,
JVM의 Stack 영역에 존재하는 'Frame' 에
일종의 포인터(C의 포인터와는 별개) 인 참조값(주소)을 가지고 있어서 이를 통해서 인스턴스를 핸들링합니다.
§ 침조 자료형 종류
- class type ( 클래스 )
- interface type (인터페이스 )
- array type (배열)
- enum type( 열거 )
☆ String Class(문자열)
: String Class는 '참조형'에 속하긴 하지만, 기본적인 사용은 기본형처럼 사용합니다.
- > 불변(immutable) 하는 객체입니다.
- > String 클래스에는 값을 변경해주는 메소드들이 존재하지만,
해당 메소드를 통해 데이터를 바꾼다 해도 새로운 String 클래스 객체를 만들어낸 것 !
- > 일반적으로 기본자료형끼리의 비교는 '==' 사용하지만
String 객체간의 비교는 '.equals() 메소드 ' 를 사용해야 합니다 !
2. Casting : 형 변환.
◇ 캐스팅은 "자료 타입의 변환"을 의미합니다.
ex) byte 타입을 int 타입으로 변환한다거나, 그 반대로 변환하는 행위를 말합니다.
- 어떠한 자료형/ 클래스의 변수/ 객체를 만든다는 것은
좌변의 자료형이 요구하는 정보를 모두 우변이 갖추었을 때 가능한 것.
int num = 1;
int num1 = 2.0; // 에러 발생!
- 캐스팅은 자료형에서도 자주 사용하지만, 객체지향(OOP)의 개념에서 매우 많이 사용되는 기법입니다.
-- > '캐스팅의 목적'은 데이터를 바꾸는 것이 주목적이 아닌,
개발자가 이미 데이터 정보를 이해했다는 가정하에 OOP의 다형성 측면에서 사용합니다.
int num2 = (int) 2.0;
int 타입으로 변환을 시킨다는 목적하에 타입을 정확히 입력.
(기본 데이터형에서의 캐스팅은 원칙적으로 데이터 손실을 막고자 합니다 )
타입 변환에 있어서, 기억해야 할 점은
" 좌변에 필요한 정보는 우변에 충분히 있어야 한다"라는 원칙입니다.
※ 캐스팅은 두 가지 갈래로 구분할 수 있습니다.
A. 자동(묵시적) 타입 변환 (Promotion) - > " JVM " 이 알아서 해줌.
- 프로그램 실행 도중 자동으로 타입 변환이 발생.
- 작은 크기를 가지는 타입이, 큰 크기를 가지는 타입에 저장될 때 발생.
정수와 부동 소수점을 연산할 때,
정수 2와 부동 소수점 1.7을 더하고자 요구하면 정수 2가 자동으로 부동 소수점 형식으로 변환되어 3.7로 연산된다.
문자열 "10"과 정수 5를 더하고자 할 때,
문자열 "10"이 자동으로 정수형으로 바뀐 후 연산이 진행되어 15가 된다.
B. 명시적 형 변환 [ 강제 타입 변환] (Demotion) : 우리가 흔히 말하는 캐스팅(개발자가 직접 지정)
double doubleValue = (double) intValue;
//라는 구문을 이용해 정수형을 실수형으로 변환할 수 있다.
//(double)이 정수를 실수로 변환하는 연산자의 역할이다.
일반적으로 우리가 말하는 '캐스팅(Casting)'이란, 명시적 형 변환과 동일한 용어로 쓰입니다.
개발자가 (type)연산자를 사용하여, 의도적으로 자료의 형식을 바꿀 때를 일반적으로 캐스팅이라고 말합니다.
명시적 캐스팅은 "업 캐스팅" & "다운캐스팅"으로 구분합니다.
◎ 업 캐스팅(Up-cating)
: " 업 캐스팅(Up-Cating)" 은 하위 클래스의 정보를 담을 수 있는 객체에다가
상위 클래스의 자료형을 부여함으로써, 마치 상위 클래스처럼 사용하게 하는 것 !
class Parent
|
class Child
- Child 는 Parent 클래스를 상속받는다고 할 때
Parent p = new Child();
Parent 형의 객체를 생성하고자 할 때, Child형의 정보를 좌변에 제공하는 것
상위 클래스인 좌변이 요구하는 정보는, 하위 클래스인 우변은 당연히 전부 가지고 있음.
◎ 다운 캐스팅(Down-cating)
: "다운 캐스팅" 은 단순히 업 캐스팅의 반대말로 정의할수는 없습니다.
다운 캐스팅은 상위 클래스 타입으로 선언된 객체를, 하위 클래스 타입으로 변환하는 것을 의미 !
class Parent
|
class Child
Parent p = new Child(); // p는 Parent형
// 업캐스팅
Child c = (Child) p; // p는 Child형
// 다운캐스팅
☆ 다운 캐스팅을 수행할 시 주의점.
- 다운 캐스팅 시에는 ClassCastException 오류에 주의해야 합니다.
[ 다운 캐스팅은 실행 시에, 타입 안전성을 보장하지 않습니다. ]
== 다운 캐스팅하려는 객체가 실제로 해당 타입이 아닐 경우, ClassCastException이 발생 가능.
=== 반드시, instanceof 연산자를 활용해, 타입을 먼저 확인한 후에 다운 캐스팅을 시도해야 합니다.
ex) Animal 이라는 부모 클래스를 Dog 라는 자녀 클래스가 상속 받는다면,
밑의 상황에서는 ClassCastException 오류가 발생합니다.
Animal a = new Animal();
Dog d = (Dog) a; // ClassCastException 발생!
타입 체크 없이 강제로 변환하려 했기에 오류가 발생하는 것
이를 피하기 위해서는
if (a instanceof Dog) {
Dog d = (Dog) a;
// Dog 관련 작업 수행
} else {
// 다른 처리
}
☆ 다운 캐스팅의 활용.
ⓐ 상속 관계에서의 사용.
- 다운 캐스팅은 주로 상속관계에서 발생.
-> 하위 클래스가 상위 클래스 타입으로 선언된 객체를 참조하고 있을 때
이 객체를 다시 하위 클래스 타입으로 변환하여 하위 클래스의 기능으로 사용 가능 합니다.
class Animal { ... }
class Dog extends Animal { ... }
Animal animal = new Dog();
// animal을 Dog 타입으로 다운 캐스팅
Dog dog = (Dog) animal;
ⓐ 실제 타입의 메소드 호출.
- 상위 클래스로 선언된 객체는 실제로는 하위 클래스의 인스턴스일 수 있습니다.
-> 다운 캐스팅을 통해, 실제 타입의 메소드를 호출 가능.
Animal animal = new Dog();
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.bark(); // Dog 클래스의 bark 메소드 호출
}
3. final & static & statc final의 차이.
☆ Static.
- static은 "정적인", "고정된" 이라는 의미로 , "전역" 이라고 이해하면 편합니다.
= > 객체 생성 없이 사용 가능한 필드와 메서드를 생성하고자 할 때 활용합니다.
ex) ErrorMessage를 모든 View에서 일관되게 반환하고자 할 경우에
a. return " [Error] 오류 발생" < - 이런 방법으로 하드 코딩을 하고 싶지는 않고
b. 따로 클래스를 만들어서 빼냄으로서, 각 클래스마다 ErrorMessage 객체를 생성하고 싶지 않다면?
== " 공용 데이터"로 활용한다면?
생성된 클래스의 메소드들을 모두 static으로 선언해주면 됩니다.
//단! 메소드를 static으로 선언하게 된다면
외부에서 불러오는 변수(class 변수)는 모두 static으로 선언되어야 합니다 !
◇ static(정적 메소드)는 '객체 참조' 없이 바로 사용할 수 있어서
인스턴스 필드 혹은 메소드, this키워드(인스턴스의 특징)를 사용할 수 없습니다.
◇ static(정적 메소드)은 메소드 영역에 저장되기 때문에
Garbage Collector(가비지 컬렉터)가 작동하지 않아서 시스템 종료시까지 계속 메모리에 남아있게 됩니다.
☆ final
- final은 "최종인", "결정적인" 이라는 뜻으로, 값이 한번 저장되면 수정이 불가능하다는 뜻 !
= > 생성자 주입을 받을 때, 해당 변수를 final로 선언함으로써 해당 인스터스의 임의 변경을 막아줍니다.!
public class Flow {
private final FlowContext flowContext;
# 받아오는 flowContext마다 다른 값을 저장하게 됨
public Flow(FlowContext flowContext) {
this.flowContext = flowContext;
}
}
= > 값을 받아오기 전까지는 어떤 값도 final 변수에 할당이 가능하므로, 완전한 상수라고 보기도 어렵습니다.
+ class에 final 함수로 선언하면, 해당 클래스를 상속 받은 클래스는 final 함수를 재정의 해줄 수 없습니다.
++ class를 final로 선언하면, 해당 클래스는 어디에서도 상속을 해줄 수 없습니다.
☆ static final
- static final = "고정된" + "최종" 이라는 뜻으로 상수를 선언하고자 할 때 사용합니다.
= > "상수란 변하지 않는 값을 의미합니다"
○ final과는 달리 애초에 빈 값으로 둘 수 없습니다.
○ static final을 선언한 순간 - > 값을 할당해줘야 오류가 발생하지 않습니다.
public class Message {
private static final String startMessage = "게임을 시작합니다.";
public static void printStartMessage() {
System.out.println(startMessage);
}
}
4. if(), switch()
★ if() 와 swithc()문은 조건에 따라서 처리하기 위해 사용됩니다.
- 개발 과정에 특정 값에 대한 특정 Action이 필요할 때, 흔히 사용하게 됩니다.
private void somethingIf(int value) {
if (value > 0) {
// do something
}
}
private void somethingSwitch(int value) {
switch(value) {
default:
// do something
}
}
둘다 비슷한 케이스에 사용하기는 하지만, 계산의 효율성 측면에서 상이하게 사용하긴 합니다.
☆ if문
- "Branch Statement" 의 대표주자입니다.
- 레지스터 2개 값 혹은 레지스터와 값 비교 후 특정 메모리 번지로 이동할지 결정합니다.
- if 문 속에 따져야 하는 조건들이 많아질수록 연산량이 늘어나게 된다는 단점이 있습니다.
- 자주 사용하는 기능 순서대로 조건문을 작성하는 것이 성능 향상에 도움이 됩니다.
☆ switch문
- "jump Statement" 의 대표주자입니다.
- 따져야하는 조건이 많을수록 유리합니다.
- 점프 테이블 생성에 오버헤드 발생 가능성이 있습니다.
- case의 개수가 4개 이하면 jump table 미 생성.
- case의 개수가 4개 이상일 경우, jump table 생성
- jump table의 크기는 가장 큰 값 - 가장 작은 값으로 결정되나
중간에 순차 증가가 아닌 경우, 더 많은 메모리를 사용합니다.
ex) case 1 , case 2, case 3, case 4 (메모리크기4)
ex) case 1 , case 2, case 3, case 10 (메모리크기10)
※ 정리.
- 조건이 4개 이하이면 if // 조건이 4개 이상이면 switch문을 사용하는 것이 유리합니다.
- 하지만 switch 문의 경우, jump table 생성에 오버헤드 발생가능성이 있어서
메모리 사용량이 중요할 경우에는 simplify 된 if문을 통해 처리하는 것이 중요합니다.
- 케이스가 정의되지 않은 경우 -- > if문으로 정의합니다.
- if문이든 switch문이든 매개변수의 경우, 사전에 null체크가 완료된 데이터를 가져옵니다.
- switch문에 default 구문은 기본 action을 정의하지 않고, Exception 케이스에 대해 정의.
5. for(), while(), do-while() 차이.
★ 반복문
: 반복문은 코드를 반복적으로 실행하고자 할 때 사용합니다.
- > 반복문의 종류로는, for문과 while문, do-while문이 있습니다.
- > for문과 while 문은 서로 변환이 가능하기 때문에 반복문을 작성할 대는 어느 쪽이든 상관 X
-> but, 반복 횟수를 알고 있을 때는 for문 // 조건에 따라 반복할 때는 while문을 주로 사용
☆ for 문
: for문은 조건식이 '참'인 동안 주어진(설정한) 횟수 만큼 실행문을 반복적으로 수행합니다.
ex) 1~10까지의 수를 반복하여 더하는 예제.
public class ForEx {
public static void main(String[] args) {
int result = 0;
// for (초기화; 조건식; 증감식) {}
for (int i = 1; i <= 10; num++) {
result += i;
}
// 1~10의 합인 55 출력
System.out.println(result);
}
}
* 주로 반복문을 초기화할 때, 반복 계수 i(iterator)를 사용합니다.
§ for 문의 구조.
: for ( 초기화; 조건식; 증감식) 으로 설정하여, 중괄호 {} 안에 실행코드를 작성합니다.
○ 초기화 : for 문이 시작될 수를 정하는 것으로, 반복할 변수의 초깃값을 설정합니다.
○ 조건식: 반복할지의 여부를 결정하는 곳
- > 조건식 안의 값이 true라면 실행문을,
false라면 실행하지 않고 반복문을 벗어납니다.
○ 증감식: 반복 횟수를 결정하는 곳입니다.
- > 변수에 값을 더하거나, 빼거나, 곱하는 등의 수행 방식을 설정합니다.
§ for 문의 실행 과정.
1. int i 변수를 선언하여, 초깃값 ' 1 ' 로 초기화합니다.
2. 초깃값 1은 10보다 작거나 같으므로, '실행 블록'을 실행합니다.
3. result 라는 변수에 i를 더하는 과정을 수행합니다.
4. 실행 블록을 빠져나와서, i에 1을 더합니다.
5. i가 11이 될 때까지 (i가 10 이하이므로) 2~4번 과정을 반복합니다.
6. i가 11이 되었을 때, 조건이 충족하지 않으므로 for 문을 종료합니다.
☆ 향상된 for 문( Enhanced for문 )
: 향상된 for문의 경우, 변수와 증감식을 사용하지 않습니다.
- 배열 및 컬렉션 항목의 개수만큼 반복하고 for문을 빠져나갑니다.
public class EnhancedForEx {
public static void main(String[] args) {
String[] names = {"Kim", "Lee", "Park"};
for (String name : names) {
System.out.println("사용자 이름 : " + name);
}
}
}
§ Enhanced for 문의 구조.
: for (저장할 변수 선언 : 사용할 배열) {}
○ 저장할 변수 선언 : 가져올 배열의 값을 임시적으로 저장하는 공간.
○ 사용할 배열 : 변수에 담을 raw데이터의 배열.
--> 배열의 길이 만큼 반복수행해서, 해당 반복 횟수 만큼 차례대로 값을 가져옵니다.
§ Enhanced for 문의 실행 과정.
1. names '배열'에서 가져올 첫 번째 값이 존재하는지 확인합니다.
2. 값이 존재하여, 이를 저장할 name '변수'에 'Lee'를 저장합니다.
3. { } 안의 실행문을 실행하여, "사용자 이름 : Lee"를 출력합니다.
4. names 배열에서 가져올 다음 값이 있는지 확인하여, 2~3번 과정을 반복합니다.
5. 만약, 더 이상 가져올 값이 없을 시, for문을 종료합니다.
☆ while 문
: for문은 반복할 횟수를 알고 있을 때 사용한다면,
while문은 조건식이 true일 경우에 계속해서 반복하게 됩니다.
ex) 1~10까지의 수를 반복하여 더하는 예제.
public class whileEx {
public static void main(String[] args) {
int i = 1;
int result = 0;
while (i <= 10) {
result += i;
i++;
}
System.out.println(result);
}
}
§ while 문의 구조 및 실행 순서.
: while(조건식) {}
○ 조건식의 결과가 true 일 때 중괄호 {} 안의 실행문을 실행합니다.
○ 실행문이 끝나면, 다시 조건식을 통해 true 또는 false를 판단합니다.
○ true이면 실행문을 반복하여 실행하고, false이면 while문을 종료합니다.
++ while 문의 조건식 안에는 boolean 타입도 사용이 가능합니다.
만일, while문 안에 조건식에 true만 사용하면 무한 루프에 빠지게 됩니다.
int num = 0;
// 무한 루프에 빠짐
while (true) {
System.out.println(num);
num += 1;
}
== 실행문 안에, while문을 벗어나게 해주는 코드가 필요합니다.
int num = 0;
boolean run = true;
// 실행문 안에서 while문 탈출
while (run) {
System.out.println(num);
num += 1;
// num이 100이 되면 while문 탈출
if (num == 100) {
run = false;
}
}
☆do - while 문
:do-while문은 조건식에 의해 반복 실행한다는 점에서 while문과 동일합니다.
하지만 ! while문은 '조건식을 검사하고 난 뒤에 실행문을 결정' 하는 반면에,
do-while문은 우선 실행을 시키고 난 뒤, 조건식을 통해 계속 반복할지를 결정합니다.
public class DoWhileEx {
public static void main(String[] args) {
int i = 1;
int result = 0;
do {
result += i;
i += 1;
} while (i <= 10);
System.out.println(result);
}
}
§ do - while 문의 구조 및 실행 순서.
: do {} while (조건식);
○ do의 중괄호 {} 안에 내용을 수행한 뒤, 조건식 안의 내용을 검사합니다.
○ 조건식 결과가 true 이면, do의 중괄호 {} 안에 담긴 실행문을 반복하여 수행합니다.
○ 만약, 조건식 결과가 false이면, do-while문을 바로 종료시킵니다.
※ 장단점 비교.
◎ while 문
○ 장점
1. 조건을 먼저 검사하므로, 불필요한 코드 실행을 방지 가능.
2. 반복 횟수가 정해지지 않은 경우에 유용
3. 코드의 가독성이 좋음.
○ 단점
1. 초기화 변수를 반복문 외부에 선언해야 하므로, 변수의 스코프가 넓어짐.
2. 조건이 처음부터 거짓이면 한 번도 실행되지 않을 수 있음.
== 조건을 먼저 확인해야 하는 경우에 적합. !
++ while문이 성능면에서는 do-while문보다 미세하게 빠를 수 있음 .
- while문은 초기식에 직접 변수를 선언하여 사용하고 문 종료 시 메모리 해체하는 반면
do-while문은 반복문에 활용되는 변수를 계속 가지고 있기 때문.
◎ do-while 문
○ 장점
1. 최소 한번은 코드 블록을 실행하므로, 초기 실행이 필요한 경우에 유용.
2. 사용자 입력을 받는 경우와 같이 최소 한 번의 실행이 필요한 상황에 적합.
○ 단점
1. 조건 검사 전 코드 블록이 실행되므로 불필요한 코드 실행될 가능성 있음
2. while문에 비해 가독성이 떨어질 수 있음.
== 최소 한 번은 코드를 실행해야 하는 경우에 사용.
◎ for 문
○ 장점
1. 인덱스 조작이 가능 // 특정 인덱스의 요소에 직접 접근하고 조작 가능.
2. ArrayList나 배열을 순회할 때, 비교적 빠른 성능
3. 반복 횟수를 명확하게 지정 가능하여서, 특정 횟수만틈 반복하는데 유용.
4. 루프의 시작과 끝을 자유롭게 지정 가능.
5. 반복 중에 요소의 변경이나 삭제가 가능.
○ 단점
1. 인덱스의 범위를 벗어나는 오류(Out of range)가 발생 가능
2. LinkedList와 같은 자료구조를 순회할 때는 성능이 저하 가능.
3. 향상된 for문(for-each)에 비해서 코드가 더 복잡하고 가독성 음
4. 반복문내에서만 사용되는 변수를 외부에서 선언해야 할 경우,
변수의 스코프가 불필요하게 넓어질 수 있음.
5. 배열이나 컬렉션의 모든 요소를 순회하는 간단한 경우, for-each문에 비해서 코드가 길어짐.