API도큐먼트는 쉽게 API를 찾아 이용할 수 있도록 문서화한 것을 의미한다. 다음 페이지를 방문하면 볼 수 있다.
https://docs.oracle.com/javase/8/docs/api/
java.util 패키지
java.util패키지는 자바 프로그램 개발에 조미료 같은 역할을 하는 클래스를 담고 있다. 컬렉션 클래스들이 대부분을 차지하고 있는데, 컬렉션 클래스들은 나중에 다룰 것이다.
우리가 기본적으로 extends를 해주지 않으면 java.lang.Object클래스를 상속하게 된다.
객체 비교(equals())
자바에서는 두 객체를 동등 비교할 때 equals() 메소드를 흔히 사용한다. 논리적으로 동등하다는 것은 같은 객체이건 다른 객체이건 상관없이 객체가 저장하고 있는 데이터가 동일함을 뜻한다. String객체의 equals()메소드는 String객체의 번지를 비교하는 것이 아니라, 문자열이 동일한지 조사해서 같다면 true를 리턴하고, 그렇지 않다면 false를 리턴한다. 이것이 가능한 이유는 String클래스가 Object의 equals()메소드를 오버라이딩해서 번지 비교가 아닌 문자열 비교로 변경했기 때문이다.
비교 객체가 동일한 타입이라면 기준 객체 타입으로 강제 타입 변환해서 필드값이 동일한지 검사해야 한다.
package com.company.BasicAPI;
import java.util.Objects;
public class Member {
public String id;
public Member(String id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Member) {
Member member = (Member) obj;
if(id.equals(member.id)) {
return true;
}
}
return false;
}
}
package com.company.BasicAPI;
public class MemberExample {
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(obj2.equals(obj3)) {
System.out.println("obj2과 obj3는 동일합니다.");
} else {
System.out.println("obj2과 obj3는 동일하지 않습니다.");
}
}
}
//obj1과 obj2는 동일합니다.
//obj2과 obj3는 동일하지 않습니다.
객체 해시코드(hashCode())
객체 해시코드란 객체를 식별할 하나의 정수값을 말한다. Object의 hashCode()메소드는 객체의 메모리 번지를 이용해서 해시코드를 만들어 리턴하기 때문에 객체마다 다른 값을 가지고 있다. 논리적 동등 비교 시 hashCode()를 오버라이딩할 필요성이 있다.
다음을 보면 그냥 equals()메소드를 재정의해서 number의 필드값이 같으면 true를 리턴하도록 했습니다. 하지만 hashCode()메소드는 재정의하지 않았기 때문에 Object의 hashCode()메소드가 사용됩니다.
package com.company.BasicAPI;
public class Key {
public int number;
public Key(int number) {
this.number = number;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Key) {
Key compareKey = (Key) obj;
if(this.number == compareKey.number) {
return true;
}
}
return false;
}
}
이런 경우 HashMap의 식별키로 Key객체를 사용하면 저장된 값을 찾아오지 못하게 됩니다. 왜냐하면 number의 필드값이 같더라도 hashCode()메소드에서 리턴하는 해시코드가 다르기 때문에 다른 식별키로 인식하게 되기 때문입니다.
package com.company.BasicAPI;
import java.util.HashMap;
public class KeyExample {
public static void main(String[] args) {
HashMap<Key, String> hashMap = new HashMap<>();
// 식별키 "new Key(1)"로 "홍길동"을 저장함
hashMap.put(new Key(1), "홍길동");
// 식별키 "new Key(1)"로 "홍길동"을 읽어옴
String value = hashMap.get(new Key(1));
System.out.println(value);
}
}
//null
의도한 대로 "홍길동"을 읽으려면 다음과 같이 재정의한 hashCode()메소드를 Key클래스에 추가하면 됩니다
package com.company.BasicAPI;
public class Key {
public int number;
public Key(int number) {
this.number = number;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Key) {
Key compareKey = (Key) obj;
if(this.number == compareKey.number) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return number;
}
}
저장할 떄의 new Key(1)과 읽을 떄의 new Key(1)은 사실 서로 다른 객체이지만 HashMap은 hashCode()의 리턴값이 같고, equals()리턴값이 true가 나오기 때문에 동등 객체로 평가합니다.
Member클래스도 다음과 같이 바꾸어줄 수 있습니다.
package com.company.BasicAPI;
import java.util.Objects;
public class Member {
public String id;
public Member(String id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Member) {
Member member = (Member) obj;
if(id.equals(member.id)) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return id.hashCode();
}
}
객체 문자 정보(toString())
package com.company.BasicAPI;
public class SmartPhone {
private String company;
private String os;
public SmartPhone(String company, String os) {
this.company = company;
this.os = os;
}
@Override
public String toString() {
return company + ", " + os;
}
}
package com.company.BasicAPI;
public class SmartPhoneExample {
public static void main(String[] args) {
SmartPhone myPhone = new SmartPhone("구글", "안드로이드");
String strObj = myPhone.toString();
System.out.println(strObj);
System.out.println(myPhone);
}
}
//구글, 안드로이드
//구글, 안드로이드
매개값으로 객체를 주면 객체의 toString()메소드를 호출해서 리턴값을 받아 출력하도록 되어 있다.
객체 복제(clone())
객체 복제는 원본 객체의 필드값과 동일한 값을 가지는 새로운 객체를 생성하는 것을 말한다. 객체를 복제하는 이유는 원본 객체를 안전하게 보호하기 위해서이다. 객체를 복제하는 방법에는 얕은 복제와 깊은 복제가 있다.
Object의 clone()메소드는 자신과 동일한 필드값을 가진 얕은 복제된 객체를 리턴한다. 이 메소드로 객체를 복제하려면 원본 객체는 반드시 java.lang.Cloneable인터페이스를 구현하고 있어야 한다.
< 얕은 복제 >
package com.company.BasicAPI;
import java.util.Objects;
public class Member implements Cloneable{
public String id;
public String name;
public String password;
public int age[];
public boolean adult;
public Member(String id, String name, String password, int age[], boolean adult) {
this.id = id;
this.name = name;
this.password = password;
this.age = age;
this.adult = adult;
}
public Member getMember() {
Member cloned = null;
try {
cloned = (Member) clone();
} catch(CloneNotSupportedException e) { }
return cloned;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Member) {
Member member = (Member) obj;
if(id.equals(member.id)) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return id.hashCode();
}
}
<
package com.company.BasicAPI;
public class MemberExample {
public static void main(String[] args) {
Member original = new Member("blue", "홍길동", "12345", new int[] {21, 22}, true);
Member cloned = original.getMember();
cloned.age[0] = 30;
for (int i : cloned.age) {
System.out.print(i + " ");
}
System.out.println();
for (int i : original.age) {
System.out.print(i + " ");
}
}
}
// 30 22
// 30 22
< 깊은 복제 >
얕은 복제의 경우 참조 타입 필드는 번지만 복제되기 때문에 원본 객체의 필드와 복제 객체의 필드는 같은 객체를 참조하게 된다. 만약 복제 객체에서 참조 객체를 변경하면 원본 객체도 변경된 객체를 가지게 된다. 이것의 반대 개념은 깊은 복제인데, 깊은 복제란 참조하고 있는 객체도 복제하는 것을 말한다.
깊은 복제를 하려면 Object의 clone()메소드를 재정의해서 참조 객체를 복제하는 코드를 직접 작성해야 합니다.
package com.company.BasicAPI;
import java.util.Arrays;
import java.util.Objects;
public class Member implements Cloneable{
public String id;
public String name;
public int age;
public int[] scores;
public Car car;
public Member(String name, int age, int[] scores, Car car) {
this.name = name;
this.age = age;
this.scores = scores;
this.car = car;
}
@Override
protected Object clone() throws CloneNotSupportedException{
// 먼저 얕은 복사를 해서 name, age를 복제한다.
Member cloned = (Member) super.clone();
// scores를 깊은 복제한다.
cloned.scores = Arrays.copyOf(this.scores, this.scores.length);
// car를 깊은 복제한다.
cloned.car = new Car(this.car.model);
// 깊은 복제된 Member 객체를 리턴
return cloned;
}
public Member getMember() {
Member cloned = null;
try {
cloned = (Member) clone();
} catch(CloneNotSupportedException e) { }
return cloned;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Member) {
Member member = (Member) obj;
if(id.equals(member.id)) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return id.hashCode();
}
}
package com.company.BasicAPI;
public class MemberExample {
public static void main(String[] args) {
Member original = new Member("홍길동", 25, new int[] {90, 90}, new Car("소나타"));
Member cloned = original.getMember();
cloned.scores[0] = 100;
cloned.car.model = "그랜저";
System.out.println("[복제 객체의 픽드값]");;
System.out.println("name: " + cloned.name);
System.out.println("age: " + cloned.age);
System.out.print("scores: {");
for(int i = 0; i < cloned.scores.length; i++) {
System.out.print(cloned.scores[i]);
System.out.print((i == (cloned.scores.length - 1)) ? "" : ",");
}
System.out.println("}");
System.out.println("[원본 객체의 픽드값]");;
System.out.println("name: " + original.name);
System.out.println("age: " + original.age);
System.out.print("scores: {");
for(int i = 0; i < original.scores.length; i++) {
System.out.print(original.scores[i]);
System.out.print((i == (original.scores.length - 1)) ? "" : ",");
}
System.out.println("}");
}
}
//[복제 객체의 픽드값]
//name: 홍길동
//age: 25
//scores: {100,90}
//[원본 객체의 픽드값]
//name: 홍길동
//age: 25
//scores: {90,90}
이와같이 객체의 깊은 복사가 완벽하게 된 것을 확인할 수 있습니다.
객체 소멸자
참조하지 읺는 배열이나 객체는 쓰레기 수집기가 힙 영역에서 자동적으로 소멸시킨다. 쓰레기 수집기는 객체를 소멸하기 직전에 마지막으로 객체의 소멸자(finalize())를 실행시킵니다. 소멸자는 Object의 finalize()메소드를 말하는데, 기본적으로 실행 내용이 없다. 만약 객체가 소멸되지 전에 마지막으로 사용했던 자원(데이터 연결, 파일등)을 닫고 싶거나, 중요한 데이터를 저장하고 싶다면 Object의 finalize()를 재정의할 수 있다.
package com.company.BasicAPI;
public class Counter {
private int no;
public Counter(int no) {
this.no = no;
}
@Override
protected void finalize() throws Throwable {
System.out.println(no + "번 객체의 finalize()가 실행됨");
}
}
package com.company.BasicAPI;
public class FinalizeExample {
public static void main(String[] args) {
Counter counter = null;
for(int i = 1; i <= 50; i++) {
counter = new Counter(i);
counter = null;
System.gc();
}
}
}
//4번 객체의 finalize()가 실행됨
//25번 객체의 finalize()가 실행됨
//27번 객체의 finalize()가 실행됨
//30번 객체의 finalize()가 실행됨
//33번 객체의 finalize()가 실행됨
//37번 객체의 finalize()가 실행됨
//42번 객체의 finalize()가 실행됨
//44번 객체의 finalize()가 실행됨
//49번 객체의 finalize()가 실행됨
//50번 객체의 finalize()가 실행됨
//48번 객체의 finalize()가 실행됨
//47번 객체의 finalize()가 실행됨
//46번 객체의 finalize()가 실행됨
//45번 객체의 finalize()가 실행됨
//43번 객체의 finalize()가 실행됨
//41번 객체의 finalize()가 실행됨
//40번 객체의 finalize()가 실행됨
실행 결과는 순서대로 소멸시키지 않고, 무작위로 소멸시키는 것을 볼 수 있다. 그리고 전부 소멸시키는 것이 아니라 메모리의 상태를 보고 일부만 소멸시킨다. 메모리가 부족할 때 그리고 CPU가 한가할 때에 JVM에 의해서 실행됩니다. 그렇기 때문에 finalize()메소드가 호출되는 시점은 명확하지 않습니다.
Objects클래스
이는 Object클래스와 이름이 비슷한데, 객체 비교, 해시코드 생성, null여부, 객체 문자열 리턴등의 연산을 수행하는 정적 메소드들로 구성된 Object의 유티리티 클래스이다.
객체 비교(compare)
package com.company.BasicAPI;
import java.util.Comparator;
public class StudentComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return Integer.compare(o1.sno, o2.sno);
}
}
package com.company.BasicAPI;
public class Student {
int sno;
Student(int sno) {
this.sno = sno;
}
}
package com.company.BasicAPI;
import java.util.Objects;
public class CompareExample {
public static void main(String[] args) {
Student s1 = new Student(1);
Student s2 = new Student(1);
Student s3 = new Student(3);
int result = Objects.compare(s1, s2, new StudentComparator());
System.out.println(result);
result = Objects.compare(s1, s3, new StudentComparator());
System.out.println(result);
}
}
//0
//-1
이와 같이 제네릭 Comparator인터페이스를 구현해야 합니다.
동등비교(equals()와 deepEquals())
Objects.equals(Object a, Object b)는 두 객체의 동등성을 비교하는데,
- a: not null, b: not null -> a.equals(b)의 리턴값
- a: not null, b: null -> false
- a: null, b: not null -> false
- a: null, b: null -> true
또한 Objects.deepEquals(Object a, Object b)역시 두 객체의 동등을 비교하는데. a와 b가 서로 다른 배열일 경우, 항목 값이 모두 같다면 true를 리턴한다.
package com.company.BasicAPI;
import java.util.Arrays;
import java.util.Objects;
public class EqualsAndDeepEqualExample {
public static void main(String[] args) {
Integer o1 = 1000;
Integer o2 = 1000;
System.out.println(Objects.equals(o1, o2));
System.out.println(Objects.equals(o1, null));
System.out.println(Objects.equals(null, o2));
System.out.println(Objects.equals(null, null));
System.out.println(Objects.deepEquals(o1, o2) + "\n");
Integer[] arr1 = {1, 2};
Integer[] arr2 = {1, 2};
System.out.println(Objects.equals(arr1, arr2));
System.out.println(Objects.deepEquals(arr1, arr2));
System.out.println(Arrays.deepEquals(arr1, arr2));
System.out.println(Objects.equals(null, arr2));
System.out.println(Objects.equals(arr1, null));
System.out.println(Objects.equals(null, null));
}
}
//true
//false
//false
//true
//true
//
//false
//true
//true
//false
//false
//true
해시코드 생성(hash(), hashCode())
Objects.hash(Object... values)메소드는 매개값으로 주어진 값들을 이용해서 해시 코드를 생성하는 역할을 합니다. 주어진 매개값들로 배열을 생성하고 Arrays.hashCode(Object[])를 호출해서 해시코드를 얻고 이 값을 리턴한다. 이 메소드는 클래스가 hashCode를 재정의할 때 리턴값을 생성하기 위해 사용되면 좋다. 클래스가 여러 가지 필드를 가지고 있을 때 이 필드로부터 해시코드를 생성하게 되면 동일한 필드값을 가지는 객체는 동일한 해시코드를 가질 수 있게 된다.
package com.company.BasicAPI;
import java.util.Objects;
public class HashCodeExample {
public static void main(String[] args) {
Student s1 = new Student(1, "홍길동;");
Student s2 = new Student(1, "홍길동;");
System.out.println(s1.hashCode());
System.out.println(Objects.hashCode(s2));
}
static class Student {
int sno;
String name;
Student(int sno, String name) {
this.sno = sno;
this.name = name;
}
@Override
public int hashCode() {
return Objects.hash(sno, name);
}
}
}
//1678652973
//1678652973
널 요부 조사
Objects.isNull(Object obj)는 매개값이 null인 경우 true를 리턴하고 notNull은 null인 경우 false를 리턴합니다. 또한 requireNotNull은 세가지 오버로딩을 가집니다 아래의 예시를 보면서 이해해 봅시다.
package com.company.BasicAPI;
import java.util.Objects;
public class NullExample {
public static void main(String[] args) {
String str1 = "홍길동";
String str2 = null;
System.out.println(Objects.requireNonNull(str1));
try {
String name = Objects.requireNonNull(str2);
} catch(NullPointerException e) {
System.out.println(e.getMessage());
}
try {
String name = Objects.requireNonNull(str2, "이름이 없습니다.");
} catch(NullPointerException e){
System.out.println(e.getMessage());
}
try {
String name = Objects.requireNonNull(str2, () -> "이름이 없다니깐요.");
} catch(NullPointerException e) {
System.out.println(e.getMessage());
}
}
}
//홍길동
//null
//이름이 없습니다.
//이름이 없다니깐요.
세번째 오버로딩을 보면 람다식을 사용한 것을 볼 수 있습니다.
객체 문자 정보
package com.company.BasicAPI;
import java.util.Objects;
public class ToStringExample {
public static void main(String[] args) {
String str1 = "홍길동";
String str2 = null;
System.out.println(Objects.toString(str1));
System.out.println(Objects.toString(str2));
System.out.println(Objects.toString(str2, "이름이 없습니다."));
}
}
//홍길동
//null
//이름이 없습니다.
Objects.toString()은 객체의 문자 정보를 리턴합니다.
Class 클래스
프로그램에서 Class객체를 얻기 위해서는 Object클래스가 가지고 있는 getClass()메소드를 이용하면 됩니다. 또한 Class.forName()메소드는 매개값으로 주어진 클래스를 찾지 못하면 ClassNotFoundException예외를 발생합니다.
package com.company.BasicAPI;
public class ClassExample {
public static void main(String[] args) {
Car car = new Car("소나타");
Class clazz1 = car.getClass();
System.out.println(clazz1.getName());
System.out.println(clazz1.getSimpleName());
System.out.println(clazz1.getPackage().getName());
try {
Class clazz2 = Class.forName("com.company.BasicAPI.Car");
System.out.println(clazz2.getName());
System.out.println(clazz2.getSimpleName());
System.out.println(clazz2.getPackage().getName());
} catch(ClassNotFoundException e) {
e.printStackTrace();
}
}
}
//com.company.BasicAPI.Car
//Car
//com.company.BasicAPI
//com.company.BasicAPI.Car
//Car
//com.company.BasicAPI
리플렉션
Class객체를 이용하면 클래스의 생성자, 필드, 메소드 정보를 알 수 있습니다.
package com.company.BasicAPI;
import java.lang.reflect.Constructor;
public class ReflectionExample {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.company.BasicAPI.Car");
System.out.println("[클래스 이름]");
System.out.println(clazz.getName());
System.out.println();
System.out.println("[생성자 정보]");
Constructor[] constructors = clazz.getDeclaredConstructors();
for(Constructor constructor : constructors) {
System.out.print(constructor.getName() + "(");
Class[] parameters = constructor.getParameterTypes();
printParameters(parameters);
System.out.println(")");
}
}
private static void printParameters(Class[] parameters ){
for(int i = 0; i < parameters.length; i++) {
System.out.print(parameters[i].getName());
if(i < parameters.length - 1) {
System.out.print(",");
}
}
}
}
//[클래스 이름]
//com.company.BasicAPI.Car
//
//[생성자 정보]
//com.company.BasicAPI.Car(java.lang.String)
동적 객체 생성
Class객체를 이용하면 new연산자를 사용하지 않아도 동적으로 객체를 생성할 수 있다. 이 방법은 코드 작성 시에 클래스 이름을 결정할 수도 없고, 런타임 시에 클래스 이름이 결정되는 경우에 매우 유용하게 사용된다.
package com.company.BasicAPI;
public class NewInstanceExample {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.company.BasicAPI.SendAction");
// Class clazz = Class.forName("com.company.BasicAPI.ReceiveAction");
Action action = (Action) clazz.newInstance();
action.execute();
}
}
//데이터를 보냅니다.
String 클래스
우선 바이트 배열을 문자열로 변환하는 예제이다.
package com.company.BasicAPI;
public class ByteToStringExample {
public static void main(String[] args) {
byte[] bytes = {72, 101, 108, 108, 111, 32, 74, 97, 118, 97};
String str1 = new String(bytes);
System.out.println(str1);
String str2 = new String(bytes, 6, 4);
System.out.println(str2);
}
}
//Hello Java
//Java
또한 System.in으로 바이트 배열을 통해 문자열로 바꿔서 읽어줄 수 있다.
package com.company.BasicAPI;
import java.io.IOException;
public class KeyboardToStringExample {
public static void main(String[] args) throws IOException {
byte[] bytes = new byte[100];
System.out.print("입력: ");
int readByteNo = System.in.read(bytes);
String str = new String(bytes, 0, readByteNo - 1);
System.out.println(str);
}
}
//입력: Hello
//Hello
charAt
또한 charAt()메소드는 매개값으로 주어진 인덱스의 문자를 리턴합니다.
package com.company.BasicAPI;
public class StringExample {
public static void main(String[] args) {
String ssn = "010624-1230123";
char sex = ssn.charAt(7);
switch(sex) {
case '1':
case '3':
System.out.println("남자 입니다.");
break;
case '2':
case '4':
System.out.println("여자 입니다.");
break;
}
}
}
//남자 입니다.
indexOf
또한 indexOf()메소드는 매개값으로 주어진 문자열이 시작되는 인덱스를 리턴합니다. 만약 주어진 문자열이 포함되어 있지 않으면 -1을 리턴합니다.
package com.company.BasicAPI;
public class StringIndexOfExample {
public static void main(String[] args) {
String subject = "자바 프로그래밍";
int location = subject.indexOf("프로그래밍");
System.out.println(location);
if(subject.indexOf("자바") != -1) {
System.out.println("자바와 관련된 책이군요");
} else {
System.out.println("자바와 관련없는 책이군요");
}
}
}
//3
//자바와 관련된 책이군요
Replace
또한 replace()로 문자열을 만들 수 있습니다. String객체의 문자열은 변경이 불가한 특성을 갖기 때문에 replace() 메소드가 리턴하는 문자열은 원래 문자열의 수정본이 아니라 완전히 새로운 문자열입니다.
package com.company.BasicAPI;
public class StringReplaceExample {
public static void main(String[] args) {
String oldStr = "자바는 객체지향언어 입니다. 자바는 풍부한 API를 지원합니다.";
String newStr = oldStr.replace("자바", "JAVA");
System.out.println(oldStr);
System.out.println(newStr);
}
}
//자바는 객체지향언어 입니다. 자바는 풍부한 API를 지원합니다.
//JAVA는 객체지향언어 입니다. JAVA는 풍부한 API를 지원합니다.
SubString
substring(int beginIndex, int endIndex)와 subString(int beginIndex)두가지 오버로딩이 있습니다.
package com.company.BasicAPI;
public class StringSubStringExample {
public static void main(String[] args) {
String ssn = "880815-1234567";
String firstNum = ssn.substring(0, 6);
System.out.println(firstNum);
String secondNum = ssn.substring(7);
System.out.println(secondNum);
}
}
//880815
//1234567
trim
trim()메소드는 앞뒤 공백을 제거한 새로운 문자열을 생성하고 리턴합니다.
String oldStr = " 자바 프로그래밍 ";
String newStr = oldStr.trim();
// 자바 프로그래밍
문자열 변환 (valueOf())
valueOf()메소드는 기본 타입의 값을 문자열로 변환하는 기능을 가지고 있습니다.
package com.company.BasicAPI;
public class StrinvValueOfExample {
public static void main(String[] args) {
String str1 = String.valueOf(10);
String str2 = String.valueOf(10.5);
String str3 = String.valueOf(true);
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
}
}
//10
//10.5
//true
StringTokenizer클래스
문자열이 특정 구분자(delimiter)로 연결되어 있을 경우 구분자를 기준으로 부분 문자열을 분리하기 위해서 String의 split()메소드를 이용하거나, java.util의 StringTokenizer클래스를 이용할 수 있습니다. split()은 정규 표현식으로 구분하고, StringTokenizer는 문자로 구분한다는 차이점이 있습니다.
split
package com.company.BasicAPI;
public class StringSplitExample {
public static void main(String[] args) {
String text = "홍길동&이수홍,박연수,김자바-최명호";
String[] names = text.split("&|,|-");
for(String name : names) {
System.out.println(name);
}
}
}
//홍길동
//이수홍
//박연수
//김자바
//최명호
StringTokenizer
문자열이 한 종류의 구분자로 연결되어 있을 경우, StringTokenizer클래스를 사용하면 손쉽게 문자열(token)을 분리해 낼 수 있습니다. StringToekenizer객체를 생성할 때 첫 번째 매개값으로 전체 문자열을 주고, 두 번쨰 매개값으로 구분자를 주면 됩니다.
package com.company.BasicAPI;
import java.util.StringTokenizer;
public class StringTokenzierExample {
public static void main(String[] args) {
String text = "홍길동/이수홍.박연수";
StringTokenizer st = new StringTokenizer(text, "/.");
int countTokens = st.countTokens();
for(int i = 0; i < countTokens; i++) {
String token = st.nextToken();
System.out.println(token);
}
System.out.println();
st = new StringTokenizer(text, "/.");
while(st.hasMoreTokens()) {
String token = st.nextToken();
System.out.println(token);
}
}
}
//홍길동
//이수홍
//박연수
//
//홍길동
//이수홍
//박연수
StringBuffer, StringBilder
문자열을 합하는 + 연산자를 많이 사용하면 사용 할수록 그만큼 String객체의 수가 늘어나기 때문에, 프로그램 성능을 느리게 하는 요인이 됩니다. 문자열을 변경하는 작업이 많은 경우에는 String클래스를 사용하는 것보다는 java.lang패키지의 StringBuffer 또는 StringBuilder클래스를 사용하는 것이 좋습니다. 이 두 클래스는 내부 버퍼에 문자열을 저장해 두고, 그 안에서 추가, 수정, 삭제 작업을 할 수 있도록 설계되어 있습니다. String처럼 새로운 객체를 만들지 않고도 문자열을 조작할 수 있다는 것입니다.
package com.company.BasicAPI;
public class StringBuilderExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append("java ");
sb.append("Program Study");
System.out.println(sb.toString());
sb.insert(4, "2");
System.out.println(sb.toString());
sb.setCharAt(4, '6');
System.out.println(sb.toString());
sb.replace(6, 13, "Book");
System.out.println(sb.toString());
sb.delete(4, 5);
System.out.println(sb.toString());
int length = sb.length();
System.out.println("총문자수: " + length);
String result = sb.toString();
System.out.println(result);
}
}
//java Program Study
//java2 Program Study
//java6 Program Study
//java6 Book Study
//java Book Study
//총문자수: 15
//java Book Study
Arrays클래스
Arrays클래스는 배열 조작 기능을 가지고 있습니다. 배열 조작이란 복사, 항목 정렬, 항목 검색과 같은 기능을 말합니다.
배열 복사
배열 복사를 위해 사용할 수 있는 메소드는 copyOf(원본 배열, 복사 길이), copyOfRange(원본배열, 시작인덱스, 끝인덱스)입니다. 또한 단순히 배열을 복사할 목적이라면 Arrays클래스를 사용하지 않고 System.arraycopy()메소드를 이용할 수 있습니다. System.arraycopy(원본배열, 원본시작인덱스, 타겟배열, 타겟시작인덱스, 복사개수)
package com.company.BasicAPI;
import java.util.Arrays;
public class ArrayCopyExample {
public static void main(String[] args) {
char[] arr1;
arr1 = new char[] {'J', 'A', 'V', 'A'};
char[] arr2 = Arrays.copyOf(arr1, arr1.length);
System.out.println(Arrays.toString(arr2));
char[] arr3 = Arrays.copyOfRange(arr1, 1, 3);
System.out.println(Arrays.toString(arr3));
char[] arr4 = new char[arr1.length];
System.arraycopy(arr1, 0, arr4, 0, arr1.length);
for(int i = 0; i < arr4.length; i++) {
System.out.println("arr4[" + i + "]=" + arr4[i]);
}
}
}
//[J, A, V, A]
//[A, V]
//arr4[0]=J
//arr4[1]=A
//arr4[2]=V
//arr4[3]=A
배열 항목 비교
Arrays의 equal()와 deepEquals()는 배열 항목을 비교합니다. equals()는 1차 항목의 값만 비교하고, deepEquals()는 1차 항목이 서로 ㅂ다른 배열을 참조할 경우 중첩된 배열의 항목까지 비교합니다.
package com.company.BasicAPI;
import java.util.Arrays;
public class EqualsExample {
public static void main(String[] args) {
int[][] original = {{1, 2}, {3, 4}};
System.out.println("[얕은 복제후 비교]");
int[][] cloned1 = Arrays.copyOf(original, original.length);
System.out.println("배열 번지 비교: " + original.equals(cloned1));
System.out.println("1차 배열 항목값 비교: " + Arrays.equals(original, cloned1));
System.out.println("중첩 배열 항목값 비교: " + Arrays.deepEquals(original, cloned1));
// 깊은 복사후 비교
System.out.println("\n[깊은 복제후 비교]");
int[][] cloned2 = Arrays.copyOf(original, original.length);
cloned2[0] = Arrays.copyOf(original[0], original[0].length);
cloned2[1] = Arrays.copyOf(original[1], original[1].length);
System.out.println("배열 번지 비교: " + original.equals(cloned2));
System.out.println("1차 배열 항목값 비교: " + Arrays.equals(original, cloned2));
System.out.println("중첩 배열 항목값 비교: " + Arrays.deepEquals(original, cloned2));
}
}
//[얕은 복제후 비교]
//배열 번지 비교: false
//1차 배열 항목값 비교: true
//중첩 배열 항목값 비교: true
//
//[깊은 복제후 비교]
//배열 번지 비교: false
//1차 배열 항목값 비교: false
//중첩 배열 항목값 비교: true
배열 항목 정렬
Comparable<Member>는 Member카입만 비교하기 위해서 제네릭을 사용했습니다. 또한 compareTo()메소드는 비교값을 리턴하도록 오버라이딩 했습니다.
package com.company.BasicAPI;
import java.util.Arrays;
public class SortExample {
public static void main(String[] args) {
int[] scores = {99, 97, 98};
Arrays.sort(scores);
for(int score : scores) {
System.out.println(score);
}
System.out.println();
String[] names = {"홍길동", "박동수", "김민수"};
Arrays.sort(names);
for(String name : names) {
System.out.println(name);
}
System.out.println();
Member[] members;
members = new Member[] {
new Member("홍길동"),
new Member("박동수"),
new Member("김민수")};
Arrays.sort(members);
for(Member member : members) {
System.out.println(member.name);
}
}
}
//97
//98
//99
//
//김민수
//박동수
//홍길동
//
//김민수
//박동수
//홍길동
package com.company.BasicAPI;
import java.util.Arrays;
import java.util.Objects;
public class Member implements Cloneable, Comparable<Member>{
public String id;
public String name;
public int age;
public int[] scores;
public Car car;
public Member(String name, int age, int[] scores, Car car) {
this.name = name;
this.age = age;
this.scores = scores;
this.car = car;
}
public Member(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException{
// 먼저 얕은 복사를 해서 name, age를 복제한다.
Member cloned = (Member) super.clone();
// scores를 깊은 복제한다.
cloned.scores = Arrays.copyOf(this.scores, this.scores.length);
// car를 깊은 복제한다.
cloned.car = new Car(this.car.model);
// 깊은 복제된 Member 객체를 리턴
return cloned;
}
public Member getMember() {
Member cloned = null;
try {
cloned = (Member) clone();
} catch(CloneNotSupportedException e) { }
return cloned;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Member) {
Member member = (Member) obj;
if(id.equals(member.id)) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public int compareTo(Member o) {
// 이름 순으로
return this.name.compareTo(o.name);
}
}
'School > Java Programming' 카테고리의 다른 글
Java Programming - Thread basic (0) | 2022.05.19 |
---|---|
Java Programming - Collection Framework (0) | 2022.04.07 |
Java Programming - Exception (0) | 2022.03.17 |
Java Programming - 중첩 클래스 & 중첩 인터페이스 (0) | 2022.03.17 |
Java Programming - Interface (0) | 2022.03.10 |