-----------------------------------------
제어자(Modifier)


1. 제어자는 외부에서 멤버의 접근을 제한하는 접근 제어자와 멤버의 상태를 제한하는 제어자가 있다.

2. 접근 제어자 종류
- private : 같은 클래스 내부에서만 접근 가능
- (default) : 접근지정자 표기하지 않은 경우. 같은 패키지 내부에서만 접근 가능
- protected : 상위 클래스에서 protected 접근 지정자를 지정한 멤버는 하위 클래스에서만 접근 가능. 단, 같은 패키지에서도 접근 가능.
- public : 모든 경우에서 접근 가능


private 생성자 테스트
//Sample39.java
package com.test;

//private 생성자를 가진 클래스는
//상속하는 과정에서 super() 생성자 호출이 안되므로
//상속 불가 클래스로 만드는 것이 좋다.
//-> final 키워드
public final class Sample39 {
 
 //private 접근 제어자를 가진 생성자 지정
 private Sample39() {
  System.out.println("Sample39 클래스의 생성자 호출!");
 }
 
 //생성자가 private이므로 인스턴스 멤버는 접근 불가.
 //-> 모든 멤버는 static 상태가 되어야 한다.
 public static void method() {
  System.out.println("Sample39 클래스의 메소드 호출");
 }

}

 

 


//SubSample39.java
package com.test;

//private 생성자를 가진 클래스는 상속이 불가능하므로
//상속이 불가능한 클래스임을 알려주는 것이 좋다.
//-> final 키워드
public class SubSample39 extends Sample39 {
 
 //SubSample39의 기본생성자는 Sample39의 생성자(super 생성자)를 필요로 한다.
 
 //생략된 멤버? -> 기본 생성자
 public SubSample39() {
  //생략된 구문? -> super();
  super(); //->private 생성자는 접근 불가
 }

}

 

 

 

//Main.java
package com.test;

public class Main {

 public static void main(String[] args) {
  
  //객체 생성 -> 생성자 호출 -> 생성자의 접근제어자가 private 상태임.
  //객체 생성이 되지 않으면 인스턴스 멤버 접근도 할 수 없다.
  //인스턴스 멤버 사용할 수 없다는 의미.
  //인스턴스 멤버가 전혀 없는 상태라는 의미.
  //-> 객체 생성 과정 불필요.
  //-> 생성자 호출 차단
  //-> private 접근 제어자 지정
  
  //Sample39 s39 = new Sample39();
  //s39.method();
  
  Sample39.method();

 }

}

 

 


//PrivateFinalTest.java
package com.test;


//private 생성자가 포함된 클래스를 상속 받는 경우
//상속 받은 클래스가 객체 생성하는 과정에서
//super() 생성자 호출 부분이 실행되지 않는다.
//-> final 클래스 지정 필요
public final class PrivateFinalTest {
 
 //추가 객체가 만들어지지 않도록 하기 위한 멤버 변수 추가
 private static PrivateFinalTest obj;

 //private 생성자 추가
 private PrivateFinalTest() {
  
 }
 
 //객체 생성을 위한 전용 메소드 추가
 //싱글톤 디자인패턴
 public static PrivateFinalTest getInstance() {
  if (obj == null) {
   obj = new PrivateFinalTest();
  }
  return obj;
 }
 
 //현재 클래스 내부에 모든 메소드가 static 상태인 경우
 //현재 클래스에 대한 객체 생성 과정이 필요 없는 경우가 있다.
 //-> private 생성자
 //-> 객체 생성 불가
 public static void method() {
  
 }

}

 

 

//SubClass.java
package com.test;

public class SubClass extends PrivateFinalTest {

}

 


//Main.java
package com.test;

public class Main {

 public static void main(String[] args) {
  
  //private 생성자이므로 객체 생성 불가
  //PrivateFinalTest test = new PrivateFinalTest();
  
  //static 멤버는 접근 가능
  PrivateFinalTest.method();
  
  //getInstance() 메소드를 이용한 객체 획득
  //객체가 추가로 만들어지지 않도록 하는 것이 목적
  PrivateFinalTest test2 = PrivateFinalTest.getInstance();
  System.out.println(test2.toString());
  PrivateFinalTest test3 = PrivateFinalTest.getInstance();
  System.out.println(test3.toString());

 }

}

 

---------------------------------------------
싱글톤 기법

//Singleton01.java
package com.test;

public class Singleton01 {
 
 //일반적으로 클래스의 객체 생성을 위해서
 //생성자를 추가한다.
 //기본생성자->자동 추가
 //생성자 역할 -> 멤버변수 초기화
 //생성자 호출 -> new 연산자를 이용한 객체 생성시
 public Singleton01() {
  
 }

}

 


//Singleton02.java
package com.test;

public final class Singleton02 {
 
 //객체 생성 과정을 위한 전용 메소드 추가
 //한 개의 객체만 생성되도록 제한
 //-> Singleton
 //-> private 생성자 준비
 //-> 객체 제공 전용 메소드 준비
 
 //private 생성자
 //-> 사용자가 클래스의 객체를 직접 생성 불가능
 private Singleton02() {
  
 }
 
 //객체 제공 전용 (인스턴스)메소드
 /*
 public Singleton02 getInstance() {
  return new Singleton02();
 }
 */
 
 //객체 제공 전용 (스태틱)메소드
 //-> new 연산자 제한이 없는 상태라서 객체가 여러개 생성될 수 있다.
 /*
 public static Singleton02 getInstance() {
  return new Singleton02();
 }
 */
 
 //객체 제공 전용 (스태틱)메소드
 //-> new 연산자 제한
 //-> 한 개의 객체만 제공
 //-> Singleton 기법
 private static Singleton02 obj; //null
 public static Singleton02 getInstance() {
  //현재 메소드를 최초 호출시
  //if문을 만족하고 객체 생성 과정 실행
  //객체의 참조 주소를 obj 변수에 저장
  //다음에 호출되는 경우는
  //obj 변수에 이미 객체의 참조 주소가 저장된 상태이므로
  //if문 실행 없이 기존의 값 반환
  if (obj == null) {
   obj = new Singleton02();
  }
  return obj;
 }
 

}

 


//Main.java
package com.test;

import java.util.Calendar;

public class Main {

 public static void main(String[] args) {

  //일반적인 객체 생성 과정
  Singleton01 singleton01 = new Singleton01();
  //toString() -> Object 클래스
  //객체 정보(패키지이름.클래스이름@해쉬코드) 출력
  System.out.println(singleton01.toString());

  //같은 자료형을 가진 다른 객체 생성 -> new 연산자
  Singleton01 singleton02 = new Singleton01();
  //해쉬코드가 다른 경우 다른 객체이다.
  System.out.println(singleton02.toString());
  
  //클래스의 객체를 한 개만 생성되도록 하려면?
  //-> new 연산자 사용 제한
  //-> private 생성자 준비
  //-> 객체 제공 전용 메소드 호출
  //-> ?
  
  //Singleton02 singleton03 = new Singleton02(); //X
  
  //-> 객체 제공 전용 메소드 호출 -> 인스턴스 -> 호출 불가능
  //singleton03.getInstance(); //X
  
  //-> 객체 제공 전용 메소드 호출 -> 스태틱 -> 호출 가능
  /*
  Singleton02 singleton03 = Singleton02.getInstance(); //O
  System.out.println(singleton03.toString());
  */
  
  //같은 자료형을 가진 다른 객체 생성 -> new 연산자
  /*
  Singleton02 singleton04 = Singleton02.getInstance(); //O
  System.out.println(singleton04.toString());
  */
  
  //Singleton 기법이 적용된 메소드 호출
  Singleton02 singleton05 = Singleton02.getInstance(); //O
  System.out.println(singleton05.toString());
  //같은 자료형을 가진 같은 객체
  Singleton02 singleton06 = Singleton02.getInstance(); //O
  System.out.println(singleton06.toString());
  
  //new 연산자 제한
  //Calendar cal0 = new Calendar(); //X
  
  //객체 제공 메소드 호출
  Calendar cal1 = Calendar.getInstance();
  System.out.println(cal1.toString());
  Calendar cal2 = Calendar.getInstance();
  System.out.println(cal2.toString());
  
 }

}

 

 

 

---------------------------------------------

 

 

 

//GetSet.java
package com.test;

public class GetSet {
 
 //default 접근제어자를 지정한 멤버변수
 //외부에서 멤버변수를 직접 접근 가능한 상태
 //멤버변수에 저장될 데이터에 대한 검증과정 추가 불가능
 //내부적으로 kor, eng, mat는 0~100 사이의 점수만 취급 예정.
 //int kor, eng, mat;
 
 //내부적인 기준을 검사하는 과정을 추가하기 위해서
 //외부에서 직접 접근 불가능하도록 설정
 private int kor, eng, mat;

 //내부적인 기준을 검사하는 과정을 추가하기 위해서
 //멤버변수만을 위한 getter, setter 메소드 추가
 public void setKor(int kor) {
  if (kor>=0 && kor<=100) {
   this.kor = kor;
  } else {
   System.out.println("범위(0~100)를 벗어나는 데이터입니다.");
  }
 }
 public void setEng(int eng) {
  if (eng>=0 && eng<=100) {
   this.eng = eng;
  } else {
   System.out.println("범위(0~100)를 벗어나는 데이터입니다.");
  }
 }
 public void setMat(int mat) {
  if (mat>=0 && mat<=100) {
   this.mat = mat;
  } else {
   System.out.println("범위(0~100)를 벗어나는 데이터입니다.");
  }
 }
 
 public int total() {
  return kor + eng + mat;
 }
 
}

 

 

//GetSetTest.java
package com.test;

public class GetSetTest {

 public static void main(String[] args) {
  
  GetSet test = new GetSet();
  
  //외부에서 직접 멤버변수에 접근해서 데이터 저장 가능
  //외부에서 내부적인 기준을 알 수 없기 때문에
  //무작위의 데이터 입력 가능
  /*
  test.kor = 200;
  test.eng = 100;
  test.mat = 100;
  */
  
  //getter, setter 등록을 하면
  //setter() 메소드를 이용해서
  //데이터 입력 처리
  //내부적인 기준을 만족하는 데이터만 입력 가능
  test.setKor(200);
  test.setEng(100);
  test.setMat(100);
  
  System.out.println(test.total());
  

 }

}

 

 

 


3. 멤버의 상태를 제한하는 제어자
- static : 멤버의 상태를 static 상태로 지정
- final : 멤버의 상태를 최종 상태로 지정. 변형 불가.
- abstract : 멤버의 상태를 추상으로 지정. 구현 불가.


//Sample40.java
package com.test;

//클래스에 final 키워드 사용시 상속 불가
public final class Sample40 {

}

 

//SubSample40.java
package com.test;

//클래스에 final 키워드 사용시 상속 불가
public class SubSample40 extends Sample40 {

}

 

//Sample41.java
package com.test;

public class Sample41 {
 
 //멤버에 final 키워드 사용시 오버라이딩 금지
 public final void method1() {
  System.out.println("final 키워드가 있는 메소드!");
 }

 public void method2() {
  System.out.println("final 키워드가 있는 메소드!");
 }

}

 


//SubSample41.java
package com.test;

public class SubSample41 extends Sample41 {

 //멤버에 final 키워드 사용시 오버라이딩 금지
 @Override
 public void method1() {
 }

 @Override
 public void method2() {
 }
  
}

 

 

//Sample42.java
package com.test;

public class Sample42 {
 
 //멤버변수(field)에 final 키워드 사용한 경우는
 //변수의 값(초기값)에 대한 변형 불가
 //초기값 지정 방법 -> 초기화 구문, 초기화 블럭, 생성자
 private final int a = 10;
 private final int b;
 
 public Sample42() {
  this.b = 20;
 }

 public Sample42(int b) {
  this.b = b;
 }

 public int getA() {
  return a;
 }

 public int getB() {
  return b;
 }
 
 //final 키워드가 지정된 멤버변수에
 //초기화 과정 이후의 대입문 사용은 불가
 public void setA(int a) {
  this.a = a;
 }
 
 public void setB(int b) {
  this.b = b;
 }

}

 

----------------------------------------------
상수
- 정해진 값을 변경하지 않고 그대로 사용하는 수.
- static final
- 상수명은 대문자로 표기

public static final int   MAX_VALUE = 0x7fffffff;


public class 클래스 {
 public static final 자료형 상수명 = 값;
}

 

 


-------------------------------------------------
과제)외부에서 데이터(이름, 전화번호)를 입력 받아서 메모리에 저장하고 출력, 검색할 수 있는 회원 입력, 출력 프로그램 작성.
회원 저장용 저장소(배열) 생성시 회원의 수는 사용자가 결정.

실행 예)
---- 회원관리 ----
1. 회원 입력
2. 회원 전체 출력
3. 회원 검색(이름 기준)
선택(1~3, 0 종료)?

//Student.java -> 회원 한 명분의 정보 저장용 클래스. 이름, 전화번호 항목으로 구성.
//MenuAction.java -> 메뉴 액션 클래스. 최초 입력시 회원 n명까지 저장할 수 있는 배열 생성. 배열의 자료형은 Student 클래스로 지정.
//Main.java -> 메뉴 출력


//Student.java
package com.sist;

public class Student {
 
 private String name, tel;

 public String getName() {
  return name;
 }

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

 public String getTel() {
  return tel;
 }

 public void setTel(String tel) {
  this.tel = tel;
 }


 //toString() 메소드 오버라이딩 구현
 //멤버변수의 데이터를 출력하는 용도로 변경
 @Override
 public String toString() {
  
  return String.format("%s %s"
    , this.getName()
    , this.getTel());
  
 }

 //문제) equals() 메소드 오버라이딩
 //equals()는 Object 클래스의 메소드
 //equals()는 원래 객체의 참조주소를 비교하는 기능이지만
 //객체의 멤버(name)을 비교하도록 변경
 @Override
 public boolean equals(Object obj) {

  //원본 -> this.name
  //비교 대상 -> obj.getName(); //X
  //비교 대상 -> ((Student)obj).getName(); //O
  //비교 방법 -> 같은지, 다른지 ? -> true or false -> 비교 대상의 자료형 -> String -> equals() 메소드 -> 문자열 비교
  return this.name.equals(((Student)obj).getName());
   
 }
 
 

}

 

 

 

//MenuAction.java
package com.sist;

import java.util.Scanner;

public class MenuAction {
 
 //학생 정보 저장용 배열 준비->데이터 저장소
 private Student[] students;
 
 public MenuAction() {
  //배열 생성 및 초기화
  students = new Student[5];
  this.init();
 }
 
 private void init() {
  
  Student student0 = new Student();
  student0.setName("hong");
  student0.setTel("010-123-1234");
  students[0] = student0;
  
  Student student1 = new Student();
  student1.setName("kim");
  student1.setTel("010-432-4321");
  students[1] = student1;

  Student student2 = new Student();
  student2.setName("park");
  student2.setTel("010-987-9876");
  students[2] = student2;
 
  Student student3 = new Student();
  student3.setName("choi");
  student3.setTel("010-567-5678");
  students[3] = student3;
 
  /*
  Student student4 = new Student();
  student4.setName("hwang");
  student4.setTel("010-876-8765");
  students[4] = student4;
  */

 }
 
 
 //1. 회원 입력
 public void menuInsert(Scanner sc) {
  //문제) 신규 정보 등록 과정 추가
  
  //배열 크기 및 여분 확인 -> 입력 가능 여부 결정
  //입력-> 새로운 name, tel
  //처리-> 저장소(배열)에 신규 저장
  //출력-> "신규 데이터 입력!" or "저장소 full!" 메시지 출력
  if (students.length > this.count()) {
   System.out.print("이름 입력 : ");
   String name = sc.next();
   System.out.print("전화번호 입력 : ");
   String tel = sc.next();
   Student stu = new Student();
   stu.setName(name);
   stu.setTel(tel);
   students[this.count()] = stu;
   System.out.printf("신규 데이터 입력 완료! %n%n");
  } else {
   System.out.printf("저장소 Full! %n%n");
  }  
  
  
 }
 
 //2. 회원 전체 출력
 public void menuSelect() {
  
  //출력 -> 저장소(배열)에 있는 모든 데이터
  /*
  for (int i=0; i<students.length; ++i) {
   Student student = students[i];
   if (student != null) {
    //System.out.println(student.toString());
    System.out.println(student);
   }
  }
  */

  System.out.printf("인원수:%d %n", this.count());
  System.out.println("---------------");
  System.out.println("이름 전화번호");
  System.out.println("---------------");
  for (Student student : students) {
   if (student != null) {
    System.out.println(student);
   }
  }
  System.out.println("---------------");
  System.out.println();
 }
 
 
 //인원수 메소드 -> private
 private int count() {
  int result = 0;
  
  //문제) 저장소(배열)에 들어있는 데이터의 갯수 확인
  for (int i=0; i<students.length; ++i) {
   Student student = students[i];
   if (student != null) {
    ++result;
   }
  }  
  
  return result;
 }
 
 
 //3. 회원 검색
 public void menuSearch(Scanner sc) {
  //외부 입력(name)
  System.out.print("name?");
  String name = sc.next();
  
  Student value = new Student();
  value.setName(name);
  
  //처리 -> 검색 액션
  //-> 배열 저장소 내에서 name이 일치하는 자료 검색
  //-> Student 자료형을 가진 객체 한 개
  Student result = null;
  for (int i=0; i<students.length; ++i) {
   Student temp = students[i];
   /*
   if (temp.getName().equals(name)) {
    result = temp;
    break;
   }
   */

   if (value.equals(temp)) {
    result = temp;
    break;
   }
   
  }
  
  //결과 출력
  if (result == null) {
   System.out.printf("검색 결과가 없습니다.%n%n");
  } else {
   /*
   System.out.printf("%s %s %n%n"
     , result.getName()
     , result.getTel());
   */
   
   /*
   System.out.println(result); //객체 정보
   System.out.println(result.toString()); //객체 정보
   */
   
   //toString() 메소드 호출시 객체 정보가 아니라
   //멤버변수의 데이터를 출력하는 용도로 변경
   //->오버라이딩
   System.out.println(result);
   System.out.println();
   
  }
 }

}

 

 


//Main.java
package com.sist;

import java.util.*;

public class Main {

 public static void main(String[] args) {
  
  Scanner sc = new Scanner(System.in);
  MenuAction menu = new MenuAction();
  
  do {
   System.out.println("--- 회원 정보 관리 ---");
   System.out.println("1. 회원 전체 출력");
   System.out.println("2. 회원 입력");
   System.out.println("3. 회원 검색");
   System.out.print("선택(1, 0-exit)?");
   int m = sc.nextInt();
   if (m==0) {
    break;
   }
   switch (m) {
   case 1: menu.menuSelect(); break;
   case 2: menu.menuInsert(sc); break;
   case 3: menu.menuSearch(sc); break;
   }
   
  }while(true);
  
  sc.close();

 }

}

 

 


----------------------------------------------------
요약

1. 멤버의 접근을 제한하는 제어자
- private
- (default)
- protected
- public

2. 멤버의 상태를 제한하는 제어자
- static
- final

3. private 생성자의 특징

4. final 키워드를 붙인 클래스, 멤버, 지역 변수의 특징

-------------------------------------------

 

 

 


 

블로그 이미지

알 수 없는 사용자

,