Chapter 05 | 참조 타입
5.1) 데이터 타입 분류
- 기본 타입 : 변수의 값 자체를 저장 (정수, 실수, 논리)
- 참조 타입 : *객체의 번지를 참조 (배열, 열거, 클래스, 인터페이스)
*객체(Object) : 데이터(필드) + 메소드
5.2) 메모리 사용 영역
- JVM이 구동되면 JVM은 OS에서 할당 받은 메모리 영역(Runtime Data Area)을 구분해서 사용
- 메소드 영역 : 바이트코드 파일의 내용이 저장되는 영역
- 힙 영역 : 객체가 생성되는 영역. 메소드 영역, 스택 영역의 상수와 변수에서 참조
- 스택 영역 : 메소드를 호출할 때마다 생성되는 프레임이 저장되는 영역
- 프레임 : 메소드 호출이 끝나면 제거됨. 내부에 로컬 변수 스택이 있음
- 로컬 변수 스택 : 기본 타입 변수와 참조 타입 변수가 생성되고 제거 됨
5.3) 참조 타입 변수의 ==, != 연산
int arr1[] = new int[] {1,2,3};
int arr2[] = new int[] {1,2,3};
int arr3[] = arr1[];
System.out.println(arr1 == arr2);
>> false
System.out.println(arr1 == arr3);
>> true
- 참조 타입 변수의 값은 객체의 번지
- ==, != 연산자는 번지를 비교하게 됨
- 번지가 같다면 동일한 객체 참조, 다르면 다른 객체 참조
5.4) null과 NullPointerException
- 참조 타입 변수는 null 값을 가질 수 있음
- null로 초기화된 참조 변수는 스택 영역에 생성됨
- NullPointException : 변수가 null인 상태에서 객체의 데이터나 메소드를 사용하려 하면 발생하는 예외
5.5) 문자열(String) 타입
// String 객체의 비교
String str1 = new String("Hello"); // heap 100
String str2 = new String("Hello"); // heap 200
String str3 = ("Hello"); // heap 300
String str4 = ("Hello"); // heap 300
// ==
System.out.println(str1 == str2); >>false
System.out.println(str3 == str4); >>true
System.out.println(str1 == str4); >>false
// equals()
System.out.println(str1.equals(str2)); >>true
System.out.println(str3.equals(str4)); >>true
System.out.println(str1.equals(str4)); >>true
- 변수에 문자열 literal이 대입되면 String 객체로 생성되고, 객체의 번지가 각각 대입됨
*literal : 직접 입력된 값, 변수의 값이 변하지 않는 데이터
문자열 비교
boolean result = str1.equals(str2);
문자 추출
char charValue = subject.charAt(3);
문자열 길이
int length = subject.length();
문자열 대체
String newStr = oldStr.replace("자바", "JAVA");
문자열 잘라내기
String firstNum = ssn.substring(0,6);
String secondNum = ssn.substring(7);
문자열 찾기
int index = subject.indexOf("프로그래밍");
분자열 분리
String arr[] = board.split(",");
5.6) 배열(Array) 타입
int[] intArray = new int[5];
int[][] intArray2 = new int[5][5];
5.7) 객체를 참조하는 배열
- ==, != 연산자를 사용하면 배열 항목이 참조하는 객체 비교
- equals() 메소드 사용하면 문자열 비교 가능
5.8) 배열 복사
System.arraycopy(oldStrArr, 0, newStrArry, 0, OldStrArr.length);
// 원본 배열, 원본 배열 복사 인덱스, 새 배열, 새 배열 붙여넣기 시작 인덱스, 복사 항목 수
- 배열은 한번 생성하면 길이를 변경할 수 없음
- 하지만 더 큰 길이의 배열을 새로 만들고 이전 배열로부터 항목들을 복사할 수 있음
- 참조하는 String 객체는 변함이 없음
5.9) 배열 항목 반복을 위한 향상된 for 문
for (int i : intArr) {
System.out.println(i);
}
- 기존 for 문은 heap에 있는 원본 int 항목을 변경
- for eah 문은 heap에 있는 원본 int 항목을 복사한 local 변수 i 변경
5.10) main() 메소드의 String[] 매개변수 용도
public class Main {
public static void main(String[] args) {
}
}
- main 메소드는 stack 영역에 제일 먼저 적재되기 때문에 객체 생성 불가능
- 객체 생성없이 메소드를 사용하려면 static이어야함
- 터미널에서 프로그램 실행 시 String 배열 인자를 받기 위해 사용
5.11) 열거(Enum) 타입
public enum Week {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
- 불변의 항목을 열거할 때 사용 (날짜, 요일, 계절)
- 프로젝트 시 코드로 관리할 것과 enum으로 관리할 것 구분
Chapter 06 | 클래스
6.1) 객체지향 프로그래밍
6.2) 객체와 클래스
6.3) 클래스 선언
6.4) 객체 생성과 클래스 변수
- 라이브러리 클래스 : 실행할 수 없으며 다른 클래스에서 이용
- 실행 클래스 : main() 메소드를 가지고 있는 실행 가능
6.5) 클래스 구성 멤버
6.6) 필드 선언과 사용
필드 선언
필드 사용
6.7) 생성자 선언과 호출
기본 생성자
public class Car {
//기본 생성자 자동추가
public Car () { }
}
- 모든 클래스는 생성자가 한개 존재
- 클래스에 생성자 선언이 없으면 컴파일러는 기본 생성자(Default Constructor) 자동 추가
생성자 선언
public class Car {
//생성자 선언
Car(String model, String color, int maxSpeed) {
}
}
- 객체를 다양하게 초기화할 수 있음
- 생성자 선언을 하면 기본 생성자를 추가하지 않음
필드 초기화
public class Korean {
//필드 선언
String nation = "대한민국";
String name;
String ssn;
//생성자 선언
public Korean(String n, String s) {
name = n;
ssn = s;
}
}
- 객채마다 동일한 값 : 필드 선언 시 초기값 대입
- 객체마다 다른 값 : 생성자에서 필드 초기화
생성자 오버로딩
public class Car {
//필드 선언
String company = "현대자동차"
String model;
String color;
//생성자 선언
Car() {}
Car(String model) {
this.model = model;
}
Car(String model, String color) {
this.model = model;
this.color = color;
}
}
- 매개변수를 달리하는 생성자를 여러 개 선언하는 것
다른 생성자 호출
public class Car {
//필드 선언
String company = "현대자동차"
String model;
String color;
Car(String model) {
this(model, "은색");
}
Car(String model, String color) {
this(model, color);
}
Car(String model, String color) {
this.model = model;
this.color = color;
}
}
- 생성자 오버로딩이 많아질 경우 중복 코드 줄이기 위해 사용
- this. 와 this() 구분할것
6.8) 메소드 선언과 호출
6.9) 인스턴스 멤버
6.10) 정적 멤버
6.11) final 필드와 상수
6.12) 패키지
6.13) 접근 제한자
6.14) Getter와 Setter
6.15) 싱글톤 패턴
Chapter 07 | 상속
7.1) 상속 개념
7.2) 클래스 상속
7.3) 부모 생성자 호출
7.4) 메소드 재정의
메소드 오버라이딩
- 오버라이딩 : 부모 메소드가 자식클래스에 맞지않게 설계되었을 때, 메소드를 자식 클래스에서 재정의하는 것
- 오버라이딩 되었으면 부모 메소드는 숨겨지고, 자식 메소드 우선 사용 됨
부모 메소드 호출
public class Child extends Parent(){
Child(){
super(); //전체 재정의
super.method1(); //mehtod1 재정의
}
}
- 매소드 재정의 시 부모 메소드의 내용 전부를 자식 메소드도 가지고 있어야 함
- super()와 super.을 이용하여 간편하게 재정의
7.5) final 클래스와 final 메소드
7.6) protected 접근 제한자
7.7) 타입 변환
7.8) 다형성
7.9) 객체 타입 확인
7.10) 추상 클래스
7.11) 봉인된 클래스
Chapter 08 | 인터페이스
8.1) 인터페이스의 역할
- 다형성 구현의 주된 기술
- 두 객체를 연결하는 역할
- 상속보다 공유되는 메소드에 집중
8.2) 인터페이스와 구현 클래스 선언
인터페이스 선언
interface 인터페이스명 { ... } //default 접근 제한
public interface 인터페이스명 { ... } //public 접근 제한
public interface 인터페이스명 {
//인터페이스가 가질 수 있는 멤버
public 상수 필드
public 추상 메소드
public 디폴트 메소드
public 정적 메소드
private 메소드
private 정적 메소드
}
- 물리적 형태는 클래스와 동일하나 선언 방법과 구성 멤버가 다름
- 접근 제한자는 default, public을 붙일 수 있음
구현 클래스 선언
- 객체 A가 인터페이스의 *추상 메소드를 호출
- 인터페이스는 객체 B의 메소드 실행
- 객체 B는 인터페이스에서 선언된 추상 메소드와 동일한 선언부를 가진(재정의된) 메소드를 가지고 있어야 함
- 객체 B는 인터페이스를 구현한(implement) 객체라고 함
- 구현객체는 선언부에 명시해야 함
public interface RemoteControl {
//*추상 메소드 : 선언부만 있고 실행부(중괄호)가 없는 메소드
public void turnOn();
}
public class Television implements RemoteControl {
@Override
public void turnOn() {
System.out.println("Television 켜짐"); //turnOn() 추상 메소드 재정의
}
}
public class Audio implements RemoteControl {
@Override
public void turnOn() {
System.out.println("Audio 켜짐"); //turnOn() 추상 메소드 재정의
}
}
변수 선언과 구현 객체 대입
- 인터페이스도 타입이므로 변수 타입으로 사용할 수 있음
- 참조타입에 속하므로 null 대입 가능
- 인터페이스를 통해 구현객체를 사용하려면 인터페이스 변수에 구현 객체(번지) 대입
- 실제로 실행되는것은 재정의된 메소드
public class User {
public static void main(String[] args){
//변수 타입으로 사용
RemoteControl rc;
RemoteControl rc = null;
rc.turnOn();
//rc 변수에 Television 객체 대입
rc = new Television();
rc.turnOn();
//rc 변수에 Audio 객체 대입(교체)
rc = new Audio();
rc.turnOn();
}
}
8.3) 상수 필드
public interface RemoteControl {
int MAX_VOLUME = 10;
int MIN_VOLUME = 0;
}
public class User {
public static void main(String[] args){
System.out.println(RemoteControl.MAX_VOLUME);
System.out.println(RemoteControl.MIN_VOLUME);
}
}
- 인터페이스에 선언된 필드는 모두 public static final의 특성을 가짐 (생략 가능)
- 상수는 구현 객체가 아니라도 인터페이스로 바로 접근해서 읽을 수 있음
8.4) 추상 메소드
public interface RemoteControl {
void turnOn();
void turnOff();
void setVolume(int volume);
}
public class User {
public static void main(String[] args) {
RemoteControl rc;
rc = new Television();
rc.turnOn();
rc.setVolums(5);
rc.trunOff();
rc = new Audio();
rc.turnOn();
rc.setVolums(5);
rc.trunOff();
}
}
- 추상 메소드는 객체 A가 인터페이스를 통해 어떻게 메소드를 호출할 수 있는지 방법을 알려주는 역할
- 인터페이스 구현 객체 B는 추상 메소드의 실행부는 갖는 재정의된 메소드가 있어야 함
8.5) 디폴트 메소드
public interface RemoteControl {
default void setMute(boolean mute) {
if(mute) {
System.out.println("음소거");
setVolume(MIN_VOLUME);
} else {
System.out.println("음소거 해제");
}
}
}
- 인터페이스는 완전한 실행 코드(중괄호)를 가진 디폴트 메소드 선언 가능
- 클래스 메소드와 선언은 동일하나 default 키워드가 리턴 타입 앞에 붙음
- 디폴트 메소드는 구현 객체가 필요
- 구현 클래스는 디폴트 메소드를 재정의할 수 있지만 public 접근 제한자를 반드시 붙혀야하고 default 키워드를 생략해야 함
8.6) 정적 메소드
public interface RemoteControl {
static void changeBattery() {
System.out.println("리모콘 건전지 교체");
}
}
- 인터페이스에는 정적 메소드 선언 가능
- 추상, 디폴트 메소드와 다르게 구현 객체 없이 인터페이스만으로 호출 가능
- 선언 방법은 클래스 정적 메소드와 동일하나 public을 생략하더라도 자동으로 붙음
- 구현 객체 없이 인터페이스명으로 접근해서 호출 가능
RemoteControl.changeBattery();
8.7) private 메소드
구분 | 구현 객체 | 호출 |
private 메소드 | 구현 객체 필요 | 디폴트 메소드 안에서만 호출 가능 |
private 정적 메소드 | 구현 객체 필요 없음 | 디폴트, 정적 메소드 안에서도 호출 가능 |
- 인터페이스는 외부에서 접근할 수 없는 private 메소드 선언 가능
- 디폴트와 정적 메소드들의 중복 코드를 줄이기 위해서 사용
8.8) 다중 인터페이스 구현
public class 구현클래스명 implements 인터페이스A, 인터페이스B {
//모든 추상 메소드 재정의
}
- 구현 객체는 여러 개의 인터페이스를 implements 가능
- 각각 인터페이스를 통해 구현 객체 사용 가능
- 쉼표로 구분해서 작성하여 모든 인터페이스가 가진 추상 메소드 재정의
8.9) 인터페이스 상속
public interface 자식인터페이스 extends 부모인터페이스1, 부모인터페이스2 { ... }
- 클래스와 달리 다중 상속을 허용
8.10) 타입 변환
자동 타입 변환(promotion)
- 인터페이스 변수 <=(자동 타입 변환)= 구현객체
강제 타입 변환(casting)
- 구현클래스 변수 <=(강제 타입 변환)= (구현클래스) 인터페이스변수
8.11) 다형성
사용 방법은 동일하지만 다양한 결과가 나오는 성질
- 필드의 다형성 : tire1과 tire2 필드에 어떤 타이어 구현 객체가 대입되어도 Car 객체는 타이어 인터페이스에 선언된 메소드만 사용하므로 문제 안됨
- 매개변수의 다형성 : drive() 메소드를 호출할 때 인터페이스 Vehicle을 구현하는 어떠한 객체라도 매개값으로 줄 수있는데, 어떤 객체를 주느냐에 따라 run() 메소드의 실행 결과가 다름. 구현 객체에서 재정의된 run() 메소드의 실행 내용이 다르기 때문
8.12) 객체 타입 확인
public void method(Vehicle vehicle) {
if(vehicle instanceof Bus){
Bus bus = (Bus) vehicle;
//vehicle에 대입된 객체가 Bus일 경우에만 Bus로 강제 타입 변환
}
}
- instanceof 연산자 사용
8.13) 봉인된 인터페이스
public sealed interface InterfaceA permits interfaceB { ... }
- java 15부터 무분별한 자식 인터페이스 생성 방지 위해 생김
- InterfaceA의 자식 인터페이스는 InterfaceB만 가능하고, 이외는 불가능
Chapter 09 | 중첩 선언과 익명 객체
1) 중첩 클래스
- 클래스 안에 또 다른 클래스 정의
- 복잡도가 증가하기 때문에 정적 멤버 클래스 외에는 잘 안씀
2) 정적 클래스
- static 클래스 안에 inner 클래스는 static으로 구현해야한다
3) 익명 객체
- 새로운 클래스를 만들고 정의한 것 처럼 동작하는 객체
- 새로 객체를 생성하는 것보다 간편하게 생성할 수 있음
- 인터페이스도 익명 객체 생성이 가능
- 굳이 이름을 줘서 만들지 않고, 부분에서만 사용할 객체를 만드는 것
Chapter 10 | 라이브러리와 모듈
1) 라이브러리, 모듈
- 생략 (한 번씩 읽어보기)
Chapter 11 | 예외 처리
1)
'LG 유플러스 유레카 > 강의 정리' 카테고리의 다른 글
[알고리즘] Part09 | 시뮬레이션 (1) | 2025.02.18 |
---|---|
[알고리즘] Part08 | 백트래킹 (0) | 2025.02.17 |
[소프트웨어 엔지니어링] Part 01 | 자바 언어의 기초 (0) | 2025.02.01 |