본문 바로가기
Java

자바 #006_클래스

by haheehee 2022. 12. 12.

객체 생성 - 메모리를 점유시키는 것.

 

객체(Object)는 클래스의 최고 조상으로, 자신의 속성을 가지면서 식별 가능한 것을 말한다. 

객체는 속성(field) + 동작(method)로 구성된다.

 

객체와 객체는 메소드를 통하여 상호작용이 가능하다.

 

자바는

집합/사용 관계에 있는 객체를 하나씩 설계하고, 조립하여 다양한 프로그램을 개발하는 객체 지향 프로그래밍 이다.

객체 지향 프로그래밍은 유지보수 측면에서 아주 좋다.


클래스

자바의 설계도.

Instance : 클래스로부터 만들어진 객체이며, 현재 만들어져서 사용하고 있는 객체를 말한다. 

 

객체 지향 프로그래밍은 클래스를 설계하고, 이 클래스로 사용할 객체를 생성하여 객체를 사용한다.

 

new 연산자로 메모리 Heap 영역에 객체를 생성한다.

객체 생성 후 객체 번지가 리턴되며, 이를 클래스 변수에 저장해 변수를 통해 객체를 사용할 수 있다. 

 

클래스 용도

  1. 라이브러리(API : Application Program Interface) 클래스 -> main 메소드가 없는 클래스
  2. 활용 클래스(실행 클래스) -> main 메소드 제공

 

클래스의 멤버

  • Field(필드) : 객체 데이터 저장
  • Constructor(생성자) : 객체 생성 시 초기화
  • Method(메소드) : 객체의 동작 실행

필드 - 객체의 고유 데이터로 객체의 현재 상태 데이터와 같은 것을 저장한다. 

 

필드는 클래스 중괄호 블록 내에 선언된다. 

생성자와 메소드 내부에 선언 불가하다. 

 

필드의 초기값이 생략되면, 기본 초기값으로 자동 설정된다.

  • 0
  • \u0000(char)
  • 0L(long)
  • 0.0F(float)
  • 0.0(double)
  • false(boolean)
  • null(배열, 클래스, String, 인터페이스)

필드는 클래스 내부에서는 필드 이름으로 읽고 수정할 수 있다. 

클래스 외부에서는 클래스로부터 객체를 생성한 후에 사용 가능하다. 

// API 클래스
package ;

public class FieldInitValue {
	// 필드
	byte byteField;
	short shortField;
	int intField;
	long longField;
	
	boolean booleanField;
	char charField;
	
	float floatField;
	double doubleField;
	
	int[] arrField;
	String referenceField;
}
// 활용 클래스
package ;

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);
	}
}

필드 결과


생성자 - 객체의 초기화를 담당하여 객체를 사용할 준비를 한다.

 

클래스로부터 new 연산자로 객체를 생성할 때 생성자를 호출하여 초기화.

 

생성자가 실행되면, Heap 영역에 객체가 생성되고, 번지가 리턴된다. 

 

클래스 내부에 생성자 선언을 생략하면, 기본 생성자(default constructor)가 자동 생성된다.

 

생성자 선언에서 매개변수는 생략도 가능하며, 여러 개 선언도 가능하다. 

생성자의 매개 변수 이름은 필드 이름과 유사하거나 동일하게 사용하는 것이 좋다.

필드와 생성자의 매개 변수 이름이 동일할 경우, this.필드 의 형태로 표현한다.

 

생성자 선언 생략으로 기본 생성자가 자동생성된 경우가 아니라면,

명시된 생성자(매개변수)의 형태로 꼭 사용하여야 한다. 

 

필드는 클래스 내에서 선언된다.

필드의 초기화는 클래스 내에서 선언과 함께 초기화될 수도 있고, 

생성자를 통하여 초기화될 수도 있다. (객체를 생성할 때)

// API
package ;

public class Korean {
	// 필드
	String nation = "대한민국";
	String name;
	String ssn;
	
	// 생성자
	public Korean(string name, String ssn) {
		this.name = name;
		this.ssn = ssn;
	}
}
// 활용 라이브러리
package ;

public class KoreanExample {

	public static void main(String[] args) {
		Korean k1 = new Korean("하히", "970707-1234567");
		System.out.println("k1.name : " + k1.name);
		System.out.println("k1.ssn : " + k1.ssn);
		
		System.out.println();
		
		Korean k2 = new Korean("티스토리", "011225-1234567");
		System.out.println("k2.name : " + k2.name);
		System.out.println("k2.ssn : " + k2.ssn);
	}
}

생성자 오버로딩(Overloading)

매개 변수가 다른 생성자를 여러 개 선언한 경우를 말한다.

다양한 데이터를 사용하여 객체화하기 위해 사용된다. 

(매개 변수 이름만 바꾸는 것은 해당되지 않으니 유의)

 

this

생성자에서 다른 생성자 호출하는 것.

생성자 첫 줄에서만 허용된다. 

필드 초기화 내용을 한 생성자에만 집중 작성하고 나머지 생성자는 초기화 내용을 가진 생성자로 호출.

출처 : 혼공자바


메소드 - 행동할 동작을 정의한 지시어 또는 그들의 모음

리턴타입 메소드이름([매개변수선언, ...]) {
	실행문;
    
    return ;(리턴타입이 void가 아니라면)
}

 

클래스이름은 대문자로 시작하는 것이 관례이며,

메소드 이름은 소문자로 시작하는 것이 관례. camel 표기법.

 

매개변수의 개수를 모를 경우에는 배열타입으로 선언이 가능하다. 

int sum1(int[] values) { }

이렇게!

혹은 배열을 생성하지 않고 값의 목록만 넘겨주는 방식도 사용된다. 

int sum2(int ... values) { }

// API 라이브러리
package ;

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;
	}
}
// 실행 라이브러리
package ;

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);
	}
}

매개변수 결과

 

리턴값이 없는 메소드는 void 타입을 메소드 앞에 명시해주어야 한다. 

접근 제한자

  • public 접근 제한자 : 외부 클래스가 자유롭게 사용
  • protected 접근 제한자 : 같은 패키지 혹은 자식 클래스에서 사용
  • private 접근 제한자 : 외부에서 사용할 수 없음
  • default 접근 제한자 : 같은 패키지에 소속된 클래스에서만 사용

 

메소드 호출은 클래스 내부에서는 단순히 메소드 이름으로 호출하며,

클래스 외부에서는 클래스 객체 생성 후, 참조 변수를 사용하여 메소드를 호출할 수 있다. 

클래스 참조변수 = new 클래스(매개값, ...);

참조변수.메소드(매개값, ...);	// 리턴값이 없는 경우, 혹은 리턴값을 받지 않을 경우
타입 변수 = 참조변수.메소드(매개값, ...);	// 리턴값이 있으며, 리턴값을 받고 싶은 경우

 

메소드 오버로딩(Overloading)

같은 이름의 메소드를 여러 개 선언.

매개값을 다양하게 받고 처리하기 위하여 오버로딩을 한다. 

오버로딩을 하기 위해서는 메소드의 매개변수의 타입과 개수, 순서 중 하나는 무조건 달라야 한다.

 

오버로딩된 메소드를 호출할 때, JVM 은 매개값 타입을 보고 메소드를 선택하여 실행한다.


인스턴스 멤버 - 객체마다 가지고 있는 멤버. 객체를 생성한 후 사용할 수 있는 필드와 메소드.

  • 인스턴스 필드 : Heap 영역의 객체마다 가지고 있는 멤버. 객체마다 다른 데이터를 저장한다.
  • 인스턴스 메소드 : 객체가 있어야 호출이 가능하다. 

static 멤버 - 객체와 상관 없는 멤버. 메소드에 위치한다. 

  • 정적 필드 및 상수 : 객체 없이 클래스만으로도 사용이 가능
  • 정적 메소드 : 객체 없이 클래스만으로 호출 가능한 메소드

 

this

현재 만들어지고 있는으로 이해하고 사용하면 된다. 

객체 내에서 인스턴스 멤버에 접근하기 위해 사용되는 예약어이다. 

생성자와 메소드의 매개 변수 이름이 필드와 동일할 경우, 필드임을 지정하기 위하여 사용된다.

 

정적(static) 멤버

객체를 생성하지 않고 사용할 수 있는 필드와 메소드를 말한다. 

객체를 생성하지 않는다 뿐이지, 사용방법은 똑같다. 

클래스 이름과 함께 도트 연산자로 접근하면 된다. ( 클래스.필드; 이런식으로!! )

 

객체마다 다를 수 있는 필드 값은 인스턴스 필드로 선언하고,

객체마다 다를 필요가 없는 필드값은 정적 필드로 선언하는 것이 이득이다.

예를들어 pi 값은 3.14...로 고정되어 있기 때문에 static으로 선언 하는 것이 좋다.

 

  • 정적 메소드를 선언할 때, 정적 메소드 내부에 인스턴스 필드 및 메소드를 사용할 수 없다.
  • 정적 메소드를 선언할 때, this키워드( 그 객체 자신을 참조하는)를 사용할 수 없다.
  • 정적 메소드에서 인스턴스 멤버를 사용하려면, 객체를 우선 생성한 후, 참조변수로 접근해야 한다.
  • main() 메소드도 동일하게 생각하여 규칙을 적용하면 된다. ( public static void main(String[] args) { } )
public class Student {	// 인스턴스
	int studentNum;
	
	void run() {
		System.out.println("학번은 " + studentNum + " 입니다.");
	}
	
	public static void main(String[] args) {	// static
		Student stNum = new Student();
		stNum.studentNum = 20221212;
		stNum.run();
	}
}

main() 메소드 정적 규칙 결과

(main문도 static 멤버이기 때문에, 인스턴스 멤버의 변수나 메소드를 사용하려면 사용권한을 얻어야 한다. new 예약어로 객체를 생성해서 사용하면 된다. 하지만, 그 반대는 static(다 사용가능)이므로 객체 생성 없이 그냥 써도 된다. )


싱글톤(Singleton)

전체 프로그램에서 단 하나의 객체만 만들도록 하는 코딩 기법이다.

 

클래스 외부에서 new연산자를 통해 생성자를 호출하는것을 불가능하게 하도록

private 접근 제한자를 사용한다. 

정적 필드를 자신의 타입으로 선언하고, 자신의 객체를 생성해 초기화한다. 

외부에서 호출할 수 있도록 getInstance()를 선언한다. 

정적필드에서 참조하는 자신 객체를 리턴한다. 

// API 라이브러리
package ;

public class Singleton {
	private static Singleton singleton = new Singleton();
	
	private Singleton() {
		
	}
	
	static Singleton getInstance() {
		return singleton;
	}
}
// 활용 라이브러리
package ;

public class SingletonEx {

	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 객체 입니다. ");
		}
	}
}

싱글톤 결과


final 필드

초기값이 저장되면 최종값이 되는 필드이다.

프로그램 실행 도중 수정이 불가능하다.

 

  1. 필드 선언 시 초기화를 한다.
  2. 객체 생성 시 외부 데이터로 초기화를 해야하는 경우, 생성자에서 초기화를 한다.(인스턴스 필드일 경우)

정적 final 필드는 관례적으로 모두 대문자로 작성(상수를 생각하면 된다.)

static final double PI = 3.14519;  // 수정 불가능

 

final 값에서 static이 없으면, 생성자로 초기화할 수 있으니 전체 대문자화 하지 않는다.


Package

프로젝트를 개발할 때, 클래스를 체계적으로 관리하기 위해 사용하는 파일 시스템의 폴더.

코드 제일 첫번째 줄에 선언한다. 

package 상위패키지.하위패키지;

 

import 문

사용하고자 하는 클래스 혹은 인터페이스가 다른 패키지에 속할 경우, import문을 통해 불러온다. 

패키지 선언 바로 밑에 선언.


Getter와 Setter 메소드

외부에서 객체에 마음대로 접근하면 객체의 무결성이 깨질 수 있으므로 getter와 setter를 사용한다.

 

Setter 메소드

외부의 값을 받아 필드의 값을 변경하는 것이 목적이다. 

유효한 값만 필드로 저자할 수 있다.

 

Getter 메소드

외부로 필드값을 전달하는 것이 목적이다.

필드값을 가공하여 외부로 전달 가능.

메모리에 저장되어 있는 것을 java에 저장.

package ;

public class Car {
	// 필드
	private int speed;
	private boolean stop;
	
	// 생성자
	
	// 메소드
	public int getSpeed() {
		return speed;
	}
	public void setSpeed(int speed) {
		if(speed < 0) {
			this.speed = 0;
			return;
		} else {
			this.speed = speed;
		}
	}
	
	public boolean isStop() {
		return stop;
	}
	public void setStop(boolean stop) {
		this.stop = stop;
		this.speed = 0;
	}
}
package ;

public class CarEx {
	public static void main(String[] args) {
		Car myCar = new Car();
		
		myCar.setSpeed(-50);
		System.out.println("현재 속도 : " + myCar.getSpeed());
		
		myCar.setSpeed(60);
		System.out.println("현재 속도 : " + myCar.getSpeed());
		
		if(!myCar.isStop()) {
			myCar.setStop(true);
		}
		System.out.println("현재 속도 : " + myCar.getSpeed());
	}
}

보안때문에 API라이브러리의 필드는 private접근 제한자를 많이 사용한다. 

getter와 setter는 무조건 필드를 이용하여 선언한다. 

setter는 메모리쪽으로 정보를 주는 것!

getter는 전달하는 것!

 

 

 

 

 

 

 

 

 

 

 

 

 

출처 : 혼자 공부하는 자바 (신용권)

댓글