본문 바로가기
Java

java.lang패키지와 유용한 클래스

by 토니짱 2022. 9. 3.

java.lang패키지

자바프로그래밍에 가장 기본이 되는 클래스들을 포함하는 패키지. 그렇게 때문에 import문 없이 사용할 수 있다.

Object클래스

모든 클래스의 최고 조상.Object클래스의 멤버들은 모든 클래스에서 바로 사용 가능하다.

Object클래스는 멤버변수는 없고 오직 11개의 메서드만 가지고 있다.

equals(Object obj)

매개변수로 객체의 참조변수를 받아서 비교하여 그 결과를 boolean값으로 알려주는 역할.

public boolean equals(Object obj){
	return (this==obj);//객체 자신(this)와 주어진 객체(obj)를 비교
}

두 객체의 같고 다름을 참조변수의 값(객체의 주소)으로 판단한다.

*객체를 생성할 때, 메모리의 비어있는 공간을 찾아 생성하므로 서로 다른 두 개의 객체가 같은 주소를 갖는 일은 있을 수 없다. 두 개 이상의 참조변수가 같은 주소값을 갖는 것(한 객체를 참조하는 것)은 가능하다.

hashCode()

객체의 지문. 이 메서드는 해싱(hashing)기법에 사용되는 ‘해시함수(hash function)’를 구현한 것이다.

해싱은 데이터관리기법 중의 하나인데 다량의 데이터를 저장하고 검색하는데 유용하다.

해시함수는 찾고자하는 값을 입력하면, 그 값이 저장된 위치를 알려주는 해시코드(hash code)(정수값)을 반환한다.

Object클래스에 정의된 hashCode메서드는 객체의 주소값으로 해시코드를 만들어 반환하기 때문에 32bitJVM에서는 서로 다른 객체는 결코 같은 해시코드를 가질 수 없었지만, 64bitJVM에서는 8byte의 주소값으로 해시코드(4byte)를 만들기 때문에 중복될 수 있다.

인스턴스변수 값으로 객체의 같고 다름을 판단해야 한다면 equals메서드 뿐 만 아니라 hashCode메서드도 적절히 오버라이딩 해야한다.

→ equals()를 오버라이딩 하면, hashCode()도 오버라이딩 해야함.

같은 객체라면 hashCode메서드를 호출했을 떄의 결과값인 해시코드도 같아야 하기 때문이다.

toString()

이 메서드는 인스턴스에 대한 정보를 문자열(String)로 제공할 목적으로 정의한 것이다.

아래는 Object클래스에 정의된 toString()이다.

public String toString(){
	return getClass().getName()+"@"+Integer.toHexString(hashCode());
}

*Class{} : 클래스정보를 담기위한 클래스

getClass() : 설계도객체

getName() : 클래스이름

“@” : 위치

Integer.toHexString : 16진수

hashCode : 객체주소

즉, toString()을 오버라이딩하지 않고 호출하면 클래스이름에 16진수의 해시코드를 얻게 된다.

toString()은 일반적으로 인스턴스나 클래스에 대한 정보 또는 인스턴스 변수들의 값을 문자열로 변환하여 반환하도록 오버라이딩되는 것이 보통이다.

//toString() overriding하기~
class Card{
	String kind;
	int number;
}

Card(){
	this("SPADE",1);  //Card(String kind, int number)를 호출
}

Card(String kind, int number){
	this.kind = kind;
	this.number = number;
}

public String toString(){//오브젝트의 toString()접근제어자를 주의해서 오버라이딩하자!
	return "kind : "+ kind + ", number : " + number;
}

clone()

이 메서드는 자신을 복제하여 새로운 인스턴스를 생성하는 일을 한다.

원래의 인스턴스는 보존하고 복제한 인스턴스로 작업을 하면 변경전의 값을 참고하는데 도움이 된다.

Object클래스의 clone()은 단순히 인스턴스변수의 값만 복사하기 때문에 복제된 인스턴스의 작업이 원래의 인스턴스에 영향을 미친다. 이런 경우 clone메서드를 오버라이딩하여 사용해야한다.

clone()메서드 사용하려면,

  1. Cloneable인터페이스를 구현한다. → 인스턴스의 데이터를 보호하기 위해서이다
  2. clone()을 오버라이딩하면서 접근제어자를 protected에서 public으로 변경한다. →상속관계가 없는 다른 클래스에서 호출하기 위함.
  3. 조상클래스의 clone()을 호출하는 코드가 포함된 try-catch문을 작성한다.

공변반환타입(covariant return type)

JDK1.5부터 추가된 공변반환타입은 오버라이딩할 때 조상 메서드의 반환타입을 자손 클래스의 타입으로 변경을 허용하는 것이다.

public Point clone(){  //반환타입을 Object에서 Point로 변경
	Object obj = null;
	try{
		obj = super.clone();
	} catch(CloneNotSupportedException e){}
	return (Point)obj;//Point차입으로 형변환한다.
}

Point copy = (Point)original.clone(); -> Point copy = original.clone();

*clone()으로 복제가 가능한 클래스인지 확인하려면 JAVA API에서 Cloneable을 구현했는지 확인하자.

얕은 복사와 깊은 복사

clone()은 단순히 객체에 저장된 값을 그대로 복제할 뿐, 객체가 참조하고 있는 객체까지 복제하지 않는다.

clone()으로 복제하는 경우 원본과 복제본이 같은 객체를 공유하므로 얕은 복사(shallow copy)라고 한다.

반면에 원본이 참조하고 있는 객체까지 복제하는 것을 ‘깊은 복사(deep copy)’라고 한다.

깊은 복사는 서로 다른 객체를 참조하기 때문에 서로 영향이 없다.

얕은 복사(shallow copy) : 원본을 변경하면 복사본도 영향을 받음

깊은 복사(deep copy) : 원본을 변경해도 복사본 영향이 없음.

getClass()

이 메서드는 속한 클래스 객체를 반환하는 메서드인데, Class객체는 이름이 ‘Class’이다.

Class객체는 클래스의 모든 정보를 담고 있으며, 클래스 당 1개만 존재한다. 그리고 ‘클래스 로더(ClassLoader)’에 의해 메모리에 올라갈 때, 자동으로 생성된다.

클래스로더는 실행 시에 필요한 클래스를 동적으로 메모리에 로드하는 역할을 한다.

  1. 기존에 생성된 클래스 객체가 메모리에 존재하는지 확인
  2. 있으면 객체의 참조를 반환 없으면 클래스패스(classpath)에 지정된 경로를 따라서 클래스 파일을 찾는다.
  3. 파일 형태로 저장되어 있는 클래스를 읽어서 Class클래스에 정의된 형식으로 변환한다.

Class객체를 얻는 방법

//생성된 객체로부터 얻는 방법
Class cObj = new Card().getClass();

//클래스 리터럴(*.class)로 부터 얻는 방법
Class cObj = Card.class;

//클래스 이름으로부터 얻는 방법
Class cObj = Class.forName("Card");

특히 forName()은 특정 클래스 파일, 예를들어 데이터베이스 드라이버를 메모리에 올릴때 주로 사용한다.

String클래스

String클래스 = 데이터(char[]) + 메서드(문자열관련)

String클래스는 문자열을 저장하고 이를 다루는데 필요한 메서드를 함께 제공한다.

변경 불가능한(immutable)클리스

String 클래스는 앞에 final이 붙어 있으므로 다른 클래스의 조상이 될 수 없다.

한번 생성된 String인스턴스가 갖고 있는 문자열은 읽기만 가능하고 변경할 수 없다.

+연산자를 이용해서 문자열을 결함하면 인스턴스 내의 문자열이 바뀌는게 아니라 새로운 인스턴스가 생성되는 것이다. 때문에 메모리공간을 차지하게 되므로 성능저하가 생긴다.

문자열간의 결합이나 추출 등 문자열을 다루는 작업이 많이 필요하면 StringBuffer클래스(변경가능)를 사용하는것이 좋다.

문자열의 비교

String str1 = "abc";             //문자열리터럴 "abc"의 주소가 str1에 저장됨
String str2 = "abc";             //문자열리터럴 "abc"의 주소가 str2에 저장됨
String str3 = new String("abc"); //새로운 String인스턴스를 생성
String str4 = new String("abc"); //새로운 String인스턴스를 생성

str1 == str2
0x100==0x100

str3 == str4
0x200!=0x300

new연산자에 의해서 메모리할당이 이루어지면 항상 새로운 String인스턴스가 생성된다. 그러나 문자열 리터럴은 이미 존재하는 것을 재사용하는 것이다.

문자열 리터럴(상수)

상수는 프로그램 실행시 자동으로 생성된다.(JVM내에 있는 Constant pool상수저장소에 저장됨)

자바 소스파일에 포함된 모든 문자열 리터럴은 컴파일 시에 클래스 파일에 저장된다.

String s1 = "AAA";  //new String("AAA"); 자동으로 만들어줌
String s2 = "AAA";  
String s3 = "BBB";  //new String("BBB"); 자동으로 만들어줌

s1과 s2는 “AAA”를 담고있는 String인스턴스를 참조(공유)하게된다.

빈 문자열(empty string)

내용이 없는 문자열. 크기가 0인 char형 배열을 저장하는 문자열

String s = “”;과 같은 문장이 있을 때, 참조변수 s가 참조하고 있는 String인스턴스는 내부에 ‘new char[0]’과 같이 길이가 0인 char형 배열을 저장하고 있는 것이다.

*크기가 0인 배열을 생성하는 것은 어느 타입이나 가능하지만 char형 변수에는 반드시 하나의 문자를 지정해야한다.

String클래스의 생성자와 메서드

*CharSequence는 JDK1.4부터 추가된 인터페이스로 String, StringBuffer 등의 클래스가 구현하였다.

join()과 StringJoiner

join()은 여러 문자열 사이에 구분자를 넣어서 결합한다.

구분자로 문자열을 자르는 split()과 반대의 작업을 한다고 생각하면 쉽다.

*join()과 java.util.StringJoiner는 JDK1.8부터 추가되었다.

//join()사용
String animals = "dog,cat,bear";
String[] arr = animals.split(",");//문자열을 ','를 구분자로 나눠서 배열에 저장
String str = String.join("-",arr);//배열의 문자열을 '-'로 구분해서 결합
System.out.println(str);//dog-cat-bear

//java.util.StringJoiner클래스 사용
StringJoiner sj = new StringJoiner{",","[","]");//구분자',' , 맨앞문자, 맨뒤문자
String[] strArr = {"aaa","bbb","ccc");

for(String s : strArr)
	sj.add(s.toUpperCase());

System.out.println(sj.toString());//[AAA,BBB,CCC]

유니코드의 보충문자

문자를 다루는 메서드인데 매개변수가 int인 것들은 뭘까? → 확장된 유니코드를 다루기 위한 것

확장에 의해 새로 추가된 문자들을 ‘보충 문자(supplementary characters)’라고 하며, 위의 표에서 매개변수가 ‘int ch’인 것들은 보충문자를 지원하고 ‘char ch’인 것들은 지원하지 않는다.

문자 인코딩 변환

getBytes(String charesetName)를 사용하면, 문자열의 문자 인코딩을 다른 인코딩으로 변경할 수 있다.

byte[] utf8_str = "가".getBytes("UTF-8");//문자열을 UTF-8로 변경
String str = new String(utf8_str,"UTF-8");//byte배열을 문자열로 변환

*UTF-8은 한글 한 글자를 3byte로 표현한다.

String.format()

format()은 형식화된 문자열을 만들어내는 간단한 방법이다.

String str = String format("%d 더하기 %d는 %d입니다.",3,5,3+5);
System.out.println(str);//3 더하기 5는 8입니다.

printf()와 사용법이 완전 똑같다.

기본형 값을 String으로 변환

숫자에 빈 문자열 “”을 더해주면 문자열이 된다. 이 외에도 valueOf()를 사용하는 방법도 있다. 성능은 valueOf()가 더 좋지만 “”을 더해주는 방법이 더 간단하고 편리해서 성능향상이 필요한 경우에만 쓴다.

String을 기본형 값으로 변환

valueOf()를 쓰거나 parseInt()를 사용하면 된다.

valueOf(String s)는 메서드 내부에서 그저 parseInt(String s)를 호출할 뿐이므로, 두 메서드는 반환 타입만 다르지 같은 메서드다.

StringBuffer클래스와 StringBuilder클래스

StringBuffer클래스는 String과 달리 내용 변경이 가능하다. 내부적으로 문자열 편집을 위한 버퍼(buffer)를 가지고 있으며, 인스턴스 생성시 그 크기를 지정할 수 있다.(충분히 길이를 잡아주는 것이 좋다)

StringBuffer클래스는 String클래스와 같이 문자열을 저장하기 위한 char형 배열의 참조변수를 인스턴스변수로 선언해 놓고 있다.

StringBuffer의 생성자

SpringBuffer클래스의 인스턴스를 생성할 때, 적절한 길이의 char형 배열이 생성되고, 이 배열은 문자열을 저장하고 편집하는 공간(buffer)으로 사용된다.

배열은 크기 변경이 불가능하므로 StringBuffer인스턴스에 저장될 문자열의 길이를 고려하여 충분한 크기로 지정하는 것이 좋다.

StringBuffer의 변경

StringBuffer sb = new StringBuffer("abc");//sb = "abc"
sb.append("123"); //sb = "abc123"
StringBuffer sb2 = sb.append("ZZ");//sb = "abc123ZZ" / sb2 = "abc123ZZ"
//위의 코드를 한줄로 변경
sb.append("123").append("ZZ");//append()의 반환타입이 StringBuffer라서 가능
StringBuffer sb = new StringBuffer("0123456");
StringBuffer sb2 = sb.delete(3,6);
System.out.println("sb = " + sb);//"0126"
System.out.println("sb2 = " + sb2);//"0126"

sb와 sb2는 같은 주소를 공유하기 때문에 결과는 같다.

StringBuffer의 비교

StringBuffer클래스는 equals메서드를 오버라이딩하지 않아서 equals를 사용해도 등가비교연산자(==)로 비교한 것과 같은 결과를 얻는다.

반면에 toString()은 오버라이딩이 되어 있어서 문자열 비교를 할 때는 StringBuffer인스턴스에 toString()을 호출해서 String인스턴스를 얻은 다음, 여기에 equals메서드를 사용해서 비교하면 된다.

StringBuilder란?

StringBuffer는 멀티쓰레드에 안전(thread safe)하도록 동기화되어 있다. 동기화가 불필요한 때에도 동기화가 되면 성능을 떨어뜨리므로 StringBuffer에서 동기화만 뺀 StringBuilder가 새로 추가되었다.

Math클래스

수학관련 static메서드의 집합

올림, 버림, 반올림

round()는 항상 소수점 첫째자리에서 반올림을 해서 정수값(long)을 결과로 돌려준다.

rint()도 round()처럼 소수점 첫 쨰자리에서 반올림하지만, 반환값이 double이다. 그리고 rint()는 두 정수 정가운데 있는 값을 항상 가장 가까운 짝수 정수를 반환한다.

예외를 발생시키는 메서드

메서드 이름에 ‘Exact’가 포함된 메서드들이 JDK1.8부터 새로 추가되었다. 이들은 정수형간의 연산에서 발생할 수 있는 오버플로우(overflow)를 감지하기 위한 것이다.

연산자는 단지 결과를 반환할 뿐, 오버플로으의 발생여부에 대해 알려주지 않지만 Exact가 포함된 메세드들은 예외를 발생시킨다.

StrictMath클래스

Math클래스는 최대한의 성능을 얻기 위해 JVM이 설치된 OS의 메서드를 호출해서 사용한다. 즉 OS에 의존적인 계산을 하고 있다. 그래서 부동소수점의 계산을 할 때 반올림 처리법이 OS마다 다를 수 있어서 결과가 같지 않을 수 있다. 이러한 차이를 없애기 위해 성능은 다소 포기하는 대신, 항상 같은 결과를 얻도록 새로 작성한 것이 StrictMath클래스이다

Math클래스의 메서드

래퍼(wrapper)클래스

객체가 아닌 기본형(primitive type)을 객체로 다뤄야 할 때 기본형 값을 감싸는 클래스.

기본형 변수도 어쩔 수 없이 객체로 다뤄야 하는 경우에 사용한다.

래퍼 클래스들은 모두 equals()가 오버라이딩되어 있어서 주소값이 아닌 객체가 가지고 있는 값을 비교한다.

오토박싱이 된다고 해도 Integer객체에 비교연산자를 사용할 수 없다. 대신 compareTo()를 제공한다.

Number클래스

숫자를 멤버변수로 갖는 래퍼 클래스의 조상

기본형 중에서 숫자와 관련된 래퍼 클래스들은 모두 Number클래스의 자손이다.

문자열을 숫자로 변환하기

JDK1.5부터 도입된 ‘오토박싱(autoboxing)’ 기능 때문에 반환값이 기본형일 때와 래퍼 클래스일 때의 차이가 없어졌다. 그래서 그냥 구별없이 valueOf()를 쓰는게 편하다. 단, 성능은 valueOf()가 조금 더 느리다.

오토박싱 & 언박싱

JDK1.5이전에는 기본형과 참조형 간의 연산이 불가능했기 때문에, 래퍼 클래스로 기본형을 객체로 만들어서 연산해야 했었다. 그러나 지금은 컴파일러가 자동으로 변환하는 코드를 넣어주기 때문에 연산이 가능하다. 컴파일러가 Integer객체를 int타입의 값으로 변환해주는 intValue()를 추가해준다.

//컴파일 전의 코드
int i = 5;
Integer iObj = new Integer(7);
int sum = i+iObj;
//컴파일 후의 코드
int i = 5;
Integer iObj = new Integer(7);
int sum = i+iObj.intValue();//기본형으로 변환해줌

//컴파일 전의 코드
Integer intg = (Integer)i;
Object obj = (Object)i;
Long lng = 100L;
//컴파일 후의 코드
Integer intg = Integer.valueOf(i);
Object obj = (Object)Integer.valueOf(i);
Long lng = new Long(100L);

오토박싱 : 기본형 값을 래퍼 클래스의 객체로 자동 변환해주는 것 (int → Integer)

언박싱 : 반대로 변환하는 것 (Integer → int)

유용한 클래스

java.util패키지에는 자주 쓰이는 유용한 클래스가 많다.

java.util.Objects클래스

Object클래스의 보조 클래스로 Math클래스처럼 모든 메서드가 ‘static’이다.

객체의 비교나 널 체크(null check)에 유용하다.

isNull()은 해당 객체가 널인지 확인하여 boolean값 반환해준다.

nonNull()은 isNull()과 정반대의 일을 한다.

requireNonNull()은 해당 객체가 널이 아니어야 하는 경우에 사용한다. 만일 객체가 널이면 예외발생.

Object클래스에는 두 객체의 등가비교를 위한 equals()만 있고, 대소비교를 하는 compare()가 없지만 Objects클래스에는 compare()가 추가되었다.

compare()는 두 대상이 같으면 0, 크면 양수, 작으면 음수를 반환한다.

java.util.Random클래스

Math.random()말고도 Random클래스를 사용하면 난수를 얻을 수 있다.

double randNum = Math.random();
double randNum = new Random().nextDouble();//위의 문장과 동일함

Math.random()과 Random의 가장 큰 차이점은 종자값(seed)를 설정할 수 있다는 것이다.

종자값이 같은 Random인스턴스들은 항상 같은 난수를 같은 순서대로 반환한다.

정규식(Regular Expression) - java.util.regex패키지

정규식이란 텍스트 데이터 중에서 원하는 조건(패턴, pettern)과 일치하는 문자열을 찾아내기 위해 사용하는 것이다.

java.util.Scanner클래스

Scanner클래스는 화면, 파일, 문자열과 같은 입력소스로부터 문자데이터를 읽어오는데 도움을 줄 목적으로 JDK1.5부터 추가되었다.

//JDK1.5이전
BufferedReader br = new BufferdReader(new InputStreamReader(System.in));
String input = br.readLine();

//JDK1.5이후 (java.util.Scanner)
Scanner s = new Scanner(System.in);
String input = s.nextLine();

//JDK1.6이후 (java.io.Console)-이클립스에서 동작 안함
Console console = System.console();
String input = console.readLine();

java.util.StringTokenizer클래스

StringTokenizer는 긴 문자열을 지정된 구분자(delimiter)를 기준으로 토큰(token)이라는 여러 개의 문자열로 잘라내는 데 사용된다.

StringTokenizer는 단 한 문자의 구분자만 사용할 수 있다.

반응형

'Java' 카테고리의 다른 글

람다식(Lambda expression)  (1) 2022.09.30
예외처리  (0) 2022.08.17
객체지향프로그래밍2  (0) 2022.08.17
객체지향 프로그래밍1  (0) 2022.08.17