본문 바로가기
Everyday Study

2024.07.02 (화) { 콜바이밸류,레퍼런스, 인터페이스, this,super, 함수형 인터페이스 }

by xogns93 2024. 7. 2.

콜바이밸류 (Call by Value)

 

콜바이벨류(Call by Value)는 함수가 인수로 전달받은 값을 복사하여 처리하는 방식이다.
이때, 전달된 값은 기본형, 즉 JS의 원시 타입(primitive type) 데이터인 경우에 해당하며, 변수가 가진 값을 복사하여 전달하므로 함수 내에서 값을 변경해도 원본 값은 변경되지 않는다. 

따라서 값의 불변성(Immutability)을 유지하는 데에 용이하다.

 

"Call by Value"는 함수 호출 시 매개변수로 값을 전달하는 방식 중 하나입니다. Java에서는 모든 메서드 호출이 "Call by Value" 방식으로 이루어집니다. 즉, 메서드에 인자로 전달되는 값의 복사본이 전달됩니다. 이를 통해 메서드 내부에서 인자의 값이 변경되더라도 원본 변수에는 영향을 미치지 않습니다.

 

Java에서는 기본 데이터 타입(primitive types)과 객체 참조(reference types) 모두 "Call by Value"로 전달됩니다. 다만, 객체 참조는 참조 변수의 값을 복사하여 전달하므로, 메서드 내부에서 객체의 상태를 변경할 수 있지만, 참조 변수가 가리키는 객체 자체를 변경할 수는 없습니다.

위 코드에서 num의 값은 modifyValue 메소드에 전달될 때 복사됩니다. 따라서 modifyValue 메소드 내에서 값을 변경해도 main 메소드의 num 값은 변하지 않습니다.

 

기본 데이터 타입 (Primitive Types)

public class Main {
    public static void main(String[] args) {
        int num = 10;
        System.out.println("Before: " + num); // 출력: Before: 10
        modifyPrimitive(num);
        System.out.println("After: " + num); // 출력: After: 10
    }

    static void modifyPrimitive(int n) {
        n = 20;
    }
}

이 예제에서 modifyPrimitive 메서드가 호출될 때, num의 값인 10이 복사되어 n에 전달됩니다. 메서드 내부에서 n의 값을 20으로 변경하더라도, 원래의 num 변수에는 아무런 영향을 미치지 않습니다. 따라서 출력 결과는 Before: 10과 After: 10이 됩니다.

 

객체 참조 타입 (Reference Types)

class Car {
    String model;

    Car(String model) {
        this.model = model;
    }
}

public class Main {
    public static void main(String[] args) {
        Car myCar = new Car("Toyota");
        System.out.println("Before: " + myCar.model); // 출력: Before: Toyota
        modifyObject(myCar);
        System.out.println("After: " + myCar.model); // 출력: After: Honda
    }

    static void modifyObject(Car car) {
        car.model = "Honda"; // 객체의 상태를 변경
    }
}

이 예제에서 modifyObject 메서드가 호출될 때, myCar의 참조 값이 복사되어 car에 전달됩니다. 이 경우, car가 가리키는 객체의 model 값을 "Honda"로 변경하면, 이는 myCar가 가리키는 객체의 model 값에도 영향을 미칩니다. 따라서 출력 결과는 Before: Toyota와 After: Honda가 됩니다.

 

요약

  • 기본 데이터 타입의 경우, 값이 복사되어 전달되므로 메서드 내부에서 변경이 발생해도 원본 변수에는 영향을 미치지 않습니다.
  • 객체 참조 타입의 경우, 참조 값이 복사되어 전달되므로 메서드 내부에서 객체의 상태를 변경하면 원본 객체에도 영향을 미칩니다. 그러나 참조 변수를 새로운 객체로 변경해도 원본 참조 변수에는 영향을 미치지 않습니다.

콜 바이 레퍼런스(Call by Reference)

 

"Call by Reference"는 함수 호출 시 인자로 전달되는 변수의 주소를 전달하는 방식을 의미합니다. 이 방식에서는 함수 내부에서 변수의 주소를 통해 직접 원본 변수에 접근하고, 이를 수정할 수 있습니다. 이는 함수 내부의 변경이 함수 외부의 원본 변수에 영향을 미치게 합니다.

요약

  • 콜바이밸류 (Call by Value): 함수에 인수의 값을 복사하여 전달. 함수 내에서 인수를 변경해도 원래 인수는 변하지 않음. 자바의 모든 인수 전달 방식은 콜바이밸류.
  • 콜바이레퍼런스 (Call by Reference): 함수에 인수의 주소를 전달. 함수 내에서 인수를 직접 참조하고 변경할 수 있음. C++과 같은 언어에서 포인터를 사용하여 구현.

인터페이스(Interface)

Java에서 인터페이스(Interface)는 추상 메서드(몸체가 없는 메서드)와 상수로만 구성된 특별한 형태의 클래스입니다. 인터페이스는 클래스가 구현해야 할 메서드의 청사진을 제공하며, 다중 상속을 지원하기 위해 사용됩니다. Java에서는 클래스가 여러 인터페이스를 구현할 수 있습니다. 인터페이스를 사용하면 코드의 유연성과 확장성을 높일 수 있습니다.

인터페이스는 본문이 없다 = 메서드 바디가 없다

 

인터페이스의 주요 특징

  1. 추상 메서드: 인터페이스에는 메서드 몸체가 없는 추상 메서드만 포함될 수 있습니다. Java 8 이후에는 디폴트 메서드와 정적 메서드도 포함할 수 있습니다.
  2. 상수: 인터페이스 내에 정의된 변수는 암묵적으로 public, static, final로 선언됩니다.
  3. 다중 상속: 클래스는 하나의 클래스만 상속할 수 있지만, 여러 인터페이스를 구현할 수 있습니다.
  4. 구현 강제: 인터페이스를 구현한 클래스는 인터페이스에 정의된 모든 메서드를 구현해야 합니다.

1. 인터페이스 정의

public interface Animal {
    // 추상 메서드 (abstract keyword는 생략 가능)
    void eat();
    void sleep();

    // 디폴트 메서드 (Java 8 이상)
    default void breathe() {
        System.out.println("Breathing...");
    }

    // 정적 메서드 (Java 8 이상)
    static void info() {
        System.out.println("This is an Animal interface");
    }
}

2. 인터페이스 구현

public class Dog implements Animal {
    // Animal 인터페이스의 메서드를 구현
    @Override
    public void eat() {
        System.out.println("Dog is eating");
    }

    @Override
    public void sleep() {
        System.out.println("Dog is sleeping");
    }
}

public class Cat implements Animal {
    // Animal 인터페이스의 메서드를 구현
    @Override
    public void eat() {
        System.out.println("Cat is eating");
    }

    @Override
    public void sleep() {
        System.out.println("Cat is sleeping");
    }
}

3. 인터페이스 사용

public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog();
        dog.eat(); // 출력: Dog is eating
        dog.sleep(); // 출력: Dog is sleeping
        dog.breathe(); // 출력: Breathing...

        Animal cat = new Cat();
        cat.eat(); // 출력: Cat is eating
        cat.sleep(); // 출력: Cat is sleeping
        cat.breathe(); // 출력: Breathing...

        Animal.info(); // 출력: This is an Animal interface
    }
}

 

인터페이스의 장점

  1. 다중 상속: Java에서는 클래스가 단일 상속만 가능하지만, 인터페이스를 통해 다중 상속과 유사한 효과를 얻을 수 있습니다.
  2. 느슨한 결합: 인터페이스를 사용하면 클래스 간의 결합도를 낮출 수 있습니다. 이는 코드의 유연성과 유지 보수성을 높입니다.
  3. 표준화: 인터페이스는 특정 클래스가 제공해야 하는 메서드를 표준화합니다. 이를 통해 일관된 프로그래밍이 가능합니다.
  4. 디자인 패턴: 인터페이스는 여러 디자인 패턴의 구현에 중요한 역할을 합니다.

 

Java에서 인터페이스는 클래스와 외부 세계 간의 계약을 형성하며, 이 계약은 컴파일러에 의해 빌드 시점에 강제됩니다. 이를 통해 인터페이스는 클래스가 반드시 제공해야 하는 메서드를 정의하여, 특정 동작을 보장하도록 합니다.


 

앱스트랙트 메서드(추상 메서드)는 Java에서 메서드의 선언만 있고 구현(몸체)이 없는 메서드를 말합니다. 추상 메서드는 주로 추상 클래스나 인터페이스에서 사용됩니다. 추상 메서드는 하위 클래스가 반드시 구현해야 하는 메서드를 정의하는 데 사용됩니다.

 

추상 메서드의 특징

  1. 메서드 바디 없음: 추상 메서드는 메서드 바디(구현)가 없습니다. 즉, 메서드 선언부만 존재합니다.
  2. 추상 클래스: 추상 메서드는 추상 클래스나 인터페이스 내에서 정의됩니다.
  3. 구현 강제: 추상 메서드를 포함하는 추상 클래스나 인터페이스를 상속받거나 구현하는 클래스는 이 메서드를 반드시 구현해야 합니다.
  4. abstract 키워드: 추상 메서드는 abstract 키워드로 선언됩니다.

this 키워드

this 키워드는 현재 객체(인스턴스)를 가리키는 참조입니다. 주로 다음과 같은 경우에 사용됩니다.

 

1. 인스턴스 변수와 지역 변수의 구별: 메서드 내에서 인스턴스 변수와 지역 변수의 이름이 같을 때, this를 사용하여 인스턴스 변수를 명시적으로 참조합니다.

public class Car {
    private String color;

    public void setColor(String color) {
        this.color = color; // this를 사용하여 인스턴스 변수에 접근
    }
}

2. 다른 생성자 호출: 한 생성자에서 다른 생성자를 호출할 때 사용됩니다. 이때 this() 메서드를 사용합니다.

public class Car {
    private String color;
    private int speed;

    public Car(String color) {
        this.color = color;
    }

    public Car(String color, int speed) {
        this(color); // 다른 생성자 호출
        this.speed = speed;
    }
}

3. 인스턴스 메서드 호출: 현재 객체의 다른 메서드를 호출할 때도 this를 사용할 수 있습니다.

public class Calculator {
    private int result;

    public void add(int number) {
        this.result += number;
    }

    public void subtract(int number) {
        this.result -= number;
    }

    public void clear() {
        this.result = 0;
    }
}

4. 인스턴스를 반환: 메서드가 현재 객체를 반환할 때 사용됩니다.

public class Person {
    private String name;

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

    public Person getName() {
        return this; // 현재 객체 반환
    }
}

 

super 키워드

super 키워드는 부모 클래스의 멤버를 참조할 때 사용됩니다. 주로 다음과 같은 경우에 사용됩니다:

 

1. 부모 클래스의 생성자 호출: 하위 클래스에서 부모 클래스의 생성자를 호출할 때 사용됩니다. super() 메서드를 사용합니다.

public class Animal {
    private String type;

    public Animal(String type) {
        this.type = type;
    }
}

public class Dog extends Animal {
    private String breed;

    public Dog(String type, String breed) {
        super(type); // 부모 클래스의 생성자 호출
        this.breed = breed;
    }
}

2. 부모 클래스의 메서드 호출: 하위 클래스에서 부모 클래스의 메서드를 재정의(오버라이딩)한 경우, super를 사용하여 부모 클래스의 메서드를 호출할 수 있습니다.

public class Animal {
    public void makeSound() {
        System.out.println("Some sound");
    }
}

public class Dog extends Animal {
    @Override
    public void makeSound() {
        super.makeSound(); // 부모 클래스의 makeSound 메서드 호출
        System.out.println("Woof woof");
    }
}

3. 부모 클래스의 변수 참조: 하위 클래스에서 부모 클래스의 멤버 변수를 참조할 때 사용됩니다.

public class Animal {
    protected String type;

    public Animal(String type) {
        this.type = type;
    }
}

public class Dog extends Animal {
    private String breed;

    public Dog(String type, String breed) {
        super(type);
        this.breed = breed;
    }

    public void displayInfo() {
        System.out.println("Type: " + super.type); // 부모 클래스의 type 변수 참조
        System.out.println("Breed: " + this.breed);
    }
}
 

결론

  • this: 현재 객체를 가리키는 참조로, 인스턴스 변수와 메서드 호출 시에 사용됩니다.
  • super: 부모 클래스를 가리키는 참조로, 부모 클래스의 생성자, 메서드, 변수 등에 접근할 때 사용됩니다.

함수형 인터페이스 (Functional Interface)

함수형 인터페이스는 단 하나의 추상 메서드만을 가진 인터페이스입니다. Java 8부터 추가된 람다 표현식과 함께 많이 사용되며, 주로 함수를 객체로 다룰 수 있도록 해줍니다.

함수형 인터페이스의 특징:

  • 단 하나의 추상 메서드: 오직 하나의 추상 메서드만을 가질 수 있습니다.
  • @FunctionalInterface 애노테이션: Java 컴파일러에게 함수형 인터페이스임을 명시적으로 알려주는 애노테이션입니다 (선택사항).
  • 람다 표현식과의 호환: 함수형 인터페이스는 람다 표현식을 통해 인스턴스화할 수 있습니다.
  • 기본 메서드와 정적 메서드: Java 8부터는 함수형 인터페이스에 기본 메서드(default method)나 정적 메서드(static method)를 포함할 수 있습니다.

자바의 참조(reference)

자바에서 변수는 일반적으로 두 가지 유형으로 나뉩니다: 기본 데이터 타입과 참조 타입입니다. 기본 데이터 타입은 실제 값을 변수에 직접 저장하지만, 참조 타입은 메모리에 객체가 저장된 위치(참조)를 가리키는 변수입니다.

 


배리어블 아규먼트(variable argument)

Java에서 메서드가 가변 개수의 인자를 전달받을 수 있도록 하는 기능을 의미합니다. 이 기능은 Java 5부터 도입되었으며, 메서드 정의 시 특정 타입의 매개변수 뒤에 ... 기호를 사용하여 표시합니다.

public class VariableArgumentsExample {

    // 가변 개수의 정수를 받아서 합을 구하는 메서드
    public static int sum(int... numbers) {
        int total = 0;
        for (int num : numbers) {
            total += num;
        }
        return total;
    }

    public static void main(String[] args) {
        // 다양한 방법으로 sum 메서드 호출
        int result1 = sum(1, 2, 3); // 출력: 6
        int result2 = sum(5, 10);   // 출력: 15
        int result3 = sum();        // 출력: 0

        System.out.println("Result 1: " + result1);
        System.out.println("Result 2: " + result2);
        System.out.println("Result 3: " + result3);
    }
}

 

 

같다 둘이 서로 

public Polygon polygonFrom(Point[] corners) = public Polygon polygonFrom(Point... corners)

 


arg (Arguments)

arg는 단순히 메서드의 매개변수를 가리키는 일반적인 용어입니다. 메서드가 받는 입력값을 가리키며, 이는 메서드 정의에서 매개변수(parameter)들을 의미합니다.

 

varargs (Variable Arguments)

varargs는 "variable arguments"의 줄임말로, Java에서 가변 개수의 인자를 메서드에 전달할 수 있게 해주는 기능입니다. 메서드가 동일한 타입의 인자를 0개 이상 받을 수 있도록 합니다. 이를 위해 메서드 선언에서 매개변수 뒤에 ... 기호를 사용하여 표시합니다.

 


 

new 연산자는 객체를 생성할 때 사용됩니다. 이 연산자는 객체를 메모리에 할당하고, 해당 객체의 참조를 반환합니다. 이 참조는 변수에 할당하여 나중에 객체에 접근하거나 사용할 수 있습니다. 그러나 변수에 할당하지 않고도 바로 사용할 수 있습니다.

 

public class Example {
    private String message;
    
    public Example(String message) {
        this.message = message;
    }
    
    public void printMessage() {
        System.out.println("Message: " + message);
    }
    
    public static void main(String[] args) {
        // 객체를 생성하고 참조를 변수에 할당하지 않고 직접 사용
        new Example("Hello, World!").printMessage();
        
        // 다른 예시: 메서드 호출 시 직접 사용
        printMessage(new Example("Direct usage"));
    }
    
    public static void printMessage(Example example) {
        example.printMessage();
    }
}

설명

  1. Example 클래스는 message 필드와 그 값을 출력하는 printMessage() 메서드를 가지고 있습니다.
  2. main 메서드에서는 다음과 같은 방법으로 new 연산자로 생성한 객체를 바로 사용할 수 있습니다:

 

new Example("Hello, World!").printMessage();

이 코드에서는 new Example("Hello, World!")가 객체를 생성하고, printMessage() 메서드를 바로 호출합니다. 이 경우 객체의 참조를 변수에 할당하지 않고도 객체의 메서드를 호출할 수 있습니다.

 

 

또 다른 예시로, printMessage() 메서드의 인자로 직접 객체를 전달하여 메서드를 호출할 수도 있습니다:

printMessage(new Example("Direct usage"));

이는 printMessage 메서드를 호출하면서 새로운 Example 객체를 생성하여 인자로 전달하는 방식입니다.

 

 

결론

new 연산자는 객체를 생성하고 해당 객체의 참조를 반환합니다. 이 참조는 변수에 할당하지 않고도 객체를 생성하고 사용할 수 있습니다. 이는 코드를 더 간결하게 만들고, 특정 객체를 일회성으로 사용할 때 유용할 수 있습니다.