⭐ 4. 클래스 (Class)

  • 객체 지향이란?
  • 객체 지향 언어란?

1. 객체지향

  • 객체(object)

    • 현실세계에 있는 사물.
    • 속성과 기능으로 이루어짐

      ex) 핸드폰 → 모양, 크기
      ex) 색(필드) - 속성
      ex) 볼륨 +/-, on/off(메소드) - 기능(동작)
      종류: int size; String color, void volume(){} 등

2. 객체 지향 프로그래밍**(OOP, object Oriented Programing)

  • 부품에 해당하는 객체들을 만들고, 하나씩 조립하여 프로그램을 만드는 기법

  • 객체간의 관계

    • 집합 관계: 완성품과 부품의 관계(예: 자동차 - 엔진,타이어,핸들 등)
    • 사용 관계: 다른 객체의 필드를 읽고 변경하거나 메소드를 호출하는 관계
    • 상속 관계: 부모자식 관계

특징

  • 캡슐화(Encapsulation): 데이터(필드), 동작(메소드)를 하나로 묶고 실제 구현 내용을 외부에 감추는 것 (정보은닉성)
  • 접근 제한자(Acces Modifier): 객체의 필드를 외부에서 변경하거나 호출할 수 없도록 막기 위해 사용
    • ‘무결성’유지를 위함
    • 종류: private, default(아무것도 안쓰면 디폴트), public, protected
  • 상속(Inheritance): 부모 객체의 필드와 메소드를 자식 객체에 물려줌
    • 코드의 재사용성을 높여줌
    • 유지 보수 시간을 최소화시켜 줌
  • 다형성(Polymorphism): 실행 결과가 다양하게 나오는 성질
    • 업캐스팅/다운캐스팅 ~ 상속이랑도 연결됨
  • 객체와 클래스: 객체를 생성할 때 설계도(Class)가 필요 클래스로부터 생성된 생성된 객체를 해당 클래스의 인스턴스라고 부름

1 객체생성과 클래스 변수

  • new 연산자 뒤에는 생성자(클래스();) 호출 코드가 온다

    ⭐️ 클래스 변수 = new 클래스(); ← 생성자

    → new 연산자는 객체를 생성시킨 후 객체의 주소를 리턴

  • 클래스의 두 가지 용도

    • 라이브러리 클래스: 실행 불가 클래스, 다른 클래스에서 이용하는 클래스
    • 실행 클래스: main() 메소드를 가지고 있는 실행 가능한 클래스
    class A{  //라이브러리 클래스. 실행불가(객체만 생성)
    	int a; //필드. 필드는 무조건 class 안에 있어야 함
    }
    
    public class Test02 { //실행클래스
    public static void main(String[] args) {
      A ab = new A();
      Scanner s = new Scanner(System.in);
                 //생성자
    	}
    }
    
  • 클래스 구성

    public class ClassName{
    
      //필드 선언
      int filedName;   //필드: 객체의 데이터가 저장되는 곳
    
      //생성자 선언
      ClassName(){...}  //생성자: 객체 생성 시 초기화 역할 담당. 이름은 클래스 이름과 동일
    
      //메소드 선언
      int methodName(){ {  //메소드: 객체의 동작으로 호출 시 실행하는 블록
        }
      }
    }
    

2. 필드 선언과 사용

필드(Field)

  • 부품 데이터를 저장하는 필드
  • 선언 시 앞에 클래스명(대문자로 시작, Tire 등)을 써도 됨
  • 필드 선언
    • 변수를 선언하는 방법과 동일

      ⭐️ 타입 필드명 [ = 초기값 ];

  • 필드와 로컬변수 차이점

    • 로컬 변수: 생성자와 메소드 블록에서 선언. 생성자와 메소드 호출 시에만 생성 사용
    • 필드: 클래스 블록에서 선언. 객체 내부에 존재, 객체 내·외부에서 사용 가능
    Public class Car{
      //필드 선언
      String model;  //고유 데이터 필드. 초기화가 안되서 null값으로 저장됨
      boolean start; //상태 데이터 필드. 초기화가 안되서 false로 저장됨
      int speed;     //상태 데이터 필드. 초기화가 안되서 0으로 저장됨
      Trie tire = new Tire(); //부품 객체 필드
    }
    
  1. 절차 지향: 순서대로 계획을 짜고 실행함
  2. 객체 지향: ↑이걸 할 수 있는 객체에게 일을 맡김

  • 예제

    class Profile{  //접근제한자를 안쓰면 defalut임. defalut는 접근제한자로 적어주면 안됨
                    //main함수가 없으므로 실행 불가능한 라이브러리 클래스
      int age;
      String name; //필드
    
      void show() {  //메소드
        System.out.println(age+" "+name);  //메소드
      }
    
    }
    
    public class Test02 { //실행클래스
      public static void main(String[] args) {
    
        Profile p = new Profile(); //객체명: p, 생성자 호출: new Profile();
                //★ 객체 p를 만들어야만 클래스 Profile을 사용할 수 있음
        p.age = 22;  //.(객체 접근 연산자)으로 객체 접근 가능
        p.name = "철수";  //필드 초기화
        p.show();  //함수 호출
    
        //출력: 22 철수
      }
    }
    
    class Car{
    // 필드 선언
      String company = "현대자동차";
      String model = "그랜저";
      String color = "검정";
      int maxSpeed = 350;
      int speed;
    }
    
    public class Test02 {
      public static void main(String[] args) {
    
        //Car 객체 생성
        Car myCar = new Car();
    
        //Car 객체의 필드값 읽기
        System.out.println("제작회사: "+myCar.company);
        System.out.println("모델명: "+myCar.model);
        System.out.println("색깔: "+myCar.color);
        System.out.println("최고속도: "+myCar.maxSpeed); //350
        System.out.println("현재속도: "+myCar.speed);  //0
    
        //Car 객체의 필드값 변경
        myCar.speed = 60;
        System.out.println("최고속도: "+myCar.speed);  //60
    
      }
    }
    

접근제한자(private 사용)

class Circle{

  private int r;  //접근제한된 필드
  private String name;
  //Circle 클래스 안에서만 사용가능(은닉화)

  double area() {
//public 안에 만들어서 공유한다면 static을 쓰지만 객체를 만들어서 바로 할거라 안씀
    return 3.14*r*r;
  }
  void show() {
    System.out.println(name);
  }
}

public class Test02 { //실행클래스
  public static void main(String[] args) {
    Circle c = new Circle();
    ~~c.r=10;~~ 	 //private이기 때문에 에러
    ~~c.name="예준"~~ //private이기 때문에 에러
  }
}

3. 생성자 선언과 호출

  • new 연산자객체를 생성한 후 생성자(constructor) 호출해서 객체 초기화 역할
  • 객체 초기화: 필드 초기화를 하거나 메소드를 호출해서 객체를 사용할 준비를 하는 것

    클래스 변수 = new 클래스();
                    ㄴ생성자 호출
    
  • 생성자는 class명과 동일해야 함

  • 생성자 선언

    • 매개변수가 없는 기본 생성자와 있는 생성자 선언이 있음.
    • 생성자는 메소드와 비슷한 모양을 가지고 있으나, 리턴 타입이 없고 클래스 이름과 동일함
    클래스(매개변수, ...){
      	//객체의 초기화 코드
      }  //생성자 블록
    
    
    class Car{
      Car(String a, String b, int c){ **//리턴타입 없음**(int, void 등)
            //대입   대입(검정)  대입(300)
      }
    }
    
    public class Test02 { //실행클래스
      public static void main(String[] args) {
        Car myCar = new Car("그랜저", "검정", 300);
        //Car myCar = new Car(); **기본 생성자 호출 못함(매개변수가 있으니까)**
    
      //myCar.a="그랜저";
      //myCar.b="검정";    → 하나씩 선언해야 하는 것을 생성자에 매개변수를 선언해서 줌
      }
    }
    
  • 필드 초기화

    • 필드 선언 시 초기값 대입: 객체마다 동일한 값을 가지고 있는 경우
    • 생성자에서 필드 초기화: 객체마다 다른 값을 가지고 있는 경우
    public class Korea{
      //필드 선언
      String nation = "대한민국";
      String name;
      String ssn;
    
      //생성자 선언
      public Korea(String n, String s){
        name = n;    //생성자 안에서 값 초기화
        ssn = s;
      }
    }
    
    public class KoreanExample{
      public static void main(String[] args){
        //Korean 객체 생성
        Korean k1 = new Korean("박자바", "011225-1234567");
        //Korean 객체 데이터 읽기
        System.out.println(k1.nation);  //대한민국
        System.out.println(k1.name);    //박자바
        System.out.println(k1.ssn);     //011225-1234567"
    
        //또다른 Korean 객체 생성
        Korean k2 = new Korean("이자바", "0930522-0654321");
        //Korean 객체 데이터 읽기
        System.out.println(k2.nation);   //대한민국
        System.out.println(k2.name);     //이자바
        System.out.println(k2.ssn);      //0930522-0654321}
    }
    
    class Rec{
    
      int a,b; //필드
    
      Rec(int a, int b){    //생성자
        this.a=a;  //a=4.필드명과 매개변수의 이름을 구분할 때 this(현재 객체)를 적어줌
        this.b=b;  //b=7
      }
      void area() {   //메소드. 출력함수라 void적음
        System.out.println(a*b);
      }
    }
    
    public class ClassStudy {
    
      public static void main(String[] args) {
    
        Rec c = new Rec(4, 7); //생성자 호출 → 위 7번째 줄 실행됨
        c.area();  //28호출
    
        Rec c2 = new Rec(7, 9);
        c2.area(); //63호출
    
      }
    }
    ---------------------------------------------------------
    public class에 있는 내용 보고 class 만들기
    
    class Student{
      String a, b;
    
      Student(String a, String b){
        this.a=a;
        this.b=b;
      }
      void pr() {
        System.out.println(a+" "+b);
      }
    
    }
    
    public class ClassStudy {
      public static void main(String[] args) {
    
        Student s1 = new Student("김길동","kim");
        Student s2 = new Student("이길동","lee");
    
        s1.pr(); s2.pr(); //모든 데이터 출력
    
      }
    }
    

4. 오버로딩

  • 오버로딩: 매개값으로 객체의 필드를 다양하게 초기화

  • 오버로딩 vs 오버라이딩 차이점을 알아야함

1) 생성자 오버로딩

  • 매개변수를 달리하는 생성자를 여러 개 선언하는 것
  • 매개변수의 타입, 개수, 순서가 다르게 여러 개의 생성자 선언
//생성자 오버로딩 기초

public class Car{
  Car{}{...}
  Car{String model}{...}
  Car{String model, String color}{...}  //→ 타입, 개수, 순서 다르게 선언 가능
  Car{String model, String color, int maxSpeed}{...}

  Car{String model, String color}{...}
  Car{String color, String model}{...} //오버로딩이 아니라 컴파일 에러 발생!
    // type, 개수가 같으면 안됨. 둘 중 하나는 달라야 함
}
//생성자 오버로딩 과정
package test01;

public class Car{
  //필드 선언
  String company = "현대자동차";
  String model;
  String cololr;
  int maxSpeed;

  //생성자 선언
  Car(){}   //①생성자

  Car{String model}{   //②생성자
    this.model = model;
  }

  Car{String model, String color}{  //③생성자
    this.model = model;
    this.color = color;
  }

  Car{String model, String color, int maxSpeed}{  //④생성자
    this.model = model;
    this.color = color;
    this.maxSpeed = maxSpeed;
  }

}

package test02;

public class CarExample{
  public static void main(String[] args) {
    Car car1 = new Car();                 //①생성자 호출
    Car car2 = new Car("자가용");          //②생성자 호출
    Car car3 = new Car("자가용","빨강");    //③생성자 호출
    Car car4 = new Car("자가용","빨강",200); //④생성자 호출
  }
}

2) 다른 생성자 호출

  • 생성자 오버로딩이 많아질 경우 생성자 간의 중복된 코드가 발생할 수 있다
  • this의 역할

    • this. : 매개변수-키워드 구분
    • this(): 다른 생성자 호출

      class Book{
      
        String title;
        String author;
        int price;  //필드
      
        Book(String title, String author, int price){
          this.title=title;
          this.author=author;
          this.price=price;
        }
      
        Book(String title, int price){
          this(title, "작자미상", price);  //다른 생성자 호출, 위에 매개변수3개 생성자 호출
        }
      
        Book(){
          this(null,null,0);  //다른 생성자 호출
          System.out.println("생성자가 호출되었음");
        }
      
        void show() {
          System.out.println(title+" "+author+" "+price);
        }
      }
      
      public class Test02 {
        public static void main(String[] args) {
          Book b1 = new Book("고양이", "베르나르", 30000); //생성자 호출
          Book b2 = new Book("자바", 40000);
          Book b3 = new Book(); //생성자가 호출되었음
      
          //생성자 오버로딩
          b1.show();
          b2.show();
          b3.show(); //기본 생성자부터 생성됨
          /*
            * 생성자가 호출되었음
            * 고양이 베르나르 30000
            * 자바 작자미상 40000
            * null null 0
            */
        }
      }
      
  • 예제

    package 01;
    
    public class Car{
      //필드 선언
      String company = "현대자동차";
      String model;
      String color;
      int maxSpeed;
    
      Car(String model){        //①생성자
        //③생성자 생성자 호출
        this(model, "은색", 250);
      }
      Car(String model, String color){   //②생성자
        //③생성자 생성자 호출
        this(model, color, 250);
      }
      Car(String model, String color, int maxSpeed){  //③생성자
        this.model = model;
        this.color = color;
        this.maxSpeed = maxSpeed;
      }
    }
    ----------------------
    package 02;
    
    public class CarExample{
      public static void main(String[] args) {
      Car car1 = new Car("자가용");    //①생성자 호출
      System.out.println(car1.company); //현대자동차
      System.out.println(car1.model);   //자가용
    
      Car car2 = new Car("자가용","빨강");    //②생성자 호출
      System.out.println(car2.company);  //현대자동차
      System.out.println(car2.model);   //자가용
      System.out.println(car2.color);   //빨강
    
      Car car3 = new Car("자가용","빨강",200);    //③생성자 호출
      System.out.println(car3.company);  //현대자동차
      System.out.println(car3.model);   //택시
      System.out.println(car3.color);   //검정
    
    }
    
  • main()함수를 보고 class 생성하기

    //main()
      public static void main(String[] args) {
    
        Car car1 = new Car("자가용","벤츠");
        System.out.println(car1.model+" "+car1.name);
    
        Car car2 = new Car("캠핑카");  //캠핑카 벤츠 2개 출력하고 싶음
        System.out.println(car2.model+" "+car2.name);
    
      }
    ----------------------------------------------
    class Car{
      //필드
      String model, name;
    
      //생성자
      Car(String m, String n){
        model=m;  //이름을 같이하면 this.을 넣어줘야 함
        name=n;   //다른 이름이니까 this.필요 없음
      }
    
      Car(String m){
        this(m, "벤츠2");
      }
    
      //메소드없음
    }
    

3) 메소드 오버로딩

  • 메소드 이름은 같되 매개변수의 타입, 개수, 순서가 다른 메소드를 여러개 선언하는 것

    //메소드 오버로딩 기초
    
    class 클래스{
      리턴타입  메소드이름  (타입 변수, ... ) {...}
        무관      동일      타입, 개수, 순서가 달라야 
      리턴타입  메소드이름  (타입 변수, ... ) {...}
    }
    
    
    package 01;
    
    public class Calcultor{
      //정사각형의 넓이
      double areaRectangle(double width){
        return width * width;
      }
      double areaRectangle(double width, double height){ //위의 함수명과 같음
        return width * height;
      }
    }
    
    package 02;
    
    public class CalcultorExample{
      public static void main(String[] args) {
        //객체 생성
        Calcultor myCalcu = new Calcultor();
    
        //정사각형의 넓이 구하기
        double result1 = myCalcu.areaRactangle(10);
    
        //직사각형의 넓이 구하기
        double result2 = myCalcu.areaRactangle(10, 20);
    
        //→ 같은 함수명이어도 매개변수가 다르므로 다른 함수가 들어가게 됨!
    
      }
    }
    

5. 메소

  • 메소드 선언

  • 리턴타입: 메소드가 실행한 후 호출한 곳으로 전달하는 결과값의 타입
    리턴값이 없는 경우 void로 작성
  • 메소드명: 첫 문자를 소문자로 시작, 캐멀 스타일로 작성(ex: setSpeed)
  • 매개변수: 메소드 호출할 때 전달한 매개값. 개수 제한없음

  • 함수 선언 및 호출 예제

    //void형 메소드
    public class Test01 {
    
      static void pro(int age) {  //반환형은 void. 반환형이 없다는 것.
        System.out.println("안녕");
        System.out.println("나이는"+age+"이다"); //메인함수  안에 없으면 출력되지 않음
        //반환형이 void이기 때문에 return이 없음
        //반환형이 void인 함수는 대부분 출력문이 들어감
      }
      public static void main(String[] args) {
        //메소드는 반드시 클래스 안에 있어야함(캡슐화 원칙)
    
        System.out.println("시작");
        pro(2); //함수 호출 > 함수를 찾아 {}확인, "안녕 나이는 2이다" 실행됨
        pro(53); //pro라는 함수를 찾아서 매개변수에 ()값을 넣어서 실행
        System.out.println("끝");
      }
    
    }
    
    //return하는 메소드
    public class Test02 {
    
      //메소드는 클래스 안에 들어와야 함
      static double area(double r) { //실수형으로 받아서 배개변수 타입 double, 이름은 아무거나 가능
          return 3.14*r*r;
      }
      static double round(double r) { //실수형으로 받아서 배개변수 타입 double, 이름은 아무거나 가능
        return 3.14*2*r;
      }
    
      public static void main(String[] args) {
    
        System.out.println("원의 넓이: "+area(3.5));
        System.out.println("원의 둘레: "+round(4.5));
    
        //넓이 = 3.14 * r * r, 둘레 = 3.14 * 2 * r
    
      }
    
    }
    
  • 출력 위치에 따른 호출

    1. main 에서 할거면 함수에서 리턴

    • 함수호출과 동시에 출력
    • 변수를 주면서 리턴값을 저장
    public class Test02 {
    
      static int multi(int a, int b) {
        int m=1;
    
        for(int i=1;i<=b;i++) {
          m *= a; //m=m*a
        }
        return m;
      }
    
      public static void main(String[] args) {
    
        System.out.println(multi(2,10)); //함수 호출과 동시에 출력
        //2의 10승 구하기(2*2*2...)
    
      }
    
    }
    

    2. 함수에서 할거면 리턴문 필요없음(void)

    public class Test02 {
    
      static void total(int a,int b) { //함수 안에서 출력하면 반환형 필요없으므로 void
        int sum = 0;
    
        for(int i=a; i<=b;i++) {
          sum += i;
        }
        System.out.println(sum);
      }
    
      public static void main(String[] args) {
    
        total(1,10);   //1부터 10까지 합 출력
        total(1,100);  //1부터 100까지 합 출력
    
      }
    
    }
    
  • 변환 예시

    //출력문 위치에 따라 반환형 반환
    1. main에서  경우 : 출력값이 있으니 반환형 지정. 실수이므로 double
    public class Test02 {
      public static void main(String[] args) {
        System.out.println(meter(176));
      }
      static double meter(int n) { //메소드는 클래스 안에만 있음 됨. 위치상관 없음
        return n/100.0;
      }
    }
    ------------------------------------------------------------
    2. 함수 안에서  경우 : 출력값 없으니 void
    public class Test02 {
      static void meter(int n) {
        System.out.println(n/100.0);
      }
      public static void main(String[] args) {
        meter(176); //1.76
      }
    }
    ----------------------------------------------------------------
    삼항조건 활용   구하기
    public class Test02 {
    
        static double big(double a, double b) {
          return a>b ? a:b;
        }
    
      public static void main(String[] args) {
    
        System.out.println(big(5.5,6.5));
        //두 수 중 큰값 출력하는 함수
        //삼항조건연산자 활용
    
      }
    
    }
    
    
  • 변수의 종류

    • 지역변수: 한 블록 안에 있는 함수가 출력됨

      public class Test02 {
      
        static void in(){ //staric = 정적함수
          int a=10;
          System.out.println(a);
        }
      
        public static void main(String[] args) {
      
          int a=0;  //지역변수
          in();     //함수 호출, 메소드 안의 값: 10
          System.out.println(a); //main에 있는 변수 호출: 0
      
        }
      
      }
      
    • 전역변수(global variable): 전역변수를 블럭이랑 상관없이 출력

      public class Test02 {
        static int *a*;   //전역변수(global variable). static은 공유의 개녕
        static void aa() {
          *a*=10;
        }
      
        static void b() {
          int a=20;  //지역변수. b함수 안에서만 효력
        }
      
        public static void main(String[] args) {
            *aa*(); //a=10
            *b*();  //b=20
            System.out.println(a); //10
        }
      }
      ---------------------------------------------------------------
      public class Test02 {
      
        static int *a*;   //전역변수(global variable). static은 공유의 개녕
        static void aa() {
          *a*=10;
        }
      
        static void b() {
          *a*=20;  // int가 없는 경우 전역 변수로 변경되며 마지막 값으로 출력
        }
      
        public static void main(String[] args) {
            *aa*(); //a=10
            *b*();  //b=20
            System.out.println(*a*); //20
        }
      }
      
      
  • 예제

    // 메소드를 활용한 큰 값 출력 코드
    
    import java.util.Scanner;
    
    public class Test01 {
    
    static int big(int []arr) { //배열 호출은 배열형을 적어주면 됨
      int max=0;
    
      for(int i=0; i<arr.length; i++) { //원래 배열명이 a지만 여기선 []arr로 지역변수 설정
        if(max < arr[i]) {
          max = arr[i];
        }
      }
      return max;
    }
    
    public static void main(String[] args) {
    
      Scanner s = new Scanner(System.in);
    
        //정수형 7개를 넣을 수 있는 배열 a 생성
        int a[] = new int[7];
    
        for(int i=0; i<a.length; i++) {
          a[i] = s.nextInt();
        }
        System.out.println(big(a)); //7개중 가장 큰 값 출력
        //매개변수가 배열일 때, 배열을 호출할 때 배열명만 적으면 됨
      }
    }
    
    import java.util.Scanner;
    
    public class Test02 {
    
      static void cal(char a, int b, int c) {
        switch(a) {
          case '+':
            System.out.println(b+c);
            break;
          case '-':
            System.out.println(b-c);
            break;
        }
      }
    
      public static void main(String[] args) {
    
        Scanner s = new Scanner(System.in);
        char a=s.next().charAt(0);
        int b=s.nextInt();
        int c=s.nextInt();
    
        cal(a,b,c);  //함수 출력  //+ 입력: b+c , -입력: b-c
      }
    
    }
    -----------------------------------
    //배열 안 정수 합 구하기
    public class Test02 {
    
      static int total(int b[]) {
    
        int sum = 0;
    
        for(int i=0; i<b.length; i++) {
          sum += b[i];
        }
        return sum;
      }
    
      public static void main(String[] args) {
        int arr[] = {1,2,3,4,5};
        System.out.println(total(arr)); //배열 총합, 15
      }
    
    }
    
    public class Test02 {
    
    static void func(int a, int b) {
      Scanner s = new Scanner(System.in);
    
      int num = s.nextInt();
      a = num/5;
      b = num%5;
    
      System.out.printf("%d를 5로 나눈 몫:%d\n,5로 나눈 나머지, "
          +"5로 나눈 나머지"+num,a,b);
      }
    
      public static void main(String[] args) {
        int a=0, b=0;
        *func*(a,b);  //a: 몫, b: 나머지
      }
    
    }
    

6. 인스턴스 멤버

  • 필드와 메소드 선언 방법에 따라 인스턴스 멤버와 정적 멤버로 분류할 수 있음

    구분 설명
    인스턴스(instance) 멤버 객체에 소속된 멤버(객체를 생성해야만 사용할 수 있음)
    static이 없으면 다 인스턴스 멤버임  
    정적(static) 멤버 클래스에 고정된 멤버(객체 없이도 사용할 수 있음)
  • 인스턴스 멤버: 객체에 소속된 멤버. 따라서 객체가 있어야만 사용할 수 있는 맴버
  • this 키워드: 객체는 자신을 ‘this’라고 함. 생성자와 메소드의 매개변수 명이 인스턴스 멤버인 필드명과 동일한 경우, 인스턴스 필드임을 강조하고자 할 때 this를 주로 사용

    Car.java
    
    public class Car{
      //필드선언
      String model;
      int speed;
    
      //생성자 선언
      Car(String model){
        this.model = model;   //매개변수를 필드에 대입(this 생략 불가)
      }
    
      void setSpeed(int speed){
        this.speed = speed;//매개변수를 필드에 대입(this 생략 불가)
      }
    
      void run(){
        this.setSpeed(100); //←↓ this 생략가능              ↓
        System.out.println(this.model+"가 달립니다.(시속:"+this.speed+"km/h)");
      }
    }
    ------------------------------------------------
    CarExample.java
    
    public class CarExample{
      public static void main(String[] args) {
        Car myCar = new Car("포르쉐");
        Car yourCar = new Car("벤츠");
    
        myCar.run();   //포르쉐가 달립니다.(시속:100km/h)
        yourCar.run(); //벤츠가 달립니다.(시속:100km/h)
    }
    

7. 접근 제한자

  • 중요한 필드가 메소드와 외부로 노출되지 않도록 해 객체의 무결성(결점이 없는 성질)을 유지하기 위해 사용

    접근 제한자 제한 대상 제한 범위
    public 클래스, 필드, 생성자, 메소드 없음
    protected 필드, 생성자, 메소드 같은 패키지이거나, 자식 객체만 사용 가능
    (default) 클래스, 필드, 생성자, 메소드 같은 패키지
    private 필드, 생성자, 메소드 객체 내부

    package ch06.sec13.exam01.package1;
    
    class A { //default 접근 제한
    }
    ----------------------------------------
    package ch06.sec13.exam01.package1;     패키지가 동일
    
    public class B {
      //필드 선언
      A a;  //o         ← A클래스 접근 가능(필드로 선언할 수 있음)
    }
    ------------------------------------------
    package ch06.sec13.exam01.package2;     패키지가 다름
    
    public class C {
      //필드 선언
      A a;  //x         ← A클래스 접근 가능(필드로 선언할 수 있음)
      B b;  //o
    }
    
  • 필드와 메소드의 접근 제한

    접근 제한자 생성자 설명
    public 필드  
    메소드(…) 모든 패키지에서 필드를 읽고 변경 o  
    모든 패키지에서 메소드 호출 o    
      필드  
    메소드(…) 같은 패키지에서 필드를 읽고 변경 o  
    같은 패키지에서 메소드 호출 o    
    private 필드  
    메소드(…) 클래스 내부에서만 필드를 읽고 변경 o  
    클래스 내부에서만 메소드 호출 o    
    package ch06.sec13.exam03.package1;
    
    public class A{
      //public 접근 제한을 갖는 필드 선언
      public int field1;
      //default 접근 제한을 갖는 필드 선언
      int field2;
      //private 접근 제한을 갖는 필드 선언
      private int field3;
    
      //생성자 선언
      public A(){              //class가 public이니까 생성자도 public이어야 함
        field1 = 1;     //O
        field2 = 2;     //O
        field3 = 3;     //O    //같은 블럭 안이어서 가능
    
        method1();     //O
        method2();     //O
        method3();     //O
      }
    
      //public 접근 제한을 갖는 메소드 선언
      public void metod1(){
      }
    
      //public 접근 제한을 갖는 메소드 선언
      void metod2(){
      }
    
      //private 접근 제한을 갖는 메소드 선언
      private void metod3(){
      }
    }
    ----------------------------------------------------------------
    package ch06.sec13.exam03.package1;  //동일한 패키지
    
    public class B{
      public void method(){
        //객체 생성
        A a = new A();
    
        //필드값 변경
        a.field1 = 1;     //O
        a.field2 = 2;     //O
        a.field3 = 3;     //X    private필드 접근 불가
    
        a.method1();     //O
        a.method2();     //O
        a.method3();     //X    private필드 접근 불가
      }
    }
    }
    ----------------------------------------------------------------
    package ch06.sec13.exam03.package2;  //다른 패키지
    
    public class C{
      public C(){
        //객체 생성
        A a = new A();
    
        //필드값 변경
        a.field1 = 1;     //O
        a.field2 = 2;     //X    defaul 필드 접근 불가
        a.field3 = 3;     //X    private필드 접근 불가
    
        a.method1();     //O
        a.method2();     //X    defaul 필드 접근 불가
        a.method3();     //X    private필드 접근 불가
      }
    }
    
  • 예제

    package ch06.sec13.exam02.package1;
    
    public class A{
      //필드선언
      A a1 = new A(true);
      A a2 - new A(1);
      A a3 - new A("문자열");
    
      //public 접근 제한 생성자 생성
      public A(boolean b) {  //a1 정보 받음 o
      }
    
      //default 접근 제한 생성자 선언
      A(int b){              //a2 정보 받음 o
      }
    
      //private 접근 제한 생성자 선언
      private A(String s) {  //a3 정보 받음 o
      }
    }
    
    package ch06.sec13.exam02.package1;
    
    public class B{
      //필드 선언
      A a1 = new A(true);      //o
      A a2 - new A(1);         //o
      A a3 - new A("문자열");   //x. private 생성자 접근 불가(컴파일 에러)
    }
    
    package ch06.sec13.exam02.package2;  //패키지가 다름
    
    import ch06.sec13.exam02.package1.*;
    
    public class C{
      //필드 선언
      A a1 = new A(true);       //o
      A a2 - new A(1);          //x. default 생산자 접근 불가(컴파일 에러)
      A a3 - new A("문자열");   //x. private 생성자 접근 불가(컴파일 에러)
    }
    

8. 정적(static) 멤버

  • static이 붙어야 하고 객체를 생성하지 않아도 됨
  • 클래스에 고정적으로 위치하는 멤버, 변경하지 않는 값(고정된 값)인 경우 주로 사용

    public class 클래스{
      //정적 필드 선언
      static 타입 필드 [=초기값];
    
      //정적 메소드
      static 리턴타입 메소드(매개변수, ...){...}
    }
    
  • 정적멤버 사용

    • 클래스가 메모리로 로딩되면 정적 멤버로 바로 사용할 수 있음
    • 클래스 이름과 함께 도트(.)연산자로 접근하면 됨(new로 객체 생성 안해도 됨)
    public class Calculator{
      static double *pi* = 3.14159;
    
      static int plus(int x, int y){
        return x+y;
      }
    
      static int minus(int x, int y){
        return x-y;
      }
    }
    
    public class CalculatorExample{
      public static void main(String[] args) {
        double result1 = 10*10*Calculator.*pi*;
        int result2 = Calculator.plus(10,5);
        int result3 = Calculator.minus(10,5);
    
        System.out.println("result1: "+result1);  //314.159
        System.out.println("result2: "+result2);  //15
        System.out.println("result3: "+result3);  //5
      }
    }
    
  • 인스턴스 멤버 사용 불가

    • 정적 메소드와 정적 블록은 객체가 없어도 실행된다
    • 때문에 내부에 인스턴스 필드나 인스턴스 메소드 사용 불가하다
    • 객체 자신의 참조인 this로 쓸 수 없음
    class St{
      int n;
      void f1(int x) {
        n=x;
      }
      static int *m*;  //정적 멤버
    
      static void f2(int x) {  //정적 메소드
    **(!)**		**n=x;       //에러가 남. static에서는 static만 쓸 수 있음**
          //n은 인스턴스 멤버여서 사용할 수 없음!
      }
      static void f3(int x) {
        *m*=x;
      }
    }
    
    public class PP {
      public static void main(String[] args) {
          St.*m* =3;  **//정적 멤버는 클래스명으로부터 바로 접근 가능(객체 생성 필요 없음)**
    **(!)		St.n =3;**  //인스턴스멤버이기 때문에 객체만들고 접근해야 함
      }
    }
    

9. final 필드와 상수

  • final 필드초기값이 최종적인 값이 되어 프로그램 도중 수정할 수 없음

    1. 필드 선언 시에 초기값 대입 (주로 이렇게 씀)
    2. 생성자에서 초기값 대입
    
  • 상수 선언

    • 객체마다 저장할 필요 없음
    • 여러 개의 값을 가져도 안되기 때문에 static하면서 final함
    • 이름을 모두 대문자로 작성하는 것이 관례
    static final double ***PI*** = 3.14159;
    static final double ***EARTH_SURFACE_AREA*** = 5.147185403641517E8;
    
    public class Earth{
      //상수 선언 및 초기화
      static final double ***EARTH_RADIUS*** = 6400;
    
      //상수 선언
      static final double ***EARTH_SURFACE_AREA***;
    
      //정적 블록에서 상수 초기화
      static{
        ***EARTH_SURFACE_AREA*** = 4 Math.*PI*****EARTH_RADIUS*** * ***EARTH_RADIUS***;
      }                          //Math.PI는 자바에서 제공하는 상수
    
    public class EarthExample{
      public static void main(String[] args) {
        256
        //상수읽기                            ↓객체생성없이 바로 불러옴
        System.out.println("지구의 반지름: "+Earth.***EARTH_RADIUS***);  //6400.0
        System.out.println("지구의 vyauswjr: "+Earth.***EARTH_SURFACE_AREA***); //5.1471840
      }
    }
    

10. 패키지

  • 주로 회사의 도메인 이름의 역순으로 생성
  • 상위 패키지와 하위 패키지는 도트(.)로 구분
  • 모두 소문자로 작성하는게 관례

  • import문

    • 다른 패키지에 있는 클래스를 사용할 때 사용 (ex: 스캐너 사용을 위한 import java.util.Scanner;)
    import java.utill.*; //모든 utill을 다 사용하겠다
    
  • import문 자동 추가

    “Ctrl + Shift + O” (이클립스)

11. Getter와 Setter

  • Getter: 값을 가져옴 / Setter: 값을 셋팅

    Private 타입 fieldName;       //필드 접근 제한자: private
    
    //Getter
    public 타입 getFieldName(){   //메소드 이름: get+필드이름(첫글자 대문자)
      return fieldName;
    }
    
    //Setter
    Public void setFieldName(타입 fieldName){ //메소드 이름: get+필드이름(첫글자 대문자)
      this.fieldname = fieldname;
    }
    

    이클립스에서 사용하기

    source > Generate Getter and Setters > 객체 선택 > Generate하면 자동적으로 생성

  • 예제
package ch06.sec14;

public class Car{
  //필드 선언
  private int speed;
  private boolean stop;

  //speed 필드의 Getter/Setter선언
  public int getSpeed() {
    return speed;
  }

  public void setSpeed(int speed){
    if(speed < 0){
      this.speed = 0;
      return;
    }else{
      this.speed = speed;
    }
  }

  //stop필드의 Getter/Setter 선언
  public boolean isStop(){
    return stop;
  }
  public void setStop(boolean stop){
    this.stop = stop;
    if(stop == true) this.speed = 0;
  }
}

package ch06.sec14;

public class CarExample{
  public static void main(String[] args) {
    //객체생성
    Car myCar = new Car();

    //잘못된 속도 변경
    myCar.setSpeed(-50);
    System.out.println("현재 속도: "+myCar.get.Speed());

    //올바른 속도 변경
    myCar.setSpeed(60);
    System.out.println("현재 속도: "+myCar.get.Speed());

    //멈춤
    if(!myCar.isStop()){
      myCar.serStop(true);
    }
    System.out.println("현재 속도: "+myCar.get.Speed());
  }
}
class A{

    private int age;
    private double height;
    private String name;
    public int getAge() {
      return age;
    }
    public void setAge(int age) {
      this.age = age;
    }
    public double getHeight() {
      return height;
    }
    public void setHeight(double height) {
      this.height = height;
    }
    public String getName() {
      return name;
    }
    public void setName(String name) {
      this.name = name;
    }
}

public class PP {
  public static void main(String[] args) {
    A a = new A();
    a.setAge(7);
    System.out.println(a.getAge());   //7
  }
}

12. 싱글톤 패턴

  • 단 한개의 객체만 생성
  • 생성자를 private 접근 제한해서 외부에서 new 연산자로 생성자를 호출할 수 없도록 막는 것
  • 생성자를 호출할 수 없어 외부에서 객체를 생성하는 것 불가능
  • 정적 메소드를 통해 간접적으로 객체를 얻을 수 있음

    public class 클래스{
      //private 접근 권한을 갖는 정적 필드 선언과 초기화
      private static 클래스 singleton = new 클래스();    //------①
    
      //private 접근 권한을 갖는 생성자 선언
      private 클래스() {}
    
      //public 접근 권한을 갖는 정적 메소드 선언
      public static 클래스 getInstance(){         //-------------②
        return sington;  //반환형 = 클래스
      }
    }
    

    ① 에서는 자신의 타입으로 정적 필드 선언, 미리 객체를 생성해서 초기화

    private 접근 제한자를 붙여 외부에서 변경하지 못하도록 막음
    

    ② 에서 정적 필드값을 리턴하는 getInstance() 정적 메소드를 public으로 선언

  • singleton 사용예

    package ch06.sec15;
    
    public class Singleton{
      //private 접근 권한을 갖는 정적 필드 선언과 초기화
      private static Singleton *Singleton* = new Singleton(); //자기 자신에서 객체 생성
      //↑ 외부에서 객체 생성을 못하도록 막음
    
      //private 접근 권한을 갖는 생성자 선언
      private Singleton(){
      }
    
      //public 접근 권한을 갖는 정적 메소드 선언
      //↓ 외부에서 접근할 수 있게 public
      public static Singleton getInstance(){  //반환형 클래스(Singleton)
        return *Singleton*;  //Singleton객체의 주소값 리턴
      }
    }
    -------------------------------
    package ch06.sec15;
    
    public class SingletonExample{
      public static void main(String[] args) {
        /*
        Singleton obj1 = new Singleton; //컴파일 에러
        Singleton obj2 = new Singleton; //컴파일 에러
        */
    
        Singleton obj1 = new Singleton.getInstance; //static은 객체생성 없이 쓸 수 있음
        Singleton obj2 = new Singleton.getInstance;
    
        //동일한 객체를 참조하는지 확인
        if(obj1 == obj2){
          System.out.println("같은 Singleton 객체입니다");
        }else{
          System.out.println("다른 Singleton 객체입니다");
        }
      }
    }
    

13. 중첩, 인스턴스 멤버 클래스

중첩클래스

  • 중첩 클래스: 클래스 내부에 선언한 클래스
    • 클래스와 멤버를 쉽게 사용할 수 있음
    • 외부에는 중첩관계 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있음
  • 클래스가 여러 클래스와 관계를 맺는 경우 독립적으로 선언하는 것이 좋다
  • 특정 클래스만 관계를 맺을 경우 중첩 클래스로 선언하는 것이 유지보수에 도움이 될 수 있다

인스턴스 멤버 클래스

  • 인스턴스 멤버 클래스B는 주로 클래스A 내부에서 사용되므로 private 접근 제한자를 갖는게 일반적
397
class A{
//인스턴스 멤버 클래스
class B{
  //인스턴스 필드
  int field1 = 1;

  //정적 필드(JAVA17부터 허용)
  static int *field2* = 2;

  //생성자
  B(){
    system.out.println("B-생성자 실행");
  }

  //인스턴스 메소드
  void method1(){
    system.out.println("B-method1 실행");
  }

  //정적 메소드(Java17부터 허용)
  static void method2(){
    system.out.println("B-method2 실행");
  }
}

//인스턴스 메소드
void useB(){
  //B객체 생성 및 인스턴스 필드 및 메소드 사용
  B b = new B();
  system.out.println(b.field1);
  b.method1();

  //B클래스의 정적 필드 및 메소드 사용
  system.out.println(b.*field2*);
  b.*method2*();
}
}

class AExample{
public static void main(String[] args) {
  //A객체 생성
  A a = new A();

  //A인스턴스 메소드 호출
  a.useB();
}
}
--------------------------------------------
출력
B-생성자 실행
1
B-method1 실행
2
B-method2 실행

14. 기출문제

  • 다섯 과목 점수가 저장된 배열의 값에 따라 #출력 (#은 5점당 하나씩 출력하며 남는 점수는 버리기. pr함수를 작성

    main(){
      int score[]=new int[] {58, 60, 86, 90, 84};
      pr(score, 5)
    }
    
    // 직성
    public class Test02 {
    
      static void pr(int[] a, int b) {
        for(int i=0; i<5; i++) {
          int j = a[i]/5;
          for(int k=0; k<j; k++) {
            System.out.print("#");
          }
          System.out.println();
        }
      }
      public static void main(String[] args) {
        int score[] = new int[] {58,60,86,90,84};
        pr(score, 5);
      }
    }
    
    // 풀이
    public class Test02 {
    
      static void pr(int a[], int b) {
        for(int k:a) {
          System.out.println(k);
          for(int i=0;i<k/b;i++) {
            System.out.print("#");
          }
          System.out.println();
        }
      }
      public static void main(String[] args) {
        int score[]=new int[] {58, 60, 86, 90, 84};
        pr(score,5);
      }
    }
    
  • p279 15번 문제 로그인

    class MemberService{
      boolean login(String a, String b) {
        if(a.equals("hong" ) && b.equals("12345")) {
          return true;
        }else {
          return false;
        }
      }
      void logout(String a) {
        System.out.println(a+"님이 로그아웃되었습니다");
      }
    }
    
    public class Test02 {
      public static void main(String[] args) {
        MemberService memberService = new MemberService();
        boolean result = memberService.login("hong", "12345"); //login 함수 존재
        if(result) {
          System.out.println("로그인 되었습니다.");
          memberService.logout("hong");
        }else {
          System.out.println("id또는 password가 올바르지 않습니다");
        }
      }
    }
    
  • main()함수를 보고 class 제작

    //main() 함수
      public static void main(String[] args) {
    
        Circle c = new Circle(); //객체생성
        c.radius = 30;           //초기화(처음으로 값을 넣음)
        c.name="java";           //초기화(처음으로 값을 넣음)
    
        double area = c.getArea(); //함수호출해서 area에 저장
        System.out.println(area);
    
        //Circle 클래스를 만들어서 radius, name, getArea()생성해야 함
      }
    ----------------------------------------------------------------
    //class함수 제작
    class Circle{  	//클래스에는 필드 생성자 메소드 존재
      //필드
      int radius;
      String name;
    
      //생성자
      //Circle c = new Circle(a,b);와 같이 매개변수가 있으면 생성자 필수
      //현재 값이 없기때문에 생성자 필요없음(기본 생성자로 들어감)
    
      //메소드
      double getArea(){  //main함수에서 매개변수 없으니까 ()
        return radius*radius*3.14;
      }
    }
    
    //main() 함수
      public static void main(String[] args) {
    
        Circle c = new Circle(30,"java"); //객체생성
        double area = c.getArea(); //함수호출해서 area에 저장
        System.out.println(area);
    
        //Circle 클래스를 만들어서 radius, name, getArea()생성해야 함
      }
    ----------------------------------------------------------------
    //class함수 제작
    class Circle{
      //필드 생성자 메소드
      int radius;
      String name;
    
      //생성자 작성
      //Circle c = new Circle(30,"java")에 매개변수가 있음
      Circle(int radius, String name){
        this.radius=radius; //radius=30
        this.name=name; //name="java"
      }
    
      //메소드
      double getArea(){  //main함수에서 매개변수 없으니까 ()
        return radius*radius*3.14;
      }
    }
    
  • main()함수를 보고 class 제작2

    //main() 함수
      public static void main(String[] args) {
    
        Cal c = new Cal();
        double a = c.area(10);
        System.out.println(a);
      }
    ----------------------------------------------------------------
    //class함수 제작
    class Cal{
      //필드, 생성자, 메소드
      //필드 없고 생성자 필요없음
    
      double area(int n) {
        return n*n;
      }
    }
    
  • 오버로딩을 활용한 class 제작

    1.main()를 보고 클래스를 작성해라.

    Student s1=new Student(“김길동”, “kim”);
    Student s2=new Student(“이길동”, “lee”);
    s1.pr(); s2.pr(); //모든 데이터 출력
    
    class Student{
      String name, first;
    
      Student(String a, String b){
        name = a;
        first = b;
      }
    
      void pr(){
        System.out.println(name+" "+first);
      }
    }
    
    public class ClassStudy {
      public static void main(String[] args) {
        Student s1 = new Student("김길동","kim");
        Student s2 = new Student("이길동","lee");
        s1.pr(); s2.pr();  //모든 데이터 출력
      }
    }
    

2.main()를 참조하여 클래스를 작성해라.

main(){
  Music m=new Music("On", "BTS");
  System.out.println(m.title+" "+m.singer); // On , BTS 출력

  Music m1=new Music("Butter");
  System.out.println(m1.title+" "+m1.singer); // Butter, 방탄 출력
class Music{
  String title, singer;

  Music(String title, String singer){
    this.title = title;
    this.singer = singer;
  }

  Music(String title){
    this(title, "방탄");
  }
}

public class ClassStudy {

  public static void main(String[] args) {

    Music m=new Music("On", "BTS");
    System.out.println(m.title+" "+m.singer); // On , BTS 출력

    Music m1=new Music("Butter");
    System.out.println(m1.title+" "+m1.singer); // Butter, 방탄 출력

  }
}

  • 클래스를 이용한 배열합

    class Score {
      int sum = 0;
    
      void show (int[][] arr) {
        for(int i=0;i<arr.length;i++) {
          for(int j=0;j<arr[i].length;j++) {
            sum += arr[i][j];
          }
        }
        System.out.println(sum/12.0);
      }
      //show 함수 구현 > 배열에 있는 총합 구해서 평균 출력
    }
    public class PP {
      public static void main(String[] args) {
        int [][] grade = { {90,100,80},
                {70,95,87},
                {80,90,70},
                {90,100,100}};
        Score s = new Score();
        s.show(grade);
      }
    }
    

  • 복권의 번호와 추첨한 복권의 번호를 확인하여 일치하는 번호의 개수를 출력하는 프로그램.
    두 배열은 main함수에 선언하고 두 배열에서 일치하는 번호를 찾아 그 개수를 반환해라.

    public class Test {
    
      static int same(int a[], int b[]) {
        int cnt = 0;
        for (int i = 0; i < a.length; i++) { //4를 기준으로
          for(int j=0; j<b.length; j++) {  //1,4,7,26,45,48 반복
            if (a[i] == b[j]) {
              cnt ++;
            }
          }
        }
        return cnt;
      }
    
      public static void main(String[] args) {
    
        int lotto[] = {4,10,25,30,45,47};
        int my[] = {1,4,7,26,45,48};
        int r;
    
        r=same(lotto,my);
        System.out.printf("일치하는 번호의 개수:%d\n",r);
    
      }
    }
    

  • show()함수를 배열을 역순으로 출력하는 함수로 정의해라.

    public class Test {
      static void show(int a[]) {
        for(int i=1; i<=a.length; i++) {
          int b=a.length-i;
          System.out.print(a[b]+" ");
        }
      }
      public static void main(String[] args) {
        int arr[] = {6,2,8,4,9};
        show(arr);
      }
    }
    ----------------------------------------------
    //더 간단하게
      static void show(int a[]) {
        for(int i=a.length-1; i>=0; i--) {
          System.out.print(a[i]+" ");
        }
      }
    

  • p279 16번

    class Printer{
      void println(int n) {
        System.out.println(n);
      }
      void println(boolean n) {
        System.out.println(n);
      }
      void println(double n) {
        System.out.println(n);
      }
      void println(String n) {
        System.out.println(n);
      }
    }
    public class PP {
      public static void main(String[] args) {
        Printer printer = new Printer();
        printer.println(10);
        printer.println(true);
        printer.println(5.7);
        printer.println("홍길동");
      }
    }
    

  • p280 17번 : static추가 및 클래스에서 바로 호출

    class Printer{
      static void println(int n) {
        System.out.println(n);
      }
      static void println(boolean n) {
        System.out.println(n);
      }
      static void println(double n) {
        System.out.println(n);
      }
      static void println(String n) {
        System.out.println(n);
      }
    }
    public class PP {
      public static void main(String[] args) {
        Printer.println(10);
        Printer.println(true);
        Printer.println(5.7);
        Printer.println("홍길동");
      }
    }
    
    
    • main() 함수를 수보고 class 만들기
    public class Test {
    
      public static void main(String[] args) {
    
        Shape s = new Shape();
        Shape s1 = new Shape(2,5);
    
        s.pr("@"); //값을 다르게 반환하기 때문에 초기화 필요
        s1.pr("#");
        s.show(); //@@@-> 1행 3열로 출력
        s1.show(); //#####->2행 5열로 출력
        //#####
    
      }
    }
    --------------------------------------------
    class Shape{
    
    int a, b;
    String c;
    
    Shape(int a, int b){
      this.a = a;
      this.b = b;
    }
    Shape(){
      this(1, 3);
    }
    
    void pr(String c) { //필드에 초기화하는 값
      this.c = c;
    }
    
    void show() {
      for(int i=0; i<a; i++) {
        for(int j=0; j<b; j++) {
          System.out.print(c);
        }
        System.out.println();
      }
    }
    }
    
    public class PP {
      public static void main(String[] args) {
      Book b1=new Book("멋진 신세계", "올더스 헉슬리");
      Book b2=new Book("더 해빙");
      Book b3=new Book();
      }
    }
    ----------------------------------------------------
    class Book{
      String a,b;
      Book(){
        System.out.println("생성자 호출!");
      }
      Book(String a){
        this(a, "작자미상");
      }
      Book(String a, String b){
        this.a = a;
        this.b = b;
        System.out.println(a+" "+b);
      }
    }
    

태그:

카테고리:

업데이트:

댓글남기기