우아한 테크 코스를 준비하면서 java를 이용해서 숫자 야구 게임을 만들게 되었습니다
하지만 저는 그동안 django를 이용하여 프로젝트를 했기 때문에 python에는 익숙하지만 java는 익숙하지 않아서 java 객체지향 프로그래밍에 대해서 공부하기로 했습니다
: method를 이용해서 부품들을 만들고 이를 결합하여 더 큰 프로그램을 만드는 것
❓ 몇몇 개발자들은 연관된 method와 변수들을 묶어서 그룹핑하고 이름을 붙여서 정리를 하고 싶어함 이것을 클래스라고 하고 클래스를 중심으로 프로그램의 구조를 만들어가는 컴퓨터 프로그래밍 방법론을 "객체지향 프로그래밍"이라고 한다
✅ 다음 코드에서 class는 FileWriter이고 instace는 f1이다
FileWriter f1= new FileWriter("data.txt");
f1.write("Hello");
f1.write(" java");
public class MyOOP{
public static void main(String[] args){
printA();
printB();
}
public static void printA(){
System.out.println("---");
System.out.println("A");
System.out.println("A");
}
public static void printB(){
System.out.println("---");
System.out.println("B");
System.out.println("B");
}
}
✅ 위와 같은 코드가 있을 때 구분자를 "----"가 아니라 "***"로 출력하고 싶다면
메소드를 하나 더 만들어주는 것은 비효율적이므로 구분자를 매개변수를 주는 방법을 택할 수 있다 구분자를 매개변수로 받게 만들어준다면 코드는 다음과 같다
public class MyOOP{
public static void main(String[] args){
printA("---"); 👈
printB("***");
}
public static void printA(String delimiter){ 👈
System.out.println(delimiter);
System.out.println("A");
System.out.println("A");
}
public static void printB(String delimiter){
System.out.println(delimiter);
System.out.println("B");
System.out.println("B");
}
}
✅ 구분자가 자주 바뀐다고 했을 때 매개변수를 하나하나 바꾸는 것은 어렵기 때문에 변수를 정의하는 방법을 사용할 수 있다
public class MyOOP{
public static void main(String[] args){
String delimiter ="---"; 👈
printA(delimiter);
delimiter ="***"; 👈
printB(delimiter);
}
public static void printA(String delimiter){
System.out.println(delimiter);
System.out.println("A");
System.out.println("A");
}
public static void printB(String delimiter){
System.out.println(delimiter);
System.out.println("B");
System.out.println("B");
}
}
✅ 인자를 변수로 주는 것도 싫다면 main 메소드에 있는 delimiter 값을 사용하면 되는데 그렇게는 할 수 없다 왜냐면 유효 범위가 있기 때문에 메소드 안에서 정의된 변수는 그 메소드 안에서만 사용할 수 있다
그렇다면 어떻게 할 수 있을까?
class에 변수를 정의를 해주면 된다
public class MyOOP{
public ststic String delimiter=""; 👈
public static void main(String[] args){
delimiter ="---";
printA();
delimiter ="***";
printB(delimiter);
}
public static void printA(){
System.out.println(delimiter);
System.out.println("A");
System.out.println("A");
}
public static void printB(){
System.out.println(delimiter);
System.out.println("B");
System.out.println("B");
}
}
✅ 다음 코드를 보면 delimiter, printA(),printB()가 연관되는 것을 알 수 없다 그래서 class를 만들어서 이들을 묶어줘야 한다 다음은 class만들어준 코드다
class Print{
public ststic String delimiter="";
public static void A(){
System.out.println(delimiter);
System.out.println("A");
System.out.println("A");
}
public static void B(){
System.out.println(delimiter);
System.out.println("B");
System.out.println("B");
}
}
public class MyOOP{
public static void main(String[] args){
Print.delimiter ="---"
Print.A();
Print.delimiter ="***"
Print.B();
}
}
✅ 클래스는 클래스명, 멤버변수, 멤버함수로 이루어진다
✅ 클래스마다 파일을 나눠준다
복제된 것들의 원형을 클래스라고 하고 클래스를 복제한 것을 인스턴스라고 한다
✅ 다음과 같이 계속 구분자를 변경해줘야 하는 번거로움이 생길 수 있다 이를 해결하기 위해 사용하는 것이 인스턴스이다 다음과 같이 인스턴스를 사용한다면 "***"를 사용하고 싶을 때는 p1을 "---"을 사용하고 싶을 때는 p2를 사용하면 된다
기존의 코드에 비해 중복되는 코드가 사라진 것을 볼 수 있다
class Print{
public String delimiter=""; 👈 static을 없앤 이유는 다음에
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");
}
}
public class MyOOP{
public static void main(String[] args){
Print p1= new Print();
p1.delimiter ="***";
p1.A();
p1.B();
Print p12= new Print();
p2.delimiter ="---";
p2.A();
p2.B();
}
}
static은 클래스 소속이다. static이 없으면 인스턴스다
✅ 다음 코드를 통해서 멤버변수에 접근이 가능한지 확인해보겠다
✅ (1) System.out.println(Foo.instanceVar);에서 에러가 난 것을 확인할 수 있는데 이유는 인스턴스를 통해서 사용해야하기 때문이다
✅ (2)을 보면 클래스 메소드에서는 인스턴스 변수에 접근할 수 없기 때문이다
✅ (3)을 보면 인스턴스 메소드에서는 클래스 변수와 인스턴스 변수 모두 접근이 가능하다는 것을 알 수 있다
✅ (4)를 보면 Foo.instaceMethod();가 에러 났는데 인스턴스 메소드는 클래스를 통해서 접근하는 것은 불가능하다
정리해보면 클래스를 통해 인스턴스 변수와 인스터느스 메소드에 접근하는 것은 금지되어있다
class Foo{
public static String classVar = "I class var";
public String instanceVar = "I instace var";
public static void classMethod(){ 👈 (2)
System.out.println(classVar); //ok
System.out.println(instanceVar); //Error
}
public void instaceMethod(){ 👈 (3)
System.out.println(classVar); //ok
System.out.println(instanceVar); //ok
}
}
public class StaticApp{ 👈 (1)
public static void main(String[] args){
System.out.println(Foo.classVar); //ok
System.out.println(Foo.instanceVar); //Error
👈 (4)
Foo.classMethod(); //ok
Foo.instaceMethod(); //Error
}
}
다음 그림을 보면 클래스의 변수를 바꾸면 모든 인스턴스의 변수가 변경이 되고 인스턴스에서 클래스 변수를 변경하면 모든 인스턴스에 적용이 된다
인스턴스 변수는 독립적이기 때문에 인스턴스의 변수를 변경한다고 해서 다른 곳에 영향을 주지 않는다
인스턴스를 생성할 때 반드시 처리해야될 어떠한 작업이 있을 수도 있을 것인데 바로 그런 초기값 또는 인스턴스가 생성될 때 최초로 실행되어야 하는 작업을 하고 싶을 때 "생성자"를 이용하여 이를 해결한다
class Print{
public String delimiter="";
public Print(String _delimiter){ 👈 (1)
delimiter=_delimiter;
}
or
public Print(String delimiter){ 👈 (2)
this.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");
}
}
public class MyOOP{
public static void main(String[] args){
Print p1= new Print("***");
p1.A();
p1.B();
Print p12= new Print("---");
p2.A();
p2.B();
}
}
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());
}
}
✅ 다음과 같이 정리정돈을 했을 때, 각 메소드들이 회계와 관련된 것을 알 수 있다
또한 에디터에서 메소드를 보여주기 때문에 편한 장점도 있다
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());
}
}
어떤 것을 인스턴스화하는 것이 좋을 까? 내부적인 상태가 한번 세팅이 되면 작업이 모두 끝날 때까지 변화가 없는 것은 인스턴스화 할 필요는 없고 클래스만 사용하면 된다
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 = 20000.0;
System.out.println("Value of supply : " + Accounting.valueOfSupply);
System.out.println("VAT : " + Accounting.getVAT());
System.out.println("Total : " + Accounting.getTotal());
}
}
하지만 클래스의 상태가 계속 변화해야 한다면 인스턴스를 사용해야 한다
class Accounting{
// 공급가액
public double valueOfSupply;
// 부가가치세율
public static double vatRate = 0.1;
👆 이 변수는 부가가치세는 0.1로 동일하기 때문에 인스턴스 소속으로 하지 않아도 된다
자원을 아낄 수 있고 한번 바꾸면 모두에 적용되기 때문에 유지보수에도 용이하다
public class Accounting(double valueOfSupply){
this.valueOfSupply=valueOfSupply
}
public double getVAT() {
return valueOfSupply * vatRate;
}
public double getTotal() {
return 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);
}
}
많아진 클래스를 정리