728x90
반응형
접근 제어자
- 접근 제어자 : 접근 권한을 지정하는 예약어
- 클래스 외부에서도 접근이 가능하게 할 것인가 또는 클래스 내부에서만 사용할 것인가를 정한다.
- 물리적인 개념에서의 보호(보안) ⇒ 정보은닉 구현
- Public : 외부 클래스 어디서나 접근 가능. 다른 패키지, 다른 클래스에서 사용하게 할 수 있다.
- Protected : 같은 패키지 내부와 상속 관계의 클래스에서만 접근 가능.
- Default : 아무것도 없는 경우이며, 같은 패키지에서만 접근 가능.
- Private : 같은 클래스에서만 접근 가능.
- 객체 지향 대표 특징 4 가지
- 캡슐화 : 정보 은닉
- 상속
- 다형성
- 추상화
accessor1 : 접근 제어자, UserTest
/*
* 접근 지정자 (= 접근 제어자)
* 클래스, 메서드, 변수 등에 대한 접근 범위를 지정하여 외부로부터의 접근 제어
* - public
* 클래스 : 같은 클래스, 같은 패키지, 다른 패키지에서 모두 접근 가능.
* 메서드/변수 : 같은 클래스, 같은 패키지, 다른 패키지의 모든 클래스에서 접근 가능
* - protected
* 클래스 : 클래스에는 사용할 수 없음
* 메서드/변수 : 같은 클래스, 같은 패키지, 상속 관계(다른 패키지의 하위 클래스에서 접근 가능)의 클래스에서만 접근 가능
* - (default)
* 클래스 : 아무 접근 지정자를 명시하지 않을 경우
* 메서드/변수 : 같은 클래스와 같은 패키지에서만 접근 가능
* - private
* 클래스 : 클래스에는 사용할 수 없음
* 메서드/변수 : 같은 클래스에서만 접근 가능.
*/
class UserTest {
public String id = "홍길동"; // 인스턴스 생성 시 명시적 초기화가 이뤄지고, public 이므로 어느 클래스에서나 사용 가능
private String pw = "1111"; // 인스턴스 생성 시 명시적 초기화가 이뤄지고, private 이므로 UserTest 클래스 내에서만 사용 가능
// 현재 pw를 반환하는 public 메서드
public String pwCheck() {
return this.pw;
}
// 문자열 타입의 새로운 비밀번호를 받아 pw를 변경하는 public 메서드
public void pwChange(String newPw) {
this.pw = newPw;
}
}
public class accessor1 {
public static void main(String[] args) {
UserTest user = new UserTest();
// id 는 public 이므로 다른 클래스에서도 접근이 가능하다.
System.out.println("id: " + user.id); // 홍길동
// pw 는 private 이므로 not visible하다는 오류가 뜬다.
// 다른 클래스에서는 접근 불가능.
// C047_accessor1 클래스와 UserTest는 다른 클래스이다.
// System.out.println("pw: " + user.pw); // 오류 발생
// private인 것들에 접근하지 말고,
// public으로 된 메서드를 활용해서 private인 변수에 접근하자.
// 직접 접근하는 것이 아니라 간접적으로 접근하게 해서 return 받자.
System.out.println("pw: " + user.pwCheck()); // 1111
// 왜 굳이 메서드를 활용해서 접근하는 것인가?
// private는 다른 클래스에서 접근 자체가 불가능하므로!
// id, pw 변경하기
System.out.println("=== 변경 후 ===");
user.id = "이순신"; // id 변경
// user.pw = "1234"; // pw 접근 불가능하므로 변경 불가
// private인 이상 비밀번호를 변경하는 방법이 없다.
System.out.println("변경된 id: " + user.id); // 이순신
// System.out.println("변경된 pw: " + user.pw); // 역시 private이라서 접근 불가, 변경 불가
// pw를 변경하고 싶다면, 변경하는 기능을 가진 public 메서드를 만들면 된다.
user.pwChange("1234"); // 새로운 pw를 public한 메서드를 활용
System.out.println("변경된 pw: " + user.pwCheck()); // 비밀번호가 바뀜.
}
}
accessor2 : 접근 제어자, Time2
class Time2 {
private boolean am;
private int hour;
private int minute;
private int second;
// 명시적 생성자 : 클래스 이름과 동일하고, 파라미터가 존재
Time2(int hour, int minute, int second) {
setHour(hour); // 시간을 처리하는 메서드
setMinute(minute); // 분을 처리하는 메서드
setSecond(second); // 초를 처리하는 메서드
}
// 시간을 반환하는 메서드
public int getHour() {
return hour;
}
// 시간을 처리하는 메서드
public void setHour(int hour) {
if (0 <= hour && hour <= 23) {
// 시간이 12 미만이면 am = true, 아니면 false
this.am = hour < 12;
this.hour = hour % 12;
if (this.hour == 0)
this.hour = 12;
}
}
// 분을 반환하는 메서드
public int getMinute() {
return minute;
}
// 분을 처리하는 메서드
public void setMinute(int minute) {
if (0 <= minute && minute <= 59) {
this.minute = minute;
}
}
// 초를 반환하는 메서드
public int getSecond() {
return second;
}
// 초를 처리하는 메서드
public void setSecond(int second) {
if (0 <= second && second <= 59) {
this.second = second;
}
}
void whatTime2() {
System.out.println(am ? "오전" : "오후");
System.out.println(hour + "시 " + minute + "분 " + second + "초");
}
}
public class accessor2 {
public static void main(String[] args) {
Time2 now = new Time2(12, 34, 56);
now.whatTime2(); // 오후 12시 34분 56초
// hour는 private 변수이므로 다른 클래스에서 접근 불가능
// System.out.println(now.hour); // 오류 발생
// public한 메서드를 통해 시간 정보를 출력해야한다.
System.out.println(now.getHour()); // 12
// 0~23 사이의 정수가 아닌 값을 시간으로 넣어보자
now.setHour(34); // 에러는 아님.
// 조건문에 만족하지 않으므로 아무런 처리가 이뤄지지 않는다.
System.out.println(now.getHour()); // 12
// 각 메서드의 조건문에 만족하는 숫자를 입력하면,
// 새로운 시간이 처리되어 입력된다.
now.setHour(10); // 변경 가능
now.setMinute(10); // 변경 가능
now.setSecond(10); // 변경 가능
now.whatTime2(); // 오전 10시 10분 10초
}
}
encapsulation : 접근제어자를 통한 캡슐화
/*
* 멤버 변수의 경우 보통 private 를 사용하여 외부로부터 직접적인 접근을 막고
* getter/setter라 부르는 멤버 메서드를 만들어 사용함으로써
* 내부 데이터에 제한적 접근을 할 수 있도록 한다.
*/
class Member {
private String id;
private String pw;
private String phone;
// 자동 완성 단축키 : alt + shift + s 누른 후 o or r
public Member(String id, String pw, String phone) {
this.id = id;
this.pw = pw;
this.phone = phone;
}
// getter / setter
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getId() {
return id;
}
public void setPw(String pw) {
this.pw = pw;
}
// public한 멤버 정보 보여주는 메서드 : String 비밀번호 파라미터 입력
public void memberInfo(String pwCheck) {
// 만약 비밀번호가 일치한다면 회원 정보를 출력
// 참조형 데이터인 문자열 비교이므로 equals 메서드 사용 (주소값 비교 X)
// 문자열 값 자체 비교 : equals()
// this.pw == pwCheck 는 주소값 비교이다.
if(this.pw.equals(pwCheck)) {
System.out.println("[ 회원 정보 ]");
System.out.println(" * 아이디: " + this.id);
System.out.println(" * 핸드폰: " + this.phone);
} else {
System.out.println("비밀번호가 일치하지 않습니다.");
}
}
}
public class encapsulation {
public static void main(String[] args) {
Member member = new Member("hong", "123", "01012345678");
// id는 private이므로 직접적인 접근 불가
// System.out.println(member.id); // 오류 발생
System.out.println(member.getId()); // hong
System.out.println(member.getPhone()); // 01012345678
// 비밀번호가 불일치하므로 회원정보 출력 안함
member.memberInfo("111"); // 비밀번호가 일치하지 않습니다.
// 비밀번호가 일치하므로 회원정보 출력됨
member.memberInfo("123");
// 456으로 비밀번호 변경
member.setPw("456");
// 456로 변경된 비밀번호로 회원번호 출력됨
member.memberInfo("456");
// 01090901212로 핸드폰 번호 변경
member.setPhone("01090901212");
member.memberInfo("456"); // 변경된 번호가 잘 출력된다.
}
}
생성자(Constructor) 생성 단축키 및 자동완성
- 단축키 alt + shift + s
- 후에 o 누르면 constructor 생성창 띄움
- 후에 r 누르면 getter / setter 생성창 띄움
- 우클릭 → Generate Constructor using Field
- 생성자를 몇 개를 받도록 할 것 인가를 정함
Getter / Setter 생성 : 단축키 및 자동 생성
- 단축키 alt + shift + s
- 후에 o 누르면 constructor 생성창 띄움
- 후에 r 누르면 getter / setter 생성창 띄움
static1 : 접근제어자, static, final 를 가진 변수
class Test1 {
// 인스턴스 변수, 멤버 변수
// private 이므로 다른 클래스에서 접근 불가능 하다.
private String name1 = "홍길동";
// 정적 변수, 멤버 변수
// public 이므로 다른 클래스에서 접근 가능하다.
// static 이므로 class 이름으로 호출이 가능하다.
// final 이므로 재할당이 불가능한 상수 값이다.
public static final String name2 = "고길동";
public void printName() {
System.out.println(this.name1);
}
}
public class static1 {
public static void main(String[] args) {
// Test1 이라는 클래스를 통해 인스턴스를 생성한다.
// new 라는 예약어를 통해 Heap 영역에 인스턴스를 저장한다.
// Test1에는 생성자가 없기 때문에, 기본 생성자가 주어진다.
Test1 ex = new Test1();
// name1은 priavte 하므로 접근 불가능
// System.out.println(ex.name1); // 오류 발생
// public 한 메서드를 활용해 name1에 접근할 수 있다.
ex.printName();
// name2 는 public이므로 다른 클래스에서 접근 가능.
// static 영역이라 Test1을 통해 호출이 가능하므로
// 인스턴스(객체)를 통한 호출은 권장되지 않는다.
System.out.println(ex.name2); // 고길동
// 정적 변수(static 붙은 변수)는 인스턴스의 생성 없이 클래스의 이름으로 호출 가능
System.out.println(Test1.name2); // 고길동
// name2는 final 이므로 상수이다.
// 그래서 재할당이 불가능하다. 수정 불가
// Test1.name2 = "이순신"; // 오류 발생
}
}
static2 : 접근제어자, static 을 가진 메서드
public class static2 {
// 정적 메서드, 멤버 메서드
public static int add(int x, int y) {
return x + y;
}
// 인스턴스 메서드, 멤버 메서드
public int minus(int x, int y) {
return x - y;
}
public static void main(String[] args) {
// 정석 방법
// add 메서드는 static 이므로 인스턴스 생성 없이도
// 클래스 이름을 통해 메서드 호출이 가능하다.
int sum1 = C051_static2.add(10, 20);
System.out.println(sum1); // 30
// 같은 클래스 안에 있으므로 메서드만 작성해서 호출하는 것도 가능
int sum2 = add(10, 20);
System.out.println(sum2); // 30
// 클래스 이름도 없고, 인스턴스 생성도 되지 않은 상태.
// int result = minus(20, 10); // 오류 발생
// static이 없는 minus 를 사용하고자 한다면, 인스턴스부터 생성해야한다.
C051_static2 instance = new C051_static2();
int result = instance.minus(20, 10);
System.out.println(result); // 10
// add는 static 메서드이므로 객체를 통한 메서드 호출이
// 권장되지 않는다는 경고가 뜨지만 실행은 가능하다.
int sum3 = instance.add(10, 20);
System.out.println(sum3); // 30
}
}
static3 : static 변수와 인스턴스 관계, 초기화 블록
class Student {
// 정적 변수
public static int serialNum;
// 인스턴스 변수
public String StudentName;
// 인스턴스 생성과 상관 없이 클래스 초기화 블록이 실행된다.
static { // 클래스 초기화 블록
serialNum = 1000;
}
// 인스턴스 초기화 블록을 사용하면
// 어느 생성자를 통해서 인스턴스를 만드는 지와 상관없이
// 인스턴스가 생성될 때 인스턴스 초기화 블록이 가장 먼저 실행된다.
// 공통적인 코드를 여기에 묶어서 한 단위로 만들 수가 있다.
// 중복 코드 제거 가능
{ // 인스턴스 초기화 블록
serialNum++;
}
// 기본 생성자
public Student() {
// serialNum++;
}
// 명시적 생성자
public Student(String name) {
this.StudentName = name;
// serialNum++;
}
// getter
public String getStudentName() {
return StudentName;
}
// setter
public void setStudentName(String studentName) {
StudentName = studentName;
}
}
public class static3 {
public static void main(String[] args) {
// static 변수인 serialNum을 클래스를 통해 호출
// static 변수는 모든 인스턴스가 공유하는 변수
// 인스턴스를 생성할 때마다 serialNum++에 의해 1 증가
System.out.println(Student.serialNum); // 1000
// lee 라는 인스턴스 생성
Student lee = new Student();
lee.setStudentName("이지원");
System.out.println(lee.StudentName + "의 학번: " + lee.serialNum);
System.out.println(Student.serialNum); // 1001
// son 이라는 인스턴스 생성
Student son = new Student();
son.setStudentName("손수경");
System.out.println(son.StudentName + "의 학번: " + son.serialNum);
System.out.println(Student.serialNum); // 1002
// 명시적 생성자를 호출해서 인스턴스를 생성해보자.
// 인스턴스 생성하면서 바로 이름 부여하기
Student park = new Student("박미경");
System.out.println(park.StudentName + "의 학번: " + park.serialNum);
// 기본 생성자와 명시적 생성자는 서로 다르기 때문에
// 명시적 생성자를 통해서 인스턴스를 생성하면 기본 생성자가 작동하지 않으므로
// 학번이 1 증가하지 않는다.
// 그래서 명시적 생성자에도 serialNum++ 을 작성해야함.
// 근데 이 코드가 중복이 되므로, 인스턴스 초기화 블록을 사용한다.
System.out.println(Student.serialNum); // 1002
}
}
singletonPattern : 싱글톤 패턴 (0번부터 5번까지 따라가보기)
/*
* 싱글턴 패턴 (Singleton Pattern)
* 단 하나의 인스턴스만 생성되도록 보장하는 디자인 패턴
* 가장 기본적인 방법은 private 생성자와 static 메서드를 사용하는 것.
* - 주로 시스템의 공통 자원(데이터베이스, 설정 파일, 로그 등)을
* 여러 객체가 동시에 사용하는 상황에서 사용됨
* 예시:
* 1. 데이터베이스 연결 시 하나의 인스턴스만 사용
* 2. 애플리케이션에서 로그를 기록할 때, 하나의 로그 관리 인스턴스만 사용
* 3. 설정 파일을 읽고 쓸 때 하나의 설정 관리자 인스턴스만 사용
*/
class Singleton {
// 0. 인스턴스 생성 전에 static 영역에 instance 변수를 선언
// private이므로 외부에서 직접 접근 불가능
// 현재 선언만 되어있고, 아직 인스턴스가 할당되지 않은 상태
private static Singleton instance;
// 5. 기본 생성자 호출하면서 인스턴스 생성
// private한 기본 생성자
// 그래서 Singleton 클래스 내부에서만 사용 가능한 생성자.
// 그래서 main 메서드에서 Singleton st = new Singleton(); 이 불가능하다
// 외부에서 new Singleton()을 사용한 인스턴스 생성을 차단
// Singleton 클래스 내부에서만 생성자를 호출할 수 있다.
private Singleton() {
System.out.println("생성자 호출");
}
// 2. getInstance 메서드가 호출된다.
public static Singleton getInstance() {
// 3. instance가 null 인지 확인
if (instance == null) {
// 4. 만약 인스턴스가 아직 없으면(할당된 것이 없으면, null이면), 새로운 인스턴스를 생성한다.
// 여기서 기본 생성자를 호출한다.
instance = new Singleton();
}
// 3-1. 인스턴스가 이미 있으면, 기존의 인스턴스를 반환
return instance;
}
// 싱글턴 인스턴스에서 호출할 수 있는 메서드
public void printMethod() {
System.out.println("인스턴스로부터 메서드 호출");
}
}
public class singletonPattern {
public static void main(String[] args) {
// 1. Singleton 클래스의 getInstance 메서드를 호출하고 인스턴스 가져오기
// 3-1 혹은 5번에 도달하고 난 후 아래 코드는 끝난다.
Singleton st1 = Singleton.getInstance();
// st1 인스턴스를 통해 printMethod 메서드 호출
st1.printMethod();
// 아래 코드 진행시 이미 st1 인스턴스가 존재하므로 3번 조건문을 skip한다
// 그래서 기본 생성자를 호출하지 않고 새로운 인스턴스를 생성하지 않는다.
// 그리고 기존의 인스턴스를 반환하여 st2에 할당
Singleton st2 = Singleton.getInstance();
st2.printMethod();
}
}
- private와 static을 사용해서 붕어빵틀을 단 하나만 생성
- 붕어빵이 없다면 붕어빵을 생성하고, 이미 있다면 가지고 있던 붕어빵을 준다.
- private static Singleton instance; 이 코드를 잘 이해해야한다.
Character
public class Character {
// 캐릭터 정보
private String id; // id
private String job; // 직업
private int level; // 레벨
private int str; // 힘 스탯
private int dex; // 민첩 스탯
private int intel; // 지능 스탯
/*
* 1. level, str, dex, intel 인스턴스 생성 시 1로 초기화한다.
* 2. 명시적 생성자 생성
* - id, job을 파라미터로 가지는 생성자
* - id, job, level, str, dex, intel 을
* 파라미터로 가지는 생성자
* 3. skill() public 메서드 생성
* - 인스턴스의 job이 "마법사" 면 "파이어볼" 출력
* - 인스턴스의 job이 "전사" 면 "배쉬" 출력
* - 인스턴스의 job이 "궁수" 면 "크리티컬" 출력
* - 그 외 "기본공격" 출력
* 4. 해당 인스턴스의 정보를 출력하는 메서드 생성
* - 출력형식
* [고구마(궁수) Lv5]님의 스탯: str(3), dex(11), intel(2)
*/
// 요구사항 1번 : 인스턴스 초기화 블록
{
level = 1;
str = 1;
dex = 1;
intel = 1;
}
// 요구사항 2-1번 : 명시적 생성자
public Character(String id, String job){
this.id = id;
this.job = job;
}
// 요구사항 2-2번 : 명시적 생성자 => 생성자 내에서 생성자 호출
public Character(String id, String job, int level, int str, int dex, int intel){
this(id, job);
this.level = level;
this.str = str;
this.dex = dex;
this.intel = intel;
}
// 요구사항 3번 : switch-case 또는 equals() 활용
public void skill() {
switch(job){
case "마법사":
System.out.println("파이어볼");
break;
case "전사":
System.out.println("배쉬");
break;
case "궁수":
System.out.println("크리티컬");
break;
default:
System.out.println("기본공격");
}
}
// 요구사항 4번 : 문자열
public void characterInfo() {
System.out.println("[" + id + "(" + job + ") Lv" + level + "]님의 스탯: str(" + str + "), dex(" + dex + "), intel(" + intel + ")");
}
}
test : Character 클래스를 호출해서 사용하는 test 클래스
public class test {
public static void main(String[] args) {
Character ch1 = new Character("홍길동", "전사");
Character ch2 = new Character("둘리", "마법사", 3, 2, 5, 500);
ch1.characterInfo();
ch1.skill();
ch2.characterInfo();
ch2.skill();
}
}
728x90
반응형