06_객체(캡슐화)
*setter 메소드
Student 클래스
package com.kh.chap02.encapsulation.model.vo;
// 캡슐화 과정을 거친 Student 클래스
public class Student {
// 필드부
/*
* 필드: 클래스 안에 바로 선언해 두는 변수
* (== 멤버변수 == 인스턴스 변수)
*
* [ 표현법 ]
* 접근제한자 자료형 필드명;
*/
private String name;
private int age;
private double height;
// 생성자부
// 메소드부
/*
* 각 기능(기능 단위 == 메소드)을 구현하는 부분
*
* [ 표현법 ]
* 접근제한자 반환형 메소드명(매개변수 => 생략 가능하나 적을 때는 짝 맞춰서 값 잘 넣어 줘야 함) {
*
* 기능 구현 코드;
*
* 반환형이 있다면 return 돌려줄값;
* }
*
* 반환형: 출력되는(가지고 오는) 자료형의 결과값
* (반환형과 돌려줄값은 일치해야 함)
* 매개변수: 입력되는(들어오는) 값
*/
// setter 메소드: 데이터를 기록 및 수정하는 용도의 메소드
// getter 메소드: 데이터를 반환해 주는 기능의 메소드
// => setter / getter 메소드는 항상 접근 가능해야 하기 때문에 public으로 써야 함
// => 필드 한 개당 setter와 getter 메소드를 1개씩 !꼭! 만들어 줘야 함
// setter 메소드: 주로 대입이 일어남
// 각각 String name, int age, double height에 대하여 만들기
// 이름값을 기록 및 수정할 수 있는 메소드(name 필드에 대입하는 용도)
public void setName(String name) {
// setter는 기록/수정용이기 때문에 반환할 반환형이 없음! 항상 void를 씀
// name = "홍길동";
// 이렇게 쓰면 setName 메소드에 무조건 홍길동만 입력되기 때문에 이러면 안 됨!
// 매개변수에 입력받을 값을 넣은 뒤
this.name = name;
// this에는 현재 나의 주소값이 담김
}
/*
* [ 표현법 ]
* public void set필드명(해당필드의자료형 해당필드명과동일한매개변수명) {
*
* this.필드명 = 매개변수명;
* }
*
* => 필드명 앞에는 항상 this. (나의 주소값)을 붙여 줘야 함
* => 메소드 영역 안에서는 이름이 같을 때 매개변수 (일종의 지역변수 개념) 의 우선순위가 높게 지정되기 때문에
* 구분 용도로 필드명 앞에는 this.을 붙여야 함 반드시!
*/
// 나이값을 기록 및 수정할 수 있는 메소드(age 필드에 대입하는 용도)
public void setAge(int age) {
this.age = age;
}
// 키값을 기록 및 수정할 수 있는 메소드(height 필드에 대입하는 용도)
public void setHeight(double height) {
this.height = height;
}
}
Run 클래스
package com.kh.chap02.encapsulation.run;
import com.kh.chap02.encapsulation.model.vo.Student;
public class Run {
/*
* 7. 캡슐화 작업을 통해서 완벽한 클래스의 형태를 갖추게 하자!
*
* 캡슐화를 하지 않으면: 외부로부터 직접 접근이 가능하기 때문에 함부로 값이 조회/변경될 수 있음
* => 이 이슈를 막기 위해 캡슐화 작업을 해야 함!
*
* *객체지향 설계 원칙 중 하나가 "정보은닉" => 캡슐화 작업을 통해 진행
* *데이터의 직접 접근을 막을 것! 단, 간접적으로 접근할 수 있게끔은 해 줘야 함
* => 메소드를 활용하여 간접적으로 접근할 수 있게 하자!
*
* 캡슐화 작업
* 1) 정보 은닉 단계: 필드들의 접근제한자를 private으로 변경하기
* 외부로부터 필드들의 직접 접근을 막기 위해 항상 필드들의 접근제한자는 public이 아닌 private를 쓴다!
* 2) setter / getter 메소드 만들기: 간접적으로나마 접근해서 값을 대입하거나 (setter: 세팅하는 애)
* 그 값을 가지고 올 수 있는 메소드를 (getter: 가지고 오는 애) 만들어야 한다!
*/
public static void main(String[] args) {
Student hong = new Student(); // 객체를 생성한다 (== 인스턴스화 한다)
/*
*직접 대입
hong.name = "홍길동"; // is not visible 오류 발생
hong.age = 20;
hong.height = 168.7;
*직접 조회
System.out.println(hong.name);
System.out.println(hong.age);
System.out.println(hong.height);
*/
// 위와 같이 대입을 직접적으로 했을 경우 또는 조회를 직접적으로 했을 경우
// 우리가 private으로 접근 제한을 막아 버렸기 때문에
// .(직접접근연산자)를 통해 필드에 접근이 불가능해짐
// => 간접적으로나마 메소드를 통해 접근이 가능하도록 해야 함
hong.setName("홍길동");
hong.setAge(20);
hong.setHeight(168.7);
}
*getter 메소드
Student 클래스
// getter 메소드: 필드에 들은 값을 외부로 반출시키는 용도 (가지고 나가겠다)
// 주로 필드값을 반환시키는 구문히 작성됨
// String name, int age, double height에 대해서 작성
// name 필드에 들어 있는 값을 돌려주는 용도의 메소드
public String getName() {
return name; // name 값을 들고 돌아가겠다( == 결과값을 돌려주겠다)
}
/*
* [ 표현법 ]
* public 해당필드의자료형 get필드명() {
*
* return 필드명;
* }
*
* => getter 메소드에서는 필드명 앞에 this. 을 붙이지 않음
* 굳이 이름을 구분할 매개변수가 없기 때문
*/
// age 필드에 들은 값을 돌려주는 용도의 메소드
public int getAge() {
return age;
}
// height 필드에 들은 값을 돌려주는 용도의 메소드
public double getHeight() {
return height;
}
// => setter와 getter 메소드까지 만들어 주는 과정까지가 캡슐화이다!
Run 클래스
public static void main(String[] args) {
Student hong = new Student(); // 객체를 생성한다 (== 인스턴스화 한다)
/*
*직접 대입
hong.name = "홍길동"; // is not visible 오류 발생
hong.age = 20;
hong.height = 168.7;
*직접 조회
System.out.println(hong.name);
System.out.println(hong.age);
System.out.println(hong.height);
*/
// 위와 같이 대입을 직접적으로 했을 경우 또는 조회를 직접적으로 했을 경우
// 우리가 private으로 접근 제한을 막아 버렸기 때문에
// .(직접접근연산자)를 통해 필드에 접근이 불가능해짐
// => 간접적으로나마 메소드를 통해 접근이 가능하도록 해야 함
hong.setName("홍길동");
hong.setAge(20);
hong.setHeight(168.7);
// 간접적으로 조회할 수 있게 도와주는 getter 메소드를 호출
// String name = hong.getName();
System.out.println(hong.getName());
System.out.println(hong.getAge());
System.out.println(hong.getHeight());
// xxx님의 나이는 xx살이고, 키는 xxxcm입니다.
System.out.println(hong.getName() +" 님의 나이는 " + hong.getAge() + "살이고, 키는 " + hong.getHeight() + "cm입니다.");
}
*setter와 getter처럼 필수는 아니지만 편의상 이용하기 좋은 (원하는 구조의) 출력문 메소드 만들기
Student 클래스
// 모든 필드값들을 하나의 문자열로 연이어서 돌려 주는 용도의 메소드
// => 캡슐화 과정은 아니기 때문에 필수는 아님! 있으면 편리하니까 꼭 만들자
// 접근제한자 반환형 메소드명(매개변수) {
// return 리턴값;
// }
public String information() {
// return name, age, height; // 한 번에 한 개의 값만 리턴 가능함
return name + " 님의 나이는" + age + "살이고, 키는 " + height + "cm입니다.";
// 그래서 하나의 문자열로 만든 후에 리턴!
}
Run 클래스
public static void main(String[] args) {
Student hong = new Student(); // 객체를 생성한다 (== 인스턴스화 한다)
hong.setName("홍길동");
hong.setAge(20);
hong.setHeight(168.7);
System.out.println(hong.getName());
System.out.println(hong.getAge());
System.out.println(hong.getHeight());
// xxx님의 나이는 xx살이고, 키는 xxxcm입니다.
// System.out.println(hong.getName() +" 님의 나이는 " + hong.getAge() + "살이고, 키는 " + hong.getHeight() + "cm입니다.");
System.out.println(hong.information());
Student kim = new Student();
kim.setName("김영희");
kim.setAge(21);
kim.setHeight(180.4);
//System.out.println(kim.getName() + " 님의 나이는 " + kim.getAge() + "살이고, 키는 " + kim.getHeight() + "cm입니다.");
System.out.println(kim.information());
}
클래스 다이어그램을 보고 클래스를 작성할 줄 알아야 함
Person 클래스
package com.kh.chap03.class_.model.vo;
public class Person {
// 필드부
// 필드 == 멤버변수 == 인스턴스변수
// 1. 필드 만들기
private String id;
private String pwd;
private String name;
private int age;
private char gender;
private String phone;
private String email;
// 생성자부
// 메소드부
// 2. setter, getter 메소드 만들기
// 각 필드에 대입시키고자 하는 값을 전달받아서 해당 필드에 대입시켜 주는 setter 메소드 7개ㅑ
// setter 메소드명: setXXX (낙타표기법)
public void setId(String id) {
this.id = id;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setGender(char gender) {
this.gender = gender;
}
public void setPhone(String phone) {
this.phone = phone;
}
public void setEmail(String email) {
this.email = email;
}
// 각 필드값을 돌려 주는 getter 메소드 7개
// getter 메소드명: getXXX (낙타표기법)
public String getId() {
return id;
}
public String getPwd() {
return pwd;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public char getGender() {
return gender;
}
public String getPhone() {
return phone;
}
public String getemail() {
return email;
}
// => 캡슐화 작업 끝!
// 3. information 메소드 만들기
// 모든 필드값을 하나의 문자열로 연이어서 반환해 주는 information 메소드
public String information() {
return "id: " + id + ", pwd: " + pwd + ", name: " + name + ", age: " + age
+ ", gender: " + gender + ", phone: " + phone + ", email: " + email;
}
}
Run 클래스
package com.kh.chap03.class_.run;
import com.kh.chap03.class_.model.vo.Person;
public class Run {
public static void main(String[] args) {
// Person이라는 클래스
// == 사람의 정보를 담고자 내가 만든 나의 자료형
// (여러 개의 자료형, 여러 개의 값들을 보관 가능)
// == 사용자 정의 자료형 (커스터마이징)
Person p = new Person(); // 객체 생성 == 인스턴스화
System.out.println(p); // 주소값
System.out.println(p.information()); // 초기값, JVM에 의해 채워진 기본값들이 출력
// => 값 대입을 안 해서 기본값이 출력된 것이므로 메소드가 잘 만들어진 것임을 알 수 있음!
// 값 넣기 => setter 메소드
p.setId("user01");
p.setPwd("pass01");
p.setName("홍길동");
System.out.println(p.information()); // id, pwd, name만 입력되고 나머지는 기본값 출력됨
p.setAge(25);
p.setGender('남');
p.setPhone("010-1111-2222");
p.setEmail("hong@naver.com");
System.out.println(p.information());
*변수 구분
- 전역변수(== 필드): 클래스 영역에 바로 선언하는 변수 => 클래스 내에서면 어디서든 사용 가능
- 지역변수: 클래스 영역 내의 어떤 특정한 구역 ({})에 선언한 변수 => 메소드 역역 안, if문 블럭 안, for문 블럭 안, for문 초기식, 매개변수, ...
1. 전역변수
- 멤버변수(== 필드 == 인스턴스변수): 일반 필드의 개념
생성 시점: new 연산자를 통해 해당 객체를 생성하는 순간 메모리의 heap 영역에 할당됨
소멸 시점: 연결이 끊긴 후 가비지 컬렉션이 일어나는 순간 소멸(객체가 소멸되는 순간)
- 클래스변수(== static변수): static이라는 예약어가 붙은 변수
생성 시점: 프로그램 시작과 동시에 메모리의 static 영역에 생성됨 (해당 객체가 생성이 되지 않더라도 바로 가져다 쓸 수 있는 개념)
소멸 시점: 프로그램 종료 시 소멸
2. 지역변수
생성 시점: 특정한 구역 ({}) 실행 중 메모리 stack 영역에 할당
소멸 시점: 특정한 구역({}) 종료 시 값이 소멸
필드 테스트
FieldTest1 클래스
package com.kh.chap04.field.model.vo;
// 변수 선언 위치에 따른 구분 (전역변수, 지역변수, 매개변수)
public class FieldTest1 {
// 멤버변수( == 필드 == 인스턴스 변수)
public int global;
// 매개변수: 일종의 지역변수 개념
public void test(int num) {
// 지역변수: 반드시 초기화
int local = 0; // local이 생성 및 초기화
// 멤버변수 출력
System.out.println(global); // public int global; 시점에 JVM에서 알아서 초기화시킴
// 지역변수 출력
System.out.println(local); // 지역변수는 int local = 0;과 같이 항상 생성 및 초기화 해 주어야 함
// 매개변수 출력
System.out.println(num); // Run 클래스에서 f1.test(10);을 실행할 때 알아서 그 시점에서 대입된 후 실행됨
}
}
FieldRun 클래스
package com.kh.chap04.field.run;
import com.kh.chap04.field.model.vo.FieldTest1; // (2) import 하기
public class FieldRun {
public static void main(String[] args) {
// 1. FieldTest1 클래스 테스트
FieldTest1 f1 = new FieldTest1(); // (1) 객체 만들기
// 이 시점에서 객체가 생성 시 f1의 global이 생성, 초기화(대입)된 것
f1.test(10); // test 메소드 호출 시 num이라는 매개변수에 10이 대입된 것
//System.out.println(num); // 메소드가 종료되었기 때문에 소멸
//System.out.println(local); // 메소드가 종료되었기 때문에 소멸
System.out.println(f1.global); // 아직 소멸되지 않음
// 연결고리를 끊겠다 == 객체를 소멸했다
f1 = null;
System.out.println(f1.global); // NullPointerException 발생
// 이 시점에서 가비지 컬렉션이 일어나면 global 값도 소멸될 예정임!
}
}
변수 생성 시점
접근제한자
* (+)public: 어디서든(같은 패키지/클래스, 다른 패키지/클래스 모두) 접근 가능
* (#)protected: 같은 패키지 내부에서는 무조건 접근 가능,
다른 패키지에 있는 클래스에서 접근하고 싶다면 적어도 그 클래스는 가져다 쓰고 싶은 클래스와 상속 구조를 이루어야 함
(상속은 다음 시간에 배움!)
* (~)default: 오직 같은 패키지 내에서만 접근 가능
* (-)private: 오직 해당 클래스 내에서만 접근 가능
=> 위에서부터 아래로 내려갈수록 접근할 수 있는 제한 범위가 좁아짐
=> +, #, ~, -: 클래스 다이어그램에서의 기호
FieldTest2 클래스
package com.kh.chap04.field.model.vo;
// 필드에서 사용 가능한 접근제한자 종류 4가지
public class FieldTest2 {
/*
* (+)public: 어디서든(같은 패키지/클래스, 다른 패키지/클래스 모두) 접근 가능
* (#)protected: 같은 패키지 내부에서는 무조건 접근 가능,
* 다른 패키지에 있는 클래스에서 접근하고 싶다면
* 적어도 그 클래스는 가져다 쓰고 싶은 클래스와 상속 구조를 이루어야 함
* (상속은 다음 시간에 배움!)
* (~)default: 오직 같은 패키지 내에서만 접근 가능
* (-)private: 오직 해당 클래스 내에서만 접근 가능
*
* => 위에서부터 아래로 내려갈수록 접근할 수 있는 제한 범위가 좁아짐
* => +, #, ~, -: 클래스 다이어그램에서의 기호
*/
public String pub = "public";
protected String pro = "protected";
String df = "default"; // default를 쓰면 오류 남! 없는 게 기본값...!
private String pri = "private";
}
FieldRun 클래스
package com.kh.chap04.field.run;
import com.kh.chap04.field.model.vo.FieldTest2;
public class FieldRun {
public static void main(String[] args) {
FieldTest2 f2 = new FieldTest2();
System.out.println(f2.pub); // public: 어디서든 직접 접근 가능
// 이 아래부터는 is not visible 오류 발생
// System.out.println(f2.pro); // protected: 같은 패키지에서는 직접 접근 가능
// 다른 패키지에서는 상속 관계일 때만 가능
// System.out.println(f2.df); // default: 같은 패키지에서만 직접 접근 가능
// System.out.println(f2.pri); // private: 해당 클래스 내에서만 직접 접근 가능
}
}
Test 클래스
package com.kh.chap04.field.model.vo;
public class Test {
public static void main(String[] args) {
FieldTest2 f2 = new FieldTest2();
System.out.println(f2.pub); // public: 직접 접근 가능
System.out.println(f2.pro); // protected: 같은 패키지에 있기 때문에 직접 접근 가능
System.out.println(f2.df); // default: 직접 접근 가능
// is not visible 오류 발생
// System.out.println(f2.pri);
}
}
*클래스 변수(static 변수)
[ 표현법 ]
접근제한자 static 자료형 변수명;
FieldTest3 클래스
package com.kh.chap04.field.model.vo;
// 클래스변수(static 변수)와 상수필드(static final)에 대해 테스트
public class FieldTest3 {
public static String sta = "static 변수";
// 생성 시점: 프로그램 시작과 동시에 static 영역에 올라가면서 생성
// (굳이 이 객체를 생성하지 않아도 가져다 쓸 수 있다)
// 소멸 시점: 프로그램 종료와 동시에 소멸됨
// static: "공유"의 목적, 개념이 강함
// => 프로그램 시작과 동시에 메모리 영역에 박스를 만들어 두고 끝날 때까지 공유해서 쓰자
// => 주로 어디서든지 자주 쓰이는 것들에 대해서만 static 붙여서 쓰는 게 가장 이득임
// 참고) 해당 클래스의 모든 메소드와 모든 필드가 static인 경우
// => Math 클래스
// => "싱글톤패턴"
/*
* 상수 필드
* [ 표현법 ]
* public static final 자료형 상수필드명 = 값;
*
* 한 번 지정된 값을 고정해서 계속 가져다 쓰기 때문에 처음부터 무조건 초기화를 해 줘야 함
* static final 예약어의 순서는 바꿔서 써도 됨 (final static도 가능)
*
* static: 공유의 개념
* final: 한 번 지정된 값은 고정의 개념(상수)
*
* => 값이 변경되어서는 안 되는 고정적인 값을 메모리 static 영역에 올려 두고
* 두고두고 공유할 목적으로 사용
*
* + 상수명은 항상 대문자임!
*/
public static final int NUM = 10;
public static void test() {
System.out.println("나는 static 메소드야");
}
}
FieldRun 클래스
package com.kh.chap04.field.run;
import com.kh.chap04.field.model.vo.FieldTest3;
public class FieldRun {
public static void main(String[] args) {
// 3. FieldTest3 클래스 테스트
// FieldTest3 f3 = new FieldTest3();
// => 싱글톤 패턴: 모든 필드가 static인 상황이므로 객체 생성할 필요 없음!
System.out.println(FieldTest3.sta);
System.out.println(FieldTest2.sta);
// 항상 Static을 찾을 때에는 해당 클래스명은 앞에 꼭 붙여야 함
// => 이름이 중복될 수 있기 때문에!
// 상수 필드에 값을 대입하기!
//FieldTest3.NUM = 20; // 불가능! 상수는 바꿀 수 없음!
FieldTest3.sta = "FieldTest3의 static"; // 가능!
System.out.println(FieldTest3.sta);
System.out.println(FieldTest3.NUM);
// static 메소드도 호출해 보기
FieldTest3.test();
// => 메소드도 마찬가지로 객체를 생성할 필요 없이 클래스명만으로 호출 가능
System.out.println(Math.PI); // 원주율
}
}
이클립스에서 control 클릭 뒤에 함수 위에 마우스 올려 보면 정의나 코딩창을 확인 가능함!