클래스와 인스턴스
🤔 클래스란?
- 클래스란 객체를 정의하는 틀 또는 설계도입니다.
-> 클래스(Class) = 데이터(Data) + 메소드(Method)로 구성되어 있습니다.
1. 데이터(Data) = 프로그램 상에서 유지되고 관리해야 할 데이터
2. 메소드(Method) = 데이터를 처리하고 조작하는 기능
- 데이터는 "변수"를 통해 유지 및 관리되고, 변수에 저장된 값(데이터)들은 "메소드의 호출"을 통해 처리가 됩니다.
- 다음의 코드를 통해 살펴봅시다.
💻 예시 코드
public class BankAccountPO {
static int balance = 0; //예금 잔액
public static void main(String[]args){
deposit(10000); //입금 진행
checkMyBalance(); //잔액 확인
withdraw(3000); //출금 진행
checkMyBalance(); //잔액 확인
}
//입금을 담당하는 메소드
public static int deposit(int amount){
balance +=amount;
return balance;
}
//출금을 담당하는 메소드
public static int withdraw(int amount){
balance -= amount;
return balance;
}
//예금 조회를 담당하는 메소드
public static int checkMyBalance(){
System.out.println("잔액: " + balance);
return balance;
}
}
📸 출력 결과
잔액: 10000
잔액: 7000
👩🏻🏫 설명
- 위의 예를 살펴보면 클래스의 처음에 다음과 같이 변수를 선언하였습니다.
public class BankAccountPO{
static int balance = 0; //예금 잔액(클래스 변수)
}
- 그리고 메소드 deposit(입금) ,withdraw(출금),chekMy Balanc(예금조회)를 통해서 선언된 클래스 변수 balance의 데이터 값에 접근하는 것을 확인할 수 있습니다.
해당 코드를 통해 우리는 2가지 사실을 알 수 있습니다.
1. 변수 balance가 가지고 있는 값은 프로그램에서 사용하는 데이터이다.
2. 메소드 deposit(입금) ,withdraw(출금),chekMy Balanc(예금조회)는 프로그램에서 데이터를 가지고 무엇인가를 수행하는 "기능”의 역할을 한다.
- 또한 더 크게 넓혀 다음과 같이 생각할 수 있습니다.
“메소드 deposit(입금) ,withdraw(출금),chekMy Balanc(예금조회)는 변수 balance를 위한 메소드이다”
“변수 balance의 값들은 메소드들(입금, 출금, 예금 조회)와 긴밀한 관계가 있다."
- 이처럼 클래스는 연관되어 있는 변수와 메소드들을 묶기 위해 사용합니다.
-> 클래스를 이용하면 변수 balance, 변수와 관련된 모든 메소드를 하나로 묶을 수 있습니다.
- 아래와 같은 코드들을 클래스 정의라고 합니다.
💻 예시 코드
/*
클래스 정의
*/
classs BankAccount{
int balance = 0; //예금 잔액
public int deposit(int amount) { //변수 balance와 연관 있는 메소드
return balance;
}
public int withdraw(int amount) { //변수 balance와 연관 있는 메소드
balance -= amount;
return balance;
}
public int checkMyBalance(){ //변수 balance와 연관 있는 메소드
System.out.println("잔액: "+ balance);
return balance;
}
}
클래스의 구성과 인스턴스화
- 위에서 본 클래스 BankAccount의 클래스 정의를 뜯어 봅시다.
class BankAccount{
//인스턴스 변수
int balance = 0;
//인스턴스 메소드
public int deposit(int amount) {....}
public int withdraw(int amount) {....}
public int checkMyBalance () {....}
}
- 클래스 내부에 위치한 변수와 메소드를 가리켜 각각 다음과 같이 부릅니다.
1. 인스턴스 변수 = 클래스 내에 선언된 변수
2. 인스턴스 메소드 = 클래스 내에 정의된 메소드
- 인스턴스 변수는 메소드 내부에 선언된 것이 아니기에 지역변수가 아닙니다.
- 따라서 다음과 같은 특징을 가집니다.
-> "인스턴스 변수는 같은 클래스 내에 위치한 메소드 내에서 접근이 가능하다"
👨🏻🏫 추가 설명 - 필드
- 인스턴스 변수는 다음과 같이 불리기도 합니다.
-> 멤버 변수, 필드(Field)
- 클래스를 객체를 정의하는 틀 또는 설계도라고 설명했습니다.
- 이번에는 다음의 설명을 통해 클래스를 자세하게 이해해봅시다.
예시
- 클래스 = 붕어빵 모향의 틀,
-> 우리는 붕어빵 틀을 통해 붕어빵을 만들어 낼 수 있습니다.
-> 붕어빵 틀은 붕어빵이 아니듯이 클래스를 정의 했더라도 그 안에 위치한 변수나 메소드를 사용할 수 있는 것은 아닙니다.
-> 틀을 이용해 빵을 만들 듯이 인스턴스(객체)라는 것을 찍어내야 사용이 가능합니다.
- 아래의 코드를 살펴 봅시다.
new BankAccount(); //클래스 BankAccount의 인스턴스화
👩🏻🏫 설명
- 위의 문장을 실행하면 BankAcoount에 정의된 메소드를 담고 있는 인스턴스(객체)라는 것이 생성됩니다.
- 인스턴스(객체)가 만들어져 실제 메모리 공간에 존재하게 됩니다.
다시 한번 아래의 코드를 살펴봅시다.
new BankAccount() ; //BankAccount 인스턴스 1
new BankAccount(); //BankAccount 인스턴스 2
👩🏻🏫 설명
- 위와 같이 인스턴스를 생성해 냈습니다. 하지만 메모리상에 인스턴스를 만들기만해서는 사용할 수 없습니다.
- 인스턴스를 참조할 무엇인가를 필요합니다. 이것을 가리켜 “참조 변수”라고 합니다.
👨🏻🏫 추가설명 - 인스턴스와 객체
객체란?
- 물리적으로 존재할 수 있거나, 추상적으로 생각할 수 있는 것 중 "자신만의 속성을 가지고 있고 다른 것과 식별 가능한 것"을 의미합니다.
인스턴스란?
- 클래스를 이용하여 힙 영역에 생성한 새로운 인스턴스를 의미합니다.
-> 즉, 인스턴스란 클래스를 이용해 구현한 것을 의미합니다.
- 클래스 BankAccount의 참조 변수를 선언하는 방법은 다음과 같습니다.
BankAccount myAcnt; //참조변수 myAcnt의 선언
- 즉, 다음과 같이 참조변수를 선언하고 이를 통해서 새로 생성되는 인스턴스(객체)를 가리키게 할 수 있습니다.
BankAccount myAcnt1; //1. 참조변수 myAcnt1 선언
BankAccount myAcnt2; //1. 참조변수 myAcnt2 선언
//2. 참조변수 myAcnt1이 새로 생성되는 인스턴스를 가리킴
myAcnt1 = new BankAccount();
//2. 참조변수 myAcnt2가 새로 생성되는 인스턴스를 가리킴
myAcnt2 = new BankAccount();
👩🏻🏫 설명
- 키워드 new를 통해 객체를 생성하면 생성된 인스턴스의 주솟값이 반환됩니다.
- 참조 변수는 생성된 객체의 주소값이 저장됩니다.
- 또한 다음과 같이 참조 변수의 선언과 인스턴스의 생성을 한 문장으로 표현할 수 있습니다.
BankAccount myAcnt1 = new BankAccount();
BankAccount myAcnt2 = new BankAccount();
- 그리고 참조변수를 이용해서 해당 인스턴스의 메소드를 호출하는 방법은 다음과 같습니다.
myAcnt1.deposit(1000); //myAcnt1이 참조하는 인스턴스의 deposit 호출
myAcnt2.deposit(2000); //myAcnt2가 참조하는 인스턴스의 deposit 호출
- 다음의 코드를 통해 자세히 살펴 봅시다.
💻 예시 코드
class BankAccount{
int balance = 0; //예금 잔액
public int deposit(int amount){
balance += amount;
return balance;
}
public int withdraw(int amount){
balance -= amount;
return balance;
}
public int checkMyBalance(){
System.out.println("잔액: " + balance);
return balance;
}
}
public class BankAccountOO {
public static void main(String []args) {
//2개의 인스턴스 생성
BankAccount yoon = new BankAccount();
BankAccount park = new BankAccount();
//각 인스턴스를 대상으로 예금을 진행
yoon.deposit(5000);
park.deposit(3000);
//각 인스턴스를 대상으로 출금을 진행
yoon.withdraw(2000);
park.withdraw(2000);
//각 인스턴스를 대상으로 잔액을 조회
yoon.checkMyBalance();
park.checkMyBalance();
}
}
📸 출력 결과
잔액: 3000
잔액: 1000
👩🏻🏫 설명
- 위의 코드를 통해 실행해보면 참조변수 yoon과 park이 가리키는 인스턴스가 서로 다른 인스턴스임을 알 수 있습니다.
참조변수의 특성
- 앞서 살펴 봤던 변수는 저장된 값(데이터)를 바꿀 수 있었습니다. 마찬가지로 참조변수도 변수입니다.
- 따라서 참조변수도 변수가 가진 특성과 동일하게 참조하는 인스턴스를 변경할 수 있습니다.
BankAccount yoon = new BankAccount();
~~
yoon = new BankAccount(); //yoon이 새 인스턴스를 참조한다.
~~~
- 또한 다음과 같이 참조변수가 가지고 있는 값을 다른 참조변수에 대입하여 하나의 인스턴스를 둘 이상의 참조변수가 동시에 참조하는 것도 가능합니다.
BankAccount ref1 = new BankAccount();
BankAccount ref2 = ref1;
다음의 코드를 통해서 살펴 봅시다.
💻 예시 코드
class BankAccount2{
int balance = 0;
public int deposit(int amount){
balance += amount;
return balance;
}
public int withdraw(int amount){
balance -= amount;
return balance;
}
public int checkMyBalance(){
System.out.println("잔액: " + balance);
return balance;
}
}
public class DupRef {
public static void main(String[]args){
BankAccount2 ref1 = new BankAccount2();
BankAccount2 ref2 = ref1; //ref1이 참조하는 대상을 ref2도 참조
ref1.deposit(3000);
ref2.deposit(2000);
ref1.withdraw(400);
ref2.withdraw(300);
ref1.checkMyBalance();
ref2.checkMyBalance();
}
}
📸 출력 결과
- 위의 코드에서 출력 결과를 통해 두 개의 참조변수 ref1과 ref2가 하나의 인스턴스를 참조하고 있음을 확인할 수 있습니다.
잔액: 4300
잔액: 4300
참조변수의 매개변수 선언
- 메소드는 매개변수를 통해 호출할 때 값을 전달할 수 있고 반환받을 수도 있습니다.
- 이와 유사하게 메소드를 호출하면서 인스턴스의 참조값을 전달하는 것도 가능합니다.
- 다음의 코드를 통해서 자세히 살펴봅시다.
💻 예시 코드
class BankAccount3{
int balance = 0; //예금 잔액
public int deposit(int amount){
balance += amount;
return balance;
}
public int withdraw(int amount){
balance -= amount;
return balance;
}
public int checkMyBalance(){
System.out.println("잔액 : " + balance);
return balance;
}
}
public class PassRef {
public static void main(String[] args){
BankAccount3 ref = new BankAccount3();
ref.deposit(3000);
ref.withdraw(300);
check(ref); //'참조 값'의 전달
}
public static void check(BankAccount3 acc){
acc.checkMyBalance();
}
}
📸 출력 결과
잔액 : 2700
👩🏻🏫 설명
- 메소드 check의 매개변수로 BankAccount의 참조변수가 선언되었습니다.
- 이 메소드는 인자로 매개변수의 참조 값을 전달받습니다.
- 따라서 메소드 내에서는 전달된 참조 값의 인스턴스를 대상으로 메소드를 호출할 수 있습니다.
🤔 참조변수에 null 대입을 한다면?
- 참조 변수에 null을 선언하면 참조하는 인스턴스와의 관계를 모두 끊습니다.
BankAccount ref = new BankAccount();
~
ref = null; //ref가 참조하는 인스턴스와의 관계를 끊음
생성자(Constructor)와 String 클래스의 소개
🤔 String 클래스란?
- 문자열을 다루는 클래스입니다.
- 문자열은 하나 이상의 문자의 모임을 의미하며 큰 따옴표( “ “)로 사용합니다.
ex) “abcdef”;
- 문자열은 다음과 같이 참조 변수를 선언해서 참조할 수도 있습니다.
- 참조변수 myName이 문자열 "아사비치즈스틱"을 가리키는 상황입니다.
String myName = "아사비치즈스틱"; //String형 참조변수의 문자열 참조
- 이와 관련하여 다음의 예를 살펴봅시다.
💻 예시 코드
public class FirstStringIntro {
public static void main(String[] args) {
//문자열 선언과 동시에 참조변수로 참조한다.
String str1 = "Happy";
String str2 = "Birthday";
System.out.println(str1 + " " + str2);
//메소드에 문자열을 전달하는 상황
printString(str1);
printString(" ");
printString(str2);
printString("\\n");
printString("End of program~ \\n");
}
//String 참조변수를 매개변수로 선언하여 문자열을 전달 받을 수 있다.
public static void printString(String str){
System.out.print(str);
}
}
📸 출력결과
Happy Birthday
Happy Birthday
End of program~
👩🏻🏫 설명
- 위의 예를 통해 다음의 두가지 사실을 알 수 있습니다.
- 문자열을 메소드의 인자로 전달할 수 있다.
- 매개변수로 String형 참조변수를 선언하여 문자열을 인자로 전달받을 수 있다.
❓각 인스턴스를 구분할 수 있는 상황이 필요하다면?
- 앞서 예를 든 BankAccount클래스를 다시 살펴봅시다.
- 평소 은행에서는 고객이 계좌를 개설할 때마다 아래의 코드의 인스턴스를 생성해야 합니다.
class BankAccount{
int balance =0; //예금 잔액
public int deposit(int amount) {
balnce += amount;
return balance;
}
public int withdraw(int amount) {
~
}
public int checkMyBalance() {
~
}
- 그런데 문제는 인스턴스를 생성하면 누구의 계좌인지 구별할 수 있는 정보가 빠졌습니다.
- 따라서 위의 클래스에는 계좌의 주인이 누구인지 구분할 수 있는 정보가 추가되어야 합니다.
1. 계좌번호 = String AccNumber
2. 주민번호 = String ssNumber
- 이를 반영하여 BankAccount를 수정한 결과는 다음과 같습니다.
💻 예시 코드
class BankAccount4{
String accNumber; //계좌번호
String ssNumber; //주민번호
int balance = 0; //예금 잔액
/*
초기화를 위한 메소드
*/
public void initAccount(String acc, String ss, int bal){
accNumber = acc;
ssNumber = ss;
balance = bal; //계좌 개설 시 예금액으로 초기화
}
public int deposit(int amount){
balance += amount;
return balance;
}
public int withdraw(int amount){
balance -= amount;
return balance;
}
public int checkMyBalance(){
System.out.println("계좌번호: " + accNumber);
System.out.println("주민번호: " + ssNumber);
System.out.println("잔 액 : " + balance + '\\n');
return balance;
}
}
public class BankAccountUnilD {
public static void main(String[]args){
BankAccount4 yoon = new BankAccount4();// yoon의 계좌 생성
yoon.initAccount("12-34-89","990990-9090990",10000); //초기화
BankAccount4 park = new BankAccount4(); // park의 계좌 생성
park.initAccount("33-55-04","77088-595907",10000); //초기화
yoon.deposit(5000);
park.deposit(3000);
yoon.withdraw(2000);
park.withdraw(2000);
yoon.checkMyBalance();
park.checkMyBalance();
}
}
📸 출력 결과
계좌번호: 12-34-89
주민번호: 990990-9090990
잔 액 : 13000
계좌번호: 33-55-04
주민번호: 77088-595907
잔 액 : 11000
👩🏻🏫 설명
- 위의 예의 클래스에는 다음의 메소드가 추가되었습니다.
public void initAccont(String acc, String ss, int bal) {
accNumber = acc;
ssNumber = ss;
balance = bal; //계좌 개설 시 예금액으로 초기화
}
- 이 메소드는 다음과 같은 부분에서 다른 메소드들과 성격상 구분됩니다.
1. 인스턴스의 초기화를 위한 메소드이다.
2. 때문에 인스턴스 생성 시 반드시 한번 호출해서 초기화를 진행한다.
- 그러나 위와 같은 메소드를 정의하지 않고 “생성자”라는 것을 정의해서 인스턴스가 생성될 때마다 초기화를 진행할 수 있습니다.
생성자
- 생성자는 인스턴스(객체) 생성과정에서 초기화를 위해, 자동으로 호출되는 일종의 메소드입니다.
생성자의 조건
1. 생성자의 이름은 해당 클래스의 이름과 동일합니다.
2. 생성자는 값을 반환하지 않고 반환형도 표시하지 않습니다.
- 위의 두 조건을 만족하면 자바 컴파일러(javac)에 의해 생성자로 인식됩니다.
- 따라서 인스턴스를 생성할 때 자동으로 호출되어 인스턴스를 초기화합니다.
- 인스턴스 초기화를 위해 정의한 메소드를 생성자로 바꾸어 봅시다.
🔎 변경할 코드
public BankAccount(String acc, String ss,int bal){
accNumber = acc;
ssNumber = ss;
balance = bal;
}
- 다음의 코드를 통해 살펴봅시다.
💻 예시 코드
class BankAccount5{
String accNumber; //계좌번호
String ssNumber; //주민번호
int balance; //예금
public BankAccount5(String accNumber, String ssNumber, int balance) {
this.accNumber = accNumber;
this.ssNumber = ssNumber;
this.balance = balance;
}
public int deposit(int amount){
balance += amount;
return balance;
}
public int withdraw(int amount){
balance -= amount;
return balance;
}
public int checkMyBalance(){
System.out.println("계좌번호: " + accNumber);
System.out.println("주민번호: " + ssNumber);
System.out.println("잔 액 : " + balance + '\\n');
return balance;
}
}
public class BankAccountConstructor {
public static void main(String[]args){
BankAccount5 yoon = new BankAccount5("12-34-89","990990-9090990",10000);// yoon의 계좌 생성
BankAccount5 park = new BankAccount5("33-55-04","77088-595907",10000); // park의 계좌 생성
yoon.deposit(5000);
park.deposit(3000);
yoon.withdraw(2000);
park.withdraw(2000);
yoon.checkMyBalance();
park.checkMyBalance();
}
}
📸 출력 결과
계좌번호: 12-34-89
주민번호: 990990-9090990
잔 액 : 13000
계좌번호: 33-55-04
주민번호: 77088-595907
잔 액 : 11000
- 위의 예제에서 인스턴스의 생성 문장이 다음과 같이 바뀌었는 것을 확인할 수 있습니다.
- 소괄호 안에 값을 전달하고 있는데 이 값들은 생성자가 호출될 때 생성자의 매개변수로 전달됩니다.
- 위의 문장을 구성하면 인스턴스의 생성 마지막 단계에서 생성자가 호출되면서 값이 할당됩니다. 그리고 이 값들로 인스턴스 변수가 초기화 됩니다.
BankAccount yoon = new BankAccount("12-34-89","990990-909090",10000);
❓ 생성자가 생략된 클래스는?
디폴트 생성자
- 생성자가 생략한 상태의 클래스를 정의하면 자바 컴파일러(javac)가 “디폴트 생성자”라는 것을 클래스 정의에 넣어줍니다.
class BankAcount{
int balance;
public BankAccont(){ //컴파일러에 의해 자동 상빕되는 "디폴트 생성"
//empty
}
public int deposit(int amount){...}
public int withdraw(int amount){...}
public int checkMyBalance() {...}
}
⚠️ 주의점
- 컴파일러에 의해 디폴트 생성자가 자동으로 삽입되더라도 생성자는 직접 정의하는 것이 좋습니다.
- 생성자가 필요없는 클래스는 잘 정의된 클래스가 아니기 때문입니다.(생성자를 작성하는 것이 더 좋은 코드입니다)
자바의 명명규칙
- 자바 프로그램을 작성하면서 일반적으로 이름을 짓는 규칙들을 정리합니다.
클래스
- 클래스의 이름을 규칙적으로 지을때 가장 보편적으로 CamelCase모델을 이용하여 이름을 사용합니다.
❓CamelCase란?
- 낙타의 등처럼 이름이 비슷한 형태로 되어 있는 경우를 의미합니다.
- 클래스의 이름의 첫 문자는 대문자로 시작합니다.
- 둘 이상의 단어가 묶여 이름을 이룰때는 새로 시작하는 단어는 대문자로 작성합니다.
ex) Circle + Point = CirclePoint
메소드와 변수의 규칙
- 일반적으로 변형된 CamelCase 형태를 사용합니다.
- 메소드와 변수의 첫 문자는 소문자로 시작합니다.
ex) Add + Your + Money = addYourMoney, Your + age = yourAge
상수의 이름 규칙
- 상수는 일반적으로 대문자로 표현합니다.
- 단 둘 이상의 문자로 구성되어 있을 경우_(언더바)를 이용하여 연결하여 이름을 짓습니다.
ex) final int COLOR = 7;
final int COLOR_RAINBOW = 7;
📒 Reference (참고 자료)
- 윤성우의 열혈 자바
'프로그래밍 언어 > Java문법 - 객체지향' 카테고리의 다른 글
6. Java 객체지향 문법(6) - 메소드 오버로딩 (0) | 2022.10.28 |
---|---|
5. Java 객체지향 문법(5) - 클래스 변수와 클래스 메소드 (0) | 2022.10.26 |
4. Java 객체지향 문법(4) - 캡슐화 (1) | 2022.10.25 |
3. Java 객체지향 문법(3) - 정보은닉 (0) | 2022.10.24 |
2. Java 객체지향 문법(2) - 패키지 (0) | 2022.10.21 |