728x90

<클래스와 인스턴스 & 객체지향 이후 공부할 것>

  1. 상속(inheritance)
  2. 인터페이스(Interface)
  3. 패키지(package)

 

1.상속inheritance

class Parent{
		public void method1() {
			// ...
		}
}

Q.위에서 저 클래스를 직접 수정할 수 없거나 변경하지 말아야하는 상황에서 method2()를 추가하고 싶다면?

A.저 클래스 전체를 카피해서 이름 다른 클래스로 해서 method2()를 추가

이 방법은 class parent의 method1의 코드 개선, 버그 해결 등을 하게 되면 이 method1을 카피한 수많은 모든 코드를 다 수정해야함. 일 산더미...?

 

이 문제 개선을 위해 자바에서 제공하는 기능이 상속

extends를 붙여서 상속표시

class Child extends Parent{
		public void method2() {
				// ... 
		}
}

Child라는 클래스에는 실제로는 method1이 구현되어 있지 않지만, 상속 받았기에 class Parent에 있기에 class Child에서도 사용 가능해짐

 - class parent 코드가 수정되면, 동시에 다른 자식 클래스에도 다 같이 수정된다

 

 

2.인터페이스(Interface)

interface contract {
		public String method1(String param);
		public int method2(int param);
}

원래 인터페이스에는 메소드의 이름, 파라미터와 리턴값의 형식은 적으나 실제 내용은 적지 않는다

 

class Concreate1 implements Contract {

}

위 코드 의미

Concreate1 이라는 클래스Contract 라는 인터페이스에 적혀있는 메소드들의 형식을 구현했다 or 구현해야한다는 의미

이 상태로 Concreate1 클래스를 컴파일하면 컴파일조차 안된다

 - 규칙위반 때문

 - Contract에 적혀 있는 메소드들을 정의해야한다는 규칙을 어겼기 때문

 

implements에 contract를 적어놓게 되면 class Concreate1은 interface의 contract적혀있는 형태의 메소드구체적으로 구현해야하는 책임을 갖는다

class Concreate1 implements Contract{
		public String method1(String param) {
				return "foo";
		}
		public int method2(int param) {
				return 1;
		}
}
// 클래스 콘크리트1 안에 내용이 메소드1의 내용으로 채워짐

 

 

마찬가지로 class Concreate2

Concreate1Concreate2서로 다른 클래스이지만 확신할 수 있는 것은,

이 클래스들은 반드시 contract에 약속되어 있는 정의되어있는 형태의 멤버들을 구현하고 있을 것이라는 것. 일종의 무언의 약속

 

3.패키지(package)

클래스 이름은 같지만 기능이 다른 두 클래스가 존재할 수 있다

ex)서로 다른 디렉토리에 있는 경우, 한 컴퓨터 안에 같은 이름의 파일이 여러개 존재할 수 있는 것

 

클래스도 서로 다른 패키지에 묶여있으면 같은 이름의 클래스가 공존 가능

많아진 클래스정리정돈의 도구로써 사용되는 것이 패키지

패키지보다 더 큰 정리정돈의 도구는 자바에서는 없다

 

 

 

 

 

728x90
반응형
728x90

어떨 때에 인스턴스를 쓰는게 좋을까?

<클래스화를 계속 써야할 상황>

1)공급가액 파라미터가 한번 세팅이 되고나서 내부적 상태가 바뀌지 않고 getVAT(), Total() 같은메소드들로 부가가치세, 총액 같은 값만 받으면 되는 간단한 상태면 클래스 사용하면 된다

또는

2)내부적인 상태가 한번 세팅이되면 여러 작업들이 끝나고 그 다음에 새로운 내부적인 상태가 변화가 오는 케이스에서도 클래스를 인스턴스화 시킬 필요는 없다고 본다

 

<인스턴스화를 써야할 상황>

그런데 클래스의 상태가 계속 바뀌어야하는 상황이라면?

ex) 공급가액(vauleOfSupply) 1만 세팅에서 2만,3만 등 경우의수가 엄청나게 많아지고 계속 바꿔가면서 써야한다면?

(즉, 클래스의 상태가 계속 바뀌어야하는 상태일 때는?)

Accounting08_2.valueOfSupply = 10000.0;		
System.out.println("Value of supply : " + Accounting.valueOfSupply);
System.out.println("VAT : " + Accounting.getVAT());
System.out.println("Total : " + Accounting.getTotal());

Accounting08_2.valueOfSupply = 20000.0;		
System.out.println("VAT : " + Accounting.getVAT());

Accounting08_2.valueOfSupply = 50000.0;		
System.out.println("VAT : " + Accounting.getVAT());

Accounting08_2.valueOfSupply = 900.0;		
System.out.println("Total : " + Accounting.getTotal());

 

공급가액(vauleOfSupply)이 하나가 아닌 내부적으로 수십개의 값들이 있고 계속 바꿔야한다면 버그 발생 확률 고위험

하나의 클래스여러 상태에서 돌려써서 버그발생 확률이 높아지게 되는 것

이럴 때 인스턴스화

독립된 인스턴스기에 상태별로 인스턴스를 만들어서 분리시키고 개별맞춤으로 관리가능

 

 

인스턴스가 생성될 때, 인스턴스가 내부적으로 꼭 가져야될 값(valueOfSupply)을 생성자 레벨에서 강제하고 싶다면?

A.아래의 코드 추가 및 인스턴스 생생코드 new Accounting(생성자); 생성자 인자부분 채우기

// 생성자가 호출될 때 인자를 매개변수로 전달하고 싶기에 public accounting() {}에 valueOfSupply를 넣는다
public Accounting08_3(double valueOfSupply) { 
		this.valueOfSupply = valueOfSupply;
}
// 생성자 인자 넣기
Accounting08_3 a1 = new Accounting08_3(**10000.0**);
        a1.valueOfSupply = 10000.0;

public accounting() {} 구현해주면 된다

생성자가 호출될 때 인자를 매개변수로 전달하고 싶기에 public accounting() {}에 valueOfSupply를 넣어주고 this.valueOfSupply 추가

 

 

위의 코드 this.valueOfSupply와 = valueOfSupply;가 가리키는 곳은?

this 키워드

 

 

 

전체코드

// OOP 8.2. 활용 - 인스턴스화

// 클래스화 to 인스턴스화

 
//class Accounting08_2{		// 클래스화
//
//    public static double valueOfSupply;		
//    public static double vatRate = 0.1;		
//    public static double getVAT() {
//        return valueOfSupply * vatRate;
//    }
//    public static double getTotal() {
//        return valueOfSupply + getVAT();
//    }
//}
//					클래스화
//      ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
//					인스턴스화

class Accounting08_2{		// 인스턴스화
	// 인스턴스 소속, static 제거
	// static은 클래스소속이고 클래스가 인스턴스에 접근하면 에러나는건 어떤 인스턴스인지 모르기때문 a1?a2?
	public double valueOfSupply;		
	public static double vatRate = 0.1;	// 부가가치세는 어느 인스턴스나 10% 고정이기에 static설정이 유리	
	public double getVAT() {			// 인스턴스 만들 때마다 메모리 사용하지 않아도 되고, 
	    return valueOfSupply * vatRate; // vatRate파라미터는 얘 하나로 조절 가능해서 유지보수 용이
	}
	public double getTotal() {
	    return valueOfSupply + getVAT();
	}
}

public class OOP08_2 {
	public static void main(String[] args) {		

//        Accounting08_2.valueOfSupply = 10000.0;		
//        System.out.println("Value of supply : " + Accounting.valueOfSupply);
//        System.out.println("VAT : " + Accounting.getVAT());
//        System.out.println("Total : " + Accounting.getTotal());
//        
//        Accounting08_2.valueOfSupply = 20000.0;		
//        System.out.println("VAT : " + Accounting.getVAT());
//        
//        Accounting08_2.valueOfSupply = 50000.0;		
//        System.out.println("VAT : " + Accounting.getVAT());
//        
//        Accounting08_2.valueOfSupply = 900.0;		
//        System.out.println("Total : " + Accounting.getTotal());
    
				Accounting08_2 a1 = new Accounting08_2();
		    a1.valueOfSupply = 10000.0;
		    
		    Accounting08_2 a2 = new Accounting08_2();
		    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());    
	}
}
728x90
반응형
728x90

 

메소드 사용방식에서 클래스화 시키면서 정리정돈

  1. 새클래스 생성
  2. 관련 카테고리의 기존 메소드들을 새클래스 안으로 이주
  3. 기존 메소드들 앞에 클래스명 추가 : Accounting.

+@ 클래스를 따로 파일화해서 분리관리

 

목차

  1. 기존 메소드 방식 코드
  2. 클래스화된 코드

 

1.기존 메소드 방식 코드

public class OOP08_1 {
	 public static double valueOfSupply = 10000.0;
	 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) {
		 System.out.println("Value of supply : " + valueOfSupply);
		 System.out.println("VAT : " + getVAT());
		 System.out.println("Total : " + getTotal());
	 }
 }

 

 

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 OOP08_1 {
	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());
	}
}
728x90
반응형
728x90

 

생성자(constructor)

  • 해당 클래스와 똑같은 이름을 정의하면, 얘가 바로 생성자(constructor)
  • 초기에 주입할 필요가 있는 값(초기값)을 전달하거나 초기에 작업을 수행할 때 쓴다
  • 리턴값이 없으며, 모든 클래스는 생성자가 반드시 한개이상 존재한다.
  • 따로 선언하지 않아도 보이지 않는 default constructor가 자동으로 추가된다.

 

 

this 키워드

  • 클래스인스턴스화 되었을 때인스턴스를 가리키게 하는 특수한 키워드
  • 자바에서 this는 자기자신을 뜻함

 

 

생성자(constructor)는 왜 써야할까?(과정설명)

파일수정 시 어떤파일을 수정할지 파일 지정해줘야하는데 파일지정 행위를 까먹거나 나중에 하게되면 문제발생

  1. 인스턴스 생성시점에서 ("data.txt")처럼 파일을 지정할 수 있다면 까먹지 않고 안정성 상승
  2. 인스턴스가 생성될 때, 처리되어야할 어떤 작업(초기값 등)이 있을 때, 또는 생성될 때 실행되어야하는 작업들을 하고 싶을 때 생성자(constructor)로 해결 가능

 

어떤 클래스가 어떤 작업을 처리하기전 delimiter값을 세팅해야 우리작업을 할 수 있는 상황이라고하면,

이 파라미터값 조정을 까먹기가 상당히 쉽다.

개선책

인스턴스 생성시, delimiter값을 지정하지 않으면 클래스가 인스턴스화되지 못하도록 하면서 개발자가 실수할 가능성 차단가능. 인스턴스를 생성할 때 delimiter값을 지정하는 것을 해볼 것. 생성자constructor를 정의해야한다.

 

자바에서의 클래스는 생성자(constructor)라는 특수한 메소드를 구현할 수 있는 기능을 제공하며, 중요기능은 초기화이다. 해당 클래스와 똑같은 이름을 정의하면, 얘가 바로 생성자(constructor)

인스턴스를 생성할 때, 자바는 이 클래스와 동일한 메소드가 있다면 그 메소드를 호출하도록 약속 되어있기에 우리는 그 클래스가 인스턴스화 될 때 실행되어야할 코드를 construct method 안에 정의 하는 걸 통해서 초기화의 목적을 달성할 수 있는 것

 

print클래스가 인스턴스화 될 때 구분자를 인자로써 받을 것이기에 print메소드의 매개변수로 delimiter를 받으면됨

 

생성자(constructor) 모양새

class Print00 {
	public String delimiter = "";
	public Print00(String delimiter) {  // print00의 ()이 생성자

 

 


 

class Print00 { 
	public String delimiter = ""; 
	public Print00(String _delimiter) {
			delimiter = _delimiter;  // 이 클래스의 인스턴스 변수인 delimiter 값은 _delimiter의 값은 "----"
	}  // 밑에 A()메소드를 호출하면 println(delimiter)값에 "----" 들어가게됨
	public void A() { 
		System.out.println(delimiter); // 인자값에 "----"
		System.out.println("A");
	}
	public void B() {
		System.out.println(delimiter);
		System.out.println("B");

}

이 클래스의 인스턴스 변수인 delimiter 값은 _delimiter의 값은 "----" 밑에 A()메소드를 호출하면 println(delimiter)값에 "----" 들어가게됨

 

만약 언더바를 빼고 delimiter = delimiter;라고 한다면

Q.왼쪽 delimiter는 인스턴스 변수delimiter일까 생성자 메소드의 delimiter매개변수일까?

A. delimiter매개변수

※ 확인방법 ※ 

실행해보면 구분자가 출력이 안되어 나오는데, String delimiter = "";에 세팅이 안됬기 때문. 또한 이클립스에서 같은변수인지 색표시에서도 각각 구별되어져 보임. 이런 경우 앞에 this.를 붙여준다. this키워드 붙인 후 연결되는 delimiter가 바뀌는게 보인다.

this는 우리가 생성한 인스턴스를 가리키는 것 this.delimiter는 인스턴스의 변수를 가리키니까 String delimiter = "";의 delimiter를 가리키며, 생성자메소드 뿐 아니라 클래스 아래있는 메소드들의 delimiter에도 this.를 붙여 명시적으로 해두는게 좋다

 

생성자(constructor)는 초기에 주입할 필요가 있는 값(초기값)을 전달하거나 초기에 작업을 수행할 때 쓴다

this는 클래스가 인스턴스화 되었을 때에 인스턴스를 가리키는 특수한 이름

 

 

 

전체코드

// OOP 7. 생성자(constructor)와 this

// 생성자(constructor)
// 초기에 주입할 필요가 있는 값을 전달하거나 초기에 작업을 수행할 때 쓴다
// 리턴값이 없으며, 모든 클래스는 생성자가 반드시 한개이상 존재한다. 
// 따로 선언하지 않아도 보이지 않는 default constructor가 자동으로 추가된다.

// this 키워드
// 클래스가 인스턴스화 되었을 때에 인스턴스를 가리키게 하는 특수한 키워드
// 자바에서 this는 자기자신을 뜻함

public class OOP07 {
	public static void main(String[] args) {
	
//	 생성자(constructor)는 왜 써야할까?
//	 파일수정 시 어떤파일을 수정할지 파일 지정해줘야하는데 파일지정 행위를 까먹거나 나중에 하게되면 문제발생
//	 1)인스턴스 생성시점에서 ("data.txt")처럼 파일을 지정할 수 있다면 까먹지 않고 안정성 상승
//	 2)인스턴스가 생성될 때, 처리되어야할 어떤 작업(초기값 등)이 있을 때,
//	 또는 생성될 때 실행되어야하는 작업들을 하고 싶을 때 생성자(constructor)로 해결 가능
	
	
//	 print클래스는 어떤 작업을 처리하기전 delimiter값을 세팅해야 우리작업을 할 수 있는 상황이라고하면,
//	 이 파라미터값 조정을 까먹기가 상당히 쉽다.
//	 개선책
//	 인스턴스 생성시, delimiter값을 지정하지 않으면 클래스가 인스턴스화되지 못하도록 하면서 개발자가 실수할 가능성 차단가능
//	 인스턴시 생성할 때 delimiter값을 지정하는 것을 해볼 것. 생성자constructor를 정의해야함
	
//	 자바에서의 클래스는 생성자라는 특수한 메소드를 구현할 수 있는 기능을 제공하며, 중요기능은 초기화
//	 해당 클래스와 똑같은 이름을 정의하면, 얘가 바로 생성자(constructor)
//	 인스턴스를 생성할 때 자바는 이 클래스와 동일한 메소드가 있다면 그 메소드를 호출하도록 약속 되어있기에
//	 우리는 그 클래스가 인스턴스화 될 때 실행되어야할 코드를 construct method 안에 
//	 정의 하는 걸 통해서 초기화의 목적을 달성할 수 있는 것
		
//	 print클래스가 인스턴스화 될 때 구분자를 인자로써 받을 것이기에 print메소드의 매개변수로 delimiter를 받으면됨
				
	Print00 p1 = new Print00("----");		// new가 없으면 메소드를 호출하는 것과 같다
    p1.A();
    p1.B();

    Print00 p2 = new Print00("====");
    p2.A();
    p2.B();    
	}
}

class Print00 {
	public String delimiter = "";
	public Print00(String delimiter) {  // print00의 ()이 생성자
		this.delimiter = delimiter; 	// _delimiter는 이 맥락에서 "----"
	}
	// 이 클래스의 인스턴스 변수인 delimiter 값은 _delimiter의 값은 "----"
	// 밑에 A()메소드를 호출하면 println(delimiter)값에 "----" 들어가게됨
	// 만약 언더바를 빼고 delimiter = delimiter;라고 한다면 왼쪽 delimiter는 
	// 인스턴스 변수delimiter일까 생성자 메소드의 delimiter매개변수일까? 
	// delimiter매개변수이다
	// 확인방법은 실행해보면 구분자가 출력이 안되어 나오는데,  String delimiter = "";에 세팅이 안됬기 때문
	// 이클립스에서 같은변수인지 색표시에서도 구별되어져 보임. 이런 경우 앞에 this.를 붙여준다.
	// this는 우리가 생성한 인스턴스를 가리키는 것
	// this.delimiter는 인스턴스의 변수를 가리키니까 String delimiter = "";의 delimiter를 가리킴
	// 생성자메소드 뿐 아니라 클래스 아래있는 메소드들의 delimiter에도 this.를 붙여 명시적으로 해두는게 좋다
	
	// 생성자(constructor)는 초기에 주입할 필요가 있는 값을 전달하거나 초기에 작업을 수행할 때 쓴다
	// this는 클래스가 인스턴스화 되었을 때에 인스턴스를 가리키는 특수한 이름
	public void A() {
		System.out.println(this.delimiter);
		System.out.println("A");
	}
	public void B() {
		System.out.println(this.delimiter);
		System.out.println("B");
	}
}

 

728x90
반응형
728x90

 

static 역할

static 뒤에 오는 변수가 클래스소속이라는 의미

(스태틱의 디테일 이해 참고자료 : https://mangkyu.tistory.com/47, https://rosypark.tistory.com/324)

static이란?

클래스가 로딩될 때 static 선언된 자원들은 JVM에서 메모리에 딱 한번 올라감. (즉, static 변수는 클래스가 사용되기 전 미리 메모리에 올라감) static을 사용하면 객체 생성할 필요없이 공용된 자원을 사용함으로써 메모리를 효율적으로 사용가능

 

classMethod()에서 classVar와 instanceVar에 액세스 가능할까?

 - classVar : yes

 - instanceVar : error

classMethod()에서 classVar에는 접근이 되나 instanceVar에는 접근할 수 없다

 

public static String classVar = "I class var";   // static O :  클래스 소속
public String instanceVar = "I instance var";    // static x : 인스턴스 소속

static 여부차이로 클래스 소속과 메소드 소속으로 나뉘어 제어되기 때문

class Foo {
	public static String classVar = "I class var"; // static O :  클래스 소속
	public String instanceVar = "I instance var";  // static x : 인스턴스 소속
	
	public static void classMethod() {		// 클래스 메소드에서 classVar와 insVar 접근가능?
		System.out.println(classVar);		// yes
		System.out.println(instanceVar);	// error
		// 클래스 메소드에서 classVar에는 접근이 되나 instanceVar에는 접근할 수 없다
	}
	public void instanceMethod() {			// 인스턴스 메소드에서 classVar와 insVar 접근가능?
		System.out.println(classVar);		// yes
		System.out.println(instanceVar);	// yes
	}
}

 

 

클래스를 통해서 classVar에 접근이 되는가? yes

클래스를 통해서 instanceVar에 접근이 되는가? no error

System.out.println(Foo.classVar); 
System.out.println(Foo.insatanceVar);  // error
Foo.classMethod();		// Foo클래스에서  클래스 메소드 호출 가능
Foo.instanceMethod();	// Foo클래스에서 인스턴스메소드 호출 불가 // error

클래스에서 인스턴스는 접근 불가능

인스턴스 메소드는 인스턴스 소속이기에 클래스를 통해서 접근하는 것은 금지 되어있음

 


 

 

f1이라는 새 인스턴스를 생성했을 때 내부적으로 어떤 일이 일어나는지 살펴보자

 

 

f1인스턴스는 클래스Foo를 원형으로하며, f1에는 실제값이 존재하지 않는다

 

<첫째줄>

[인스턴스 f1] static String classVar는 [클래스Foo] static String classVar="I class var"를 가릴킬 뿐이다

 

<둘째줄>

instanceVar는 [클래스Foo]에서 [인스턴스 f1]이라는 인스턴스가 생성될 때 인스턴스바라고 하는 변수가 생성되면서 클래스 값도 세팅되어있다면 값도 복제됨.

이 둘은 서로 링크 걸려있지 않기에 [인스턴스 f1]의 값이 바꾼다고 해서 [클래스Foo]의 값이 바뀌지 않음

첫째줄 [인스턴스 f1]의 static String classVar의 값을 바꾸면 [클래스Foo]의 static String classVar="I class var"변경됨.

물론 반대로 [클래스Foo]의 값을 바꿔도 [인스턴스 f1]의 값도 같이 변경된다(원형과 복제본) ★상호영향 중요★

 

<셋째줄>

메소드도 마찬가지로 클래스foo를 참조하는 것 instance f1의 static classMethod()의 메소드는 class Foo의 static classMethod()를 참조

 

<넷째줄>

인스턴스f1의 instanceMethod()는 클래스foo의 instanceMethod()를 복제한 것. 독립된 존재

 

<인스턴스f2 생성>

 

<중요법칙>

클래스의 변수를 바꾸면 모든 인스턴스의 값바뀐다 인스턴스에서 원형클래스 변수를 바꿀 수도 있는데, 그럼 이 클래스와 이 클래스를 사용하는 모든 인스턴스의 값변경된다

 

 

위의 그림표의 코드를 실제 실행한 코드

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";		  // 클래스바 변수값을 인스턴스f1이 변경시킴."changed by f1"으로
System.out.println(Foo.classVar);     // 출력 : changed by f1
System.out.println(f2.classVar); 	  // 출력 : changed by f1
		
f1.instanceVar = "changed by f1";	  // 인스턴스바 변수값을 인스턴스f1이 변경시킴."changed by f1"으로
System.out.println(f1.instanceVar);	  // 출력 : changed by f1  // 변경된 변수값으로 출력됨
System.out.println(f2.instanceVar);   // 출력 : I instance var // f1과 f2가 독립적이라 기존값으로 출력됨

 

전체코드

// OOP 6. static

class Foo {
	public static String classVar = "I class var"; // static O :  클래스 소속
	public String instanceVar = "I instance var";  // static x : 인스턴스 소속
	
	public static void classMethod() {		// 클래스 메소드에서 classVar와 insVar 접근가능?
		System.out.println(classVar);		// yes
//		System.out.println(instanceVar);	// error
		// 클래스 메소드에서 classVar에는 접근이 되나 instanceVar에는 접근할 수 없다
	}
	public void instanceMethod() {			// 인스턴스 메소드에서 classVar와 insVar 접근가능?
		System.out.println(classVar);		// yes
		System.out.println(instanceVar);	// yes
		// 인스턴스 메소드에서는 클래스 변수, 인스턴스 변수 모두 접근가능!
	
	}
}

public class OOP06 {
	public static void main(String[] args) {
	
	// 클래스를 통해서 classVar에 접근이 되는가? 	yes
	// 클래스를 통해서 instanceVar에 접근이 되는가?	no error
		System.out.println(Foo.classVar);
//		System.out.println(Foo.insatanceVar);  error
		Foo.classMethod();		// Foo클래스에서  클래스메소드 호출 가능
//		Foo.instanceMethod();	// Foo클래스에서 인스턴스메소드 호출 불가
		// 인스턴스 메소드는 인스턴스 소속이기에 클래스를 통해서 접근하는 것은 금지 되어있음
		
		
		
		// f1이라는 새 인스턴스를 생성했을 때 내부적으로 어떤 일이 일어나는지 살펴보자
		
		//				class Foo        		  vs       	instance f1
		// static String classVar="I class var" 		 static String classVar
		// String instanceVar="I instance var"	 	 String InstanceVar="I instance var"
		// 			static classMethod()		 		 static classMethod()	
		// 			instanceMethod()					 instanceMethod()
			
		
		// f1인스턴스는 클래스Foo를 원형으로하며, f1에는 실제값이 존재하지 않는다
		
		// 첫째줄
		// 인스턴스f1의 static String classVar는 클래스Foo의 static String classVar="I class var"를 가릴킬 뿐
		
		// 둘째줄
		// instanceVar는 Foo에서 f1이라는 인스턴스가 생성될 때 인스턴스바라고 하는 변수가 생성되면서 클래스 값도 세팅되어있다면 값도 복제됨. 
		// 이 둘은 서로 링크 걸려있지 않기에 인스턴스f1의 값이 바꾼다고 해서 class foo의 값이 바뀌지 않음 
		// 첫째줄 인스턴스f1의 static String classVar의 값을 바꾸면 클래스Foo의 static String classVar="I class var"값도 변경됨.
		// 물론 반대로 class foo의 값을 바꿔도 instance f1의 값도 같이 변경된다(원형과 복제본) ★상호영향 중요★!!!
		
		// 셋째줄
		// 메소드도 마찬가지로 클래스foo를 참조하는 것
		// instance f1의 static classMethod()의 메소드는 class Foo의 static classMethod()를 참조
		
		
		// 넷째줄
		// 인스턴스f1의 instanceMethod()는 클래스foo의 instanceMethod()를 복제한 것. 독립된 존재
		
		// 인스턴스f2 생성
		
		
		// 중요법칙
		// 클래스의 변수를 바꾸면 모든 인스턴스의 값이 바뀐다
		// 인스턴스에서 원형클래스 변수를 바꿀 수도 있는데, 그럼 이 클래스와 이 클래스를 사용하는 모든 인스턴스의 값도 변경된다 
		
		
		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";		 // 클래스바 변수값을 인스턴스f1이 변경시킴."changed by f1"으로
		System.out.println(Foo.classVar);  	 // 출력 : changed by f1
		System.out.println(f2.classVar); 	 // 출력 : changed by f1
		
		f1.instanceVar = "changed by f1";	 // 인스턴스바 변수값을 인스턴스f1이 변경시킴."changed by f1"으로
		System.out.println(f1.instanceVar);	 // 출력 : changed by f1  // 변경된 변수값으로 출력됨
		System.out.println(f2.instanceVar);	 // 출력 : I instance var // f1과 f2가 독립적이라 기존값으로 출력됨
		// 복제된 인스턴스끼리는 영향을 주지 않음. 원형인 클래스값을 변경시키지 않는 이상
		// 
	}
}

 

728x90
반응형
728x90

 

클래스 : 원형

인스턴스 : 복제본

 

원형본인 클래스에서 인스턴스를 만들고 새 변수에 담아두고 이 인스턴스의 메소드를 호출하므로써 이 인스턴스를 조작할 수 있게되는 메커니즘

 

 

 

Print05.delimiter = "----";	
Print05.A();					
Print05.A();	

Print05.delimiter = "====";	
Print05.B();
Print05.B();		

Print05.delimiter = "****";
Print05.A();
Print05.delimiter = "====";
Print05.B();

 

위와 같이 계속 변수의 파라미터를 계속 바꿔서 써야하는 상황이라면?

이럴 때 인스턴스 사용

 

print클래스 안에 있는 메소드들의 static들 삭제

 

 

static 역할

static 뒤에 오는 String(변수(?))이 클래스소속이라는 의미

 - 이렇기에 인스턴스 소속 메소드를 쓰는게 목적이므로 스태틱을 삭제하여 메소드를 클래스 소속에서 인스턴스 소속으로 변경해주는 것

 

인스턴스 사용의 장점

클래스를 재료로 사용할 때 세분화시키고 싶다면 인스턴스로 부분적으로 각각 다른 네이밍과 기능을 지정해 사용할 수 있다

 - 전처럼 중복된 코드를 계속 바꿀 필요 없이, 파라미터 ****가 필요하면 p1 인스턴스를 불러오고 +가 필요하면 p2를 부르면된다

 

 

전체코드

// OOP 5. 인스턴스

class Print05 {
	public String delimiter = ""; 
	public void A() {
		// ... 1억줄 코드
		System.out.println(delimiter); // printA() 메소드 안에  delimiter가 없다면
		System.out.println("A");	   // 이 파일 클래스(메인 메소드 위에)에서 찾아서 사용
		System.out.println("A");	   // 
	}
	public void B() {
		// ... 1억줄 코드
		System.out.println(delimiter);
		System.out.println("B");
		System.out.println("B");
	}
}

public class OOP05 {
	public static void main(String[] args) {
	
	// 클래스 : 원형본
	// 인스턴스 : 복제본
	//
	// 원형본인 클래스에서 인스턴스를 만들고 새변수에 담아두고 이 인스턴스의 메소드를 호출하므로써
	// 이 인스턴스를 조작할 수 있게되는 메커니즘
	
//		Print05.delimiter = "----";	
//		Print05.A();					
//		Print05.A();	
//	
//		Print05.delimiter = "====";	
//		Print05.B();
//		Print05.B();		
//	
//		Print05.delimiter = "----";
//		Print05.A();
//		Print05.delimiter = "====";
//		Print05.B();
		
		
	// 위와 같이 계속 변수의 파라미터를 계속 바꿔서 써야하는 상황이라면?
	// 이럴 때 인스턴스 사용
	
	// static : statice 뒤에 오는 String(변수(?))이 클래스소속이라는 의미
	// 고로 위에 클래스 안 메소드에서 static 삭제
	Print05 p1 = new Print05();
	p1.delimiter = "****";
	p1.A();
	p1.A();
	p1.B();
	p1.B();

	Print05 p2 = new Print05();
	p2.delimiter = "++++";
	p2.A();
	p2.A();
	p2.B();
	p2.B();
	// 전처럼 중복된 코드를 계속 바꿀 필요 없이,
	// 파라미터 ****가 필요하면 p1 인스턴스를 불러오고 +가 필요하면 p2를 부르면된다

	}
}

 

 

728x90
반응형
728x90

 

public : 접근제어자라 불림

파일명인 class명 앞에는 퍼블릭을 붙이며, 한번만 등장한다

 

 

클래스 Print랑 클래스명이자 파일명인 oop05를 이클립스에서 저장(컴파일) 했을 때,

자바 확장자 파일과 더불어 파일명 Print이고 확장자가 클래스인 파일도 같이 생성된다

즉, 하나의 자바파일에서 그 안에 클래스를 여러개 만들면 그 클래스 개수만큼 .class파일이 생성된다

이는 메인 파일 안에 다 넣어서 거대하게 만들 수도 있지만 따로 클래스만 떼어서 파일을 만들 수도 있다는 의미

  • 이클립스에서 새로운 클래스 만들 때, public static void main(String[] args) 체크를 안하고 클래스만 따로 만들어서 위와 같은 클래스 파일을 만들 수도 있는 것
  • 거대 프로젝트에서 협업할 때 이런 식으로 나눠서 할 수 있는 장점

 

 

※ 이클립스 Refactor 클래스타입 파일 만들기

[Refactor] - [Move type to New File]

사이드 클래스 부분만 따로 떼어서 파일화 시킴

 

 

리팩터 전

파일1개

// OOP 4.2. 클래스 - 형식

// 이클립스 [Refactor] - [Move type to New File]
//	사이드 클래스 부분만 따로 떼어서 파일화 시킴
//
class Print04_2 {
	public static String delimiter = ""; 
	public static void A() {
		// ... 1억줄 코드
		System.out.println(delimiter); // printA() 메소드 안에  delimiter가 없다면
		System.out.println("A");	   // 이 파일 클래스(메인 메소드 위에)에서 찾아서 사용
		System.out.println("A");	   // 
	}
	public static void B() {
		// ... 1억줄 코드
		System.out.println(delimiter);
		System.out.println("B");
		System.out.println("B");
	}
}
public class OOP04_2 {
	public static void main(String[] args) {
		
		Print04_2.delimiter = "----";	// 추가 경로지정 : 클래스명. 추가
		Print04_2.A();					
		Print04_2.A();	
		
		Print04_2.delimiter = "====";	
		Print04_2.B();
		Print04_2.B();			
	}
}

 

리팩터 후

파일 2개

public class OOP04_2 {
	public static void main(String[] args) {
		
		Print04_2.delimiter = "----";	// 추가 경로지정 : 클래스명. 추가
		Print04_2.A();					
		Print04_2.A();	
		
		Print04_2.delimiter = "====";	
		Print04_2.B();
		Print04_2.B();			
	}
}
class Print04_2 {
	public static String delimiter = ""; 
	public static void A() {
		// ... 1억줄 코드
		System.out.println(delimiter); // printA() 메소드 안에  delimiter가 없다면
		System.out.println("A");	   // 이 파일 클래스(메인 메소드 위에)에서 찾아서 사용
		System.out.println("A");	   // 
	}
	public static void B() {
		// ... 1억줄 코드
		System.out.println(delimiter);
		System.out.println("B");
		System.out.println("B");
	}
}

 

 

 

728x90
반응형
728x90

 

JAVA 객체 지향 프로그래밍 - 4.1. 클래스 - 존재 이유와 기본형식

 

클래스 존재 이유 : 정리정돈

 - 메소드 코드가 1억줄이라면 복잡성은 헬

 

새로 클래스를 생성하고 전에 수업에서 만든 메소드들을 class 안으로 이사시키자

그리고 메인 메소드에서 해당 메소드들을 호출하는 명령어 코드 앞에 클래스명 추가(경로지정 작업)

 

전체코드

// OOP 4.1 : 클래스 - 존재 이유와 기본형식

class Print04_1 {
	public static String delimiter = ""; 
	public static void A() {
		// ... 1억줄 코드
		System.out.println(delimiter); // printA() 메소드 안에  delimiter가 없다면
		System.out.println("A");	   // 이 파일 클래스(메인 메소드 위에)에서 찾아서 사용
		System.out.println("A");	   // 
	}
	public static void B() {
		// ... 1억줄 코드
		System.out.println(delimiter);
		System.out.println("B");
		System.out.println("B");
	}
	// 메소드가 1억개라면 헬 난이도 복잡도
	// 구원자는 class
	// 새로운 클라스를 만들어서 정리하자
	// class print04를 생성하고 같은 주제인 메소드들을 안으로 이사시킴
}

public class OOP04_1 {
	public static void main(String[] args) {
		
		Print04_1.delimiter = "----";	// 추가 경로지정 : 클래스명. 추가
		Print04_1.A();					
		Print04_1.A();	
		
		Print04_1.delimiter = "====";	
		Print04_1.B();
		Print04_1.B();			
	}
}

 

 

 

 

728x90
반응형
728x90

 

JAVA 객체 지향 프로그래밍 - 3. 변수와 메소드

 

※이클립스 Refactor- extract method 기능

  - 자동으로 메소드 만들어주는 기능

 

 

이전 메소드 수업에서 3가지 형태를 좀 더 풀어서 설명하시는 듯함

 1.메소드

 2.클래스 소속 메소드

 3.인스턴스 소속 형태 메소드 

 

아래부터는 코드를 점점 개선해 나아갈 것인데 뭐가 문제점이고 어떻게 개선시키는지를 중점적으로 보자

 

OOP 03_1 : 변수와 메소드 - 메소드 호출 방식

메소드 생성하고 해당 메소드를 호출 & 메소드 한 줄마다 파라미터를 지정해줘야함

많은 양의 코드에서 일일히 다 수정하기가 불가능하기에 구분자만 바꿀 수 있도록 지정 해주는 것

// OOP 03_1 : 변수와 메소드

// 1.메소드
// 2.클래스 소속 메소드
// 3.인스턴스 소속 메소드

// 1.메소드
//
// 메소드 생성하고 해당 메소드를 호출 & 메소드 한 줄마다 파라미터를 지정해줘야함  
public class OOP03_1 {
	public static void main(String[] args) {
		
		printA();			
		printA();			
		printB();
		printB();	// 이 방식은 메소드 한줄마다 바꿔줘야함. 그래서 구분자 변수 지정(String delimiter = "----";) 하는 것
	}

	public static void printA() {
		// ... 1억줄 코드
		System.out.println("----"); // 여기서 구분자를 ----으로했지만
		System.out.println("A");	// 위 printA()에서 *로 하고 싶다면?
		System.out.println("A");	// 각각의 메소드에 파라미터 지정해주는 것
									// 옆 메소드에서 printA()에 타입,변수지정
									// 및 지정변수 println하고 
									// (메소드09번 수업1,2,3에서 변환한 그거인듯)
	}
	public static void printB() {
		// ... 1억줄 코드
		System.out.println("====");
		System.out.println("B");
		System.out.println("B");
	}
}

 


 

OOP 03_2 : 변수와 메소드 - 메소드 호출 + 구분자 방식

위의 03_1 방식에서 매 메소드마다 바꾸지 않아도 되게끔 따로 구분자만 변수 처리해서 한번만 바꾸도록 개선

// OOP 03_2 : 변수와 메소드

public class OOP03_2 {
	public static void main(String[] args) {
		
		// 1억줄 코드에 자주 구분자를 바꿔줘야한다면?
		// 변수를 지정해주자 ↓↓↓
		String delimiter = "----";
		printA(delimiter);			
		printA(delimiter);	
		
		delimiter = "====";
		printB(delimiter);
		printB(delimiter);			
	}

	public static void printA(String delimiter) {
		// ... 1억줄 코드
		System.out.println(delimiter); 
		System.out.println("A");	
		System.out.println("A");	
	}
	public static void printB(String delimiter) {
		// ... 1억줄 코드
		System.out.println(delimiter);
		System.out.println("B");
		System.out.println("B");
	}
}

 

 


 

OOP 03_3 : 변수와 메소드 - 메소드 호출 + 구분자 + 유효범위확장 방식

 

서비스를 하고 기능이 많아지면 여러 주제의 메소드도 늘어나고 메소드만 1억개라면...?

메소드를 주제별로 정리해줄 구원자가 class

 

인자로 변수를 주는 것도 싫다면?

메인 메소드 안 delimiter를 메소드 안에서 메소드 밖에 있는 delimiter값을 사용하면 됨. 다만, 유효범위 체크

 

delimiter 인식 순서 & 유효범위

메인 메소드 안에 delimiter 변수를 먼저 찾고 없으면, 이 파일 클래스 전체에서 찾는 것

printA() 메소드 안에 delimiter가 없다면, 이 파일 클래스(메인 메소드 위에)에서 찾아서 사용

// OOP 03_3 : 변수와 메소드

public class OOP03_3 {
	public static String delimiter = ""; 
	//메인 메소드 안 delimiter를 메소드 안에서 메소드 밖에 있는 delimiter값을 사용하게끔 지정
	public static void main(String[] args) {
		
		// 인자로 변수를 주는 것도 싫다면?
		// 
		
		// 메인 메소드 안 delimiter를 메소드 안에서 메소드 밖에 있는 delimiter값을 사용하면 됨
		// 다만, 유효범위 체크
		delimiter = "----";	// 이 delimiter = public static String delimiter = ""; 
		printA();			// 메인 메소드 안에 delimiter 변수가 없기에 이 파일 클래스 전체에서 찾는 것
		printA();	
		
		delimiter = "====";	// 이 방식은 구분자 하나만 바꿔주면 끝
		printB();
		printB();			// 이 방식은 메소드 한줄마다 바꿔줘야함. 그래서 구분자 변수 지정(String delimiter = "----";)
	}

	public static void printA() {
		// ... 1억줄 코드
		System.out.println(delimiter); // printA() 메소드 안에  delimiter가 없다면
		System.out.println("A");	   // 이 파일 클래스(메인 메소드 위에)에서 찾아서 사용
		System.out.println("A");	   // 
	}
	public static void printB() {
		// ... 1억줄 코드
		System.out.println(delimiter);
		System.out.println("B");
		System.out.println("B");
	}
	// public static String delimiter = ""; 
	// public static void printA() {
	// public static void printB() { 와 같이 연관성이 깊고 같은 주제 코드들이 모여있지만
	// 주제가 다 다른 코드들이 1억개라면 지옥 같이 복잡해짐
	// 이 상황에서 구원자는 class! 
	
}

 

 

728x90
반응형
728x90

JAVA 객체 지향 프로그래밍 - 2. 남의 클래스 & 남의 인스턴스

 

OOP(objected Oriented Programming)

 

 

System.out.println(Math.PI);
// 결과값 : 3.141592653589793

math라고 하는 클래스PI라는 변수가 있는 것이고, 그 변수 안에 3.14의 구체적인 숫자가 적당한 정밀도로 적혀있는 것

 

System.out.println(Math.PI);
System.out.println(Math.floor(1.8)); // 내림
System.out.println(Math.ceil(1.8));  // 올림

Math는 클래스이고, 클래스 안에는 수학과 관련된 PI라고 하는 변수도 있고 floor,ceil과 같은 메소드들도 들어 있는 것.

즉, 코드가 많아짐에 따라서 서로 연관된 같은 주제를 가지고 있는 변수와 메소드를 그루핑한 껍데기가 클래스

 

 

FileWriter f1 = new FileWriter(”data.txt”)

new를 붙이므로써 FileWriter라는 클래스의 복제본f1을 만들겠다

 

 

FileWriter f1 = new FileWriter("data.txt"); // new를 붙이므로써 FileWriter라는 클래스의 복제본을 만들겠다
f1.write("Hello");
f1.write("Java");
f1.close();

일회용으로 작업을 끝내면 되는 것들은 메소드나 변수를 클래스에 소속된 그냥 클래스에 있는거 그냥 사용합니다

ex) Math.floor()나 Math.ceil()

 

 

하지만 긴 맥락을 가지고 작업해야하는 것들은 클래스를 직접 사용하지 않고 인스턴스를 사용해서 복제본을 사용해서 관리한다

ex) f1인스턴스를 계속 write write close까지 길게 여러번

		FileWriter f1 = new FileWriter("data.txt"); // FileWriter의 복사본
		f1.write("Hello");
		f1.write("Java");

				
		FileWriter f2 = new FileWriter("data2.txt"); // FileWriter의 또 다른 복사본
		f2.write("Hello");
		f2.write("Java2");
		f2.close();
		
		f1.write("!!!");  				// 긴 맥락의 작업
		f1.close();

 

 

 

 

아래에서

클래스 : System, Math, FileWriter

인스턴스 : f1, f2

import java.io.FileWriter;
import java.io.IOException;

public class OOP02 {

	public static void main(String[] args) throws IOException {
		// class : System, Math, FileWriter
		// Instance : f1, f2 
		System.out.println(Math.PI);
		System.out.println(Math.floor(1.8));
		System.out.println(Math.ceil(1.8));
		
		FileWriter f1 = new FileWriter("data.txt"); // FileWriter의 복사본
		f1.write("Hello");
		f1.write("Java");

				
		FileWriter f2 = new FileWriter("data2.txt"); // FileWriter의 또 다른 복사본
		f2.write("Hello");
		f2.write("Java2");
		f2.close();
		
		f1.write("!!!");  				// 긴 맥락의 작업
		f1.close();
	}
}
728x90
반응형

+ Recent posts