JAVA 공부중
사용자의 입력을 받을 때 사용
scanner로 사용자의 입력을 받아 사용하고 있었는데 이건 입출력 방식이 느리면 여러 줄을 입력받을 때 시간초과가 날 수 있다고 한다.
Scanner scanner = new Scanner(System.in);
String i = scanner.nextLine(); //문자
int i = scanner.nextInt(); //숫자
또한 System.out.println(); 도 출력 시 시간초과를 낼 수 있다고 함.
System.out.println();
시간초과를 막기위해서 좀 더 빠른 입력시 bufferedReader와 출력시 bufferedWriter를 쓴다고 함.
//BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int t = Integer.parseInt(br.readLine()); //숫자로 쓸거면 형변환 필수
//BufferedWriter
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
bw.write(Integer.toString(num1 + num2)); // 내보낼때도 toString으로 바꿔서 해줘야함. 안그럼 이상한 문자가 출력된다.
bw.newLine(); //줄바꿈
bw.flush(); //남아있는 데이터 모두 출력
bw.close();
StringTokenizer//StringTokenizer
StringTokenizer st = new StringTokenizer(br.readLine()); //BufferedReader로 받은걸 넣서 쓰면 됨.
int num1 = Integer.parseInt(st.nextToken()); //이것도 형변환 필수
int num2 = Integer.parseInt(st.nextToken())
참고 블로그
https://m.blog.naver.com/ka28/221850826909
https://rlakuku-program.tistory.com/33
사실 println을 사용했을때와 toString을 사용했을때 객체의 정보를 조회할 수 있다는 점이 같다. 왜냐면 println 내부에 toString이 들어있기 때문. 그래서 toString 을 오버라이딩하게 되면 println을 했을 때도 오버라이딩된 걸 사용할 수 있다.
IDE를 이용하면 쉽게 toString 오버라이딩할 수 있다. (인텔리제이 윈도우 Alt+insert 이용)
public class Dog {
private String dogName;
private int age;
public Dog(String dogName, int age) {
this.dogName = dogName;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"dogName='" + dogName + '\'' + ", age=" + age +
'}';
}
}
== 연산자 사용. 두 객체의 참조가 동일한 객체를 가리키고 있는지 확인 (완전히 같은 건지 확인)equals()를 사용해서 두 객체가 논리적으로 동등한지 확인동등서을 비교하고 싶으면 equals()메서드를 재정의해야함. 왜냐면 비교할 대상이 다 다르기 때문임.
public class UserV2 {
private String id;
public UserV2(String id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
UserV2 user = (UserV2) obj;
return id.equals(user.id);
}
}
equals를 재정하기하기 힘들기때문에 IDE로 재정의하는게 정확하다.
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Rectangle rectangle = (Rectangle) o;
return width == rectangle.width && height == rectangle.height;
}
기본형은 값이 복사가 되어 사이드 이펙트를 발생시키지 않는다.
참조형의 경우 참조값(주소값)이 복사가 되어 사이드 이펙트를 발생시킬 가능성이 크다.
그럴 때 사용되는 것이 불변 객체이다. 그냥 클래스 내 필드를 final 지정해주면된다. 그럼 setValue()와 같은 값을 지정해주는 메서드도 필요없게 되어 불변객체가 된다.
public class ImmutableAddress {
private final String value;
public ImmutableAddress(String value) {
this.value = value;
}
public String getValue() {
return value;
}
@Override
public String toString() {
return "Address{" +
"value='" + value + '\'' + '}';
}
}
불변객체에서도 값을 변경하는 메서드가 존재할 수 있는데 그건 기존 객체를 변경하는게 아니라 기존 객체를 이용해서 새로운 객체를 생성해 반환하는 방법을 사용한 것.
public ImmutableObj add(int addValue) {
int result = value + addValue;
return new ImmutableObj(result);
}
문자 표현: char
문자열 표현: String (사실 char[], byte[](자바9부터는 byte로 대체)로 만든 클래스임)
//1. 객체 생성
String str1 = new String("hello");
//2. 리터럴 (자바에서 편의를 위해 만든 것)
String str2 = "hello"
String result1 = a.concat(b);
String result2 = a + b
==비교(동일성)가 아니라 equals()비교(동등성)를 해야함.public static void main(String[] args) {
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println("new String() == 비교: " + (str1 == str2)); //false
System.out.println("new String() equals 비교: " + (str1.equals(str2))); // true
String str3 = "hello";
String str4 = "hello";
System.out.println("리터럴 == 비교: " + (str3 == str4)); //true
System.out.println("리터럴 equals 비교: " + (str3.equals(str4))); //true
}

-new String()은 각 인스턴스를 바라보기 때문에 동일성 비교할 때 false로 뜬다.

문자열 리터럴의 경우 문자열을 힙 영역인 문자열 풀에 담아서 중복없이 사용한다. 문자열덕에 같은 문자를 사용하는 경우 메모리 사용을 줄이고, 문자 만드는 시간도 줄여서 성능도 최적화 할 수 있음
상황에 따라 ==와 equals()를 어떻게 사용해야하나 싶으나 결국엔 그냥 equals()를 사용해서 동등성 비교를 하는것이 낫다.
문자열 리터럴로 사용하는 경우 만약 문자열이 바뀌면 같은 문자열을 참조하고 있는건 어떻게 되는걸까?
다행히도 String 클래스는 불변객체여서 사이드 이펙트같은 문제는 발생하지 않는다. 대신 불변객체처럼 concat이나 + 연산을 사용할 경우는 새로운 객체를 반환해서 사용해야한다.
public class StringBuilderMain1_1 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append("A"); // 문자열을 추가
sb.append("B");
sb.append("C");
sb.append("D");
System.out.println("sb = " + sb); //sb = ABCD
sb.insert(4, "Java"); // 특정 위치에 문자열 삽입
System.out.println("insert = " + sb); // insert = ABCDJava
sb.delete(4, 8); //특정 범위의 문자열을 삭제
System.out.println("delete = " + sb); // delete = ABCD
sb.reverse(); // 문자열 뒤집기
System.out.println("reverse = " + sb); // reverse = DCBA
//StringBuilder -> String
String string = sb.toString(); // 문자열을 변경하는 동안만 StringBuilder 를 사용하고, 마지막엔 안전한 불변객체로 만들어주는게 좋다.
System.out.println("string = " + string); // string = DCBA
}
}
//최적화 전
String helloWorld = "Hello, " + "World!";
// 최적화 후
String helloWorld = "Hello, World!";
// 최적화 전
String result = str1 + str2;
//최적화 후
String result = new StringBuilder().append(str1).append(str2).toString();
// 최적화 전
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
String result = "";
for (int i = 0; i < 100000; i++) {
result += "Hello Java ";
}
long endTime = System.currentTimeMillis();
System.out.println("result = " + result);
System.out.println("time = " + (endTime - startTime) + "ms");
}
// 최적화 후
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100000; i++) {
sb.append("Hello Java ");
}
String result = sb.toString();
long endTime = System.currentTimeMillis();
System.out.println("result = " + result);
System.out.println("time = " + (endTime - startTime) + "ms");
}