12. java.base 모듈

12.2 java.base 모듈

모든모듈이 java.base를 참조하고있음. 그래서 최소한을 알아야함.
java.lang 등 패키지 들어가잇음. String, system 등 들어가잇음.


너무 많기 때문에 다 외울 필요는 없고 자주 사용되는 것만 알아 두자.
String System Integer Double Exception RuntimeException 들은 java.lang패키지에있고
키보드를 사용한 Scanner는 java.util패키지에 있다.
java.lang은 자바 언어의 기본적인 클래스를 담고 있는 패키지로 이 패키지에 있는 클래스와 인터페이스는 import없이 사용할수있다.

12.3 Object 클래스

클래스를 선언할때 extends 키워드로 다른 클래스를 상속하지 않으면 암시작으로 java.lang.Object 클래스를 상속하게된다.
object가 가지고 있는 필드와 메소드는 모든 클래스에서 사용가능하다.
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html

그중 대표
boolean equals(Object obj) 객체의 번지를 비교하고 결과를 리턴
int hashCode() 객체의 해시코드를 리턴
String toString() 객체의 문자정보를 리턴

12.3.1 객체 동등비교

객체는 달라도 그 안에 데이터가 같다면 동등하다고 본다.
public boolean equals(Object obj)
equals()메소드의 매개변수 타입이 Object 이므로 자동타입 변환에 의해 모든 객체가 매개값으로 대입될 수 있다.
equals() 메소드는 비교 연산자인 ==과 동일한 결과를 리턴한다. 두객체가 동일하면 true 아니면 false 리턴
일반적으로 equals()메소드는 재정의해서 동등비교용으로 사용됨.
동등비교를 하는데 저절로 되느넥 아니라 재정의를해야함.
뭘비교할지 모르니까 비교할 대상을 정해두고 재정의 해야함.
동등비교 기능을 넣고싶으면 넣어야함.

package ch12.sec03.exam01;

public class Member {
public String id;

public Member (String id) {
    this.id = id;
}

@Override //equals() 재정의
public boolean equals(Object obj) {
    if(obj instanceof Member target) {//obj가 Member타입인지 검사하고 타이변환후에 target변수에 대입
        if(id.equals(target.id)) { //id 문자열이 같은지 비교
            return true;
        }
    }
    return false;
}
}

package ch12.sec03.exam01;

public class EqualsExample {

public static void main(String[] args) {

    Member obj1 = new Member("blue");
    Member obj2 = new Member("blue");
    Member obj3 = new Member("red");

    if(obj1.equals(obj2)) {
        System.out.println("obj1과 obj2는 동등합니다.");
    }else {
        System.out.println("obj1과 obj2는 동등하지 않습니다.");
    }

    if(obj1.equals(obj3)) {
        System.out.println("obj1과 obj3는 동등합니다.");
    }else {
        System.out.println("obj1과 obj3는 동등하지 않습니다.");
    }

12.3.2 객체 해시코드

객체 해시코드란 객체를 식별하는 정수를 말한다.
hashCode() 메소드는 객체의 메모리 번지를 이요ㅣㅇ해서 해시코드를 생성하기 때문에 객체마다 다른 정수값을 리턴한다.
두 객체가 동등한지를 비교할때 주로 사용한다.
equals()만으로도 가능하지만 좀 더 정확하게 비교하기 위해서 hashCode를 사용한다.
public int hashCode()
해시코드 -> 이퀄스 순서로 다같으면 동등 아니면 다른 객체

package ch12.sec03.exam02;

public class Student {
private int no;
private String name;

public Student(int no, String name) {
    this.no = no;
    this.name = name;
}

public int getNo() {return no;}
public String getName() {return name;}

@Override
//hashCode를 메소드를 재정의해서 학생번호와 이름 해시코드를 합한 
새로운 해시코드를 리턴하도록함.(번호와 이름이 같으면 동일한 해시코드생성)
public int hashCode() {
    int hashCode = no + name.hashCode();
    return hashCode;
}

@Override
public boolean equals(Object obj) {
    if(obj instanceof Student target) {
        if(no == target.getNo()) {
            return true;
        }
    }
    return false;
}
}

 package ch12.sec03.exam02;

public class HashCodeExample {
public static void main(String[] args) {

    Student s1 = new Student(1, "홍길동");
    Student s2 = new Student(1, "홍길동");

    if(s1.hashCode() == s2.hashCode()) {
        if(s1.equals(s2)) {
            System.out.println("동등 객체입니다.");
        } else {
            System.out.println("데이터가 다르므로 동등 객체가 아닙니다.");
        }
    }else {
        System.out.println("해시코드가 다르므로 동등 객체가 아닙니다.");
    }
}
}

15장에서 배울 컬렉션에 속하는 HashSet은 동등객체를 중복 저장하지 않는 특징이 잇다.
실제로 동등비교를 어디서 사용하느냐 HashSet는 객체를 집합적으로 저장하는 역할을 함.
동등객체일경우 한번만 저장함.
HashSet은 hashCode()와 equals()메소드를 이용해서 동등비교를 하기 때문에 재정의해서 설계를 해두어야함.

HashSet hashSet = new HashSet();

Student s1 = new Student(1, "홍길동");
hashSet.add(s1);
System.out.println("저장된 객체수: " + hashSet.size());

Student s2 = new Student(1, "홍길동");
hashSet.add(s2);
System.out.println("저장된 객체수: " + hashSet.size());

Student s3 = new Student(2, "홍길동");
hashSet.add(s3);
System.out.println("저장된 객체수: " + hashSet.size());

12.3.3 객체 문자정보

어떤객체를 출력햇을때어떤 내용을 출력할것인가?
객체를 왜 출력? 객체안에 어떤 데이터가 있는지를 확인하려고 함.
Object의 toString()사용하기.
toString을 안해도 자체적으로 객체가 출력이됨. java.lang.클래스이름@16진수해시코드로 구성된 문자열이 리턴됨.
만약 생성하는 객체으 데이터를 알고 싶으면 toString을 재정의해야함.
예를들어 Date클래스는 현재날짜와 시간을 출력함. String클래스는 저장된 문자열을 리턴하도록함.

package ch12.sec03.exam03;

public class SmartPhone {
private String company;
private String os;

public SmartPhone(String company, String os) {
    this.company = company;
    this.os = os;
}

@Override //Object의 toString() 메소드를 재정의해서 제조사와 운영체제가결합된 문자열을 리턴하도록 함.
public String toString() {
    return company + ", " + os;
}
}

 package ch12.sec03.exam03;

public class ToStringExample {

public static void main(String[] args) {
    SmartPhone myPhone = new SmartPhone("삼성전자", "안드로이드");

    String strObj = myPhone.toString();
    System.out.println(strObj);

    System.out.println(myPhone);
}
}

12.3.4 레코드 선언

레코드 기록한다x DTO(데이터를 전달하는 객체)를 작성할때 반복적으로 사용되는 코드를 줄이기 위해 자바14부터 레코드가 도입되었다.
객체와 객체에서 전달할때 매개변수로 전달할때 데이터가 너무많으면 복잡해짐.
전달하는 객체를 만들대 getter setter를 가져야함. 등등이 자동으로 코드가 만들어짐.
public record Person(String name, int age){} 컴파일러는 private final필드, 생성자를 자동으로 생성함.
정확히 말하면 getter가 아니라 필드 이름고 동일한 메소드 만들어지고 필드값을 리턴하는 유사 게터가 나들어짐
해시코드와 이퀄스도 나와서 비교해줌 투스트링으로 자동으로 생성해줌

package ch12.sec03.exam04;

public record Member(String id, String name, int age) {
}

 package ch12.sec03.exam04;

public class RecordExample {

public static void main(String[] args) {
    Member m = new Member("winter", "눈송이", 25);
    System.out.println(m.id()); //getter메소드 호출
    System.out.println(m.name());
    System.out.println(m.age());
    System.out.println(m.toString());
    System.out.println();

    Member m1 = new Member("winter", "눈송이", 25);
    Member m2 = new Member("winter", "눈송이", 25);
    System.out.println("m1.hashCode(): " + m1.hashCode());
    System.out.println("m2.hashCode(): " +m2.hashCode());
    System.out.println("m1.equals(m2): " + m1.equals(m2));
}
}

12.3.5 롬복 사용하기

롬복은 JDK에 포함된 표준 라이브러리는 아니지만 개발자들이 즐겨쓰는 자동 코드 생성라이브러리이다.
롬복은 레코드와 마찬가지로 DTO클래스를 작성할때 Getter Setter hasCode() equals() toStirng()메소드를 자동생성하기 때문에 작성할 코드의 양을 줄여준다.
레코드와의 차이점은 필드가 final이 아니며 값을 읽는 Getter는 get...(또는 is...)로 Setter는 set...로 생성된다.
생산성을 높이는 라이브러리임.

이클립스에서 롬복을 사용하려면 설치과정이 필요하다. projectlombok.org/download 링크가서 lombok.jar다운
lib폴더 만들기 파일 복사하고 lib에 복사 붙여넣기 해야 들어감.
빌드 패스 jar에 두고 bulidpath add to bulidpath

package ch12.sec03.exam05;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;

@Data
@NoArgsConstructor // 기본 매개변수가 없는 생서자 포함
@AllArgsConstructor // 모든필드를 초기화시키는 생성자 포함
public class Member {

private String id;
@NonNull private String name;
private int age;
}


필드를 선언하고 class선언위에 @Data를 부팅면 어노테이션이라고하는데 나중에 설명됨.
컴파일과정에서 기본생성자와 함께 Getter Setter hasCode() equals() toStirng()메소드가 자동생선된다.
@NoArgsConstructor - 기본 매개변수가 없는 생서자 포함
@AllArgsConstructor- 모든필드를 초기화시키는 생성자 포함
필드옆에 @NonNull혹은 final 붙으면 이 필드만 초기화시키는 생성자를 포함시키낟.
이 둘의 차이점은 final은 필드 값을 변경불가능하지마(setter가 만들어지지않음)
@NonNull은 null값이 아닌 다른값으로 Setter를 통해 변경할 수있다.

12.4 System 클래스

시스템클래스는 출력문 쓸때 사용했음.
역할? 운영체제에서 실행하는 것이아니라 자바 가상머신 위에서 실행하는 거임. 따라서 운영체제의 모든 기능을 자바코드로 직접접근이 어려움
하지만 java.lang 패키지에 속하는 시스템 클래스를 이용하면 운영체제의 일부 기능을 이용할수잇다.
시스템 클래스의 정적필드와 메소드를 이용하면 프로그램종료, 키보드 입력 , 콘솔 모니터 출력 ,현재시간읽기 , 시스템프로피터읽기등이 가능하다.
System.out.println(); 을 사용할때 그냥 사용했던게 '정적'필드라 그렇다.

12.4.1 콘솔출력

콘솔에 err에러 내용으로 출력하기

package ch12.sec04;

public class ErrExample {
public static void main(String[] args) {
    try{
        int value = Integer.parseInt("1oo");
    } catch(NumberFormatException e){
        System.err.println("[에러 내용]");
        System.err.println(e.getMessage());
    }
}
}

12.4.2 키보드입력

자바는 키보드로부터 입력된 키를 읽기 위해 System 클래스에서 in필드를 제공한다.
다음과 같이 in필드를 이용해 read()메소드를 호출하면 입력된 키의 코드값을 얻을수 잇다.
int keyCode = System.in.read();
read()메소드는 호출과 동시에 키 코드를 읽는 것이 아니라키를 누르기 전까지는 대기상태이다가 엔터키를 누르면 입력했던 키들을 읽는다.
단read()메소드는 IOException을 발생할 수 잇는 코드 이므로 예외ㅏ처리가 필요하다.
raed는 하나의 키값만 읽을수있음. Scanner와의 차이점!

package ch12.sec04;

public class InExample {
public static void main(String[] args) throws Exception {
    int speed = 0;
    int keyCode = 0;

    while(true) {
        //엔터키를 읽지 않았을 경우에만 실행
        if(keyCode != 13 && keyCode != 10) {
            if(keyCode == 49) { 
                //숫자 1키를 읽었을 경우
                speed++;
            } else if (keyCode == 50) {
                //숫자 2키를 읽었을 경우
                speed--;
            } else if (keyCode == 51) {
                //숫자 3키를 읽었을 경우
                break;
            }
            System.out.println("-----------------");
            System.out.println("1.증속|2.감속|3.중지");
            System.out.println("-----------------");
            System.out.println("현재속도: " + speed);
            System.out.println("선택: ");


        }
        //키를 하나씩 읽음
        keyCode = System.in.read();
    }
    System.out.println("프로그램 종료");
}
}

12.4.3 프로세스 종료

운영체제는 실행중인 프로그램은 프로세스로 관리한다.
자바프로그램을 시작하면 JVM 프로세스가 생성되고 이 프로세스가 main()메소드를 호출한다. 프로세스를 강제로 종료하고 싶다면 system.exit()메소드를 사욯나다.
System.exit(int status)

exit()메소드는 int 매개값이 필요한데 이값을 종료 상태값이라고 한다. 종료 상태값을 어떤값으로 주더라도 프로세스는 종료되는데
정상종료일 경우 0 비정상종료는 1 또는 -1로 주는 것이 관례이다.

package ch12.sec04;

public class ExitExample {
public static void main(String[] args) {
    for(int i = 0; i<10; i++) {
        //i값 출력
        System.out.println(i);
        if(i==5) {
            //JVM프로세스 종료
            System.out.println("프로세스 강제 종료");
            System.exit(0);
        }
    }
}
}

12.4.4 진행시간 읽기

시스템 클래스의 currentTimeMillis() 메소드와 nanoTime()메소드는 1970년 1월1일 0시부터 시작해서 현재까지 진행된 시간을 리턴한다.
long currentTimeMillis() 1/1000초 단위로 진행된 시간을 리턴
long nanoTime() 1/10^9초 단위로 진행된 시간을 리턴
이 두 메소드는 프로그램 처리 시간을 측정하는데 주로 사용된다. 프로그램 처리를 시작할때 한번 끝날때 한번 읽어서 그차이를 구하면 프로그램 처리시간이 나온다.

package ch12.sec04;

public class MeasureRunTimeExample {
public static void main(String[] args) {
    long time1 = System.nanoTime();
        int sum = 0;
        for (int i = 0 ; i<=1000000; i++){
            sum += i;
        }
    long time2 = System.nanoTime();

    System.out.println("1~1000000가지의 합: " + sum);
    System.out.println("계산에" + (time2-time1) + "나노초가 소요되었습니다.");
}
}

12.4.5 시스템 프로퍼티 읽기

시스템 프로퍼티란 자바 프로글매이 시작될때 자동으로 설정되는 시스템의 속성을 말한다.
예를들어 운영체제 종류 및 사용자 정보, 자바 버전등의 기본 사양 정보가 해당한다. 다음은 시스템 프로퍼티의 주요속성과 값에 대해 설명한것이다.

package ch12.sec04;

import java.util.Properties; //getProperties는 모든 시스템이 가지고있는 객체
import java.util.Set;

public class GetPropertyExample {

public static void main(String[] args) {
    //운영체제와 사용자 정보 출력
    String osName = System.getProperty("os.name");
    String userName = System.getProperty("user.name");
    String userHome = System.getProperty("user.home");
    System.out.println(osName);
    System.out.println(userName);
    System.out.println(userHome);

    //전체키와 값을 출력
    System.out.println("--------------------");
    System.out.println("key: value");
    System.out.println("--------------------");
    Properties props = System.getProperties();
    Set keys = props.keySet();

    for (Object objkey : keys) {
        String key = (String) objkey;
        String value = System.getProperty(key);
        System.out.printf("%-40s: %s\n", key, value);
    }
}
}

12.5 문자열 클래스

String 문자열을 저장하고 조작할때 사용
StringBuilder 효율적인 문자열 조작 기능이 필요할 때 사용
StringTokenizer 구분자로 연결된 문자열을 분리할때 사용

12.5.1 String 클래스

문자열을 저장하고 조작할때 사요한다.
문자열 리터럴은 자동으로 String 객체로 생성되지만 String클래스의 다양한 생성자를 이용해서 직접 객체르 생성할수도잇다.
프로그램을 개발하다보면 byte 배열을 문자열로 변환하는 경우가 종좆ㅇ잇다.
예를들어 네트워크 통신으로 얻으 byte배열을 원래 문자열로 변환하는 경우이다.
이때는 String 생성자 중에서 다음 두가지를 이용해 String 객체로 생성가능하다.
기본 문자 셋으로 byte 배열을 디코딩해서 String 객체로 생성
String str = new String(byte[] bytes);
특정 문자셋으로 byte배열을 디코딩해서 String객체로 생성
String str new String(byte[] bytes, String charsetName);

package ch12.sec05;

import java.util.Arrays;

public class ByteToStringExamle {

public static void main(String[] args) throws Exception {
    String data = "자바";

    //String -> byte배열(기본: UTF-8인코딩)
    byte[] arr1 = data.getBytes(); // byte[] arr1 = data.gaetBytes("UTF-8");
    System.out.println("arr1: " + Arrays.toString(arr1));

    //byte 배열 -> string
    String str1 = new String(arr1);
    System.out.println("str1: " + str1);

    //String -> byte배열(EUC-KR 인코딩);
    byte[] arr2 = data.getBytes("EUC-KR");
    System.out.println("arr2: " + Arrays.toString(arr2));

    //byte 배열 -> string(EUC-KR 인코딩);
    String str2 = new String(arr2,"EUC-KR");
    System.out.println("str2: " + str2);
}
}


한글 1자를 UTF-8로 인코딩하면 3바이트가되고 EUC-KR로 인코딩하면 2바이트가 된다.
따라서 인코딩할때 사용한 문자셋으로 디코딩을 해야만 한글이 올바르게 복원될 수있다.

12.5.2 StringBuilder 클래스

String 은 내부 문자열을 수정할 수 없다. 다음 코드를 보면 다른 문자열을 결합해서 내부 문자열을 변경하는 것처럼 보이지만
사실 ABCDEF라는 새로운 String 객체를 생성하는 것이다. 그리고 data변수는 새로 생ㅅ어된 String객체를 참조하게 된다.
String data= "ABC";
data += "DEF"

문자열의 +연산은 새로운 String 객체가 생성되고 이전 객체는 계속 버려지는 것이기때문에 효율성이 좋다고 볼수는 없다.
잦은 문자열 변경작업을 해야한다면 StringBuilder를 사용하는 것이 좋다.

StringBuilder는 내부 버퍼(데이터를 저장하는 메모리)에 문자열을 저장해두고 그 안에서 추가, 수정, 삭제 작업을 하도록 설꼐되어잇다.
따라서 String처럼 새로운 객체를 만들지 않고도 문자열을 조작할 수 잇다.
제공 메소드는 다음과 같다.

package ch12.sec05;

public class StringBuildereExample {

public static void main(String[] args) {
    String data = new StringBuilder()
            //;를 안찍으면 걔속 추기할 수 잇음.
            .append("DEF") //제일마지막에 추가
            .insert(0,"ABC") // 인덱스 번호에 추가 
            .delete(3, 4) //시작위치 끝위치 삭제
            .toString(); //완성된 문자열을 리턴 
    System.out.println(data);    
}
}

12.5.3 StringTokenizer클래스

문자열이 구분자로 연결되어 있을경우 구분자를 기준으로 문자열을 분리하면 String의 split()메소드를 이용하거나 StringTokenizer를 사용할수있다.
split은 정규 표현식으로 구분할 수 있어서 좀더 복잡하게 구분할 수 있음.
StringTokenizer는 문자로 구분한다는 차이점이 있다.
String data = "홍길동&이수홍,박연수,김자바-최명호";
String[] names = data.split("&|,|-"); 이런식으로 다양한 구분자가 잇을경우에는 이거 사용
String data = "홍길동/이수홍/박연수";
StringTokenizer st = new StringTokenizer(data, "/");

StringTokenizer가 사용되면 다음 메소드들을 이용해서 분리된 문자열을 얻을 수잇다.
리턴타입 int / counTokens() / 분리할 수 있는 문자열의 총수
boolean / hasMoreTokens() / 남아있는 문자열이 있는지 여부
String / nextToken() / 문자열을 하나씩 가져옴
nextToken() 은 분리된 문자열을 하나씩 가져오고 더이상 가져올 문자열이 없다면 예외를 발생시킨다.
그래서 nextToken() 를 사용하기전에 hasMoreTokens() 메소드로 가져울 문자열이 있는지 먼저 조사하는 것이 좋은 방법이다.

package ch12.sec05;

import java.util.StringTokenizer;

public class StringTokenizerExample {

public static void main(String[] args) {
    String data1 = "홍길동&이수홍,박연수";
    String[] arr = data1.split("&|,");
    for(String token : arr) {
        System.out.println(token);
    }
    System.out.println();

    String data2 = "홍길동/이수홍/박연수";
    StringTokenizer st = new StringTokenizer(data2, "/");
    while(st.hasMoreTokens()) {
        String token = st.nextToken();
        System.out.println(token);
    }
}
}

2022.11.26 리뷰

중요한 것은 꺾이지 않는 마음

'기초단계 > JAVA' 카테고리의 다른 글

2022.11.28-1 JAVA java.base 모듈  (1) 2022.11.28
2022.11.27-1 JAVA java.base 모듈  (0) 2022.11.28
2022.11.25-2 JAVA java.base 모듈  (0) 2022.11.25
2022.11.25-1 JAVA 예외 처리  (1) 2022.11.25
2022.11.24-1 JAVA 라이브러리와 모듈  (0) 2022.11.25

+ Recent posts