JAVA공부 [2. JAVA의 기본 문법(2) ]
0.1. 조건문(conditional Statements)
자바에서는 if문의 조건이 boolean변수로 들어와야하기 때문에 살짝 다르다..!
- 전체적인 흐름은 앞서 학습했던 c언어와 유사하다.
주의해야하는점
if(count != 0 ||(avg = total/count) > MAX)
System.out.println(avg);
- 이 코드의 문제점은 count가 0이 아닐 경우..! or연산이기 때문에 뒤 연산(avg값 구하기)를 실행하지 않는다.
Indentation
들여쓰기는 나만 보는게 아니니..유지보수를 위해 깔끔하게 짜자..
0.2. 반복문(Repetitions Statements)
- 전체적인 흐름은 앞서 학습했던 c언어와 유사하다.
1. 🔥 배열
자바의 배열은 기본적으로 전부 동적배열이다.
기본적인 사용방법
public class App {
public static void main(String[] args) throws Exception {
int []arr = new int[10]; //동적할당..!
for(int i = 0; i < 10; i++)
arr[i] = i * 3;
for(int i = 0; i < 10; i++) //for(int i = 0; i < arr.length; i++)
System.out.println(arr[i]);
}
}
- 자바에서 배열은 c언어의 배열과는 전혀 다른 방식으로 동작한다.
쉽게 생각하면 배열이라는 자체가 따로 존재(c언어는 변수를 이어놓은?)따라서 해당 메서드를 호출할 수 있다.
마치 클래스처럼 작동한다.
public class App {
public static void func(int []arr){ //마치 포인터처럼 받아서 값을 참조하여 변경가능
for(int i = 0; i<arr.length; i++)
arr[i] = i * 2;
}
public static void main(String[] args) throws Exception {
int arr[] = new int[10];
func(arr);
for(int i = 0; i < 10; i++)
System.out.println(arr[i]);
---
int arr[] = new int[10];
int arr2[] = arr; // 포안터와 같이 동작한다. 즉, arr이가 가르키고 있는 배열을 같이 가르킴
func(arr2);
}
}
만약 자바가 범위를 벗어난 인덱스를 잡는 경우나 생성되지 않는 배열을 사용하는 경우에는 바로 예외를 던진다..!
null
프로그래밍에서 null은 0이 아니라 아무것도 가르키고 있지 않은 상황을 말하며 이는 아직 아무것도 참조하고 있지 않은 상태를 나타낸다.
2. foreach문
public static void main(String[] args) throws Exception {
int []arr = new int[10];
func(arr);
for(int elem : arr) //기본적인 foreach문 사용방법..!
System.out.println(elem);
}
- 보는 그대로 해석하면 된다. 기존 for문에서는 필요없는 변수 i를 선언해서 인덱스를 체크했다면 불필요한 변수를 줄이고 arr배열에서 elem을 하나씩 꺼내오겠다는 의미..!
주의해야하는 점!
위에서 사용한 코드 func메서드에서 값을 초기화할 때 for문을 사용해서 바꾸었는데 그렇다면 값을 바꾸는 연산또한 간단하게 foreach문으로 대체할 수 있지 않을까?
- 답은 x이다..! 왜냐하면…
for(int elem : arr)
elem = arr[i]; //내부에서 이루어 지는 연산 즉, elem이라는 int형 변수에 하나씩 값을 넣어주 것
- 따라서 foreach문은 값을 확인하거나 뽑아볼 때 주로 사용한다.
자바는 배열를 만들면 초기값이 0으로 고정된다.
정리
-
선언하는 방법
int arr[] = new int[10]; //기본적인 방법 int [] arr2 = new int[11]; //자바느낌
-
int -> 배열의 타입, arr -> 배열에 대한 레퍼런스변수, [] -> 배열 선언
그대로 해석하면 된다..!
2.1. 2차원 배열
int [][]arr = new int[3][4]; //3행 4열의 2차원 배열 생성
int []arr1 = arr[0]; //배열을 가르키는 레퍼런스 변수
- 접근하는 방법은 c언어와 동일하지만 동적으로 만들어진다는 점이 다르다..!
public static void main(String[] args){
int [][]arr = new int[3][];
arr[0] = new int[5];
arr[1] = new int[2];
arr[2] = new int[3];
}
- 위 코드처럼 동적할당의 이점을 이용해 c언어 처럼 각각 동적할당이 쉽게 가능하다..!
그렇다면 이러한 2차원배열을 foreach문으로 접근할 때는 어떻게 접근할까?
public static void main(String[] args){
int [][]arr = new int[3][];
arr[0] = new int[5];
arr[1] = new int[2];
arr[2] = new int[3];
for(int [] subArray : arr)
for(int elem : subArray)
System.out.println(elem);
}
- 배열을 가르키는 레퍼런스 변수를 이용하여 각각에 접근이 가능하다..!
3. 🔥 객체지향
지금까지 다뤄온 c언어 즉, 절차지향형 프로그래밍은 위에서 아래로 순차적으로 이루어지는 구조였다.
- 객체지향은 하나의 부품, 물건, 객체로 보고 그 객체간의 연결관계로 프로그램이 돌아가는 것을 말한다.
크게 3가지 특성을 가진다
캠슐화,상속,다형성
간단한 예
집이 하나의 프로그램이라고 본다면 안에는 다양한 객체들이 존재 나, TV, 카메라, 책상 등등..
- 물건 하나하나가 각각 객체로 보고 그러한 객체들로 완성된게 나의 집이라고 할 수 있다 이때, 나의 집에서 큰 티비가 존재하는 집 으로 바꾸고 싶다면 TV객체만 교체하면 된다.
캡슐화
자바의 첫번 째, 특성 매우 중요..!
만약 TV를 예로 든다면 우리는 TV가 작동의 유무는 알지만 어떻게 작동하는지는 모른다.
- 이러한 보완성을 띄는것을 캡슐화라고 한다. (클래스 내부를 숨기는 행위)
객체를 캡슐로 감싸서 내부를 볼 수 없게 하는것..!
또한 굳이 공개하지 않아도 되는 정보들을 숨기는 것.. 만약 공개한다면 프로그램이 위험해질 수 도 있기 때문에 내부에서 숨겨놓는 것을 말한다.
클래스
위에서 말한 캡슐화를 자바에서는 클래스를 이용하여 구현한다.
클래스 내부에는 필드(멤버 변수), 메서드(멤버 함수)가 존재하며 이를 은닉하는 것을 캡슐화라고 한다.
클래스란?
- 객체 모양을 선언한 틀! (많이 드는 예시로 붕어빵틀이 있다.)
이러한 클래스로 만든 것(instance)이 바로 객체이다.
상속
객체지향의 두번째 특성인 상속은 하위 객체가 상위 객체의 속성을 가지는 관계이다.
간단한 예를 들어 생물->동물->인간 이러한 순으로 상속 받는다고 생각한다면 인간이라는 클래스는 생물의 모든 속성을 가지고 있다.
-
또한 인간은 생물, 동물에서 좀더 구체화, 확장된 개념으로 상속을 거듭할 수록 좀더 확장된다.
-
한가지 더 예를 들어 생물에 한가지 기능이 더 추가된다면 생물을 상속 받은 클래스는 전부 같은 기능이 업데이트되어 매우 간편해진다..!
다형성
객체지향의 세번째 특성인 다형성은 같은 이름의 메서드가 클래스나 객체에 따라 다르게 동작하도록 구현하는 것을 말한다.
- 오버로딩이나 오버라이딩이 여기에 해당한다..!
만약 생물, 동물, 인간에 각각 메서드에 먹기()라는 메서드 (생물로 부터 상속받은)가 있다면 각각 동물, 인간은 그 메서드를 오버라이딩하여 자신에 맞게 구현하였을 것..!
- 이 때 동일한 메서드를 실행하면 각각 클래스에 맞게 다른 모습으로 메서드가 실행된다.
객체지향의 목적
객체지향이 등장하게 된 배경은 80->90년대로 넘어오면서 개인컴퓨터가 보급되며 자리잡히게 된 개념이다.
특징
- 재사용과 부분수정이 빠름 -> 위에서 말한 3가지 특성 덕분(캡슐화, 상속, 다형성)
- 소프트웨어을 다시만드는 부담x -> 동일
- 소프트웨어 생산성 향상
3.1. 클래스 생성
class MyCircle{
double radius; //필드
String name;
void print(){ // 메서드
System.out.println("name : "+name+"r : "+radius);
}
}
public class App {
public static void main(String[] args) throws Exception {
MyCircle a; //이 변수는 MyCircle로 생성된 객체를 가르키는 레퍼런스 변수이다. 포인터처럼 동작 따라서 직접 사용하고 싶다면 객체화(instance)해줘야함
MyCircle b = new MyCircle(); // 객체화(동적할당)이 이루어 진다. 즉, 메모리공간이 잡힘
a = b; // b와 동일한 곳을 가르키게 된다.
a.name = "fkdl"; // 해당 필드를 직접 참조 가능
a.radius = 3.14;
a.print();
}
}
- 가장 낮은 수준의 캡슐화를 구사하는 기본적인 클래스이다.
- 기본형 변수는 생성 즉시 메모리를 할당하지만 레퍼런스형 변수는 동적할당을 통해 메모리를 줘야함
반드시 new키워드를 통해 생성해야지 메모리가 잡힌다.
3.2. 캡슐화를 도와주는 장치들
지금까지 배운 개념들이 객체지향의 기본 개념들이다. 앞으로 배우게 되는 내용들은 앞서 배운 내용들을 유연하게 연결 시켜주는 개념들이다..!
생성자
생성자는 기본적인 메서드 장치이며 여러가지 규칙이 존재한다.
생성자의 기본적인 목적은 초기화이다.
- 중요한 요점은 다른 사람이 내가만든 클래스를 사용할 때 강제하는 강력한 조건이나 해야하는 것들을 생자에 넣어서 실수를 줄여줄 수 있다.
- 생성자는 기본적으로 클래스 이름과 동일한 이름을 가져야한다.
- 리턴값이 존재하지 않음
- 여러개가 존재 가능하고 인자를 받거나,안받거나가 가능하다.(오버로딩)
class MyCircle{
double radius;
MyCircle(){ //디폴트 생성자 / 아무 인자값없이 생성할 경우 실행
radius = 1.0; //초기화
}
public void print() {
System.out.println("radius : "+radius);
}
}
public class App {
public static void main(String[] args) throws Exception {
MyCircle a = new MyCircle(); //위에서도 계속 생성자를 호출하고 있었던것 지금은 사용자가 직접 정의한 경우
a.print(); // 따로 필드 수정없이 찍어도 이미 1.0값이 들어가 있음
}
}
-
생성자는 반드시 호출되며 객체를 생성할 때 딱 한번 호출된다..! 이후에
a.MyCircle()
오류처리 -
따라서 객체가 생성될 때 꼭 수행해야 하는 작업들을 넣어서 처리가 가능하다..!
생성자 오버로딩
class MyCircle{
double radius;
MyCircle(){ //디폴트 생성자
radius = 1.0;
}
MyCircle(double radi){ //생성자 오버로딩
if(radi < 0) radi = 0; // 생성자 안에서 조건문 가능..
radius = radi;
}
public void print() {
System.out.println("radius : "+radius);
}
}
- 위 코드처럼 인자값에 따라 오버로딩이 가능하다..!
주의
만약 디폴트 생성자를 만들지 않고 인자값을 필요로 하는 생성자만 만들었다면 디폴트로 객체화를 막을 수 있다.
- 클래스를 만든 사람이 일부러 디폴트로 생성하지 못하게 막아두는 경우가 이런 방식에 해당된다.(캡슐화)
this
this키워드는 자기 자신을 참조할 때 사용하는 키워드 이다.!
사용 용도
- 객체의 멤버변수와 메서드의 변수이름이 같을 때
- 다른메서드 호출 시 객체 자신의 레퍼런스를 전달할 때
- 메서드가 객체 자신의 레퍼런스를 반환할 때
- 예를 들어 클래스 내에서 다른클래스의 메서드를 호출(이 메서드는 현재 메서드를 사용)하여 자기자신의 객체가 필요한 메서드를 작성할 때 this를 통해 자신을 반환가능하다.
기본적으로 생성자는 다른 생성자에서 호출이 불가능하다.
- 하지만 예외적으로 this키워드를 통해 호출이 가능하다..!
class MyCircle{
double radius;
String name;
// MyCircle(){ //디폴트 생성자
// radius = 1.0;
// }
// 디폴트 생성자를 주석처리 함으로 인자값입력을 강제함
MyCircle(double radi){ //메서드 오버로딩을 통해 동일한 코드를 줄임 또한 한가지 생성자만 업데이트 해도 자동으로 연동됨
this(radi, "이름 없음"); //this명령어는 생성자 바로 밑에서 호출해야함
}
MyCircle(double radi, String na){
if(radi<0) radi = -radi;
radius = radi;
name = na;
}
public void print() {
System.out.println("radius : "+radius);
}
}
- 이 처럼 this명령어는 생성자를 호출하는 예외적인 경우에 사용가능하다.(코드 재사용을 줄임)
- 아무 생성자를 생성하지 않으면 컴파일러는 보이지 않는 기본생성자를 생성해줌
3.3. 레퍼런스 변수
public class App {
public static void main(String[] args) throws Exception {
MyCircle a = new MyCircle(10.32);
MyCircle b;
b = a;
b.print();
}
}
- 여기서 b는 레퍼런스 변수 즉, 주소값을 가르키는 변수로 사용된다.
내부의 모습은 지금 a와b가 같은 주소값을 참조중..!
따라서 b로 수정해도 a가 수정된다.
a = b가 copy가 아니라 같은 주소 참조라면 copy는 어떻게 하는지?
-
새로운 객체를 생성헤서 필드값을 하나하나 넘겨주는 방법
-
객체를 복사하는 생성자를 미리 정의
- 1번 방법은 하드 코딩의 느낌이 많이 들고 번거롭기 때문에 2번을 사용한다.
MyCircle(MyCircle in)
{
radius = in.radius;
name = in.name;
}
- 객체를 받는 생성자를 만들어 복사과정을 진행! (깊은 복사)
가비지 컬렉션 기본 개념
위에서 작성한 얕은 복사 즉, 메모리 참조의 개념을 보면 원래 b가(new로 생성되었다는 가정하에)가리키던 객체는 더이상 찾을 수 없게 된다.
- 이를 c언어에선 메모리 누수라고 하는데 자바에선 가비지컬렉션라는 놈이 알아서 메모리 해제작업을 진행해준다.
우리에겐 보이지 않지만 객체를 생성할 때마다 레퍼런스 카운팅이라는 것이 생긴다.
- 이 때, 그 객체를 가르키는 레퍼런스 변수가 한개당 +1씩 증가되게 되는데 만약 아무것도 가르키는 게 없는 객체는 소실(가비지 발생)되었다고 말할 수 있다.
즉 정리하자면 위에 코드를 예로 들어 a의 레퍼런스 카운트는 2가되고 b는 0이된다.
댓글남기기