[Java] 클래스, 메서드 (추상 클래스, 추상 메서드), 오버로딩
자바 복습 및 정리 3P
클래스
객체 지향 프로그래밍에서 중요한 개념 중 하나
데이터와 이를 처리하는 메서드를 하나로 묶어놓은 틀이나 템플릿이다.
클래스는 설계도라고 할 수 있으며, 객체를 생성하는데 사용된다.
클래스는 크게 네 가지 요소로 구성된다.
필드, 메서드, 생성자, 이너클래스
public class ExampleClass {
int x = 10; // (1)필드
void printX() {...} // (2)메서드
ExampleClass {...} // (3)생성자
class ExampleClass2 {...} // (4)이너 클래스
}
필드 - 클래스의 속성을 나타내는 변수. 자동차로 예를 들면 모델명, 컬러, 바퀴의 수 등이 포함.
메서드 - 클래스의 기능을 나타내는 함수. 시동걸기, 가속하기, 정지하기 등이 포함.
생성자 - 클래스의 객체를 생성하는 역할.
이너 클래스 - 클래스 내부의 클래스.
클래스는 다음과 같은 특징을 가지고 있다.
속성 (멤버 변수, 필드)
클래스 내부에는 데이터를 저장하는 멤버 변수들이 있다.
이 멤버 변수들은 클래스가 표현하는 객체의 상태나 특징을 나타낸다.
메서드 (멤버 함수)
클래스 내부에는 데이터를 처리하고 조작하는 메서드들이 있다.
이 메서드들은 클래스가 가진 기능이나 동작을 정의한다.
생성자
객체가 생성될 때 초기화하는데 사용되는 특별한 메서드이다.
생성자를 통해 객체의 초기 상태를 설정할 수 있다.
접근 제어자
멤버 변수와 메서드에는 접근 제어자(public, private 등)를 사용하여 외부에서의 접근을 제한할 수 있다.
상속
클래스 간에 상속을 통해 기존 클래스의 특성과 기능을 물려받아 새로운 클래스를 정의할 수 있다.
다형성
여러 클래스가 같은 이름의 메서드를 가지면서 다른 동작을 하는 것을 의미하며, 객체의 타입에 따라 다른 메서드가 호출될 수 있다.
추상 클래스
객체 생성을 위한 템플릿이며, 일부 메서드를 추상 메서드로 정의하여 하위 클래스에서 반드시 구현하도록 할 수 있다.
인스턴스화
클래스를 바탕으로 실제 객체를 생성하는 과정을 인스턴스화라고 한다.
인스턴스는 클래스의 구조를 따르며 독립적인 데이터와 동작을 가진다.
정적 멤버
클래스 레벨에서 접근할 수 있는 정적 멤버(변수, 메서드)를 정의할 수 있다.
인스턴스 생성 없이 클래스 이름으로 접근 가능하다.
// 클래스 정의
class Car {
// 속성 (멤버 변수, 필드)
String brand;
String model;
int year;
// 생성자
public Car(String brand, String model, int year) {
this.brand = brand;
this.model = model;
this.year = year;
}
// 메서드 (기능)
public void startEngine() {
System.out.println("Engine started!");
}
public void drive() {
System.out.println("Driving the " + year + " " + brand + " " + model);
}
}
public class Main {
public static void main(String[] args) {
// 객체 인스턴스화 (클래스로부터 실제 객체 생성)
Car myCar = new Car("Toyota", "Camry", 2022);
// 메서드 호출
myCar.startEngine();
myCar.drive();
}
}
객체
클래스가 개별 객체(인스턴스)를 만들기 위한 설계도이며,
클래스를 통해 만들어진 객체가 실제로 사용할 수 있는 실체이다.
public class Person {
// 속성 (멤버 변수)
private String name;
private int age;
// 생성자
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 메서드
public void introduce() {
System.out.println("안녕하세요, 저는 " + name + "이고 " + age + "살입니다.");
}
}
public class Main {
public static void main(String[] args) {
// 객체 생성
Person person1 = new Person("Alice", 25);
Person person2 = new Person("Bob", 30);
// 메서드 호출
person1.introduce(); // 출력: 안녕하세요, 저는 Alice이고 25살입니다.
person2.introduce(); // 출력: 안녕하세요, 저는 Bob이고 30살입니다.
}
}
메서드
코드를 논리적으로 그룹화하고 재사용성을 높이기 위해 사용되는 블록 단위의 코드 조각.
메서드는 클래스 내에 선언되며 특정한 작업을 수행하는 코드 블록을 정의하고 호출할 때 실행된다.
메서드는 다음과 같은 구성 요소로 구성된다.
1. 메서드 시그니처
메서드의 이름과 매개변수(parameter) 목록으로 이루어진다.
매개변수는 메서드가 실행될 때 필요한 입력값을 나타낸다.
2. 메서드 본문
메서드가 수행할 코드 블록이다.
메서드가 호출되면 이 코드 블록이 실행된다.
3. 리턴 타입
메서드가 값을 반환하는 경우, 그 반환 값의 자료형을 정의한다.
반환하지 않는 메서드는 void를 리턴 타입으로 가진다.
public class MyClass {
// 메서드 정의
public int add(int a, int b) { // int a, int b = parameter
int result = a + b;
return result;
}
public void printMessage(String message) {
System.out.println(message);
}
// 메인 메서드 (프로그램의 시작점)
public static void main(String[] args) {
MyClass myObject = new MyClass();
int sum = myObject.add(5, 7); // 메서드 호출
myObject.printMessage("Hello, Java!"); // 메서드 호출
}
}
위 예시에서 add 메서드는 두 개의 정수를 더한 값을 반환하고,
printMessage 메서드는 메서드 문자열을 화면에 출력한다.
메서드는 코드 재사용성과 모듈화를 증가시키며, 큰 프로그램을 더 작고 관리 가능한 조각으로 나눌 수 있게 한다.
public class MyClass {
public static String getPhoneNumber() {
String phoneNumber = "010-1234-1234";
return phoneNumber;
}
public static void main(String[] args) {
String phone = getPhoneNumber();
System.out.println("전화번호 : " + phone);
}
}
// 출력
// 전화번호 : 010-1234-1234
참고
public static String hello() {
...
}
public String hello() {
...
}
위 두 메서드의 차이점은 static 키워드의 유무로서 메서드가 객체에 종속적인지 클래스에 종속적인지를 나타낸다.
메서드가 static으로 선언되면 해당 메서드는 클래스에 종속되어 객체를 생성하지 않고도 호출할 수 있다.
반면에 static이 없는 메서드는 객체를 생성한 후 해당 객체의 메서드로 호출해야 한다.
위 두 메서드를 예로 들어 코드로 보면 이런 차이점이 있다.
public class MyClass {
// static 메서드
public static String staticHello() {
return "Hello from static method!";
}
// 인스턴스 메서드
public String instanceHello() {
return "Hello from instance method!";
}
public static void main(String[] args) {
// static 메서드 호출
String staticMessage = MyClass.staticHello();
System.out.println(staticMessage);
// 인스턴스 생성
MyClass myObject = new MyClass();
// 인스턴스 메서드 호출
String instanceMessage = myObject.instanceHello();
System.out.println(instanceMessage);
}
}
이 외에 static 키워드 말고도 다양한 키워드가 있다.
final
변수에 사용되면 해당 변수를 상수로 만들어 값을 변경할 수 없게 한다.
메서드에 사용되면 해당 메서드를 오버라이드할 수 없게 하거나 클래스에 사용되면 해당 클래스를 상속할 수 없게 한다.
// final 키워드의 예시
final int constantValue = 10;
// final 메서드 예시
final void finalMethod() {
// 메서드 내용
}
abstract
클래스나 메서드에 사용될 수 있다.
클래스에 사용되면 추상 클래스를 나타내며, 객체를 직접 생성할 수 없다.
메서드에 사용되면 해당 메서드가 추상 메서드임을 나타내며, 하위 클래스에서 반드시 구현해야 한다.
// abstract 클래스 예시
abstract class AbstractClass {
abstract void abstractMethod();
}
synchronized
멀티스레드 환경에서 동기화를 제공하는 역할을 한다.
해당 키워드로 둘러싼 블록은 한 번에 하나의 스레드만 실행할 수 있게 한다.
// synchronized 메서드 예시
synchronized void synchronizedMethod() {
// 메서드 내용
}
volatile
변수를 메인 메모리에 저장하고 캐시를 사용하지 않도록 지정하는 역할을 한다.
멀티스레드 환경에서 변수의 값을 보장하기 위해 사용된다.
// volatile 변수 예시
volatile int volatileValue;
transient
직렬화를 할 때 해당 변수를 제외하도록 지정한다.
// transient 변수 예시
transient int transientValue;
native
자바 코드 내에서 해당 메서드가 네이티브 코드(c, c++ 등)로 작성된 메서드임을 나타낸다.
// native 메서드 예시
native void nativeMethod();
추상 클래스, 추상 메서드
추상 클래스
인스턴스를 생성할 수 없는 클래스로, 다른 클래스들의 공통된 특성을 추상화하여 상속을 통해 확장되는 용도로 사용된다.
추상클래스는 abstract 키워드를 사용하여 정의하며, 추상 메서드를 포함할 수 있다.
추상 클래스 내에는 일반 메서드 또는 멤버 변수도 포함될 수 있다.
추상 메서드
메서드의 선언만 있고 본체가 없는 메서드이다.
이 메서드는 하위 클래스에서 반드시 구현되어야 한다.
추상 메서드는 추상 클래스 내에서 abstract 키워드를 사용하여 선언한다.
// 추상 클래스 정의
abstract class Shape {
// 추상 메서드 선언 (하위 클래스에서 반드시 구현해야 함)
abstract double calculateArea();
}
// Circle 클래스는 Shape 클래스를 상속하며 추상 메서드를 구현합니다.
class Circle extends Shape {
double radius;
Circle(double radius) {
this.radius = radius;
}
@Override
double calculateArea() {
return Math.PI * radius * radius;
}
}
// Rectangle 클래스도 Shape 클래스를 상속하고 추상 메서드를 구현합니다.
class Rectangle extends Shape {
double width;
double height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
double calculateArea() {
return width * height;
}
}
오버라이딩의 역할은 다음 포스트에서 확인할 수 있다.
추상클래와 추상 메서드의 사용 목적
공통된 기능을 추상화
여러 하위 클래스에서 공통된 속성과 동작을 추상화하여 정의할 수 있다.
코드의 중복을 줄이고 유지 보수성을 향상시킬 수 있다.
다형성 구현
추상 클래스를 사용하면 다형성을 구현할 수 있다.
서로 다른 하위 클래스들을 추상 클래스 타입으로 관리하고, 추상 클래스에 정의된 추상 메서드를 통해 다양한 하위 클래스의 구체적인 기능을 활용할 수 있다.
메서드 강제 구현
하위 클래스에 특정 메서드의 구현을 강제할 수 있다.
이를 통해 하위 클래스가 반드시 해당 메서드를 구현하도록 보장하고, 일관된 동작을 유지할 수 있다.
확장성
새로운 하위 클래스를 쉽게 추가하거나 기존 클래스를 확장할 수 있다.
추상 클래스의 공통된 속성과 메서드를 상속받아 기능을 추가하거나 수정할 수 있다.
설계의 유연성
인터페이스와 구현의 분리를 실현할 수 있다.
추상 클래스는 인터페이스와 구현 사이의 중간 단계로서, 하위 클래스들이 공통된 틀을 가지며 동시에 각각의 독립적인 특성을 갖을 수 있도록 도와준다.
코드 가독성과 유지 보수성
상속 관계와 메서드의 목적을 명확하게 나타낼 수 있다.
추상화는 복잡한 현실 세계에서 중요한 세부사항을 무시하고 핵심 개념이나 속성을 강조하는 과정을 말한다.
abstract class Animal {
abstract void makeSound();
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("멍멍!");
}
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("야옹~");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.makeSound(); // 멍멍!
Cat cat = new Cat();
cat.makeSound(); // 야옹~
}
}
오버로딩
자바에서 동일한 이름을 가진 메서드를 여러 개 정의하는 개념
각 메서드는 매개변수의 개수, 타입 또는 순서가 다르도록 정의된다.
이를 통해 메서드의 이름은 같지만 다양한 매개변수를 받아 처리할 수 있다.
public class Printer {
public void print(int num) {
System.out.println("정수: " + num);
}
public void print(double num) {
System.out.println("실수: " + num);
}
public void print(String text) {
System.out.println("문자열: " + text);
}
}
public class Main {
public static void main(String[] args) {
Printer printer = new Printer();
printer.print(10); // 출력: 정수: 10
printer.print(3.14); // 출력: 실수: 3.14
printer.print("Hello"); // 출력: 문자열: Hello
}
}
위 예시에서 Printer 클래스는 print 메서드를 정수, 실수, 문자열 타입에 대해 오버로딩하여 세 가지 버전의 메서드를 가지고 있다.
메서드 호출 시 전달되는 인자의 타입에 따라 적절한 오버로딩된 메서드가 호출되어 처리된다.
댓글남기기