목차
1. Object 클래스
모든 클래스의 최고 조상 클래스로 11개의 메서드를 제공하는데, 모든 객체는 Object 클래스를 상속하기 때문에 모든 메서드에서는 이 11개의 메서드를 사용할 수 있다.
하지만 경우에 따라서 오버라이딩으로 재정의해서 사용해야 한다.
equals(Object obj)
public boolean equals(Object obj) {
return (this==obj);
}
Java
복사
•
객체 비교 메서드
•
default 로직은 동일성 비교이다.
•
동등성 비교를 하고자 하면 재정의를 해줘야 한다.
•
재정의 로직은 사용자의 임의대로 만들 수 있다.
⇒ 하지만, 기본적으로 hash를 이용한 방식을 추천하며 기본 오버라이딩 자동생성 로직도 이와같이 hash를 사용한다.
hashCode()
•
객체의 주소값을 이용해 해시코드를 만들어 반환해주는 메서드
•
객체간에 해시코드는 모드 유일하다.
⇒ 식별자로 사용이 가능하다는 의미
•
객체가 아닌 필드 역시 해시코드화가 가능하다.
⇒ 적절한 해시코드 재정의로 객체간의 동일성 비교를 할 수 있다.
public class Axe implements Weapon{
public static final Axe DEFAULT_AXE = new Axe("강철도끼", 1000L, 50);
private String name;
private long price;
private int damage;
//...
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Axe)) return false;
Axe axe = (Axe) o;
return price == axe.price && damage == axe.damage && Objects.equals(name, axe.name);
}
@Override
public int hashCode() {
return Objects.hash(name, price, damage);
}
}
Java
복사
toString()
public String toString() {
return getClass().getName()+"@"+Integer.toHexString(hashCode());
}
Java
복사
Object 클래스에 정의된 기본 toString()
•
인스턴스 정보를 문자열(String)으로 제공할 목적으로 정의된 메서드
•
사용자가 이해할 수 있는 의미있는 문자열로 보고싶을 경우 재정의해서 사용한다.
•
출력문(System.out)에서 toString을 작성안해도 인스턴스만 대입해도 자동으로 toString()이 호출된다.
•
사용 예제
public class Axe implements Weapon{
public static final Axe DEFAULT_AXE = new Axe("강철도끼", 1000L, 50);
private String name;
private long price;
private int damage;
//...
@Override
public String toString() {
return "Axe{" +
"name='" + name + '\'' +
", price=" + price +
", damage=" + damage +
'}';
}
}
Java
복사
clone()
•
Cloneable 구현을 통해 clone을 정의해줘야 사용이 가능하다.
import java.util.ArrayList;
import java.util.List;
public class CloneTest implements Cloneable {
private List<Integer> list = new ArrayList<>();
public CloneTest() {
}
public List<Integer> getList() {
return list;
}
public void setList(List<Integer> list) {
this.list = list;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Java
복사
•
자신을 복제하여 새로운 인스턴스를 생성하는 메서드
•
원래의 인스턴스를 보존하고 새로운 인스턴스를 생성해 작업하고자 할 때 사용한다.
•
인스턴스변수의 값만 복사한다.
⇒ 참조타입의 인스턴스 변수는 참조 주소값을 복사하기에 같은 인스턴스를 바라보게 된다.
⇒ clone된 객체간에 동일한 참조변수주소를 공유함으로써 값 변조에 취약해진다.
⇒ clone 오버라이드에서 이런 참조타입 인스턴스 변수를 복사하는 로직을 넣어줘야 한다.
공변 반환타입(covariant return type)
•
오버라이딩할 때 조상 메서드의 반환타입을 자손 클래스의 타입으로 변경을 허용하는 것.
•
JDK1.5 버전부터 지원하기 시작한 기능.
⇒ 지원 이전 방식 : Point point = (Point) original.clone()
⇒ 지원 이후 방식: Point point = original.clone()
얕은 복사와 깊은 복사
•
얕은 복사(shallow copy | 피상적인 복사)
⇒ 인스턴스 변수만을 복사하며 참조 타입 인스턴스 변수는 그 참조 주소값만을 복사하는 것.
•
깊은 복사(deep copy)
⇒ 원본이 참조하는 참조변수의 주소값이 아닌 주소에 해당하는 객체역시 복사하는 것.
getClass()
•
자신이 속한 클래스의 Class 객체를 반환하는 메서드이다.
•
클래스의 모든 정보를 담고 있으며 클래스 당 1개만 존재한다.
•
클래스 로더(ClassLoader)에 의해 메모리에 올라갈 때 자동으로 생성되며 실행 시 필요한 클래를 동적으로 메모리에 로드하는 역할을 한다.
•
Reflextion API사용에 주로 쓰인다.
•
사용 예) 스프링의 LoggerFactory등록
Logger log = LoggerFactory.getLogger(getClass());
Java
복사
2. String 클래스
문자열을 다루는 클래스
일반적인 원시타입(Primitive) 변수(ex: int, double, long, char ...)와는 다르게 참조 타입의 클래스지만 실제로 사용은 원시타입과 거의 유사하게 동작한다.
⇒ 동일성 비교를해도 참조주소 비교가 아닌 내용 비교를 하고, String 타입 변수를 인자값으로 넘기면 복사가 되서 넘어가기에 참조변수 주소 공유가 되지 않는다.
변경 불가능(immutable)
public final class String implements java.io.Serializable, Comparable {
private char[] value;
//...
}
Java
복사
•
문자 타입(char)의 배열이 문자열 클래스 String이다.
•
final 타입이기에 조상 클래스가 될 수 없다.
•
+ 연산자를 사용해 문자열 결합을 시도할 경우 새로운 문자열 클래스가 생생되는 것.
•
문자열 결합이 많아질수록 새로운 String 인스턴스 생성이 되기에 최소화 하는 것이 좋다.
⇒ StringBuffer나 StringBuilder를 사용하자.
문자열 비교
String str1 = "abc";
String str2 = "abc";
String str3 = new String("abc");
String str4 = new String("abc");
Java
복사
str1 == str2의 결과는?
str3 == str4의 결과는?
문자열 리터럴이란?
•
클래스 파일이 클래스로더에 의해 메모리에 올라갈 때 상수 풀(constant pool)에 저장되는 공유 인스턴스
빈 문자열(empty string)
String emptyStr = "";
Java
복사
•
길이가 0 인 char 배열
•
null을 대입해도 빈 공백열("")으로 초기화한다.
join()과 StringJoiner
•
구분자(Delimiter)를 이용해 문자를 결합하는 메서드
String[] arr = {"catsbi", "crong", "pobi"};
String join = String.join(",", arr);
System.out.println("join = " + join);
//join = catsbi,crong,pobi
Java
복사
•
StringJoiner를 이용한 문자열 결합.
⇒ 추가적으로 prefix, suffix 결합도 가능하다.
String[] arr = {"catsbi", "crong", "pobi"};
StringJoiner sj = new StringJoiner(",", "[", "]");
for (String s : arr) {
sj.add(s);
}
System.out.println("sj = " + sj);
//sj = [catsbi,crong,pobi]
Java
복사
문자 인코딩 변환
•
서버 to 서버나, 파일 to 서버 아니면 클라이언트 to 서버 처럼 데이터를 송/수신 할 때 텍스트를 올바르게 인코딩 하기위해서는 올바른 인코딩 타입을 알아야하는데, 이 인코딩을 이용해서
인코딩 변경도 가능하다.
•
getByte() 메서드를 이용해 문자열을 Byte 타입으로 컨버팅한 다음 다른 인코딩으로 변경이 가능하다.
•
사용 예
⇒ UTF-8 을 UTF-16 인코딩으로 변환하고자 할 때
byte[] utf8_str = "가".getByte("UTF-8");
String str = new String(utf8_str, "UTF-16");
System.out.println("str = " + str);
//str = �
Java
복사
기본형 값을 String으로 변환
원시 타입(int, double, char, long ...)을 문자열로 혹은 그 반대로 변환하는 경우가 자주 있다.
예를들어 웹 클라이언트에서 쿼리스트링 혹은 Message body로 보내는 데이터는 모두 숫자도 String 타입으로 전송된다. 그렇기때문에 적절한 파싱이 필요하다.
이처럼 문자열 기본형 이 서로 변환이 가능해야하고 다음과 같은 방법으로 가능하다.
기본타입을 String으로
•
빈 문자열 결합
⇒ String str1 = 100 + "";
•
valueOf() 메서드 사용
⇒ String str2 = String.valueOf(100);
String을 기본타입으로
•
기본타입의 래퍼클래스의 parseXxx() 메서드를 사용하기
⇒ int i = Integer.parseInt("100");
⇒ double d = Double.parseDouble("100.5");
•
기본타입의 래퍼클래스의 valueOf() 메서드를 사용하기
⇒ int i = Integer.valueOf("100");
⇒ 참고로 해당 메서드의 반환타입은 Integer이지만 오토박싱(auto-boxing)에 의해 자동변환된다.
참고
Integer 클래스의 parseInt() 메서드는 a~f까지 알파벳도 16진수 변환도 가능하다.
예를들어 Integer.parseInt("a", 16)은 10으로 변환이 된다.
참고
오토박싱& 언박싱이란 기본타입과 이 기본타입의 래퍼클래스간에 양방향으로 자동으로 객체화 혹은 기본타입화 해주는 것을 말하는데 기본형값을 자동으로 객체화 해주는것을 오토박싱이라 하고 그 반대를 언박싱이라 한다.
•
기본타입과 래퍼클래스간에 연산이 바로 안되는 부분 때문에 JDK 1.5 이후로 지원되기 시작했다.
3. 유용한 클래스
java.util 패키지안에 존재하며 개발자가 꽤나 자주사용하는 몇몇 클래스에 대한 소개
3.1 java.util.Objects 클래스
•
Object 클래스의 보조클래스
•
유틸 클래스이기에 모든 메서드는 static이다.
•
주로 객체 비교 및 널 체크(null check)에 사용된다.
Apple apple = null;
Apple apple2 = null;
...
//null check
Objects.isNull(apple);
Objects.nonNull(apple);
Objects.requireNonNull(apple, "사과가 존재하지 않습니다.");
//equals
Objects.equals(apple, apple2);
Objects.deepEquals(apple, apple2);
//hashCode
Objects.hashCode(apple);
Java
복사
•
Objects.euqals()를 사용하면 매개변수(객체)가 null인지 체크 할 필요가 없다.
•
deepEquals()를 사용하면 재귀호출로 다차원 배열 비교도 가능해진다.
⇒ 그냥 equals()로 비교하려면 반복문을 통해 하나하나 갑을 추출해 비교해야 한다.
•
Object.hashCode()와 동일하지만 null일때 0을 반환한다는 차이가 있다.
3.2 java.util.Random 클래스
•
난수 생성 유틸 클래스
•
Math.Random()도 결국 Random클래스의 인스턴스를 사용하기에 편한것을 사용하면 된다.
double randNum = Math.random();
double randNum = new Random().nextDouble();
Java
복사
두 로직은 동일하다.
Random 클래스의 생성자와 메서드
public Random() {
this(System.currentTimeMillies());
}
Java
복사
Random()은 기본생성자에서 System.currentTimeMillis()로 시드(seed)를 가지기에 실행할 때마다 얻는 난수가 달라진다.
3.3 정규식(Regular Expression)
•
텍스트 데이터의 특정 패턴으로 문자를 찾아내는 방식.
사용법
1.
정규식을 매개변수로 Pattern 클래스의 static 메서드인 Pattern compile(String regex)으로 Pattern 인스턴스를 생성한다.
2.
해당 인스턴스를 사용해 비교할 대상을 matcher 메서드의 인자값으로 넘겨줘서 반환값으로 Matcher 타입의 인스턴스를 받는다.
3.
Matcher 타입 인스턴스로 matches() 메서드로 일치여부를 확인한다.
public static void main(String[] args) throws UnsupportedEncodingException {
Pattern pattern = Pattern.compile("^[_a-z0-9-]+(.[_a-z0-9-]+)*@(?:\\w+\\.)+\\w+$");
Matcher matcher1 = pattern.matcher("hansolsolsol@gmail.com");
Matcher matcher2 = pattern.matcher("한솔솔솔@gmail.com");
List<Matcher> matchers = Arrays.asList(matcher1, matcher2);
for (Matcher matcher : matchers) {
printMatcher(matcher);
}
}
private static void printMatcher(Matcher matcher) {
if (matcher.matches()) {
System.out.println("이메일 사용이 가능합니다.");
} else {
System.out.println("유효하지 않은 이메일입니다. ");
}
}
Java
복사
•
실행결과
3.4 java.util.Scanner 클래스
•
화면, 파일, 문자열과 같은 입력소스로부터 문자데이터를 읽어오는데 도움을 주는 목적의 클래스
•
다양한 생성자를 지원하며 문자열, 파일등 다양한 포맷을 지원한다.
•
주로 콘솔 I/O 입력에 사용된다.
•
문자열의 경우 유틸 클래스를 이용해 정규식 혹은 구분자 처리가 가능하다.
Scanner useDelimiter(Pattern pattern)
Scanner useDelimiter(String delimiter);
Java
복사
•
여러 메서드를 이용해 편하게 문자를 입력받을 수 있다.
useDelimiter 사용해보기
public static void main(String[] args) throws UnsupportedEncodingException {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.print("input: ");
String str = sc.nextLine();
if (str.equals("9")) {
break;
}
Scanner sc2 = new Scanner(str).useDelimiter(",");
int sum = 0;
while (sc2.hasNextInt()) {
sum+=sc2.nextInt();
}
System.out.println("sum = " + sum);
}
}
Java
복사
3.5 java.util.StringTokenizer 클래스
•
문자열을 구분자(delimiter)를 기준으로 토큰(token)으로 잘라내는 기능을 제공하는 클래스
split()과 useDelimiter()와의 차이점
•
정규식을 사용하지 않는다.
⇒ 단 하나의 문자 구분자(delimiter)만을 사용한다.
제공 메서드
사용 예
public static void main(String[] args) throws UnsupportedEncodingException {
useTwoParameterStringTokenizer("100,200,300,400");
useThreeParameterStringTokenizer("100,200+300x400", false);
useThreeParameterStringTokenizer("100,200+300x400", true);
useStringTokenizerWithMultiDelimiter("100,200+300x400", true);
}
private static void useTwoParameterStringTokenizer(String str) {
StringTokenizer st = new StringTokenizer(str, ",");
st.asIterator()
.forEachRemaining(token->{
System.out.println("token1 = " + token);
});
}
private static void useThreeParameterStringTokenizer(String str, boolean isDelims) {
StringTokenizer st = new StringTokenizer(str, ",", isDelims);
st.asIterator()
.forEachRemaining(token->{
System.out.println("token2 = " + token);
});
}
private static void useStringTokenizerWithMultiDelimiter(String str, boolean isDelims) {
StringTokenizer st = new StringTokenizer(str, ",+x", isDelims);
st.asIterator()
.forEachRemaining(token->{
System.out.println("token3 = " + token);
});
}
Java
복사
•
실행 결과
•
해당 클래스에서 구분자는 한 문자의 구분자만 사용할 수 있는데, delimiter가 ,+x 이런식으로 여러 구분자가 들어가면 모든 구분자가 or condition 으로 적용되어 문자열을 분리한다.
3.6 java.math.BigInterger 클래스
•
숫자를 다루는 기본 타입중 가장 큰 long보다 큰 수를 표시하기 위한 클래스
•
기본형이 아니지만 String 클래스처럼 불변(immutable)이다.
•
int형 배열([])을 이용해 값을 다룬다.
⇒ signum 이라는 변수로 값의 양수(1)/음수(-1)를 구분할 수 있다.
사용법
BigInteger를 생성하는 방법
•
문자열로 생성하는 방법
⇒ new BigInteger("12345678901234567890"0;
•
n진수(radix)의 문자열로 생성
⇒ new BigInteger("FFFF', 16);
•
숫자로 생성하는 방법
⇒ BigInteger.valueOf(1234567890L);
타입 변환
BigINteger val = new BigInteger("12345678890");
//문자열
val.toString()
//문자열(진법 변환)
val.toString(16);// 16진수 변환
//byte 배열 변환
val.toByteArray();
//int 변환
val.intValue();
//long 변환
val.longValue();
//float 변환
val.floatValue();
//double 변환
val.doubleValue();
Java
복사
참고: Exact 접미사가 붙은 메서드는 타입에 엄격하다.
정수형 변환 메서드 중 접미사로 Exact가 붙은 메서드들은 변환 결과가 변환한 타입 범위에 속하지 않을 경우 ArithmeticException 예외가 발생한다.
•
byte byteValueExact()
•
int intValueExact()
•
long longValueExact()
연산하기
BigInteger는 참조타입이기에 기본타입처럼 기본적인 사칙연산 연산자를 통해서 연산할 수는 없으며 수학적인 계산을 하도록 도와주는 메서드들을 사용한다.
•
덧셈
⇒ BigInteger add(BigInteger val) //(this + val)
•
뺄셈
⇒ BigInteger subtract(BigInteger val) //(this - val)
•
곱셈
⇒ BigInteger multiply(BigInteger val) //(this * val)
•
나눗셈
⇒ BigInteger divide(BigInteger val) //(this / val)
•
나머지
⇒ BigInteger remainder(BigInteger val) //(this % val)
비트 연산
BigInteger를 숫자개념이아닌 비트개념으로 연산하기위해 지원하는 메서드
•
int bitCount()
⇒ 2진수로 표현했을 때, 1의 개수(음수는 0의 개수)를 반환
•
int bitLength()
⇒ 2진수로 표현했을 때, 값을 표현하는데 필요한 bit수
•
boolean testBit(int n)
⇒ 우측에서 n+1번째 비트가 1이면 true, 0이면 false를 반환하는 메서드
•
BigInteger setBit(int n)
⇒ 우측에서 n+1번째 비트를 1로 변경
•
BigInteger clearBit(int n)
⇒ 우측에서 n+1번째 비트를 0으로 변경
•
BigInteger flipBit(int n)
⇒ 우측에서 n+1번째 비트를 전환(0과 1을 토글)
사용 예) 짝수/홀수 파악하기
3.7 java.math.BigDecimal 클래스
•
double 타입으로 표현할 수 없는 더 큰 숫자를 더 정확히 표현하고자 할 때 사용한다.
•
BigInteger와 동일하게 불변(immutable)하다.
•
내부에서는 BigInteger를 사용한다.
private final BigInteger intVal; //정수(unscaled value)
private final int scale; //지수(scale)
private transient int precision //정밀도(precision) - 정수의 자릿수
Java
복사
생성하기
•
문자열로 생성하기
⇒ new BigDecimal("123.4567890");
•
double 타입의 리터럴로 생성
⇒ new BigDecimal(123.456);
•
int, long타입의 리터럴로 생성
⇒ new BigDecimal(123456);
•
valueOf(double) 사용해 생성
⇒ BigDecimal.valueOf(123.456);
•
valueOf(int)사용해 생성
⇒BigDecimal.valueOf(123456);
주의점: 생성시 인자값으로 double 타입을 전달하면 오차가 생길 수 있다.
System.out.println(new BigDecimal(0.1)); // 0.10000000...555111...
System.out.println(new BigDecimal("0.1")); // 0.1
Java
복사
타입 변환
•
문자열 변환
◦
toPlainString() : 어떤 경우에도 다른 기호없이 숫자로만 표현
◦
toString() : 필요하면 지수 형태로 표현할수도 있다.
참고: 두 메서드는 대부분 동일한 값을 반환하지만 지수형태의 리터럴을 사용하면 다른 결과를 반환할 수 있다.
반올림 모드 - devide() 와 setScale()
BigInteger와 다르게 BigDecimal클래스에서는 나눗셈 처리 메서드(devide)에서 결과에 대한 내림, 올림, 반올림 여부를 플래그로 넣어줄 수 있다.
오버로딩된 divide의 갯수이며 밑줄이 그어진건 deprecated된 메서드이다.
이중 roundingMode라는 파라미터가있는데 이 파라미터로 BigDecimal에 정의된상수를 선택해 반올림/올림/내림 여부를 결정할 수 있다.
•
열거형 RoundingMode에 정의된 상수
public enum RoundingMode {
UP(0),
DOWN(1),
CEILING(2),
FLOOR(3),
HALF_UP(4),
HALF_DOWN(5),
HALF_EVEN(6),
UNNECESSARY(7);
final int oldMode;
private RoundingMode(int oldMode) {
this.oldMode = oldMode;
}
public static RoundingMode valueOf(int rm) {
switch(rm) {
case 0:
return UP;
case 1:
return DOWN;
case 2:
return CEILING;
case 3:
return FLOOR;
case 4:
return HALF_UP;
case 5:
return HALF_DOWN;
case 6:
return HALF_EVEN;
case 7:
return UNNECESSARY;
default:
throw new IllegalArgumentException("argument out of range");
}
}
}
Java
복사
열거형 RoundingMode에 정의된 상수 설명
그리고 또 다른 파라미터중 MathContext도 있었는데 이는 정밀도를 의미하며 해당 파라미터는 java.math.MathContext 클래스이다.
divide(BigDecimal decimal, MathContext mc) 에서는 MathContext를 이용하는데 MathContext는 precision이 정수와 소수점 이하를 모두 포함한 자릿수를 의미한다.
public static void main(String[] args) throws UnsupportedEncodingException {
BigDecimal bd1 = new BigDecimal("123.456");
BigDecimal bd2 = new BigDecimal("2.0");
System.out.println(bd1.divide(bd2, new MathContext(2, RoundingMode.HALF_DOWN)));
//62
}
Java
복사
⇒ MathContext를 이용한 결과는 precision(정밀도)를 가지고 반올림하기에 bd1의 precision인 123456dptj 3째(n+1)자리에서 반올림해서 precision은 12000이 아니라 12가 된다. 여기서 scale이 반영되어 1.2E+2가 된다.