Chap 6 클래스
1. 객체 지향 프로그래밍
- 객체(Object)란
물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서
자신의 속성을 가지고 있으면서 식별 가능한 것을 말함
ex ) 자동차, 자전거, 책, 사람과 추상적 학과, 강의, 주문 등
- 객체는 속성(field)과 동작(method)으로 구성됨
- ex) 객체가 사람일 때 사람은 이름, 나이 등의 속성과 웃다, 걷다 등의 동작이 있음
- 객체 모델링(object modeling)
- 현실 세계의 객체를 소프트웨어 객체로 설계하는
- 현실 세계 객체의 속성과 동작을 추려내어 소프트웨어 객체의 필드와 메소드로 정의하는 것
1) 객체의 상호작용
객체들은 각각 독립적으로 존재하고, 다른 객체와 서로 상호작용을 하면서 동작함.
객체들 사이의 상호작용 수단은 메소드이고,
이때 객체가 다른 객체의 기능을 이용하는 것이 바로 메소드 호출임
메소드 호출의 형태
- 객체에 도트(.) 연산자를 붙이고 메소드 이름을 기술
도트 연산자는 객체의 필드와 메소드에 접근할 때 사용함. - 매개값은 메소드를 실행하기 위해 필요한 데이터
리턴값은 메소드가 실행되고 난 후 호출한 곳으로 돌려주는 값.
- 객체의 상호작용은 객체 간의 메소드 호출을 의미하며 매개값과 리턴값을 통해서 데이터를 주고 받는다.
2) 객체 간의 관계
- 객체는 개별적으로 사용될 수 있지만, 대부분 다른 객체와 관계를 맺고 있음
- 관계의 종류
- 집합 관계
- 집합 관계에 있는 객체는 하나는 부품이고 하나는 완성품
- 상속 관계
- 상위(부모) 객체를 기반으로 하위(자식) 객체를 생성하는 관계
- 상위 객체는 종류를 의미하고, 하위 객체는 구체적인 사물에 해당한다.
- 사용 관계
- 객체 간의 상호작용을 말함
- 객체는 다른 객체의 메소드를 호출하여 원하는 결과를 얻어냄
- 사람은 자동차를 사용할 때 달린다, 멈춘다 등의 메소드를 호출하는 것
- 집합 관계
3) 객체와 클래스
- 객체는 설계도를 바탕으로 만든다.
- 자바에서 설계도가 바로 클래스(class)
(1) 클래스
- 객체를 생성하기 위한 필드와 메소드가 정의되어 있음
(2) 인스턴스
- 클래스로부터 만들어진 객체
- 자동차 객체는 자동차 클래스의 인스턴스 인 것과 같다.
- 인스턴스화 :: 클래스로부터 객체를 만드는 과정
- 하나의 클래스로부터 여러 개의 인스턴스를 만들 수 있음
동일한 설계도로 여러 대의 자동차를 만드는 것과 같음
(3) 객체 지향 프로그래밍 개발의 3단계
- 클래스를 설계한다.
- 설계된 클래스를 가지고 사용할 객체를 생성한다.
- 생성된 객체를 이용한다.
클래스를 객체를 만들기 위한 설계도이지만 아직 객체로 만들어보지는 않고
단순히 main() 메소드만 작성해서 실행할 목적으로 클래스를 이용함
하지만 main() 메소드가 없는 클래스는 객체 생성 과정을 거쳐 사용해야함
4) 클래스 선언
사용하고자 하는 객체를 구상했다면 그 객체의 대표 이름을 하나 결정하고
그것을 클래스 이름으로 정한다.
클래스 이름은 다른 클래스와 식별할 목적으로 사용되므로
자바의 식별자 작성 규칙에 따라서 만들어야 한다.
[ 식별자 작성 규칙 ]
- 하나 이상의 문자로 이루어져야 한다.
- 첫 글자에는 숫자가 올 수 없다.
- '$', '_' 외의 특수 문자는 사용할 수 없다.
- 자바 키워드는 사용할 수 없다.
통상적으로 클래스 이름이 단일 단어라면 첫 글자만 대문자로 한다.
서로 다른 단어가 혼합된 이름을 사용한다면 각 단어의 첫 글자만 대문자로 작성한다.
ex) Calculator, Car, Member, ChatClient, ChatServer, Web_Browser
클래스 이름을 정했다면,
'클래스 이름.java'로 소스 파일을 생성해야 한다.
소스 파일 이름 역시 대소문자를 구분하므로 반드시 클래스 이름과 대소문자가 같도록 해야함.
소스 파일을 생성하면 소스 파일을 열고 다음과 같이 클래스를 선언한다.
public class 클래스이름 { } |
여기서 public class 키워드는 클래스를 선언할 때 사용하며 반드시 소문자로 작성해야함
클래스 이름 뒤에는 반드시 중괄호 {}를 붙여줌
시작 중괄호 {는 클래스 선언의 시작을 알려주고 끝 중괄호 }는 클래스 선언의 끝을 알려줌
일반적으로 소스 파일당 하나의 클래스를 선언하지만, 2개 이상도 가능
2개 이상의 클래스가 선언된 소스 파일을 컴파일하면 바이트 코드 파일(.class)은 클래스를 선언한 개수만큼 생긴다.
소스 파일은 클래스 선언을 담고 있는 저장 단위일 뿐,
클래스 자체는 아님
주의!!
public 접근 제한자는 파일 이름과 동일한 이름의 클래스 선언에만 붙일 수 있음!!!
가급적 소스 파일 하나당 동일한 이름의 클래스 하나를 선언하는 것이 좋음!!!
5) 객체 생성과 클래스 변수
클래스를 선언한 다음, 컴파일을 했다면(이클립스에서는 저장)
객체를 생성할 설계도가 만들어진 것과 같음
클래스로부터 객체를 생성하려면 다음과 같이 new 연산자를 사용하면 됨.
new 클래스(); |
new는 클래스로부터 객체를 생성시키는 연산자
new 연산자 뒤에는 생성자가 오는데, 생성자는 클래스() 형태를 가지고 있다.
new 연산자로 생성된 객체는 메모리 힙(heap) 영역에 생성됨!!
객체 지향 프로그램에서도 메모리 내에서 생성된 객체의 위치를 모르면 객체를 사용할 수 없음.
그래서 new 연산자는 힙 영역에 객체를 생성시킨 후 객체의 번지를 리턴하도록 함.
이 주소를 참조 타입인 클래스 변수에 저장해두면 변수를 통해 객체를 사용할 수 있음
클래스로 선언된 변수에 new 연산자가 리턴한 객체의 번지를 저장하는 코드 |
클래스 변수; 변수 = new 클래스(); |
클래스 변수 선언과 객체 생성을 1개의 실행문으로 작성할 수도 있음
클래스 변수 = new 클래스(); |
클래스 선언 // Student.java |
package sec01.exam01;
public class Student { } |
클래스로부터 객체 생성 // StudentExample.java |
package sec01.exam01;
public class StudentExample { public static void main(String[] args) { Student s1 = new Student(); System.out.println("s1 변수가 Student 객체를 참조합니다."); Student s2 = new Student(); System.out.println("s2 변수가 또 다른 Student 객체를 참조합니다."); } } |
- StudentExample을 실행하면 다음 그림과 같이 메모리에 클래스 변수와 객체가 생성됨.
- Student 클래스는 하나지만 new 연산자를 사용한 만큼 객체가 메모리에 생성됨.
- 이러한 객체들은 Student 클래스의 인스턴스임
- 비록 같은 클래스로부터 생성되었지만 각각의 Student 객체는 자신만의 고유 데이터를 가지고 메모리에서 활동함.
- s1과 s2가 참조하는 Student 객체는 완전히 독립된 서로 다른 객체임.
Student와 StudentExample 클래스의 용도
- 클래스는 두 가지 용도가 있다.
- 하나는 라이브러리 용이고, 다른 하나는 실행용
- 라이브러리 클래스: 다른 클래스에서 이용할 목적으로 설계됨
- 프로그램 전체에서 사용되는 클래스가 100개라면 99개는 라이브러리 클래스이고,
단 하나만이 실행 클래스이다. - 실행 클래스는 프로그램의 실행 진입점인 main() 메소드를 제공하는 역할을 한다.
- Student는 라이브러리 클래스, StudentExample은 실행 클래스
- 하지만 다음과 같이 Student에 main() 메소드를 작성해서 라이브러리인 동시에 실행 클래스로 만들 수도 있음
public class Student { // 라이브러리로서의 코드(필드, 생성자, 메소드) ... //실행하기 위한 코드 public static void main(String[] arg) { Student s1 = new Student(); System.out.println("s1 변수가 Student 객체를 참조합니다."); Student s2 = new Student(); System.out.println("s2 변수가 또 다른 Student 객체를 참조합니다."); } } |
프로그램이 단 하나의 클래스로 구성된다면 위와 같이 작성하는 것이 좋은 방법이 될 수 있지만
대부분의 객체 지향 프로그램은 라이브러리(부품 객체 및 완성 객체)와 실행 클래스가 분리되어 있다.
6) 클래스의 구성 멤버
- 클래스에는 객체가 가져야 할 구성 멤버가 선언됨.
- 구성 멤버에는 필드, 생성자, 메소드가 있음.
- 이 구성 멤버들을 생략되거나 복수의 개수로 작성될 수 있음.
- 필드
- 필드는 객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳이다.
- 선언 형태는 변수와 비슷하지만, 필드를 변수라고 부르지는 않는다.
- 변수는 생성자와 메소드 내에서만 사용되고 생성자와 메소드가 실행 종료되면 자동 소멸됨.
- 필드는 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재
- 생성자
- 생성자는 new 연산자로 호출되는 특별한 중괄호 {} 블록이다.
- 생성자의 역할은 객체 생성 시 초기화를 담당함.
- 필드를 초기화 하거나 메소드를 호출해서 객체를 사용할 준비를 함
- 생성자는 메소드와 비슷하게 생겼지만, 클래스 이름으로 되어 있고 리턴 타입이 없음.
- 메소드
- 메소드는 객체의 동작에 해당하는 중괄호 {} 블록을 말함
- 중괄호 블록은 이름을 가지고 있는데 이것이 메소드 이름임
- 메소드를 호출하게 되면 중괄호 블록에 있는 모든 코드들이 일괄적으로 실행됨.
- 이 때 메소드는 필드를 읽고 수정하는 역할도 하지만, 다른 객체를 생성해서 다양한 기능을 수행하기도 함.
- 메소드는 객체 간의 데이터를 전달하는 수단
- 외부로부터 매개값을 받아 실행에 이용하고, 실행 후 결과 값을 외부로 리턴할 수도 있음
2. 필드
- 필드는 객체의 고유 데이터, 객체가 가져야 할 부품, 객체의 현재 상태 데이터를 저장하는
1) 필드 선언
- 클래스 중괄호 {} 블록 어디서든 가능
- 생성자 선언과 메소드 선언의 앞과 뒤 어떤 곳에서도 필드 선언이 가능
- 하지만 생성자와 메소드 중괄호 {} 블록 내부에는 선언될 수 없음
- 생성자와 메소드 중괄호 블록 내부에 선언된 것은 모두 로컬 변수가 됨
- 필드 선언은 변수의 선언 형태와 비슷함
타입 필드 [ = 초기값 ] ; |
- 타입은 필드에 저장할 데이터의 종류를 결정
- 타입에는 기본 타입 (byte, short, int, long, float, double, boolean)과
- 참조 타입 (배열, 열거, 인터페이스)이 모두 올 수 있음
- 필드의 초기값은 필드 선언 시 주어질 수도 있고 생략될 수도 있음
String company = "현대자동차" ; String model = "그랜저" ; int maxSpeed = 300 ; int productionYear ; int currentSpeed ; boolean engineStart ; |
- 초기값이 지정되지 않은 필드는 객체 생성 시 자동으로 기본 초기값으로 설정됨.
- 필드의 타입에 따라 기본 초기값이 다른데, 다음 표는 필드 타입별 기본 초기값을 보여줌.
2) 필드 사용
- 필드를 사용한다 = 필드값을 읽고 변경한다.
- 클래스 내부의 생성자나 메소드에서 사용할 경우 단순히 필드 이름으로 읽고 변경하면 됨
- 클래스 외부에서 사용할 경우 우선적으로 클래스로부터 객체를 생성한 뒤 필드를 사용해야함
- 필드가 객체에 소속된 데이터이므로 객체가 존재하지 안으면 필드도 존재하지 않기 때문
- Car 클래스의 speed 필드는 생성자와 메드에서 변경이 가능하다
- 사용 방법은 변수와 동일한데,
차이점으로 변수는 자신이 선언된 생성자 또는 메소드 블록 내부에서만 사용할 수 있지만
필드는 생성자와 모든 메소드에서 사용이 가능하다. - 하지만 외부 Person 클래스에서 Car 클래스의 speed 필드값을 사용하려면 다음과 같이 Car 객체를 우선 생성해야함
Car myCar = new Car(); |
- myCar 변수가 Car 객체를 참조하게 되면 도트(.) 연산자를 사용해서 speed 필드에 접근할 수 있음
- 도트(.) 연산자는 객체 접근 연산자로 객체가 가지고 있는 필드나 메소드를 사용하고자 할 때 사용됨
Car 클래스 필드 선언 // Car.java |
package sec02.exam01;
public class Car { String company = "현대자동차"; String model = "그랜저"; String color = "검정"; int maxSpeed = 350; int speed; } |
외부 클래스에서 Car 필드값 읽기와 변경 // CarExample.java |
package sec02.exam01;
public class CarExample { public static void main(String[] args) { Car myCar = new Car(); System.out.println("제작회사: " + myCar.company); System.out.println("모델명: " + myCar.model); System.out.println("색깔: " + myCar.color); System.out.println("최고속도: " + myCar.maxSpeed); System.out.println("현재속도: " + myCar.speed); myCar.speed = 60; System.out.println("수정된 속도: " + myCar.speed); } } |
출력결과
제작회사: 현대자동차
모델명: 그랜저 색깔: 검정 최고속도: 350 현재속도: 0 수정된 속도: 60 |
- Car 클래스에서 speed 필드 선언 시 초기값을 주지 않았는데도
기본 값인 0이 저장되어 있음
필드 자동 초기화 // FieldInitValue.Java |
package sec02.exam02;
public class FieldInitValue { byte byteField; short shortField; int intField; long longField; boolean booleanField; char charField; float floatField; double doubleField; int[] arrField; String referenceField; } |
필드값 출력 // FieldInitValueExample.java |
package sec02.exam02;
public class FieldInitValueExample { public static void main(String[] args) { FieldInitValue fiv = new FieldInitValue(); System.out.println("byteField: " + fiv.byteField); System.out.println("shortField: " + fiv.shortField); System.out.println("intField: " + fiv.intField); System.out.println("longField: " + fiv.longField); System.out.println("booleanField: " + fiv.booleanField); System.out.println("charField: " + fiv.charField); System.out.println("floatField: " + fiv.floatField); System.out.println("doubleField: " + fiv.doubleField); System.out.println("arrField: " + fiv.arrField); System.out.println("referenceField: " + fiv.referenceField); } } |
실행결과
byteField: 0 shortField: 0 intField: 0 longField: 0 booleanField: false charField: floatField: 0.0 doubleField: 0.0 arrField: 0.0 referenceField: null |
3. 생성자(Constructor)
- new 연산자로 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당함
- 객체 초기화
- 필드를 초기화하거나 메소드를 호출해서 객체를 사용할 준비를 하는 것을 말함.
- 생성자를 실행하지 않고는 클래스로부터 객체를 만들 수 없다.
- new 연산자에 의해 생성자가 성공적으로 실행되면 힙 영역에 객체가 생성되고 객체의 번지가 리턴됨
- 리턴된 객체의 번지는 클래스 변수에 저장됨
1) 기본 생성자
- 모든 클래스는 생성자가 반드시 존재하며, 생성자를 하나 이상 가질 수 있음
- 클래스 내부에 생성자 선언을 생략했다면 컴파일러는 다음과 같이 중괄호 {} 블록 내용이 비어 있는
기본 생성자(Default Constructor)를 바이트 코드에 자동 추가함
[public] 클래스 () { } |
- 클래스가 public class로 선언되면 기본 생성자에서도 public이 붙지만,
클래스가 public 없이 class로만 선언되면 기본 생성자에도 public이 붙지 않는다. - 예를 들어 Car 클래스를 설계할 때 생성자를 생략하면 기본 생성자가 다음과 같이 생성됨
- 따라서 클래스에 생성자를 선언하지 않아도 다음과 같이 new 연산자 뒤에 기본 생성자를 호출해서 객체를 생성
Car myCar = new Car() ; |
- 그러나 클래스에 명시적으로 선언한 생성자가 1개라도 있으면
컴파일러는 기본 생성자를 추가하지 않는다. - 명시적으로 생성자를 선언하는 이유는 객체를 다양한 값으로 초기화하기 위해서임
2) 생성자 선언
클래스( 매개변수선언, ... ) { / / 객체의 초기화 코드 } |
- 생성자는 메소드와 비슷한 모양을 가지고 있으나, 리턴 타입이 없고 클래스 이름과 동일함
- 생성자 블록 내부에는 객체 초기화 코드가 작성되는데,
일반적으로 필드에 초기값을 저장하거나 메소드를 호출하여 객체 사용 전에 필요한 준비를 한다. - 매개 변수 선언은 생략할 수도 있고 여러 개를 선언해도 좋다.
- 매개 변수는 new 연산자로 생성자를 호출할 때 외부의 값을 생성자 블록 내부로 전달하는 역할을 함
Car myCar = new Car("그랜저", "검정", 300) ; |
- 2개의 매개값은 String 타입이고 마지막 매개값은 int 타입임
- 세 매개값을 생성자가 받기 위해서는 다음과 같이 매개 변수를 선언해야함
public class Car { Car ( String model, String color, int maxSpeed) { ... } } |
- 클래스에 생성자가 명시적으로 선언되어 있을 경우에는 반드시 선언된 생성자를 호출해서 객체를 생성해야함.
생성자 선언 // Car.java |
package sec03.exam01;
public class Car { // 생성자 Car(String color, int cc) { } } |
생성자를 호출해서 객체 생성 // CarExample.java |
package sec03.exam01;
public class CarExample { public static void main(String[] args) { Car myCar = new Car("검정", 3000); //Car myCar = new Car(); (x) } } |
3) 필드 초기화
생성자에서 필드 초기화 // Korean.java |
package sec03.exam02;
public class Korean { //필드 String nation = "대한민국"; String name; String ssn; //생성자 public Korean(String n, String s) { name = n; ssn = s; } } |
객체 생성 후 필드값 출력 // KoreanExample.java |
package sec03.exam02;
public class KoreanExample { public static void main(String[] args) { Korean k1 = new Korean("박자바", "011225-1234567"); System.out.println("k1.name : " + k1.name); System.out.println("k1.ssn : " + k1.ssn); Korean k2 = new Korean("김자바", "930525-0654321"); System.out.println("k2.name : " + k2.name); System.out.println("k2.ssn : " + k2.ssn); } } |
4) 생성자 오버로딩
- 외부에서 제공되는 다양한 데이터들을 이용해서 객체를 초기화하려면 생성자도 다양화될 필요가 있음
- Car 객체를 생성할 때 외부에서 제공되는 데이터가 없다면 기본 생성자로 Car 객체를 생성해야 함
- 외부에서 model 데이터가 제공되거나 model과 color가 제공될 경우에도 Car 객체를 생성할 수 있어야 함.
- 생성자가 하나뿐이라면 이러한 요구 조건을 수용할 수 없음.
- 다양한 방법으로 객체를 생성할 수 있도록 생성자 오버로딩을 제공함.
- 생성자 오버로딩이란?
- 매개 변수를 달리하는 생성자를 여러 개 선언하는 것
생성자의 오버로딩 // Car.java |
package sec03.exam03;
public class Car { //필드 String company = "현대자동차"; String model; String color; int maxSpeed; //생성자 Car() { } Car(String model) { this.model = model; } Car(String model, String color) { this.model = model; this.color = color; } Car(String model, String color, int maxSpeed) { this.model = model; this.color = color; this.maxSpeed = maxSpeed; } } |
객체 생성 시 생성자 선택 // CarExample.java |
package sec03.exam03;
public class CarExample { public static void main(String[ ] args) { Car car1 = new Car( ); System.out.println("car1.company : " + car1.company); System.out.println( ); Car car2 = new Car("자가"); System.out.println("car2.company : " + car2.company); System.out.println("car2.model : " + car2.model); System.out.println( ); Car car3 = new Car("자가용", "빨강"); System.out.println("car3.company : " + car3.company); System.out.println("car3.model : " + car3.model); System.out.println("car3.color : " + car3.color); System.out.println( ); Car car4 = new Car("택시", "검정", 200); System.out.println("car4.company : " + car4.company); System.out.println("car4.model : " + car4.model); System.out.println("car4.color : " + car4.color); System.out.println("car4.maxSpeed : " + car4.maxSpeed); } } |
5) 다른 생성자 호출: this()
- 생성자 오버로딩이 많아질 경우 생성자 간의 중복된 코드가 발생할 수 있음
- 매개 변수의 수만 달리하고 필드 초기화 내용이 비슷한 생성자에서 이러한 현상을 많이 볼 수 있음
- 생성자에서 다른 생성자를 호출할 때에는 다음과 같이 this( ) 코드를 사용함
- this()는 자신의 다른 생성자를 호출하는 코드로 반드시 생성자의 첫 줄에만 허
다른 생성자를 호출해서 중복 코드 줄이기 // Car.java |
package sec03.exam04;
public class Car { // 필드 String company = "현대자동차"; String model; String color; int maxSpeed; // 생성자 Car() { } Car(String model) { this(model, "은색", 250); } Car(String model, String color) { this(model, color, 250); } Car(String model, String color, int maxSpeed) { this.model = model; this.color = color; this.maxSpeed = maxSpeed; } } |
객체 생성 시 생성자 선택 // CarExample.java |
package sec03.exam04;
public class CarExample { public static void main(String[] args) { Car car1 = new Car(); System.out.println("car1.company : " + car1.company); System.out.println(); Car car2 = new Car("자가용"); System.out.println("car2.company : " + car2.company); System.out.println("car2.model : " + car2.model); System.out.println(); Car car3 = new Car("자가용", "빨강"); System.out.println("car3.company : " + car3.company); System.out.println("car3.model : " + car3.model); System.out.println("car3.color : " + car3.color); System.out.println(); Car car4 = new Car("택시", "검정", 200); System.out.println("car4.company : " + car4.company); System.out.println("car4.model : " + car4.model); System.out.println("car4.color : " + car4.color); System.out.println("car4.maxSpeed : " + car4.maxSpeed); } } |
4. 메소드
메소드 선언은 선언부와 실행 블록으로 구성
메소드 선언부를 메소드 시그니처라고 하며, 선언부와 실행 블록에는 다음 요소를 포함
- 리턴 타임: 메소드가 리턴하는 결과의 타입을 표시
- 메소드 이름: 메소드의 기능이 드러나도록 식별자 규칙에 맞게 이름을 지어줌
- 매개 변수 선언: 메소드를 실행할 때 필요한 데이터를 받기 위한 변수를 선언
- 메소드 실행 블록: 실행할 코드를 작성
1) 메소드 선언
메소드 선언은 선언부(리턴 타입, 메소드 이름, 매개 변수 선언)와 실행 블록으로 구성
(1) 리턴 타입
- 리턴 타입: 리턴값의 타입을 말함
- 리턴값: 메소드를 실행한 후의 결과값을
- 메소드는 리턴값이 있을 수도 있고 없을 수도 있으나
리턴값이 있을 경우 리턴 타입이 선언부에 명시되어야 함
(2) 메소드 이름
- 메소드 이름은 자바 식별자 규칙에 맞게 작성하면 됨
- 숫자로 시작 불가, $와 _를 제외한 특수 문자 사용 금지
- 관례적으로 메소드 이름은 소문자로 작성
- 서로 다른 단어가 혼합된 이름일 땐 뒤이어 오는 단어의 첫 글자는 대문자로 작성
(3) 매개 변수 선언
- 매개 변수는 메소드가 실행할 때 필요한 데이터를 외부로부터 받기 위해 사용함.
- 메소드에서 매개 변수가 필요한 경우가 있고 필요 없는 경우가 있음
메소드 선언 // Calculator.java |
package sec04.exam01;
public class Calculator { //메소드 void powerOn() { System.out.println("전원을 켭니다."); } int plus(int x, int y) { int result = x + y; return result; } double divide(int x, int y) { double result = (double)x / (double)y; return result; } void powerOff() { System.out.println("전원을 끕니다."); } } |
메소드 호출 // CalculatorExample.java |
package sec04.exam01;
public class CalculatorExample { public static void main(String[] args) { Calculator myCalc = new Calculator(); myCalc.powerOn(); int result1 = myCalc.plus(5, 6); System.out.println("result1: " + result1); byte x = 10; byte y = 4; double result2 = myCalc.divide(x, y); System.out.println("result2: " + result2); myCalc.powerOff(); } } |
(4) 매개 변수의 개수를 모를 경우
- 매개 변수를 배열 타입으로 선언한다.
매개 변수의 개수를 모를 경우 // Computer.java |
package sec04.exam02; public class Computer { int sum1(int[] values) { int sum = 0; for(int i=0; i<values.lengthe; i++) { sum += values[i]; ; return sum; } int sum2(int ... values) { int sum = 0; for (int i=0; i<values.length; i++) { sum += values[i]; } return sum; } } |
매개 변수의 개수를 모를 경우 // ComputerExample.java |
package sec04.exam02;
public class ComputerExample { public static void main(String[] args) { Computer myCom = new Computer(); int[] values1 = {1, 2, 3}; int result1 = myCom.sum1(values1); System.out.println("result1: " + result1); int result2 = myCom.sum1(new int[] {1, 2, 3, 4, 5}); System.out.println("result2: " + result2); int result3 = myCom.sum2(1, 2, 3); System.out.println("result3: " + result3); int result4 = myCom.sum2(1, 2, 3, 4, 5); System.out.println("result4: " + result4); } } |
result1: 6
result2: 15 result3: 6 result4: 15 |
2) 리턴(return)문
(1) 리턴값이 있는 메소드
- 메소드 선언에 리턴 타입이 있는 메소드는 반드시 return문을 사용해야 한다.
(2) 리턴값이 없는 메소드
- 리턴값이 없는 메소드는 리턴 타입으로 void를 사용함.
- void로 선언된 메소드에 return문을 사용하면 메소드를 실행을 강제 종료시킴
return문 // Car.java |
package sec04.exam03;
public class Car { //필드 int gas; //생성자 //메소드 void setGas(int gas) { this.gas = gas; } boolean isLeftGas() { if(gas==0) { System.out.println("gas가 없습니다."); return false; } System.out.println("gas가 있습니."); return true; } void run() { while(true) { if(gas > 0) { System.out.println("달립니다.(gas잔량:" + gas + ")"); gas -= 1; } else { System.out.println("멈춥니다.(gas잔량:" + gas + ")"); return; } } } } |
return문 // CarExample.java |
package sec04.exam03;
public class CarExample { public static void main(String[] args) { Car myCar = new Car(); myCar.setGas(5); // Car SetGas() 메소드 호출 boolean gasState = myCar.isLeftGas(); //Car의 isLeftGas() 메소드 호출 if(gasState) { System.out.println("출발합니다."); myCar.run(); //Car의 run() 메소드 호출 } if(myCar.isLeftGas()) { //Car의 isLeftGas() 메소드 호출 System.out.println("gas를 주입할 필요가 없습니다."); } else { System.out.println("gas를 주입하세요."); } } } |
3) 메소드 호출
메소드는 클래스 내 외부의 호출에 의해 실행됨.
클래스 내부의 다른 메소드에서 호출할 경우에는 단순한 메소드 이름으로 호출하면 되지만
클래스 외부에서 호출할 경우에는 우선 클래스로부터 객체를 생성한 뒤 참조 변수를 이용해서 메소드를 호출해야한다.
객체가 존재해야 메소드도 존재하기 때문임.
(1) 객체 내부에서 호출
클래스 내부에서 메소드 호출 // Calculator.java |
package sec04.exam04;
public class Calculator { int plus(int x, int y) { int result = x + y; return result; } double avg(int x, int y) { double sum = plus(x, y); double result = sum / 2; return result; } void execute() { double result = avg(7, 10); println("실행결과: " + result); } void println(String message) { System.out.println(message); } } |
Calculator의 execute() 실행 // CalculatorExample.java |
package sec04.exam04;
public class CalculatorExample { public static void main(String[] args) { Calculator myCalc = new Calculator(); myCalc.execute(); } } |
실행결과: 8.5
|
(2) 객체 외부에서 호출
클래스 외부에서 매소드 호출 // Car.java |
package sec04.exam05;
public class Car { int speed; int getSpeed() { return speed; } void keyTurnOn() { System.out.println("키를 돌립니다."); } void run() { for(int i=10; i<=50; i+=10) { speed = i; System.out.println("달립니다.(시속:" + speed + "km/h)"); } } } |
클래스 외부에서 매소드 호출 // CarExample.java |
package sec04.exam05;
public class CarExample { public static void main(String[] args) { Car myCar = new Car(); myCar.keyTurnOn(); myCar.run(); int speed = myCar.getSpeed(); System.out.println("현재 속도: " + speed + "km/h"); } } |
키를 돌립니다.
달립니다.(시속:10km/h) 달립니다.(시속:20km/h) 달립니다.(시속:30km/h) 달립니다.(시속:40km/h) 달립니다.(시속:50km/h) 현재 속도: 50km/h |
4) 메소드 오버로딩
클래스 내에 같은 이름의 메소드를 여러 개 선언하는 것을 메소드 오버로딩이라고 한다.
오버로딩의 사전적 의미는 많이 싣는 것을 뜻함
하나의 메소드 이름으로 여러 기능을 담음
메소드 오버로딩 // Calculator.java |
package sec04.exam06;
public class Calculator { double areaRectangle(double width) { return width * width; } double areaRectangle(double width, double height) { return width * height; } } |
메소드 오버로딩 // CalculatorExample.java |
package sec04.exam06;
public class CalculatorExample { public static void main(String[] args) { Calculator myCalcu = new Calculator(); double result1 = myCalcu.areaRectangle(10); double result2 = myCalcu.areaRectangle(10, 20); System.out.println("정사각형의 넓이=" + result1); System.out.println("직사각형의 넓이=" + result2); } } |
정사각형의 넓이=100.0
직사각형의 넓이=200.0 |
5. 인스턴스 멤버와 정적 멤버
- 인스턴스 멤버: 객체마다 가지고 있는 멤버
- 정적 멤버: 클래스에 위치시키고 객체들이 공유하는 멤
1) 인스턴스 멤버와 this
- 인스턴스 멤버란 객체를 생성한 후 사용할 수 있는 필드와 메소드를 말함
- 이들을 각각 인스턴스 필드, 인스턴스 메소드라고 부른다.
인스턴스 멤버와 this // Car.java |
package sec05.exam01;
public class Car { String model; int speed; Car(String model) { this.model = model; } void setSpeed(int speed) { this.speed = speed; } void run() { for(int i=10; i<=50; i+=10) { this.setSpeed(i); System.out.println(this.model + "가 달립니다.(시속:" + this.speed + "km/h)"); } } } |
인스턴스 멤버와 this // CarExample.java |
package sec05.exam01;
public class CarExample { public static void main(String[] args) { Car myCar = new Car("포르쉐"); Car yourCar = new Car("벤츠"); myCar.run(); yourCar.run(); } } |
포르쉐가 달립니다.(시속:10km/h)
포르쉐가 달립니다.(시속:20km/h) 포르쉐가 달립니다.(시속:30km/h) 포르쉐가 달립니다.(시속:40km/h) 포르쉐가 달립니다.(시속:50km/h) 벤츠가 달립니다.(시속:10km/h) 벤츠가 달립니다.(시속:20km/h) 벤츠가 달립니다.(시속:30km/h) 벤츠가 달립니다.(시속:40km/h) 벤츠가 달립니다.(시속:50km/h) |
2) 정적 멤버와 static
- 정적 멤버는 클래스에 고정된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메소드를 말함
- 이들을 각각 정적 피드, 정적 메소드라고 부름
정적 멤버 사용 // Calculator.java |
package sec05.exam02;
public class Calculator { static double pi = 3.14159; static int plus(int x, int y) { return x + y; } static int minus(int x, int y) { return x - y; } } |
정적 멤버 사용 // CalculatorExample.java |
package sec05.exam02;
public class CalculatorExample { public static void main(String[] args) { double result1 = 10 * 10 * Calculator.pi; int result2 = Calculator.plus(10, 5); int result3 = Calculator.minus(10, 5); System.out.println("result1 : " + result1); System.out.println("result2 : " + result2); System.out.println("result3 : " + result3); } } |
result1 : 314.159
result2 : 15 result3 : 5 |
정적 메소드 선언 시 주의할 점
- 정적 메소드를 선언할 때는 이들 내부에 인스턴스 필드나 인스턴스 메소드를 사용할 수 없음.
정적 메소드 선언 시 주의할 점 |
package sec05.exam03;
public class Car { int speed; void run() { System.out.println(speed + "으로 달립니다."); } public static void main(String[] args) { Car myCar = new Car(); myCar.speed = 60; myCar.run(); } } |
3) 싱글톤(singleton)
- 전체 프로그램에서 단 하나의 객체만 만들도록 보장해야하는 경우 이 객체를 싱글톤이라고 한다.
싱글톤 // Singleton.java |
package sec05.exam04;
public class Singleton { private static Singleton singleton = new Singleton(); private Singleton() {} static Singleton getInstance() { return singleton; } } |
싱글톤 객체 // SingletonExample.java |
package sec05.exam04;
public class SingletonExample { public static void main(String[] args) { /* Singleton obj1 = new Singleton(); //컴파일 에러 Singleton obj2 = new Singleton(); // 컴파일 에러 */ Singleton obj1 = Singleton.getInstance(); Singleton obj2 = Singleton.getInstance(); if(obj1 == obj2) { System.out.println("같은 Singleton 객체입니다."); } else { System.out.println("다른 Singleton 객체입니다."); } } } |
같은 Singleton 객체입니다.
|
4) final 필드와 상수
- final 필드는 초기값이 저장되면 이것이 최종적인 값이 되어서 프로그램 실행 도중에 수정할 수 없음
- final 필드의 초기값을 주는 방법
- 필드 선언 시에 주는 방법
- 생성자에 주는 방법
(1) final 필드
final 필드 선언과 초기화 |
package sec05.exam05;
public class Person { final String nation = "Korea"; final String ssn; String name; public Person(String ssn, String name) { this.ssn = ssn; this.name = name; } } |
final 필드 테스트 |
package sec05.exam05;
public class PersonExample { public static void main(String[] args) { Person p1 = new Person("123456-1234567", "홍길동"); System.out.println(p1.nation); System.out.println(p1.ssn); System.out.println(p1.name); //p1.nation = "usa"; //p1.ssn = "654321-7654321"; p1.name = "홍삼원"; } } |
(2) 상수
상수 선언 |
package sec05.exam06;
public class Earth { static final double EARTH_RADIUS = 6400; static final double EARTH_AREA = 4 * Math.PI * EARTH_RADIUS * EARTH_RADIUS; } |
상수 사용 |
package sec05.exam06;
public class EarthExample { public static void main(String[] args) { System.out.println("지구의 반지름: " + Earth.EARTH_RADIUS + " km"); System.out.println("지구의 표면적: " + Earth.EARTH_AREA + " km^2"); } } |
6. 패키지와 접근 제한자
패키지의 물리적인 형태는 파일 시스템의 폴더이다
패키지는 단순히 파일 시스템의 폴더 기능만 하는 것이 아니라 클래스 일부분으로,
클래스를 유일하게 만들어주는 식별자 역할을 한다.
클래스 이름이 동일하더라도 패키지가 다르면 다른 클래스로 인식한다.
1) 패키지 선언
클래스를 작성할 때 해당 클래스가 어떤 패키지에 속할 것인지를 선언하는 것을 말함
- 예를 들어 Car 클래스가 com.mycompany 패키지에 속해야 한다면 다음과 같이 Car 클래스를 작성한다.
package com.mycompany; public class Car { ... } |
2) 접근 제한자
말 그대로 접근을 제한하기 위해 사용됨.
접근이란 클래스 및 인터페이스 그리고 이들이 가지고 있는 멤버의 접근을 말함
클래스와 인터페이스를 다른 패키지에서 사용하지 못하게 할 때 사용가능
접근 제한자의 종류
- public 접근 제한자
- 단어 뜻 그대로 외부 클래스가 자유롭게 사용할 수 있도록 한다.
- protected 접근 제한자
- 같은 패키지 또는 자식 클래스에서 사용할 수 있도록 한다.
- private 접근 제한자
- 단어 뜻 그래도 개인적인 것이라 외부에서 사용될 수 없도록 한다.
위 3가지 접근 제한자가 적용되지 않으면 default 접근 제한을 가진다.
- default 접근 제한 : 같은 패키지에 소속된 클래스에서만 사용가능
3) 클래스의 접근 제한
(1) default 접근 제한
- 클래스 선언 시 public을 생략했다면 default 접근 제한
- 같은 패키지에서는 아무런 제한 없이 사용 가능하지만 다른 패키지에서는 사용할 수 없음
(2) public 접근 제한
- 클래스 선언 시 public을 접근 제한자를 붙였다면 public 접근 제한
- 같은 패키지 뿐만 아니라 다른 패키지에서도 아무런 제한 없이 사용할 수 있다.
4) 생성자의 접근 제한
(1) public 접근 제한
- 모든 패키지에서 아무런 제한 없이 생성자를 호출 가
(2) protected 접근 제한
- 패키지에 속하는 클래스에서 생성자를 호출할 수 있도록 함
- 다른 패키지에 속한 클래스가 해당 클래스의 자식 클래스라면 생성자를 호출할 수 있다.
(3) default 접근 제한
- 같은 패키지에서는 아무런 제한 없이 사용 가능하지만 다른 패키지에서는 사용할 수 없음
(4) private 접근 제한
- 동일한 패키지이건 다른 패키지이건 상관없이 생성자를 호출하지 못하도록 제한
5) 필드와 메소드의 접근 제한
(1) public 접근 제한
- 모든 패키지에서 아무런 제한 없이 필드와 메소드를 사용할 수 있도록 해줌
(2) protected 접근 제한
- 패키지에 속하는 클래스에서 필드와 메소드를 사용할 수 있도록 함
- 다른 패키지에 속한 클래스가 해당 클래스의 자식 클래스라면 필드와 메소드를 사용할 수 있음
(3) default 접근 제한
- 같은 패키지에서는 아무런 제한 없이 사용 가능하지만 다른 패키지에서는 필드와 메소드를 사용할 수 있음
(4) private 접근 제한
- 동일한 패키지이건 다른 패키지이건 상관없이 필드와 메소드를 사용할 수 있음
- 오로지 클래스 내부에서만 사용 가능
4) Getter와 Setter 메소드
일반적으로 객체 지향 프로그래밍에서 객체의 필드를 객체 외부에서 직접적으로 접근하는 것을 막는다.
외부에서 마음대로 변경하는 것을 막기 위함
객체 지향 프로그래밍에서는 메소드를 통해서 필드를 변경하는 방법을 선호함.
필드는 외부에서 접근할 수 없도록 막고 메소드는 공개해서 외부에서 메소드를 통해 필드에 접근하도록 유도
메소드는 매개값을 검증해서 유효한 값만 객체의 필드로 저장할 수 있기 때문.
이런 역할을 하는 메소드가 Setter임.
마찬가지로 외부에서 객체의 데이터를 읽을 도 메소드를 사용하는 것이 좋다.
필드값을 작접 사용하면 부적절한 경우도 있기 때문
이런 경우에 메소드로 필드값을 가공한 후 외부로 전달하는 메소드인 Getter를 사용함.
클래스를 선언할 때 가능하다면 필드를 private로 선언해서 외부로부터 보호하고,
필드에 대한 Setter와 Getter 메소드를 작성해서 필드값을 안전하게 변경/ 사용하는 것이 좋음
[ 기본 미션 ]
'혼공 스터디 > 혼자 공부하는 자바' 카테고리의 다른 글
[혼공자바] 6주차: 예외와 API 클래스 (0) | 2024.02.06 |
---|---|
[혼공자바] 5주차 : 인터페이스 (0) | 2024.02.04 |
[ 혼공자바 ] 4주차 : 상속 (1) | 2024.01.26 |
[ 혼공자바 ] 2주차 : 조건문, 반복문, 참조 타입 (1) | 2024.01.14 |
[ 혼공자바 ] 1주차 (1) | 2024.01.07 |