- 자바의 String 은 불변 객체이다.
- 객체의 비교는 equals() 메서드로 해야한다.
- toString()
//a,b,c 라는 문자의 조합이다.
//s는 리모콘, heap에는 문장인 "abc"가 저장되어 있다.
String s = "abc";
//상황1
String s1 = "하";
s1 += "하"
String s2 = "하하";
System.out.println(s1 == s2); // 리모콘 끼리 비교하기 때문에 무조건 false 나온다.
System.out.println(s1.equals(s2)); //true 나온다.
//상황2
String s1 = "가";
String s2 = "가"; //컴파일 시점에서 s1과 값이 같아서 같은 것을 가리킨다.
System.out.println(s1 == s2); //true 나온다.
//상황3
String s1 = new String("하"); //new 연산은 heap에 객체를 생성한다.
String s2 = new String("하");
System.out.println(s1 == s2); // new 연산으로 생성했기 때문에 서로 주소값이 다르다. -> false
객체 == 비교는 주소값을 비교
하는 것이다. 즉, 리모컨이 가지고 있는 주소값을 비교//heap 메모리에는 객체 2개가 생성된다.
String s = "첫번째 객체";
s = "두번째 객체";
//heap 메모리에는 객체 4개가 생성된다.
String s = "첫번째 객체";
s += "이렇게 해도 두번째 객체";
s += "세번째 객체";
s += "네번째 객체";
//위와 같이 하고 싶으면 StringBuilder 를 사용해라
StrinbBuilder sb = new StringBuilder();
sb.append("1");
sb.append("2");
sb.append("3");
StringBuilder
클래스를 이용해보자.-> String에 관해서는 String pool으 따로 공부해보자.
package org.example;
public class Main {
public static void main(String[] args) {
Person person = new Person();
person.name = "후후";
person.age = 21;
System.out.println(person);
}
}
class Person{
String name;
int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package org.example;
import java.util.Objects;
public class Main {
public static void main(String[] args) {
Person person = new Person();
person.name = "후후";
person.age = 21;
Person person2 = new Person();
person2.name = "후후";
person2.age = 21;
//false
System.out.println(person == person2);
//true 나온다.
System.out.println(person.equals(person2));
}
}
class Person{
String name;
int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//아래의 equals()는 intellij에서 자동생성 해주는 코드
@Override
public boolean equals(Object o) {
if (this == o)
return true;
//getClass() == o.getClass() 서로 같은 클래스인지 확인
if (o == null || getClass() != o.getClass())
return false;
Person person = (Person) o;
//이름, 나이 비교해서 true, false 반환
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
//직접 만들어 본 equals()
@Override
public boolean equals(Object o) {
//나와 같은 클래스가 아니라면 입구컷
if(this.getClass() != o.getClass())
return false;
//명시적 형변환 해준다.
Person other = (Person) o;
//이 아래는 멤버변수의 값 비교 equals() 비교
if(!name.equals(other.name))
return false;
if(age != other.age)
return false;
return true;
}
}
Car car = new 페라리();
청둥오리 청둥오리 = (청둥오리)new 오리();
→ Int저장소, Float저장소, Double 저장소 등이 존재하고 모두 동일한 기능을 가지고있다고하자. 근데 이러한 것들이 너무 많아서 Object저장소 1개로 퉁친다고 하자.
→ 이 Object에는 어떤 타입이 들어올지 모른다. 이것을 외부에서 사용자에 의해 지정
한다.
대락적인 형태
class 제너릭저장소<T>{
Object data;
int getData(){
reutn (T)data;
}
}
new 제너릭저장소<Integer>();//이런 형식으로 사용자가 타입을 지정한다.
예제
class Main {
public static void main(String[] args) {
저장소<Integer> a저장소1 = new 저장소<>();
a저장소1.setData(50);
int a = a저장소1.getData();
System.out.println(a);
저장소<Double> a저장소2 = new 저장소<>();
a저장소2.setData(5.5);
double b = a저장소2.getData();
System.out.println(b);
저장소<사과> a저장소3 = new 저장소<>();
a저장소3.setData(new 사과());
사과 c = a저장소3.getData();
System.out.println(c);
}
}
class 저장소<T> {
Object data;
T getData() {
return (T)data;
}
void setData(T inputedData) {
this.data = inputedData;
}
}
-> 기존에는 Int, Double, 사과 별로 저장소 클래스가 따로 있었는데 제네릭을 이용해서 하나의 클래스 파일로 줄였다.