[Java] 객체지향 프로그래밍 (2)

당당·2023년 4월 22일
0

Java

목록 보기
17/20
post-thumbnail

📔설명

이전 시간에 등장했던 static에 대해 알아보자.
그리고, 생성자this에 대해 알아보고 이것을 응용해서 적용해보자!


🧀static

변수

클래스 Foo를 만들고, 그 안에는 두가지의 변수를 줄 것이다.

static String classVar="I class var"
String instanceVar="I instance var"

클래스의 소속인 classVar과, 인스턴스 소속인 instanceVar이다.

class Foo{
	public static String classVar="I class var";
	public String instanceVar="I instance var";
}
public class StaticApp {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(Foo.classVar); //OK
		System.out.println(Foo.instanceVar); //Error
	}

}

여기서 보면, Foo.classVar는 에러가 나지 않지만,
Foo.instanceVar는 에러가 나는 것을 알 수 있다. 즉, instanceVar는 인스턴스를 통해서 사용하도록 고안된 변수다는 것을 알 수 있다.

메소드

classMethod()라는 함수를 만들고, 그 안에서 테스트를 해보자.

class Foo{
	public static String classVar="I class var";
	public String instanceVar="I instance var";
	public static void classMethod() {
		System.out.println(classVar); //Ok
		System.out.println(instanceVar); //Error
	}
}
public class StaticApp {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(Foo.classVar);
//		System.out.println(Foo.instanceVar);
	}

}

classMethod()안에서 classVar는 접근이 가능하나 instanceVar는 접근이 안돼서 오류가 뜨는 것을 확인할 수 있다.

이번엔 instanceMethod()를 만들어보고 위와 똑같은 내용으로 채워보자.

class Foo{
	public static String classVar="I class var";
	public String instanceVar="I instance var";
	public static void classMethod() {
		System.out.println(classVar); //Ok
//		System.out.println(instanceVar); //Error
	}
	public void instanceMethod() {
		System.out.println(classVar); //Ok
		System.out.println(instanceVar); //Ok
	}
}
public class StaticApp {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(Foo.classVar);
//		System.out.println(Foo.instanceVar);
	}

}

classMethod()와 다르게 instanceMethod()에서는 둘다 에러가 나지 않는다.

이제 메소드에 접근을 해보자.

public class StaticApp {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(Foo.classVar);
//		System.out.println(Foo.instanceVar);
		Foo.classMethod(); //ok
		Foo.instanceMethod(); //error
	}

}

Foo.classMethod()는 에러가 없지만, Foo.instanceMethod()는 에러가 난다. 인스턴스 메소드는 인스턴스 소속이기 때문에, 클래스를 통해서 접근하는 것은 금지되어있다!

이제 인스턴스를 생성해보자.

Foo f1=new Foo();

https://youtu.be/hvTuZshZvIo

여기서, 생성한 인스턴스 f1에 있는 classVar과 클래스 FooclassVar는 링크되어있다. 서로 값이 변경되면 서로가 영향을 받는 것이다.
그러나 instanceVar는 서로 링크되어있지 않아 영향을 받지 않는다.

그리고 메소드도 똑같이 생각하면 된다!

class Foo{
	public static String classVar="I class var";
	public String instanceVar="I instance var";
	public static void classMethod() {
		System.out.println(classVar); //Ok
//		System.out.println(instanceVar); //Error
	}
	public void instanceMethod() {
		System.out.println(classVar); //Ok
		System.out.println(instanceVar); //Ok
	}
}
public class StaticApp {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(Foo.classVar);
//		System.out.println(Foo.instanceVar);
		Foo.classMethod();
//		Foo.instanceMethod();
		
		Foo f1=new Foo();
		Foo f2=new Foo();
		
		System.out.println(f1.classVar); //I class var
		System.out.println(f1.instanceVar); // I instance var
		
		f1.classVar="changed by f1"; 
		System.out.println(Foo.classVar); //changed by f1
		System.out.println(f2.classVar);//changed by f1
		
		f1.instanceVar="changed by f1";
		System.out.println(f1.instanceVar); //changed by f1
		System.out.println(f2.instanceVar); //I instance var
		
	}

}

해당 소스코드를 보고, 하나하나 따져보도록 하자!

f2인스턴스를 생성하자.

그리고 f1으로 classVar에 접근을 해보자.
그러면 클래스 FooclassVar를 가리키므로 I class var를 출력한다.

f1instanceVar는 클래스에 셋팅된 기본 값인 I instance var가 복제된 상태이기 때문에 f1.instanceVarI instance var가 출력이 된다.

f1.classVar="changed by f1"로 값을 바꾸면 static이기 때문에 클래스 FooclassVar 값이 변하게 된다.
Foo.classVarf2.classVar를 하면 둘다 changed by f1으로 출력이 된다.

f1.instanceVar="changed by f1"을 통해 instanceVar의 값을 바꾸면 f1은 자신의 instanceVar를 바꾼 것이기 때문에, f2instanceVar값은 바뀌지 않는다.


👉🏻생성자와 this

생성자

OthersOOP.java를 살펴보자. (이전시간의 다른 이의 클래스와 인스턴스)
여기서, FileWriter f1=new FileWriter("data.txt")에서,
인스턴스를 생성하는 시점에 "data.txt"는 꼭 들어가야 한다.

인스턴스가 생성될 때, 또는 초기값을 주고 싶을 때 생성자라는 것을 이용한다.

MyOOP.java를 보자.

여기에서 사용자는 구분자를 주는 것을 깜빡하기가 쉽다.
그러므로 인스턴스를 생성할 때, delimiter값을 지정하지 않으면 인스턴스 화 되지 못하도록 해보자.

public class MyOOP {
	
	public static void main(String[] args) {
		
		Print p1=new Print("----");
		p1.A();
		p1.A();
		p1.B();
		p1.B();
		
		Print p2=new Print("****");
		p2.A();
		p2.A();
		p2.B();
		p2.B();
		
		
		p1.A();
		p2.A();
		p1.A();
		p2.A();
	}
	

}

원하는 건 이렇게 되는 것이다!

Java에서 클래스의 이름과 똑같은 메소드를 정의하면 그것이 바로 생성자이다.


class Print{
	public String delimiter="";
	public Print(String _delimiter) {
		delimiter=_delimiter;
	}
	public void A() {
		System.out.println(delimiter);
		System.out.println("A");
		System.out.println("A");
	}
	
	public void B() {
		System.out.println(delimiter);
		System.out.println("B");
		System.out.println("B");
	}
}

매개변수를 통해 들어온 구분자의 값이 해당 클래스 안에서 변수인 delimiter값이 변경하게 된다.

this


class Print{
	public String delimiter="";
	public Print(String delimiter) {
		delimiter=delimiter;
	}
	public void A() {
		System.out.println(delimiter);
		System.out.println("A");
		System.out.println("A");
	}
	
	public void B() {
		System.out.println(delimiter);
		System.out.println("B");
		System.out.println("B");
	}
}

만약 _delimiter에서 _를 빼면, Print()생성자 안에 있는 앞 뒤의 delimiter는 둘다 매개변수 delimiter를 가리킨다.
실행시키면 구분자 없이 출력된다.


class Print{
	public String delimiter="";
	public Print(String delimiter) {
		this.delimiter=delimiter;
	}
	public void A() {
		System.out.println(this.delimiter);
		System.out.println("A");
		System.out.println("A");
	}
	
	public void B() {
		System.out.println(this.delimiter);
		System.out.println("B");
		System.out.println("B");
	}
}

this는 우리가 생성한 인스턴스를 가리키는 이름이다.
즉, 인스턴스의 delimiter 변수를 가리키는 것이다.


🎤클래스와 인스턴스 활용

이전 AccountingApp.java


public class AccountingApp {
	public static double valueOfSupply;
	public static double vatRate = 0.1;
	
	public static double getVAT() {
		return valueOfSupply*vatRate;
	}
	
	public static double getTotal() {
		return valueOfSupply+getVAT();
	}
	
	public static void main(String[] args) {
		valueOfSupply = 10000.0;
		System.out.println("Value of supply : "+valueOfSupply); //공급가
		System.out.println("VAT : "+getVAT()); //부가가치세
		System.out.println("Total : "+getTotal());//소비자가낼돈
	}

}

메소드 수업시간에 작성했던 AccountingApp.java에 클래스와 인스턴스를 도입해보자!

클래스화

Accounting이라는 클래스를 만들어보자.

class Accounting{
	public static double valueOfSupply;
	public static double vatRate = 0.1;
	public static double getVAT() {
		return valueOfSupply*vatRate;
	}
	public static double getTotal() {
		return valueOfSupply+getVAT();
	}
}

public class AccountingApp {
	public static void main(String[] args) {
		Accounting.valueOfSupply = 10000.0;
		System.out.println("Value of supply : "+Accounting.valueOfSupply); //공급가
		System.out.println("VAT : "+Accounting.getVAT()); //부가가치세
		System.out.println("Total : "+Accounting.getTotal());//소비자가낼돈
	}

}

Accounting클래스에 부가가치세랑 관련된 메소드와 변수들을 모아두었다.
그러면 이제, valueOfSupply에 접근하려면 클래스명.변수명으로 접근하고, 메소드에 접근하려면 클래스명.메소드명으로 접근하면 된다.



인스턴스화

만약,공급가가 만원일때와, 2만원일때를 번갈아가며 출력해야 한다고 가정해보자.

class Accounting{
	public static double valueOfSupply;
	public static double vatRate = 0.1;
	public static double getVAT() {
		return valueOfSupply*vatRate;
	}
	public static double getTotal() {
		return valueOfSupply+getVAT();
	}
}

public class AccountingApp {
	public static void main(String[] args) {
		Accounting.valueOfSupply = 10000.0;
		System.out.println("Value of supply : "+Accounting.valueOfSupply); //공급가
		Accounting.valueOfSupply = 20000.0;
		System.out.println("Value of supply : "+Accounting.valueOfSupply); //공급가
		
		Accounting.valueOfSupply = 10000.0;
		System.out.println("VAT : "+Accounting.getVAT()); //부가가치세
		Accounting.valueOfSupply = 20000.0;
		System.out.println("VAT : "+Accounting.getVAT()); //부가가치세
		
		Accounting.valueOfSupply = 10000.0;
		System.out.println("Total : "+Accounting.getTotal());//소비자가낼돈
		Accounting.valueOfSupply = 20000.0;
		System.out.println("Total : "+Accounting.getTotal());//소비자가낼돈
	}

}

두개의 상태만으로도 아주아주 끔찍해진다.

행복해지기 위해 인스턴스를 도입하자!

public class AccountingApp {
	public static void main(String[] args) {
		Accounting a1=new Accounting();
		a1.valueOfSupply=10000.0;
		
		Accounting a2=new Accounting();
		a2.valueOfSupply=20000.0;
		
		System.out.println("Value of supply : "+a1.valueOfSupply);
		System.out.println("Value of supply : "+a2.valueOfSupply);
		
		System.out.println("VAT : "+a1.getVAT());
		System.out.println("VAT : "+a2.getVAT());

		System.out.println("Total : "+a1.getTotal());
		System.out.println("Total : "+a2.getTotal());
	}

}

인스턴스 a1a2를 도입해서 편해졌다.
그러면 Accounting클래스는 어떻게 변해야 할까?

class Accounting{
	public double valueOfSupply;
    //vatRate는 어떤 인스턴스간에 동일하므로 instance 소속보단 클래스 소속이 더 나음
	public static double vatRate = 0.1; 
	public double getVAT() {
		return valueOfSupply*vatRate;
	}
	public double getTotal() {
		return valueOfSupply+getVAT();
	}
}

짜자잔~

생성자 추가

인스턴스가 생성될 때 valueOfSupply를 넣도록 바꿔보자!
즉, 생성자를 도입해보자~

class Accounting{
	public double valueOfSupply;
	public static double vatRate = 0.1;
	public Accounting(double valueOfSupply) {
		this.valueOfSupply=valueOfSupply;
	}
	public double getVAT() {
		return this.valueOfSupply*vatRate;
	}
	public double getTotal() {
		return this.valueOfSupply+getVAT();
	}
}

public class AccountingApp {
	public static void main(String[] args) {
		Accounting a1=new Accounting(10000.0);
		Accounting a2=new Accounting(20000.0);
		
		System.out.println("Value of supply : "+a1.valueOfSupply);
		System.out.println("Value of supply : "+a2.valueOfSupply);
		
		System.out.println("VAT : "+a1.getVAT());
		System.out.println("VAT : "+a2.getVAT());

		System.out.println("Total : "+a1.getTotal());
		System.out.println("Total : "+a2.getTotal());
	}

}

코드가 좀 더 간결해졌다!
깔끔해서 이쁘다 :)


🕦이후

다음은 상속에 대해서 배워보자!

JAVA강의가 얼마 남지 않았당..

profile
MySQL DBA 신입 지원

0개의 댓글