Programming Language/자바(JAVA)
[JAVA] java.base 모듈 - 각종 클래스, 리플렉션, 어노테이션
토자맨
2024. 11. 26. 18:54
Object 클래스
JAVA의 모든 클래스는 Object의 자식 or 자손 클래스
- 클래스를 선언할 때 extends로 상속받지 않으면 암시적으로 Object 클래스 상속 받음
Object 메소드 - equals(), hashCode(), toString()
equals()
boolean equals(Object obj)
- 객체의 번지(주소)를 비교하고 결과를 리턴(
==
연산자와 같은 기능)
- 객체의 번지(주소)를 비교하고 결과를 리턴(
- String에서 equals()
- String에서는 객체의 번지가 아닌 내용을 주소하도록 오버라이딩되어 있다.
==
와 다르게 리터럴로 선언했든 객체 생성 연잔사(new)로 선언했든 상관 없이 값으로만 비교하여 반환한다.
public class Main {
public static void main(String[] args) {
String str1 = "test";
String str2 = "test";
String str3 = new String("test");
String str4 = new String("test");
System.out.println(str1==str3); //false
}
}
hashCode()
객체를 식별하는 정수로써 객체의 메모리 번지를 이용해서 해시코드를 생성한 뒤 리턴(객체마다 다른 값을 리턴)
int hashCode()
- 두 객체가 동등한지를 비교할 때 주로 사용한다.
equals()
과 마찬가지로 객체의 데이터를 기준으로 오버라이딩해서 새로운 정수값을 리턴하는 것이 일반적이다.- 아래 사진과 같이
equals()
과hashCode()
를 오버라이딩해서 두 객체의 값을 비교할 수 있다.
toString()
String toString()
- 객체 문자 정보를 리턴
- 각 클래스별로 오버라이딩하여 사용
- String 클래스
- 저장된 문자열 리턴
- Date 클래스
- 현재 날짜, 시간 리턴
- String 클래스
레코드 선언
- DTO 작성 시 반복적으로 사용되는 코드 줄이기 위해 JAVA 14부터 레코드 도입
- 레코드 소스를 컴파일하면 변수의 타입과 이름을 이용해 private final 필드가 자동 생성되고, 생성자 및 Getter 메소드가 자동으로 추가된다. hashCode(), equals(), toString() 메소드를 재정의한 코드도 자동 추가
- 즉,
record
로 선언하면 아래 코드들을 직접 작성하지 않아도 자동으로 만들어줌
// Person DTO
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String name() { return this.name; }
public String age() { return this.age; }
@Override
public int hashCode() { ... }
@Override
public boolean equals(Object obj) { ... }
@Override
public String toString() { ... }
}
// 위 동일한 코드를 생성하는 레코드 선언
public record Person(String name, int age) { ... }
롬복
다양한 메소드들을 자동으로 생성해주는 어노테이션을 제공하는 라이브러리
- 레코드와 다르게 필드가 final이 아니다.
- Getter, Setter를 getXxx(), setXxx()로 생성한다.
어노테이션 | 설명 |
---|---|
@Data | Getter, Setter, hashCode(), equals(), toString() 메소드 자동 생성 |
@NoArgsConstructor | 기본(매개변수가 없는) 생성자 포함 |
@AllArgsConstructor | 모든 필드를 초기화시키는 생성자 포함 |
@RequiredArgsConstructor | 기본적으로 매개변수가 없는 생성자 포함. 만약 final 또는 @NonNull 이 붙은 필드가 있다면 이 필드만 초기화시키는 생성자 포함 |
@Getter | Getter 메소드 포함 |
@Setter | Setter 메소드 포함 |
@EqualsAndHashCode | equals()와 hashCode() 메소드 포함 |
@ToString | toString() 메소드 포함 |
문자열(String) 클래스
StringBuilder 클래스
내부 버퍼(데이터를 저장하는 메모리)에 문자열을 저장해두고 그 안에서 추가, 수정, 삭제 작업
- String은 내부 문자열을 수정할 수 없다.
- String 객체에 값을 추가하는 것처럼 보여도 실제론 새로운 String 객체를 생성하는 것이다.
- "A" String 객체는 그대로 있고 새로운 "AB" String 객체를 생성하여 참조하는 방식
String data = "A";
data += "B";
- 이러한 방식은 너무 비효율적이기 때문에 잦은 변경 작업을 해야 한다면 StringBuilder를 사용한다.
리턴 타입 | 메소드(매개변수) | 설명 |
---|---|---|
StringBuilder | append(기본값 | 문자열) |
StringBuilder | insert(위치, 기본값 | 문자열) |
StringBuilder | delete(시작 위치, 끝 위치) | 문자열 일부 삭제 |
StringBuilder | replace(시작 위치, 끝 위치, 문자열) | 문자열 일부 대체 |
String | toString() | 완성된 문자열 리턴 |
StringTokenizer 클래스
구분자로 연결된 문자열을 구분자를 기준으로 분리
- split()와 차이점
split()
- 정규 표현식으로 구분
- 여러 종류로 구분되어 있을 경우 사용
StringTokenizer
- 문자로 구분
- 한 구분자만 있을 때 사용
String data = "홍길동&이수홍,박연수,김자바-최명호";
String[] names = data.split("&|,|-");
String data = "홍길동/이수홍/박연수";
StringTokenizer st = new StringTokenizer(data, "/");
리턴 타입 | 메소드(매개변수) | 설명 |
---|---|---|
int | countTokens() | 분리할 수 있는 문자열의 총 수 |
boolean | hasMoreTokens() | 남아 있는 문자열이 있는지 여부 |
String | nextToken() | 문자열을 하나씩 가져옴 |
포장 클래스
자바는 기본 타입(byte, char, short, int, long, float, double, boolean)의 값을 갖는 객체를 생성할 수 있는데, 이런 개체를 포장(wrapper) 객체라 한다.
- 포장 객체는 객체이기 때문에 비교 연산자를 사용할 때
==
연산자가 아닌 객체의 번지를 비교하는equals()
연산자를 사용해야 한다. - 박싱
- 기본 타입 -> 포장 객체
- 언박싱
- 포장 객체 -> 기본 타입
Integer obj = 100; // 박싱
int value = obj; // 언박싱
수학 클래스
- Math 클래스가 제공하는 메소드는 모두 static 메소드이므로 객체 생성 없이 클래스로 바로 사용 가능Math 클래스 메소드
- 절대값:
Math.abs(n)
- 올림값:
Math.ceil(n)
- 버림값:
Math.floor(n)
- 최대값:
Math.max(a, b)
- 최소값:
Math.min(a, b)
- 랜덤값:
Math.random()
-> 0.0과 1.0 사이의 double 타입 난수를 리턴
- 절대값:
Random 클래스 메소드
생성자 | 설명 |
---|---|
Random() |
현재 시간을 이용해서 종자값을 자동 설정한다. |
Random(long seed) |
주어진 종자값을 사용한다. |
리턴값 | 메소드(매개변수) | 설명 |
---|---|---|
boolean |
nextBoolean() |
boolean 타입의 난수를 리턴 |
double |
nextDouble() |
double 타입의 난수를 리턴 (0.0 <= x < 1.0) |
int |
nextInt() |
int 타입의 난수를 리턴 (-2^32 <= x <= 2^32 - 1) |
int |
nextInt(int n) |
int 타입의 난수를 리턴 (0 <= x < n) |
정규 표현식 클래스
문자열이 올바르게 구성되어 있는지 검증하는 클래스
(02|010)-\d{3,4}-\d{4}
- 전화번호 형식 검사
\w+@\w+\.\w+(\.\w+)?
- 이메일 형식 검사
- 이러한 검사는 Pattern 클래스로 검증할 수 있다.
- Pattern 클래스는 정규 표현식으로 문자열을 검증하는 matches() 메소드 제공한다.
boolean result = Pattern.matches("정규식", "검증할 문자열");
- Pattern 클래스는 정규 표현식으로 문자열을 검증하는 matches() 메소드 제공한다.
리플렉션
메타 정보(패키지 정보, 타입 정보, 멤버 정보(생성자, 필드, 메소드) 등)를 프로그램에서 읽고 수정하는 행위
클래스 정보 얻기
Class clazz = 클래스이름.class;
Class clazz = Class.forName("패키지...클래스이름");
Class clazz = 객체참조변수.getClass();
패키지와 타입 정보 얻기
Package getPackage()
: 패키지 정보 읽기String getSimpleName()
: 패키지를 제외한 타입 이름String getName()
: 패키지를 포함한 전체 타입 이름
멤버 정보 얻기
Constructor[] getDeclaredConstructors()
: 생성자 정보 읽기Field[] getDeclaredFields()
: 필드 정보 읽기Method[] getDeclaredMethods()
: 메소드 정보 읽기
리소스 경로 얻기
URL getResource(String name)
: 리소스 파일의 URL 리턴InputStream getResourceAsStream(String name)
: 리소스 파일의 InputStream 리턴clazz.getResource("photo.jpg").getPath();
- URL 객체의 메소드로 절대 경로를 리턴
어노테이션
@로 작성되는 요소로써 클래스 또는 인터페이스를 컴파일하거나 실행할 때 어떻게 처리해야 할 것인지를 알려주는 설정 정보
- 용도
- 컴파일 시 사용하는 정보 전달
- 빌드 툴이 코드를 자동으로 생성할 때 사용하는 정보 전달
- 실행 시 특정 기능을 처리할 때 사용하는 정보 전달
- 대표적인 어노테이션
@Override
- 컴파일러가 메소드 재정의 검사를 하도록 설정
- 정확히 재정의 되지 않았다면 에러 발생
어노테이션 타입 정의와 적용
- 어노테이션은 속성을 가질 수 있음
- 기본값은 이름 뒤에
default 기본값
으로 설정
- 기본값은 이름 뒤에
// 어노테이션 정의
public @interface AnnotationName {
// 어노테이션 속성
String prop1();
int prop2() default 1; // 기본값 설정
}
// 사용
@AnnotationName(prop1= "값", prop2=3);
public @interface AnnotationName {
// 어노테이션 속성
String value();
int prop2() default 1; // 기본값 설정
}
@AnnotationName("값"); // value 속성을 가진 어노테이션을 사용할 때는 값만 기술
@AnnotationName(prop1= "값", prop2=3); // 다른 속성과 같이 값을 동시에 주고 싶다면 value 속성 이름 언급 해야 함
어노세이션 적용 대상 - @Target
@Target
어노테이션을 사용하여 적용 대상 지정
// 클래스, 인터페이스, 열거 타입, 필드, 메소드 적용 가능
@Target( { ElementType.Type, ElementType.FIELD, ElementType.METHOD } )
public @interface AnnotationName {
}
어노테이션 유지 정책 - @Retention
@Retention
어노테이션을 사용하여 어노테이션을 언제까지 유지할 것인지 지정@Retention
의 기본 속성인 value는 RetentionPolicy 열거 상수 값 가짐
@Target( { ElementType.TYPE, ElementType.FIELD, ElementType.METHOD } )
@Retention( RetentionPolicy.RUNTIME )
public @interface AnnotationName {
}
@AnnotationName // TYPE(클래스)에 적용
public class ClassName {
@AnnotationName // 필드에 적용
private String fieldName;
// @AnnotationName // @Target에 CONSTRUCT가 없으므로 생성자에는 적용 못함
public ClassName() {}
@AnnotationName // 메소드에 적용
public void methodName() {}
}
어노테이션 설정 정보 이용
- 리플렉션을 이용하여 적용 대상으로부터 어노테이션 정보를 다음 메소드로 얻어낼 수 있다.
- 이런 게 있다 정도만 알아두자
isAnnotationPresent(AnnotationName.class)
: 지정한 어노테이션이 적용되었는지 여부 - boolean 리턴getAnnotation(AnnotationName.class)
: 지정한 어노테이션이 적용되어 있으면 어노테이션을, 그렇지 않다면 null을 리턴getDeclaredAnnotations()
: 적용된 모든 어노테이션을 리턴(Annotation[])