본문 바로가기

프로그래밍/JAVA

반응형

이번 글에서는 private 필드를 외부에서 직접 접근하지 않고,
gettersetter 메서드를 이용해
안전하게 값을 읽고 변경하는 방법을 학습합니다.
이 방식은 캡슐화(Encapsulation) 라고 하며, 객체 지향 프로그래밍의 핵심 원칙 중 하나입니다.


📦 클래스 코드 (Car.java)

package ch06.sec14;

public class Car {
	private int speed;
	private boolean stop;

	public int getSpeed() {
		return speed;
	}

	public void setSpeed(int speed) {
		if (speed < 0)
			this.speed = 0;
		else
			this.speed = speed;
	}

	public boolean isStop() {
		return stop;
	}

	public void setStop(boolean stop) {
		this.stop = stop;
		if (stop)
			this.speed = 0;
	}
}

📌 실행 코드 (CarExample.java)

package ch06.sec14;

public class CarExample {
	public static void main(String[] args) {
		Car car = new Car();
		
		car.setSpeed(-50);
		System.out.println("현재 속도 : " + car.getSpeed());
		
		car.setSpeed(60);
		System.out.println("현재 속도 : " + car.getSpeed());
		
		if (!car.isStop())
			car.setStop(true);
		System.out.println("현재 속도 : " + car.getSpeed());
	}
}

💬 코드 설명

  • private int speed;, private boolean stop;
    → 외부에서 직접 접근할 수 없는 비공개 필드
  • public int getSpeed()
    speed 값을 외부에서 읽을 수 있게 해주는 메서드
  • public void setSpeed(int speed)
    speed 값을 설정하는 메서드
    → 입력 값이 음수면 0으로 강제 조정 (유효성 검사)
  • public boolean isStop()
    stop 상태를 외부에서 읽을 수 있게 해주는 메서드
  • public void setStop(boolean stop)
    stop 상태를 설정하고, 멈추면 speed를 자동으로 0으로 만듦

💻 실행 결과

현재 속도 : 0
현재 속도 : 60
현재 속도 : 0

📌 간단 정리

메서드 역할
getSpeed() 현재 속도를 읽기
setSpeed(int) 속도를 설정 (0 이상만 허용)
isStop() 현재 멈춤 여부 확인
setStop(boolean) 멈춤 설정 (멈추면 속도 0)

💡 포인트 정리

  • private 필드는 객체 외부에서 직접 접근을 차단
  • getter 메서드로 값을 안전하게 읽을 수 있음
  • setter 메서드로 값을 제어하면서 유효성 검사(Validation) 가능
  • 캡슐화는 객체의 무결성을 유지하고, 버그를 예방하는 데 큰 도움이 됨
  • boolean 타입 getter는 is필드명() 형태로 작성하는 것이 관례
댓글
반응형

이번 글에서는 클래스 내부 필드와 메서드에 적용된
접근 제한자(public, default, private)
같은 패키지 또는 다른 패키지에서 접근할 때
어떤 영향을 미치는지 실습을 통해 확인합니다.


📦 클래스 코드 (A.java)

package ch06.sec13.exam03.package1;

public class A {
	public int field1;
	int field2;
	private int field3;

	public A() {
		field1 = 1;
		field2 = 1;
		field3 = 1;

		method1();
		method2();
		method3();
	}

	public void method1() {
	}

	void method2() {
	}

	private void method3() {
	}
}

📦 클래스 코드 (B.java)

package ch06.sec13.exam03.package1;

public class B {
	public void method() {
		A a = new A();

		a.field1 = 1; // (O) public
		a.field2 = 1; // (O) default - 같은 패키지라서 가능
		a.field3 = 1; // (X) private - 접근 불가

		a.method1();  // (O) public
		a.method2();  // (O) default - 같은 패키지라서 가능
		a.method3();  // (X) private - 접근 불가
	}
}

📦 클래스 코드 (C.java)

package ch06.sec13.exam03.package2;

import ch06.sec13.exam03.package1.A;

public class C {
	public C() {
		A a = new A();

		a.field1 = 1; // (O) public
		a.field2 = 1; // (X) default - 다른 패키지라서 접근 불가
		a.field3 = 1; // (X) private - 접근 불가

		a.method1();  // (O) public
		a.method2();  // (X) default - 다른 패키지라서 접근 불가
		a.method3();  // (X) private - 접근 불가
	}
}

💬 코드 설명

  • public
    → 어디서든 접근 가능 (같은 패키지 + 다른 패키지 모두)
  • default (아무 키워드 없음)
    같은 패키지 안에서는 접근 가능, 다른 패키지에서는 접근 불가
  • private
    클래스 내부에서만 접근 가능. 다른 클래스에서는 절대 접근 불가

📌 간단 정리

접근 제한자 같은 패키지 다른 패키지 같은 클래스 내부
public O O O
default (생략) O X O
private X X O

💻 실행 결과

  • B 클래스에서는 field1, field2, method1(), method2() 사용 가능
    → field3, method3() 사용 불가 (private 때문)
  • C 클래스에서는 field1, method1()만 사용 가능
    → field2, field3, method2(), method3() 모두 접근 불가

💡 포인트 정리

  • public은 모두에게 공개
  • default같은 패키지끼리만 공개
  • private자기 클래스 내부에서만 사용 가능
  • 다른 패키지에서 접근하려면 반드시 public이어야 함
  • private 필드는 외부에서 직접 수정하거나 읽을 수 없기 때문에 getter/setter를 통해 우회 접근함
댓글
반응형

이번 글에서는 여러 패키지에 동일한 이름을 가진 클래스를 사용할 때
import 구문을 활용해 클래스를 가져오는 방법과,
패키지 경로를 직접 명시하는 방법을 학습합니다.
패키지를 나누어 관리하면 코드가 깔끔해지고 충돌을 방지할 수 있습니다.


📌 클래스 코드 (Car.java)

package ch06.sec12.hyundai;

import ch06.sec12.hankook.SnowTire;
import ch06.sec12.kumho.AllSeasonTire;

public class Car {
	ch06.sec12.hankook.Tire t1 = new ch06.sec12.hankook.Tire();
	ch06.sec12.kumho.Tire t2 = new ch06.sec12.kumho.Tire();

	SnowTire t3 = new SnowTire();
	AllSeasonTire t4 = new AllSeasonTire();
}

💬 코드 설명

  • package ch06.sec12.hyundai;
    → Car 클래스가 hyundai 패키지에 속해 있다는 선언
  • import ch06.sec12.hankook.SnowTire;
    → SnowTire 클래스를 별도의 패키지에서 가져옴 (짧게 사용 가능)
  • import ch06.sec12.kumho.AllSeasonTire;
    → AllSeasonTire 클래스를 가져옴
  • ch06.sec12.hankook.Tire / ch06.sec12.kumho.Tire
    → 서로 다른 패키지에 동일한 이름(Tire)이 존재하므로 패키지명을 직접 명시하여 구분
  • SnowTire, AllSeasonTire
    → import 덕분에 패키지명 없이 클래스명만 사용 가능

📌 간단 정리

사용 방법 설명
import 패키지명.클래스명; 클래스를 가져와 짧게 사용
패키지명.클래스명 직접 지정 같은 이름이 여러 패키지에 있을 때 충돌 방지

💻 실행 흐름 요약

  • Tire는 직접 패키지명을 써야 한다 (충돌 방지용)
  • SnowTire, AllSeasonTire는 import로 짧게 사용 가능
  • 모든 객체가 정상적으로 생성되며 패키지 구성이 깔끔하게 관리됨

💡 포인트 정리

  • 패키지를 나누어 관리하면 클래스 이름 충돌을 방지할 수 있음
  • 서로 다른 패키지에 같은 이름의 클래스가 있을 경우, 패키지명까지 명시해야 구분 가능
  • import 구문을 활용하면 패키지명을 생략하고 클래스명만 사용할 수 있음
  • 패키지 구조를 잘 설계하면 대규모 프로젝트에서도 유지보수가 쉬워짐
댓글
반응형

이번 글에서는 클래스 내부에 변하지 않는 고정값을 선언할 때 사용하는
static final 조합, 즉 상수(Constant)를 정의하는 방법을 학습합니다.
상수는 프로그램 전체에서 같은 값을 공유하고, 변경되지 않도록 보장할 수 있습니다.


📦 클래스 코드 (Earth.java)

package ch06.sec11.exam02;

public class Earth {
	static final double EARTH_RADIUS = 6400;
	static final double EARTH_SURFACE_AREA = 4 * Math.PI * EARTH_RADIUS * EARTH_RADIUS;
}

📌 실행 코드 (EarthExample.java)

package ch06.sec11.exam02;

public class EarthExample {
	public static void main(String[] args) {
		System.out.println("지구의 반지름 : " + Earth.EARTH_RADIUS + "km");
		System.out.println("지구의 표면적 : " + Earth.EARTH_SURFACE_AREA + "km^2");
	}
}

💬 코드 설명

  • static final double EARTH_RADIUS = 6400;
    → 지구 반지름 상수, 프로그램 어디서나 동일하게 사용
  • static final double EARTH_SURFACE_AREA = 4 * Math.PI * EARTH_RADIUS * EARTH_RADIUS;
    → 구의 표면적 공식(4πr²)을 이용해 계산한 값
    → 반지름을 이용해 다른 상수도 정의 가능
  • Earth.EARTH_RADIUS, Earth.EARTH_SURFACE_AREA
    클래스 이름으로 직접 접근 (객체 생성 없이 사용)

💻 실행 결과

지구의 반지름 : 6400.0km
지구의 표면적 : 514718540.2467583km^2

📌 간단 정리

선언 형태 의미
static 클래스에 소속, 객체 없이 사용 가능
final 한 번 초기화되면 변경 불가
static final 변하지 않는 고정값(상수)을 클래스에 소속시킴

💡 포인트 정리

  • static final은 상수를 정의할 때 사용
  • 상수 이름은 관례적으로 모두 대문자로 작성 (ex. EARTH_RADIUS)
  • 프로그램 어디서든 일관된 값을 사용할 수 있음
  • 수식에 상수를 활용하면 코드 가독성유지보수성이 높아짐
  • 상수는 변경될 가능성이 없는 공통 데이터(물리 상수, 시스템 설정) 등을 정의할 때 사용
댓글
반응형

이번 강의에서는 자바 클래스와 필드, 메서드 등에 적용할 수 있는
접근 제한자(access modifier)에 대해 학습합니다.
접근 제한자는 코드의 보안성과 설계 구조를 명확하게 만들기 위해 사용되며,
패키지 또는 객체 간 접근을 제어합니다.


📦 클래스 코드 (Korean.java)

package ch06.sec11.exam01;

public class Korean {
	final String nation = "대한민국";
	final String ssn;
	String name;

	public Korean(String ssn, String name) {
		this.ssn = ssn;
		this.name = name;
	}
}

📌 실행 코드 (KoreanExample.java)

package ch06.sec11.exam01;

public class KoreanExample {
	public static void main(String[] args) {
		Korean k1 = new Korean("123456-1234567", "자바킴");

		System.out.println(k1.nation);
		System.out.println(k1.ssn);
		System.out.println(k1.name);

		k1.name = "김자바";
	}
}

💬 코드 설명

  • final String nation = "대한민국";
    → 선언과 동시에 초기화한 필드 → 절대 변경 불가
  • final String ssn;
    → 생성자에서만 초기화할 수 있음 → 이후 변경 불가
  • String name;
    → 일반 필드 → 자유롭게 읽고 쓸 수 있음
  • 생성자 Korean(String ssn, String name)
    → 객체 생성 시 주민등록번호와 이름을 초기화
  • k1.name = "김자바";
    → name 필드는 수정 가능 (final이 아님)

💻 실행 결과

대한민국
123456-1234567
자바킴

※ name을 "김자바"로 변경했지만 출력은 안 했기 때문에 변경 내용은 확인되지 않음.


📌 간단 정리

필드명 final 여부 설명
nation O "대한민국" 고정, 변경 불가
ssn O 생성자에서만 초기화 가능, 이후 변경 불가
name X 자유롭게 변경 가능

💡 포인트 정리

  • final 필드는 한 번만 초기화 가능하며 이후 수정 불가
  • 선언과 동시에 초기화하거나, 생성자에서 초기화해야 함
  • 개인 식별정보(ssn 등)처럼 절대 변하지 않아야 하는 값에 final을 적용
  • 일반 필드는 자유롭게 읽고 쓸 수 있지만, 설계에 따라 final 적용 여부를 결정
댓글
반응형

이번 글에서는 static 메서드 안에서
인스턴스 멤버(필드, 메서드)를 직접 사용하려면 객체를 생성해야 한다는 규칙을 학습합니다.
static은 클래스에 소속되고, 인스턴스 멤버는 객체에 소속되기 때문에 이 둘은 구분해서 사용해야 합니다.


📌 실행 코드 (Car.java)

package ch06.sec10.exam03;

public class Car {
	int speed;

	void run() {
		System.out.println(speed + "으로 달립니다.");
	}

	static void simulate() {
		Car car = new Car();
		car.speed = 200;
		car.run();
	}

	public static void main(String[] args) {
		simulate();

		Car car = new Car();
		car.speed = 60;
		car.run();
	}
}

💬 코드 설명

  • int speed
    → 자동차 속도를 저장하는 인스턴스 필드
  • void run()
    → 현재 속도로 달리는 메시지 출력 (인스턴스 메서드)
  • static void simulate()
    → static 메서드이기 때문에 직접 speed나 run()을 호출할 수 없음 → 대신 new Car()로 객체를 생성한 뒤 인스턴스 필드와 메서드를 사용
  • main()
    → 프로그램 시작점
    → simulate() 호출 후, 별도로 또 다른 Car 객체를 생성해서 동작

💻 실행 결과

200으로 달립니다.
60으로 달립니다.

📌 간단 정리

구분 설명
simulate() 객체를 직접 생성하여 인스턴스 멤버 사용
main() static 메서드. simulate() 호출 후, 별도 Car 객체 생성

💡 포인트 정리

  • static 메서드에서는 인스턴스 필드나 메서드를 직접 사용할 수 없다
  • 사용하려면 객체를 생성해야 한다 (new 클래스명())
  • static 메서드는 프로그램 시작이나 공통 기능 수행에 적합
  • 객체별로 독립적인 상태(speed)를 가질 수 있음
댓글
반응형

이번 글에서는 클래스에 소속되어 객체 생성 없이 사용할 수 있는
static(정적) 필드static 메서드를 학습합니다.
공통적으로 사용하는 데이터나 기능은 static으로 선언하여 메모리 효율을 높일 수 있습니다.


📦 클래스 코드 (Calculator.java)

package ch06.sec10.exam01;

public class Calculator {
	static double pi = 3.14159;

	static int plus(int x, int y) {
		return x + y;
	}

	static int minus(int x, int y) {
		return x - y;
	}
}

📌 실행 코드 (CalculatorExample.java)

package ch06.sec10.exam01;

public class CalculatorExample {
	public static void main(String[] args) {
		double re1 = 10 * 10 * Calculator.pi;
		int re2 = Calculator.plus(10, 5);
		int re3 = Calculator.minus(10, 5);

		System.out.println("result1 : " + re1);
		System.out.println("result2 : " + re2);
		System.out.println("result3 : " + re3);
	}
}

💬 코드 설명

  • static double pi
    → 원의 넓이 계산 등에 사용할 공통 상수 값
  • static int plus(int x, int y)
    → 두 수의 합을 반환하는 정적 메서드
  • static int minus(int x, int y)
    → 두 수의 차를 반환하는 정적 메서드
  • 모든 static 멤버는 클래스 이름으로 바로 접근 가능
    (Calculator.pi, Calculator.plus(), Calculator.minus())

💻 실행 결과

result1 : 314.159
result2 : 15
result3 : 5

📌 간단 정리

static 멤버 설명
pi 원주율 상수값 (3.14159)
plus(x, y) 두 수의 합계 반환
minus(x, y) 두 수의 차이 반환

💡 포인트 정리

  • static 키워드를 붙이면 객체 생성 없이 클래스 이름으로 직접 사용 가능
  • static 필드는 모든 객체가 공유하는 하나의 값
  • static 메서드는 객체 상태와 무관한 기능을 제공할 때 사용
  • 예를 들어 수학 계산, 공용 설정값 등은 static으로 처리하는 경우가 많음
  • 클래스명.필드명 / 클래스명.메서드명() 형태로 접근
댓글
반응형

이번 글에서는 객체 내부 메서드에서 this 키워드를 이용해 필드를 가리키고,
메서드 간 호출을 통해 객체 동작을 연결하는 방법을 학습합니다.
또한 생성자를 통해 필드를 초기화하고, 이를 동작에 반영하는 구조를 실습합니다.


📦 클래스 코드 (Car.java)

package ch06.sec09;

public class Car {
	String model;
	int speed;

	Car(String model) {
		this.model = model;
	}

	void setSpeed(int speed) {
		this.speed = speed;
	}

	void run() {
		this.setSpeed(100);
		System.out.println(this.model + "가 달립니다. (시속 : " + speed + "km/h)");
	}
}

📌 실행 코드 (CarExample.java)

package ch06.sec09;

public class CarExample {
	public static void main(String[] args) {
		Car car = new Car("포르쉐");
		Car car2 = new Car("벤츠");

		car.run();
		car2.run();
	}
}

💬 코드 설명

  • Car(String model)
    → 생성자를 통해 자동차 모델명을 필드에 저장
  • setSpeed(int speed)
    → 자동차의 현재 속도를 설정하는 메서드
  • run()
    → setSpeed(100)을 호출해 시속 100km/h로 설정한 뒤, 모델명과 속도를 출력
    → this를 명시적으로 사용하여 현재 객체의 메서드나 필드에 접근
  • car.run(), car2.run()
    → 각각 다른 객체가 독립적으로 동작

💻 실행 결과

포르쉐가 달립니다. (시속 : 100km/h)
벤츠가 달립니다. (시속 : 100km/h)

📌 간단 정리

메서드 역할
Car(String model) 모델명 초기화
setSpeed(int) 속도 설정
run() 속도 설정 후 주행 메시지 출력

💡 포인트 정리

  • this는 현재 객체 자신의 필드나 메서드를 가리킨다
  • this.필드명, this.메서드() 형태로 명시적으로 호출 가능
  • 생성자를 통해 필드를 초기화하고, 초기화된 값을 객체 동작에 반영
  • 여러 객체(car, car2)가 서로 독립적으로 동작함 → 객체지향의 기본
댓글