함수(메소드)의 (인자)호출 방식은 

Call by value

Call by reference

두 개가 있다. 말그대로 '값에 의한 호출' , '참조에 의한 호출' 이다. 

기본 타입이 인자로 전달되는 경우

byte, char, int double 등 자바의 기본 타입이 인자로 전달되는 경우에는 호출자가 건네는 인자의 값을 복사하여 메소드의 인자에 전달한다. 

public class Test {
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int num1 = 10, num2 = 20;
		
		System.out.println("num1 = " + num1);
		System.out.println("num2 = " + num2);
		swap(num1, num2);
		System.out.println("swap");
		System.out.println("num1 = " + num1);
		System.out.println("num2 = " + num2);
	}
	
	static void swap(int num1, int num2) {
		int temp;	
		temp = num1;
		num1 = num2;
		num2 = temp;
	}
}

결과는

num1 = 10
num2 = 20
swap
num1 = 10
num2 = 20

메소드 swap을 썻음에도 불구하고 num1,2값은 변화가 없다. 메소드 안에서 위치를 바꾼다고 해서 원본 데이터가 바뀌는 것이 아니라는 것을 알 수 있다. 위 코드 메소드 내에서 두 수를 바꾸는 것은 단지 복사된 값을 바꾸는 것이다. 따라서 자바는 기본 데이터 타입이 인자로 전달되는 경우는 Call by value(값에 의한 호출)로 처리된다.

Call by value(값에 의한 호출)

Call by value(값에 의한 호출)는 메소드 호출 시에 사용되는 인자의 메모리에 저장되어 있는 값을 복사하여 보낸다.

객체 레퍼런스가 인자로 전달되는 경우

메소드 인자로 객체에 대한 레퍼런스가 전달되는 경우 객체가 통으로 전달되는 것이 아니고 레퍼런스 값만 복사되어 전달된다. 이런 경우는 커스텀 클래스를 사용한다.

public class Test {
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		NumberClass num1 = new NumberClass(10);
		NumberClass num2 = new NumberClass(20);
		
		System.out.println("num1 = " + num1.num);
		System.out.println("num2 = " + num2.num);
		swap(num1, num2);
		System.out.println("swap");
		System.out.println("num1 = " + num1.num);
		System.out.println("num2 = " + num2.num);
	}
	
    
	static void swap(NumberClass num1, NumberClass num2) {
		int temp;	
		temp = num1.num;
		num1.num = num2.num;
		num2.num = temp;
	}
}

class NumberClass {
	int num;
	
	NumberClass (int num) {
		this.num = num;
	}
}

결과는

num1 = 10
num2 = 20
swap
num1 = 20
num2 = 10

위 코드에서는 참조값을 직접 바꾼것이 아니라 객체의 참조값을 통해 그 객체의 멤버변수에 접근해 값을 바꾼것이다. 힙영역에서 참조 되어지는 값 자체를 바꾸어 call by reference 처럼 보이게 한것이다. 중요한 것은 자바에서 메소드 호출 시 객체가 전달되는 경우 객체에 대한 레퍼런스만 복사되지 객체가 통째로 복사되지 않는다는점이다.

Call by reference(참조에 의한 호출)

Call by reference(참조에 의한 호출)는 메소드 호출 시 사용되는 인자 값의 메모리에 저장되어 있는 주소를 복사해 보낸다.

배열이 인자로 전달되는경우

배열이 메소드의 인자로 전달되는 경우도 객체 레퍼런스가 인자로 전달되는 경우와 동일하다. 배열이 통째로 전달되는 것이 아니라 배열에 대한 레퍼런스만 전달된다.

 

결론은 자바는 기본형 타입 변수와 참조형 타입 변수 둘 다 Call by value 방식으로 받는다. 하지만 기본형 타입은 그 값을 복사해서 넘겨주지만 참조형 타입은 레퍼런스를 복사해서 넘겨주는 차이가있다.

객체 지향 언어

객체 지향 언어가 출현할 당시 가장 범용적으로 사용되는 언어는 절차 지향 언어였다. 객체 지향 언어는 절차 지향 언어의 단점을 보안고 다음 목적을 달성하기 위해 탄생했다.

- 소프트워어의 생산성 향상

 객체 지향 언어는 상속, 다형성, 객체, 캡슐화 등 소프트웨어의 재사용을 위한 여러장치를 내장하고 있다.

- 실세계에 대한 쉬운 모델링

 컴퓨터의 발전에 따라 실세계에서 발생하는 일을 프로그래밍해야 할 일이 더욱 많아지게 되었다. 객체의 속성과 행위를 묘사하고 객체 사이의 상호작용을 표현하는 방법으로 효과적인 프로그래밍을 할 수 있게 한다.

 C언어처럼 위에서부터 아래의 방향으로 절차대로 명령어를 실행하는 프로그램을 절차 지향 프로그램이라고 부르며 이런 언어를 절차 지향 언어라 한다. 이런 언어들은 흐름도를 설계하고 흐름도에 맞게 프로그래밍 함으로써 일련의 동작들이 순서에 맞게 실행되도록 작성한다.

 그러나 실제 세상은 각 물체 간의 관계, 상호 작용 등 훨씬 복잡하게 구성되어있다.이에 등장한 객체 지향 프로그램은 보다 실제 세상에 가깝게 모델링하여 물체를 객체로 표현한다.

객체지향 언어의 특성

-캡슐화

-상속

-다형성

-캡슐화(Encapsulation)

 캡슐화란 객체를 캡슐로 싸서 그 내부를 보호하고 볼 수 없게 하는것을 말한다. 자바에서 객체는 메소드(함수)와 필드 (데이터 변수)로 구성된다. 클래스라는 캡슐을 사용하여 객체를 표현하며 메소드(method)와 필드(field)를 클래스 내에 구현한다. 이렇게 함으로써 객체 외부에서는 객체 내의 숨겨놓은 메소드나 필드를 직접 접근할 수 없으며 메소드의 구현 내용도 알 수 없다. 몇몇 메소드와 필드는 객체 외부와의 인터페이스를 위해 노출된다.

 캡슐화의 목적은 객체 내 데이터에 대한 보안, 보호, 외부 접근 제한등을 위한것이다. 이때 외부에서 클래스 내부의 데이터 접근을 금지하는 것을 정보 은닉화라고 한다.

-상속(Inheritance)

 상속은 상위 개체의 속성이 하위 개체에 물려져서, 하위 개체가 상위 개체의 속성을 모두 가지고 있음을 의미한다. 예시로 동물은 생물의 속성을 갖고있고, 사람은 동물의 속성을 가지고 있다. 자바로 바꿔보면 동물은 생물의 부모 클래스이고 생물은 자식 클래스이다.

 자바에서 상속은 부모 클래스 즉 슈퍼 클래스(super class)를 자식 클래스 서브 클래스(sub class)가 상속받는것을 말한다. 상속은 이미 만들어진 클래스의 필드와 메소드를 물려받게 함으로써 자바 코드의 중복 작성을 방지하며, 코드의 재사용을 가능하게 한다.

-다형성(Polymorphism)

 다형성은 같은 이름의 메소드 호출에 대해 객체에 따라 다른 동작을 할 수 있도록 구현되는 것을 의미한다. 동물의 소리내기를 예로 든다면 개,고양이가 동물의 서브 클래스라 했을때 각각 개는 멍멍, 고양이는 야옹 하는 소리를 냈을 것이다. 이유는 개 고양이에 구현되어있는 소리내기는 각각 서로 다르기 때문이다. 이는 오버라이딩과 밀접한 관련이 있는데 오버라이딩은 다음에 오버로딩과 다시 다루겠다.

클래스와 객체 + 인스턴스

클래스는 객체들이 어떤 특성을 갖는다고 정의만 할 뿐 값을 가지지 않는다. 또한 객체의 행동에 대한 절차나 방법을 정의할 뿐 실제 행동을 하지않는다. 즉 클래스는 객체를 생성하기 위한 설계도 또는 틀이라 생각할 수 있다. 객체는 설계도 또는 틀로 찍어낸 실체라고 볼 수 있다. 이러한 이유로 객체를 클래스의 인스턴스 라고 부른다.

클래스 와 객체

클래스는 설계도 객체는 설계도로 구현한 모든 대상을 의미한다.

객체 와 인스턴스

클래스의 타입으로 선언되었을 때 객체라고 부르고, 그 객체가 메모리에 할당되어 실제 사용될 때 인스턴스라고 부른다.

객체는 현실 세계에 가깝고 인스턴스는 소프트웨어 세계에 가깝다.

엄격하게 객체와 인스턴스를 나누는것은 어렵다. 그래서 객체와 인스턴스 두 용어를 구별없이 사용한다.

클래스 구성

public class Person{ //클래스에 대한 접근 권한 - 키워드 - 클래스 이름
    public String name; //필드
    public int age;     //필드
    
    public Person(){ // 생성자(default)
    }
	public Person(String s){ // 생성자2
    	name = s
    }
    public String getName(){ //메소드
    	return name;
    }
}

위 코드가 기본적인 클래스의 구성이다. 이제 이 클래스로 객체를 생성해 보자.

객체 생성과 레퍼런스 변수

public static void main (String args[]){
   Person men;					// 객체에 대한 레퍼런스 변수 men선언
   men = new person("sejun");	// new 연산자 사용 person 객체 생성
   
   men.age=27;					//.을 이용해 객체 멤버 접근
   String s = men.getName();
}

위 코드는 객체를 생성하고 .을 이용해 객체 멤버에 접근하는 것을 보여준다.

Person men;  먼저 Person이라는 클래스의 레퍼런스 변수 men을 생성 했다. 객체를 생성할 때는 먼저 객체를 가르킬 레퍼런스 변수의 선언이 필요하다. men은 레퍼런스를 가지는 변수일 뿐 객체는 아니다.

자바에서는 반드시 new 연산자를 사용하여 객체를 생성해야 한다.

men = new person("sejun"); 이 문장의 실행 결과는

- Person 타입의 객체 메모리 공간 확보

- Person(String s){..} 생성자2가 실행되어 name 필드의 값을 "sejun"으로 설정

한것이다. 그럼 객체 men이 만들어진 것이다.

객체 멤버 접근

객체 멤버에 접근할 때는 점 . 연산자를 붙인다. men.age = 27; 은 men객체의 age필드에 27을 대입한 것이고, String s = men.getName(); 는 men객체의 getName() 메소드를 호출한 것이다.

main()

main() 메소드는 자바에서 응용프로그램이 시작되는 메소드로서 특별한 의미를 가진다.

public static void main(String[] args){ 
}

원형은 이러하다. main() 메소드의 타입과 특징은

-자바 응용프로그램 실행은 main() 메소드부터 시작한다.

-main() 메소드는 public 속성이다. : 자바 가상 기계(JVM)에 의해 호출되어야 하므로 public 속성이다

-main() 메소드는 static 속성이다. : 클래스의 인스턴스(객체)가 생성되기 전에 호출되므로 static 속성이다.

-main() 메소드의 리턴 타입은 void 이다. : 아무 값도 리턴하지 않기 때문에

-main() 메소드는 인자는 무자열 배열(String [])이 전달된다. 

main() 메소드에 인자 전달

main() 메소드에서 받은 인자값은 args 배열을 통해 들어온다.

public class MainTest { 
     
     public static void main(String[] args) { 
           
           for(int i=0; i < args.length; i++) { 
                System.out.println("args[" + i + "] = " + args[i]);             
           }
           
     }
}

이렇게 되면 아무것도 넣지 않았기 때문에 출력값이 없지만 args 배열에 값을 넣어주면 문자형배열과 같이 출력된다.

예외

예외 : 프로그래밍 언에의 문법에 맞지 않게 프로그램을 작성하면 컴파일 오류(compile time error)가 발생한다. 그러나 프로그램 실행 중 계속 변하는 배열의 인덱스가 범위를 벗어나는 것은 컴파일 시점에서 걸러낼 수 없다. 이처럼 프로그램 실행 중 발생하는 런타임 오류(run time error)는 미리 걸러낼 수가 없어 자바에서는 예외(exception)를 사용해 처리한다. 대표적인 예외들이 아래 표에 있다.

예외 종류 예외 발생 경우
ArithmeticExecption 정수를 0으로 나눌 때 발생
NullPointerExecption null 래퍼런스를 참조할 때 발생
ClassCastExecption 변환할 수 없는 타입으로 객체를 변환할 때 발생
OutOfMemoryError 메모리가 부족한 경우 발생
ArrayIndexOutOfBoundsExecption 배열의 범위를 벗어난 접근 시 발생
IlleagalArgumentExecption 잘못된 인자 전달 시 발생
IOEExecption 입출력 동작 실패 또는 인터럽트 시 발생
NumberFormatExecption 문자열이 나타내는 숫자와 일치하이 않는 타입의 숫자로 변환 시 발생

예외 처리, try - catch - finally

예외 처리란 발생한 예외에 대해 개발자가 작성한 프로그램 내에서 대응하는 것을 말한다. 자바에서 예외 처리 시 try - catch - finally 문을 사용한다.

try{
	 예외가 발생할 가능성이 있는 실행문 (try 블록)
}
catch(처리할 예외 타입 선언){
	예외 처리문 (catch 블록)
}
finally{
	예외 발생 여부와 상관없이 무조건 실행되는 문장(finally 블록)
}//finally블록은 경우에 따라 생략이 가능하다.

try 안의 실행문에서 예외가 발생할 경우 catch문으로 이동하고 발생하지 않으면 finally 문아래 코드를 계속 실행한다.

배열이란?

배열(array)은 인덱스(index)와 인덱스에 대응하는 데이터들로 이루어진 자료구조

배열을 사용하는 큰 이유 중 하나는 반복문의 활용에 있다.

배열의 선언 및 생성

자바의 배열생성에는 두가지 단계가 필요하다.

(1) 배열에 대한 레퍼런스 변수 선언

(2) 배열 생성

배열 공간을 가르키기 위한 레퍼런스 변수 선언하는 단계(1)과 배열 공간을 할당하는 단계(2)로 구분된다.

(1) 배열에 대한 레퍼런스 변수 intArray 선언

int intArray []; // 순서대로 배열타입- 배열에 대한 레퍼런스 변수 - 배열선언

(2) 배열 생성

intArray = new int [5]; //배열에 대한 레퍼런스변수- 배열생성 - 타입 - 원소 개수

위 과정을 그림으로 나타내면

그림[4-1]

그림[4-1]과 같이 나타난다.

여기서 래퍼런스 변수는 intArray를 나타낸다. 레퍼런스 변수를 설명하기 위해선 인스턴스(instance)의 정의가 필요하다.

클래스를 사용하기 위해서는 반드시 메모리에 생성해 주어야 한다. 이렇게 메모리상에 생성된 클래스를 객체 혹은 인스턴스라고 부른다. 레퍼런스 변수메모리상에 생성된 인스턴스를 카리키는데 사용되는 변수이다. 위 그림에서 점으로 표현된 부분이 인스턴스이고 intArray가 해당 인스턴스를 가르키는 레퍼런스 변수인것이다. 모든 인스턴스는 레퍼런스 변수만을 통해서 사용이 가능하며, 일반적인 데이터를 넣어두는 변수가 아니고 인스턴스를 가르키는 값이다. 또한 레퍼런스 변수 . 을 이용해 인스턴스의 맴버 변수나 메소드를 사용할 수 있다.

배열참조

배열의 선언과 생성은 별개이다. 그러므로 한개의 배열을 다수의 레퍼런스가 참조할 수 있다.

 

그림[4-2]

그림[4-2]와 같이 각각 다른 레퍼런스 변수인 intArray와 myArray가 하나의 배열을 참조했다. 각각 배열의 인덱스를 참조할 수 있으며 변경시에 나중에 기록된것으로 바뀐다.

배열 원소 접근

배열의 원소에 대한 접근은 배열 레퍼런스 변수인덱스를 이용한다.

원소에 대한 인덱스는 0부터 시작한다.

int arr[] = new int[3];
arr[0] = 51;
arr[2] = 24;
int n = arr[2]; // 라고 했을때 n 의 출력 값은 24가 된다.

배열의 인덱스(index)는 정수만 가능하며 정수형 상수도 사용할 수 있다. 인덱스는 0부터 시작하며 마지막 원소의 인덱스는 (배열의 크기 -1)이 된다. 자바에서는 배열도 하나의 객체 처럼 다루어진다. 따라서 .length() 를 이용해 배열의 길이를 알고자 할때 사용한다.

int arr[];
arr = new int[31];

int arrSize = arr.length; // arrSize의 출력값은 31

for- each 문

for문을 변형해 배열이나 나열의 각 원소를 순차적으로 접근하기 편한 반복문이다. 반복 횟수는 지정한 배열의 인덱스 만큼이다.

String name[] = {"a","s","d","f","q"};
for(String s : name){
	System.out.printf(s);
}
//결과 값은 asdfq 총 for-each문은 5번 반복했다.

2차원 배열

2차원 배열은 1차원 배열을 겹쳐놓은 모양으로 선언은 다음과 같다

int arr1[][];
float arr2[][];

1차원 배열과 마찬가지로 레퍼런스 변수 선언 후 배열을 생성해야 한다.

arr1 = new int[4][2];
arr2 = new float[6][3];

메소드에서 배열 리턴

메소드에서 배열을 리턴할 수 있다. 이 경우 실제 배열에 대한 레퍼런스가 리턴된다. 메소드가 리턴하는 배열 타입과 배열의 차원은 리턴받는 배열 레퍼런스 변수의 타입과 배열의 차원에 일치해야 한다. 메소드 선언 시 배열의 크기는 매번 다를 수 있으므로 배열의 크기는 정하지 않는다.

int[] makeArr(){
    int temp[] = new int[4];
    return temp;
}

+ Recent posts