자바(Java) 개념 정리-접근 제어자, 캡슐화, this, String 최적화

My Pale Blue Dot·2025년 3월 5일
0

JAVA

목록 보기
13/35
post-thumbnail

📆 날짜: 2025-03-05


1. 접근 한정자 (Access Modifier)

자바에서는 클래스, 변수, 메서드의 접근 권한을 제한하여 보안성을 높이고 코드의 유지보수를 쉽게 할 수 있다.

🔹 접근 한정자의 종류

접근 제어자설명접근 가능 범위
public모든 클래스에서 접근 가능어디서든 접근 가능
private해당 클래스 내에서만 접근 가능외부 접근 불가능 (정보 은닉)
protected같은 패키지 + 상속 관계의 클래스에서 접근 가능패키지 내부 또는 상속 관계에서만 접근 가능
(default)아무 키워드도 작성하지 않으면 기본 적용같은 패키지 내에서만 접근 가능

접근 한정자 예제

class Person {
    private String name;  // private 멤버 변수 (직접 접근 불가능)
    protected int age;    // protected 멤버 변수
    public String address;  // public 멤버 변수

    // 생성자
    public Person(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    // private 변수 접근을 위한 getter 메서드
    public String getName() {
        return this.name;
    }
}

📌 핵심 정리

  • private 변수는 외부에서 직접 접근할 수 없음 → getter/setter 사용
  • protected 변수는 같은 패키지 또는 상속 관계에서만 접근 가능
  • public 변수는 어디서든 자유롭게 접근 가능

2. 캡슐화 (Encapsulation)

캡슐화란?

  • 데이터(변수)와 기능(메서드)을 하나로 묶고, 데이터를 외부에서 직접 접근하지 못하도록 제한하는 개념
  • 정보 은닉을 통해 불필요한 접근을 막고, 객체의 무결성을 유지할 수 있음

캡슐화 예제

class Engine {
    private void 흡입() { System.out.println("공기 흡입"); }
    private void 압축() { System.out.println("공기 압축"); }
    private void 폭발() { System.out.println("연료 폭발!"); }
    private void 배기() { System.out.println("배기 가스 배출"); }

    public void startEngine() {
        흡입();
        압축();
        폭발();
        배기();
    }
}

class Car {
    private Engine engine;  // 엔진을 캡슐화하여 외부에서 직접 접근 불가능

    public Car() {
        engine = new Engine();
    }

    public void run() {
        engine.startEngine();  // 자동차를 작동시키면 내부적으로 엔진이 작동됨
    }
}

public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        car.run();
    }
}

📌 핵심 정리

캡슐화를 통해 내부 동작을 숨김 → 유지보수성 증가
✔ 외부에서는 Carrun() 메서드만 호출하면 내부적으로 Engine이 동작
✔ 내부 동작이 변경되더라도 외부 코드에는 영향을 주지 않음


3. this 키워드

this란?

this현재 객체의 참조를 의미하는 키워드로, 다음과 같은 용도로 사용됨.

🔹 this의 주요 기능

1️⃣ 멤버 변수와 지역 변수 구별

class Person {
    private String name;

    public Person(String name) {
        this.name = name;  // 멤버 변수와 지역 변수 구별
    }
}

2️⃣ 다른 생성자 호출 (this(...))

class Example {
    int x, y;

    Example() {
        this(0, 0);  // 다른 생성자 호출
    }

    Example(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

3️⃣ 현재 객체 반환 (return this)

class Example {
    Example getThis() {
        return this;
    }
}

4. String 객체와 문자열 연결

🔹 concat() 메서드

  • concat() 메서드는 두 개의 문자열을 이어붙일 때 사용
  • 하지만 String불변 객체(Immutable) 이므로 concat()을 사용할 때마다 새로운 객체가 생성됨메모리 비효율적

concat() 예제

String str1 = "Java";
String str2 = " Programming";
String str3 = str1.concat(str2);  // 새로운 문자열 생성됨

System.out.println(str3);  // Java Programming

🔹 String vs StringBuilder vs StringBuffer

타입특징사용 추천
String불변(Immutable), 메모리 낭비변경이 적을 때
StringBuilder가변(Mutable), 빠름단일 스레드 환경
StringBuffer가변(Mutable), 동기화 지원멀티스레드 환경

반복문에서 concat() vs StringBuilder.append()

String str = "";
for (int i = 0; i < 10; i++) {
    str = str.concat(String.valueOf(i));  // 매 반복마다 새로운 객체 생성됨 ❌
}
System.out.println(str);

✔ 위 코드는 concat()을 반복 사용하여 메모리 낭비 발생

StringBuilder sb = new StringBuilder("");
for (int i = 0; i < 10; i++) {
    sb.append(i);  // 같은 객체에서 문자열 수정 (메모리 효율적) ✅
}
System.out.println(sb);

StringBuilder.append()를 사용하면 객체를 새로 생성하지 않고 기존 객체를 수정함 → 성능 최적화 🚀


🔹 String+ 연산자와 concat() 비교

String str1 = "Hello";
String str2 = " World";

String result1 = str1 + str2;  // 내부적으로 StringBuilder 사용 (최적화)
String result2 = str1.concat(str2);  // 새로운 String 객체 생성

System.out.println(result1);  // Hello World
System.out.println(result2);  // Hello World

+ 연산자는 내부적으로 컴파일러가 StringBuilder로 변환하여 최적화
concat()새로운 객체를 생성하므로 메모리 낭비 발생


5. StringBuilderStringBuffer

문자열 연결 방식 비교

타입특징사용 추천
String불변(Immutable), 메모리 낭비변경이 적을 때
StringBuilder가변(Mutable), 빠름단일 스레드 환경
StringBuffer가변(Mutable), 동기화 지원멀티스레드 환경

메모리 효율적인 문자열 연결

StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");  // 기존 객체에서 문자열 수정 (메모리 절약)
System.out.println(sb);  // Hello World

StringBuilder를 사용하면 새로운 객체를 생성하지 않고 문자열을 수정할 수 있음
반복문에서 += 대신 StringBuilder.append() 사용!


🔹 String을 사용한 문자열 덧붙이기 (비효율적)

int i = 0;
String str = "";
while (i < 10) {
    str += i;
    System.out.print("str : " + str + " ");
    System.out.printf("위치 : %X\n", System.identityHashCode(str));
    i++;
}

+= 연산을 사용할 때마다 새로운 String 객체가 생성됨
반복문을 돌릴수록 메모리 낭비 발생


🔹 StringBuilder를 사용한 문자열 덧붙이기 (메모리 절약)

int i = 0;
StringBuilder str = new StringBuilder("");
while (i < 10) {
    str.append(i);  // += 대신 append() 사용
    System.out.print("str : " + str + " ");
    System.out.printf("위치 : %X\n", System.identityHashCode(str));
    i++;
}

메모리 주소가 동일함! (System.identityHashCode() 결과 같음)
append() 사용 시 기존 객체를 수정하므로 메모리 낭비 없음
훨씬 빠르고 효율적


🔹 실행 결과 예상

str : 0 위치 : 3FCD7E
str : 01 위치 : 3FCD7E
str : 012 위치 : 3FCD7E
str : 0123 위치 : 3FCD7E
str : 01234 위치 : 3FCD7E
str : 012345 위치 : 3FCD7E
str : 0123456 위치 : 3FCD7E
str : 01234567 위치 : 3FCD7E
str : 012345678 위치 : 3FCD7E
str : 0123456789 위치 : 3FCD7E

StringBuilder를 사용하면 주소값이 변하지 않음!


📌 최종 결론

  1. concat()String을 연결할 때 사용 가능하지만, 새로운 객체를 생성하기 때문에 비효율적
  2. 문자열을 반복해서 연결해야 한다면 StringBuilder.append()를 사용하는 것이 좋음!
  3. 반복문에서 += 연산자를 남발하면 메모리 낭비가 심하므로 StringBuilder를 활용할 것

📝 총정리

접근 한정자 (private, public, protected)로 정보 보호
캡슐화 (private 변수 + public 메서드)로 내부 동작 숨기기
this객체 참조 및 생성자 재사용
문자열 비교는 .equals() 사용 (==은 주소 비교)
문자열 연결은 StringBuilder가 더 효율적! (concat()은 메모리 낭비)


profile
Here, My Pale Blue.🌏

0개의 댓글