http://trypsr.tistory.com/74

에서 아주 잘 정리하셨길래 퍼왔음.

 

테스트 없이 눈으로만 코딩할 때 가장  쉬운 부분이 call by value 와 call by refence 를  이해하지 못할 때 생기는 오류가 아닐까 싶다.

기본형과 객체가  기본형은 call by value 이고 객체는 call by refence 라는  대부분의 java 개발자들이 알고 있을꺼라 생각한다.

그 예로 swap  가장 많이 설명하는데..

예제 1) 

class Test {
    private static void swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    }

    public static void main(String args[]) {
        int a = 1;
        int b = 2;

        System.out.println("a => " + a);
        System.out.println("b => " + b);

        swap(a, b);

        System.out.println("------- swap 후 -------");

        System.out.println("a => " + a);
        System.out.println("b => " + b);
    }
}

예제 1 의  원하던 결과가 아닌 것을 바로 알아 낼 수 있을 것이다.
 메소드에 넘기는 것은 reference 가 아닌 value 이기 때문에...
쉽다.  

다음 예제 2 를 보자
예제 2)

class Test {
    private static void swap(Integer a, Integer b) {
        Integer temp = a;
        a = b;
        b = temp;
    }

    public static void main(String args[]) {
        Integer a = new Integer(1);
        Integer b = new Integer(2);

        System.out.println("a => " + a.intValue());
        System.out.println("b => " + b.intValue());

        swap(a, b);

        System.out.println("------- swap 후 -------");

        System.out.println("a => " + a.intValue());
        System.out.println("b => " + b.intValue());
    }
}

예제 2  경우 Integer 는 Object 이다. Object 는 call by reference  
따라서 위의 예제는 원하는 결과를 가져올 것이다.
그러나 실행을 하면 예제 1과 전혀 다르지 않다는 것을 알  있다.

왜? 객체는 call by reference 라며 사기친거야?

 말하면 객체는 call by reference 맞다

그러나 해당 객체를  새로운 reference 를 참조해서 넘기는 것이다.

따라서 동일한 객체를  있지만 
main 에서의 reference 값과 swap 함수에서의 reference 값은  

따라서 위의 예제의 경우 원하는 결과가 나오지 않는다.

  이부분이 가장 이해가 힘들었는데, 즉 메소드에서 변수의 주소를 받았다 하더라도 실제 메소드 안에서 실행될때는 지역변수일 뿐입니다. 즉, 메소드를 벗어나게 되면 영향력이 없어지는 것이죠..

그래서 영향력이 있을때인 메소드 안에서 직접 그 주소의 값을 변경하면 영향을 받지만, 그런것이 아닌 단순한 주소의 복사는, 그 메소드 안에있는 지역변수의 변화일 뿐 실제 값에는 영향이 없습니다.


 어떻게 해야 해?

예제 3 을 보자.

예제 3)

class Test {
    int value;

    Test(int value) {
        this.value = value;
    }

    private static void swap(Test a, Test b) {
        int temp = a.value;
        a.value = b.value;
        b.value = temp;
    }

    public static void main(String args[]) {
        Test a = new Test(1);
        Test b = new Test(2);

        System.out.println("a => " + a.value);
        System.out.println("b => " + b.value);

        swap(a, b);

        System.out.println("------- swap 후 -------");

        System.out.println("a => " + a.value);
        System.out.println("b => " + b.value);
    }
}

예제 2와 같이 객체의 reference 를 넘긴다.
reference 를 직접  게 아니라.
reference 가 참조하는 객체의 value 를 변경하고 있다.
 같은 객체를 보고 있는 main 에서도 값이 바뀌는 것을 알  있다.

call by reference

해당 객체의 주소값을 직접 넘기는 게 아닌 객체를 보는 또 다른 주소값을 만들어서 넘기다는 사실을 잊지 말자~

 

'Programming > JAVA' 카테고리의 다른 글

JAVA IO  (1) 2011.03.24
JAVA Threads  (2) 2011.03.24
The AWT Component Library  (1) 2011.03.24
The AWT Event Model  (0) 2011.03.24
Building GUIs & Java Graphics  (0) 2011.03.24

0. 메소드 3요소 : Return type, Method name, Parameter

 

1. 메소드의 접근

 1) Member Method, Instance Method : 멤버변수와 같은 개념

 2) Class Method, Static Method : 클래스변수와 같은 개념

 public class MethodTest{
 public static void main(String[] args) {
  MethodTest mt = new MethodTest();
  mt.display();
  display2();
  SubTest st = new SubTest();
  st.display3();
  SubTest2.display4();
 }

 void display(){  //Member Method, Instance Method
  System.out.println("Hello, World");
 }
 static void display2(){ //Class Method, Static Method
 System.out.println("Hello, World2");
 }
}

class SubTest{
 void display3(){  //Member Method, Instance Method
  System.out.println("Hello, World3");
 }
}

class SubTest2{
 static void display4(){  //Member Method, Instance Method
  System.out.println("Hello, World4");
 }
}

 

2. Method 호출

 1) Call by value

 public class MethodTest1{
 public static void main(String[] args) {
  int result, a, b; //argument
  a=10; b=50; 
  result = hap(a,b); 
  display(a,b,result);
  a=1; b=5;
  result = hap(a,b); 
  display(a,b,result); 
 }
 static void display(int a, int b, int result){
  System.out.println(a+"부터"+b+"까지합="+result);
 }
 static int hap(int start,int last){//parameter
  int sum = 0;
  for(int i=start ; i<=last ; i++ ){
   sum += i;
  }
  return sum;
 } 
}

 1. 합계를 출력하는 메소드에

시작값과 끝값의 입력을 받아 

각각 다른 결과값을 가져올 수 있다.

 2. 출력 메소드 역시 입력값에 따라 다른 출력을 가져올 수 있다.

 

 3. Call by value는 Value type이 대상이기 때문에 값복사를 하며, 별도의 공간 2개가 따로 만들어진다. 상대방에게 영향을 주지 않는다.

 

 2) Call by Reference

 public class MethodTest2{
 int a, b;
 public static void main(String[] args) {    
  MethodTest2 mt2 = new MethodTest2();
  mt2.a = 5; mt2.b=9;
  System.out.println("mt2.a="+mt2.a+"mt2.b="+mt2.b);  
  swap(mt2);
  System.out.println("mt2.a="+mt2.a+"mt2.b="+mt2.b);
 }
 static void swap(MethodTest2 mt){
  int tmp;
  tmp = mt.a; mt.a=mt.b; mt.b=tmp; 
 }
}

  생성자의 변수로 주소값을 넘겨준다.

 public class MethodTest3{
 public static void main(String[] args) {  
  int [] array = method();
  System.out.printf("%d, %d",array[0],array[1]);
 }
 static int[] method(){
  int[] array ={5,6};
  return array;
 }
}

  배열로 받는 방법.

 

 3)Varargs (Variable Arguments)

public class MethodTest4{
 public static void main(String[] args) {
  method(1,2,3,3,"string",'A',false);  //아무거나 넣어도 된다.
 }
 static void method(Object ... array){
  for (Object obj : array ){   
   System.out.print(obj + "\t");   
  }
 }
}

 

 Variable Arguments :  

 메소드에 인자값을 다양하게 (갯수/형) 주어도 메소드에서 입력받을 수 있다.

 배열처럼 사용하지만 배열이 아니라는의미인

... 을 사용하여 모든 형을 Object로 받는다.

 

 4) Recursive Methods (재귀 함수)

  - 굳이 반복문으로 표현 할 수 있는 것을 재귀함수로 사용하지말자. (메모리 사용량 증가)

 

 5) Method Overloading(오버로딩) (메소드 중복정의) //오버라이딩이랑 다르다.

  - 메소드의 이름이 같아도 입력 parameter가 다르면 사용 할 수 있다.

 public class MethodTest6{
 public static void main(String[] args) {
  display();
  display(3);
  display(3,5);
  display(3.4);
 }
 static double display(double a){  return 1.2;}
 static void display(int a){}
 static char display(int a, int b){ return 'A';}
 static void display(){}
}

 

 6) static Methods

  - 생성자 없이 클래스명으로 접근하기위해서

  - 왜 main ()는 static인가? : 생성자 없이 바로 main()를 실행하기 위해서.

 

 

 

ps-------------------------------------

-return 은 메소드의 끝을 의미하며, 그 뒤에는 문장이 올 수 없다. 하지만 조건문 속에서는 가능하다.(조건적 return)

 static void exampleMethod( ){
intsu;
//...
System.out.println("Hello");
if (su< 10)
return;
System.out.println("World");
}

 

-String 은 Call by value의 예외이다. (값을 바꿀 수 없다)

1. Unicode

 

2. ASCII Characters

 1) 기본적으로 알아야 할 코드값 : 48 (0), 57(9), 10(NewLine), 13(Carriage return)

 

3. Comment(주석)

 1) // 한줄

 2) /* 한줄 이상의 문장 */

 3) JavaDoc : JAVA를 HTML 문서로 만드는 것. (APIDoc의 문서처럼 작성 할 수 있다.)

   - /**  문서화 된 코멘트 **/

   - 설명할 코드 바로 위에 작성 할 것

   - 명령어

 $javadoc -author -version -d [.\경로][자바파일이름]  : 경로에 html파일이 생성된다.

   - Doxygen 툴을 사용하면 쉽게 html문서를 작성 할 수 있다.

 

4. Separators(구분자)

 - (). {}, [], ;, ,, .

 - Word < Statements < Block

 

5. 식별자

 - 클래스,메소드,변수명을 지정 할 수있다.

 - 첫 클래스는 영문자나 (_), ($)만 사용할 수 있다.

 - 길이 제한이 없긴 하다.

 

6. 키워드, 예약어

 - 특수한 목적을 사용하기위해 이미 정의가 된 단어.

 - const, goto 는 키워드에 등록되어 있지만 사용 할 수는 없다.

 - enum : 1.5버전 이상에서부터 사용 가능한 키워드.

 

7. 데이터 저장

 1) 비트

  - unsigned : 모든 비트를 데이터의 양수를 표현

  - signed : 비트 하나를 부호비트로 설정하여 1일 때 음수를 표현한다.

 2) 보수

  - 1의 보수 : 데이터 비트의 반전

  - 2의 보수 : 데이터 비트의 반전 +1

 3) 자료형

  i) 내장형(기본형) : Primitive type

 수치형

 true or false

 bloolean(1bit)

 문자형

 char(2byte)

 정수형

 byte(1byte)

 short(2byte)

 int(4byte)

 long(8byte)

 실수형

 float(4byte)

 double(8byte)

 무치형

 

 void()

 

   - 형변환 : 기본적으로 강제/자동 형변환이 일어나지만, 연산에 의해서는 자동형변환이 일어나지 않는다.

 short a = 5; // 정수 5는 자동으로 short로 형변환 되어진다

 short b = 10;

 short sum = a+b ; // 하지만 연산 과정인 a+b에서는 자동 형변환이 일어나지 않아 int형식으로 sum에 입력 되기 때문에 오류가 난다.

 

 정수는 기본적으로 int의 형을 갖고

 실수는 Double의 값을 갖는다.

 float f = 0.123456789123456789F;  // double형인 실수를 float로 형변환 하여 저장하게된다.
 double d = 0.123456789123456789; //기본으로 실수는 double형이기 때문에 double에 자동으로 맞추어 출력된다.

 

  - cast :

  - convert :

 

  ii) 외장형(추상형) : Reference type = Class, Interface, Enum

    (ps. C 언어의 외장형(추상형) : User-Defined type = 구조체(Struct), Union, Class, Pointer)

  - Heap 공간을 이용한다. (변수는 값을 갖는게 아니라 그 값의 주소를 갖는다.(integer변수와 같은 4바이트를 갖는다)) 

  - String은 new 없이 사용 할 수 있는  클래스이다. ( 많이 사용하기때문에 컴파일러가 대신 new를 만들어 준다.)

 정식적인 사용 방법 :

 String str = new String("Hello");

 축약 방법 :

 String str1 = "Hello";

  - call by value, call by reference value

  Value Copy

 public class ValueCopy{
 public static void main(String[] args) {
  Test t = new Test();
  t.su = 5;
  t.num= t.su; //값복사
  System.out.println("t.num="+t.num);
  t.su =100;
  System.out.println("t.num="+t.num);

 }
}

class Test{
 public int su, num;
}

  Reference Copy

 public class ReferenceCopy{
 public static void main(String[] args) {
  Demo d = new Demo();
  d.su = 5;
  Demo d1 = new Demo();
  d1 = d; //주소복사
  System.out.println("d1.su = "+d1.su);
  d.su=100; // d 가 가지고 있는 주소를 d1에게 주었기 때문에 값이 변한다.
  System.out.println("d1.su = "+d1.su);
 }
}

class Demo{
 public int su;
}

 

 4)포인터와 레퍼런스의 차이

  - 포인터는 변수 메모리의 절대번지를 접근한다.

  - 레퍼런스는 메모리에 접근을 할 수 없다. (그래서 JAVA에서는 디바이스를 직접 생성 할 수 없다.)

 

 5) 상수 (Constants)

  - 자바에서 상수는 final keyword를 갖는다.

  - 변수명은 대문자와 특수문자 (_)를 사용한다.

 

7. 이름 정하기 (Naming Conventions) : 권고 사항으로 개발자들이 개발할 때 더욱 편하게 이름을 작성하는 표기법

 1) Pascal casing (대문자 표기법)

  - class = 명사를 사용하며 2개 이상의 단어 합성 시 첫글자는 대문자.  

  - interface = 형용사형 이나 명사형을 사용한다.

  - 상수 = 모두 대문자를 쓰며 2단어 이상 합성할 때 사이에 (_)를 쓴다.

 2) Camel casing (소문자 표기법)

  - Method = 소문자로 동사형을 사용한다. 2개 이상 합성단어의 첫문자는 대문자.

  - 변수명 = 소문자 명사형

 

 

 

--------------------------------------------------------------------------------------------------------

 - UNC = 윈도우에서 네트워크 상의 컴퓨터에 접근하기위해 사용하는 ID (LAN 환경 안에서만 사용 가능하다)

 - vachar 와 char : 메모리 용량의 사용을 줄이기 위해 가변적인 공간을 저장하였지면 현재는 메모리의 용량보다 속도가 더 중요하기 때문에 작은 데이터를 저장하더라도 char를 사용하는게 더 빠르다.

 - Stack 영역에서 Heap영역으로 옮기는 것을 boxing이라 하고, 그 반대 과정을 unboxing이라고 한다.


'Programming > JAVA' 카테고리의 다른 글

자바 배열이란?  (2) 2011.03.24
자바 제어문(조건/반복/분기)  (2) 2011.03.24
JAVA 문법과 연산자  (2) 2011.03.24
JAVA의 특징과 설치  (2) 2011.03.24
자바(JAVA)란?  (1) 2011.03.24

+ Recent posts