[Java] String, 제네릭

김민우·2023년 2월 27일
0

String

  • 자바의 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
  • 객체 비교는 equal()로 해야한다. 기본 자료형 비교는 == 비교를 한다.
  • 객체 == 비교는 주소값을 비교하는 것이다. 즉, 리모컨이 가지고 있는 주소값을 비교
    • 그래서 같은 문자열이 저장되어 있어도 == 비교를 하면 주소값 비교를 해서 false가 나온다.
  • equals()는 값을 비교하는것이다.

String은 불볍 객체이다.

//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");
  • String은 불변객체이다.
  • 초기에 문자열을 생성하고 계속 내용을 추가한다면 추가한 만큼 객체가 새로 생기는 것이다.
  • 문장을 계속해서 추가할 생각이라면 StringBuilder 클래스를 이용해보자.

-> String에 관해서는 String pool으 따로 공부해보자.

toString()

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 +
                '}';
    }
}
  • toString()를 구현하지 않고 객체를 System.out.println()으로 출력하면 객체의 주소값(=리모콘)이 찍힌다.
  • toString()은 Object 클래스에 존재한다. 따라서 구현을 해줘야한다.

equals()

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 페라리();
  • 큰 컵에서 작은컵으로 옮김 때는 안전보장X(수동 형변환 필요)
    • 청둥오리 청둥오리 = (청둥오리)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, 사과 별로 저장소 클래스가 따로 있었는데 제네릭을 이용해서 하나의 클래스 파일로 줄였다.

  • 이후에 자바 내용에서 제네릭이 사용되는곳은 HashMap<>, List<> 등이 있다.

0개의 댓글