[JAVA]자바 스터디 1주차 정리

bbbbbhyun·2025년 1월 2일
0

JAVA란?

자바는 썬 마이크로시스템즈의 제임스 고슬링(James Gosling)과 연구원들이 개발한 객체 지향 프로그래밍 언어로 1995년에 발표되었다. 처음에는 가전제품에 탑재해 동작하는 프로그램을 만들기 위해 탄생했으나 지금은 웹과 모바일 앱 개발에서 가장 많이 사용하는 언어로 성장했다.

JAVA 특징

  • 객체 지향적이다
    - 객체 지향언어로 상속, 캡슐화, 다형성을 지원
  • 자동 메모리 관리
    - GC(garbage collection)가 자동으로 메모리를 관리해서 참조되지 않은 메모리를 해제해줌
  • 멀티 스레드를 지원한다
    - 멀티 스레드를 지원하면 프로그램 단위가 같은 스레드를 동시에 수행할 수 있다. 자바는 멀티 프로세서 하드웨어를 지원하도록 설계되었으므로 멀티 CPU 시스템에서 효율이 높다.
  • 동적이다
    - 자바는 동적 로딩을 지원함으로써 프로그램 실행 시 모든 클래스가 로딩되지 않고 필요한 시점에 필요한 클래스만을 로딩

JAVA 단점

  • 실행속도가 상대적으로 느리다.
    - jvm위에서 돌아가기때문에 컴파일 언어에 비해 상대적으로 느릴 수 있다.
  • 메모리 사용량이 많습니다.
    - 가비지 컬렉션이 자동으로 메모리를 관리하는 과정에서 오버헤드가 발생할 수 있다.

JVM vs JRE

  • JVM

    JVM은 Java 바이트코드를 실행하는 가상 머신이다. 운영 체제와 무관하게 Java 프로그램이 실행될 수 있도록 하는 핵심 컴포넌트이다.

  • JRE

    JRE는 Java 프로그램을 실행하기 위한 환경이다. JVM을 포함하며, Java 애플리케이션이 실행되기 위해 필요한 라이브러리와 구성 요소를 제공한다.

JAVA 실행과정

  1. 자바 컴파일러가 소스코드를 바이트코드로 변환시킨다.
    • 바이트 코드란?
      • .java 파일을 JVM이 이해할 수 있도록 하는 Bytecode 로 변환하고 .class 파일을 만드는 것을 의미하는데, .class 파일에 존재하는 데이터
  2. 클래스로더가 바이트코드를 JVM의 runtime data area(메모리 영역)로 올린다.
  3. Execution engine의 interpreter와 JIT compiler를 통해 코드를 해석한다.
  • interpreter란?
    • 소스코드를 빌드시에 암것도 하지 않다가, 런타임시에 한줄 한줄 읽어가며 변환
  • JIT compiler 란?
    • 소스코드를 한꺼번에 컴퓨터가 읽을 수 있는 native machine (기계)어로 변환

JAVA 버전별 특징

JAVA version특징
6- interface에 @Override 추가됨
- JDBC 4.0
- Scripting Language Support
- Java Compiler API
- pluggable annotation
8- lambda expression
- type annotation
- stream api 추가
- repeating annotation
- static link library
- interface default method
- unsigned integer 계산
- 날짜와 시간 API(new) -> JodaTime
- rhino 대신 nashorn javascript 엔진 탑재
11- 람다 지역변수 var 키워드 사용 가능
- G1 GC가 기본 GC로 설정 (GC : Garbage Collection)
- 컬렉션, 스트림 등에 메소드 추가
17- recode class 키워드 사용 가능
- 애플 M1 및 이후 프로세서 탑재 제품군에 대한 정식 지원
- 난수 생성 API 추가
- 봉인 클래스(Sealed Class) 정식 추가
- String 여러줄 사용시 텍스트 블록 기능 사용 가능
- NumberFormat,DateTimeFormatter 기능 향상
- Stream.toList() 사용 가능

JAVA 기초

main함수가 static로 선언하는 이유는 ?

static을 사용하여 JVM이 클래스의 인스턴스를 생성하지 않고 바로 main 메소드를 호출하기 위함

public class MainExample {
    public static void main(String[] args) {
        System.out.println("Hello world!");
    }
}

동일성(Identity) vs 동등성(Equality)

  • 동일성이란 두 객체가 같은 메모리 주소를 참조하는지 여부를 확인
    연산자를 사용하여 두 객체의 참조 주소를 비교
String a = new String("Hello");
String b = new String("Hello");

System.out.println(a == b); // false (메모리 주소가 다름)
System.out.println(a.equals(b)); // true (내용이 같음)
  • 동등성이란 두 객체의 내용이 같은지, 즉 객체가 나타내는 값이 같은지를 확인
    .equals() 메서드를 사용하여 객체의 상태(속성 값)를 비교
String a = "Hello";
String b = "Hello";

System.out.println(a == b); // true (리터럴은 같은 메모리를 참조)
System.out.println(a.equals(b)); // true (내용이 같음)

class Person {
    String name;

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

Person p1 = new Person("John");
Person p2 = new Person("John");

System.out.println(p1 == p2); // false (메모리 주소가 다름)
System.out.println(p1.equals(p2)); // true (내용이 같음)

equals() vs hashCode()

  • equals 란 객체의 동등성을 비교하는 메서드
  • hashCode란 Java에서 객체를 고유하게 식별할 수 있는 정수 값을 반환하는 메서드
특징equals()hashCode()
목적객체의 내용(논리적 동등성)을 비교객체를 고유한 정수로 나타내며, 해시 기반 데이터 구조에서 사용
비교 기준객체의 속성 값(내용)을 기준으로 비교객체의 해시코드(정수 값)를 반환
기본 구현Object 클래스에서는 참조 주소 비교Object 클래스에서는 메모리 주소를 기반으로 해시 생성
재정의 필요성동등성을 정의하려면 반드시 재정의 필요equals 재정의 시 반드시 함께 재정의 필요
사용 대상모든 데이터 구조에서 객체 동등성 확인 가능주로 해시 기반 컬렉션(HashMap, HashSet 등)에서 사용
중요한 규칙a.equals(b) == true라면 a.hashCode() == b.hashCode()여야 함같은 hashCode()를 가진 객체라도 equals()는 false일 수 있음
  • equals 재정의 시 반드시 함께 재정의 필요한 이유
  1. hash 값을 사용하는 Collection(HashSet, HashMap, HashTable)을 사용할 때 문제가 발생
  2. equals()를 재정의했지만 hashCode()를 재정의하지 않으면, 논리적으로 같은 객체가 서로 다른 해시코드를 가져서 컬렉션에서 제대로 관리되지 않음

example) hashCode() 정의 안한 경우

import java.util.HashSet;

class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return name.equals(person.name);
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("Alice");
        Person p2 = new Person("Alice");

        HashSet<Person> set = new HashSet<>();
        set.add(p1);
        set.add(p2);

        System.out.println(set.size()); // 출력: 2
    }
}

example) hashCode() 정의 한 경우

import java.util.HashSet;
import java.util.Objects;

class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name); // equals()와 일관된 기준으로 hashCode 생성
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("Alice");
        Person p2 = new Person("Alice");

        HashSet<Person> set = new HashSet<>();
        set.add(p1);
        set.add(p2);

        System.out.println(set.size()); // 출력: 1 
    }
}

toString()

  • 객체가 가지고 있는 정보나 값들을 문자열로 만들어 리턴하는 메소드
  • 기본적으로는 클래스명.객체명@hashcode의 문자열 형태로 출력

@Override 안한 경우

class Person {
	private String name;
    public Person(String name) {
        this.name = name;
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("Alice");
        
        System.out.println(p1.toString()); 
        // 출력: Person.p1@26f0a63f
    }
}

@Override한 경우

class Person {
	private String name;
    public Person(String name) {
        this.name = name;
    }
    @Override
	public String toString() {
		return this.name;
	}
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("Alice");
        
        System.out.println(p1.toString()); 
        // 출력: Alice
    }
}

상수(Constant) vs 리터럴(Literal) vs 변수(variable)

이름정의비고
상수고정된 값으로, 변수처럼 이름이 붙음, 한 번 초기화되면 변경 불가,
final 키워드로 선언
final 키워드는 변수, 메소드, 클래스에 선언 가능
final로 선언시 재할당할려고 하면 컴파일 오류가 발행
리터럴코드에 직접적으로 나타나는 값, 변경 불가, 값 그 자체로 사용
변수변수(variable) 하나의 값을 저장하기 위한공간, 변경 가능

Call by Value vs Call by Reference

Call by Value

  • 값 자체를 복사하여 메서드에 전달하는 방식
  • Java의 모든 기본 타입(Primitive Type) 변수는 Call by Value로 동작
  • 메서드에 전달된 값은 복사본
  • 원본 값은 메서드 내부에서 변경되지 않음
    example)
public class Main {
    public static void modifyValue(int x) {
        x = 10; // 복사본의 값을 변경
        System.out.println("Inside method: x = " + x);
    }

    public static void main(String[] args) {
        int a = 5;
        System.out.println("Before method: a = " + a);
        modifyValue(a); // a의 값이 복사되어 전달됨
        System.out.println("After method: a = " + a); // 원본은 변경되지 않음
    }
}
/*
* Before method: a = 5
* Inside method: x = 10
* After method: a = 5
*/

Call by Reference

  • 참조(주소)를 복사하여 메서드에 전달하는 방식
  • 메서드 내부에서 참조된 객체의 내용을 직접 수정 가능
  • Java는 객체의 참조값을 Call by Value로 전달하기 때문에, 객체의 내용을 수정할 수 있지만, 참조 자체를 변경 불가능
    example)
public class Main {
    public static void modifyArray(int[] arr) {
        arr[0] = 10; // 참조된 객체의 내용을 변경
        System.out.println("Inside method: arr[0] = " + arr[0]);
    }

    public static void main(String[] args) {
        int[] array = {1, 2, 3};
        System.out.println("Before method: array[0] = " + array[0]);
        modifyArray(array); // 배열의 참조값이 전달됨
        System.out.println("After method: array[0] = " + array[0]); // 원본 변경됨
    }
}
/*
* Before method: array[0] = 1
* Inside method: arr[0] = 10
* After method: array[0] = 10

*/

Primitive Type(기본 타입) vs Reference Type(참조 타입)

특징Primitive TypeReference Type
정의기본 타입은 값(value)을 직접 저장하는 데이터 타입참조 타입은 객체(Object) 또는 배열의 참조(주소)를 저장하는 데이터 타입
변수에는 실제 데이터가 아니라 데이터가 저장된 메모리의 주소값이 저장됩니다.
데이터 저장 방식값 자체를 저장데이터가 저장된 메모리 주소를 저장
저장 위치스택(Stack)참조 값은 스택, 데이터는 힙(Heap)에 저장
초기화 값타입별 기본값 존재null
메모리 효율성고정된 크기, 메모리 효율적객체 크기에 따라 달라짐
사용 예byte, short, int ,long, float, double, char, boolean배열, 클래스, 인터페이스, 열거형 등
GC(Garbage Collector)해당 없음사용되지 않는 객체를 자동으로 정리
성능상대적으로 빠름객체 접근 시 상대적으로 느림
값 비교값 자체 비교 (==)주소 또는 내용 비교 (== 또는 equals)

interface vs abstract class

  • interface
특징설명
목적행동(메서드 시그니처) 정의
상속 관계다중 구현 가능 (다중 상속 지원)
메서드Java 8 이전: 추상 메서드만
Java 8 이후: 디폴트 및 정적 메서드 포함
필드public static final(상수)만 가능
상속 키워드implements 사용
추가 기능Java 9 이후 private 메서드 제공
사용성특정 행동을 구현하도록 강제 (다중 행동 계약 가능)

example)

public interface Animal {
    void eat();    // 추상 메서드
    void sleep();  // 추상 메서드
}
public class Dog implements Animal {
    @Override
    public void eat() {
        System.out.println("Dog eats food.");
    }

    @Override
    public void sleep() {
        System.out.println("Dog sleeps.");
    }
}
  • abstract class
특징설명
목적공통 상태와 행동 제공
상속 관계단일 상속만 가능
메서드추상 메서드와 일반 메서드 모두 포함 가능
필드모든 종류의 필드 선언 가능
상속 키워드extends 사용
추가 기능생성자, 필드 초기화, 상태 관리 가능
사용성공통 상태 및 기본 동작을 제공

example)

public abstract class Animal {
    protected String name; // 필드
    
    public Animal(String name) {
        this.name = name;
    }
    
    public abstract void makeSound(); // 추상 메서드

    public void eat() { // 일반 메서드
        System.out.println(name + " is eating.");
    }
}
public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println(name + " says Woof!");
    }
}

참고

https://wikidocs.net/190
https://i3utterfly.tistory.com/entry/JAVA-버전별-정리
https://www.oracle.com
https://velog.io/@calis_ws/Java-hashCode-란
https://devlog-wjdrbs96.tistory.com/243
https://study-developmnet.tistory.com/6
https://velog.io/@god1hyuk/Javaclass-오버라이딩overriding과-오버로딩overloading
https://velog.io/@gillog/Java-Interface-vs-Abstract-Class-정리

profile
BackEnd develope

0개의 댓글