HAZEL

[ CH04. 자바의 유용한 클래스들 ] Object 클래스, java.lang 패키지, clone() , toString() ,Class 클래스, Stirng, StringBuilder, StringBuffer 본문

PROGRAMMING/Java

[ CH04. 자바의 유용한 클래스들 ] Object 클래스, java.lang 패키지, clone() , toString() ,Class 클래스, Stirng, StringBuilder, StringBuffer

Rmsid01 2021. 5. 11. 13:27

 

CH04. 자바의 유용한 클래스들 

: 패스트 캠퍼스 강의를 공부하고 정리한 내용입니다.

 

 

01. Object 클래스 - 모든 클래스의 최상위 클래스

1. java.lang 패키지

: 프래그래밍 시  import 하지 않아도 자동으로 import 됨. 

: import.java.lang.*;  ( 랭 _ 이라고 읽는다 ) 

: 많이 사용하는 기본 클래스들이 속한 패키지 ex, String , Interger, System .. 

 

2. 모든 클래스는 Objec 클래스를 상속 받음 - 모든 클래스의 최상위 클래스 

: 모든 클래스는 final 로 선언되어있지 않은 메서드는 재정의해서 사용할 수 있다.

 

- toString() 메서드

: 객체의 정보를 String 으로 바꾸어 사용할 때 쓰임 

: String 이나, Integer 클래스는 이미 재정의 되어있음 

 

class Book {

    private String title;
    private String author;

    public Book(String title, String author){
        this.title = title;
        this.author = author;
    }
}


public class BookTest {

    public static void main(String[] args) {
        Book book = new Book("데미안", "헤르만헤세");

        System.out.println(book);   // ch01.Book@1540e19d

        String str = new String("test");
        System.out.println(str);   // test   - 이미 String 에는 toString 되어있어서, 주소값이 아니라 string 값이 나옴 
        System.out.println(str.toString());   // test

    }
}

 

System.out.println(book); // ch01.Book@1540e19d 

 

이 부분도 주소의 값이 아니라 String 으로 나오게 하려면, toString() 으로 오버라이딩 해줘야한다. 

class Book {

    private String title;
    private String author;

    public Book(String title, String author){
        this.title = title;
        this.author = author;
    }

    @Override
    public String toString() {
        return title + ',' + author ;
    }
}

 

 

02. Object 클래스의 메서드 활용

1. equals() 메서드

:  두 인스턴스가 같다는 것을 확인하기 위해서 사용하는 메서드 - 두 인스턴스의 주소 값을 비교해여 , true / false 로 반환 

: 재 정의해서 두 인스턴스가 논리적으로 동일하다는 것을 확인 할 수 있음 

: 인스턴스가 다르더라도 논리적으로 동일하면 , True 를 반환하도록 재정의할 수있다.  ex, 같은 학번, 같은 사번

 

2. hashCode() 메서드 

:  hashCode() 는 인스턴스의 저장 주소를 반환함.

: 힙 메모리에 인스턴스가 저장되는 방식이 hash 방식

: hash : 정보를 저장, 검색하는 자료구조

: 자료의 특정 값(키 값)에 대한 저장 위치를 반환해주는 해시 함수를 사용

 

** equals() 를 오버라이딩하면,  hashCode() 도 오버라이딩, 

 

package ch02;

public class Student {

    private int studentId;
    private String studentName;

    public Student(int studentId, String studentName) {
        this.studentId = studentId;
        this.studentName = studentName;
    }

    public String toString(){
        return studentName + "," + studentName;
    }
}


public class EqualTest {

    public static void main(String[] args) {
        Student std1 = new Student(100, "LEE");

        Student std2 = new Student(100, "LEE");

        Student std3 = std1;  // 단순히 주소값만 복사해주는 것

        System.out.println(std1 == std2);  // false
        System.out.println(std1.equals(std2));  // false - equals 의 원래 정의 : 두개의 주소값이 같냐
        System.out.println(std1 == std3);   // true
        
        System.out.println(std1.hashCode());  // 356573597  
        System.out.println(std2.hashCode());  // 1735600054 
    }
}

 

System.out.println(std1 == std2);  의 결과가 false 가 나온 것을 확인 할 수 있다.

 

하지만, 논리적으로 학생 id 가 같다면, True 로 나오게 하고싶다면, overriding 을 해준다.

  @Override
  public boolean equals(Object obj) {

  if (obj instanceof Student){
  Student std = (Student) obj; // 다운 캐스팅
  if ( this.studentId  == std.studentId )
  return true;
  else return false;
  }
  return false;
  }
  @Override
  public int hashCode() {
  return studentId;
  }
  
  
  
  public class EqualTest {

    public static void main(String[] args) {
        Student std1 = new Student(100, "LEE");
        Student std2 = new Student(100, "LEE");

        System.out.println(std1.hashCode());  // 356573597  -> 100
        System.out.println(std2.hashCode());  // 1735600054 -> 100

        System.out.println(System.identityHashCode(std1)); // 진짜 해쉬 코드 반환
        System.out.println(System.identityHashCode(std2));
    }
}

 

3. clone() 메서드 

: 객체의 원본을 복제하는데 사용하는 메서드로, 생성과정의 복잡한 과정을 바복하지 않고 복제할 수 있다.

: clone() 메서드를 사용하면 객체의 정보( 멤버 변수 값 등 ) 가 동일한 또다른 인스턴스가 생성되는 것이므로, 객체 지향 프로그램에서의 정보은닉, 객체 보호의 관점에서 위배될수 있다. 

: 해당 클래스의 clone() 메서드의 사용을 허용한다는 의미로 cloneabel 인터페이스를 반드시 선언할 것 !  - implements Cloneable { } 

 

public class Student implements Cloneable{

   ...
   @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class EqualTest {
	public static void main(String[] args) throws CloneNotSupportedException{
   
      Student copyStudent = (Student)std1.clone();  // 생성이 아니라 클래스를 그대로 복제할 때 사용 함
      System.out.println(copyStudent);

    }
}

 

03. Stirng, StringBuilder, StringBuffer 클래스, text block

1. Stirng 클래스

1. String 선언하기 < 2가지가 존재함 >

- new 를 해서 사용하는 방법 ( 힙에 메모리가 생성 ) , 직접 assign(=) 해서 쓰는 방법 ( 상수풀에 있는  address 만 가리킴 )

- 힙 메모리는 생성될때마다 다른 주소 값을 가지지만, 상수 풀의 문자열은 모두 같은 주소 값을 가짐 

public class StringTest {

    public static void main(String[] args) {
        String str1 = new String("abc");
        String str2 = new String("abc");

        System.out.println(str1 == str2); // false

        String str3 = "abc";
        String str4 = "abc";

        System.out.println(str3 == str4); // true
    }
}

 

-  한번 생성된 String 은 불변이다. 안을 뜯어보면, final 로 선언되어있음을 확인할 수 있다. 

- String을 연결하면 ( str.concat( str2) )  기존의 String 에 연결되는 것이 아닌 새로운  문자열이 생성됨 

-> 메모리 에러가 발생할 수도 있다. 그래서 별로 추천하는 방법은 아니라고 한다! 이것을 해결하기 위해서 아래의 내용을 사용한다. 

 

public class StringTest2 {

    public static void main(String[] args) {
        String  str1 = new String("java");
        String str2 = new String("android");
        System.out.println(System.identityHashCode(str1));  // 356573597

        str1 = str1.concat(str2);

        System.out.println(str1); // javaandroid
        System.out.println(System.identityHashCode(str1)); // 1735600054
    }
}

 

2. StringBuilder , StringBuffer 사용

: String 은 불변하지만, 이 아이들은 내부적으로 가변적인 char[] 를 멤버 변수로 가지고 있다.  - final 로 선언되어있지 않다. 

: 문자열을 여러번 연결하거나, 변경할때 사용하면 유용하며, 새로운 인스턴스를 생성하지 않고 char[] 를 변경함 

: StringBuffer 은 멀티 쓰레드 프로그래밍에서 동기화를 보장해준다. - 두개이상의 쓰레드가 같은 메모리에 접근할 때 순서를 정해준다.

   - 락을 걸어줄 수 있다. ( 보호를 해줌 ) 

: StringBuilder 는 단일 쓰레드 프로그램에서 사용을 권장한다.  

: 사용할때는 toString 으로 변환해주면 된다. 

public class StringBuilderTest {

    public static void main(String[] args) {
        String str1 = new String("java");
        String str2 = new String("android");

        StringBuilder buffer = new StringBuilder(str1);
        System.out.println(System.identityHashCode(buffer)); // 356573597  - 속도가 빠름
        buffer.append(str2); // 복잡한 애들도 append로 넣을 수 있다.
        System.out.println(buffer); // javaandroid
        System.out.println(buffer.getClass().getName());  // 타입 확인 : java.lang.StringBuilder
        System.out.println(System.identityHashCode(buffer)); // 356573597

        String test = buffer.toString(); // 결론적으로는 스트링으로 받아야함 . 사용할때는 toString 으로 변환해주면 된다.
        System.out.println(test);
        System.out.println(test.getClass().getName()); // 타입 확인 : java.lang.String
    }
}

 

 

3. text block 사용 - java 13 이후 사용

: 문자열을 """ """ 사이에 이어서 만들수 있음

: html, json 문자열을 만드는데 유용하게 사용할 수 있음 

public class StringTextBlock {

    public static void main(String[] args) {

        String strBlock = """
                This
                is
                text
                block
                text.""";
        System.out.println(strBlock);

        System.out.println(getBlockOfHtml());
    }
    
    public static String getBlockOfHtml(){
        return """
            <html>
                <body>
                    <span> example text </span>
                </body>
            </html>""";
    } 
}

 

 

04. Class 클래스

1. Class 클래스

: 자바의 모든 클래스와 인터페이스는 컴파일 후 class 파일이 생성됨

: class 클래스는 컴파일 된 class 파일을 로드하여 객체를 동적로드하고, 정보를 가져오는 메서드가 제공됨

: class.forName('클래스 이름') 메서드로 클래스를 동적으로 로드함

Class c = Class.forName("java.lang.String");

 

- 클래스 이름으로 직접 Class 클래스 가져오기

Class c = String.class;

 

- 생성된 인스턴스에서 Class 클래스 가져오기

String s = new String();

Class c = s.getClass(); // Object 메서드

 

2. 동적로딩

: 컴파일시에 데이터 타입이 binding 되지 않고, 실행 중에 데이터 타입을 binding 하는 방법

: 프로그래밍 시에는 문자열 변수로 처리하고, 런타임시에 원하는 클래스를 로딩하여 binding 할 수 있다는 장점이 있다.

  ( 속도는 조금 느릴 수 있다.  ) 

 -> 하지만, 컴파일 시에 타입이 정해지지 않으므로 동적 로딩시 오류가 발생하면 장애가 발생할 수 있다.

 ( 스펠링이 틀리거나, local 에 class 가 없다면, ) 

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class StringTestf {
    public static void main(String[] args) throws ClassNotFoundException{
        Class c = Class.forName("java.lang.String");

        Constructor[] cons = c.getConstructors();

        for(Constructor co : cons){
            System.out.println(co);
        }

        // 메서드 출력
        Method[] m = c.getMethods();
        for (Method mth : m ){
            System.out.println(mth);
        }

        // 위에처럼 하는 이유는, 로컬에 이러한 오브젝트가 없을때, 인보케이션? 을 사용하기 위해 이용

        String str = new String("test");
    }
}

 

3. Class 의 newinstance()메서드로 인스턴스 생성

: new 키워드를 사용하지 않고 클래스 정보를 활용하여 인스턴스 생성할 수 있음.

 

4. 클래스 정보 

: reflection 프로그래밍 : Class 클래스를 사용하여 클래스의 정보(생성자, 변수, 메서드)등을 알 수 있고 인스턴스를 생성하고, 메서드를 호출하는 방식의 프로그래밍이다. 

: 로컬 메모리에 객체 없는 경우, 원격 프로그래밍, 객체의 타입을 알 수 없는 경우에 사용 한다. 

: java.lang.reflect 패키지에 있는 클래스를 활용하여 프로그래밍 한다. 

:일반적으로 자료형을 알고 있는 경우엔 사용하지 않는다.