Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

개발자입니다

[Java] 예제 소스 정리 - 생성자 활용, 인스턴스 메서드와 클래스 메서드 활용 본문

네이버클라우드 AIaaS 개발자 양성과정 1기/Java

[Java] 예제 소스 정리 - 생성자 활용, 인스턴스 메서드와 클래스 메서드 활용

끈기JK 2023. 1. 6. 19:44

com.eomcs.oop.ex04

 

예제 소스 정리

 

생성자 활용

 

 

생성자 활용 예 - 자바에서 제공하는 클래스 사용을 통해 생성자 활용을 익혀보자!
public class Exam0111 {

  public static void main(String[] args) throws Exception {
    // 생성자를 호출하여 문자열 인스턴스를 초기화시킨다.

    String s0 = new String(); // default constructor 호출
    System.out.println(s0);
    System.out.println("-----------------------------------");

    // => 문자열 리터럴을 사용하여 String 인스턴스를 초기화시키기.
    String s1 = new String("HelloABCabc012가각간"); // String(스트링 리터럴) 생성자를 호출하여 인스턴스 초기화
    System.out.println(s1);
    System.out.println("-----------------------------------");

    // => char[] 을 사용하여 String 인스턴스 초기화시키기.
    char[] chars = new char[] {'H', 'e', 'l', 'l', 'o'};
    String s2 = new String(chars); // String(char[]) 생성자를 호출하여 인스턴스 초기화
    System.out.println(s2);
    System.out.println("-----------------------------------");

    s2 = new String(chars, 1, 3); // String(char[], offset, count) 생성자를 호출하여 인스턴스 초기화
    System.out.println(s2);
    System.out.println("-----------------------------------");

    // => 바이트 배열을 가지고 String 인스턴스 초기화시키기
    byte[] bytes = {
        (byte)0x48, // H 
        (byte)0x65, // e
        (byte)0x6c, // l
        (byte)0x6c, // l
        (byte)0x6f  // o 
    };
    String s3 = new String(bytes); // String(byte[]) 생성자를 호출하여 인스턴스 초기화

    System.out.printf("%s, %s, %s\n", s1, s2, s3);
  }
}

 생성자의 활용
 => 인스턴스 변수를 초기화시키기 위해 여러 개의 생성자를 만들어 제공할 수 있다.
 => 자신에게 맞는 적절한 생성자를 호출하여 인스턴스를 초기화시킨 후 사용하면 된다. 

 

public class Exam0112 {

  public static void main(String[] args) throws Exception {
    System.out.println(Charset.defaultCharset());

    // 한글 문자 코드의 바이트 배열을 가지고 String 인스턴스 초기화시키기.
    byte[] bytes = {
        (byte)0xb0, (byte)0xa1, // 가 (EUC-KR 코드)
        (byte)0xb0, (byte)0xa2, // 각 (EUC-KR 코드)
        (byte)0xb6, (byte)0xca, // 똘 (EUC-KR 코드)
        (byte)0xb6, (byte)0xcb  // 똥 (EUC-KR 코드)
    };
    String s1 = new String(bytes); 
    // 바이트 배열에 들어 있는 문자 코드가 어떤 문자집합에 맞춰 작성되었는지 알려주지 않으면
    // String 클래스는 JVM이 가정하는 문자집합으로 작성되었을 거라고 생각하고 Unicode로 변환한다.

    System.out.println(s1);
    System.out.println("----------------------------");
    // 결과: 
    // => 한글 출력이 깨진다.
    //
    // 이유?
    // => String 클래스는 파라미터로 넘겨 받은 바이트 배열을 가지고
    //    유니코드(UCS2) 문자열로 변환할 때
    //    바이트 배열이 OS의 기본 문자 코드로 되어 있다고 간주한다.
    // => OS 마다 기본으로 사용하는 문자 코드표(Character Set)가 다르다.
    //    Windows : MS949
    //    Unix/Linux/macOS : UTF-8
    //    이클립스에서 실행할 경우: OS에 상관없이 UTF-8 이라고 가정한다.
    // => 그런데 위 예제의 바이트 배열은 EUC-KR 코드이다.
    //    그래서 String 클래스는 바이트 배열을 제대로 해석하지 못한 것이다.

    //
    // 해결책?
    // => String 클래스의 생성자를 호출할 때
    //    바이트 배열과 인코딩 정보를 함께 받는 생성자를 사용하라!
    // => 즉 bytes 배열에 EUC-KR의 코드 값이 들어 있다고 알려준다.
    //    그러면 JVM은 바이트 배열에 들어 있는 값을 제대로 유니코드 바꿀 것이다.
    // 
    String s2 = new String(bytes, "EUC-KR");
    System.out.println(s2);
  }
}

 

public class Exam0113 {

  public static void main(String[] args) throws Exception {

    // UTF-8 문자 코드의 바이트 배열을 사용하여 String 인스턴스 초기화시키기.
    byte[] bytes = {
        (byte)0x41, // A
        (byte)0x42, // B
        (byte)0x43, // C
        (byte)0x61, // a
        (byte)0x62, // b
        (byte)0x63, // c
        (byte)0x30, // 0
        (byte)0x31, // 1
        (byte)0x32, // 2
        (byte)0x20, // space
        (byte)0x21, // !
        (byte)0x23, // #
        (byte)0x25, // %
        (byte)0x2b, // +
        (byte)0xea, (byte)0xb0, (byte)0x80, // 가
        (byte)0xea, (byte)0xb0, (byte)0x81, // 각
        (byte)0xeb, (byte)0x98, (byte)0x98, // 똘
        (byte)0xeb, (byte)0x98, (byte)0xa5  // 똥
    };

    String s1 = new String(bytes);
    System.out.println(s1);
    System.out.println("-------------------------------------");
  }
}

 생성자에 바이트 배열을 넘길 때 바이트 배열에 들어 있는 데이터의 문자 코드표를 알려주지 않으면, String 생성자는 OS의 기본 문자 코드표로 간주하여 변환한다.
 따라서 위 예제를 Linux, macOS, Unix 의 CLI(Command Line Interface; 콘솔창/명령창)에서 실행하면 정상적으로 한글 문자열이 출력되지만, Windows에서 실행하면 한글 문자열이 깨진다.

 이유?
 => Linux, macOS, Unix가 기본으로 사용하는 문자 코드표는 UTF-8이다.
 => Windows가 기본으로 사용하는 문자 코드표는 MS949이다.

 그런데 이클립스에서 실행하면 깨지지 않는 이유?
 => 이클립스에서 JVM을 실행할 때 입출력 기본 인코딩을 UTF-8로 설정하기 때문이다.

 Windows CLI에서 깨지지 않게 하는 방법?
 => JVM 실행 옵션에 다음을 추가하라
     -Dfile.encoding=UTF-8
 => java -Dfile.encoding=UTF-8 -cp bin/main 클래스명
 => PowerShell 이 아닌 Command 창에서 실행하라!
    PowerShell 에서는 -Dfile.encoding 옵션을 제대로 처리하지 못한다.
    도트(.)를 분리 문자로 인식한다.

 

 

생성자 활용 예 - java.util.Date 클래스의 생성자
public class Exam0120 {

  public static void main(String[] args) throws Exception {
    // java.util.Date 클래스는 날짜 데이터를 다루는 클래스이다.
    // => 이 클래스에는 날짜 데이터를 다룰 수 있는 다양한 메서드가 들어 있다.

    // Date() 기본 생성자는 메모리를 오늘 날짜 값으로 초기화시킨다.
    Date d1 = new Date();
    System.out.println(d1);

    // 년, 월, 일 값으로 날짜 인스턴스를 초기화시킨다.
    Date d2 = new Date(122, 4, 3);
    System.out.println(d2);

    // 1970년 1월 1일 0시 0분 0초부터 측정된 밀리초를 가지고 
    // 날짜 인스턴스(객체=메모리) 초기화시킨다.
    Date d3 = new Date(1000L * 60 * 60 * 24 * 365 * 50);
    System.out.println(d3);
  }
}

 

 

생성자 활용 예 - java.util.Calendar 클래스의 생성자
public class Exam0130 {

  public static void main(String[] args) throws Exception {
    // 생성자가 있다하더라도 접근 권한이 없다면,
    // 생성자를 호출할 수 없다.
    // 이런 경우 new 명령으로 인스턴스를 생성할 수 없다.
    //    Calendar c = new Calendar(); // 컴파일 오류!

    // Calendar 클래스의 경우도 생성자를 protected 로 막고 있다.
    // 즉 new 명령을 통해 바로 인스턴스를 생성할 수 없다.
    // 대신 클래스 메서드를 통해 생성하도록 유도하고 있다.
    // 
    Calendar c1 = Calendar.getInstance();
    Calendar c2 = Calendar.getInstance();
    System.out.println(c1 == c2);

    System.out.println(c1.get(1));
    System.out.println(c2.get(Calendar.YEAR));
  }
}

getInstance() 호출 시점의 시각이 다르기 때문에 두 객체의 주소는 다르다.

이렇게 자바에서 생성자의 사용 권한을 막고 메서드를 호출하여 객체를 생성하도록 유도하는 경우는 다음과 같다.

1) 같은 값을 갖는 객체를 쓸데없이 여러 개 생성하지 못하도록 하고 싶을 때,
    => 메모리를 절약할 수 있다.
    => 이런 방법을 사용하는 설계 기법: Singleton
2) 객체 생성과정이 복잡할 때,
    => 객체 생성 코드를 단순하게 만들 수 있다.
    => 생성된 객체를 재활용할 수 있다.
    => 이런 방법을 사용하는 설계 기법: Factory Method

 

 

 

인스턴스 메서드와 클래스 메서드 활용

 

 

 

인스턴스 메서드와 클래스 메서드의 활용 - String 클래스
public class Exam0210 {
  public static void main(String[] args) throws Exception {
    String s1 = new String("Hello");

    // s1 인스턴스(s1 레퍼런스가 가리키는 인스턴스)의 값을 조회하는 메서드 사용
    // 따라서 이 메서드를 호출하려면 반드시 String 인스턴스의 주소를 줘야 한다.
    char c = s1.charAt(1);
    System.out.println(c);

    System.out.println(s1.compareTo("Helli"));
    System.out.println(s1.compareTo("Hello"));
    System.out.println(s1.compareTo("Hellq"));

    System.out.println(s1.contains("ll"));
    System.out.println(s1.contains("ee"));

    // 두 문자열을 연결하여 새 문자열을 만들자!
    String s2 = s1.concat(", world!");
    System.out.println(s1); // 기존 인스턴스의 값은 변경하지 않는다.
    System.out.println(s2); // 새로 문자열을 만든다.

    // 두 인스턴스에 들어 있는 문자열이 같은 지 비교할 때 
    System.out.println(s1.equals("aaa")); // false
    System.out.println(s1.equals("Hello")); // true
    System.out.println(s1 == "Hello"); // false

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

    String s3 = new String("ABC가각");
    // 인스턴스에 들어 있는 문자 코드를 바이트 배열로 만들어 리턴한다.
    byte[] bytes = s3.getBytes(); 
    // => 인스턴스에 들어 있는 각 문자를 바이트 배열에 저장할 때 
    //    인코딩 문자집합을 지정하지 않으면 JVM의 기본 문자집합으로 인코딩 한다. 
    //    이클립스에서 JVM을 실행하면 JVM은 기본으로 UTF-8 문자표를 사용하여 
    //    바이트 배열에 코드 값을 저장한다. 
    for (int i = 0; i < bytes.length; i++)
      System.out.printf("%x,", bytes[i]);
    System.out.println();
    System.out.println("-------------------------");

    // 다른 인스턴스 메서드를 사용하여 바이트 배열을 추출해보자.
    bytes = s3.getBytes("EUC-KR");
    for (int i = 0; i < bytes.length; i++)
      System.out.printf("%x,", bytes[i]);
    System.out.println();
    System.out.println("-------------------------");

    // String 클래스에도 특정 인스턴스가 아닌 일반용으로 
    // 문자열을 다룰 수 있는 메서드를 제공한다.
    // 즉 "클래스 메서드=스태틱 메서드"를 제공한다.

    // => 형식을 갖춘 문자열을 만들기
    String s4 = String.format("%s님 반갑습니다", "홍길동");
    System.out.println(s4);

    // => 구분자와 문자열들을 파라미터로 받아서 새 문자열을 만든다.
    String s5 = String.join(":", "홍길동", "임꺽정", "유관순");
    System.out.println(s5);

    // => primitive 값을 문자열로 만든다.
    String s6 = String.valueOf(true); // "true"
    String s7 = String.valueOf(3.14f); // "3.14"
    String s8 = String.valueOf(100); // "100"
    System.out.println(s6);
    System.out.println(s7);
    System.out.println(s8);
  }
}

 

 

인스턴스 메서드와 클래스 메서드의 활용 - wrapper 클래스
public class Exam0220 {
  public static void main(String[] args) throws Exception {
    // 다음과 같이 생성자를 통해 Integer 객체를 생성할 수 있지만,
    // 이 생성자는 사용하지 말라고 권고한 것이기 때문에 
    // 가능한 개발 중에 사용하지 말라!
    Integer obj1 = new Integer(100);
    Integer obj2 = new Integer(200);
    Integer obj3 = new Integer(300);

    // 대신 다음과 같이 클래스 메서드를 사용하여 Integer 인스턴스를 생성하라!
    Integer i1 = Integer.valueOf(100); // int 값을 가지고 Integer 객체를 생성할 때!
    Integer i2 = Integer.valueOf(200);
    Integer i3 = Integer.valueOf(300);

    // 인스턴스 메서드 사용
    System.out.println(i2.compareTo(i1));
    System.out.println(i2.compareTo(i3));

    int v1 = i2.intValue(); // Integer 객체에서 int 값을 뽑아 낼 때 
    System.out.println(v1);

    // 스태틱 메서드 = 클래스 메서드 사용
    int v2 = Integer.parseInt("1280"); // String ===> int 변환
    String s1 = Integer.toBinaryString(77);
    String s2 = Integer.toOctalString(77);
    String s3 = Integer.toHexString(77);
    System.out.printf("77 = %s, %s, %s\n", s1, s2, s3);

    Integer x1 = Integer.valueOf("44"); // 문자열에 있는 수를 10진수로 간주한다.
    Integer x2 = Integer.valueOf("44", 16); // 16진수라고 지정한다.
    System.out.printf("%d, %d\n", x1, x2);

    float f = Float.parseFloat("3.14f");
    boolean b = Boolean.parseBoolean("true");
    System.out.printf("%f, %b\n", f, b);

    float f2 = Float.valueOf("3.14f");
    System.out.printf("%f\n", f2);
  }
}

 

 

Integer 클래스: new Integer() vs Integer.valueOf()
public class Exam0221 {
  public static void main(String[] args) throws Exception {
    Integer obj1 = new Integer(100); 
    Integer obj2 = new Integer(100);
    Integer obj3 = new Integer(100);

    Integer i1 = Integer.valueOf(127); 
    Integer i2 = Integer.valueOf(127);
    Integer i3 = Integer.valueOf(127);

    // 1) 생성자를 통해 객체를 만들면 무조건 새 객체를 만든다.
    System.out.println(obj1 == obj2);
    System.out.println(obj1 == obj3);
    System.out.println(obj2 == obj3);
    System.out.println("---------------------------");

    // 2) valueOf()를 통해 객체를 만들면 자주 쓰는 값(-128 ~ +127)에 대해서는 한 번만 만들어 공유한다.
    System.out.println(i1 == i2);
    System.out.println(i1 == i3);
    System.out.println(i2 == i3);

  }
}

 

 

인스턴스 메서드와 클래스 메서드의 활용 - Math 클래스
public class Exam0230 {
  public static void main(String[] args) throws Exception {
    // Math 클래스는 수학 관련 메서드를 모아둔 클래스이다.
    // 전체 메서드가 "클래스 메서드=스태틱 메서드"이다.

    // => 절대값 계산
    System.out.println(Math.abs(-200));

    // => ceil() : 파라미터로 주어진 부동소수점이 바로 위 큰 정수 값을 리턴
    // => floor() : 파라미터로 주어니 부동소수점의 바로 밑 작은 정수 값을 리턴
    System.out.println(Math.ceil(3.28)); // 4
    System.out.println(Math.floor(3.28)); // 3
    
    System.out.println(Math.ceil(-3.28)); // -3
    System.out.println(Math.floor(-3.28)); // -4

    // => 2의 7승 값을 알고 싶을 때
    System.out.println(Math.pow(2, 7));

    // => 반올림하여 정수 값 리턴
    System.out.println(Math.round(3.14));
    System.out.println(Math.round(3.54));


  }
}

 

 

인스턴스 메서드와 클래스 메서드의 활용 - Date 클래스
public class Exam0240 {
  public static void main(String[] args) throws Exception {
    Date d1 = new Date();

    String str0 = d1.toString();
    System.out.println(str0);

    // 인스턴스 메서드 활용
    System.out.println(d1.getYear() + 1900);
    System.out.println(d1.getMonth() + 1);
    System.out.println(d1.getDate());

    // 스태틱 메서드 활용
    long millis = Date.parse("Sat, 12 Aug 1995 13:30:00 GMT");
    System.out.println(millis);

    // 실무에서는 java.util.Date 대신 이 클래스의 자식 클래스인
    // java.sql.Date을 쓰기도 한다.
    // 이 클래스는 날짜 데이터를 문자열로 다룰 때 
    // yyyy-MM-dd 형식으로 다루기 때문에 편리하다.

    // 스태틱 메서드 활용
    long currMillis = System.currentTimeMillis();

    // 생성자 활용
    java.sql.Date today = new java.sql.Date(currMillis);

    // 인스턴스 메서드 활용 
    String str = today.toString();
    System.out.println(str);

    // 스태틱 메서드 활용
    java.sql.Date d = java.sql.Date.valueOf("2019-12-30");
    System.out.println(d);
    // println()에 문자열을 주지 않고 그냥 객체(의 주소)를 넘기면
    // println() 내부에서 해당 객체의 toString()을 호출한 후에 
    // 그 리턴 값을 출력한다.

  }
}

 

 

인스턴스 메서드와 클래스 메서드의 활용 - Calendar 클래스
public class Exam0250 {
  public static void main(String[] args) throws Exception {
    // Calendar 클래스의 생성자는 protected로 접근이 제한되어 있기 때문에
    // 다른 패키지에서 직접 생성자를 호출할 수 없다.
    //Calendar c = new Calendar(); // 컴파일 오류!

    // 오늘 날짜 및 시간 정보를 저장한 객체를 만들어 리턴한다.
    // 달력은 그레고리안 달력을 사용한다.
    Calendar c = Calendar.getInstance();


    System.out.println(c.get(5));

    // 인스턴스 메서드 활용
    System.out.println(c.get(1)); // 년도
    System.out.println(c.get(2) + 1); // 월(0 ~ 11)
    System.out.println(c.get(5)); // 일
    System.out.println(c.get(7)); // 요일(1 ~ 7)
    System.out.println(c.get(4)); // 그 달의 몇 번째 주
    System.out.println(c.get(10)); // 시(0 ~ 11)
    System.out.println(c.get(11)); // 시(24시)
    System.out.println(c.get(12)); // 분
    System.out.println(c.get(13)); // 초

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

    // 상수의 활용
    System.out.println(c.get(Calendar.YEAR)); // 년도
    System.out.println(c.get(Calendar.MONTH) + 1); // 월(0 ~ 11)
    System.out.println(c.get(Calendar.DATE)); // 일
    System.out.println(c.get(Calendar.DAY_OF_WEEK)); // 요일(1 ~ 7)
    System.out.println(c.get(Calendar.WEEK_OF_MONTH)); // 그 달의 몇 번째 주
    System.out.println(c.get(Calendar.HOUR)); // 시(0 ~ 11)
    System.out.println(c.get(Calendar.HOUR_OF_DAY)); // 시(24시)
    System.out.println(c.get(Calendar.MINUTE)); // 분
    System.out.println(c.get(Calendar.SECOND)); // 초
  }
}