본문 바로가기
CS 면접준비

Java

by 코도꼬마 2023. 8. 23.

1. 인스턴스 변수, 전역 변수(클래스 변수), 지역 변수의 정의와 차이

      # 클래스 변수와 인스턴스 변수는 멤버변수라고도 함

  • 인스턴스 변수
    • 객체지향 프로그래밍에서 사용
    • 클래스 내부의 멤버 변수로 선언하여 사용
    • 클래스의 생성자를 통해 초기화 되고 해당 클래스의 모든 인스턴스에서 사용가능
    • 객체 생성 없이는 사용 불가능
    • 인스턴스 마다 서로 다른 값을 가질 수 있음
    • 인스턴스마다 독립적으로 존재하며 객체의 상태를 나타내는 데 사용
public class MyClass {
    int instanceVariable; // 인스턴스 변수 선언
    
    public MyClass(int value) {
        instanceVariable = value; // 생성자를 통해 인스턴스 변수 초기화
    }
}

 

  • 전역 변수(클래스 변수)
    • java에서는 엄밀히 따지자면 전역변수가 없음. static을 사용하여 정의한 멤버변수를 해당 클래스의 모든 인스턴스에 공유되는 변수로 간주할 수 있음
    • 프로그램 전체에서 접근 가능
    • 객체 생성 없이 사용가능 하고, 프로그램이 시작될 때 생성되어 종료될 때까지 유지됨
    • 전역변수를 많이 사용할 경우 프로그램이 복잡해지고 디버깅이 어려움
    • 프로그램 전체에서 접근 가능하며 주로 공유 데이터를 저장하기 위해 사용
public class MyClass {
    static int globalVariable; // 클래스 변수 선언
    
    public static void main(String[] args) {
        globalVariable = 10; // 클래스 변수에 값 할당
    }
}

 

  • 지역 변수
    • 변수가 선어된 블록이나 함수 내에서만 접근 가능
    • 해당 블록이나 함수의 실행이 완료되면 소멸됨
    • 변수가 선언된 블록이나 함수 내에서만 접근 가능하며 임시 데이터를 저장하는 데 사용
public class MyClass {
    public void myMethod() {
        int localVar = 5; // 로컬 변수 선언
        
        if (localVar == 5) {
            int innerVar = 10; // 중첩된 블록 내의 로컬 변수 선언
        }
        
        // localVar는 여기서는 접근 가능하지만 innerVar는 접근 불가능
    }
}


1-1. 각각의 변수가 저장되는 위치

  • 인스턴스 변수
    • 객체가 생성될 때 Heap 메모리 영역에 저장
    • 각 객체마다 독립적으로 메모리를 할당받고, 객체의 상태를 나타내는 데이터 저장됨
    • 객체의 생명주기 동안 유지되며, 객체가 더 이상 참조되지 않을 때 소멸됨

 

  • 전역 변수(클래스 변수)
    • 클래스의 static 멤버 변수로서 클래스의 정적 데이터 영역(static data area)에 저장
    • 프로그램이 실행되면서 클래스의 정적 변수들이 초기화되고 프로그램 종료 시까지 유지됨

 

  • 지역 변수
    • 해당 블록이나 메서드가 실행될 때 메모리의 스택(Stack) 영역에 저장
    • 스택은 메서드 호출 시 생성되는 지역 변수와 임시 데이터를 저장하는 데 사용되며, 메서드의 실행이 종료되면 해당 스택 프레임과 함께 로컬 변수도 소멸됨



2. Inner Class(내부 클래스)의 장점

    # 하나의 클래스 내부에 선언된 또 다른 클래스
    # 외부 클래스(outer class)와 긴밀한 관계를 맺고 있을 때 선언할 수 있음

 

  • 캡슐화와 은닉성 강화
    • 내부 클래스는 외부 클래스의 멤버에 쉽게 접근할 수 있음
    • 이로 인해 관련된 클래스와 데이터를 더 쉽게 캡슐화하고, 내부 클래스의 세부 구현을 외부로부터 숨길 수 있음

 

  • 모듈화
    • 내부 클래스는 외부 클래스와 논리적으로 밀접한 관계를 가질 때 유용
    • 외부 클래스와 내부 클래스 간에는 더 높은 결합도와 더 낮은 응집도를 유지할 수 있음
    • 이는 클래스 간의 관련성을 강화하고, 코드를 모듈화하여 관리하기 쉽게 만들어 줌

 

  • 코드의 가독성 향상
    • 내부 클래스를 사용하면 관련된 코드를 논리적으로 그룹화할 수 있어 코드의 가독성을 향상시킬 수 있음
    • 관련 있는 클래스를 그룹화하여 코드의 복잡성을 줄일 수 있음
  •  

 


3. 배열과 리스트의 차이

  배열 리스트
크기 - 생성할 때 크기 지정. 크기를 변경할 수 없음
- 배열의 크기를 변경하려면 새로운 배열을 생성하고 기존 데이터를 복사해야함
- 동적으로 크기 조절 가능
- 제한없이 원소 추가, 제거 가능
데이터 타입 - 동일한 데이터 타입의 원소만 저장할 수 있음 - 다양한 데이터 타입의 원소를 저장할 수 있음
  (but 타입 안정성이 감소하고 런타임 에러의 가능성이 높아 사용지양)
- 자바의 제네릭을 사용하여 타입 안정성 유지
메모리 할당 - 일반적으로 연속된 메모리 공간에 원소들을 저장 - 각 원소는 다음 원소의 위치를 가리키는 방식으로 저장
접근 방식 - 인덱스를 통해 원소에 접근할 수 있음
- 접근 속도가 빠름
- 처음부터 순차적으로 접근해야함
- 배열보다 접근 속도가 느릴 수 있음
기능 및 연산 - 주어진 크기의 고정된 원소를 관리하는 간단한 구조
- 특별한 메서드나 연산을 제공하지 않음
- 원소의 추가, 삭제, 검색 등 다양한 연산을 위한 메서드 제공 (예: ArrayList, LinkedList 등)
구현과 사용
- 언어의 기본 자료구조로서 지원
- 선언 후 바로 사용 가능
- 언어에 따라 다양한 형태의 리스트가 구현될 수 있음
- 표준 라이브러리나 외부 라이브러리를 통해 사용 가능

  # 데이터 크기가 고정되어 있고 빠른 접근이 필요한 경우에는 배열을 사용하고, 
      데이터 크기가 동적으로 변하며 다양한 연산이 필요한 경우에는 리스트를 사용

 


3-1. 동적 할당이 필요한 경우

         # 정적할당 시 stac 영역에 저장되고, 동적할당 시 heap 영역에 저장됨

  • stac 영역
    • 컴파일 되며 크기가 결정됨
    • 지역변수, 매개변수, 반환값 등이 저장됨
    • 함수가 호출된 때 생겨나고 종료 시 사라짐
    • 다른 함수나 스레드의 값들을 참조할 수 없음
    • 선입후출 방식

 

  • heap 영역
    • 런타임에 크기가 결정됨
    • heap 영역에 저장하는 경우
      • 데이터 배열의 크기가 일정하지 않거나 변동이 있을 때
      • 프로그램 전반에서 해당 주소를 참조해야하는 경우
    • 모든 스레드에서 값을 공유
    • 사용이 끝난 메모리는 해제하지 않으면 메모리 누수가 발생하여 cpu를 지연시킬 수 있음
    • 선입선출 방식

 

  • 데이터 크기가 변경될 가능성이 있을 경우
    • 프로그램 실행 중에 데이터 크기가 변경되는 경우 동적 할당이 필요함
    • 예를 들어, 사용자가 입력하는 항목의 개수가 변할 수 있는 경우 배열보다는 ArrayList나 LinkedList와 같은 동적인 데이터 구조를 사용하여 메모리를 효율적으로 활용할 수 있음

  • 동적으로 생성되는 객체
    • 프로그램이 실행 중에 동적으로 객체를 생성해야 할 때 동적 할당이 필요함
    • 예를 들면, 사용자가 요청한 작업에 따라 다른 유형의 객체를 생성해야 할 경우

  • 메모리 효율성
    • 한 번에 모든 데이터의 메모리를 할당하는 것은 비효율적이고 프로그램의 구조나 요구 사항 변경에 대응하기 어려울 수 있음
    • 동적 할당을 사용하면 필요한 메모리만 사용하여 메모리 효율성을 높이고 코드 수정 없이도 프로그램을 확장하거나 변경할 수 있음
    • 예를 들어, 파일의 내용을 읽어와서 처리해야 할 때 모든 내용을 한 번에 메모리에 로드하는 대신 필요한 만큼만 메모리를 할당하면서 작업할 수 있음

  • 재귀적인 데이터 구조
    • 재귀적인 데이터 구조에서는 데이터의 깊이나 수준을 예측하기 어려워 트리나 그래프와 같은 구조에서 노드를 동적으로 추가하거나 제거해야 할 때 동적 할당이 필요함

 

 # ArrayList, LinkedList, HashMap과 같은 자료구조를 활용하여 동적 할당을 수행할 수 있음

 



4. 기본형 형변환, 참조형 형변환의 정의와 차이

  • 기본형 형변환 (Primitive Type Casting)
    • 하나의 기본 데이터 타입을 다른 기본 데이터 타입으로 변환하는 것
    • 기본형 형변환은 값 자체의 변환으로 이루어지며, 주로 작은 크기의 데이터 타입에서 큰 크기의 데이터 타입으로 변환하거나, 데이터의 손실을 감안하고 큰 크기의 데이터 타입에서 작은 크기의 데이터 타입으로 변환할 때 사용
    • 예를 들어, int를 double로 변환하거나 double을 int로 변환하는 것
    • 큰 범위에서 작은 범위로 형변환 시 데이터 손실이 발생할 수 있음

  • 참조형 형변환 (Reference Type Casting)
    • 클래스나 인터페이스와 같은 참조형 데이터 타입 간의 변환
    • 참조형 형변환은 상속 계층이나 인터페이스 구조에 따라 이루어짐
    • 이러한 형변환은 실제 객체의 형태나 내용을 변경하는 것이 아니라, 참조 변수의 타입을 변환하는 것임. 참조형 형변환은 다형성을 활용하여 다른 클래스들 간에 상호 작용을 편리하게 할 수 있도록 도와줌
    • 업캐스팅(Upcasting)
      • 두 클래스가 부모-자식 관계에 있을 때, 자식 클래스의 인스턴스를 부모 클래스의 참조 변수로 가리킬 수 있음
      • 이 경우 명시적으로 타입 캐스팅을 하지 않아도 자동으로 처리
    • 다운캐스팅(Downcasting) 
      • 부모 클래스의 참조 변수를 자식 클래스의 인스턴스로 가리키는 것
      • 이 경우 명시적인 타입 캐스팅이 필요

 


4-1. 기본형과 참조형 변수의 차이

  기본형 변수 참조형 변수
데이터 저장 방식 실제 값을 변수에 저장 실제 값의 메모리 위치(참조)를 변수에 저장
메모리 사용 메모리 사용이 적음 메모리 사용이 많으나 GC를 통해 메모리 관리 가능
종류 int, double, char, boolean 등 - 클래스, 인터페이스, 배열 등과 같이 객체나 데이터의 구조를 나타내는 데이터 유형
- String, 사용자 정의 클래스, 배열 등
Null 불가능 가능
메서드 호출 시 - 해당 변수에 저장된 값이 메서드로 전달
- 메서드 내에서 변수 값이 변경되어도 호출자에게 영향을 미치지 않음
- 해당 변수가 가리키는 객체의 참조(메모리 위치)가 메서드로 전달
- 메서드 내에서 객체의 내용이 변경될 수 있고, 이는 호출자에게 영향을 미칠 수 있음




5. 추상화, 다형성, 상속의 개념 및 예시 코드

  • 추상화 (Abstraction)
    • 복잡한 현실 세계를 단순화하여 중요한 특징을 강조하는 것( ex) 약도)
    • 객체의 공통적인 속성과 기능을 추출하여 정의하는것
    • 어떤 객체가 수행해야 하는 핵심적인 역할만을 규정해두고, 실제적인 구현은 해당 인터페이스를 구현하는 각각의 객체들에서 하도록 함
    • 추상화를 통해 프로그램의 복잡성을 감소시키고 필요한 정보만을 남겨 더 효율적으로 다룰 수 있음

  • 다형성 (Polymorphism)
    • 같은 이름의 메서드나 연산자가 다양한 형태로 작동할 수 있는 능력
    • 메서드 오버로딩과 메서드 오버라이딩을 통해 구현됨
    • 다형성을 통해 코드 재사용성이 높아지며, 객체의 다양한 유형을 하나의 일반적인 인터페이스로 다룰 수 있음
    • 상위 클래스 타입의 참조변수로 하위 클래스의 객체를 참조할 수 있도록 하는 것

  • 상속 (Inheritance)
    • 하위 클래스(subclass)가 상위 클래스(superclass)의 특성과 동작을 상속받아 사용하는 것
    • 상속을 통해 클래스 간에 계층 구조를 형성하여 공통된 코드를 재사용할 수 있으며, 다형성을 구현하는 기반이 됨

 

// 추상화 예시: 추상 동물 클래스
abstract class Animal {
    String name;

    Animal(String name) {
        this.name = name;
    }

    abstract void makeSound(); // 추상 메서드, 하위 클래스에서 구현 필요
}

class Dog extends Animal {
    Dog(String name) {
        super(name);
    }

    @Override
    void makeSound() {
        System.out.println(name + " barks");
    }
}

class Cat extends Animal {
    Cat(String name) {
        super(name);
    }

    @Override
    void makeSound() {
        System.out.println(name + " meows");
    }
}

// 다형성과 상속을 활용한 메서드 호출
public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog("Buddy");
        Animal cat = new Cat("Whiskers");

        animalMakeSound(dog); // 다형성을 통해 메서드 호출
        animalMakeSound(cat);
    }

    static void animalMakeSound(Animal animal) {
        animal.makeSound(); // 다형성으로 실제 객체의 메서드 호출
    }
}




6. 오버라이딩, 오버로딩의 개념과 차이

  • 오버라이딩(Overrriding)
    • 부모 클래스에게 상속받은 메서드를 재정의 하는 것
    • 부모 매서드와 이름, 매개변수, 반환타입이 같아야 함
    • 접근제어자는 부모클래스 보다 좁은 범위로 변경할 수 없음
    • 부모 클래스의 메서드 보다 많은 수의 예외를 선언할 수 없음

 

  • 오버로딩(Overloading) 
    • 이름은 같지만 기존에 없던 새로운 기능의 메서드를 새로 정의하는 것
    • 하나의 클래스 안에 같은 이름의 메서드를 여러개 선언
    • 다만 조건이 있음. 매개변수의 갯수나 데이터 타입이 달라야함
    • 예시)
      • println 메서드 : 오버로딩 하지 않고 사용하려면 매개변수의 데이터 타입마다 매서드 명이 달라야함
      • 계산기 : 연산을 수행하려면 대입될 수 있는 매개변수의 모든 데이터 타입에 따라 메서드를 생성해야 함

 



7. 추상클래스, 인터페이스의 개념과 차이

  • 추상 클래스 (Abstract Class)
    • 하나 이상의 추상 메서드를 포함하는 클래스
    • 추상 메서드는 선언만 되어 있고 구현 내용이 없기 때문에 하위 클래스에서 반드시 구현해야함
    • 모든 추상 메서드를 구현하지 않는 경우 추상클래스로 간주
    • 추상 클래스는 추상 메서드 뿐만 아니라 일반적인 멤버 변수와 메서드도 포함 가능
    • 추상 클래스는 인스턴스화할 수 없음. 즉, 추상 클래스로 직접 객체를 생성할 수 없음. 추상 클래스를 상속은 하위 클래스에서 추상 메서드를 구현하여 객체를 생성해야함
    • abstract 키워드를 사용하여 정의
    • 접근 제어자의 제한이 없음

 

  • 인터페이스 (Interface)
    • 추상 메서드로만 구성되어 있고 클래스가 특정한 동작을 수행할 수 있도록 규격을 정의하는 역할
    • 인터페이스를 구현하는 클래스는 인터페이스의 모든 추상 메서드를 반드시 구현해야함
    • 모든 추상 메서드를 구현하지 않는 경우 인터페이스로 간주
    • 인스턴스화 불가능. 하위 클래스에서도 불가능 하나 익명객체 사용하여 가능
    •  implements 키워드를 사용하여 정의
    • 접근 제어자는 public만 가능함

 

  • 차이점
    • 추상 클래스는 상속 관계를 통해 코드의 중복을 방지하고 확장하기 위해 사용하고, 인터페이스는 클래스 간에 공통된 동작을 보장하기 위해 사용
    • 추상 클래스는 단일 상속만 가능 / 인터페이스는 다중 구현이 가능
    • 추상 클래스는 구현 코드와 추상 메서드를 함께 포함할 수 있음 / 인터페이스는 Java 8 이전에 추상 메서드만을 가질 수 있었으나 Java 8부터는 디폴트, 정적 메서드 사용 가능
    • 추상 클래스의 경우 하위 클래스는 상위 클래스의 멤버 변수와 메서드를 직접 사용할 수 있음 / 인터페이스는 상수와 메서드 시그니처만을 제공하며, 실제 구현은 클래스에서 이루어짐
    • 추상 클래스와 인터페이스를 혼합하여 사용할 수 있음

 




8. 동기화, 비동기화의 개념과 차이

  • 동기화 (Synchronization)
    • 여러 개의 작업이나 스레드가 동시에 실행될 때, 공유 데이터나 리소스에 대한 접근을 조절하여 데이터 일관성과 정확성을 유지하는 것
    • 동기화를 통해 한 작업이 공유 데이터를 변경하는 동안 다른 작업이 이를 읽거나 수정하지 못하도록 보호할 수 있음

    • 동기화의 목적
      • 경쟁 조건 (Race Condition) 방지 : 여러 개의 작업이 동시에 공유 데이터에 접근하면서 예측할 수 없는 결과가 발생하는 문제를 방지
      • 데이터 일관성 유지 : 공유 데이터의 변경과 관련된 작업들이 순차적으로 실행되어 데이터 일관성을 유지

 

  • 비동기화 (Asynchronization) 
    • 여러 작업이 순차적으로 실행되는 대신, 각 작업이 독립적으로 실행되고 완료 여부를 기다리지 않고 다음 작업을 시작
    • 비동기 프로그래밍은 주로 비동기 이벤트 핸들링, 멀티스레드 환경, 네트워크 통신 등에서 사용

    • 비동기화의 특징
      • 작업 간 독립성 : 각 작업은 다른 작업에 영향을 미치지 않고 별도로 실행
      • 작업 큐 및 콜백 : 작업은 큐에 추가되어 순차적으로 실행되며, 작업이 완료되면 콜백 함수를 호출하여 결과를 처리

 

  • 차이점
    • 동기화는 작업이 순차적으로 실행되도록 조절하여 데이터의 일관성을 유지 / 비동기화는 작업이 병렬 또는 별개의 스레드에서 독립적으로 실행되며, 작업 간 상호작용이 필요할 때 콜백 등을 활용하여 처리
    • 동기화는 여러 스레드나 작업 간의 실행을 조절하는 방식이므로 상대적으로 더 많은 리소스와 오버헤드가 발생할 수 있음 / 비동기화는 병렬 실행과 작업 분산으로 인해 효율성이 증가
    • 동기화는 복잡한 상호작용과 데이터 일관성을 필요로 하는 경우에 적합 / 비동기화는 작업 간 독립성이 중요하거나, 대기 시간을 최소화하려는 경우에 적합
    • ex) 웹 애플리케이션에서 사용자의 요청을 처리할 때 동기화된 방식으로 데이터베이스에 접근하여 데이터 일관성을 유지할 수 있음 /  웹 애플리케이션에서 비동기적으로 이미지 업로드나 이메일 발송과 같은 작업을 처리하면 응답 시간을 단축시킬 수 있음

'CS 면접준비' 카테고리의 다른 글

Network  (1) 2023.10.01
DB  (0) 2023.09.20
SPRING  (0) 2023.09.13
JAVA  (1) 2023.09.12
Sevlet  (0) 2023.08.27