JAVA/Study

[0127] 2. 변수와 타입 , String 클래스의 특성, Scanner 사용

1) 변수와 타입

1.1 변수란? 

    - 하나의 값을 저장 할 수 있는 메모리 공간

    - 변수의 선언 : 타입 변수이름, int age; double value;

    - 변수 이름 명명 규칙 : 첫 글자는 문자, 소문자여야한다! 다른 단어를 이어붙여쓸 경우 첫자를 대문자로 한다.

1.2 데이터 타입

    - 기본 타입(자료형) : 정수형, 실수형, 논리형으로 3종류의 8가지 타입이 있으며 값이 저장된다.

    - 참조 타입(자료형) : 배열, 열거, 클래스, 인터페이스, 참조 자료형은 주소 값을 가진다.

1.3 타입 변환

    - 데이터의 자료형을 다른 자료형으로 변환하는 행위

    - 변환 종류 : 묵시적(Promotion), 명시적(Casting) - Casting 시에는 데이터 오버플로우를 주의해야한다.

    - 데이터 연산 시에 타입이 다를 경우 피연산자중 큰 타입으로 자동변환하여 연산된다.

      └ int + double > int형이 double형으로 변환되어 연산한다.

      └ int형으로 연산을 원할 경우 double형을 int형으로 Casting 해줘야 한다.

1.4 참조 자료형 instance

    - 참조 자료형 변수를 비교 연산자(==, !=)로 비교 할 경우 주소 값을 비교한다.

    - 묵시적 객체 생성시 대입하는 상수 값이 같으면 같은 주소를 가진다.

    - String 클래스는 불변적 특징으로 인해 String 클래스에 문자열을 이어붙일 경우 힙 영역에 

      └ 잉여 객체가 생성되며 가비지 컬렉터가 이를 자주 소거하게 하여 자원을 낭비하게 된다.

    - 주의해야 할 사항 > 안드로이드, 미들웨어 환경에서는 메모리 효율이 매우 중요하다!

1.5 JVM이 사용하는 메모리 영역

    - 메모리 영역 : 메소드 영역(클래스, 바이트코드 등), 힙 영역(객체, 배열 등), JVM스택(지역변수, 지역메서드)

    - 위 내용은 매우 간략히 간소화 시킨 내용이며 좀 더 깊은 내용은 이후에 다루게 된다.

1.6 import

    - 외부에 있는 패키지 및 클래스를 불러오는 명령어

    - Scanner : 인풋 스트림을 통해 문자 데이터를 전달받는다.

    - System.in : 키보드 장치로부터 입력받는다.

 


소스 코드

package ex1;

public class Ex1_Demotion {
    public static void main(String[] args) {
        byte num1 = 10;
        byte num2 = 20;
        byte num3 = (byte) (num1 + num2);
        System.out.println(num3);
        System.out.println("------------------------------------");
        // 연습) short sh1, sh2에 값을 각각 100, 200을 대입
        // short sh3에 sh1 + sh2 연산값을 저장한 후 출력 해봅시다
        
        short sh1 = 100;
        short sh2 = 200;
        short sh3 = (short) (sh1+sh2);
        int sh = sh1 + sh2;
        System.out.println(sh1 + " + " + sh2 + " = " + sh3);
        System.out.println("------------------------------------");
        
        // -------------------------------***
        char ch1 = 'A'; // A는 유니코드로 65
        System.out.println("ch1 : " + ch1);
        short ch2 = 1;
        System.out.println("정수형과 연산 : " + (ch1 + ch2));
        // int형으로 승격
        char ch3 = (char) (ch1 + ch2); // 연산시에는 캐스팅을 통해 디모션해준다.
        // char형은 문자로 변환한다.
        System.out.println(ch3); // 66은 유니코드로 B이므로,
        // -------------------------------***
        
        char ch4 ='가';
        System.out.println(ch4);
        char ch5 = 44032;   // 10진수로 표기한 유니코드 '가'
        System.out.println(ch5);
        char ch_def = '\u0000'; // 초기화
        System.out.println("char의 초기값 : " + ch_def);
        char ch6 = '\uac00'; // 16진수로 표기한 유니코드 '가'
        System.out.println(ch6);
        // 유니코드 문자열을 한 문자씩 char에 저장해서 출력할때도 사용 가능
    }
}

package ex1;

public class Ex1_Variable1 {
    public static void main(String[] args) {
        
        // pojo 타입에서 다른 외부 프레임워크에서
        // 현재의 변수 Val을 인식 못하는 경우가 발생한다.
        // 변수는 반드시 소문자로 작성해야 한다.
        int Val = 10;
        System.out.println("Val : " + Val);
        
        // 변수 이름의 권장 사례 (pdf 2장 참고)
        int ifCase = 0;
    }
}

package ex1;

public class Ex1_VariableDataType {

    // Alt + shift + f : 자동 정렬 코드
    public static void main(String[] args) {
        int a = 3; // 선언과 초기값을 대입
        int b; // 선언
        b = 3; // 대입

        // + 연산자 : 덧셈, 문자열 연결 연산자.
        System.out.println("a의 값 :" + a);
        System.out.println("b의 값 :" + b);
        // PDF 2장 2절 데이터 타입 참조해서 설명
        // 4바이트 이하의 자료형은 저장할 수 있으나 JVM의 연산시
        // int형이 되기 때문에 잘 사용하지 않음
        byte d = 100;
        short c = 50;
        System.out.println("d의 값 :" + d);
        System.out.println("c의 값 :" + c);
        // 리터러 상수값 : \n (개행)
        System.out.println(
                "변수 a의 값 :" + a + "\n"
                + "변수 b의 값 :" + b + "\n"
                + "변수 c의 값 :" + c + "\n"
                + "변수 d의 값 :" + d);

        // 시스템의 현재 시간을 밀리세컨드 => 1/1000 출력
        System.out.println(System.currentTimeMillis());

        // long형 8byte -> int 4byte
        // int형의 자료형의 범위를 넘어서는 값이라면
        // 오버플로우가 발생해서 정확한 값이 나오지 않는다.
        // 큰 자료형의 데이터를 작은 자료형으로 바꿀때 사용 - 캐스팅, 디모션
        
        // long형 데이터를 반환해주는 currentTimeMillis()에 (int)를 캐스팅하여
        // 데이터가 오버플로우 되어 데이터 손실이 발생합니다.
        // 그리고 나서 long형 time2에 대입해주며 프로모션이 작용하지만
        // 이미 데이터는 손실이 발생하여 int형이 담을수 있는 값만 대입되게 됩니다.
        long times2 = (int) System.currentTimeMillis();
        System.out.println("long형 time2에 int형으로 캐스팅한 값을 대입할 경우 : " + times2);
        
        // 자료형 변환 예제
        // currentTimeMillis() 함수는 long형 데이터를 반환하므로
        // int형 times 변수에 대입해줄때 (int)를 통해 캐스팅(디모션) 해준다.
        int times = (int) System.currentTimeMillis();
        System.out.println("int형 time 변수의 값 : " + times);

        // long형 time1 변수는 캐스팅 없이 바로 대입이 가능하다. (같은 데이터 자료형)
        long times1 = System.currentTimeMillis();
        System.out.println("long형 time1 변수의 값 : " + times1);
                
        // long 자료형 변수 e에 접미사 L을 붙이지 않을 경우 컴파일 오류 발생.
        long e = 1000000000000000000L; // L, l 리터럴 접미사
        // 오류 발생의 이유는 상수의 경우 접미사가 없을 경우
        // 기본적인 자료형이 int로 정의 되는데 e = 1000000000000000000; 코드는
        // int형이 담을 수 있는 데이터를 초과하여 오버플로우가 발생하기 때문.
        
        System.out.println("변수 e의 값은 : " + e);

        // 상수 => 프로그램 영역안에서 한번 선언 후 유지하기 위해 사용.
        // [final] [자료형 [변수] = 값;
        // local 영역에 선언한 상수, 대문자료 표기하는 것이 원칙이나
        // 인터페이스 등에서는 변수와 같은 소문자로 표기 할 수 있다.
        final int SIZE;
        SIZE = 5;
        System.out.println("상수값 : " + SIZE);
        //SIZE = 15; (불가능)
        //**************************************************************

        float g = 3.14f; // double -> 3.14이고 -> F,f의 리터럴 접미사 필요
        double h = 3.14; // double, 3.14d도 가능, d,D 리터럴 접미사
        boolean i = true;

        // 자바에서는 한 문자를 유니코드로 인식(2byte)
        char j = 'A';   // 문자는 ' '를 사용한다. " "는 참조자료형이다.
        int k = (int) 100L; // 디모션, 캐스팅(강제적) (큰 => 작은)
        long l = k; // 프로모션(묵시적) (작은 => 큰)
        System.out.println("float : " + g + "\ndouble : " + h
                + "\nboolean : " + i + "\nchar : " + j + "\nint : " + k
                + "\nlong : " + l);
    }
}

package ex1;

public class Ex3_ReferenceDataType {
    // 1) jvm -> main 메서드가 호출
    public static void main(String[] args) {
        // String 타입의 참조 자료형 변수 str을 선언
        // null도 주소값이다 (값이 없는 상태의 주소값이다)
        // heap 영역의 주소값을 의미한다.
        // 2) 지역 변수 선언, 힙에 생성 된 null의 주소를 저장
        String str = null;
        // 3) System 클래스 안에 PrintStream이 힙에 생성이 되고
        // println() 함수를 호출 , 스택에서 제거(pop)
        System.out.println("result1 : " + str);
        // 4) 새로운 형태로 System 클래스 안에 PrintStream이 힙에 생성이 되고
        // println() 함수를 호출 , 스택에서 제거(pop)
        System.out.println("result2 : " + str);
        // 5) main 메서드가 종료 되면서 스택에서 빠져 나가기 때문에
        // 이 안에 선언 된 모든 지역 변수도 함께 사라진다.
        
        int num1 = 100;
        System.out.println(num1); // 정수형 변수는 println() 할 경우 문자열로 변환
        
        // String 문자열 참조 자료형 변수를 선언
        String str1;
        // 글자의 갯수와는 상관이 없다.
        str1 = "aaaaaabbbbbbcccccc";
        System.out.println(str1);
        
        // 문자열의 길이를 확인하기 위한 String 클래스의 메서드를 호출
        System.out.println(str1.length());
        str1 = "                   h1"; // 공백도 문자열로 인식됨
        System.out.println(str1);
        System.out.println(str1.length());
        
        str1 = null;                // 다시 초기화
        str1 = "hi" + "one";        // 문자열 + 문자열 : 연결의미
        System.out.println(str1);   // *** 문자열은 객체, 불변적 특징이 있다
        
        str1 = "hi" + 10;           // 문자열 + 비문자열 : 연결의미
        System.out.println(str1);
        
        str1 = false + "hi";
        System.out.println(str1);
    }
}

package ex1;

public class Ex3_ReferenceDataType1 {
    // 핵심 포인트 : 참조 자료형일 ? == , != 연산자는 값을 비교하는 것이
    // 아니라 주소 값을 비교한다.
    public static void main(String[] args) {
        // == 비교 연산자 (<,>,|=, <=, >=) : boolean
        // +, -, /, *, % => 산술 연산자
        int num1 = 10;
        int num2 = 20;
        // 일반 자료형일 경우 값 비교
        System.out.println("num1 == num2 => " + (num1 == num2));
        System.out.println("num1 != num2 => " + (num1 != num2));
        
        // 참조 자료형일 경우 ***** : 주소 값을 비교한다.
        // 명시적 객체 생성시에는 
        
        String str1 = new String("Test"); // 0x100
        String str2 = new String("Test"); // 0x200
        System.out.println("str1 == str2 => " + (str1 == str2));
        
        // 내용을 비교하고 싶을 때는 String 클래스에서 제공하는 메서드를 활용
        System.out.println(str1.equals(str2));
        // 내용을 비교할 때 대소문자 구분없이 비교해서 제공하는 메서드
        System.out.println(str1.equalsIgnoreCase(str2));
        System.out.println("----------------------------------");
        
        // 묵시적 객체 생성 방법
        // 상수 값이 같을 경우에는 주소 값이 같다 *****
        // 설명) 
        // step1) s1에서 객체가 100번지로 힙에서 생성이 된다. [상수풀] Test
        // step2) s2에서는 선언 한 후에 상수풀에 이미 등록 된 Test가 존재 하기 때문에
        // 힙에서 더 이상 생성하지 않고 이미 힙에서 생성 된 100번지를 s2가 함께 참조하는 개념
        String s1 = "Test";
        String s2 = "Test";
        System.out.println("s1 == s2 " + (s1 == s2));   // true
        
        // String 클래스의 불변적 특징.
        // 때문에 힙 영역에 잉여 객체를 가비지 객체가 소거하는 자원을 낭비하게 된다.
        // 주의해야 할 사항 -> 안드로이드, 미들웨어 환경에서는 메모리 효율이 매우 중요함.
        String msg = "AB";
        msg = msg + "CD";
        msg = msg + "EF";
        System.out.println(msg);    // ABCDEF
        
        String msg2 = "AB";
        msg2 += "CD";
        msg2 += "EF";
        System.out.println(msg2);    // ABCDEF
        System.out.println("----------------------------------");
        
        // 개선책 += -> StringBuffer와 같은 버퍼 클래스를 생성해서 사용 권장!!
        // 스레드 동기화 여부에 따른 차이가 있다.
        // 객체를 생성
        StringBuilder sb = new StringBuilder();
        
        // 생성 된 객체의 주소 값을 저장한 sb를 가지고 "."(참조연산자) 가지고
        // 해당 객체를 찾아가서 가지고 있는 메서드를 호출해서 사용하는 방법
        // 주소가 버퍼에 유지 되기 때문에 가비지 컬렉션이 불필요하게 객체를 삭제
        // 하는데 자원을 소비하지 않는다 -> 효율적이다.
        sb.append("ABABAB");
        sb.append("CDCDCD");
        sb.append("EFEFEFEF");
        System.out.println(sb);
        
        int cap = sb.capacity();
        System.out.println("용량 : " + cap);
        System.out.println("길이 : " + sb.length());
        sb.delete(0, 14);
        System.out.println(sb);
        sb.trimToSize(); // 문자열 데이터 사이즈 최소화
        cap = sb.capacity();        
        System.out.println("용량2 : " + cap);
        System.out.println("길이2 : " + sb.length());
    }
}

package ex1;

import java.util.Scanner;

// 클래스를 객체로 생성 해보기
// jdk 5부터 제공해주는 Scanner 클래스를 생성해보자
// 외부 패키지에 있는 클래스를 불러오는 방법
// import 패키지명.클래스명 -> 올바른 표현 방법
// import 패키지명.*;       -> 나쁜 표현 방법
// import java.util.Scanner;

public class Ex4_Scanner {
    public static void main(String[] args) {
        // String str; 클래스 변수 선언
        // Scanner sc;
        // 단축키 ctrl + space (클래스 내부 함수 보기, 클래스 자동 import)
        // System.in : 키보드 장치로 입력
        // sc = new Scanner(System.in);
        
        // 실전
        System.out.print("메세지 입력하세요 : ");
        Scanner sc = new Scanner(System.in);
        
        // . 연산자를 사용해서 힙에 접근해서 Scanner가 가지고 있는
        // 자원을 접근해서 사용한다.
        // sc.nextLine() 호출하면 반환 값이 String 이다.
        // 그래서 메서드가 수행한 후의 그 값을 변수에 저장해서
        // 다시 가공해서 사용하는 것이 일반적이다.
       
        String msg;
        msg = sc.nextLine();    // 대기하는 메서드 (blocking 메서드)
        System.out.println("Msg : " + msg);
    }
}