자바 개발자 일기 9일차 (getter, setter, 접근제한자, super)

Shy·2024년 1월 11일

아이티윌

목록 보기
9/22

자바빈(JavaBean)

자바빈(JavaBean)은 자바에서 사용되는 컴포넌트 모델이며, 재사용 가능한 소프트웨어 컴포넌트를 만들기 위한 규약이다. 자바빈은 소프트웨어 개발에서 일반적으로 사용되는 객체를 쉽게 생성, 관리, 조작할 수 있게 해준다. 자바빈의 주요 특징은 다음과 같다.

  1. 캡슐화: 자바빈은 캡슐화 원칙을 따른다. 즉, 클래스의 필드(데이터)는 주로 private로 선언되고, 이 필드에 접근하기 위한 public 메소드(getter와 setter)를 제공한다.
  2. 기본 생성자: 자바빈은 매개변수가 없는 기본 생성자를 가져야 한다. 이로 인해 쉽게 인스턴스화될 수 있고, 다양한 도구와 프레임워크에서 활용될 수 있다.
  3. 직렬화 가능: 자바빈은 Serializable 인터페이스를 구현하는 것이 좋다. 이는 자바빈이 네트워크를 통해 전송되거나 파일에 저장될 수 있게 해준다.
  4. 접근자(Getter)와 설정자(Setter) 메소드: 속성에 접근하기 위해 getter 메소드를, 속성을 수정하기 위해 setter 메소드를 사용한다. 예를 들어, name이라는 필드가 있다면, getName()과 setName(String name) 같은 메소드를 제공한다.

자바빈 예시

public class Person implements Serializable {
    private String name;
    private int age;

    // 기본 생성자
    public Person() {
    }

    // getter
    public String getName() {
        return name;
    }

    // setter
    public void setName(String name) {
        this.name = name;
    }

    // getter
    public int getAge() {
        return age;
    }

    // setter
    public void setAge(int age) {
        this.age = age;
    }
}

이 예제에서 Person 클래스는 name과 age라는 두 개의 속성을 가지며, 각 속성에 대한 getter와 setter 메소드를 제공한다. 이렇게 간단하고 일관된 접근 방식 덕분에 자바빈은 많은 자바 프레임워크와 라이브러리에서 널리 사용된다.

getter, setter 생성

캡슐화

자바에서 캡슐화는 클래스의 데이터(필드)와 그 데이터를 다루는 메소드를 하나의 단위로 묶는 것을 의미한다. 이 개념의 핵심은 객체의 세부 구현 내용을 숨기고, 외부에서는 오직 정의된 인터페이스만을 통해 상호작용할 수 있게 하는 것이다.

캡슐화의 장점은 다음과 같다.

  1. 데이터 보호: 클래스 내부의 필드는 private 접근 제한자를 사용해 보호될 수 있으며, 이는 외부에서 직접 접근할 수 없게 한다. 대신 public 메소드(예: getter와 setter)를 통해 필드에 접근하게 함으로써 데이터를 보호할 수 있다.
  2. 유지보수성 증가: 클래스 내부 구현을 숨김으로써, 내부 구현을 변경해도 외부에 영향을 미치지 않는다. 이는 유지보수를 쉽게 해준다.
  3. 인터페이스와 구현의 분리: 사용자는 객체가 '무엇을 하는지'는 알지만, '어떻게 하는지'는 모른다. 이는 시스템의 복잡성을 줄이고, 사용하기 쉽게 만든다.

간단한 예를 들어보자. Car 클래스가 있고, 이 클래스에는 speed라는 private 필드가 있다고 하자. 이 필드에 접근하기 위해 getSpeed()setSpeed()라는 public 메소드를 제공할 수 있다. 이렇게 함으로써 speed 필드는 외부에서 직접 접근할 수 없게 되며, Car 클래스의 메소드를 통해서만 접근할 수 있다. 이는 캡슐화의 전형적인 예이다.

이처럼 캡슐화는 자바 프로그래밍에서 중요한 객체지향 원칙 중 하나이며, 프로그램의 안정성과 유지보수성을 향상시키는 데 기여한다.

접근 제한자

자바에서 접근 제한자(Access Modifiers)는 클래스, 메소드, 변수 등의 멤버에 대한 접근 범위를 제한하는 키워드다. 자바에는 네 가지 주요 접근 제한자가 있다:

  1. private: 가장 제한적인 접근 수준이다. private으로 선언된 멤버는 해당 클래스 내부에서만 접근 가능하다. 다른 클래스나 패키지에서는 접근할 수 없다.
  2. default (package-private): 접근 제한자를 명시하지 않으면 기본적으로 적용된다. 같은 패키지 내의 클래스들 사이에서만 접근할 수 있다. 다른 패키지의 클래스에서는 접근할 수 없다.
  3. protected: protected 멤버는 같은 패키지 내의 다른 클래스나, 다른 패키지의 자식 클래스에서 접근할 수 있다.
  4. public: 가장 넓은 접근 범위를 가진다. public으로 선언된 멤버는 어떤 클래스에서든 접근할 수 있다.

이러한 접근 제한자들은 객체지향 프로그래밍의 캡슐화 원칙을 지원하는 데 중요한 역할을 한다. 캡슐화는 클래스의 내부 구현을 숨기고, 외부에서는 제공된 메소드를 통해서만 상호작용할 수 있도록 함으로써, 데이터 보호와 구현의 세부 사항 숨김을 가능하게 한다.

예를 들어, 클래스 Person이 있고, 이 클래스에는 name, age라는 필드와 getName(), setName(String name) 같은 메소드가 있다고 가정해보자. name 필드를 private로 선언하고 getName(), setName(String name) 메소드를 public으로 선언하면, 외부 클래스에서는 직접 name 필드에 접근할 수 없고, 제공된 public 메소드를 통해서만 name 필드의 값을 읽거나 변경할 수 있다. 이것이 캡슐화의 기본적인 예이며, 접근 제한자는 이러한 캡슐화를 구현하는 데 필수적이다.

private, public

privatepublic은 자바에서 사용되는 접근 제한자이다. 이들은 클래스의 멤버(변수, 메소드 등)에 대한 접근 수준을 정의한다.

private 접근 제한자

  • private으로 선언된 멤버는 해당 클래스 내부에서만 접근 가능하다.
  • 클래스 외부에서는 직접 접근할 수 없다.
  • 클래스의 내부 데이터를 숨기고 외부의 불필요한 접근으로부터 보호하는 데 사용된다.

public 접근 제한자

  • public으로 선언된 멤버는 어디서든 접근 가능하다.
  • 클래스의 공개 인터페이스의 일부로서, 외부에서 자유롭게 사용할 수 있다.

예시 코드

class Person {
    // private 멤버 변수
    private String name;
    private int age;

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

    // public 메소드
    public void displayInfo() {
        System.out.println("Name: " + name + ", Age: " + age);
    }

    // private 메소드
    private String getDetails() {
        return "Name: " + name + ", Age: " + age;
    }

    // public getter
    public String getName() {
        return name;
    }

    // public setter
    public void setName(String name) {
        this.name = name;
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person("Alice", 30);
        person.displayInfo(); // 가능: public 메소드

        System.out.println(person.getName()); // 가능: public getter

        // person.getDetails(); // 불가능: private 메소드, 클래스 외부에서 접근 불가
        // System.out.println(person.name); // 불가능: private 변수, 직접 접근 불가
    }
}

이 예제에서, nameage 변수는 private으로 선언되어 Person 클래스 외부에서 직접 접근할 수 없다. 대신, public으로 선언된 getName()setName(String name) 메소드를 통해 간접적으로 이 변수들에 접근할 수 있다. displayInfo() 메소드 역시 public이므로 클래스 외부에서 호출할 수 있지만, getDetails() 메소드는 private이므로 Person 클래스 내부에서만 호출할 수 있다.

이렇게 private와 public을 적절히 사용함으로써 클래스의 캡슐화를 향상시키고, 외부에서 불필요하거나 위험한 접근을 제한할 수 있다.

super();

super();는 자바에서 상속 관계에 있는 클래스들 사이에서 사용되는 특별한 키워드로, 하위 클래스에서 상위 클래스의 생성자를 호출하는 데 사용된다. 상위 클래스를 '슈퍼클래스'라고도 하며, 하위 클래스는 이 슈퍼클래스로부터 상속을 받는다.

super(); 의 주요 특징

  1. 상위 클래스 생성자 호출: super();는 하위 클래스의 생성자 내에서 상위 클래스의 생성자를 호출한다. 이 호출은 하위 클래스의 객체가 생성될 때 상위 클래스의 객체도 적절하게 초기화되도록 보장한다.
  2. 기본 생성자 호출: super();는 상위 클래스의 '기본 생성자'(매개변수가 없는 생성자)를 호출한다. 만약 상위 클래스에 기본 생성자가 명시적으로 정의되어 있지 않고 다른 생성자만 정의되어 있다면, 하위 클래스에서 super();를 사용하면 컴파일 에러가 발생한다.
  3. 자동 삽입: 하위 클래스의 생성자에서 상위 클래스의 생성자를 명시적으로 호출하지 않으면, 컴파일러는 자동으로 상위 클래스의 기본 생성자 호출을 위한 super();를 첫 번째 줄에 삽입한다.
  4. 생성자의 첫 줄에 위치: super();는 하위 클래스의 생성자의 첫 번째 문장이어야 한다. 만약 첫 번째 문장이 아니라면 컴파일 에러가 발생한다.

super 예제

class Parent {
    public Parent() {
        System.out.println("Parent 클래스의 생성자");
    }
}

class Child extends Parent {
    public Child() {
        super(); // Parent 클래스의 기본 생성자 호출
        System.out.println("Child 클래스의 생성자");
    }
}

이 경우, Child 클래스의 객체를 생성할 때 Child 클래스의 생성자가 호출되기 전에 super();에 의해 Parent 클래스의 생성자가 먼저 호출된다. 따라서 출력은 다음 순서로 나타난다.

Parent 클래스의 생성자
Child 클래스의 생성자

super();는 클래스 상속과 객체 생성 과정에서 부모 클래스의 올바른 초기화를 보장하는 중요한 역할을 한다.

실습예제

package com.mystudy.array;

public class SungjukExam {

	public static void main(String[] args) {
		// 2차원 배열을 사용한 성적 처리
		// 국어, 영어, 수학 점수 3개를 저장한 2차원 배열(sungjunk)을 만들고
		// 3명 성적을 입력하고 개인별 총점과, 평균을 계산하여 데이터 출력
		// --------------------------------------------
		/*
		 * 국어\t영어\t수학 총점 평균
		 * --------------------
		 * 100	90	80	270	90.0
		 * 95	95	95	275	95.0
		 * 100	90	82	272	90.66
		 * ---------------------
		 */
		
		int[][] studentScore = {{100, 90, 80}, {100, 90, 81}, {100, 90, 82}};
		printAllScore(studentScore);

	
	}
	
	static void printAllScore (int[][] arr) {
		System.out.println("국어\t영어\t수학\t총점\t평균\t");
		System.out.println("--------------------------------------");
		for (int[] i : arr) {
			int scSum = scoreSum(i);
			double avSum = avrSum(i, scSum);
			printScore(scSum, avSum, i);
		}
	}
	
	static int scoreSum (int[] arr) {
		int sum = 0;
		for (int score : arr) {
			sum = sum + score;
		}
		return sum;
	}
	
	static double avrSum(int[] arr, int sum) {
	    double avr = Math.round((double) sum / arr.length * 100.0) / 100.0;
	    return avr;
	}
	
	static void printScore(int scoreSum, double avrSum, int[] arr) {
		for (int i : arr) {
			System.out.print(i + "\t");
		}
		System.out.print(scoreSum + "\t" + avrSum + "\n");
	}

}
국어	영어	수학	총점	평균	
--------------------------------------
100	90	80	270	90.0
100	90	81	271	90.33
100	90	82	272	90.67

실습예제2

package com.mystudy.bean;
/*
■ 자바빈(Java Bean)
  - 멤버변수(property)의 접근제어자는 private
  - 멤버변수(property) 마다 get/set 메소드 제공(선택적으로 get만 제공)
  - get/set 메소드는 public
  - get 메소드는 파라미터 없고, set 메소드는 하나 이상의 파라미터 존재
  - 멤버변수(property)가 boolean 타입이면 get 메소드 대신 is 메소드 사용가능
  - 외부에서 멤버변수(property) 접근시에는 get/set 메소드를 통해 접근
*/

//public class Student extends Object {
class Student { //extends Object 작성 안하면 컴파일러가 자동 삽입
	private String name; //private 선언시 외부에서 직접 접근불가
	private int kor = 0;
	private int eng = 0;
	private int math = 0;
	private int tot = kor + math + eng;
	private double avg =  Math.round((tot / 3) * 100) / 100;
	
	// 생성자 ====================
	public Student() {
		// super : 부모클래스 객체(인스턴스)
		// super(); : 부모클래스 객체(인스턴스)의 기본생성자 호출문
		super(); // 생략시 컴파일러가 자동 삽입해서 처리함
	}
	
	public Student(String name) {
		super(); // 생성자 호출구문은 첫 번재로 작성해야 한다.
		this.name = name;
	}
	
	public Student(String name, int kor, int eng, int math) {
		this(name); //현재객체(인스턴스)의 생성자 호출, 생성자 재사
		//this.name = name;
		this.kor = kor;
		this.eng = eng;
		this.math = math;
		setTotAvg();
	}
	
	
	// 메소드 ================
	// 외부에서 사용할 수 있도록 메소드 제공(public)
	// 같은 패키지 내에서 사용하려면 default
	// 명칭(호칭) : set메소드, setter, set property
	public void setName(String name) {
		this.name = name;
	}
	
	// 외부에서 데이터를 읽어 가기 위한 get 메소드
	// 명칭(호칭) : get메소드, getter, get property(속성값 읽기/조회)
	public String getName() {
		return name;
	}
	
	// kor : setter, getter
	public void setKor(int kor) {
		if (kor >= 0 && kor <= 100) {
			this.kor = kor;
			setTotAvg();
		} else {
			System.out.println("국어 점수 오류");
		}	
	}
	
	public int getKor() {
		return kor;
	}
	
	public void setEng(int eng) {
		this.eng = eng;
		setTotAvg();
	}
	
	public int getEng() {
		return eng;
	}
	
	public void setMath (int math) {
		this.math = math;
		setTotAvg();
	}
	
	public int getMath() {
		return math;
	}
	
	private void setTotAvg() {  // private이므로 이 메소드 안에서만 처리한다.
	    this.tot = (kor + math + eng);
	    this.avg = Math.round(((double) tot / 3) * 100) / 100.0;
	}
	
	public int getTot() {
		return tot;
	}
	
	public double getAvg() {
		return avg;
	}
	
	public String toString() {
		return "Student [" + "name:" + name + ", kor:" + kor + ", eng:" + eng + ", math:" + math + ", tot:" + tot + ", avg:" + avg + "]";
	}
	// (실습) setter, getter 만들기 ==============
	
}

package com.mystudy.bean;

public class StudentMain {

	public static void main(String[] args) {
		Student stu = new Student();
		System.out.println(stu);
		// System.out.println("name : " + stu.name); // pirvate선언으로 직접 접근 불가능
		stu.setName("홍길동");
		System.out.println("name : " + stu.getName());
		String name = stu.getName();
		System.out.println("name : " + name);
		
		stu.setKor(100);
		System.out.println("국어 : " + stu.getKor());
		
		setScore(stu, 90, 70, 78);
		printScore(stu);
		System.out.println(stu.toString());
		
		Student stu2 = new Student("김유신", 99, 88, 77);
		System.out.println(stu2.toString());

	}
	
	static void setScore(Student stu, int kor, int eng, int math) {
		stu.setKor(kor);
		stu.setEng(eng);
		stu.setMath(math);
	}
	
	static void printScore(Student stu) {
		System.out.println("국어:" + stu.getKor() + "\t영어:" + stu.getEng() + "\t수학:" + stu.getMath() + "\t총합:" + stu.getTot() + "\t평균:" + stu.getAvg());
	}

}
Student [name:null, kor:0, eng:0, math:0, tot:0, avg:0.0]
name : 홍길동
name : 홍길동
국어 : 100
국어:90	영어:70	수학:78	총합:238	평균:79.33
Student [name:홍길동, kor:90, eng:70, math:78, tot:238, avg:79.33]
Student [name:김유신, kor:99, eng:88, math:77, tot:264, avg:88.0]

실습예제3

package com.mystudy.bean.vo;

/*
 * 자바빈(Java Bean) 형태의 클래스 작성
 * VO(Value Object) : 값(데이터)을 저장하기 위한 클래스(객체) - Oxxx, OxxxVO, OxxxVo 방식으로 사용
 * 	사용예) Student, StudentVO, StudentVo
 * DTO(Data Transfer Object) : 값(데이터)을 저장해서 전달하기 위한 클래스(객체)
 * 	사용예) Student, StudentDTO, StudentDto
 */

public class StudentVO {
	// 필드(변수) 선언 ---------
	// 성명 - name : String
	// 국어 - kor : int
	// 영어 - eng : int
	// 수학 - math : int
	// 총점 - tot : int
	// 평균 - avg : double
	private String name;
	private int kor = 0;
	private int eng = 0;
	private int math = 0;
	private int tot = 0;
	private double avg = 0;
	
	public StudentVO(String name, int kor, int eng, int math) {
		this(name);
		setKor(kor);
		setEng(eng);
		setMath(math);
	}
	
	public StudentVO(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
		setTot();
		setAvg();
	}
	public int getKor() {
		return kor;
	}
	public void setKor(int kor) {
		if (kor <= 100 && kor >= 0) {
			this.kor = kor;
			setTot();
			setAvg();
		} else {
			System.out.println("잘못돤 국어 점수입니다.");
		}
	}
	public int getEng() {
		return eng;
	}
	public void setEng(int eng) {
		if (eng <= 100 && eng >= 0) {
			this.eng = eng;
			setTot();
			setAvg();
		} else {
			System.out.println("잘못된 영어 점수입니다.");
		}
	}
	public int getMath() {
		return math;
	}
	public void setMath(int math) {
		if (math <= 100 && math >= 0) {
			this.math = math;
			setTot();
			setAvg();
		} else {
			System.out.println("잘못된 수학 점수입니다.");
		}
		
	}
	public int getTot() {
		return tot;
	}
	public double getAvg() {
		return avg;
	}
	
	private void setTot() {
		this.tot = calTot(this);
	}
	
	private void setAvg() {
		this.avg = calAvg(this);
	}
	
	static int calTot(StudentVO student) {
		int tot = (student.getKor() + student.getEng() + student.getMath());
		return tot;
	}
	
	static double calAvg(StudentVO student) {
		double avg = Math.round(((double) student.getTot() / 3) * 100) / 100.0;
		return avg;
	}
	
	public String toString() {
		return "Student [" + "name:" + name + ", kor:" + kor + ", eng:" + eng + ", math:" + math + ", tot:" + tot + ", avg:" + avg + "]";
	}
	
	public void printScore() {
		System.out.println("Student [" + "name:" + name + ", kor:" + kor + ", eng:" + eng + ", math:" + math + ", tot:" + tot + ", avg:" + avg + "]");
	}
}

package com.mystudy.bean.vo;

public class StudentManager {

	public static void main(String[] args) {
		// 2차원 배열을 사용한 성적 처리
		// 국어, 영어, 수학 점수 3개를 저장한 2차원 배열(sungjunk)을 만들고
		// 3명 성적을 입력하고 개인별 총점과, 평균을 계산하여 데이터 출력
		// --------------------------------------------
		/*
		 * 성명\t국어\t영어\t수학 총점 평균
		 * --------------------
		 * 김유신	100	90	80	270	90.0
		 * 이순신	95	95	95	275	95.0
		 * 홍길동	100	90	82	272	90.66
		 * ---------------------
		 */
		
		StudentVO stu1 = new StudentVO("김유신", 100, 90, 80);
		StudentVO stu2 = new StudentVO("이순신", 95, 95, 95);
		StudentVO stu3 = new StudentVO("홍길동", 100, 90, 82);
		StudentVO stu4 = new StudentVO("asdf", 101, -1, 103);
		System.out.println(stu4.getKor());
		
		StudentVO[] stuArr = {stu1, stu2, stu3};
		
		for (StudentVO st : stuArr) {
			st.printScore();
		}
		

	}

}
잘못돤 국어 점수입니다.
잘못된 영어 점수입니다.
잘못된 수학 점수입니다.
0
Student [name:김유신, kor:100, eng:90, math:80, tot:270, avg:90.0]
Student [name:이순신, kor:95, eng:95, math:95, tot:285, avg:95.0]
Student [name:홍길동, kor:100, eng:90, math:82, tot:272, avg:90.67]
profile
신입사원...

0개의 댓글