10.21.(금) Java-09: 클래스(1)

클래스(1)
맨 처음엔 우린 코드를 구성하는 가장 작은 단위인 변수에 대해 배우고, 그 다음엔 변수를 모아서 처리할 수 있는 명령의 단위인 함수를 배웠다. 이젠 이러한 변수들과 함수들을 묶을 수 있는 단위인 클래스를 배워보자.
class 클래스명{
문장들...
}
이클립스에서 class를 새로 만들때 항상 적혀있는 public class XXXX {} 또한 하나의 클래스이다.
이렇게 클래스를 나누는 이유는 같은 목적과 성질을 가진 변수 및 함수들을 묶어준 다음에, main함수에서 끌어다 쓸 수 있도록 나만의 라이브러리를 만드는 거라고 생각하면 된다.
사람에 대한 정보를 나열하는 데이터를 만들어보자.
package census;
class PersonInfo { // 구현클래스
public String name;
public int age;
public float height;
public void disp() { // 멤버변수를 출력해주는 함수
System.out.println(name);
System.out.println(age);
System.out.println(height);
}
}
public class Info {
public static void main(String[] args) { // 실행클래스
PersonInfo hong=new PersonInfo(); // 객체명 : 클래스에서 생성된 객체
hong.name="홍길동";
hong.age=27;
hong.height=188.2f;
hong.disp();
PersonInfo lee=new PersonInfo();
lee.name="이순신";
lee.age=28;
lee.height=176.3f;
lee.disp();
PersonInfo peng=new PersonInfo();
peng.name="펭수";
peng.age=10;
peng.height=210f;
peng.disp();
}
}
class들을 하나로 묶어주는 단위를 package라고 일단 알아놓고 살펴보자.
PersonInfo 클래스는 개인에 대한 정보(이름, 나이, 키)를 정리하는 함수이다. 이 클래스 안에는 이름, 나이, 키를 각각 name, age, height라는 변수에 넣을 수 있게 초기값으로 선언하고, 입력된 값을 출력할 수 있는 disp() 함수가 모여있다.
main함수에서 PersonInfo 클래스를 가져다 쓰려면, 클래스에서 객체를 생성해야지만 그 객체에다가 원하는 명령을 실행시킬 수 있다.
위 예시에서는 객체 hong을 생성해서 그 안에 홍길동이라는 사람의 정보를 선언했다.
객체의 변수 및 함수를 호출하는 방법은 객체명 뒤에 .을 붙이고 나서 불러오면 된다.
이렇게 하면 홍길동의 이름, 나이, 키에 대한 정보는 hong이라는 객체에 저장되고, 이 객체의 형식은 PersonInfo 라는 클래스를 따라간다.
그래서 우리는 main함수가 포함되어있는 Info 클래스를 실행클래스, PersonInfo 클래스는 구현클래스라고 부르기로 했다.
구현클래스를 다른 파일로 구분하기
모든 구현클래스들을 실행클래스와 함께 모아놓는다면 얼마나 지저분할지 생각해보자.
물론 cmd+f라는 아주 좋은 기능이 있지만, 각 클래스들 안에 있는 함수들 이름을 짜주는 것 부터 숨이 턱 막힐 것이다.
그래서 구현클래스를 하나의 package안에 존재하는 파일로 만들어서 실행클래스로 불러올 수 있다.
package Math;
public class Caculator {
public static void main(String[] args) {
}
}
위 예시는 Math 패키지 -> Calculator 실행클래스이다. 그리고 같은 Math 패키지 안에 Calculation 구현클래스를 만들어보자.
package Math;
public class Calculation {
public int su1;
public int su2;
public int sumResult;
public int subResult;
public int multResult;
public float divResult;
public void sum() {
sumResult=su1+su2;
}
public void sub() {
subResult=su1-su2;
}
public void mult() {
multResult=su1*su2;
}
public void div() {
divResult=(float) su1/su2;
}
public void disp() {
System.out.println(sumResult);
System.out.println(subResult);
System.out.println(multResult);
System.out.println(divResult + "\n");
}
}
Calculation 구현클래스 안에는 사칙연산에 필요한 변수들과 함수들을 만들고 마지막엔 출력해주는 함수까지 완성했다.
이제 이 구현클래스를 실행클래스에서 불러오기만 하면 된다.
package Math;
public class Caculator {
public static void main(String[] args) {
Calculation a=new Calculation();
Calculation b=new Calculation();
a.su1=10;
a.su2=20;
a.sum();
a.sub();
a.mult();
a.div();
a.disp();
b.su1=30;
b.su2=40;
b.sum();
b.sub();
b.mult();
b.div();
b.disp();
}
}
두가지의 연산을 진행할 예정이므로 a라는 객체와 b라는 객체를 각각 만들어 10과 20, 30과 40으로 사칙연산을 진행한 후 출력했다.
함수를 더 간결하게 만들기
실행클래스에서 일일이 객체.변수 형식으로 선언하기엔 너무 길고 가독성도 많이 떨어지기 때문에 이를 구현클래스로 넘겨서 선언하는 방법을 배워보자.
이는 구현클래스에 변수값을 입력받는 또 하나의 함수를 만들어서 해결할 수 있다.
학교에서 한 학생의 성적을 입력해서 시험 총점과 평균을 구해보자. 필요한 변수들은 학생의 번호, 이름, 국어, 수학, 영어 성적 순이다.
package mid_term;
public class Grade { // 클래스
public int number; // 필드 또는 멤버 변수
public String name;
public int kor;
public int eng;
public int math;
public int tot;
public float avg;
public void input(int Number, String Name, int Kor, int Eng, int Math) {
number=Number;
name=Name;
kor=Kor;
eng=Eng;
math=Math;
}
// 총점 담당 함수
public void total() { // 멤버함수
tot=kor+eng+math;
}
// 평균 담당 함수
public void avg() {
avg=(float) tot/3;
}
// 출력 담당 함수
public void disp() {
System.out.println(number + "번 " + name + "의 평균 성적은 " + avg + "점입니다.");
}
}
실행클래스의 main함수가 온갖 변수값들로 넘쳐흐르는걸 방지하기 위해, Grade 구현클래스에서 변수들을 선언해주고 일일이 값을 넣어줬다. 이렇게 되면 구현클래스에서 변수 선언, 처리, 출력 등 모든 명령을 만들고 실행클래스에선 가져다 쓰기만하면 된다.
package mid_term;
public class GPA {
public static void main(String[] args) {
Grade kim=new Grade(); // 클래스의 객체 생성
kim.input(1, "펭수", 70, 80, 95); // 값을 함수로 입력해준다
kim.total();
kim.avg();
kim.disp();
Grade park=new Grade();
park.input(2, "홍길동", 85, 98, 79);
park.total();
park.avg();
park.disp();
Grade lee=new Grade();
lee.input(3, "이하이", 97, 96, 99);
lee.total();
lee.avg();
lee.disp();
}
}
이렇게 다시보니 실행클래스에서 구현클래스에게 하청을 주는 것 같아보이기도 하다.
접근 제한자: public, private, protected(상속)
지금껏 모든 함수 앞에 붙어있던 public의 의미에 대해 알아보자.
사전적 의미 그대로 공개적으로 쓰일 수 있는 변수 또는 함수라는 것을 의미한다. 하지만 전부 다 public으로 선언하게 된다면, 나중에 프로젝트가 어마무시하게 커졌을때, 충돌이 일어나서 대참사가 벌어질 수 있다. 그럴때 쓰이는게 private 제한자이다.
private 제한자는 해당 변수와 함수가 객체 안에서만 적용되도록 바운더리를 정해주는 속성이다.
코드량이 방대해지면 이름이 겹쳐서 충돌하는 경우가 있을 수도 있기 때문에 대부분 private을 써줘서 꼬임을 방지한다.
변수의 90%는 private, 함수의 90%는 public이 쓰인다.
그러니까 이제부턴 객체안에 있는 변수에겐 public 대신 private을 붙여주도록 하자.
package privacy;
public class Person {
private String name;
private String address;
private String phoneNumber;
private String id; // 클래스 밖 외부에서 접근하지 못하게 설정
public void input(String Name, String Address, String PhoneNumber, String Id) {
name=Name;
address=Address;
phoneNumber=PhoneNumber;
id=Id;
}
public void disp() {
System.out.println(name);
System.out.println(address);
System.out.println(phoneNumber);
System.out.println(id);
}
}
package private;
public class PersonalInfo {
public static void main(String[] args) {
Person kim=new Person();
kim.input("김아무개", "서울시 강남구", "010-1234-5678", "981024-1111111");
kim.disp();
}
}
※ this. 키워드
지금 수준의 코드에서는 변수명을 안 겹치게 만들어내는게 크게 어렵지 않다. 하지만 우린 더 큰 물에서 놀기 위해 배우고 있기 때문에, 곱절은 복잡한 상황에 대비해야한다. 만약 더 이상 겹치지 않고서 연관성있게 이름을 지을 수 없을땐 결국 연관성이 없는 이름으로 지어야할텐데, 이렇게되면 나중에 찾아서 고치기도 힘들 것이다. 이를 도와주기 위해 필요한 것이 this.이다.
this.는 객체 자기 자신을 표현하는 속성이다. 위 예시를 보며 어떻게 쓰는건지 알아보자.
package privacy;
public class Person {
private String name;
private String address;
private String phoneNumber;
private String id; // 클래스 밖 외부에서 접근하지 못하게 설정
public void input(String Name, String Address, String PhoneNumber, String Id) {
name=Name;
address=Address;
phoneNumber=PhoneNumber;
id=Id;
}
public void disp() {
System.out.println(name);
System.out.println(address);
System.out.println(phoneNumber);
System.out.println(id);
}
}
input 함수를 통해 변수값을 전달받을때 변수명이 겹치면 안돼서 전달받는 변수들은 첫글자를 대문자로 바꿔서 적었다.
하지만 이젠 this.가 있기 때문에 귀찮게 첫글자만 대문자로 바꿀 필요없다.
package privacy;
public class Person {
private String name;
private String address;
private String phoneNumber;
private String id; // 클래스 밖 외부에서 접근하지 못하게 설정
public void input(String name, String address, String phoneNumber, String id) {
this.name=name;
this.address=address;
this.phoneNumber=phoneNumber;
this.id=id;
}
public void disp() {
System.out.println(name);
System.out.println(address);
System.out.println(phoneNumber);
System.out.println(id);
}
}
input함수 안의 this.name을 비롯해서 this.가 붙은 변수들은 private속성을 가진 변수들이고, 괄호 안에 나열되어있는 자료형 변수들은 실행클래스에서 끌어오는 값들이다.
이제는 this.를 통해서 객체에서 선언된 변수와 외부에서 끌어오는 변수들을 구분할 수 있게 됐다.