[2023.08.19] Java 객체지향 1

이재하·2023년 8월 19일
3

항해99

목록 보기
18/48

객체지향개념1,2을 계속 까먹어서 정리했다.

객체지향개념 1


클래스와 객체

클래스 : 객체를 정의해 놓은 것

  • 용도 : 객체를 생성하는데 사용

객체 : 실제로 존재하는 것, 모든 인스턴스를 대표하는 일반적인 용어

  • 용도 : 객체가 가지고 있는 기능(메소드)과 속성(변수)에 따라 다름

인스턴스 : 특정 클래스로부터 생성된 객체(예 : Tv 인스턴스)

예 : TV 클래스

Class Tv {
	// 변수
	String color;	// 색깔
    boolean power;	// 전원상태
    int channel;	// 채널
    
    //메소드
    void power()		{power = !power;}
    void channelUp()	{channel++;}
    void channelDOwn()	{channel--;}
}

인스턴스의 생성과 사용

일반적인 인스턴스 생성 방법

클래스명 변수명;			// 클래스의 객체를 참조하기 위한 참조변수 선언
변수명 = new 클래스명();	// 클래스의 객체를 생성 후,객체의 주소를 참조변수에 저장

Tv t;				// Tv 클래스 타입의 참조변수 t를 선언
t = new Tv();		// Tv 인스턴스를 생성한 후, 생성된 Tv 인스턴스의 주소를 t에 저장 

예제

Class Tv {
	// 변수
	String color;	// 색깔
    boolean power;	// 전원상태
    int channel;	// 채널
    
    //메소드
    void power()		{power = !power;}
    void channelUp()	{channel++;}
    void channelDOwn()	{channel--;}
}

class TvTest {
	public static void main(String args[]) {
		Tv t;				// Tv 인스턴스를 참조하기 위한 변수 t를 선언

        t = new Tv();		// Tv 인스턴스 생성
        t.channel =7;		// Tv 인스턴스의 멤버변수 channel의 값을 7로 한다
        t.channelDown();	//Tv 인스턴스의 메소드 channelDOwn(()을 호출
        System.out.println("현재 채널은 " + t.channel + "입니다.");
	}
}


channel 의 값을 7로 했기 때문에 이 사진에서 channel의 값은0 이 아닌 7.
후에 channelDown 메소드에 의해 6이 된다.


참조변수에는 하나의 값(주소)만이 저장될 수 있으므로 둘 이상의 참조변수가 하나의 인스턴스를 참조하는 것은가능하지만하나의 참조변수로 여러 개의 인스턴스를 가리키는 것은 가능하지 않다.


객체의 배열

많은 수의 객체를 다뤄야 할 때 객체를 배열로 다룬다.
객체 배열 안에 객체가아닌 객체의 주소가 저장된다.

객체 배열을 생성하는 것은 객체를 다루기 위한 참조 변수들이 만들어진 것 뿐.
객체가 저장되지 않음.
따라서 객체를 생성해서 객체 배열의 각 요소에 저장해야 한다.

Tv[] tvArr = new Tv[3]; // 참조변수 배열(객체 배열)을 생성

// 객체를 생성해서 배열의 각 요소에 저장
tvArr[0] = new Tv();
tvArr[1] = new Tv();
tvArr[2] = new Tv();
  • 배열의 초기화 블럭 사용하요 한줄로 나타내기
Tv[] tvArr = {new Tv(), new Tv(), new Tv()};
  • 다뤄야 할 객체의 수가 많을 떄는 for문 이용
Tv[] tvArr = new Tv[100];

for(int i = 0; i < tvArr.length; i++) {
	tvArr[i] = new Tv();
}

클래스의 또 다른 정의


선언위치에 따른 변수의 종류

변수의 종류 : 클래스 변수 = static 변수(cv), 인스턴스 변수 (iv), 지역 변수(lv)


클래스변수와 인스턴스 변수

인스턴스 변수는 인스턴스가 생성될 때 마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된 값을 갖는다.

각 Card 인스턴스는 자신만의 kind 와 number 를 유지하고 있어야 하므로 인스턴스변수,
카드의 width 와 height 는 모든 인스턴스가 공통적으로 같은 값을 유지해야하므로 클래스 변수로선언

class Ex6_3 {
	public static void main(String args[]) {
		System.out.println("Card.width = " + Card.width);
		System.out.println("Card.height = " + Card.height); 
        // 클래스 변수 (static 변수) 는 객체생성 없이 직접 사용 가능

		Card c1 = new Card();
		c1.kind = "Heart";
		c1.number = 7; // 인스턴스 변수의 값 변경

		Card c2 = new Card();
		c2.kind = "Spade";
		c2.number = 4; // 인스턴스 변수의 값 변경

		System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 (" + c1.width + ", " + c1.height + ")");
		System.out.println("c2는 " + c2.kind + ", " + c2.number + "이며, 크기는 (" + c2.width + ", " + c2.height + ")");
		System.out.println("c1의 width와 height를 각각 50, 80으로 변경합니다.");
		c1.width = 50;	// 클래스 변수의 값 변경
		c1.height = 80; // 클래스 변수의 값 변경

		System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 (" + c1.width + ", " + c1.height + ")");
		System.out.println("c2는 " + c2.kind + ", " + c2.number + "이며, 크기는 (" + c2.width + ", " + c2.height + ")");
	}
}

class Card {
	String kind;
	int number;
	static int width = 100;
	static int height = 250;
}


// 실행 결과
// Card.width = 100
// Card.height = 250
// c1은 Heart, 7 이며, 크기는 (100,250)
// c2는 Spade, 4 이며, 크기는 (100,250)
// c1의 width와 height를 각각 50, 80으로 변경합니다.
// c1은 Heart, 7 이며, 크기는 (50, 80)
// c2은 Spade, 4 이며, 크기는 (50, 80)

메소드

메소드란?

  • 작업을 수행하기 위한 명령문의 집합
  • 어떤 값을 입력 받아서 처리하고 그 결과를 돌려준다
    (입력받는 값이 없을 수도 있고 결과를 돌려주지 않을 수도 있다)

메소드를 사용하는 이유

  • 높은 재사용성
  • 중복된 코드의 제거
  • 프로그램의 구조화

메소드의 선언과 구현

  • 반환 되는 변수는 메서드의 반환타입과 일치해야 함

메소드의 호출

메소드를 호출해야만 구현부 {} 의 문장들이 수행된다.

메소드 흐름

public class Computer {
	int sum1(int[] values) {
	int sum = 0;
	for(int i = 0; i <values.length; 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;
	}
}

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

return 문

반환값의 유무에 관계없이 모든 메소드에는 적어도 하나의 return문이 있어야한다.
반환 타입이 void인 경우, return문없이 아무런 문제가 없었던 이유는 컴파일러가 메소드 마지막에 return; 을 자동적으로 추가해주었기 때문이다.


기본형 매개변수, 참조형 매개변수

메소드를 호출할 때 매개변수(parameter)로 지정한 값을 메소드의 매개변수에 복사해서 넘겨준다.

매개변수의 타입이 기본형(primitive type)일 때는 기본형 값이 복사 되지만,
참조형(reference type)이면 인스턴스의 주소가 복사된다.

기본형 매개변수 : 변수의 값을 읽기만 할 수 있다. - 기본형으로 선언하면 저장된 값만 얻기 때문
참조형 매개변수 : 변수의 값을 읽고 변경할 수 있다. - 참조형으로 선언하면 값이 저장된 곳의 주소를 알 수 있기 때문

  • 매개변수 타입이 배열이면 참조형 매개변수다.

이해하기 위해 호출 스택을 보면 도움이 된다.


클래스 메소드(static 메소드), 인스턴스 메소드

인스턴스 메소드

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

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

  • 객체 생성 없이 클래스이름.메소드이름() 으로 호출
  • 인스턴스 변수나 인스턴스 메소드와 관련없는 작업을 하는 메소드
  • 메소드 내에서 인스턴스 변수 사용 불가
  • 메소드 내에서 인스턴스 변수를 사용하지 않는다면 static을 붙이는 것을 고려
class MyMath2 {
	long a, b;

	// 인스턴스 변수 a, b만을 잉요해서 작업하므로 매개변수가 필요없다.
	long add()		{ return a + b; }  // a, b는 인스턴스 변수
	long subtract() { return a - b; }
	long multiply() { return a * b; }
	double divide() { return a / b; }

	// 인스턴스 변수와 관계없이 매개변수만으로 작업이 가능하다.
	static long   add(long a, long b)		 { return a + b; }  // a, b는 지역변수
	static long   subtract(long a, long b)   { return a - b; }
	static long   multiply(long a, long b)   { return a * b; }
	static double divide(long a, long b) { return a / (double)b; }
	
}


class Ex6_9 {
	public static void main(String args[]) {
		// 클래스 메서드 호출. 인스턴스 생성없이 호출가능
		System.out.println(MyMath2.add(200L, 100L));
		System.out.println(MyMath2.subtract(200L, 100L));
		System.out.println(MyMath2.multiply(200L, 100L));
		System.out.println(MyMath2.divide(200L, 100L));

		MyMath2 mm = new MyMath2(); // 인스턴스를 생성
		mm.a = 200L;
		mm.b = 100L;
		// 인스턴스 메서드는 객체생성 후에만 호출이 가능함.
		System.out.println(mm.add());
		System.out.println(mm.subtract());
		System.out.println(mm.multiply());
		System.out.println(mm.divide());
   }
}


메소드 오버로딩

하나의 클래스에 같은 이름의 메소드를 여러개 정의하는 것

오버로딩의 조건

  • 메소드의 이름이 같아야 한다.
  • 매개변수의 개수 또는 타입이 달라야 한다.
  • 매개변수는 같고 리턴 타입이 다른 경우는 오버로딩이 성립되지 않음
    (리턴 타입은 오버로딩에 아무 영향 없음)
class Ex6_10 {
	public static void main(String args[]) {
		MyMath3 mm = new MyMath3();
		System.out.println("mm.add(3, 3) 결과:"    + mm.add(3,3));
		System.out.println("mm.add(3L, 3) 결과: "  + mm.add(3L,3));
		System.out.println("mm.add(3, 3L) 결과: "  + mm.add(3,3L));
		System.out.println("mm.add(3L, 3L) 결과: " + mm.add(3L,3L));

		int[] a = {100, 200, 300};
		System.out.println("mm.add(a) 결과: " + mm.add(a));
   }
}

class MyMath3 {
	int add(int a, int b) {
		System.out.print("int add(int a, int b) - ");
		return a+b;
	}
	
	long add(int a, long b) {
		System.out.print("long add(int a, long b) - ");
		return a+b;
	}
	
	long add(long a, int b) {
		System.out.print("long add(long a, int b) - ");
		return a+b;
	}

	long add(long a, long b) {
		System.out.print("long add(long a, long b) - ");
		return a+b;
	}

	int add(int[] a) {		// 배열의 모든 요소의 합을 결과로 돌려준다.
		System.out.print("int add(int[] a) - ");
		int result = 0;
		for(int i=0; i < a.length;i++) 
			result += a[i];
		
		return result;
	}
}

생성자

  • 인스턴스가 생성될 때마다 호출되는 인스턴스 초기화 메소드
  1. 생성자의 이름은 클래스의 이름과 같아야 한다.
  2. 리턴값이 없다. (void 안붙임)
  3. 모든 클래스는 반드시 생성자를 가져야 한다.

https://blog.naver.com/heartflow89/220955879645
생성자에 대해 잘 설명되있는 블로그

인스턴스를 생성할 때 "클래스 객체변수 = new 클래스();" 라는 구문을 사용하고 이때 "클래스();"는 생성자를 호출하는 의미
[출처][JAVA/자바] 생성자(Constructor)와 초기화|작성자 JOKER

기본 생성자 (매개변수가 없는)

  • 매개변수가 없는 생성자

  • 생성자가 하나도 없을 때만, 컴파일러가 자동 추가

    	클래스이름() {}	// 기본 생성자
    	Point() {}	  // Point 클래스의 기본 생성자
    
    	Card c = new Card();
    	1. 연산자 new에 의해서 메모리(heap)에 Card 클래스의 인스턴스가 생성된다.
    	2. 생성자 Card()가 호출되어 수행된다.
    	3. 연산자 new의 결과로, 생성된 Card 인스턴스의 주소가 반환되어 참조변수 c에 저장된다.
class Data_1 {
	int value;
    // 기본생성자 추가할 필요가 없음. 생성자가 없기떄문에 컴파일러가 자동 추가
}

class Data_2 {
	int value;
	
    Data_2() {} // 기본 생성자를 추가하면 에러가 사라짐
	Data_2(int x) {   // 매개변수가 있는 생성자.
		value = x;
	}
}

class Ex6_11 {
	public static void main(String[] args) {
		Data_1 d1 = new Data_1();
		Data_2 d2 = new Data_2(); //  기본 생성자를 호출하기 때문에 compile error발생
//      Data_2 d2 = new Data_2(10); // 기본생성자 안쓸거면 이렇게 써야됨
	}
}

기본 생성자가 컴파일러에 의해서 추가되는 경우는 클래스에 정의된 생성자가 하나도 없을 때 뿐이다.

매개 변수가 있는 생성자

class Car {
	String color;		// 색상
	String gearType;	// 변속기 종류 - auto(자동), manual(수동)
	int door;			// 문의 개수

	Car() {}

	Car(String c, String g, int d) {
		color = c;
		gearType = g;
		door = d;
	}
}

class Ex6_12 {
	public static void main(String[] args) {
		Car c1 = new Car();
		c1.color    = "white";
		c1.gearType = "auto";
		c1.door = 4;

		Car c2 = new Car("white", "auto", 4);

		System.out.println("c1의 color=" + c1.color + ", gearType=" + c1.gearType+ ", door="+c1.door);
		System.out.println("c2의 color=" + c2.color + ", gearType=" + c2.gearType+ ", door="+c2.door);
	}
}

인스턴스를 생성한 다음에 인스턴스변수의 값을 변경하는 것보다 매개변수를 갖는 생성자를 사용하는 것이 코드를 보다 간결하고 직관적으로 만든다.

클래스를 작성할 때 다양한 생성자를 제공함으로써 인스턴스 생성 후에 별도로 초기화를 하지 않아도 되도록 하는 것이 바람직하다.


this(), this

생성자 this(), this(매개변수)

생성자에서 다른 생성자 호출할 때 사용

조건

  • 생성자의 이름으로 클래스이름 대신 this를 사용한다.
  • 한 생성자에서 다른 생성자를 호출할 때는 반드시 첫줄에서만 호출이 가능하다.

참조변수 this

인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있다.

  • 인스턴스 메소드 (생성자 포함) 에서 사용 가능
  • 지역변수와 인스턴스변수를 구별할 때 사용
  • 모든 인스턴스 메소드에 지역변수로 숨겨진 채로 존재한다.

Getter Setter

SET, GET 메소드를 사용하는 이유는 외부로부터 변수값에 직접적으로 접근하는것을 막기 위해서다. 직접 접근하게 되면 값이 변하게 되고 그러면 데이터 무결성이 깨질 수 있기 때문이다.

대표적으로 자바에서는 함수를 통해 값을 전달받고, 전달하고 방식을 권장하고 있다.
또한 클래스 내에서 변수 private(캡슐화, 정보은닉)를 선언해서 외부에서 접근할 수 없도록 한다.

getter는 private를 외부로 꺼내는 메서드, setter는 private에 값을 넣는 메서드이다.

private 변수를 다른 클래스에 꺼내는 메서드는 get + 변수명(첫글자 대문자)

private 변수에 값을 초기화하는 메서드는 set + 변수명(첫글자 대문자)

Getter :

      내부의 멤버변수에 저장된 값을 외부로 리턴.

      메개변수는 없고, 리턴값만 있는 (void 불가) 메서드로 정의한다. 

      메서드명은 주로 getXXX() 메서드 형식으로 지정

      XXX은 해당 멤버변수의 변수명을 사용.

Setter :

	  외부로부터 데이터를 전달받아 멤버변수에 저장.

      매개변수만 있고, 리턴값은 없는 (반드시 void) 메서드로 정의.
class A {
	private int num = 10;

	public int getNum() {
		return a;
	}

	public void setNum(int a) {
		this.a = a;
	} 
}


변수의 초기화

0개의 댓글