LG CNS AM CAMP 1기/AI 서비스 개발을 위한 백엔드 I

2일차_Java 프로그래밍 언어 기본 문법

solog 2025. 1. 20. 22:58

1주차 자바 기초
- Java 개발 환경 구성
- Java 프로그래밍 언어 기본 문법

 

25.01.10 (금)

강의 책 : 자바/스프링 개발자를 위한 실용주의 프로그래밍 (위키북스, 김우근 저)

아래의 내용은 [LG CNS AM CAMP 1기] 수업을 바탕으로 작성하였습니다.

 

<참조 자료형>

[배열]

- 동일한 자료형을 묶어 저장하는 참조 자료형

- 생성할 때 크기를 지정해야 하고, 한 번 크기를 지정하면 절대 변경할 수 없는 특징이 있음

- 자료형[] 변수명; 또는 자료형 변수명[];

    int[] a;                       int a[];

    String[] b;                 String b[];

 

[1차원 배열의 생성 및 값 대입]

방법1. 배열 객체의 생성 + 값 대입

int[] a = new int[3];

a[0] = 3;

a[1] = 4;

a[2] = 5;

 

방법2. 배열 객체의 생성 및 값 대입

방법3. 대입할 값만 입력

int[] a = { 3, 4, 5 };

 

=> 방법1과 2는 선언과 할당을 분리할 수 있지만, 방법3은 분리할 수 없다.

 

[코드 예시]

package com.test;

import java.util.Arrays;

 

<메모리 초기화>

[스택 메모리]

● 초기값을 부여하지 않는 경우 빈 칸으로 존재

● 읽기 불가능

       int a;

       System.out.println(a); // 오류 발생

 

[힙 메모리]

● 빈 칸으로 존재할 수 없으며, 디폴트 초기값이 강제 설정

● 기본 자료형 ⇒ 숫자 : 0 / boolean : false

● 참조 자료형 ⇒ null

- 배열은 참조자료형이기 때문에 스택메모리에 주소를 가지고 있기 때문에 값이 변하는 것.

 

<배열 데이터를 읽는 방법>

방법1. for 반복문 ⇒ 배열의 크기 만큼 루프를 돌면서 인덱스로 참조

 

방법2. for-each 반복문 ⇒ 루프를 돌면서 배열 데이터를 가져와서 사용

//=> for of 구문과 비슷

 

< main() 메서드의 입력 매개변수 >

public void static main(String[] args)

                                     ~~~~~~~~~~ 프로그램이 실행될 때 입력되는 값 (전달되는 값)

 

< 타입 변환 메서드>

- 문자열 → 정수 ⇒ Integer.parseInt(문자열)

- 문자열 → 실수 ⇒ Double.parseDouble(문자열)

- 정수 → 문자열 ⇒ String.valueOf(정수)

- 실수 → 문자열 ⇒ String.valueOf(실수)

 

<String>

[String 객체 생성 방법]

방법1. new 키워드 사용 (권장)

 

방법2. 문자열 리터럴 이용

String str = "안녕";

 

[String 클래스의 특징]

- 한 번 정의된 문자열은 변경할 수 없다. ⇒ 문자열의 내용을 변경하면 문자열을 수정하는 것이 아니고, 새로운 문자열을 포함하고 있는 객체를 생성해서 사용 (기존 문자열 객체는 버림)

- 문자열 리터럴을 바로 입력해 객체를 생성할 때 같은 문자열끼리는 객체를 공유

⇒ new 키워드를 이용해서 객체를 생성하면 항상 새로운 객체를 생성

⇒ 문자열 리터러로 생성하면 동일한 문자열을 포함하고 있는 객체가 있으면 그 객체를 공유

 

[문자열 + 문자열]

- [문자열 + 기본 자료형] 또는 [기본 자료형 + 문자열] ⇒ 기본 자료형을 문자열로 바꾸서 결합 연산

 

[ String 클래스의 주요 메서드 ]

- 문자열의 실제 내용을 비교하기 위해서는 == 보다는 equals를 사용해야한다.

https://docs.oracle.com/javase/8/docs/api/java/lang/String.html  

 

<클래스>

-  객체(object)는 사용할 수 있는 실체를 의미 ⇐ 붕어빵

-  클래스(class)는 객체를 만들기 위한 설계도 ⇐ 붕어빵 틀

- 하나의 클래스를 이용해서 여러 개의 객체를 만들 수 있음

- 데이터가 임의로 변형되는 것을 막을 수 있다.

- 왼쪽은 절차지향, 오른쪽은 객체지향 flow

- 객체지향은 확장이 쉽다.

 

[자바에서 제공하는 객체지향 문법 요소]

- 인터페이스 : 명세만 존재. 

- 클래스는 실질적인 동작이 구현되는 것. 추상클래스는 동작이 100% 구현되지 않는 것이다.

- 인터페이스는 프로그램을 유연하게 해준다. 두개의 다른 대상을 연결해주는 역할을 한다. 쉽게 연동이 가능해진다.

- 인터페이스의 가장 좋은 예시로 프린터가 있다. 

 

[클래스 구조]

 

[클래스 멤버 = 필드 + 메서드 + 내부 클래스 ]

-  객체를 생성할 때는 new 키워드를 사용

- 클래스명 참조변수명 = new 생성자();

- 생성자는 객체를 사용할 때 사용하는 함수

- 포인트 연산자를 사용하여 메서드와 필드를 접근

- 자바에서는 힙 메모리에 직접 접근을 할 수 없음

- 참조변수명.필드명

  참조변수명.메서드명()

 

[필드 vs 지역변수]

class A {

 int m = 3;  //필드

 int n = 4;

  void work1() {

   int k = 5;  //지역변수

   System.out.println(k);

   work2(3);

     }

   void work2(int i) { //매개변수 = 지역변수

    int j = 4;              // 지역변수

    System.out.println(i + j);

   }

}

- 프레임이라는 단위로 메소드 별로 생김

 

[필드와 지역변수의 초기값]

- 스택메모리는 초기화가 되지 않기 때문에 오류가 발생

- 필드는 기본 값으로 초기화 되고 지역변수는 초기화 되지 않아 오류 발생

 

<메서드>

- 여러 리턴 타입을 메서드는 가질 수 있다.

- 리턴 타입이 void일 때, 메서드 내에서 return을 사용 ⇒ 메서드를 종료한다는 의미

 

[메서드 호출]

1. 클래스 외부에서 메서드 호출 ⇒ 참조변수를 이용해서 메서드를 호출 ⇐ 객체를 먼저 생성

2. 클래스 내부에서 메서드 호출 ⇒ 객체를 생성하지 않고 호출이 가능 (단, static이 붙어 있는 메서드는 static이 붙어 있는 필드 또는 메서드만 호출이 가능)

- 해당 클래스 내에서는 호출이 자유롭지만, 외부에서는 인스턴스를 만들어서 호출해야한다.

 

[입력 매개변수가 배열인 메서드를 호출]

- printArray({1,2,3})은 정의와 호출을 분리할 수 없기 때문에 불가능하다.

- 기본 자료형을 매개변수의 값으로 전달하는 경우, 값을 복사해서 사용한다.

-  기본자료형의 경우 스택의 값을 복사해서 넘겨서 main frame의 값은 변경되지 않는다.

- 참조자료형의 경우 주소를 가리키게 돼므로, 4,5,6의 값으로 바뀌면 array의 값도 바뀌게 되는 것이다.

 

※ 참고: 관련된 보안약점

● public 메서드로부터 반환된 private 배열 ⇒ getter 메서드를 잘못 구현했을 때 발생

● private 배열에 public 데이터 할당 ⇒ setter 메서드를 잘못 구현했을 때 발생

 

=> 주소가 반환되어 private한 데이터도 외부에서 변경이 가능하게 됌 (보안약점)

 

[메서드 오버로딩]

- 메서드 시그니처(method signature) = 메서드명 + 매개변수의 자료형 ⇐ 메서드를 구부하는 기분

- 메서드 오버로딩 ⇒ 매개변수의 개수나 자료형이 다른 여러 개의 동일한 이름을 지닌 메서드를 같은 공간에 정의

                            ⇒ return 타입은 포함되지 않는다.

 

ex. 가변 길이 배열 데이터를 매개변수로 받는 메서드

- 가변길이를 사용할 때는 ... 을 사용한다.

<클래스 내부 구성 요소 - 생성자 >

- 객체 생성에 사용

- 필드 초기화에 사용

- 클래스 이름과 동일한 이름을 가지고, 리턴 타입이 없음 (반환값이 없음)

- 기본 생성자 ⇒ 생성자를 포함하지 않은 클래스에서 컴파일러가 자동으로 추가하는 생성자 (기본 생성자는 매개변수가 없고 생성자 본문이 비어 있음)

- 기본생성자는 컴파일러가 생성해준다.

 

- this 키워드 ⇒ 자신이 포함된 클래스의 객체를 가리키는 참조 변수

                    ⇒ 명시적으로 매개변수의 이름과 필드의 이름이 같을 때 사용한다.

                    ⇒ this를 생랼하여도 컴파일러가 자동으로 this를 추가한다.

 

- this() 메서드

⇒ 자신이 속한 클래스 내부의 다른 생성자를 호출 ⇒ 생성자 내부에서만 사용할 수 있고, 생성자의 첫 줄에 위치해야 함

⇒ this() 메서드는 코드의 중복을 줄일 수 있다.

 

< 클래스 외부 구성 요소 - 패키지(package) >

- 동일한 목적으로 만들어진 클래스들을 묶어(동일한 공간(폴더)) 관리하는 것 ⇒ 클래스명의 충돌을 방지 ⇒ 클래스의 풀네임(full name) ⇒ 패키지명.클래스명

- 다른 클래스와 구분하기 위함

 

< 클래스 외부 구성 요소 - 외부 클래스(external class) >

- public 클래스 외부에 정의한 클래스

- 외부 클래스는 같은 패키지 안에서만 사용할 수 있음 ⇐ default 접근 지정자를 가지는 클래스

 

< 접근 지정자 >

- 자바 제어자의 한 종류로, 클래스, 멤버(필드, 메서드, 인너 클래스), 생성자 앞에 위치

- 사용 범위를 정의

- 멤버 및 생성자의 접근 지정자 ⇒ public, protected, default(=package), private

- 필드는 private, 메소드는 public, 외부에서 사용할 수 없는 메소드는 private를 주로 사용한다.

- 클래스의 접근 지정자 ⇒ public, default

                                                   ~~~~~~~ 같은 패키지 내에서만 사용이 가능

- public은 다른 클래스에서 접근해서 사용할 수 있다.

- public이 아닌 defualt 클래스를 참조하려고하면 불가능하다.

 

< static 제어자 >

- 클래스 멤버(필드, 메서드, 이너 클래스)에 사용하는 제어자

- static이 붙어 있는 멤버 ⇒ 정적 멤버(static member) ⇒ 객체 생성 없이 "클래스명.멤버명"으로 사용이 가능

- static이 붙어 있지 않은 멤버 ⇒ 인스턴스 멤버(instance member) ⇒ "참조변수명.멤버명"

⇒ 정적 필드는 객체 간 고유 변수의 성격을 가짐

- static 변수는 클래스 영역 안에 별도의 공간이 만들어져 그곳에 값이 들어간다.

- 모든 클래스의 인스턴스에 동일한 값이나 규칙이 적용되어야 할 때 static을 사용한다.

 

[인스턴스 메서드와 정적 메서드]

- 정적 메서드 내에서는 정적 필드 또는 정적 메서드만 사용이 가능

- this 키워드를 사용할 수 없음 (this는 인스턴스가 있어야 사용가능하기 때문)

 

<정적 필드의 초기화 할때>

- 정적 초기화 블록 ⇒ 정적 필드를 초기화하기 위한 문법

<static main() 메서드>

 

<상속>

- 오늘 배운 것 중 가장 중요 ★ ★ ★

- UML 표현법

 

[장점]

장점1. 코드의 중복을 제거

장점2. 다형적 표현이 가능 ⇒ 다형성(polymorphism) : 객체를 여러 가지 모양으로 표현할 수 있는 특징

- extends로 상속을 표현한다.

- fruit를 정의하면 상속받은 과일들이 모두 들어올 수 있다. (따로따로 정의해야하는 것들이)

 

- 자바의 클래스는 다중 상속이 불가능 ⇒ class 자식클래스 extends 부모1클래스, 부모2클래스 { ... } (X)

- 클래스가 아니면 가능하다. (인터페이스는 다중 상속 가능)

- 부모를 먼저 만들고 다음에 자식 클래스를 만든다.

- 상속을 수행할 때 클래스의 내부 구성 요소 중에선 멤버(필드, 메서드, 이너 클래스)만 상속되고, 생성자는 상속되지 않음

[기본 자료형]

- 등호를 중심으로 데이터 타입이 일치되어야 한다. (왼쪽 = 오른쪽)

- 일치 되지 않으면 자동으로 형변환 되거나, 수동으로 바꿔주어야 한다.

- 객체에서 자식 클래스에서 부모 클래스 쪽으로 변환되는 것 업 캐스팅이라고 하고, 그 반대를 다운 캐스팅이라고 함

- 업 캐스팅은 명시적으로 하지 않아도 컴파일러가 자동으로 수행

- 다운 캐스팅은 개발자가 명시적으로 수행

- C가 만들어지지 않았기 떄문에 참조를 할 수 없다. 그렇기 때문에 불가능한 것 (힙메모리에서 C객체 찾을 수 없기 때문)

- B의 객체를 A 타입으로 선언했을 때 자식이 가지고 있는 것은 쓸수가 없다. 

- 밖의 자식의 것을 쓰기 위해서는 캐스팅을 해야한다.

   ex. B b = (B) a;

         System.out.printlln(b.n);

         b.bcd 

위와 같이 캐스팅을 해야 사용할 수 있다.

- 그렇다면 캐스팅 가능여부를 확인 할 수 있어야 한다. 

- 캐스팅 가능 여부를 확인 ⇒ instanceof 키워드

- 안전한 캐스팅을 하기 위해서는 instanceof를 이용해 캐스팅 여부 확인하고 다운캐스팅 해야한다.

 

※ 사용법

참조변수 instanceof 타입

⇒ true 캐스팅 가능

⇒ false 캐스팅 불가능

 

- 상속을 받는 이유는 다형성을 위해 받는 것이다.

- 그렇다면 데이터를 쉽게 관리 할 수 있다.

- 부모를 정의하면 자식들의 데이터를 여러가지 구현할 수 있어 데이터를 유연하게 받을 수 있다.

- 데이터를 사용하기 위해서는 캐스팅이 필요한데, 이때 필요한 것이 instanceof이다.

<메서드 오버라이딩(method overriding) >

- 부모 클래스에서 상속받은 메서드와 동일한 이름의 메서드를 재정의하는 것

- 부모 메서드를 자신이 만든 메서드로 덮어쓰는 개념

- 부모 클래스의 메서드와 시그니처와 리턴 타입이 동일해야 함

- 부모 클래스의 메서드다 접근 지정자의 범위가 같거나 넓어야 함 (public -> public)

- 오버라이딩 된 것을 명시적으로 알려주기 위해서 @Override 라고 사용한다. (annotation : 컴파일러에게 알려줌)

- A a b = n e w B ( ) ; a b . p r i n t ( ) ; / / B 클 래 스 

- 오버라이딩 된 메소드가 호출된다. (다형성을 구현하는데 꼭 필요한 개념)

- 부모는 구조를 정의하고, 구현은 오버라이드 하도록 한 후 자식에서 만든 것을 내가 만든 것을 특정 시점에 구현할 수 있게 함 (캐스팅을 하지 않아도)