2023/04/04 ~ 04/05

이동규·2023년 4월 5일
post-thumbnail

JAVA 기초 문법 강의

연산자

→ 연산자 우선순위 : 산술 > 비교 > 논리 > 대입

  • 산술 연산자 : +, -, *, /, %, <<, >>

  • 논리 연산자 : &&, ||, ! → 비교 연산의 결과값으로 받을 수 있는 boolean 값을 연결하는 연산

  • 기타 연산자 : (type)→ 형변환 연산자, ? :, instance

    • 삼항 연산자
      • 조건 ? 참 : 거짓 → 조건이 맞다면 참에 있는 값이 나오고 아니면 거짓에 있는 값이 나옴
    • instance of
      • 피연산자가 조건에 명시된 클래스의 객체인지 비교하여 맞으면 true, 틀리면 false
  • 비트 연산자

    • 비트 연산이 제일 빠름 (컴퓨터가 바로바로 이해할 수 있어서)

    • 자릿수를 왼쪽으로 옮기는 횟수만큼 2의 배수로 곱셈이 연산 되는 것과 동일

    • 자릿수를 오른쪽으로 옮기는 횟수만큼 2의 배수로 나눗셈이 연산되는 것과 동일

조건문

  • switch 문과 if 문 차이
    • switch 문이 가독성이 좋음
    • if 문은 복합 조건 지원 → 조건을 여러 개 생성 가능

반복문

  • 향상된 for문
    • for 문을 2개로 줄여줌

      int[] numbers = {3, 6, 9, 12, 15};
      for (int number : numbers) {
      	~~~~
      }

Continue

  • continue 명령어 다음은 skip 하고 바로 다음 반복문으로 돌아감!!

배열

  • 선언과 생성이 필요하다
    • 생성 시에는 배열의 크기를 미리 정해야 한다.
  • 배열을 복사할 때 얕은 복사를 하면 복사 원본 배열도 요소가 바뀜
    • 깊은 복사를 해야함(clone 사용 → 2차원 배열에는 얕은 복사로 동작!!)
      - 즉, Arrays.copyOf(복사 배열 원본, 길이); 사용!!

      int[] a = {1, 2, 3, 4};
      int[] b = Arrays.copyOf(a, a.length); 
  • String 배열
    • 복습 [기본형 변수 vs. 참조형 변수]

      • 기본형 변수는 ‘소문자로 시작함’ 반면, 참조형 변수는 ‘대문자로 시작함’ → Wrapper class에서 기본형 변수를 감싸줄 때(boxing), int → Integer
      • 기본형 변수는 값 자체를 저장, 참조형 변수는 별도의 공간에 값을 저장 후 그 주소를 저장(주소형 변수)
      • String이 가지고 있는 기능이 많아서 String을 더 많이 사용함
    • String 기능 활용

      String str = "ABCD";
      
      int strLength = str.length();
      char strChar = str.charAt(1); // str의 1번째 문자 출력
      
      String strSub = str.substring(0, 3); // str의 0번째 부터 3번째 값 출력
      
      //toCharArray() : String -> char[]
      char[] strCharArray = str.toCharArray();
      
      //반대로
      char[] charArray = {'A', 'B', 'C'};
      String charArrayString = new String(charArray);
  • 다차원 배열
    • int[][] array = new int[행 개수(y)][열 개수(x)];

컬렉션

  • Wrapper Class로 type 선언
  • List, Set, Queue, Map 존재
  • 기능 : 크기 자동조정/추가/수정/삭제/반복/순회/필터/포함확인 등
  • 컬렉션🧬 종류
    • List : 순서가 있는 데이터의 집합 (데이터 중복 허용) - 배열과 비슷
    • Queue : 빨대🥤처럼 한쪽에서 데이터를 넣고 반대쪽에서 데이터를 뺄 수 있는 집합
      • First In First Out : 먼저들어간 순서대로 값을 조회할 수 있다.
    • Set : 순서가 없는 데이터의 집합 (데이터 중복 허용 안함) - 순서없고 중복없는 배열
    • Map : 순서가 없는 (Key,Value) 쌍으로 이루어진 데이터의 집합 (Key값 중복 허용 안함)

  • Collection🧬 은 기본형 변수가 아닌 참조형 변수를 저장

  • List

    • 처음에 길이를 몰라도 만들 수 있음

    • ArrayList → 동적 배열

    • 생성 시점에 작은 연속된 공간을 요청해서 참조형 변수들을 담아놓는다.

      ArrayList<Integer> intList = new ArrayList<Integer>(); //선언 생성
      
      intList.add(99);
      intList.add(15);
      intList.add(3);
      
      sout(intList.get(2));
      
      //2번째 값 10으로 변경
      intList.set(1, 10);
      
      //삭제
      intList.remove(0); //list 첫번째 값 삭제
      
      //비우기
      intList.clear();
      
      //list 속 인자 확인
      sout(intList.toString());
    • linked list

      • 메모리에 남는 공간을 요청해서 여기 저기 나누어서 실제 값을 담는다.

      • 실제 값이 있는 주소 값으로 목록을 구성하고 저장하는 자료구조

      • 기본적 기능은 ArrayList와 동일

      • 조회하는 속도가 느림 (여기저기 저장해서) but, 값을 추가하거나 삭제할 때는 빠름

        LinkedList<Integer> linkedList = new LinkedList<Integer>();
        
        //ArrayList와 명령어는 같음
        
        linkedList.add(2, 4); //2번째 index에 4를 추가 -> 빠름
  • Stack
    • FILO

    • push, peek, pop 기억!!

    • 최근 저장된 데이터를 나열하거나, 데이터 중복 처리를 막고 싶을 때

      Stack<Integer> intStack = new Stack<Integer>();
      
      intStack.push(10);
      intStack.push(15);
      intStack.push(1);
      
      while(!intStack.isEmpty()){ // 비어 있을 때까지 값을 빼준다.
      	sout(intStack.pop()); // 상단에 있는 값만 빼준다.
      }
      
      intStack.push(10);
      intStack.push(15);
      intStack.push(1);
      
      sout(intStack.peek()); //상단에 있는 값 출력
      sout(intStack.size()); //Stack 크기 출력
  • Queue
    • FIFO

    • add, peek, poll 기억

    • 생성자가 없는 인터페이스

      Queue<Integer> intQue = new LinkedList<>(); //생성자가 없기 때문에 LinkedList로 선언
      
      intQue.add(1);
      intQue.add(5);
      intQue.add(9);
      
      while(intQue.isEmpty()) {
      	sout(intQue.poll()); //처음 넣었던 값 순서대로 빼내기
      }
      
      intQue.add(1);
      intQue.add(5);
      intQue.add(9);
      
      sout(intQue.peek()); // 맨 먼저 넣었던 값 출력
      sout(intQue.size()); // 큐 사이즈 출력
  • Set
    • 집합과 닮음 : 순서 없고, 중복 없음

    • 순서가 보장되지 않는 대신 중복을 허용하지 않도록 하는 프로그램에서 사용할 수 있는 자료구조

    • Set → 그냥 쓸 수도 있으나, HashSet, TreeSet 등으로 응용

    • 생성자가 없는 인터페이스여서 바로 생성 불가

      → 생성자가 존재하는 HashSet을 이용해서 set 구현 가능

    • 입력한 순서대로 요소를 유지해야 할 필요가 있는 경우에는 LinkedHashSet
      을 사용

    • set은 특정 위치의 값을 불러들이기 힘들다.

      Set<Integer> intSet = new HashSet<>();
      
      intSet.add(1);
      intSet.add(12);
      intSet.add(5);
      intSet.add(9);
      intSet.add(1);
      intSet.add(12);
      
      for (Integer val : intSet){
      	sout(value);
      } // 값이 1, 5, 9, 12 -> 4개만 나옴(중복 제거)
      
      //contains 메소드
      sout(intSet.contains(2)); // 2를 포함하고 있니? -> true or false
      
  • Map
    • map : key - value pair → 중요!!

    • key라는 값으로 unique하게 보장이 되어야 함!!

    • Map → HashMap, TreeMap 응용!

      Map<String, Integer> intMap = new HashMap<>(); // <key, value> !!
      
      intMap.put("일", 11);
      intMap.put("이", 12);
      intMap.put("삼", 13);
      intMap.put("삼", 14);// 중복 키
      intMap.put("삼", 15);// 중복 키
      
      for(String key : intMap.keySet()) { //키 값만 빼낸다
      		sout(key);
      } // 세개 키 값만 출력
      
      for(String key : intMap.values()) { //value 값만 빼낸다
      		sout(key);
      } // 11, 12, 15 출력 -> 중복 키의 value 값 중 마지막 값으로 출력
      
      sout(intMap.key("삼")); // 키가 "삼"이라는 키의 value 값을 출력 -> 15!!

객체 지향 언어

  • 객체란 무었인가?

    • 식별이 가능한 것
    • 속성과 행위 가질 수 있다
      • 속성 = 필드
      • 행위 = 메서드
    • 객체 간의 협력!
      • 객체가 (매개 변수와 함께)메서드를 호출하면서 상호작용이 일어난다. 이로써 데이터를 주고 받을 수 있다.
    • 사용 관계
      • 사람과 차의 관계
    • 포함 관계
      • 차와 타이어 관계
    • 상속 관계
      • 공장과 차의 관계 또는 공장과 기차의 관계
      • 이 안에 차와 기차는 기계 시스템의 객체를 상속 받는다.
  • 객체 지향 프로그래밍의 특징

    • 캡슐화, 상속, 다향성, 추상화
    • 캡슐화
      • 속성과 행위를 하나로 묶어 객체로 만든 후 실제 내부 구현 내용은 외부에서 알 수 없게 감춘다.
      • 보안 관점에서 중요!!
      • 외부 객체에서 접근이 불가하여 객체가 변화하지 않게 한다.
      • 노출 유무로 접근 제어자(public/private)을 사용
    • 상속
      • 부모 객체와 자식 객체가 존재
      • 부모 객체가 갖고 있는 속성(필드)와 행위(메서드)를 자식 객체에 물려주어 이를 사용할 수 있게 만든다.
      • 상속을 하는 이유
        • 객체 간의 구조 파악 쉬움
        • 코드 중복이 줄어듦
    • 다향성
      • 객체가 하나의 행위에 대해 각 객체가 가지고 있는 고유의 특성에 따라 여러가지 형태로 재구성 되는 의미
      • 각각의 객체들은 다양한 형태의 메서드를 가져갈 수 있도록 변경 가능
    • 추상화
      • 객체에서 공통된 부분들을 모아 상위 개념으로 새롭게 선언하는 것
      • 어떠한 객체 안에 반복되고 공통되는 속성들을 추상화하여 여러 군데에 모델링이 가능
  • 객체와 클래스

    • 객체를 생성하기 위해서는 설계도가 필요
    • 설계도에 해당하는 클래스가 필요
    • 클래스를 토대로 생성된 객체를 ‘인스턴스’라 한다.
  • 중요!!

    • .java 파일 속 class 클래스_이름 = 객체를 만들기 위한 설계도!!!
  • 클래스 설계

    • 클래스를 만들기 위한 4가지 STEP
      1. 만들려고 하는 설계도를 선언.(클래스 선언)
      2. 객체가 가지고 있어야 할 속성(필드)를 정의
        • 변수 형태로 선언
      3. 객체를 생성하는 방식을 정의.(생성자 - constructor)
        • 어떤 input을 넣어서 생성할지
        • 어떤 기본적인 로직이 출력할지
        • 어떤 로그를 출력할지
        • 생성자 부분은 클래스 이름과 동일한 형태의 이름을 가진 메서드 형태여야 한다.
      4. 객체가 가지고 있어야 할 행위(메서드) 정의
    • Car Class 생성 example)
public class Car {
    //필드 영역===============================================================//
    //필드 선언
    //고유 데이터 영역---------------------------------------------------------//
    String company;
    String model;
    String color;
    double price;
    //상태 데이터 영역---------------------------------------------------------//
    double speed;
    char gear;
    boolean lights;
    //객체 데이터 영역---------------------------------------------------------//
    Tire tire;
    Door door;
    Handle handle;

    //생성자 영역=============================================================//
    //생성자 : 처음 객체가 생성될 때(instance 화) 어떤 로직을 수행하며,
		//어떤 값이 필수로 들어와야 하는지 정의!
    public Car() {
    }

    //logic
    // 아무것도 없는 상태 : 기본 생성자 = 생략 가능
    // 메서드 영역============================================================//
    //gasPedal
    //input : km/H
    //output : speed
    double gasPedal(double kmH) {
        speed = kmH;
        return speed;
    }

    //brakePedal
    //input : void
    //output : speed
    double brakePedal() {
        speed = 0;
        return speed;
    }

    //changeGear
    //input : gear(char type)
    //output : gear(char type)
    char changeGear(char type) {
        gear = type;
        return gear;
    }

    //onOffLight
    //input : void
    //output : lights(boolean)
    boolean onOffLights() {
        lights = !lights;
        return lights;
    }

    //horn
    //input : void
    //output : void
    void horn() {
        System.out.println("빵빵~~~");
    }
}
  • 객체 생성
    • Main Class 코드
public class Main {
    public static void main(String[] args) {
        Car car1 = new Car();
        Car car2 = new Car();

        System.out.println(car1); // week03.Car@6d03e736
                                  //-> 별도 공간에 저장하고 그 주소를 가져옴
        //
        Car[] carArray = new Car[3];
        car1.changeGear('P');
        carArray[0] = car1;

        car2.changeGear('N');
        carArray[1] = car2;

        Car car3 = new Car();
        car3.changeGear('D');
        carArray[2] = car3;

        for(Car car : carArray) {
            System.out.println("car.gear = " + car.gear);
        }
    }
}

//======================================================================//
//Tire Class & Handle Class & Door Class
public class Tire {
    public Tire() {
        System.out.println("타이어가 생성 되었습니다.");
    }
}

public class Handle {
    public Handle() {
        System.out.println("손잡이 객체가 생성되었습니다.");
    }
}

public class Door {
    public Door() {
        System.out.println("문 객체이 생성되었습니다.");
    }
}
  • 객체의 속성

    • 필드

    • 필드를 정의하여 선언했다고 바로 사용 불가 → 인스턴스화를 해야한다.

    • 필드 사용방법

      📌 ‘필드를 사용한다’ 라는 의미는 필드의 값을 변경하거나 읽는 것을 의미 - 우리가 클래스에 필드를 정의하여 선언했다고 해서 바로 사용할 수 있는 것은 아님 - 클래스는 설계도일 뿐 실제로 필드의 데이터를 가지고 있는 것은 객체이다. - 따라서 객체를 생성한 후에 필드를 사용할 수 있다. - 외부 접근 - `Car car = new Car();` - 이렇게 객체를 생성했다면 우리는 참조변수 car를 이용하여 외부에서 객체 내부의 필드에 접근하여 사용할 수 있다. - 이때 객체의 내부 필드에 접근하는 방법은 도트(.) 연산자를 사용하면 된다. - `car.color = "blue";` - 내부 접근 - 도트 연산자를 사용하여 외부에서 객체 내부에 접근할 수 있을 뿐만 아니라 객체 내부 메서드에서도 내부 필드에 접근할 수 있다. ```java double brakePedal() { speed = 0; return speed; } ``` - 이처럼 `brakePedal()` 메서드 내부에서 객체의 필드 speed를 바로 호출해서 사용할 수 있다.
    • 초기화한 Main Class 코드

      public class Main {
          public static void main(String[] args) {
              Car car = new Car();
      
              //초기값과 기본값 확인 : 초기값을 준 것은 그 값이 들어가고,
      				//아닌 값은 default value가 set
              System.out.println("car.model = " + car.model); // 초기값 "Gv80"이 출력
              System.out.println("car.color = " + car.color); // 기본값 null이 출력
              System.out.println();
      
              System.out.println("car.speed = " + car.speed); // 기본값 0.0이 출력
              System.out.println("car.gear = " + car.gear);  // 기본값 \u0000(공백)이 출력
              System.out.println("car.lights = " + car.lights); // 초기값 true가 출력
              System.out.println();
      
              System.out.println("car.tire = " + car.tire); // 초기값 인스턴스의 주소가 출력
              System.out.println("car.door = " + car.door); // 기본값 null이 출력
              System.out.println();
      
              //필드 사용
              car.color = "blue"; // 필드 color "blue" 저장
              car.speed = 100;
              car.lights = false;
              System.out.println("car.speed = " + car.speed); // 100.0 출력
              System.out.println("car.color = " + car.color); // blue 출력
              System.out.println("car.lights = " + car.lights); // false 출력
      
          }
      }
  • 객체의 행위 : 메서드
    • 객체 간의 협력을 위해 사용
    • 메서드의 행위를 정의하는 방법은 블록{ } 내부에 실행할 행위를 정의하면 된다
    • 위의 Car Class 코드 안에 메서드 영역을 살펴보면 메서드 선언 방법을 알 수 있다.
    • 주의할 점은 메서드에 리턴타입을 선언하여 반환할 값이 있다면 반드시 return 문으로 해당하는 리턴타입의 반환값을 지정해야 한다.
    • 메서드는 실행할 때 return문을 만나면 그대로 종료하게 되는데 void 타입일 때 return; 이렇게 return문을 사용하여 원하는 지점에서 메서드를 종료할 수도 있다.
    • 매개 변수는 input, return 값은 output
    • 외부 접근
      • Car car = new Car();
        • 이렇게 객체를 생성했다면 우리는 참조변수 car를 이용하여 외부에서 객체 내부의 메서드에 접근하여 호출할 수 있습니다.
        • 이때 객체의 내부 메서드에 접근하는 방법은 도트(.) 연산자를 사용하면 됩니다.
          • car.brakePedal();
        • 또한 메서드가 매개변수를 가지고 있다면 반드시 호출할 때 매개변수의 순서와 타입에 맞게 매개값을 넣어줘야 합니다.
          • car.gasPedal(100, 'D');
    • 내부 접근
      • 도트 연산자를 사용하여 외부에서 객체 내부에 접근할 수 있을 뿐만 아니라 객체 내부 메서드에서도 내부 메서드에 접근하여 호출할 수 있습니다.
        double gasPedal(double kmh, char type) {
            changeGear(type);
            speed = kmh;
            return speed;
        }
        • 이처럼 gasPedal(double kmh, char type) 메서드 내부에서 해당 객체의 changeGear(type); 메서드를 호출할 수 있습니다.
  • gasPedal 메서드 & carSpeed 메서드
double gasPedal(double kmH, char type) {
        changeGear(type); // 가속도 페달을 밟으면 자동으로 기어가 변한다.
        speed = kmH;
        return speed;
}

// 자동차의 속도 .. 가변길이 메서드
void carSpeed(double ... speeds) {
        for(double v : speeds) {
            System.out.println("v = " + v);
        }
}
  • main Class 코드
public class Main {
    public static void main(String[] args) {
        Car car = new Car();

        System.out.println("밟기 전 car.gear = " + car.gear);
        double speed = car.gasPedal(100, 'D');
        System.out.println("speed = " + speed); // 100.0 출력

        System.out.println("밟은 후 car.gear = " + car.gear); // D 출력

        car.carSpeed(100, 80);
        System.out.println();
        car.carSpeed(110, 120, 150); // 하나씩 출력
    }
}
  • 메서드 오버로딩
    • 한 클래스 내에 이미 사용하려는 이름과 같은 이름을 가진 메서드가 있더라도, 매개변수의 개수 또는 타입, 순서가 다르면 동일한 이름을 사용해서 메서드를 정의할 수 있음
    • 조건
      • 메서드의 이름이 같고, 매개변수의 개수 or 타입 or 순서가 달라야 함

      • 오버 로딩은 매개변수의 차이로만 구현할 수 있음

      • 예시 코드

        public void println(boolean x) {
                if (getClass() == PrintStream.class) {
                    writeln(String.valueOf(x));
                } else {
                    synchronized (this) {
                        print(x);
                        newLine();
                    }
                }
            }
        
            public void println(char x) {
                if (getClass() == PrintStream.class) {
                    writeln(String.valueOf(x));
                } else {
                    synchronized (this) {
                        print(x);
                        newLine();
                    }
                }
            }
        
            public void println(int x) {
                if (getClass() == PrintStream.class) {
                    writeln(String.valueOf(x));
                } else {
                    synchronized (this) {
                        print(x);
                        newLine();
                    }
                }
            }
      • 메서드 이름을 절약할 수 있음

      • 기본형 매개 변수 → 읽는 것만 가능

      • 참조형 매개 변수 → 읽고 변경하는 것만 가능

      • 예시 코드 Car Class & Main Class

        
        double brakePedal(char type) {
                speed = 0;
                type = 'P'; // 정지 후 매개변수 type을 어떤 타입으로 전달 받았는지
        										//상관없이 'P'로 고정시키기
                changeGear(type);
                return speed;
            }
        
        //기본형 매개 변수
        				char type = 'D';
                car.brakePedal(type);
        
                // 메서드 실행 완료 후 전달할 매개값으로 지정된 type 값 확인
                System.out.println("type = " + type); // 기존에 선언한 값 'D' 출력,
        																							//원본 값 변경되지 않음
                // 메서드 실행 완료 후 반환된 car 인스턴스의 gear 타입 확인
                System.out.println("gear = " + car.gear); // 객체 내부에서 type을 변경하여
        																									//수정했기 때문에 'P' 출력
        
        Tire setTire(Tire tireCompany) {
                tireCompany.company = "KIA"; // 금호 타이어를 전달 받았지만 강제로
        																		//KIA 타이어로 교체
                tire = tireCompany;
                return tire;
            }
        
        // 참조형 매개 변수
        				Tire tire = new Tire();
                tire.company = "금호"; // 금호 타이어 객체 생성
        
                // 차 객체의 타이어를 등록하는 메서드 호출한 후 반환값으로 차 객체의
        				//타이어 객체 반환
                Tire carInstanceTire = car.setTire(tire);
        
                // 메서드 실행 완료 후 전달할 매개값으로 지정된 참조형 변수 tire의
        				//company 값 확인
                System.out.println("tire.company = " + tire.company); // "KIA" 출력
                // 전달할 매개값으로 지정된 tire 인스턴스의 주소값이 전달되었기 때문에
        				//호출된 메서드에 의해 값이 변경됨.
        
                // 메서드 실행 완료 후 반환된 car 인스턴스의 tire 객체 값이 반환되어 저장된
        				//참조형 변수 carInstanceTire의 company 값 확인
                System.out.println("carInstanceTire.company = " + carInstanceTire.company);
        				// "KIA" 출력
  • 인스턴스 멤버 / 클래스 멤버

    • 멤버 = 필드 + 메서드
      • 인스턴스 멤버 = 인스턴스 필드 + 인스턴스 메서드

      • 클래스 멤버 = 클래스 필드 + 클래스 메서드

      • 선언하는 방법에 따라 인스턴스 멤버인지 클래스 멤버인지 구분

      • 필드와 메서드를 클래스 멤버로 만들기 위해서는 static 키워드를 사용하면 된다.

      • 일반적으로 인스턴스마다 모두 가지고 있을 필요없는 공용적인 데이터를 저장하는 필드는 클래스 멤버로 선언하는 것이 좋다.

      • 또한 인스턴스 필드를 사용하지 않고 실행되는 메서드가 존재한다면 static 키워드를 사용하여 클래스 메서드로 선언하는 것이 좋다.

      • 인스턴스 멤버는 객체 생성 후에 사용 가능 클래스 멤버는 객체 생성 없이도 사용 가능

        [클래스]static String company = "GENESIS"; // 자동차 회사 : GENESIS
        
        [인스턴스]String getCompany() {
            return "(주)" + company;
        }

        → 필드가 클래스 & 메서드가 인스턴스

        [클래스]static String setCompany(String companyName) {
            //[인스턴스] System.out.println("자동차 모델 확인: " + model);
        		// 인스턴스 사용 불가
            company = companyName;
            return company;
        }

        메서드가 클래스 필드가 인스턴스/ model을 static을 붙여서 선언

        위 코드에서 model은 static 선언을 안 해서 사용 불가

        public class Main {
            public static void main(String[] args) {
                // 클래스 필드 company 확인
                System.out.println(Car.company + "\n");
                // 클래스 필드 변경 및 확인
                Car.company = "Audi";
                System.out.println(Car.company + "\n");
        
                // 클래스 메서드 호출
                String companyName = Car.setCompany("Benz");
                System.out.println("companyName = " + companyName);
        
                System.out.println();
                // 참조형 변수 사용
        				// 인스턴스화 안하고 사용이 가능해서 아래와 같이 안하는 것이 좋음
                Car car = new Car(); // 객체 생성
        
                car.company = "Ferrari";
                System.out.println(car.company + "\n");
        
                String companyName2 = car.setCompany("Lamborghini");
                System.out.println("companyName2 = " + companyName2);
            }
        }
  • 지역 변수/final 필드/상수

    • 지역 변수
      • 메서드 내부에 선언한 변수
      • 메서드가 종료될 때까지만 유지
    • final 필드
      • 초기값이 저장되면 해당값을 프로그램 실행하는 도중에는 절대 수정 불가
      • 반드시 초기값 지정
    • 상수
      • 불변의 값
      • static final 로 지정
      • 인스턴스마다 상수를 지정할 필요 없음
      • 일반적으로 대문자로 작성하는 것이 관례
  • 생성자 !!

    • 객체가 생성될 때 호출되며 객체를 초기화하는 역할
    • 클래스를 생성하고 생성자를 안넣어 줘도 기본적으로 생성이 됨
    • 오버로딩 가능
    • this
      • 인스턴스를 의미

      • 무조건 this를 써주는게 좋다.

      • this() → 생성자 의미

        public Car(String model) {
            this.model = model;
            this.color = "Blue";
            this.price = 50000000;
        }
        
        public Car(String model, String color) {
            this.model = model;
            this.color = color;
            this.price = 50000000;
        }
        
        public Car(String model, String color, double price) {
            this.model = model;
            this.color = color;
            this.price = price;
        }
        
        // 같은 의미 코드 중복 제거!!
        
        public Car(String model) { // 맨 아래 생성자로 토스!
            this(model, "Blue", 50000000);
        }
        
        public Car(String model, String color) { // 맨 아래 생성자로 토스!
            this(model, color, 100000000);
        }
        
        public Car(String model, String color, double price) {
            this.model = model;
            this.color = color;
            this.price = price;
        }
  • 접근 제어자

    • 접근 제어자 : public, protected, default, private → 접근을 어디까지 허용할 것인
    • 그 외 제어자 : static, final, abstract
    • 클래스, 멤버변수, 메서드, 생성자에 사용되고, 지정되어 있지 않다면 default 입니다.
      • public : 접근 제한이 전혀 없습니다. *
      • protected : 같은 패키지 내에서, 다른 패키지의 자손 클래스에서 접근이 가능합니다
      • default : 같은 패키지 내에서만 접근이 가능합니다.
      • private : 같은 클래스 내에서만 접근이 가능합니다. *
      • 밑으로 내려갈 수록 허용 범위가 줄어듦
    • 사용가능한 접근 제어자
      • 클래스 : public, default
      • 메서드 & 멤버변수 : public, protected, default, private
      • 지역변수 : 없음
    • 일반적으로 생성자의 접근 제어자는 클래스의 접근 제어자와 일치
      • Getter 와 Setter
        • 객체의 무결성 즉, 변경이 없는 상태를 유지하기 위해 접근 제어자를 사용한다.
          • 이때 외부에서 필드에 직접 접근하는 것을 막기 위해 필드에 private, default 등의 접근 제어자를 사용할 수 있다.
          • 그렇다면 우리는 어떻게 객체의 private 필드를 읽어오거나 저장할 수 있을까?
          • 우리는 Getter 와 Setter 를 사용하여 이를 해결할 수 있다.
        • 캡슐화를 생각!!
        • 직접적으로 값의 조회/세팅을 방지하기 위한 방법
        • Getter
          • 정말 내보내야 할 정보만 내보낼 때 사용
            • 외부에서 객체의 private한 필드를 읽을 필요가 있을 때
        • Setter
          • 정보를 정합성이 안 맞게 저장/수정을 방지하기 위해 사용
            • 외부에서 객체의 private한 필드를 저장/수정할 필요가 있을 때
  • package와 import

    • 클래스의 일부분이며, 하위 패키지를 도트(.)로 구분한다.
  • 상속

    • 클래스 간의 관계와 상속
      • 상속을 사용하면 코드의 중복이 제거되고 재사용성이 크게 증가하여 생산성과 유지보수성에 매우 유리
    • extends 사용
      • 부모 클래스에 새로운 필드와 메서드가 추가되면 자식 클래스는 이를 상속받아 사용할 수 있다.
      • 자식 클래스에 새로운 필드와 메서드가 추가되어도 부모 클래스는 어떠한 영향도 받지 않는다.
      • 따라서 자식 클래스의 멤버 개수는 부모 클래스보다 항상 같거나 많다.
      • 부모 클래스가 자식 클래스보다 큰 범위는 아님!!! 자식 클래스 범위가 부모 클래스 범위와 같거나 더 크다!!
      • 부모가 가진 필드 & 메서드에서 확장된 개념
    • 상속 관계 → 자식 클래스 is 부모 클래스
    • 포함 관계 → has
    • JAVA는 다중 상속을 허용하지 않는다.
  • final 클래스 & final 메서드

    • final을 선언하면 최종적인 클래스가 됨으로 더 이상 상속할 수 없는 클래스가 된다.
  • Object 클래스

    • 최상위 클래스 → 모든 클래스가 사용 가능
    • Object clone() : 해당 객체의 복제본을 생성하여 반환함.
    • boolean equals(Object object) : 해당 객체와 전달받은 객체가 같은지 여부를 반환함.
    • Class getClass() : 해당 객체의 클래스 타입을 반환함.
    • int hashCode() : 자바에서 객체를 식별하는 정수값인 해시 코드를 반환함.
    • String toString() : 해당 객체의 정보를 문자열
      로 반환함. & Object 클래스에서는 클래스이름 @해쉬코드값 리턴함.
  • 오버 라이딩

    • 부모 클래스로부터 상속받은 메서드의 내용을 재정의 하는 것
    • @Override → 부모 클래스의 메서드를 자식 클래스에서 재정의 할 때 사용
      • @ : 애노테이션
    • super, super()
      • super : 자식 클래스에서 부모 클래스 멤버에 접근할 때 사용

        // 부모 클래스 Car
        String model; // 자동차 모델
        String color; // 자동차 색상
        double price; // 자동차 가격
        
        // 자식 클래스 SportsCar
        String model = "Ferrari"; // 자동차 모델
        String color = "Red"; // 자동차 색상
        double price = 300000000; // 자동차 가격
        
        //자식 클래스의 메서드
        public void setCarInfo(String model, String color, double price) {
            super.model = model; // model은 부모 필드에 set
            super.color = color; // color는 부모 필드에 set
            this.price = price; // price는 자식 필드에 set
        }
      • 자식 클래스의 메서드를 호출하면 super 키워드로 접근한 부모 클래스의 model, color 필드에 매개변수의 값이 저장

      • this 키워드로 접근한 자식 클래스의 price 필드에는 매개변수의 값이 저장

  • 다형성

    • 여러 가지 형태를 가질 수 있는 능력

    • instanceof → 상속 관계 확인 명령어

      Parent p = new Parent();
      
              System.out.println(p instanceof Object); // true 출력
              System.out.println(p instanceof Parent); // true 출력
              System.out.println(p instanceof Child);  // false 출력
      
              Parent c = new Child();
      
              System.out.println(c instanceof Object); // true 출력
              System.out.println(c instanceof Parent); // true 출력
              System.out.println(c instanceof Child);  // true 출력
  • 추상화

    • abstract 키워드를 사용하여 추상 메서드를 선언

    • 추상 메서드는 일반적인 메서드와는 다르게 블록{ }이 없다.

      • 즉, 정의만 할 뿐, 실행 내용은 가지고 있지 않다.

        public abstract class 추상클래스명 {
        		abstract 리턴타입 메서드이름(매개변수, ...);
        }
    • 추상 메서드는 extends 키워드를 사용하여 클래스에서 상속

    • 상속받은 클래스에서 추상 클래스의 추상 메서드는 반드시 오버라이딩 되어야 한다.

      public class 클래스명 extends 추상클래스명 {
      		@Override
          public 리턴타입 메서드이름(매개변수, ...) {
      		       // 실행문
          }
      }
profile
진짜 개발자가 되고 싶다

0개의 댓글