Java 객체 지향 개념

I C-AN·2021년 7월 17일
0

Java

목록 보기
9/26
post-thumbnail

Java 객체 지향 개념

클래스와 객체, 인스턴스

클래스

  • 객체를 정의해 놓은 것
  • 객체를 생성하는 데 사용

클래스의 작성

  1. public class가 있는 경우 소스파일의 이름은 public class와 일치해야 한다
  2. 하나의 소스파일에 둘 이상의 public class가 존재하면 안된다

객체

  • 실제로 존재하는 것으로 사물 또는 개념
  • 객체가 가지는 기능과 속성에 따라 용도가 다름

인스턴스

  • 특정 클래스로부터 생성된 객체
1. 클래스 생성
class Tv { // Tv 클래스 = 설계도
	String color; 
	boolean power;
	int channel;

	void power() {
		power = !power;
	}

	void channelUp() {
		channel++;
	}

	void channelDown() {
		channel--;
	}
}

2. 객체 생성
Tv t = new Tv(); // Tv 인스턴스의 주소를 저장하는 참조변수 t

3. 객체 사용
t.channel = 7; // Tv의 멤버변수 channel의 값을 7로
t.channelDown(); // Tv의 메서드 호출

객체 배열

참조변수의 배열
다양한 타입의 데이터를 객체 배열을 통해 저장할 수 있다
객체의 메모리를 따로 생성하는 과정이 별도로 필요함

Tv[] tvArr = new Tv[3]; // 길이가 3인 Tv타입의 참조변수 배열
Tv[] tvArr2 = { new Tv(), new Tv(), new Tv() };

클래스의 정의

사용자 정의 타입으로 데이터와 함수의 결합이다

  1. 변수 : 하나의 데이터를 저장할 수 있는 공간
  2. 배열 : 같은 종류의 여러 데이터를 하나로 저장할 수 있는 공간
  3. 구조체 : 서로 관련된 여러 데이터를 하나로 저장할 수 있는 공간
  4. 클래스 : 데이터와 함수의 결합

변수의 종류

class Variables {
	int iv; // 인스턴스 변수
	static int cv; // 클래스 변수 (static 변수, 공유변수)

	void method() {
		int lv = 0; // 지역변수
	}
}

class Card {
	// 인스턴스 변수 : 카드 객체마다 다르게 적용
	String kind; // 스페이드, 다이아, 하트, 클로버
	int no; // 1 ~ 13
    
    // 클래스 변수 : 카드 객체에 공통적으로 적용
	static int width; 
	static int height;
}

선언 위치에 따라 변수의 종류가 달라진다

변수의 종류선언 위치생성시기소멸시기
클래스 변수(cv)클래스 영역클래스가 메모리에 올라갈 때프로그램 종료 시
인스턴스 변수(iv)클래스 영역인스턴스가 생성되었을 때인스턴스 소멸 시
지역변수(lv)클래스 영역 이외의 영역변수 선언문이 수행되었을 때블럭을 벗어날 때

클래스 변수

  • static 키워드를 사용하여 선언하고 어디서든 사용할 수 있다
  • 공통적으로 사용되는 변수를 static으로 정의해서 사용하여 메모리 절약

인스턴스 변수

  • 객체를 생성해야만 사용할 수 있다
  • 객체 개별로 변수를 적용할 때 사용

지역 변수

  • 메서드, 생성자, 초기화 블럭 내부 등에서 선언된 변수
  • 해당 블럭에서 벗어나면 소멸

변수의 초기화

class InitTest {
	int x; // 인스턴스 변수
	int y = x; // 인스턴스 변수

	void method1() {
		int i; // 지역변수
		int j = i; // 지역변수를 초기화하지 않고 사용하여 에러
	}
}
  • 지역변수는 사용 전에 꼭 직접 초기화를 해야한다
  • 클래스 변수와 인스턴스 변수는 자동으로 초기화된다

멤버변수의 초기화

class Car {
	// 명시적 초기화 (간단 초기화)
	static int[] arr = new int[10];
	int door = 4;
	Engine e = new Engine();

	// 초기화 블럭 (복잡 초기화)
	static {
		int wheel = 4;
		for (int i = 0; i < arr.length; i++)
			arr[i] = (int) (Math.random() * 10) + 1;
	}
}
  • 명시적 초기화는 대입연산자를 사용하여 값을 할당하는 간단 초기화 방식이다
  • 참조형 변수의 값은 객체 주소값 또는 null이기 때문에 객체를 생성하는 것이 중요하다
  • 여러 문장의 복잡한 코드를 초기화할 때 초기화 블럭을 사용하며 { }, static { }으로 작성한다
  • 생성자를 이용하여 인스턴스 변수를 초기화할 수 있다
  • 클래스 변수는 클래스가 처음 로딩될 때 단 한번 초기화되고, 인스턴스 변수는 인스턴스가 생성될 때 마다 초기화된다

메서드

어떠한 특정 작업을 수행하기 위한 명령문의 집합

  • 반복적인 프로그래밍을 피할 수 있고 재사용성을 높임
  • 모듈화로 가독성, 유지보수가 쉬워짐
  • 하나의 메서드는 하나의 기능만 수행하도록 작성

메서드의 사용

// 메서드 문법
void A(parameter){} // 인자를 받고 리턴값이 없음
void B(){} // 인자를 받지 않으며 리턴값이 없음
dataType C(parameter){ return } // 인자를 받으며 해당 데이터 타입으로 리턴
dataType D(){ return } // 인자를 받지 않으며 해당 데이터 타입으로 리턴

// add 메서드 작성
class Test {
	int add(int x, int y) { // int 인자를 받아 int 값을 리턴하는 메서드
      return = x + y; // 두 int 인자를 더한 값을 리턴
    }
}

Test test = new Test(); // 인스턴스 생성
int result = test.add(3, 9); // 메서드 호출

// return문
void print(String a) {
	System.out.println(a); // 반환 타입이 void라 return 생략 가능
}

int minus(int a, int b) {
	int result = a - b;
    return result; // 반환 타입이 명시되어있어 return 생략 불가
}

int max(int a, int b) {
	if(a > b)
    	return a; // 조건식이 거짓일 경우 return이 없어서 에러
}        
  1. 먼저 인스턴스를 생성한다
  2. 인스턴스의 메서드를 호출한다
  3. 인자가 있다면 인자가 대입되며 블럭의 문장을 수행한다
  4. 문장을 모두 실행하거나 return문을 만나면 호출한 메서드로 되돌아와 이후의 문장을 수행한다

    반환 타입이 void가 아니라면 반드시 return문이 필요

매개변수

기본형 매개변수 : 변수의 값을 읽기만 할 수 있다
참조형 매개변수 : 변수의 값을 읽고 변경할 수 있다

// 기본형 매개변수 예제
class Data {
	int x;
}

public class Ex {
	public static void main(String[] args) {
		Data d = new Data();
		d.x = 10;
		System.out.println("main() : x = " + d.x); // main() : x = 10

		change(d.x); // change() : x = 1000
		System.out.println("main() : x = " + d.x); // main() : x =
	}

	static void change(int x) { // 기본형 매개변수 (읽기만 가능)
		x = 1000; // 지역변수
		System.out.println("change() : x = " + x);
	}

}

// 참조형 매개변수 예제
class Data2 {
	int x;
}

public class aaaa {
	public static void main(String[] args) {
		Data2 d = new Data2();
		d.x = 10;
		System.out.println("main() : x = " + d.x); // main() : x = 10

		change(d); // change() : x = 1000
		System.out.println("main() : x = " + d.x); // main() : x = 1000
	}

	static void change(Data2 d) { // 참조형 매개변수 (읽기, 쓰기 가능)
		d.x = 1000; // 참조하는 주소 d의 x를 바꿈
		System.out.println("change() : x = " + d.x);
	}

}

// 참조형 반환타입 예제
class Data3 {
	int x;
}

public class aaaa {
	public static void main(String[] args) {
		Data3 d = new Data3();
		d.x = 10;

		Data3 d2 = copy(d);
		System.out.println("d.x = " + d.x); // 10
		System.out.println("d2.x = " + d2.x); // 10
	}

	static Dat3 copy(Data3 d) { // 참조형 반환타입 (객체의 주소 리턴)
		Data3 tmp = new Data3(); // 객체 tmp 생성
		tmp.x = d.x; // d.x의 값을 tmp.x에 복사
		return tmp; // 복사한 객체의 주소 리턴
	}

}

static 메서드와 인스턴스 메서드

class MyMath {
	long a, b; // 인스턴스 변수
	
	// 인스턴스 메서드
	long add() { 
		return a + b;
	}

	// 클래스 메서드 (static 메서드)
	static long add(long a, long b) { // 지역 변수
		return a + b; // 지역 변수 (가까운 쪽 변수)
	}
}

public class Main {

	public static void main(String[] args) {
		// 클래스 메서드 호출 (객체 생성없이 호출 가능)
		System.out.println(MyMath.add(100L, 200L)); 

		MyMath mm = new MyMath(); // 인스턴스 생성
		mm.a = 100L; // 인스턴스 변수
		mm.b = 200L;
		System.out.println(mm.add()); // 인스턴스 메서드 호출
	}
}

인스턴스 메서드

  • 인스턴스 생성 후 참조변수.메서드이름()으로 호출
  • 인스턴스 멤버(iv, im)와 관련된 작업을 하는 메서드
  • 메서드 내에서 인스턴스 변수 사용가능

static 메서드 (클래스 메서드)

  • 클래스이름.메서드이름()으로 호출
  • 인스턴스 멤버(iv, im)와 관련없는 작업을 하는 메서드
  • 메서드 내에서 인스턴스 변수 사용불가

메서드 간의 호출과 참조

class Test {
	int iv; // 인스턴스 변수
	void instanceMethod() {} // 인스턴스 메서드

	static int cv; // 클래스 변수
	static void staticMethod() {} // 클래스 메서드

	// 인스턴스 메서드
	void instanceMethod() {
		System.out.println(iv); // 인스턴스 변수 사용가능
		System.out.println(cv); // 클래스 변수 사용가능
	}

	void instanceMethod2() {
		instanceMethod(); // 다른 인스턴스 메서드 호출가능
		staticMethod(); // 클래스 메서드 호출가능
	}

	// 클래스 메서드
	static void staticMethod() {
		System.out.println(iv); // 인스턴스 변수 사용불가
		System.out.println(cv); // 클래스 변수 사용가능
	}

	static void staticMethod2() {
		instanceMethod(); // 인스턴스 메서드 호출불가
		staticMethod(); // 클래스 메서드 호출가능
	}
}
  • 클래스 멤버는 객체 생성없이 항상 호출 가능
  • 클래스 메서드 호출 시 인스턴스 멤버가 없을 수도 있음
  • 클래스 메서드는 인스턴스 멤버를 사용할 수 없다
  • 인스턴스 멤버는 객체를 생성해야만 사용가능

오버로딩 (overloading)

void println()
void println(boolean x)
void println(char x)
void println(char[] x)
void println(double x)
void println(float x)
void println(int x)
void println(long x)
void println(Object x)
void println(String x)

한 클래스 안에 같은 이름의 메서드를 여러 개 정의하는 것

  1. 메서드 이름이 같아야 함
  2. 매개변수의 개수 또는 타입이 달라야 함
  3. 반환 타입은 영향없음
// 오버로딩 성립 X
int add(int a, int b) { return a + b; }
int add(int x, int y) { return x + y; }
long add(int a, int b) { return (long)( a + b ) } // 반환타입은 오버로딩과 무관

long add(int a, long b) { return a + b; } // 매개변수 타입이 다르지만
long add(long a, int b) { return a + b; } // ambiguous 에러

// 오버로딩 성립 O
// 매개변수는 다르지만 같은 의미의 기능 수행
int add(int[] a) {
	int result = 0;
    for(int i = 0; i < a.length; i++){
    	result += a[i];
    }
    return result;
}

int add(int i, int j) {
	return i + j;
}

double add(int i, double j) {
	return i + j;
}

String add(String s) {
	return "Hello" + s;
}

String add(String s, int i) {
	return null;
}

생성자

class Car {
	String carname = "포니";

	public Car() { // 기본 생성자 함수
		System.out.println("기본 생성자");
	}

	public Car(String color) { // 오버로딩 생성자 함수
		System.out.println("오버로딩 생성자");
	}
}

인스턴스가 생성될 때마다 호출되는 인스턴스 초기화 메서드

  • 이름이 클래스 이름과 같아야 한다
  • 리턴값이 없다
  • 모든 클래스는 반드시 하나 이상의 생성자를 가져야 한다
  • 오버로딩이 가능하다
  • 생성자를 직접 구현하지 않으면 컴파일러가 기본 생성자를 생성한다

참조변수 this

// this
class Car3 {
	String carname;

	public Car3() {
		this.carname = "포니";
	}

	public Car3(String name) {
		this.carname = name; // Car3.carname과 같은 의미
	}
}
  • this 참조 변수는 인스턴스가 바로 자기 자신을 참조하는 데 사용하는 변수이다
  • this 참조 변수는 해당 인스턴스의 주소를 가리키고 있다
  • 지역변수와 인스턴스 변수를 구별할 때 사용한다

생성자 this()

// this()
class Car {
    private String modelName;
    private int modelYear;
    private String color;
    private int maxSpeed;
    private int currentSpeed;
 
    Car(String modelName, int modelYear, String color, int maxSpeed) {
        this.modelName = modelName;
        this.modelYear = modelYear;
        this.color = color;
        this.maxSpeed = maxSpeed;
        this.currentSpeed = 0;
    }
 
    Car() {
        this("소나타", 2012, "검정색", 160); // 다른 생성자를 호출
    }
 
    public String getModel() {
        return this.modelYear + "년식 " + this.modelName + " " + this.color;
    }
}

 

public class Method05 {
    public static void main(String[] args) {
        Car tcpCar = new Car(); System.out.println(tcpCar.getModel());
    }
}
  • this() 메서드는 생성자 내부에서만 사용할 수 있으며, 같은 클래스의 다른 생성자를 호출할 때 사용한다
  • 다른 생성자를 호출할 때 첫 줄에서만 사용이 가능하다
  • this() 메서드에 인수를 전달하면, 생성자 중에서 메서드 시그니처가 일치하는 다른 생성자를 찾아 호출한다
  • 반복되는 코드의 중복을 제거하는 데 유용하다
profile
할 수 있다

0개의 댓글