기본적인 윈도우 환경에서의 데이터 정렬(Data alignment)은 4byte를 기준으로 이루어지게 된다.

struct A

{

    char a;

    short b;

};

위와 같은 구조체가 있다. 윈도우에서는 어떻게 메모리를 잡을까 생각을 해보자.

윈도우는 4byte가 가장 작은 메모리 할당량이다. 그러므로 어떠한 변수 하나를 잡기 위해서 4byte를 기준으로 계산하게 된다.

short = 2byte, char = 1byte이므로 4byte를 할당 받아 short을 먼저 2byte 할당하고 남는 2byte에 char를 할당하게 된다.

즉, 3byte를 사용하기 위해서 4byte의 메모리를 사용하게 되는 것이다.

 

하지만, 한가지 고려해야하는 부분은 컴파일러에 있다. Visual Studio는 기본적으로 8byte를 사용한다.

위 구조체를 할당하기 위해서는 8byte가 필요하게 되는 것이다.

 

#pragma pack(push, 1)

구조체

#pragma pack(pop)

 

위와 같은 방식으로 선언을 해준다면, Data alignment가 변하게 되는 것이다.

위의 선언은 데이터 정렬 기준은 1byte로 한다는 것이다.

즉, struct A는 위의 환경에서는 3byte만이 필요하게 되는 것이다.

메모리가 필요할 경우 무조건 1byte씩을 할당을 하게 되므로 불필요한 공간이 없이 필요한 공간만을 할당하게 되는 것이다.

 

#pragma pakc(pop)을 하지 않을 경우는 #pragma pack(push, 1)로 선언된 이후의 부분은 전부 적용이 되는 것이다.

이것에 신경을 잘 쓰지 않으면 프로젝트가 엉망이 될 수 있다. 주의!!!!

예) 프로젝트 중간에 pack을 했다면 같은 값을 pack이 된 곳과 안된곳의 값이 다르게 표현이 되게 된다.

      이유는 구조체 자체의 메모리 할당이 서로 다르기 때문에 생기게 되는 곳이다.

 

가장 유용하게 사용되는 부분은 네트워크 통신에 사용되는  packet을 정의할 때 가장 유용하게 사용된다.

network packet은 서버 클라이언트에서 같이 사용하기 때문에 문제가 되는 점은 발견되지 않으며, network packet의 사이즈를 적절하게 해주기 때문에 더욱 유용한 것이다.

 

추가)

#pragma warning(disable:4996)

...

#pragma warning(default:4996)

이는 컴파일 단계에 발생되는 단순한 warning을 무시하는 기능을 한다.

crt function을 사용하거나 하는 등의 단순한 warning에서만 사용을 해야함...

처음 disable에서는 무시를 하게 되고, default에서는 다시 원상태로 변경을 하게 된다.


Posted by 모과이IT
,
안드로이드 인터페이스에 관한 프로그래밍을 하다보면 종종 '120dp', '100px' 등등 이런 저런 치수에 관한 내용을 접하게 된다.
이번엔 그런 치수에 대해서 정확히 짚어보고 넘어가도록 하자.

 


Posted by 모과이IT
,
안드로이드 화면을 구성 할 때 사용할 수 있는 요소는 매우 많다.
이 요소들은 View 클래스를 상속하고 있으며, 이러한 클래스들을 위젯(Widget)이라고도 부른다.
ViewGroup 클래스를 상속하고 있는 요소들은 다른 인터페이스 요소들을 포함 할 수 있다.
Layout이라고 명명된 클래스를 배치 관리자(Layout manager)라고 한다.


Posted by 모과이IT
,

액티비티의 생명주기에 따라 적절한 메소드가 호출되므로 이를 숙지해서 액티비티를 작성해야 한다.

 

 

Posted by 모과이IT
,

안드로이드 어플리케이션을 개발하기 위해선 자바XML을 다룰 수 있어야 한다.

 

안드로이드 프로젝트를 생성하면 아래와 같은 패키지들과 자바 파일 그리고 XML파일이 생성된다.

기본 자바와는 다르게 너무나도 많은 것들이 생성되어 혼란을 일으킬 수도 있으나

각각의 역할을 생각하면서 차분하게 짚어 본다면 쉽게 눈에 익을 것이다.

 

 

 

4개의 기본 구조

 

 

패키지 표시 화면에서 보라색으로 강조 표시를 해놓은 파일이 주요 구성요소이다. 그리고 위의 그림은 그 구성 요소의 관계를 간략하게 나타낸 그림이다.

 

1. Java File

 이것이 메인 소스이며 여기에 코드를 작성하게 되있다. 필요한 만큼 소스파일을 추가할 수 있다. 이 공간 만큼은 자바라고 생각해도 좋다.

 

 여기서 메인 클래스는 화면에 나타내야 하기 때문에 기본적으로 Activity라는 클래스를 상속받는다.

그리고 onCreate 메서드를 재정의해서 기본적인 초기화를 해주게 된다.

다음으로 setContentView를 이용하여 메서드를 호출하여 Activity를 채우게 된다.

 

 메서드를 호출하는 방법은 2가지가 있는데

첫째는 XML파일에 레이아웃을 기술하고 그 ID를 setContentView로 전달하는 방법이고,

둘째는 뷰 객체를 생성하여 setContentView로 전달하는 방법이다.

 

첫째 방법은 관리하기가 용이하고 복잡한 모양을 만들기 수월하다.

둘째 방법은 실행 도중에 동적으로 레이아웃을 구성할 수 있으나 관리하기가 어렵다.

 

 

2. R.java

 코드나 XML파일에서 참조하는 ID가 이 파일에서 정의된다. 자동으로 생성되는 파일이기 때문에 수정하지 말라는 경고가 써있다. 수정하지 말자.

 

3. main.xml

 레이아웃을 설정한다.

 

4. strings.xml

 화면에 들어가는 문자들을 설정한다.

Posted by 모과이IT
,

1. 안드로이드 주요 용어


2. 안드로이드 4대 컴포넌트
 - 액티비티
 - 서비스
 - 브로드캐스트 리시버
 - 콘텐트 프로바이더

 
   애플리케이션을 구성하는 안드로이드 4대 컴포넌트 
Posted by 모과이IT
,

▩ 자바 프로그램의 구조

/*
public
- 외부에서 별다른 제약없이 이 클래스에 접근 할 수 있습니다.
- private, protected, friendly

class
- 현재 만들어지는 모듈은 클래스입니다.
- interface
 
Hello
- 클래스 이름, 파일명은 Hello.java로 대소문자도 일치해야합니다.
*/
public class Hello {

/*   
public: 외부에서 이 메소드는 아무런 제약없이 호출할 수 있습니다.
static: 객체를 생성하지 않고도 메모리할당이 이루어져
        사용할 수 있습니다.
void  : 이 메소드는 호출된후 처리결과를 리턴하지 않습니다.
        int, float, String등 각 타입이 가능 
main  : JVM에 의해서 최초로 자동으로 호출되는 메소드입니다.
        반드시 한개만 존재해야 합니다.
String[]: 문자열을 저장할 수 있는 배열을 의미합니다. 1차원 배열
args  : 배열명입니다. 도스상에서 입력한 인수를 가져옵니다.
*/
    public static void main(String[] args) {
//System.out.println("AAA"): 화면에 AAA문자열을 출력합니다.
//    문자열은 반드시 Double Quotation Mark로 감싸주어야 합니다.
//System.out.println(10): 화면에 숫자 10이 출력합니다.
//";"은 명령의 종결을 표시합니다.
        System.out.println("안녕하세요.!!!");
        System.out.println(10);
    } //중괄호, 중괄호는 열린 갯수만큼 닫혀야합니다.
}
//중괄호안에 들어가는 코드는 일반적으로 4자정도의 들여쓰기를
//합니다.


// 단일행 주석

/*
  여러행 주석1
  여러행 주석2
 */
 
/**
 * Documentation 주석
 */



  
 

▩ 식별자
   - 클래스, 메소드, 변수 이름
   - 이름 자체로 어느정도 내용이 식별이 되어야 합니다.

1. 클래스 이름
   - 첫자는 대문자가 아니어도 에러는 발생이 안되나 일반적으로 첫자는 대문자를 이용합니다.
     또한 마디마다 대문자를 이용합니다.

     Hello, HelloWorld, CompanyName, Company_name

   - 스칼라 기법을 이용합니다.



 

2. 메소드명
   - 첫자는 일반적으로 소문자로 시작합니다.
   - 메소드의 마디는 대문자를 이용합니다.

     println(), printName(), print_name()




3. 변수의 작성 규칙
   - int kuk = 10; 이라고 선언 했을 경우 kuk는 변수가 됩니다. 또한 식별자로 포함이 됩니다.
   - String name="왕눈이"; 이런 경우는 객체변수에 해당이 됩니다.
   - 알파벳, 대소문자, 숫자, _, $만 이용
   - 첫 문자가 숫자이면 안됨
   - 대소문자 완벽히 구별(파일명, 폴더 모두 해당)
   - 키워드(예약어)와 같으면 안됨
   - 길이 제한 없음(변수, 메소드명은 5자 ~ 15자  안팎)
   - 이름만 보고 알아 볼수 있도록 의미 부여
   - 스칼라 표기법: 무조건 단어의 첫자를 대문자를 사용합니다.
   - 헝가리안 표기법: 단어의 약자를 추출하여 이용합니다.  CompanyName --> CN
  
   예) 권장되는 변수명 : companyName, i_kuk, jumsu_kuk, jumsu_eng, jumsu = _jumsu
    




▩ 데이터 형
   - CPU와 메모리의 한계 때문에 데이터타입은 정확하게 지정해야 합니다.

1. 논리형
   - boolean: 1 Byte(8 Bit)
   - 초기값 : false
   - 갖을 수 있는 값의 범위:true, false
   - 조건문에서 조건이 참/거짓인지 판별하는 기준으로 쓰입니다.
  
     boolean bo=true;




2. 문자형
   - char: 2 Byte(16 Bit)
   - 초기값 : \u0000
   - 범위: \u0000 ~ \uFFFF(Unicode 0~65535)
 
     char grade = 'A';



3. 정수 숫자형(음의 정수, 양의 정수)

※ 2진수의 원리

  

※ 음수의 원리(반도체에서의 양수/음수의 원리)
   - 1의 보수
   - 부호화 절대치
   - 2의 보수


   - byte: 1 Byte
   - 초기값: 0
   - 값의 범위: -128 ~ 127, -2^7 ~ 2^7-1

   1 Byte: 8Bit

   1 Bit: 2가지 표현, 0, 1
   2 Bit: 4가지 표현, (0,0), (0,1), (1,0), (1,1)
   3 Bit: 8가지 표현, (0,0), (0,1), (1,0), (1,1) ...
   4 Bit: 16가지 표현, (0,0), (0,1), (1,0), (1,1) ...
   5 Bit: 32가지 표현, (0,0), (0,1), (1,0), (1,1) ...
   6 Bit: 64가지 표현, (0,0), (0,1), (1,0), (1,1) ...
   7 Bit: 128가지 표현, (0,0), (0,1), (1,0), (1,1) ...
   8 Bit: 256가지 표현, (0,0), (0,1), (1,0), (1,1) ...

   256b ---> 128 ~ 128 ---> -128 ~ +128 ---> -128 ~ +127
  

>>>>> ByteTest.java
/*
 * byte는 8bit
 * -128 ~ +127
 * */

public class ByteTest {

    public static void main(String[] args) {
        byte b = 127;
        //byte b1 = 128; //ERROR
        byte b2 = -128;
        //byte b3 = -129;
       
        System.out.println(b);
        System.out.println(b2);
    }
}




   - short: 2 Byte
   - 초기값: 0
   - 값의 범위: -32768 ~ 32767, -2^15 ~ 2^15-1
  


   - int: 4 Byte
   - 초기값: 0
   - 값의 범위: -2147483648 ~ +2147483647, -2^31 ~ 2^31-1


   - long: 8 Byte
   - 초기값: 0
   - 값의 범위: -2^61 ~ 2^61-1




4. 실수 숫자형
   - float: 4 Byte
   - 초기값: 0.0
   - -1.40e-45 ~ +3.40e+38

   - double: 8 Byte
   - 초기값: 0.0
   - 값의 범위: -4.94e-324 ~ 1.79e+308


>>>>> Silsu.java
public class Silsu {

 public static void main(String[] args) {
      //실수는 기본적으로 double로 인식됩니다.
      //float f = 10.5;
        float f = 10.5f;
        System.out.println("실수 출력:"+f);
       
        double d = 10.5;
        System.out.println("더블형 실수 출력:"+d);
 }
}



▶ 변수, 상수 실습
   - System.out.println()메소드는 기본적으로 10진수로 출력합니다.
   - 출력의 연결은 '+'기호를 사용합니다.

>>>>> Integer_Test.java
public class Integer_Test {
       public static void main(String args[]) {
          System.out.println("정수형 상수 예제");
          System.out.println("10진수 26 10진수로: " + 26);
          System.out.println("8진수 26 10진수로: " + 026);    //숫자0은 8진수
          System.out.println("16진수 AB는 10진수로: " + 0xAB);  //0x 16진수
       }
}




>>>>> Float_Test.java
public class Float_Test {
   public static void main(String args[]) {
      System.out.println("실수형 상수 예제");
      System.out.println("양 실수 12.345: " + 12.345);
      System.out.println("음 실수 -12.345: " + -12.345);
     
      //12.34E3 == 12.34E+3 == 12.34 * 1000
      System.out.println("지수 표현 12.34E3: " + 12.34E3);

      //12.34E-3 == 12.34E-3 == 12.34 / 1000
      System.out.println("지수 표현 12.34E-3: " + 12.34E-3);
   }
}




>>>>> String_Test.java
public class String_Test {
   public static void main(String args[]) {
      String str1 = "My Name is ";
      String str2 = "강";
      String str3 = "남";
      String str4 = "it";

      System.out.println("문자열형 상수 예제");
      System.out.println("-------------------------");
      System.out.println(str1 + str2 + str3 + str4 + 100 + 200);
   }
}




>>>>> Variable_Test.java
public class Variable_Test {
   public static void main(String args[]) {
      int i = 1234;
      int j = 5678;
      int hap = 0;

      hap = i + j;
     
      //200 = i + j;
     
      System.out.println("변수를 이용한 예제");
      System.out.println("i = " + i);
      System.out.println("j = " + j);
      System.out.println("hap = :" + hap);
     
     
      /*
      CPU                  Stack
     
      ALU <----┬---- int i=1234; <-┐
                     └---- int j=5678;    │
                                                 │
      i+j --------------------------┘
                                     6912       
                    
      */

      i = i + j;
      System.out.println("i = i + j => " + i);
   }
}





▩ 형변환
   - 작은 타입의 데이터형은 큰 타입의 데이터형으로 아무런 작업 없이 변환할 수 있습니다.
   - 큰 타입의 데이터형을 작은 타입의 데이터형으로 변환할시에는 캐스트 연산자를 써서 형변환을

      해야합니다.
   - Casting시에는 데이터 짤림이 발생하는지 확인해야 합니다. 데이터 짤림이 발생하면 캐스팅은

      피해야 합니다.
   - 실수를 정수로 바꾸는 경우에 주로 사용합니다.

>>>>> Cast_Test.java
public class Cast_Test {
       public static void main(String args[]) {
          int i = 1234;
          int k;
          float f = 10.5f;
          double d = 100.55;
         
          // k = f;  k는 정수만 저장함으로 ERROR
          k = (int)f;  //작은 타입 = (작은 타입)큰타입
          System.out.println(k); //10
         
          f = i;  //실수형 = 정수형 f = 1234
         
          System.out.println(f); //1234.0
         
          f = (float)d;
          System.out.println(f); //100.55         
       }
    }




public class Cast_Test2 {
    public static void main(String[] args) {
                        //MSB             LSB
                        //3       2       1
                        //18765432187654321
                        //----------------- 
        byte  b = 100;  //         01100100 8비트 필요
        short s = 300;  // 0000000100101100 16비트로 필요
        int   i = 70000;//10001000101110000 24비트가 필요
       
        //                         32+8+4=44
        b = (byte)s;    //00000001/00101100
        System.out.println("b=" + b);

    }

}




▩ 연산자
   
1. 산술(수치) 연산자 : +, -, *, /, %
   - 정수/정수 = 정수
   - float n = 0.0f; f를 제거하면 double 8바이트가 됩니다.

>>>>> Arithmetic.java
public class Arithmetic {
   public static void main(String args[]) {
      int i = 20;
      int j = 12;

      int a = i + j;
      int b = i - j;
      int c = i * j;
      int d = i / j;
      int e = i % j;
      float n = 0.0f;

      System.out.println("i : " + i + "j : " + j);
      System.out.println("덧셈 결과 : " + a);
      System.out.println("뺄셈 결과 : " + b);
      System.out.println("곱셈 결과 : " + c);
      System.out.println("나눗셈 결과 : " + d);
      System.out.println("나머지 결과 : " + e);
     
      n = i/j;
      System.out.println("정수/정수의 결과:" + n);
   }
}




2. 대입 연산자 : =
   - 좌변은 상수값이 아니라 기억장소가 와야합니다.
     a = i + j;
     b = 10 + 20;
     100 = i + 10;



3. 연산후대입 연산자 : +=, -=, *=, /=, %=
   - 처리속도 향상

>>>>> Proportion.java
public class Proportion {
   public static void main(String args[]) {
      int i = 12;
      int j = 27;

      System.out.println("i : " + i + ", j : " + j);
      System.out.println("---------------");

      i += j; //i=i + j;
      System.out.println("i+=j : " + i);

      i -= j; //i=i - j;
      System.out.println("i-=j : " + i);

      i *= j; //i=i * j;
      System.out.println("i*=j : " + i);

      i /= j; //i=i / j;
      System.out.println("i/=j : " + i);

      i%=j; //i=i % j;
      System.out.println("i%=j : " + i);
   }
}




4. 증가/감소 연산자 : ++, --
   - 알아보기 쉽게 코딩하는 것이 필요합니다.

>>>>> IncDec.java
public class IncDec{
      public static void main(String args[]){
          int x=1;
          int y = x++; //후위 연산자  
          // y = x;
          // x = x + 1;

          System.out.println("x의 값은" + x); //2
          System.out.println("y의 값은" + y); //1
       
          x=1;           
          int z=++x; //전위 연산자
          //x = x + 1;
          //z = x;     
       
         System.out.println("x의 값은" + x); //2
         System.out.println("z의 값은" + z); //2
        
         x=1;
         x++; //++x;
         z=x;
         System.out.println("-----------------------");         
         System.out.println("x의 값은" + x); //2
         System.out.println("z의 값은" + z); //2
        
      }
}




>>>>> IncDec2.java
public class IncDec2{
      public static void main(String args[]){
          int x=1;
          int y = x--; //후위 연산자  
          // y = x;
          // x = x + 1;

          System.out.println("x의 값은" + x); //2
          System.out.println("y의 값은" + y); //1
       
          x=1;           
          int z=--x; //전위 연산자
          //x = x + 1;
          //z = x;     
       
         System.out.println("x의 값은" + x); //2
         System.out.println("z의 값은" + z); //2
        
      }
}




5. 관계(비교) 연산자 : <, <=, >=, >, ==, !=, instanceof

>>>>> Compare.java
public class Compare {
   public static void main(String args[]) {
      int i = 12;
      int j = 23;
      int k = 17;
      String name="왕눈이";

      System.out.println("변수 i는 " + i + ", 변수 j는 " + j + ", 변수 k는" + k + "이다.");
      System.out.println("-------------------");
      System.out.println("12==23 : " + (i==j));
      System.out.println("12!=17 : " + (i!=k));
      System.out.println("23<17  : " + (j<k));
      System.out.println("k>i : " + (k>i));
      System.out.println("i<=k : " + (i<=k));
      System.out.println("i>=j : " + (i>=j));
     
      System.out.println(name instanceof String);
    //System.out.println(i instanceof int);     
   }
}




6. 비트연산자
   - byte 0 ~ 255까지 출력하기

>>>>> Bitwise.java
//>>> 무조건 0이 채워지는 shift연산만 이루어짐
class Bitwise {
      public static void main(String args[]) {
        int a = 2;
        int b = 5;
       
        int c = a | b; //or
        //2진수 연산
     
        // ....8421 
        // 00000010
        //+00000101
        //--------- 
        // 00000111--> 7
       
        int d = a & b; //and
        // 00000010
        //+00000101
        //--------- 
        // 00000000--> 0
       
       
        int e = a ^ b; //Exclusive or
        // 00000010
        //+00000101
        //--------- 
        // 00000111--> 7
       
       
        int i; int j;
        i = a << 2;    //좌 shift 연산
        // ....8421 
        // 00000010
        // 00001000 --> 8
       
       
        j = b >> 2;    //우 shift 연산
        // ....8421 
        // 00000101
        // 00000001 --> 1
       

        System.out.println("        a = " + a);
        System.out.println("        b = " + b);
        System.out.println("      a|b = " + c);
        System.out.println("      a&b = " + d);
        System.out.println("      a^b = " + e);
        System.out.println("     a<<2 = " + i);
        System.out.println("     b>>2 = " + j);
      }
    }




7. 논리연산자(조건 연산자)
   - 조건문과 함께 많이 사용됨
   - &&: 양쪽의 조건이 전부 맞아야 참입니다.
   - ||: 어느 한쪽만 참이면 참입니다.




8. 삼항 연산자

>>>>> Ternary.java
class Ternary
{
    public static void main(String args[])
    {
        int x = 10;
        int y;
       
        //System.out.println("결과는 " + y);

        //System.out.println("초기화되지 않은 y의 값: " + y);
        //y = 조건문 ? 참값 : 거짓값
        y = x < 9 ? 3 : 5;
       System.out.println("결과는 " + y);
    }
}

'개발지식창고 > JAVA' 카테고리의 다른 글

자바 클래스의 종류  (0) 2011.09.11
static 키워드 바로 알기  (0) 2011.09.11
오버로딩, 오버라이딩, 추상클래스, 인터페이스 개념  (0) 2011.09.11
추상클래스의 개념  (0) 2011.09.11
Final  (0) 2011.09.11
Posted by 모과이IT
,

클래스는 선언위치에 따라 다음과 같이 나뉘어 진다.

1. 일반 클래스

    1) 선언위치 : 파일의 시작부분

    2) 용      도 : 일반 클래스의 생성

    3) 특      징 : 일반적인 형태의 클래스

    4) 파일형태 : A.class

    5) 모      양 : class [클래스 이름]{

                       }


2. 중첩 클래스

    1) 선언위치 : 클래스의 내부

    2) 용      도 : 클래스와 연관관계가 밀접한 경우

    3) 특      징 : static 선언만 가능

    4) 파일형태 : A$B.class

    5) 모      양 : class [일반클래스 이름]{

                               static class [중첩클래스 이름]{

                               }

                        }


3. 내부 클래스

    1) 선언위치 : 클래스의 내부

    2) 용      도 : 이벤트 처리, 데이터 구조선언

    3) 특      징 : static 메소드 혹은 변수를 가질 수 없음

    4) 파일형태 : A$B.class

    5) 모      양 : class [일반클래스 이름]{

                               static class [내부클래스 이름]{

                               }

                        }


4. 지역 클래스

    1) 선언위치 : 메소드 내부

    2) 용      도 : 메소드 내에서만 사용되는 클래스를 생성할때

    3) 특      징 : 지역변수를 final로 생성

    4) 파일형태 : A$x$B.class

    5) 모      양 : class [일반클래스 이름]{

                               메소드{

                                      static class [지역클래스 이름]{

                                       }

                               }

                        }


5. 익명 클래스

    1) 선언위치 : 메소드 내부

    2) 용      도 : 단 한번만 정의하여 사용할때

    3) 특      징 : 지역클래스와 같으나 클래스 선언 후에 ; 붙임

    4) 파일형태 : A$x.class

    5) 모      양 : class [일반클래스 이름]{

                               메소드{

                                       new class [익명클래스 이름](){

                                       }

                               }

                        }

Posted by 모과이IT
,

자바를 한번쯤 공부해본사람이라면 static키워드를 모르지는 않을 것입니다.

하지만, 바르게 알고 있는 사람들은 그리 많지 않습니다.


자바경력자를 면접볼 때 static키워드에 대해서 질문하곤 합니다.


면접관 : static키워드에 대해서 설명해보세요.
응시자 : static키워드를 쓰면, 객체를 생성하지 않고도 변수나 함수를 사용할 수 있습니다.


면접관 : 왜 static키워드를 쓰나요?
응시자 : 객체를 생성하지 않아도 되니까 편리하고 속도도 빠릅니다.


면접관 : 그렇다면 모든 변수와 함수에 static을 붙이는 것이 좋겠네요?
응시자 : 가능한한 static을 붙이는 것이 좋다고 생각합니다.


면접관 : 어떤 경우에 static을 붙일 수 있고, 어떤 경우에 static을 붙일 수 없습니까?
응시자 : ...


면접관 : 만일 당신이 새로운 클래스를 작성한다고 할 때, 어떤 경우에 static키워드를
             사용해야한다고 생각합니까?

응시자 : ...


대부분의 경우 위와 같은 내용으로 문답이 진행됩니다.

사실 응시자의 대답은 다 맞는 얘기입니다. 하지만, static의 핵심적인 개념을 모르기 때문에
어떤 경우에 왜 static을 사용해야하는지는 잘모르는 것 같습니다.


먼저 결론부터 간단히 정리하면 다음과 같습니다.


1.클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통적으로 사용해야하는 것에 static을 붙인다.
 - 인스턴스를 생성하면, 각 인스턴스들은 서로 독립적기 때문에 서로 다른 값을 유지한다.
    경우에 따라서는 각 인스턴스들이 공통적으로 같은 값이 유지되어야 하는 경우 static을
    붙인다.


2. static이 붙은 멤버변수는 인스턴스를 생성하지 않아도 사용할 수 있다.
 - static이 붙은 멤버변수(클래스변수)는 클래스가 메모리에 올라갈때 이미 자동적으로
   생성되기 때문이다.


3. static이 붙은 메서드(함수)에서는 인스턴스 변수를 사용할 수 없다.
 - static이 메서드는 인스턴스 생성 없이 호출가능한 반면, 인스턴스 변수는 인스턴스를
    생성해야만 존재하기 때문에... static이 붙은 메서드(클래스메서드)를 호출할 때
    인스턴스가 생성되어있을수도 그렇지 않을 수도 있어서 static이 붙은 메서드에서
    인스턴스변수의 사용을 허용하지 않는다.
    (반대로, 인스턴스변수나 인스턴스메서드에서는 static이 붙은 멤버들을 사용하는 것이
     언제나 가능하다. 인스턴스변수가 존재한다는 것은 static이 붙은 변수가 이미 메모리에
     존재한다는 것을 의미하기 때문이다.)


4. 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.
 - 메서드의 작업내용중에서 인스턴스 변수를 필요로 한다면, static을 붙일 수 없다.
    반대로 인스턴스변수를 필요로 하지 않는다면, 가능하면 static을 붙이는 것이 좋다.
    메서드 호출시간이 짧아지기 때문에 효율이 높아진다.
    (static을 안붙인 메서드는 실행시 호출되어야할 메서드를 찾는 과정이 추가적으로
    필요하기 때문에 시간이 더 걸린다.)


5. 클래스 설계시 static의 사용지침
 - 먼저 클래스의 멤버변수중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있는지
    살펴보고 있으면, static을 붙여준다.
 - 작성한 메서드 중에서 인스턴스 변수를 사용하지 않는 메서드에 대해서 static을
    붙일 것을 고려한다.
 
일반적으로 인스턴스변수와 관련된 작업을 하는 메서드는 인스턴스메서드(static이 안붙은
메서드)이고 static변수(클래스변수)와 관련된 작업을 하는 메서드는 클래스메서드(static이 붙은 메서드)라고 보면 된다.


다음은 static에 대한 자세한 설명과 예제입니다.


static은 객체지향개념을 이해하는 가장 중요한 첫걸음이니 확실히 알아두셔야합니다.


==================================================================
   


 

3.2 클래스변수와 인스턴스변수


클래스변수와 인스턴스변수의 차이를 이해하기 위한 예로 카드 게임에 사용되는 카드를 클래스로 정의해보자.



카드 클래스를 작성하기 위해서는 먼저 카드를 분석해서 속성과 기능을 알아 내야한다. 속성으로는 카드의 무늬, 숫자, 폭, 높이 정도를 생각할 수 있을 것이다.
이 중에서 어떤 속성을 클래스 변수로 선언할 것이며, 또 어떤 속성들을 인스턴스 변수로 선언할 것인지 생각해보자.


class Card {
     String kind ;                         // 카드의 무늬 - 인스턴스 변수
     int number;                         // 카드의 숫자 - 인스턴스 변수
     static int width = 100 ;             // 카드의 폭 - 클래스 변수
     static int height = 250 ;            // 카드의 높이 - 클래스 변수
}


각 Card인스턴스는 자신만의 무늬(kind)와 숫자(number)를 유지하고 있어야 하므로 이들을 인스턴스변수로 선언하였고, 각 카드들의 폭(width)과 높이(height)는 모든 인스턴스가 공통적으로 같은 값을 유지해야하므로 클래스변수로 선언하였다.

만일 카드의 폭을 변경해야할 필요가 있을 때는 모든 카드의 width값을 변경하지 않고, 한 카드의 width값만 변경해도 모든 카드의 width값이 변경되는 셈이다.

[예제6-4] CardTest.java

class CardTest{
      public static void main(String args[]) {
            // 클래스변수(static 변수)는 객체생성없이 '클래스이름.클래스변수'로 직접 사용 가능하다.
            System.out.println("Card.width = " + Card.width);
            System.out.println("Card.height = " + Card.height);

            Card c1 = new Card();
            c1.kind = "Heart";
            c1.number = 7;

            Card c2 = new Card();
            c2.kind = "Spade";
            c2.number = 4;

            System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 (" + c1.width + ", " + c1.height + ")" );
            System.out.println("c2는 " + c2.kind + ", " + c2.number + "이며, 크기는 (" + c2.width + ", " + c2.height + ")" );             System.out.println("이제 c1의 width와 height를 각각 50, 80으로 변경합니다.");
            c1.width = 50;
            c1.height = 80;

            System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 (" + c1.width + ", " + c1.height + ")" );
            System.out.println("c2는 " + c2.kind + ", " + c2.number + "이며, 크기는 (" + c2.width + ", " + c2.height + ")" );
      }
}

class Card {
     String kind ;                         // 카드의 무늬 - 인스턴스 변수
     int number;                         // 카드의 숫자 - 인스턴스 변수
     static int width = 100;             // 카드의 폭 - 클래스 변수
     static int height = 250;             // 카드의 높이 - 클래스 변수
}

[실행결과]
Card.width = 100
Card.height = 250
c1은 Heart, 7이며, 크기는 (100, 250)
c2는 Spade, 4이며, 크기는 (100, 250)
이제 c1의 width와 height를 각각 50, 80으로 변경합니다.
c1은 Heart, 7이며, 크기는 (50, 80)
c2는 Spade, 4이며, 크기는 (50, 80)


Card클래스의 클래스변수(static변수)인 width, height 그리고 color는 Card클래스의 인스턴스를 생성하지 않고도 '클래스이름.클래스변수'와 같은 방식으로 사용할 수 있다.
Card인스턴스인 c1과 c2는 클래스 변수인 width와 height를 공유하기 때문에, c1의 width와 height를 변경하면 c2의 width와 height값도 바뀐 것과 같은 결과를 얻는다.
Card.width, c1.width, c2.width는 모두 같은 저장공간을 참조하므로 항상 같은 값을 갖게 된다.
인스턴스 변수는 인스턴스가 생성될 때 마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된 값을 갖는다.
[플래시동영상]자료실의 플래시동영상 MemberVar.swf을 꼭 보도록하자.



3.9 클래스메서드(static메서드)와 인스턴스메서드


변수에서 그랬던 것과 같이, 메서드 앞에 static이 붙어 있으면 클래스메서드이고 붙어 있지 않으면 인스턴스메서드이다.
클래스 메서드는 호출방법 역시 클래스변수처럼, 객체를 생성하지 않고도 '클래스이름.메서드이름(매개변수)'와 같은 식으로 호출이 가능하다.
그렇다면 어느 경우에 static을 사용해서 클래스메서드로 정의해야하는 것일까?

클래스는 '데이터(변수)와 데이터에 관련된 메서드의 집합'이라고 할 수 있다. 같은 클래스 내에 있는 메서드와 멤버변수는 아주 밀접한 관계가 있다. 인스턴스메서드는 인스턴스변수와 관련된 작업을 하는, 즉 메서드의 작업을 수행하는데 인스턴스변수를 필요로 하는 메서드이다.
그래서 인스턴스변수와 관계없거나(메서드 내에서 인스턴스변수를 사용하지 않거나), 클래스변수만을 사용하는 메서드들은 클래스메서드로 정의한다.

물론 인스턴스변수를 사용하지 않는다고 해서 반드시 클래스 메서드로 정의해야하는 것은 아니지만, 그렇게 하는 것이 일반적이다.
참고로 Math클래스의 모든 메서드는 클래스메서드임을 알 수 있다. Math클래스에는 인스턴스변수가 하나도 없거니와 Math클래스의 함수들은 작업을 수행하는데 필요한 값들을 모두 매개변수로 받아서 처리 하기 때문이다. 이처럼, 단순히 함수들만의 집합인 경우에는 클래스메서드로 선언한다.

[참고]인스턴스 변수 뿐만 아니라 인스턴스 메서드를 호출하는 경우에도 인스턴스 메서드로 선언되어야 한다. 인스턴스 메서드를 호출하는 것 역시 인스턴스 변수를 간접적으로 사용하는 것이기 때문이다.

[예제6-12] MyMathTest2.java

class MyMath2 {
      long a, b;
     
      // 인스턴스변수 a, b를 이용한 작업을 하므로 매개변수가 필요없다.
      long add() {       return a + b; }
      long subtract() {       return a - b; }
      long multiply() {       return a * b; }
      double divide() {       return a / b; }

      // 인스턴스변수와 관계없이 매개변수만으로 작업이 가능하다.
      static long add(long a, long b) {       return a + b; }
      static long subtract(long a, long b) {       return a - b; }
      static long multiply(long a, long b) {       return a * b; }
      static double divide(double a, double b) {       return a / b; }
}

class MyMathTest2 {
      public static void main(String args[]) {
            // 클래스메서드 호출
            System.out.println(MyMath2.add(200L, 100L));
            System.out.println(MyMath2.subtract(200L, 100L));
            System.out.println(MyMath2.multiply(200L, 100L));
            System.out.println(MyMath2.divide(200.0, 100.0));

            MyMath2 mm = new MyMath2();
            mm.a = 200L;
            mm.b = 100L;
            // 인스턴스메서드는 객체생성 후에만 호출이 가능함.
            System.out.println(mm.add());
            System.out.println(mm.subtract());
            System.out.println(mm.multiply());
            System.out.println(mm.divide());

}
[실행결과]
300
100
20000
2.0
300
100
20000
2.0

인스턴스메서드인 add(), subtract(), multiply(), divide()는 인스턴스변수인 a와 b만으로도 충분히 원하는 작업이 가능하기 때문에, 매개변수를 필요로 하지 않으므로 괄호()에 매개변수를 선언하지 않았다.
반면에 add(long a, long b), subtract(long a, long b) 등은 인스턴스변수 없이 매개변수만으로 작업을 수행하기 때문에 static을 붙여서 클래스메서드로 선언하였다. MyMathTest2의 main메서드에서 보면, 클래스메서드는 객체생성없이 바로 호출이 가능했고, 인스턴스메서드는 MyMath2클래스의 인스턴스를 생성한 후에야 호출이 가능했다.
이 예제를 통해서 어떤 경우 인스턴스메서드로, 또는 클래스메서드로 선언해야하는지, 그리고 그 차이를 이해하는 것은 매우 중요하다.



3.10 클래스멤버와 인스턴스멤버간의 참조와 호출.


같은 클래스에 속한 멤버들간에는 별도의 인스턴스를 생성하지 않고도 서로 참조 또는 호출이 가능하다. 단, 클래스멤버가 인스턴스멤버를 참조 또는 호출하고자 하는 경우에는 인스턴스를 생성해야 한다.
그 이유는 인스턴스멤버가 존재하는 시점에 클래스멤버는 항상 존재하지만, 클래스멤버가 존재하는 시점에 인스턴스멤버가 항상 존재한다는 것을 보장할 수 없기 때문이다.

[예제6-] ArrayEx.java

class MemberCall {
      int iv = 10;
      static int cv = 20;

      int iv2 = cv;
//   static int cv2 = iv;                   에러. 클래스변수는 인스턴스 변수를 사용할 수 없음.
      static int cv2 = new MemberCall().iv;   // 굳이 사용하려면 이처럼 객체를 생성해야함.

      static void classMethod1() {
            System.out.println(cv);
//         System.out.println(iv);       에러. 클래스메서드에서 인스턴스변수를 바로 사용할 수 없음.
            MemberCall c = new MemberCall();      
            System.out.println(c.iv);   // 객체를 생성한 후에야 인스턴스변수의 참조가 가능함.
     }

      void instanceMethod1() {
            System.out.println(cv);            
            System.out.println(iv);  // 인스턴스메서드에서는 인스턴스변수를 바로 사용가능.
     }

      static void classMethod2() {
            classMethod1();
//         instanceMethod1(); 에러. 클래스메서드에서는 인스턴스메서드를 바로 호출할 수 없음.
            MemberCall c = new MemberCall();
            c.instanceMethod1(); // 인스턴스를 생성한 후에야 인스턴스메서드를 호출할 수 있음.
      }
     
      void instanceMethod2() { // 인스턴스메서드에서는 인스턴스메서드와 클래스메서드
            classMethod1();         // 모두 인스턴스생성없이 바로 호출이 가능하다.
            instanceMethod1();
     }
}

클래스멤버(클래스변수와 클래스메서드)는 언제나 참조 또는 호출이 가능하다.
그렇기 때문에 인스턴스멤버가 클래스멤버를 참조, 호출하는 것은 아무런 문제가 안 된다.
클래스멤버간의 참조 또는 호출 역시 아무런 문제가 없다.

그러나, 인스턴스멤버(인스턴스변수와 인스턴스메서드)는 반드시 객체를 생성한 후에만 참조 또는 호출이 가능하기 때문에 클래스멤버가 인스턴스멤버를 참조, 호출하기 위해서는 객체를 생성하여야 한다.

하지만, 인스턴스멤버간의 호출에는 아무런 문제가 없다. 하나의 인스턴스멤버가 존재한다는 것은 인스턴스가 이미 생성되어있다는 것을 의미하며, 즉 다른 인스턴스멤버들도 모두 존재하기 때문이다.

실제로는 같은 클래스 내에서 클래스멤버가 인스턴스멤버를 참조 또는 호출해야하는 경우는 드물다. 만일 그런 경우가 발생한다면, 인스턴스메서드로 작성해야할 메서드를 클래스메서드로 한 것은 아닌지 한번 더 생각해봐야 한다.

[알아두면 좋아요]

수학에서의 대입법처럼, c = new MemberCall()이므로 c.instanceMethod1();에서 c대신 new MemberCall()을 대입하여 사용할 수 있다.

      MemberCall c = new MemberCall();
      int result = c.instanceMethod1();

위의 두 줄을 다음과 같이 한 줄로 할 수 있다.

      int result = new MemberCall().instanceMethod1();

대신 참조변수를 사용하지 않았기 때문에 생성된 MemeberCall인스턴스는 더 이상 사용할 수 없다
Posted by 모과이IT
,

1. 오버로딩

오버로딩이란 메서드의 중복을 말하는데, 같은 이름으로 여러 역할을 하도록 만드는 기술이다. 예를 들어

public class Poly {

    public void width(int r){

        float wid=3.14f*r*r;

        System.out.println("원의 넓이 : " + wid);

    } 

    public void width(int garo, int sero){

        int wid=garo*sero;

        System.out.println("사각형의 넓이 : " + wid);

    }

    public static void main(String args[]){

        Poly poly = new Poly();

        poly.width(10);

        poly.width(20, 10);   

}


  위에서 width()를 보자. 그러면 width(r)과 width(garo, sero)가 보이는데 이 두 메서드가 오버로딩되었다고 말할 수 있는 것이다.

  만약 width(10)으로 호출하게 되면 이 10이라는 것을 받을 수 있는 int 형 중 인수가 하나이기 때문에 width 메서드 중 위에 것이 호출되게 된다. 이것은 절차지향 프로그래밍과는 달리 객체지향 프로그래밍에서는 메서드의 이름으로 메서드가 같은 지를 판단하는 것이 아닌 메서드 인수의 타입이나 개수로 판단하기 때문에 가능한 것이다.



2. 오버라이딩

  오버라이딩은 간단히 정의해서 부모 클래스에서 정의되어 있는 메서드를 같은 이름으로 다른 역할을 재정의하고 싶을때 사용하게 된다.

  객체지향 프로그래밍은 유지보수에 초점이 맞추어져 있다. 그러다보니 비슷한 역할이라는 메서드의 이름을 통일하는 것을 더욱 좋게본다. 예를 들어 넓이를 구하는 의미인데, 어떤 메서드에서는 'width'라는 이름을 사용하고 어떤 메서드에서는 '넓이'라는 이름을 사용하면 나중에 같은 의미지만 헤메이게 될 소지가 있기 때문이다. 그러면 아래의 예를 보자.

public class Poly {

    private int garo;

    private int sero;

    public Poly(int garo, int sero) {

        this.garo=garo;

        this.sero=sero;

    }

    public void width(){

        int wid=garo*sero;

        System.out.println("사각형의 넓이 : " + wid);

    }

}

public class Tri extends Poly {

    public Tri(int garo, int sero) {

        this.garo = garo;

        this.sero = sero;

    }

    public void width() {

        float wid=garo*sero*0.5f;

        System.out.println("삼각형의 넓이 : " + wid);

    }

    public static void main(String[] args) {

        Tri tri = new Tri(20, 10);

        tri.width();

    }

}


  위의 예에서 보듯, 부모에 있는 width는 사각형을 구하기 위한 메서드였다. 그러나 Poly로부터 상속받은 Tri에서는 삼각형을 구하고자 했다. 그렇기 때문에 width라는 이름으로 넓이를 통일시키고자 Poly의 width를 Tri에서 재정의를 통해 구현한 것이다.



3. 추상 클래스

  추상 클래스는 선언만 되어 있고, 구현은 되어 있지 않은 메서드를 추상 메서드라고 하는데 추상 메서드를 하나라도 포함하게 되는 클래스를 추상클래스라고 한다. 추상메서드와 클래스는 항상 abstract라는 키워드를 붙여 줌으로서 선언하게 된다. 그럼 추상 클래스를 왜 사용해야할까? 아래의 예를 보면서 얘기해보자.

public abstract class Poly {

    int garo;

    int sero;

    public abstract void width();

}


  우리는 Poly 클래스에 이미 가로와 세로가 선언되어져 있고, 사각형의 넓이를 구할 수 있는 메서드가 정의되어 있다는 것을 알고 Poly를 이용해서 사각형 뿐만이 아닌 삼각형의 넓이도 구하려고 한다. 그런데 Poly에서는 삼각형과 사각형의 공식이 서로 틀려 어떻게 구현되어야 할지 감을 잡을 수가 없다. 그렇기 때문에 상속받는 자식에서 구현하라는 의미로 우리는 여기서 선언만 되어 있는 width를 선언하게 된것이다. 그리고 abstract라는 키워드가 메서드와 클래스의 앞에 각각 붙어져 있는 것을 확인할 수 있다.

  가장 중요한 것은 추상 클래스로부터 상속받는 클래스에서는 추상 메서드는 반드시 오버라이딩 시켜서 사용해야 한다는 것이다. 그럼 상속받은 삼각형과 사각형 클래스를 각각 정의해보자.

public class Tri extends Poly {

    public Tri(int garo, int sero) {

        this.garo=garo;

        this.sero=sero;

    }

    public void width(){

        float wid=garo*sero*0.5f;

        System.out.println("삼각형의 넓이 : " + wid);

    }

    public static void main(String[] args) {

        Tri tri = new Tri(20, 10);

        tri.width();

    }

}

public class Rect extends Poly {

    public Rect(int garo, int sero) {

        this.garo=garo;

        this.sero=sero;

    }

    public void width(){

        int wid=garo*sero;

        System.out.println("사각형의 넓이 : " + wid);

    }

    public static void main(String[] args) {

        Rect rect = new Rect(20, 10);

        rect.width();

    }

}



4. 인터페이스

  자바에서는 원칙적으로 다중 상속을 금하고 있다. extends 키워드로는 두 개 이상의 클래스로부터 상속받을 수 없다는 의미이다. 그러나 다중 상속을 꼭 해야하는 경우가 있다. 이럴때 사용할 수 있는 것이 인터페이스이다. 인터페이스는 추상메서드와 변수가 아닌 상수만을 소유할 수 있다. 인터페이스에서 변수를 선언하게 되면 상수화되기 때문에 상수 선언시 값초기화를 해주어야 한다. 또한 인터페이스로부터 상속받을 때는 extends 키워드가 아닌 implements 키워드를 사용한다. 역시 인터페이스에 있는 추상메서드도 반드시 오버라이딩 시켜야 하며, 추상 메서드라고 해서 abstract를 붙이지는 않는다.

public interface Poly {

    float PI=3.14f;

    public void width(int r);

}

public class Circle implements Poly {

    public void width(int r) {

        float wid = 3.14f * r * r;

        System.out.println("원의 넓이 : " + wid);

    }

    public static void main(String[] args) {

        Circle circle = new Circle();

        circle.width(10);

    }

}


'개발지식창고 > JAVA' 카테고리의 다른 글

자바 클래스의 종류  (0) 2011.09.11
static 키워드 바로 알기  (0) 2011.09.11
추상클래스의 개념  (0) 2011.09.11
Final  (0) 2011.09.11
Vector(벡터) 정리  (0) 2011.09.11
Posted by 모과이IT
,