java 클래스

개미Coder
|2024. 4. 19. 10:20
반응형

 

 

-객체 지향의 특징

-캡슐화, 상속, 추상화, 다형성

 

#캡슐화

-객체의 필드, 메소드를 하나로 묶고, 실제 구현 내용을 감추는 것

-보호하는 이유는 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록 하기 위해서다.

 

#상속 (부모가 가지고 있는 필드와 메소드를 상속 받을 수 있다)

-상위(부모) 객체의 필드와 메소드를 하위(자식) 객체에게 물려주는 행위

-하위 객체는 상위 객체를 확장해서 추가적인 필드와 메소드를 가질 수 있음

-상속 대상 : 필드와 메소드

-상속은 다중 상속이 되지 않고, 오직 하나만 가능하다.

 

1. 상위 객채레를 재사용해서 하위 객체를 빨리 개발 가능

2. 반복된 코드의 중복을 줄임

3. 유지 보수의 편리성 제공

4. 객체의 다형성 구현

 

 

#다형성

-같은 타입이지만 실행 결과가 다양한 객체를 대입할 수 있는 성질

-부모 타입에는 모든 자식 객체가 대입

-인터페이스 타입에는 모든 구현 객체가 대입

 

-효과

-객체를 부품화시키는 것 가능, 유지보수 용이

 

 

## 객체(Object)와 클래스(Class)

 

-현실세계 : 설계도 -> 객체

-자바        : 클래스 -> 객체

 

-클래스에는 객체를 생성하기 위한 필드(속성)와 메소드(동작)가 정의

-클래스로부터 만들어진 객체를 해당 클래스의 인스턴스(instance)

객체와 인스턴스는 같은 말이다.

-하나의 클래스로부터 여러 개의 인스턴스를 만들 수 있음

 

 

# 클래스의 규칙

 

-한글 이름도 가능하나, 영어 이름으로 작성

-알파벳 대소문자는 서로 다른 문자로 인식

-첫 글자와 연결된 다른 단어의 첫 글자는 대문자로 작성하는 것이 관례

 

 

#클래스 선언

 

-하나의 클래스 안에 여러개의 클래스를 만들 수 있지만, public은 한 개만 가능하다. (접근제한자)

-소스 파일당 하나의 클래스를 선언하는 것이 관례

-소스 파일 이름과 동일한 클래스만 public으로 선언 가능

-선언한 개수만큼 바이트 코드 파일이 생성

 

 

#new 연산자 (new 뒤에는 생성자라는게 와야 한다. 필수적)

 

Scanner sc = new Scanner(System.in)

Scanner 라는 클래스로 부터 나는 sc라는 이름의 변수를 만들거야.

new 연산자는 sc라는 변수를 heap 영역에 객체로 만들어준다.

new 뒤에는 생성자를 만들어줘야 하는데, Scanner()은 생성자이다.

 

 

-객체 생성 역할 new 클래스();

-클래스()는 생성자를 호출하는 코드

-생성된 객체는 힙 메모리 영역에 생성

 

 

-new 연산자는 객체를 생성 후, 객체 생성 번지 리턴(데이터 주소를 변수에 return 해주고, 변수는 데이터 주소를 참조하게 된다)

 

 

-new는 클래스로부터 객체를 생성시키는 연산자이다. 
-new 연산자 뒤에는 생성자가 오는데, 생성자는 클래스() 형태를 가지고 있다.  (생성자는 뒤에서 학습한다.)
-new 연산자로 생성된 객체는 메모리 힙(heap) 영역에 생성된다. 
-현실 세계에서 물건의 위치를 모르면 물건을 사용할 수 없듯이 
  객체 지향 프로그램에서도 메모리 내에서 생성된 객체의 위치를 모르면 객체를 사용할 수 없다. 
  그래서 new 연산자는 힙 영역에 객체를 생성시킨 후, 객체의 주소를 return하도록 되어 있다.   
-이 주소를 참조 타입인 클래스 변수에 저장해 두면, 변수를 통해 객체를 사용할 수 있다.   

 

 

 

# 클래스의 용도

 

-main 클래스(실행클래스) + n개의 라이브러리 클래스

 

 

-라이브러리

-자체적으로 실행되지 않음

-다른 클래스에서 이용할 목적으로 만든 클래스

 

 

-실행용

-main() 메소드를 가지고 있는 클래스로 실행할 목적으로 만든 클래스

 

 

클래스는 두 가지 용도가 있다. 
하나는 라이브러리(API: Application Program Interface)용이고 다른 하나는 실행용이다. 
 # 라이브러리 클래스 : 라이브러리 클래스는 다른 클래스에서 이용할 목적으로 설계된다. 
    프로그램 전체에서 사용되는 클래스가 100개라면 99개는 라이브러리이고 단 하나가 실행 클래스이다. 
 # 실행 클래스 : 실행 클래스는 프로그램의 실행 진입점인 main() 메서드를 제공하는 역할을 한다.
 


-Student는 라이브러리 클래스이고 StudentExample은 실행 클래스이다. 
-라이브러리 클래스는 반드시 객체를 생성하고 사용해야 한다.
 (단 정적 멤버와 정적 메소드는 객체 생성없이 사용이 가능하다.)

 

 

 

# 클래스의 구성 멤버

 

-필드(Field)

-생성자(Constructor)

-메소드(Method)

 

 

# 필드(Field)

 

 

 

-메인 메서드 안에서의 변수 선언과 선언 방법이 동일하지만, 같은게 아니다.

 

-필드의 기본 초기값

 

-객체를 만들고 데이터를 참조해야 필드 사용이 가능하다.

 

 

 

Car2 myCar = new Car2();
myCar.maxSpeed = 200;
myCar.productionYear = 2024;
myCar.currentSpeed = 58;
myCar.engineStart = true;

System.out.println("myCar의 현재 Spec");
System.out.println("★제작사 : " + myCar.company);
System.out.println("★차종 : " + myCar.model);
System.out.println("★최고 속도 : " + myCar.maxSpeed);
System.out.println("★제작년도 : " + myCar.productionYear);
System.out.println("★현재 주행 속도 : " + myCar.currentSpeed);
System.out.println("★현재 차량 엔진 : " + myCar.engineStart);

System.out.println("-주행 속도 체크-");
if (myCar.currentSpeed > 120) {
    System.out.println("※경고 : 현재 주행 속도 위험");
} else {
    System.out.println("-주행 속도가 정상적입니다.-");
}

 

 

 

# 생성자

-new 연산자에 의해 호출되어 객체의 초기화 담당

-필드의 값 설정

-메소드 호출해 객체를 사용할 수 있도록 준비하는 역할 수행

 

기본 생성자(Default Constructor)

-모든 클래스는 생성자가 받느시 존재하며 하나 이상 가질 수 있음

-생성자 선언을 생략하면 컴파일러는 다음과 같은 기본 생성자 추가

-내가 생성자를 만들면, 기본 생성자는 생성이 안된다.

 

-매개변수 없이도 기본 생성자를 통해 만들고 싶으면, 내가 만든 매개변수 생성자와 함께 기본 생성자도 함께 만들어줘야, 오류가 발생하지 않는다.

 

 

 

-생성자에서 만든 매개변수(parameter)를 생성자 안에서 해당 매개변수에 대한 값을 필드에 선언한 값과 연결시켜줘야 한다.

 

 

 

-이제는 필드에다가 값을 지정하지 말고, 생성자(Constructor) 안에다가 기본적인 값을 지정해주자!

 

 

 

# 생성자 오버로딩(Overloading)

 

 

-매개변수의 타입, 개수, 순서가 다른 생성자 여러 개 선언

 

 

 

 

 

 

-매개변수 저장할 때 if문을 써서 범위 또한 지정이 가능하다. (아래는 값을 200에 제한을 걸어두고, 500을 입력하니 채널이 0으로 나온다.)

public Tv(int channel) {
    if(0 <= channel && channel <= 200 ) {
        this.channel = channel;
    }
}
Tv tv2 = new Tv(500);
System.out.println("현재 채널 : " + tv2.channel);

 

 

 

 

 

 

-class를 활용하여 각각의 생성자마다 매개변수 다르게 하여 각각의 구성이 다른 spec의 tv 만들기

package example0419;

public class TvEx {
	
	String brand;
	int inch;
	boolean power;
	int channel;
	int vol;
	
	public TvEx() {
		this.inch = 100;
	}
	
	public TvEx(int channel) {
		this.inch = 100;
		if (1<= channel && channel < 200) {
			this.channel = channel;
		} else {
			this.channel = 1;
		}
	}
	
	public TvEx(int channel, int vol) {
		this.inch = 100;
		
		if (1<= channel && channel < 200) {
			this.channel = channel;
		} else {
			this.channel = 1;
		}
		
		if(1 <= vol && vol <= 50) {
			this.vol = vol;
		} else {
			this.vol = 1;
		}
		
	}
	
	public TvEx(int channel, int vol, int brand) {
		this.inch = 100;
		if (1<= channel && channel < 200) {
			this.channel = channel;
		} else {
			this.channel = 1;
		}
		
		if(1 <= vol && vol <= 50) {
			this.vol = vol;
		} else {
			this.vol = 1;
		}
		
		switch (brand) {
		case 1 :
			this.brand = "SAMSUNG";
			break;
		case 2 :
			this.brand = "LG";
			break;
		case 3 :
			this.brand = "SONY";
			break;
		default :
			this.brand = "SAMSUNG";
	}
	

	}

}

 

-위 switch문을 if문으로 이렇게 사용할 수도 있겠다.

// 연산자 우선순위 && > ||
if (brand == 1 || (brand  != 2 && brand !=3)) {
    this.brand = "SAMSUNG";
} else if (brand == 2) {
    this.brand = "LG";
} else if(brand == 3) {
    this.brand = "SONY";
}
package example0419;

public class TvExMain {
	
	public static void main(String[] args) {
		
		System.out.println("[[==Tv spec 정리표 ==]]");
		TvEx tv1 = new TvEx();
		System.out.println("[tv1] inch : " + tv1.inch);
		System.out.println();
		
		TvEx tv2 = new TvEx(500);
		System.out.println("[tv2] inch : " + tv2.inch);
		System.out.println("[tv2] channel : " + tv2.channel);
		System.out.println();
		
		TvEx tv3 = new TvEx(168, 35);
		System.out.println("[tv3] inch : " + tv3.inch);
		System.out.println("[tv3] channel : " + tv3.channel);
		System.out.println("[tv3] channel : " + tv3.vol);
		System.out.println();
		
		TvEx tv4 = new TvEx(168, 35,7);
		System.out.println("[tv4] inch : " + tv4.inch);
		System.out.println("[tv4] channel : " + tv4.channel);
		System.out.println("[tv4] channel : " + tv4.vol);
		System.out.println("[tv4] channel : " + tv4.brand);
		System.out.println("[[모든 tv의 spec이 종료되었습니다.]]");
		
	}
}

 

 

 

 

 

 


 

 

 

 

 

## 메소드(Method)

 

-생성자(Constructor)와 차이는 생성자는 값을 초기화 하는데 사용하고, 메소드는 결과를 얻어내고자 할 때 사용한다.

 

메소드는 객체의 동작에 해당하는 중괄호 { } 블록을 말한다. 
중괄호 블록은 이름을 가지고 있는데, 이것이 메서드 이름이다.  
메소드를 호출하게 되면 중괄호 블록에 있는 모든 코드들이 일괄적으로 실행된다. 
메소드는 필드를 읽고 수정하는 역할도 하지만, 다른 객체를 생성해서 다양한 기능을 수행하기도 한다. 
메소드는 객체 간의 데이터 전달의 수단으로 시용된다. 
외부로부터 매개값을 받을 수도 있고, 실행 후 어떤 값을 return할수도 있다.

 

// return 타입이 없을 때 (void 사용)
void method(매개변수, 매개변수2) {
}

// return 타입이 있을 때
int method() {
    int result = 1+1;
    return result;
}

 

 

# 메소드선언

메소드 선언은 선언부(리턴타입 메소드이름 매개변수선언)와 실행 블록으로 구성된다. 
메소드 선언부를 메소드 signature 라고도 한다.

 

 


# 리턴타입


리턴 타입은 메소드가 실행 후 리턴히는 값의 타입을 말한다. 
메소드는 리턴값이 있을 수도 있고 없을 수도 있다. 
메소드가 실행 후 결과를 호출한 곳에 넘겨줄 경우에는 리턴값이 있어야 한다. 



예를들어 전자계산기 객체에서 전원을 켜는 powerOn() 메소드와 
두 수를 나누는 기능인 divide() 메소드가 있다고 가정해보자. 

divide() 메소드는 나늦셈의 결과를 리턴해야 하지만 powerOn() 메소드는 전원만 켜면 그만이다. 
따라서 powerOn() 메소드는 리턴값이 없고, divide() 메소드는 리턴값이 있다고 봐야 한다.
리턴값이 없는 메소드는 리턴타입에 void가 와야하며 리턴값이 있는 메소드는 리턴값의 타입이 와야 한다. 
divide() 메소드의 결과가 double 값이라면 double을 리턴 타입으로 사용해야한다.

void powerOn () {
}
double divide(int  x,  int y)  { 
}



리턴값이 있느냐 없느냐에 따라 메소드를 호출히는 방법이 조금 다르다. 위의 두 메소드는 다음과 같이 호출할 수 있다.

powerOn();
double result = divide ( 10, 20 );

powerOn() 메소드는 리턴값이 없기 때문에 변수에 저장할 내용이 없다. 단순히 메소드만 호출하 면 된다. 
그러나 divide () 메소드는 10을 20으로 나눈 후 0.5를 리턴하므로 이것을 저장할 변수가 있어야 한다. 
리턴값을 받기 위해 변수는 메소드의 라턴 타입인 double 타입으로 선언되어야 한다.


만약 result 변수를 int타입으로 선언하게 되면 double 값을 저장할 수 없기 때문에 컴파일 에러가 발생한다.

int result = divide ( 10, 20 ); // 컴파일 에러발생 (리턴값은 doube이지만 저장을 int변수에 대입)


리턴 타입이 있다고 해서 반드시 리턴값을 변수에 저장할 필요는 없다. 
리턴값이 중요하지 않고, 메소드 실행이 중요할 경우에는 다음과 같이 변수 선언 없이 메소드를 호출할 수도 있다.

 

 

-메소드를 사용하려면(클래스 안에 있는 필드를 사용하려면), 객체가 생성이 되어야 한다.

 

 

 

 

-return 값이 있는 메서드와 없는 메서드 호출하기

 

void channelUp () {
    this.channel++;
}

void channelDown () {
    this.channel--;
}

void powerOnOff () {
    // boolean의 기본값이 false이기에 부정형인 !를 넣어서 반대로 만들어줌.
    this.power = !power;
    if (power) {
        System.out.println("전원이 켜졌습니다.");
    } else {
        System.out.println("전원이 꺼졌습니다.");
    }
}
System.out.println(tv1.channel);
tv1.channelUp();
System.out.println(tv1.channel);
tv1.channelUp();
System.out.println(tv1.channel);

tv1.channelDown();
System.out.println(tv1.channel);
tv1.channelDown();
System.out.println(tv1.channel);

tv1.powerOnOff();
tv1.powerOnOff();
tv1.powerOnOff();

 

 

 

 

-return 값이 없는 void 메소드와 return 값이 있는 int 타입의 메소드의 분명한 차이

 

 

 

-return 값이 true와 false인 메소드 활용 예제

 

 

-메서드의 활용으로 차량이 주유소에서 가스를 충전했다가 달리는 것 까지 재현이 가능하다.

package example0419;

public class GasCar {
	
	int gas;
	
	
	//gas가 있는지 없는지 확인해준다.
	boolean isLeftGas() {
		if (gas <= 0) {
			System.out.println("gas가 없습니다.");
			return false;
		}
		System.out.println("현재 가스량 : " + gas);
		return true;
	}
	
	
	// 주유소 (가스 충전하는 곳)
	void setGas(int gas) {
		this.gas = gas;
		System.out.println("가스를 충전했습니다. 충전 가스량 : " + this.gas);
	}

	// 차 달리는 코드 (가스 없어질 때 까지 달림)
	void run() {
		while (true) {
			if (gas > 0) {
				System.out.println("차가 달립니다. 가스잔량 : " + gas);
				gas--;
			} else {
				System.out.println("가스가 없어 차가 멈춥니다.");
				return;
			}
		}
	}
	
	
	
}

 

package example0419;

public class GasCarMain {

	public static void main(String[] args) {


		GasCar gasCar = new GasCar();

		gasCar.setGas(5);

		boolean gasState = gasCar.isLeftGas();

		if(gasState) {
			System.out.println("차량이 출발합니다.");
			gasCar.run();
		}
		
		if(gasCar.isLeftGas()) {
			System.out.println("gas를 충전할 필요가 없습니다. 현재 가스 잔량 : " + gasCar.gas);
		} else {
			System.out.println("gas가 없습니다. gas를 충전하세요.");
		}
		
	}
}

 

 

-return은 항상 호출한 곳으로 간다.

-avg에 있는 plus(x, y)는 avg를 호출한 곳에서의 매개변수 값을 확인해서 넣으면 된다.(단순하게 생각하자)

 

 

 

-생성자(Constuctor)과 비슷한 메서드(Method) 오버라이딩

-역시나 생성자 오버라이딩과 마찬가지로 타입이 겹치니 오류가 뜬다.

 

 

# 딜레이 만드는 코드

try {
    Thread.sleep(1000);
    System.out.println(3);
    Thread.sleep(1000);
    System.out.println(2);
    Thread.sleep(1000);
    System.out.println(1);
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
package example0419;

public class Potion {
	
	
	int hp;
	int damage;
	String monsterName;
	int monsterDamage;
	
	public void myStatus(int hp) {
		for (int i = 0; i < 1; i++) {
			this.hp = hp;
			if (hp > 100) {
				System.out.println("hp는 100미만 이여야 합니다. 다시 지정해주세요.");
				this.hp = 0;
				break;
			} else {
				System.out.println("올바른 hp입니다.");
			}
			System.out.println("당신의 hp =" + hp );
		}
	}
	
	void monster () {
		int monsterNum = (int) (Math.random() * 4) + 1;
		if(monsterNum == 1) {
			this.monsterName = "슬라임";
			this.monsterDamage = 10;
			System.out.println("가장 약한 슬라임이 소환됐습니다.");
		} else if(monsterNum == 2) {
			this.monsterName = "스톤골렘";
			this.monsterDamage = 20;
			System.out.println("스톤골렘이 소환됐습니다.");
		} else if(monsterNum == 3) {
			this.monsterName = "초록버섯";
			this.monsterDamage = 30;
			System.out.println("초록버섯이 소환됐습니다.");
		} else {
			this.monsterName = "드레이크";
			this.monsterDamage = 50;
			System.out.println("가장 강한 드레이크가 소환됐습니다.");
		}
	}
	
	void fight () {

		// 메서드로 만들기
		try {
			Thread.sleep(1000);
			System.out.println(3);
			Thread.sleep(1000);
			System.out.println(2);
			Thread.sleep(1000);
			System.out.println(1);
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(this.monsterName + "과의 전투가 시작됩니다.");
		System.out.println();
	}
	
	boolean hpCheck () {
		if (hp <= 0) {
			System.out.println("hp가 부족합니다.");
			return false;
		}
	}

}
package example0419;

public class PotionMain {

	public static void main(String[] args) {

		
		
		
		Potion gamer = new Potion();
		
		gamer.myStatus(100);
		gamer.monster();
		
		gamer.fight();
		
		
		
		
		
		
	}

}
반응형

'java(2)↗' 카테고리의 다른 글

java 상속  (0) 2024.04.23
java 클래스(2)  (0) 2024.04.22
java 데이터 참조 타입  (0) 2024.04.18
java 제어문(if, switch, for, while)  (0) 2024.04.16
java 연산자  (0) 2024.04.15