클래스(class)는 객체 지향 프로그래밍(OOP)에서 특정 객체를 생성하기 위해 변수와 메소드를 정의하는 일종의 틀(template)이다.
용도 | 목적 | 개수 |
---|---|---|
라이브러리 클래스 | 다른 클래스에서 이용하기 위함 | n-1개 |
실행 클래스 | main 메소드 제공 | 1개 |
앞선 포스트에서 설명했던 참조 변수의 종류 중, 클래스 변수라는 것이 있다.
// 클래스의 첫 글자는 대문자로
MyClass mine = new MyClass();
mine은 클래스 변수로, new 연산자로 생성된 객체의 주소(실제 주소는 아님)를 갖고있다.
mine은 new 연산자로 생성된 객체(인스턴스)를 참조한다.
인스턴스는 힙 영역에 생성된다.
: 객체의 데이터를 저장하는 역할을 함
: 객체 생성 시 초기화하는 역할을 함
: 객체의 동작에 해당하는 실행 블록 (객체 간 데이터 전달 수단)
필드는 객체의 데이터를 저장하는 클래스 멤버다.
// 선언 방법:
// 타입 필드 [= 초기값]
public class MyClass{
int field1;
double field2 = 4.5;
String field3 = "hi";
}
타입 | 초기값 |
---|---|
byte | 0 |
char | \u0000 (공백) |
short | 0 |
int | 0 |
long | 0L |
float | 0.0F |
double | 0.0 |
boolean | false |
참조형 | null |
public class UseMyClass{
public static void main(String[] args){
MyClass mine = new MyClass();
mine.field1 = 10; // 도트 연산자를 사용하여 객체에 접근
}
}
생성자는 객체의 초기화를 담당하는 클래스 멤버이다.
// 소스 파일
public class MyClass{
}
// 바이트 코드 파일
public class MyClass{
MyClass(){ } // 자동 생성됨
}
// 생성자 선언:
// 클래스(매개변수, ...) { }
public class MyClass{
int field1;
double field2 = 4.5;
String field3 = "hi";
MyClass(int field1, double field2){
// 필드와 매개변수 이름이 동일한 경우, 매개변수의 우선순위가 높다.
// 따라서, this를 사용한다.
// this는 객체 자기 자신의 참조이다.
this.field1 = field1;
this.field2 = field2;
}
}
여러개의 생성자를 구현한 경우 다양한 매개변수로 객체를 생성할 수 있는데, 이를 생성자 오버로딩이라 한다.
public class MyClass{
MyClass(int field1, double field2){ }
MyClass(double field2, int field1){ }
MyClass(String field3){ }
// My Class(int field2, double field1)은 오버로딩이 아님
}
public class MyClass{
MyClass(){ }
MyClass(String model){
this(model,"은색",100);
}
MyClass(String model, String color){
this(model, color, 100);
}
MyClass(String model, String color, int speed){
this.model = model;
this.color = color;
this.speed = speed;
}
}
메소드는 객체의 기능을 담당하는 클래스 멤버이다.
public class MyClass{
// 방법1: 배열 사용
int sum1(int[] values){
int sum = 0;
for(int i=0;i<values.length;i++) {
sum += values[i];
}
return sum;
}
// 방법2: ... 사용
int sum2(int ... values){
int sum = 0;
for(int i=0;i<values.length;i++) {
sum += values[i];
}
return sum;
}
}
public class UseMyClass{
public static void main(String[] args){
MyClass mine = new MyClass();
int result1 = mine.sum1(new int[1,2,3,4,5]); // 인수는 반드시 배열로
int result2 = mine.sum2(1,2,3,4,5) // ... 사용시 배열은 자동 생성됨
}
}
클래스 내에 같은 이름의 메소드를 여러개 선언하는 것을 메소드 오버로딩이라 한다.
인스턴스 멤버: 객체마다 가지고 있는 멤버
정적 멤버: 모든 객체가 공유하는 멤버
public class MyClass{
int field1;
int getField(){
return field1;
}
}
위의 코드에서, 인스턴스 필드 field1은 객체마다 존재하고, 인스턴스 메소드는 메소드 영역에 저장되고 공유된다.
❓인스턴스 메소드는 왜 메소드 영역에 저장되고 공유되지??
메소드는 '코드 블록'이므로, 객체마다 똑같은 코드 블록을 갖고 있는 것은 비효율 적이다.
인스턴스 메소드라 부르는 이유는, 메소드 안에 인스턴스 필드가 포함될 수 있기 때문이다.
public class MyClass{
int field1; // 인스턴스 필드
static double field2 = 1.1; // 정적 필드
int getField(){
return field1; // 인스턴스 필드를 사용하므로, 인스턴스 메소드로 선언
}
static int plus(int x){
return x + 1; // 정적 메소드
}
}
정적 메소드는 클래스이름.메소드()로 사용한다.
public class UseMyClass{
public static void main(String[] args){
int x = 1;
int result = MyClass.plus(x); // 인스턴스 생성 없이 바로 사용 가능
}
}
싱글톤이란, 전체 프로그램에서 단 하나만 생성하도록 보장된 객체이다.
싱글톤을 만드려면, 다음과 같은 과정을 거쳐야 한다.
--> 생성자를 private로 제한한다.
--> 인스턴스 필드인 경우, 반드시 해당 객체의 인스턴스를 생성해야만 사용 가능하기 때문이다. 클래스 외부에서는 생성자를 호출할 수 없으므로, 인스턴스 생성도 불가능하다.
--> 해당 객체를 얻기위한 유일한 수단이다.
public class Singleton{
private static Singleton singleton = new Singleton();
private Singleton(){ }
static Singleton getInstance(){
return singleton;
}
}
final 필드는, 초기값이 저장되면 변경 불가능한 필드이다.
final 필드의 초기값을 설정하는 방법은 2가지 밖에 없다.
1. 선언과 동시에 설정
2. 생성자로 설정
❓그럼 상수랑 뭐가 다르지??
다음의 예시를 한번 보자
public class MyClass{
final String nation = "Korea";
final String name;
MyClass(String name){
this.name = name;
}
}
public static void main(String[] args){
MyClass mine1 = new MyClass("ju");
MyClass mine2 = new MyClass("kim");
}
상수는 "불변"의 값이다.
하지만, final 필드는 각 인스턴스마다 값이 다를 수 있다.
상수를 만들기 위해서는 static final 필드를 사용해야 한다.
static final 필드는 객체마다 존재하지 않고 클래스에만 존재하며, 초기값 지정 시 변경 불가능하다.
static final double PI = 3.141592;
패키지는 클래스 전용 파일 시스템이라 생각하면 된다.
클래스 이름이 동일하더라도, 패키지가 다르면 다른 클래스로 인식한다.
package 상위패키지.하위패키지;
public class MyClass{}
import 상위패키지.하위패키지.클래스이름; // 상위패키지를 import 한다고 하위패키지까지 import 되는건 아님
import 상위패키지.하위패키지.*; // 패키지에 있는 전체 클래스 사용 가능
public class MyClass{}
접근 제한자는 클래스 및 인터페이스 그리고 이들이 갖고 있는 멤버들에게 접근하는 것을 제한한다.
요소 | 사용가능한 접근 제한자 |
---|---|
class | public, default |
생성자 | public, protected, default, private |
필드 | public, protected, default, private |
메소드 | public, protected, default, private |
일반적으로 객체 지향 프로그래밍에서는 객체의 필드를 외부에서 접근하는 것을 막는다.
필드는 private, 메소드는 public 접근 제한자를 적용하여 메소드를 통해 필드에 접근하도록 한다.
필드의 값을 리턴하는 메소드를 Getter, 필드를 변경하는 메소드를 Setter라고 한다.
혼자 공부하는 자바