불변성 (Immutable) : String 객체는 한 번 생성되면 그 내용을 변경할 수 없음. 공간이 변하는게 아닌 다른 공간에 새로운 것이 생김.
비동기화 : String은 동기화를 제공하지 않음. 따라서 멀티 스레드 환경에서는 안전하지 않으나, 단일 스레드 환경에서 사용하기 적합함.
String str = "Hello";
String str2 = "Hello";
서로 다름
String str3 = new String("Hello");
String str = "Hello"; // 1234
str2 = str + "world";
가변성 (Mutable) : StringBuilder는 문자열을 변경할 수 있다.
즉, 문자열 연산 시 새로운 객체를 생성하지 않고, 기존 객체의 내용을 변경한다.
비동기화 : StringBuilder는 동기화를 제공하지 않음. 마찬가지로 멀티보다 단일스레드 환경에서 적합.
가변성 (Mutable) : StringBuffer는 문자열을 변경할 수 있다.
즉, 문자열 연산 시 새로운 객체를 생성하지 않고, 기존 객체의 내용을 변경한다.
동기화 (Thread-Safe) : StringBuffer는 모든 메서드가 synchronized 키워드를 사용하여 동기화 되어 있다. 따라서 멀티스레드 환경에서 안전하지만, 동기화로 인한 성능 저하가 발생할 수 있다.
결론적으로 중요한 사실은, StringBuffer와 StringBuilder 는 가변성을 띄기 때문에 기존
문자열에 추가적인 연산이 일어나도 새로운 객체를 생성하지 않고, 기존 객체의 내용을 변
경한다는 점이다.

오버헤드(Overhead)란?
어떤 작업을 수행하는 데 있어서
직접적인 결과를 얻기 위해 필요한 추가적인 시간, 메모리, 또는 자원을 의미.
Input : 입력, 외부에서 내부로 값이 들어오는 것. Scanner
Output : 출력, 내부에서 외부로 값이 나가는 것. Println
Stream : 외부와 내부를 이어주는 통로

File file = new File("파일 경로");
File file = new File("C:/dev/test.txt");




바이트 기반 스트림은 1Byte만 가능


객체 생성
- FileInputStream객체가 생성될 때 파일과 직접 연결 됨
- 만약 파일이 존재하지 않으면 FileNotFoundException이 발생하므로 예외처리 필수
FileInputStream fis = new FileInputStream("C:/dev/test.txt");

객체생성
- FileOutputStream객체가 생성될 때 파일과 직접 연결 됨
- 만약 파일이 존재하지 않으면 자동으로 생성하지만
이미 파일이 존재하는 경우 파일을 덮어쓰는 단점이 있음FileOutputStream fos = new FileOutputStream("C:/data/test.txt");만일 기존 파일에 이어서 계속 작성하고 싶다면 아래 예제처럼 객체 생성 시 가능
FileOutputStream fos = new FileOutputStream("C:/data/test.txt", true);

객체생성
- FileReader객체가 생성될 때 파일과 직접 연결 됨
- 만약 파일이 존재하지 않으면 FileNotFoundException이 발생하므로 예외처리 필수
FileReader fr = new FileReader("C:/dev/test.txt"); FileReader fr = new FileReader(new File("C:/dev/test.txt"));

객체생성
- FileWriter객체가 생성될 때 파일과 직접 연결 됨
- 만약 파일이 존재하지 않으면 자동으로 생성하지만
이미 파일이 존재하는 경우 파일을 덮어쓰는 단점이 있음FileWriter fw = new FileWriter("C:/data/test.txt");만일 기존 파일에 이어서 계속 작성하고 싶다면 아래 예제처럼 객체 생성 시 가능
FileWriter fw = new FileWriter("C:/data/test.txt", true);

FileInputStream fis = new FileInputStream("sample.txt"); //기반 스트림 생성
BufferedInputStream bis = new BufferedInputStream(fis); //보조스트림 생성
bis.read(); //보조스트림으로부터 데이터 읽어옴



Serializable 인터페이스를 implements하여 구현
객체 직렬화 시 private 필드를 포함한 모든 필드를 바이트로 변환하지만
transient키워드를 사용한 필드는 직렬화에서 제외
직렬화된 객체를 역직렬화할 때는 직렬화 했을 때와 같은 클래스 사용
단, 클래스 이름이 같더라도 클래스 내용이 변경된 경우 역직렬화 실패
직렬화한 클래스와 같은 클래스임을 알려주는 식별자 역할로 컴파일 시 JVM이 자동으로
serialViersionUID 정적 필드를 추가해줘 별도로 작성하지 않아도 오류는 나지 않지만
자동 생성 시 역직렬화에서 예상하지 못한 InvalidClassException을 유발할 수 있음
private static final long serialVersionUID = -6423919775137290062L;
