▩ 자바 프로그램의 구조

/*
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
,

5.1.1 추상클래스의 개념

Abstract클래스는 빈 깡통 클래스입니다. abstract클래스는 구현이 덜 되었거나 또는 아직은 미완성 클래스이기 때문에 우리는 이 클래스를 추상 클래스라 부릅니다. 어디가 미완성일까요? 미완성 메서드를 포함하고 있기 때문에 클래스자체가 미완성이 되는 것입니다. 미완성 메서드는 어디가 미완성일까요? 메서드의 몸체가 없습니다. 몸체 없는 메서드, 이를 우리는 추상 메서드라 부릅니다. 그리고 이 추상 메서드를 단 하나라도 포함하고 있는 클래스를 추상 클래스라고 합니다.

 

 

5.1.2 추상클래스와 추상메서드

 추상클래스는 미완성 클래스이기 때문에 약점이 있습니다. 완전한 클래스가 아니기 때문에 절대 객체를 생성하지 못합니다. 당연한 것 아니겠습니까? 완성되지 않은 클래스이니 객체를 만들 수 없다는 것은 이치에 합당합니다. 이 미완성 클래스를 어디에 사용할까요? 사용방법은 다음과 같습니다.(이해하기 편하게 추상클래스를 추상아버지클래스, 이를 상속 받는 클래스를 아들클래스라고 하겠습니다. )

 

n        추상아버지 클래스는 추상 메서드를 가지고 있습니다.

n        아들 클래스는 추상 아버지클래스로부터 상속 받습니다.

n        아들은 추상 아버지 클래스의 몸체 없는 메서드를 모두 메서드 재정의와 같이 다시 만듭니다. 이것을 우리는 구현한다고 말합니다. 몸체를 달아 주는 것입니다.

n        아들 클래스는 완성된 클래스이기 때문에 객체를 생성할 수 있습니다.

 

 다음은 추상 메서드를 만드는 방법을 보여 주고 있는 예입니다.

추상 메서드를 만드는 방법

abstract class 클래스이름 {

abstract 메소드선언;        // 메소드의 몸체는 없음

abstract 메소드선언;        // 메소드의 몸체는 없음

}

 

)

 

public abstract class AbstractTest {

   public abstract void abstractMethod();

}

 

메서드에 몸체가 붙지 않는다면 여러분은 반드시 abstract키워드를 붙여야 합니다. 그리고 이 abstract메서드를 하나라도 포함하고 있다면 클래스명 앞에 abstract를 붙여야 합니다. 안 붙이면 언제나 그런 것처럼 친절하게 에러를 발생 시킵니다. 아래의 에러는 추상클래스내에 추상 메서드에 abstract를 붙이지 않았을 때 발생하는 에러입니다.

 

C:\examples\5. Class for Polymorphism Java>javac AbstractTest.java

AbstractTest.java:2: missing method body, or declare abstract

        public void abstractMethod();

                    ^

1 error

 

아주 간단하죠. 추상 클래스는 그 자체로는 객체를 생성할 수 없다는 것을 한번 더 밝혀 두며 실제 이용하는 가장 간단한 예를 보도록 하겠습니다.

 

NewCan.java(추상 메서드를 만드는 방법)

public class NewCan extends EmptyCan{

             public void sound(){

                           System.out.println("EmptyCan:빈깡통은 소리가 요란하다");

             }

             public void who(){

                           System.out.println("EmptyCan:나는 빈깡통입니다.");

             }

             public void sayHello(){

                           System.out.println("NewCan:추상클래스 테스트입니다.");

             }

             public static void main(String args[]) {

                           NewCan ecm = new NewCan();

                           ecm.who();

                           ecm.sound();

                           ecm.sayHello();

             }

}

Empty.java(추상클래스)

public abstract class EmptyCan{  

   public abstract void sound();//몸체없음

   public abstract void who();//몸체 없음  

}

C:\examples\5. Class for Polymorphism Java>javac NewCan.java

 

C:\examples\5. Class for Polymorphism Java>java NewCan

EmptyCan:나는 빈깡통입니다.

EmptyCan:빈깡통은 소리가 요란하다

NewCan:추상클래스 테스트입니다.

 

추상클래스는 객체가 가지는 특성들을 추상화시켜 놓았을 뿐, 아직 구체화 시키지 못한 클래스이므로, 이 추상클래스를 상속하는 하위클래스에서 좀 더 구체화 시키도록 하는 방법을 사용합니다. 주의 할 것은 추상 메서드를 하나도 빼지 말고 전부 구현 해야 객체를 생성할 수 있습니다. 아들이 상속을 받아서 추상 메서드를 하나라도 남겨 두었다면 아들도 추상클래스가 됩니다. 부전자전이죠. 다음은 상속을 했지만 추상 메서드를 전부 구현 하지 않았다면 abstract클래스가 되는 것을 증명하는 예제입니다.

 

CompleteCan.java(추상 메서드를 만드는 방법)

public class CompleteCan extends IncompleteCan{

             public void who(){

                           System.out.println("EmptyCan:나는 빈깡통입니다.");

             }

             public void sayHello(){

                           System.out.println("NewCan:추상클래스 테스트입니다.");

             }

             public static void main(String args[]) {

                           CompleteCan cc = new CompleteCan();

                           cc.who();

                           cc.sound();

                           cc.sayHello();

             }

}

Incomplete.java(추상클래스)

public abstract class IncompleteCan extends EmptyCan{

             public void sound(){

                           System.out.println("EmptyCan:빈깡통은 소리가 요란하다");    

             }

}

Empty.java(추상클래스)

public abstract class EmptyCan{  

   public abstract void sound();//몸체없음

   public abstract void who();//몸체 없음  

}

C:\examples\5. Class for Polymorphism Java>javac EmptyCan.java

C:\examples\5. Class for Polymorphism Java>javac IncompleteCan.java

C:\examples\5. Class for Polymorphism Java>javac CompleteCan.java

C:\examples\5. Class for Polymorphism Java>java CompleteCan

EmptyCan:나는 빈깡통입니다.

EmptyCan:빈깡통은 소리가 요란하다

NewCan:추상클래스 테스트입니다.

 

추상메소드는 추상클래스와 마찬가지로 아직 구현이 이루어지지 않고 단지 그 메서드의 이름만 가지고 있다는 뜻입니다. 그래서 몸체가 없다고 말하고 있는 것입니다. 이것을 역으로 말한다면 추상메서드가 되려면 몸체가 없어야 한다라는 명제를 얻을 수 있습니다. 보통 우리가 전문적인 용어로 이야기 할 때 추상메서드는 메서드의 프로토타입만 가지고 있다라고 이야기 합니다. 

 

 

5.1.3 클래스의 구조를 디자인하기 위한 추상 클래스

 추상클래스는 클래스의 구조를 잡기 위한 방법으로 사용됩니다. 하나의 클래스를 만든다고 가정한다면 하나의 클래스에 모든 것을 전부 넣을 수는 없습니다. 이러한 방법은 별로 좋지 않은 방법이죠. 클래스가 크다고 가정한다면 작업별로 클래스를 쪼개게 됩니다. 작업을 분할 하는 것은 수평적인 개념에서 비슷한 작업끼리 묶는 것입니다. 유유상종(類類相從)이라는 말이 적당할 것 같군요. 비슷한 작업끼리 묶어서 작업별 클래스를 만드는 것입니다.

 

저 또한 초보시절의 자바 프로그램은 비슷한 작업을 묶는 것으로 시작했습니다. 하지만 수평적으로 묶는 것 조차도 작업의 설계와 분석을 해야만 이루어지는 아주 어려운 일입니다. 이 단계를 거치고 나면 작업을 레벨단위로 묶는 것을 생각하게 됩니다. 거의 1년 이상 걸리더군요. 제가 머리가 나빠서 그런지도 모르겠지만 개인적으로는 상당히 어려운 일이었습니다. 레벨 단위의 작업으로 발전하기까지는 상당히 많은 시간과 생각이 필요한 것 같습니다. 작업을 단계별로 만들어 주는 역할을 하는 것이 바로 추상 클래스의 역할입니다.

레벨 단위의 구조를 살펴 보도록 하죠.

위의 그림은 도형을 그리기 위한 클래스를 디자인 하고 있습니다. 모든 클래스에서 공통되는 작업을 상위레벨에 놓고 그 클래스를 상속 받아 각각의 다른 클래스로 분류되어지고 있습니다. 상위레벨에 존재하는 작업은 구현할 필요성이 없다고 생각하여 abstract으로 만듭니다. 즉, 하위레벨에서 구현하겠다는 것입니다. 이렇게 하였을 때의 코드를 직접 만들어 보겠습니다. 물론 Shape클래스는 abstract으로 만들어질 것이며 그 하위의 Circle, Triangle, Rectangle은 모두 Shape의 abstract메서드를 구현 할 것입니다. 구현은 대충 아래와 같이 되어 질 것입니다.

 

FigureTest.java(abstract의 레벨기법을 테스트하기 위한 예제)

abstract class Shape {

             public abstract void draw();

             public abstract void delete();

}

class Circle extends Shape {

             public void draw(){

                           System.out.println("원을 그립니다");           

             }

             public void delete(){

                           System.out.println("원모양을 지웁니다");     

             }

}

class Triangle extends Shape {

             public void draw(){

                           System.out.println("삼각형을 하나, 둘, 셋, 그립니다.");          

             }

             public void delete(){

                           System.out.println("삼각형을 지웁니다");     

             }

}

class Rectangle extends Shape {

             public void draw(){

                           System.out.println("사각형을 원, 투, 쓰리, 포 그립니다.");     

             }

             public void delete(){

                           System.out.println("사각형을 지웁니다");     

             }

}

//abstract을 테스트하기 위한 클래스

public class FigureTest{

             public static void main(String[] args){

                           Circle c = new Circle();

                           Triangle t = new Triangle();

                           Rectangle r = new Rectangle();

                           c.draw();

                           t.draw();

                           r.draw();

                           c.delete();

                           t.delete();

                           r.delete();

             }

}

C:\examples\5. Class for Polymorphism Java>javac FigureTest.java

C:\examples\5. Class for Polymorphism Java>java FigureTest

원을 그립니다

삼각형을 하나, 둘, 셋, 그립니다.

사각형을 원, 투, 쓰리, 포 그립니다.

원모양을 지웁니다

삼각형을 지웁니다

사각형을 지웁니다

 

상속과 abstract을 설명하기 위해서 어디서나 흔히 볼 수 있는 예제입니다. 이 간단한 예제가 무엇을 의미하는지 제대로 안다면 자바의 강력한 힘을 발휘할 수 있습니다. 클래스의 수평적인 작업 분할과 수직적인 작업 분할을 동시에 이용한다면 여러분은 아주 효율적인 코드를 작성할 수 있습니다. 재사용성 100%와 유지, 보수, 관리 능력까지 갖춘 잘 설계된 프로그램을 하실 수 있을 것입니다.

 

 

5.1.4 결론

추상클래스에 대하여 정리 해 보죠.

 

n         추상 메서드는 몸체 없는 프로토타입만을 가진 메서드입니다.

n         추상 메서드는 반드시 메서드이름 앞에 abstract 키워드를 명시해야 합니다.

n         추상 메서드를 단 하나라도 포함하고 있으면 이를 추상 클래스라고 합니다.

n         추상 클래스는 클래스이름 앞에 abstract를 명시해야 합니다.

n         상속을 이용하여 추상 메서드를 모두 구현한 뒤, 객체를 생성할 수 있습니다.

 

일반적인 특징은 이러하지만 추상클래스의 뒷면에 존재하는 느낌은 수직적인 작업의 분할이라는 아주 무서운 개념이 숨어 있습니다. 프로그램을 하면서 어떻게 계층적으로 프로그램을 할지를 결정하지말고 펜을 들고 작업을 분석하는 것이 옳을 것입니다. 그리고 작업 분석이 끝났다면 수직과 수평의 개념을 적용 시켜서 어느 정도 설계를 하는 것이 옳을 것입니다. 하지만, 기본적인 배경 없이는 아무것도 할 수 없으니 지금은 느낌을 얻으시기 바랍니다.

 

여러분이 클래스를 만들고 시간이 지나서 다시 여러분이 만든 클래스를 볼 기회 있을 것입니다. 절대 같은 디자인의 클래스는 만들 수 없습니다. 물론, 클래스를 만드는 기법은 비슷하지만 같은 디자인으로는 프로그램을 하려고 해도 잘 되지 않습니다. 약간의 시간이 지난 후, 과거와 현재를 비교해 보면 여러분 스스로 진화했다는 말을 사용해도 될 만큼 아주 많은 발전을 이룬 것을 볼 날이 있을 것입니다. 

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

static 키워드 바로 알기  (0) 2011.09.11
오버로딩, 오버라이딩, 추상클래스, 인터페이스 개념  (0) 2011.09.11
Final  (0) 2011.09.11
Vector(벡터) 정리  (0) 2011.09.11
자바 벡터 테스트 예제  (0) 2011.09.11
Posted by 모과이IT
,

Final

개발지식창고/JAVA 2011. 9. 11. 23:18

final 키워드는 대개 정적인 방식으로 많이 쓰입니다. 예를 들어 클래스 상수로 쓰이거나, 클래스의 상속이나 메소드 재정의(overriding)을 막기 위해서 자주 사용되죠.

상대적으로 잘 쓰이지 않지만, 초기화 이후에 값을 바꿀 수 없는 변수를 만드는 동적인 용도로도 사용이 가능합니다. 자바 언어 레퍼런스를 보면 다음과 같이 내용이 있습니다:

A variable can be declared final. A final variable may only be assigned to once. It is a compile time error if a final variable is assigned to unless it is definitely unassigned immediately prior to the assignment.

C나 C++에 const라는 키워드가 있는데 변수에 대해서는 final보다 const가 더 적절한 이름이라고 생각합니다. 하지만, 클래스나 메소드 정의에 부여하는 경우는 final이 아주 좋다고 생각합니다.

배열을 인자로 받아서 합계를 내는 함수가 있다고 해보죠.

int sum(int[] a) {
  int result = 0;
  for (int i : a)
       result += i;
  return result;
}

이 경우 어떤 이유에서건 아래와 같이 구현된다면 해당 메소드를 사용자 입장에서는 의도하지 않은 결과를 접하게 될 가능성이 높습니다.

int sum(int[] a) {
 int[] others = {-1, -2, -3};
 a = others;
 int result = 0;
 for (int i : a)
  result += i;
 return result;
}

간단한 예를 통해서 보면 완전히 어리섞은 구현이긴 합니다. 하지만, 테스트가 없이 장문의 타이핑을 하는 환경에서는 이와 유사한 일이 일어나지 말라는 법은 없습니다.

int sum(final int[] a) {
  int result = 0;
  for (int i : a)
       result += i;
  return result;
}

이와 같이 정의해주면 적어도 a에 새로운 할당을 시도할 수 없게 됩니다.

3 + 4 = ?

위와 같이 더하기라는 연산을 할 때 피 연산자인 3과 4는 변하지 않습니다. 3과 4가 변한다면 사람들은 위험해서(?) 덧셈을 하지 않겠죠. :)

sum()에 인자로 제공해주는 것은 피연산자와 같습니다. 의미적으로 상수가 전달되어야 하는 경우라고 할 수 있죠. 이럴 때 final을 붙여주면 보다 의미가 명확해질 수 있습니다.

아래와 같은 구문에 왜 final을 쓰면 안되느냐는 질문을 받은 일이 있습니다.

int sum(int[] a) {
  final int result = 0;
  for (int i : a)
       result += i;
  return result;
}

자칫 범하기 쉬운 오류지만, result라는 변수의 용처를 명확하게 정립해보면 논리적인 오류임을 알 수 있습니다. result는 말 그대로 임시 저장소입니다. 지역 변수(local variable)은 임시(temp/temporary) 변수라고 하는데 딱 어울리는 용도로 사용한 것이죠.

세로 타원으로 그린 것이 for 문의 실행시의 논리적인 영역을 나타냅니다. 문맥(context)이라고 할 수도 있겠죠.  반복이 진행되면서 우측으로 이동하기 때문에 배열의 요소들의 이전 값을 기억하기 위해서는 별도의 저장소가 요구됩니다. 어떤 프로그래밍 언어를 배우거나 초기에 익히는 것이지만, 논리적으로 이러한 그림을 머리속에 그릴 수 있다면 더욱 복잡한 경우를 포용할 때 매우 유리합니다.

위와 같은 경우 a[0]의 값이 temp에 들어가 있어야 하고, 반복이 한 차례 더 수행되면 temp 값에 a[1]을 더한 값이 다시 할당되어져야 하니 final로 정의하는 것은 실수죠.
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 모과이IT
,

●벡터(Vector)

   1. 대용량의 데이터를 효과적으로 다룰 있는 클래스

   2. 용량의 변경이 용의

   3. 벡터에 저장하는 모든 데이터는 Object타입

   4. 어떤 종류의 객체도 함께 담을 있다.

   +++ 배열의 크기를 한번 정해지면 변경 불가하고 같은 종류의 데이터만

        사용할 있다는 단점 보안

 

벡터 생성자

   1. Vector :  초기용량이 10, 용량 초과시 크기를 두배 증가

   2. Vector(int aaa) : 지정한 크기의 용량으로 초기화된 Vector 객체를 생성한다.

   3. Vector(int aaa, int bbb) : 지정한 크기의 용량으로 초기화된 벡터객체를 생성하고

                                          용량 초과시 bbb만큼 증가 시킨다.

일반적으로 용량의 문제가 거의 발생하지 않기 때문에 보통 인자가 없는

    생성자를 사용하여 벡터 객체를 생성한다.      Vector v = new Vector();

 

●벡터에 객체 저장

  메소드

   1. void add(int index, Object object) - 지정한 인덱스의 위치에 객체를 추가함

   2. void addElement(Object objec) - 벡터의 끝에 객체를 추가한다

        Vector v = new Vector();

        v.add(1, "은주");             //지정한 위치에 객체 추가

        v.addElement("현규");     //마지막에 객체 추가

        v.addElement("수미");     //마지막에 객체 추가

 

●벡터로 부터 객체 삭제

  메소드

1.       Object remove(int index) – 지정한 위치의 객제를 벡터에서 제거

2.       boolean remove(Object object) – 지정한 객체를 벡터에서 제거

3.       void clear() – 벡터의 모든 요소를 제거

) Vector v = Vector();            //벡터 생성

   v.remove(3);                        //지정한 위치의 객체 제거

   v.remove(“은주”);            //지정한 객체 제거

   v.clear();                        //벡터의 모든 요소를 제거

 

●벡터로 부터 객체 검색

  메소드

1.       Object elementAt(int index) – 지정한 위치의 객체를 리턴

2.       Object get(int index) – 지정한 위치의 객체를 리턴

벡터에 요소를 추가할 때는 String형을 그대로 사용할 있지만 검색한 결과는 Object형이므로 사용하기 위해서는 원래 데이터형으로 캐스팅해야 한다.

) Vector v = Vector();                        //벡터 생성

   String s = (String)v.elementAt(0);            //지정한 위치의 객체를 리턴

   String s2 = (String)v.get(1);                   //지정한 위치의 객체를 리턴

   Enumeration e = v.elements();            //Vector 요소의 리스트를 리턴

    Iterator 비슷한 역할(저장 객체 추출)

 

 

●벡터의 기타 메소드

1.      int capcity() – 벡터의 현재 용량의 리턴

2.      boolean contains(Object object) – 주어진 요소가 벡터에 있는지 알아낸다.

3.      int indexof(Object object) – 주어진 요소의 위치를 리턴(없으면 -1)

4.      int size() – 벡터에 포함되어 있는 요소의 수를 리턴

5.      void trimToSize() – 벡터의 용량을 현재 벡터의 크기에 맞게 수정

 

Enumeration

벡터에 저장된 객체를 열거형으로 리턴

  Enumeration e = v.elements();               //Vector 요소의 리스트를 리턴

     While(e.hasMoreElements()) {

    System.out.println(e.nextElement());

}

 

Iterator

Collection 저장된 객체를 나열 또는 열거하기 위한 인터페이스

  Iterator ie = v.iterator();         //Vector 요소의 리스트를 리턴

  While(ie.hasNext()){

    System.out.println(ie.next());

}

 

Stack

1.      Object 저장하는 하나의 방법

2.       가장 나중에 들어간 데이터가 가장 먼저 밖으로 나오는 형태

LIFO(Last In First Out)

) import java.util.*;

public class StackTest{

public static void main(String[] args){

      Stack s = new Stack();

      System.out.println(s.empty());           //스택이 비어있는지 확인 true

      s.push(“은주”);           //데이터 넣기

      s.push(“현규”);

      System.out.println(s.empty());           //false

      System.out.println(s.peek());   //가장 먼저 나올 데이타(은주)

      System.out.println(s.pop());           //스택에 저장 되어 있는 차례로 출력

      System.out.println(s.pop());

      System.out.println(s.empty());            //스택이 비어있는지 확인 true

}

}

 

LinkedList

1.      List 인터페이스의 링크 리스트의 구현

2.      void add(int index, Object element) – 지정된 위치에 지정된 요소 삽입

void addLast(Object element) – 리스트의 마지막에 지정된 요소 추가

Object get(int index) – 지정된 위치에 있는 요소 리턴

Object getLast() – 리스트내의 마지막 요소 리턴

Object remove(int index, Object element) – 지정된 위치에 있는 요소 삭제

3.      데이터의 첨가, 삭제가 편리하고 속도가 빠르다.

 

Map & hashing

키와 값의 쌍으로 이루어진 요소를 저장하는 자료구조

해싱이란 키객체를 처리하여 hash code(정수값) 만들어 내는 방법이다.

 

HashMap

Null허용, Map interface implements 클래스

 

Hashtable

Null 허용하지 않음, Map interface implements 클래스

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

추상클래스의 개념  (0) 2011.09.11
Final  (0) 2011.09.11
자바 벡터 테스트 예제  (0) 2011.09.11
Eclipse Console 에서 한글이 깨지는 경우  (0) 2011.09.11
[JAVA] 자바의 자료형  (0) 2011.09.10
Posted by 모과이IT
,

자바 벡터 테스트 예제 기본입니다.
기본적인 기능을 있는 예제 입니다.

class VectorTest 
{
 public static void main(String[] args) 
 {
  /*
  // Vector의 요소 접근
  java.util.Vector v = new java.util.Vector();

  for(int i=0; i<args.length; i++)
   v.addElement(args[i]);  // 데이터를 낱개로 addElement을 사용
  System.out.println(v);

  for(int i=0; i<v.size(); i++){
   System.out.println("Vector " + i + "번째 요소는 " + v.elementAt(i));
  }
  */
  /*
  // Vector의 요소 찾기
  java.util.Vector v = new java.util.Vector();
  for(int i=0; i<args.length; i++)
   v.addElement(args[i]);

  String s = "임꺽정";

  if(v.contains(s)){
   int i = v.indexOf(s);
   System.out.println("해당 객체가 " + (i+1) + "번재 있다.");
  }
  else{
   System.out.println("해당 객체가 없다.");
  }
  */

  /*
  // 벡터의 요소 지우기
  java.util.Vector v = new java.util.Vector();

  for(int i=0; i<args.length; i++)
   v.addElement(args[i]);  // 데이터를 낱개로 addElement을 사용
  System.out.println(v);

  for(int i=0; i<v.size(); i++){
   System.out.println("Vector " + i + "번째 요소는 " + v.elementAt(i));
  }

  System.out.println("===================지우고 난 후 ==================");

  v.removeElementAt(0);

  for(int i=0; i<v.size(); i++){
   System.out.println("Vector " + i + "번째 요소는 " + v.elementAt(i));
  }
  */

  // Vector의 크기 변화 시키기 
  java.util.Vector v = new java.util.Vector();

  for(int i=0; i<args.length; i++)
   v.addElement(args[i]);  // 데이터를 낱개로 addElement을 사용

  System.out.println("벡터에 들어있는 엘리먼트 수는 " + v.size());
  System.out.println("벡터의 크기는 " + v.capacity());

  v.trimToSize();

  System.out.println("벡터의 크기는 " + v.capacity());


 }
}

==========================예제2===================================== 

자바 벡터를 객체로 적용된 예제입니다.

class Mem{
 String name;
 int age;
 String address;

 Mem(String name, int age, String address){
  this.name = name;
  this.age = age;
  this.address = address;
 }
 void Disp(){
  System.out.println(name + "\t" + age + "\t" + address);
 }
}

class VectorTest1 
{
 public static void main(String[] args) 
 {
  Mem ob1 = new Mem("홍길동", 24, "서울");
  Mem ob2 = new Mem("임꺽정", 28,  "광주");
  Mem ob3 = new Mem("이순신", 32, "제주");

  java.util.Vector v = new java.util.Vector();
  v.addElement(ob1);
  v.addElement(ob2);
  v.addElement(ob3);

  //System.out.println(v);

  java.util.Enumeration e = v.elements();
  
  Mem m[] = new Mem[3];
  int i = 0;
  while(e.hasMoreElements()){
   m[i] = (Mem)e.nextElement();
   i++;
  }

  m[0].Disp();
  m[1].Disp();
  m[2].Disp();
///////////////////////////////////////////////////////////////
  for(i=0; i<3; i++){
   Mem m2 = (Mem)v.elementAt(i);
   m2.Disp();
  }

 }

}

 

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

Final  (0) 2011.09.11
Vector(벡터) 정리  (0) 2011.09.11
Eclipse Console 에서 한글이 깨지는 경우  (0) 2011.09.11
[JAVA] 자바의 자료형  (0) 2011.09.10
이클립스로 자바 프로그램 Hello World 만들기  (0) 2011.09.10
Posted by 모과이IT
,

최근 Java Module을 만들면서 UTF-8로 프로젝트를 생성하고 코드를 작성하고 있었다.
회사에서 배포하는 Module이 다국어를 지원 할 수 있어야 하는 관계로 어쩔 수 없는 상황.

그런데 묘하게도 실행/디버깅을 하는 과정에서 Eclipse 콘솔 화면에 한글이 깨져서 출력되는 것이다.

이클립스 콘솔에서 어플리케이션 실행 시 한글이 깨져서 출력되는 모습.


'아띠...! 이게 모야...'

위 화면은 실제 업무중 어플리케이션 실행시 입력한 인자값을 체크하여 부적합한 옵션 입력 시 에러를 출력하는 화면을 간단하게 만들어 테스트 하는 과정에서 발생한 경우이다.

프로젝트 인코딩을 UTF-8로 설정하였기에 각 Java 소스 파일이 ANSI로 저장되었나 싶어 확인 해보니 Java 소스는 UTF-8 포맷으로 저장되어 있었다.

이쯤 되면 이제 고민에 빠진다... 구글링을 할 것인가.. 그냥 넘어 갈 것인가.
요즘 출퇴근 하는 동안 '실용주의 프로그래머' 라는 책을 읽고 있는데, 책의 저자를 생각해서라도 저건 그냥 넘어가서는 안될 것 같았다. 찾아보면 해결방법은 얼마든지 있다.

Run Configuration > 작성중인 Application 선택 > Common 탭 으로 이동하여 보면 "Console Encoding" 이라는 항목이 있으며, Default 가 inherited 되어 있기 때문에 현재는 Console Encoding이 UTF-8로 설정되어 있을 것이다. 이걸 Other 옵션에서 EUC-KR로 바꿔준다.

현재 Console Encoding 이 UTF-8 로 프로젝트 Encoding에 의해 상송되어 있다.

Other 옵션을 체크하고 우측의 Select Box 에서 EUC-KR을 선택하였다.


위 화면과 같이 설정하고 Apply를 클릭.
이제 어플리케이션을 실행하여 한글이 정상적으로 출력 되는지 확인하는 과정만 남았다.
두근거리는 가슴을 안고 실행...!!


오~!! 멋져..!! 이제 한글이 정상적으로 출력 된다.
이런 순간이 되면, 오늘 할일을 다 한것 같은 기분이 든다.

Posted by 모과이IT
,

[JAVA] 자바의 자료형

▶ 자료형 : 데이터가 갖는 형으로 데이터의 실질적인 구조 및 개념을 의미한다.

▶ 기본 자료형
- boolean, byte, short, int, long,float, double, char

▶ 참조형 (주기억 장치에 저장되어 있는 객체의 주소값을 가르킨다.)
-  배열 참조형 : 배열 객체를 참조하기 위한 자료형
- 클래스 참조형 : 클래스 객체를 참조하기 위한 자료형
- 인터페이스 참조형 : 인터페이스 객체를 참조하기 위한 자료형

▶ 정수 리터널
* 리터널 : 값이 한번 정의되면 프로그램이 실행되는 도중에 변하지 않는 값으로 소수점을 갖지 않는 정수를 말한다.
- 10진수형 : 숫자 0~ 9로 구성된 자연수 (ex 234)
- 8진수형 : 0~7이내 상수앞에 '0'을 붙인다. (ex 071)
- 16진수형 : 0~9, A~F 상수앞에 '0x'를 붙인다. (ex 0xc1)
- long형 : 상수뒤에 'l' 또는 'L'을 붙인다. (ex 36l, 36L)

▶ 정수형 변수
* 변수 : 프로그램 실행 중 처리대상이 되는 자료나 처리된 결과를 기억시킬 기억장소의 이름으로 실행도중 그 값이 변할 수 있다.


- 정의 방법 : 자료형 변수1; (ex int a; 또는 int a=0;)
- 데이터의 표현 : "2의 보수에 의한 표현방법"에 의해 표현되며, 최상위 비트(MSB)는 부호 비트로 사용된다.
* 보수 : 뺄셈을 덧셈으로 연산하기 위해 보수라는 개념을 사용하며 가산기를 이용하여 뺄셈을 수행할 목적으로 보수를 사용한다.

▶ 부동 소수 리터널
- float 형 상수 : 'f' 또는 'F'를 끝에 붙여 표현한다.
(ex .0f, 10.5f)
- doule 형 상수 : 아무것도 붙지 않거나 'd' 또는 'D'를 붙인다.
(ex 10.0 3.14D)

▶ 실수형 변수


- 정의 방법 : 자료형 변수1;
- 특징 : (1)무한대의 수나 0에 가까운 수의 표현이 가능하다.
           (2) 부동소수 연산에서는 어떤 예외도 발생하지 않는다.
           (3) 자바에서의 부동소수 값은 Float나 Double클래다음과 같이 정의되어 있다.
                  Float.POSITIVE_INFINITY : 양의 무한대 값
                  Float.NEGATIVE_INFINITY : 음의 무한대 값
                  Float.NaN : 부정, Not-a-Number(0으로 나누었을 때와 같은 잘못된 수식의 결과)
                  Double.POSITIVE_INFINITY: 양의 무한대 값
                  Double.NEGATIVE_INFINITY: 음의 무한대 값
                  Double.NaN: 부정, Not-a-Number(0으로 나누었을 때와 같은 잘못된 수식의 결과)

▶ 논리 자료형으로 boolean으로 1Byte, true 또는 false 값을 갖는다.

▶ 문자 리터널
* 단일 문자로 구성되며, 단일 인용부호('')로 둘러 싸여 있고 한 문자를 의미한다.
(ex 'A'     '1')

▶ 확장열
* 키보드로 직접 표현할 수 없는 문자등을 처리


▶ 문자열 상수
* 하나 이상의 문자들로 구성되며, 이중 인용부호("")안에 사용한다.
(ex "A"     "1")

▶ 문자형 변수
* 기본적으로 char자료 형을 사용하며 Unicode로 표현한다.


- 정의 방법 : char 변수1;

▶ 변수의 초기 값
* 멤버 변수를 선언하고 초기화 하지 않는 경우 기본값으로 초기화 된다. 하지만 지역변수는 초기화 하지 않으며, 지역변수를 초기화 하지 않고 사용할 경우 컴파일 오류가 발생한다.



Posted by 모과이IT
,