728x90

이전에는 데이터의 상태정보에 초점을 맞춰 DTO, VO 클래스 위주로 데이터를 다루었다면, 행위(동작) 정보를 초점에 맞춰서 클래스와 클래스를 설계(상속)하는 방법을 알아보겠습니다.


 

수평적 구조로 설계하다보면 Dog와 Cat의 공통적으로 할 수 있는 동작은 eat(먹다) 라는 같은 기능을 하는 동작의 중복이 발생합니다.
동물들에게는 eat라는 중복기능이 나올 확률이 높습니다.

 

        class Animal {
          // 부모 클래스 멤버
        }


        class Dog extends Animal {
          // 자식 클래스 멤버
        }


        Dog dog = new Dog();
        Animal animal = dog; // Upcasting


        Animal animal = new Dog(); // Upcasting


        if (animal instanceof Dog) {

          Dog dog = (Dog) animal; // Downcasting
          // dog 변수를 통해 animal이 Dog 클래스의 멤버에 접근

        }

 

https://yeomboyeon.tistory.com/m/63

 

🎈 Upcasting(업캐스팅 / 자동형변환) 이란 ?

업캐스팅은 부모 클래스 타입으로 자식 클래스의 객체를 참조하는 것을 말합니다.
업캐스팅을 사용하는 이유는 다형성(Polymorphism)을 활용하기 위함입니다. 부모 클래스는 자식 클래스의 공통된 특징과
기능을 포함하고 있으므로, 업캐스팅을 통해 부모 클래스 타입으로 자식 클래스의 객체를 다룰 수 있게 됩니다.
이로써 코드의 유연성과 확장성을 높일 수 있습니다. 업캐스팅은 런타임에 동적으로 객체의 실제 타입을
결정할 수 있기 때문에 다양한 자식 클래스의 객체를 부모 클래스 타입으로 처리할 수 있습니다.

 

💡 업캐스팅 문법 → 상위 클래스타입 인스턴스 변수 = new 하위클래스();

 

Animal x = new Dog();

 

→ 객체로의 생성은 Dog()이지만 Animal의 타입으로 받습니다. 둘은 상속관계이기때문에 가능합니다. (하위가 상위로 들어가는 것은 자동!)
부모가 자식을 가리키는 객체 생성 방법 → 하위 클래스의 동작을 알 수 없을때는, 부모타입으로 객체를 생성할 수 밖에 없기때문에 자주 사용됩니다.

 

🎈 Downcasting(다운캐스팅 / 강제형변)이란 ?

다운캐스팅은 업캐스팅된 객체를 다시 원래의 자식 클래스 타입으로 변환하는 것을 말합니다.
다운캐스팅은 주로 다형성을 통해 업캐스팅된 객체가 실제로 어떤 자식 클래스의 객체인지 확인하고,자식 클래스에 고유한 메서드나 속성에 접근하기 위해 사용됩니다.
다운캐스팅은 정확한 타입의 메서드나 속성을 사용할 수 있도록 객체를 변환해주는 역할을 합니다.
다운캐스팅은 업캐스팅된 객체를 다시 자식 클래스 타입으로 형변환하여 사용하는 것이기 때문에
정확한 타입 체크가 필요하며, 올바른 타입이 아닌 경우에는 ClassCastException이 발생할 수 있습니다.

 

💡 다운캐스팅 문법하위클래스의 타입 다운캐스팅된 객체를 저장할 변수 = (하위클래스의 타입) 상위클래스의 객체

 

다운캐스팅은 주의해야 할 점이 있습니다. 만약 다운캐스팅을 시도하는 객체가 실제로 해당 하위 클래스의 인스턴스가 아니라면,ClassCastException이 발생할 수 있습니다. 따라서 다운캐스팅을 수행하기 전에 항상 해당 객체가 정말로 하위 클래스의 인스턴스인지를 확인하는 것이 좋습니다.
이를 위해 instanceof 연산자를 사용할 수 있습니다.

 

instanceof 연산자 : instanceof 연산자는 객체의 타입을 확인하기 위해 사용되는 연산자 사용 문법 : [객체] instanceof [타입]

 

업캐스팅은 다양한 자식 클래스를 부모 클래스의 타입으로 다룰 수 있도록 하고, 다운캐스팅은 업캐스팅된 객체를 원래의 자식 클래스 타입으로 형변환하여 자식 클래스에 고유한 기능에 접근할 수 있도록 합니다.

728x90
반응형
728x90

 

 

🖥️ 설계라는 것은 클래스를 여러개를 사용해서 개발을 진행됩니다. 

클래스를 설계(상속)
각 클래스들이 아무 관계가 없이 만들어지는 것이 아니라 클래스들끼리 연결을 시켜서 프로그램이 개발되는데 그 시작이 상속에서부터 시작됩니다.

 

Java에서 상속이란 ? 클래스를 계층화 하는 것

상속은 한 클래스가 다른 클래스의 특성과 동작을 상속받아 사용할 수 있도록 해줍니다.

상속 관계에서는 두 개의 클래스가 있습니다: 부모 클래스(상위 클래스 또는 슈퍼 클래스)와 자식 클래스(하위 클래스 또는 서브 클래스)입니다.
부모 클래스는 자식 클래스에게 공통된 속성과 메서드를 상속해줍니다. 자식 클래스는 부모 클래스의 특성을 확장하거나 변경하여 새로운 속성과 메서드를 추가할 수 있습니다.

Java에서 클래스 간의 상속 관계를 구현하기 위해서는 extends 키워드를 사용합니다.
자식 클래스가 부모 클래스를 상속받으려면 클래스 선언 시에 extends 키워드를 사용하고, 부모 클래스의 이름을 지정합니다.
이렇게 하면 자식 클래스는 부모 클래스의 멤버(필드와 메서드)를 상속받습니다.

 

 🎈  상속 관계 설정 문법 - class Child extends Parent

 

class Animal { // 부모 클래스

    protected String name;
    public void eat() {
        System.out.println("Animal is eating.");
    }
}


class Dog extends Animal { // 자식 클래스
    public void bark() {
        System.out.println("Dog is barking.");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "Tom";
        dog.eat(); // 부모 클래스의 메서드 호출
        dog.bark(); // 자식 클래스의 메서드 호출
    }
}

//출력 : Animal is eating. Dog is barking.

 

위 예시에서 Animal 클래스는 부모 클래스로, Dog 클래스는 자식 클래스입니다. Dog 클래스는 extends 키워드를 사용하여 Animal 클래스를 상속받습니다. 따라서 Dog 클래스는 name 필드와 eat() 메서드를 상속받아 사용할 수 있습니다. Dog 클래스는 또한 bark()라는 자신만의 메서드를 추가로 가지고 있습니다.

상속을 통해 부모 클래스의 속성과 메서드를 재사용하고, 자식 클래스에서 새로운 기능을 추가하거나 기존 기능을 재정의할 수 있습니다.
이를 통해 코드의 재사용성과 확장성을 높일 수 있습니다.

 

  🎈 클래스의 수평적 구조 vs 수직적 구조

 


Dog와 Cat의 클래스를 수평적으로 설계하게 된다면 생성된 클래스들의 연계되었기보다는 독립적으로 생성되어지며, 코드의 중복이 발생하는 단점이 발생합니다.
그로인해 새로운 요구사항이 발생했을 때, 반영이 어려워 유지보수가 어려워집니다. 유지보수가 어렵다보니 그에 따르는 확장성이 떨어지게 됩니다.

 

  💡 클래스의 수직적 구조 = 계층화 = 상속(Inheritance) = 클래스와 클래스의 관계 설계

클래스들이 공통으로 가지게 되는 기능이 담긴 별도의 Animal클래스로 생성하여, 제일 상단에 위치하였습니다.
여기서 Aniaml 클래스가 부모 클래스가 되며 상속(extends : 확장) 을통해 하단의 Dog, Cat클래스는 자손 클래스가 됩니다.

 

✔ “is a kind of” - 상속관계

 

"is a kind of"은 객체 지향 프로그래밍에서 클래스 간의 관계를 표현하는 개념입니다.
이 개념은 상속 관계를 나타내는 것을 의미합니다.
상위 클래스에는 공통적인 특징과 동작을 구현하고, 하위 클래스는 상위 클래스의 특성을 상속받으면서 자신만의 추가적인 특성을 정의할 수 있습니다.

객체를 수직적인 구조로 설계하면 코드의 중복을 최소화하고, 새로운 요구사항 발생 시 반영이 쉽다는 장점이 있습니다.
그로 인해 확장성은 좋아질 수 있으나, 코드의 복잡성은 증가하게 됩니다.

java에서는 둘 이상의 클래스로부터 상속을 받을 수 없도록 단일 상속만을 허용한다. 단일상속은 하나의 부모클래스만을 가질 수 있기 때문에
다중상속에 비해 불편하지만, 클래스간의 관계가 보다 명확해지고 코드를 더욱 신뢰할 수 있게 만들어 준다는 점에서 다중상속보다 유리합니다.

 

🎈 메모리를 통한 상속(extends)의 이해 (상태정보 재활용)

 

상속 : UML (Unified Modeling Laguage)
상속을 다이어그램으로 표현할 때, UML - 객체 지향 모델링 언어로 표현할 수 있습니다.
그림으로 표현할 수 있는 언어이며, 그림으로 표현하는 다이어그램으로 설계를 한 후 의사소통을 하는 것이 효율적입니다.
설계는 다이어그램을 보고 코드로 작성이 진행되게 됩니다. ** UML은 프트웨어 시스템을 시각적으로 모델링하고 설계하기 위해 사용되는 표준화된 그래픽 언어입니다.
UML은 시스템의 구성 요소, 클래스와 객체, 관계, 동작, 상태 등을 시각적으로 표현할 수 있습니다.

 

 

public class Employee {

			protected String name;
			-> protected : 상속관계에서 하위 클래스가 상위 클래스의 접근을 허용하는 접근 권한
			protected String phone;
			protected String phone;
			protected String empDate;
			protected String dept;
			
	public Employee() {
		super();
}

	public class RempVO() extends Employee {
		public RempVO() {
			super();
	}
}

 

상속관계에서 상태변수(멤버변수)를 private로 접근제어를 작성한다면, 자식클래스가 부모에 있는 상태변수에 접근할 수 없기 때문에
protected 접근제어자를 사용합니다. (자식 클래스만 작성 가능하도록 해야하기 때문에 public이 아니라 protected로 작성합니다.)
protected : 같은 패키지 내에서, 그리고 다른 패키지의 자손 클래스에서 접근이 가능합니다.

 

🎈 super() 메서드 : super()는 상위클래스의 생성자를 호출하는 역할

 

상속관계의 클래스를 작성한 후 생성자를 만들게 되면 { } 중괄호 안에 아무것도 작성되어 있지 않아도, 자동으로 super(); 키워드가 입력되게됩니다.

Q. 상속관계가 된 후 객체 생성을 진행한다면 ?

 

RempVo vo = new RempVO(); → RempVO가 상속 관계 있을 때, 객체를 생성하게 될 때 RempVO 객체라는 건 부모 클래스인 Employee() 객체가 존재하기 때문에 존재할 수 있습니다.
상속 관계에서는 자식 클래스의 객체가 존재하기 위해서는 부모의 객체가 먼저 생성이 되어야지만 자식 클래스에서의 객체 생성이 가능합니다.
자식 생성자 안에서 부모 생성자를 호출할 수 있는 방법이 필요한데 그 때 super(); 메서드를 사용하여 호출합니다.

super()는 자식 클래스 내부에서 부모 클래스의 생성자를 호출할 때 사용되며, 자식 클래스의 생성자 첫 줄에서 호출(=first statement)되어야 합니다.
super();가 아래에서 초기화가 된다면, 부모클래스가 먼저 만들어지지 않고 객체가 생성되기 때문에 반드시 생성자의 첫번째 문장에 사용해야 합니다.
예를 들어, **super()**를 사용하여 부모 클래스의 기본 생성자를 호출하면 부모 클래스의 필드를 초기화하고
부모 클래스의 생성자에서 수행되는 작업을 수행할 수 있습니다 (객체가 생성되려면 생성자가 호출되어야 생성이 가능)

 

생성자의 첫 문장에는 super();가 기본적으로 생략된채로 만들어집니다. -> .상속 관계에서 객체 생성은 부모 클래스에서부터 생성되어 자식 클래스들로 전달되는데 이를 상속 체이닝이라고 합니다

참조변수는 객체를 가리키는 변수입니다. 자바에서 객체는 클래스의 인스턴스를 의미하며, 객체를 생성하면 해당 객체를 가리키기 위한 참조변수가 필요합니다. 참조변수는 객체의 주소를 저장하고, 해당 주소를 통해 객체에 접근하여 필드를 읽거나 메서드를 호출할 수 있습니다.

따라서 super()는 부모 클래스의 생성자를 호출하는 특수한 구문이며, 참조변수는 객체를 가리키는 변수를 의미합니다.

728x90
반응형
728x90

 

💡 어떤 클래스의 (객체) 모든 멤버가 static 멤버인 경우를 생각해보자

 

하나의 클래스 내부에 선언된 모든 메서드가 static으로 선언되었을 시 메인 메서드가 선언된 클래스에서 static 메서드로 접근할 시 클래스이름.메서드이름으로 접근이 쉽게 할 수 있습니다.

static 으로 선언한 메서드를 new연산자를 생성하여 객체 생성을 해서 사용할 수도 있기 때문에 코드를 작성할 때, 생성자 메서드(default method)를 private로 접근을 제한하여 선언해주면 객체생성을 못하도록 인위적으로 막을수가 있습니다.

https://velog.io/@steadygo247

자바 API에서는 private 생성자를 가지고 있는 클래스도 있다 ex) System , Math 등

//AllStatic 클래스

public class AllStatic {

    private AllStatic() {}
    public static int hap(int a, int b) {
        int v = a+b;
        return v;
    }
    
    public static int max(int a, int b) {
        return a>b ? a : b;
    }
    
    public static int min (int a, int b){
        return a<b ? a : b;
    }
}

//메인 메서드 클래스

public class AllStaticTest {

    public static void main(String[] args) {
    
        //AllStatic st = new AllStatic();
        //System.out.println(st.hap(3,5));
        //System.out.println(st.max(10,5));
        //System.out.println(st.min(10,5));
        
        System.out.println(AllStatic.hap(10,20));
        System.out.println(AllStatic.max(10,20));
        System.out.println(AllStatic.min(10,20));
    }
}

AllStatic 클래스내에서 Allstatic 생성자 메서드를 접근제어자 private를 사용해서
외부클래스 메인 메서드에서 객체 생성이 되지 않도록 막아두었음.

 

🎈 Class, Object, Instance 구분해보기

객체지향의 가장 기본이라고 볼 수 있는 용어들이며 , 객체를 나타내는 말들이지만 생성되는 시점에 따라서 조금씩 용어들이 달라질 뿐이다. 객체지향의 기본 개념은 인스턴스를 이용하여 생성된 객체에 접근하는 것이 가장 기본!

  • Class (클래스) : 객체를 모델링 하는 도구 (설계도) / 새로운 자료형을 만드는 도구! ex) public class Student { … }
  • Object(객체) : 클래스를 통해서 선언되는 변수 ex) Student st(객체변수 - 학생이라는 객체를 담을 변수(담을 예정)) → 앞으로 가리킴 변수가 구체적인 실체(대상)을 가리키지 않는 상태 / 객체가 서로 구분이 되지 않는 시점
  • Instance(인스턴스 , 실체) : 객체생성에 의해 메모리 (Heap Memory)에 만들어진 객체를 인스턴스(Instance)라고 한다. ex) st = new Student(); (인스턴스 - new 연산자와 생성자 메서드를 이용하여 객체가 생성되며 구체적인 실체로 할당을 받으면서 객체변수에서 인스턴스변수로 변하게 된다) 객체가 서로 구분이 되는 시점 (name , age, email, year …등)
728x90
반응형
728x90
📄 static 메서드란?
객체의 생성 없이 클래스 이름을 통해 직접 호출할 수 있는 메서드입니다.

static 메서드는 static이 붙어있는 메서드(static멤버는) 클래스를 사용하는 시점에서 자동으로 static-zone에 로딩됩니다. 정적 메서드 코드는 프로그램이 실행될 때 메모리의 static-zone에 로드되며, 메서드 호출 시 실행됩니다.

❓ main(시작) 클래스는 왜 객체생성없이 (new)로 객체 생성하지 않았는데 실행이 되었을까

         public class Static Test{
                 public static void main(String[] args) {
                         System.out.println(”Hello Java:);
                }
        }

main 클래스의 동작 방식
  1. run을 통해 실행하게 되면 내부의 JVM이 실행할 클래스를 찾습니다.
  2. 찾은 후에 설계된 클래스(파일)가 실행이 되려면 메모리 위에 올라와야 하는데, new를 하지 않은 상황에선 static 키워드가 붙어있는 멤버들( static 키워드가 붙은 메서드는 main) 정해진 메모리(static-zone) 위치에 한번 자동으로 로딩이 됩니다. → static 멤버들은 클래스를 사용하는 시점 즉, 클래스이름.메서드이름으로 호출될 때, 에서 딱 한번 Method Area 메모리에 로딩된다는 점이 중요합니다. 위의 코드에서는 main() 메서드가 static이기 때문에 메모리에 자동으로 로딩합다.
  3. JVM이 static-zone에서 main() 메서드를 호출합니다.
  4. 호출된 메서드를 Call Stack Frame Area(Stack Area)에 push(기계어 코드를 넣고)한 뒤 동작을 시작한다.

** Stack이 텅 비어있으면 현재 모든 프로그램이 종료된 상황 **

https://yang-droid.tistory.com/52

 

//Math 클래스 안에 static으로 작성된 클래스들

public class Math {
    public static int add(int a, int b) {
        return a + b;
    }


    public static int multiply(int a, int b) {
        return a * b;
    }
}


public class Main {
    public static void main(String[] args) {
    
        int sum = Math.add(5, 3);
        System.out.println("더하기: " + sum);


        int multiple = Math.multiply(4, 2);
        System.out.println("곱하기: " + multiple);
        
    }
}

//출력 -> 더하기 : 8 / 곱하기 : 8

위의 코드에서 Math 클래스에는 두 개의 정적 메서드인 addmultiply가 있습니다. 이 메서드들은 static 키워드로 선언되었기 때문에 클래스의 인스턴스를 생성하지 않고도 직접 접근하여 사용할 수 있습니다. 접근하는 방법은 dot( . ) 연산자를 이용하여 클래스이름.(static)메서드이름으로 매개변수를 전달하여 호출할 수 있습니다.

클래스이름.메서드이름

자주 사용하거나 빈번하게 사용하는 클래스 멤버들은 static으로 설정하여 멤버에 접근이 용이하도록 작성해주는 것이 좋습니다. ****static 메서드는 클래스의 인스턴스 없이도 호출되며, 간편하게 사용할 수 있습니다.

 

💡 none-static 메서드의 접근 방법 (인스턴스 메서드 / static이 붙지 않음)
- 객체를 생성해서 메모리에 로딩시켜야 합니다.

 

//Myutil1 클래스로 static이 작성되지 않음.

public class Myutil1 {
    public int hap(int a, int b ) {
        int v = a+b;
        return v;
    }
}


//main 메서드의 클래스
import model.Myutil1;

public class NoneStaticAccess {
    public static void main(String[] args) {
    
        int a = 10;
        int b = 16;
     //static이 아닌 클래스를 사용한다면 객체를 생성해주면 된다.
     
        Myutil1 ut = new Myutil1();
        int sum = ut.hap(a,b);
        System.out.println("sum = " + sum);
    }
}

 

💡 Method Area : 메서드의 기계어 코드가 할당되는 메모리 공간 / static 멤버들의 할당되는 메모리 공간
💡 Heap Area : 객체가 생성(new)되는 메모리공간

 

https://velog.io/@yonii/JAVA-Static이란

 

💡 JVM내에서의 메모리 모델

 

.크게 4가지로 구분지어서 확인할 수 있습니다.

  1. Method Area : static-zone과 none-static-zond으로 구성되어 있으며, 메서드의 바이트코드(기계어코드)가 할당되는 공간입니다. static 멤버들은 static-zone에 할당됩니다.
  2. Heap Area : 실제 객체가 생성되는 메모리 공간(new 연산자) / Java 프로그램의 메모리 구조 중 하나이며, 메모리 관리와 객체의 동적 생성 및 소멸에 중요한 역할을 합니다. GC(Garbage Collector)에 의해서 메모리가 수집됩니다. Heap Area는 우리가 객체를 생성되기 때문에 객체를 사용 후에는 소멸이 되어야 하는데, 메모리 계속 쌓이게 되면 용량을 차지하게 됩니다. 이 후, 객체를 생성할 때 메모리 용량이 부족하면 지연시간이 생기거나 에러가 날 수 있습니다. 이 때, GC라는 프로세스를 통해 Heap Area에 더이상 사용이 되지 않고 남아있는 Garbage 객체들은 주기적으로 clear 해주는 역할을 합니다. GC가 한번 Heap Area를 스캔하며 지나갈 때 각각의 객체가 사용중이라면 , 각각의 스캔 주기를 세대로 설정해줍니다. (맨 처음은 1세대) 이 후, 두번째 프로세스로 돌아왔을 때 기존에 사용중인 게 있다면 2,3,4..세대로 계속 업데이트를 해줍니다. 이 때 , 숫자가 높은 것들부터 GC를 진행하는 것을 Generation이라고 합니다.
  3. Thread : 스레드(Thread)는 프로그램 실행의 기본 단위로, 독립적으로 실행될 수 있는 작업 단위입니다. (JVM도 하나의 스레드라고 볼 수 있습니다) 스레드를 사용하면 여러 작업이 동시에 진행되는 것처럼 보이며, 다양한 작업들을 병렬적으로 처리할 수 있습니다. 스레드는 프로세스 내에서 독립적으로 실행되며, 각각의 스레드는 독립적인 작업 공간인 스택(Stack Area - Call Stack Frame Area)과 프로그램 카운터(Program Counter)를 가지고 있습니다. 메서드가 호출되면 메서드의 기계어코드를 할당 받고 메서드가 실행되는 공간(Call Stack Frame Area) - 지역변수, 매개변수들이 만들어지는 공간 PC에 의해서 현재 실행중인 프로그램 위치가 관리된다. LIFO(Last In First Out)구조로 운영되는 메모리공간
  4. Runtime Constant Pool (Literal Pool) : 상수 값 할당이 되는 메모리 공간 문자열 중 문자열 상수 (Literal : 리터럴)가 할당되는 메모리공간 (ex) 문자열 = “APPLE” → 리터럴)
728x90
반응형
728x90

 

 

🔐 정보은닉(Informaiton hiding)


  • 정보은닉 : 다른 객체에게 자신의 정보를 숨기고 자신의 동작, 기능, 연산만을 통해 접근을 허용하는 것으로, 클래스 외부에서 특정 정보에 접근을 막는다는 의미이다. 캡슐화와 연관성이 밀접한 단어이다.

  • 캡슐화 : 정보 은닉은 객체의 속성과 메서드를 적절하게 그룹화하여 외부에 노출시키지 않습니다. 객체 내부의 구현 세부 사항은 외부로부터 숨겨지고, 오직 공개된 인터페이스만을 통해 상호작용할 수 있습니다. 이를 통해 객체는 자신의 상태와 동작을 캡슐화하고, 외부에서는 그 구체적인 내용을 알 필요 없이 사용할 수 있습니다.
💡 정보은닉이 되어있는 상태정보에 접근하는 방법 (private에 접근하는 방법) 2가지의 대표 방법이 있다.

데이터에 쉽게 접근하지 못하게 상태정보를 private로 설정해두었다면, 해당 데이터를 메인 클래스에서
객체를 생성하여 사용하지 못하게 됩니다. ( private는 자기자신을 제외 모든 패키지에서 접근이 불가하기 때문입니다.)


 

1. Getter와 Setter

객체 지향 프로그래밍에서 클래스의 속성(=상태정보) 에 접근하고 값을 가져오거나 설정하기 위한 메서드를 말합니다.
일반적으로 속성은 private으로 선언되어 외부에서 직접 접근할 수 없으므로, Getter와 Setter를 사용하여 간접적으로 필드에 접근하고 값을 가져오거나 설정합니다.

 

< Getter와 Setter의 예시 >

< Getter와 Setter의 예시 >

public class Person {
    private String name; // private 필드

    public String getName() { // Getter 메서드
        return name;
    }

    public void setName(String newName) { // Setter 메서드
        name = newName;
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("John"); // Setter를 통해 필드 값 설정

        String name = person.getName(); // Getter를 통해 필드 값 읽기
        System.out.println(name); // 출력: John
    }
}

 

🎈  Getter는 속성의 값을 반환하는 메서드로, 외부에서 속성 값을 읽을 수 있도록 합니다.
      Getter는 일반적으로 속성 이름 앞에 "get" 접두사를 붙이고, 속성의 데이터 타입과 일치하는 값을 반환합니다.
      밖으로 데이터를 보내주는 용도 get멤버변수(이 때, 멤버변수의 시작은 대문자로 시작한다)

🎈 Setter는 속성에 값을 설정하는 메서드로, 외부에서 속성 값을 변경할 수 있도록 합니다.
     Setter는 일반적으로 속성 이름 앞에 "set" 접두사를 붙이고, 속성의 데이터 타입과 일치하는 매개변수를 받아 필드 값을 변경합니다.
     저장하는 용도 set멤버변수(이 때, 멤버변수의 시작은 대문자로 시작한다) → 메서드로서 매개변수로 name이라는 변수를 받아,
     this로 접근하여 받아온 name을 값을 this.name(클래스가 가지고 있는 멤버변수)에다가 할당해준다.

💡 Getter와 Setter의 주요 목적은 정보 은닉(Encapsulation)을 유지하면서 속성에 접근하는 기능을 제공하는 것
입니다. 속성을 private으로 선언하여 직접 접근을 제한하고, Getter와 Setter를 통해 필드에 접근하면서 캡슐화를 유지할 수 있습니다.

private로 접근이 제한된 변수들을 get,set을 사용하여 public으로 외부 클래스에서도 접근이 가능할 수 있게 설정해주었습니다.
set속성으로 해당 메모리공간을 불러온 후 ( )안에 출력되기를 원하는 데이터를 입력한 후, get속성으로 출력할 수 있습니다.

 

2. 생성자 메서드를 통해서 접근 가능(객체 초기화)

 

  • 생성자 메서드를 아무것도 만들지 않으면 컴파일러가 자동으로 default 생성자가 생성되어 있는데 그 default 생성자 안에 this.속성(상태정보) = “데이터”; 와 같은 문법으로 객체를 생성한 후 초기화를 하여 정보은닉화 된 메모리 공간에 값을 저장해 줄 수 있습니다.
  • 생성자 메서드의 역할은 객체를 생성한 후, 객체가 가지고 있는 상태정보에 데이터를 바로 저장할 때 생성자 메서드를 사용하게됩니다.
  • private 접근 제한자는 같은 클래스 내에서는 자기자신의 데이터로 접근이 허용되고 생성자 메서드 내부에서 this를 이용해메모리공간에 값을 입력하는 것이 가능합니다.

setter 대신 생성자를 초기화하여 속성 값에 데이터를 입력해주면 setter는 작성할 필요없이 getter로 main메서드에서 호출하여 사용하면 된다.

 

public class Person {
    private String name;
    private int age;

    // 생성자 초기화
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Getter 메서드
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

public class Main {
    public static void main(String[] args) {
        // 생성자를 통해 객체 생성 및 초기화
        Person person = new Person("John", 25);

        System.out.println(person.getName()); // 출력: John
        System.out.println(person.getAge(); // 출력: 25
    }
}

 

 

 

 

3. 생성자 메서드를 오버로딩(Overloading)해서 초기화 가능

 

PersonVO p = new PersonVO(”홍길동”, 50, “010-1234-4567”); 위와 같이 작성하여 객체를 생성함과 동시에 p에 값들을 입력해주고, 해당 값들을 class PersonVO에 생성자 메서드를 오버로딩하여 초기화가 가능하다.
public PersonVO(String name, int age, String phone) {
               this.name = name;
               this.age = age;
               this.phone = phone;
}

 

PersonVo class 

//생략된 생성자 메서드가 있다. -> 기본생성자 (default Constructor)
    public PersonVo() {
        this.name = "홍길동";
        this.age = 30;
        this.phone = "111-1111-1111";
    }

    public PersonVo(String name, int age, String phone) {
        //객체를 생성하는 코드는 내부에서 만들어진다.
        //객체를 초기화 한다.
        this.name = name;
        this.age = age;
        this.phone = phone;
    }


import model.PersonVo;

public class Capsul_personvo {
    public static void main(String[] args) {

        //Q. 한사람의 [회원] 정보를 저장할 [객체를 생성]하세요.
        PersonVo vo = new PersonVo();
        PersonVo vo1 = new PersonVo("나길동" , 50, "222-2222-2222");
        PersonVo vo2 = new PersonVo("나길동" , 50, "222-2222-2222");

        System.out.println(vo.getName() + "\t" + vo.getPhone() + "\t" + vo.getAge());
        System.out.println(vo1.getName() + "\t" + vo1.getPhone() + "\t" + vo1.getAge());
        System.out.println(vo2.getName() + "\t" + vo2.getPhone() + "\t" + vo2.getAge());
    }
}

 

🎈  toString() 메서드를 활용하여 객체가 가지고 있는 모든 값을 리턴하기

생성자 메서드를 활용하여 개발자가 입력한 데이터를 입력하여 객체를 출력할 수 있게는 하였지만, getter를 각각의 속성들 마다 입력하여 불러오는 번거로움이 발생합니다.

이 때, toString() 메서드를 활용하면 객체 내부에 저장된 모든 값들을 한번에 문자열로 출력할 수 있게됩니다. 그럼 getter를 하나하나 입력하는 것이 아닌, toString 메서드에 만들어진 retrun 값대로 출력할 수 있게됩니다.

public String toString() {
        return name + "\t"+age+"\t"+phone;
    }

import model.PersonVo;

public class ToStringPrint {
    public static void main(String[] args) {
        //Q.생성자 메서드를 통해서 PersonVo객체에 원하는 이름, 나이, 전화번호를 저장하고 toString() 메서드로 출력하세요.
        PersonVo vo = new PersonVo("홍길동" , 34, "111-1111-1111");
        System.out.println(vo.getName() + "\t" + vo.getAge()+"\t"+vo.getPhone());
        System.out.println(vo.toString());
        //getter를 세번이나 입력해서 출력을 반복하는 것보다 toString
				System.out.println(vo); -> vo.toString() 과 동일한 출    
		}
}

여기서 toString의 생략도 가능해진다. 생성자 메서드로 저장된 vo객체만 입력하여 출력했다고 하더라도, 컴파일러가 객체가 가지고 있는
모든 데이터를 출력해야한다고 판단하여, vo.toString이라는 메서드를 찾아서 toString 메서드에 의해서 출력될 수 있도록 진행해준다.

 

💡 잘 설계된 VO 클래스란 ?

1. 모든 상태정보 ( = 속성)을 정보 은닉하기 (private)
2. default 생성자를 반드시 만들기
3. 생성자 메서드를 오버로딩하여 객체 초기화 하기
4. setter 메서드를 만들기( 값을 저장하기 위한 용도)
5. getter 메서드를 만들기( 값을 가져오기위한 용도)
6. toString() 메서드를 만들기( 객체가 가지고 있는 전체 값 출력 용도)

 

💡 intelliJ에서 제공하는 Generate 이용하기

 

먼저 VO파일을 생성한 후 우클릭을 누르면 Generate라는 메뉴가 보이는데 해당 메뉴를 이용하여 default 생성자 및 getter setter를 손쉽게 생성할 수 있다.

 

 

Constructor를 클릭하여 default생성자 및 만들어진 기본 생성자를 오버로딩하는 메서드도 만들 수 있고, Getter and Setter를 클릭하면 선언된 속성에 따르는 getter setter를 바로 만들 수 있다.

728x90
반응형
728x90
  • 객체 지향 프로그래밍에서는 객체들 간의 접근을 제어할 수 있어야 합니다. 상태와 동작을 상호간에 접근을 허용할 수도 있어야하고, 접근을 막아야 하는 경우도 있습니다. 접근 제어자를 사용하는 이유는 클래스의 내부에 선언된 데이터를 보호하기 위해서인데, 데이터가 유효한 값을 유지하도록 또는 비밀번호와 같은 데이터를 외부에서 함부로 변경하지 못하도록 하기 위해서 외부로부터 접근을 제한하는 것이 필요합니다.
  • 이를 데이터 감추기(data hiding)이라고 하며, 객체지향개념에서는 캡슐화에 해당하는 내용입니다. 또 다른 이유로는, 클래스 내에서만 사용되는, 내부 작업을 위해 임시로 사용되는 멤버 변수나 부분 작업을 처리하기 위한 메서드 등의 멤버들을 클래스 내부에 감추기 위해서입니다. 외부에서 접근할 필요가 없는 멤버들을 private로 접근을 제한하면 코드의 복잡성도 줄일 수 있습니다.

 

접근제어(Access Modifier) 란?

객체의 상태정보(=멤버 변수) 는 중요하기 때문에 다른 클래스에서의 접근을 허용하지 않습니다. (정보은닉)
상태정보에 다른 객체가 접근하여 값을 수정하게 된다면, 객체가 불필요한 정보들을 갖게될 수 있고, 잘못된 데이터를 가지게 될 수도 있습니다.

  • 객체의 행위정보(=멤버 메서드) 는 상호작용이 필요하기 때문에 클래스끼리의 접근을 허용합니다.
  • 클래스나 멤버변수, 메서드, 생성자에 접근 제어자가 지정되어 있지 않다면, 접근 제어자가 default임을 뜻합니다.

 

https://cloudstudying.kr/lectures/201

 

       public > proteced > (default) > private

  1. public : 모든패키지에서 접근 가능 (모든 클래스 , 멤버 메서드는 public)
  2. private : 모든 패키지에서 접근 불가 (자기 자신만 접근 가능 / 모든 멤버변수는 private) 일반적으로 상태변수는 private으로 접근을 제한해주는 것이 일반적
  3. protected : 상속 관계에서 하위 클래스에서 상위 클래스 접근가능 자식이 부모에 있는 기능들을 사용하고 싶다면 protected로 제한한다.
  4. default : 동일한 패키지에서만 접근 가능 (코드에 작성되어 있지 않고 생략되어 있음)
    → 접근 제한자를 작성하지 않는다면 기본적으로 default이며, 클래스끼리는 동일한 패키지 내에서의 클래스끼리는 다 접근이 가능하다는 의미
    public이라고 작성하는 이유는 외부 패키지에서도 해당 클래스에 접근할 수 있도록 하기위해서 일반적으로 class를 작성할 때는 public을 작성해준다.

    📋 접근 제어자는 클래스와 클래스 내부에서 만들어지는 멤버변수, 멤버 메서드에 접근 제한자를 사용할 수 있다.

 

💡 Package란?

서로 기능이 비슷한 클래스들끼리 모아서 관리를 쉽게 하기 위해서 사용 (폴더 개념)
java는 대부분 2단계의 폴더구조를 가지고 있다 (API) / 기능이 비슷한 API들끼리 묶어서 패키지로 보관하여 사용하고 있다.

https://jeniffer0812techstory.tistory.com/24

 

  • 클래스를 접근하는 이름 이해하기

패키지를 포함하지 않는 클래스 이름은 (class name) 패키지를 포함한 클래스 이름 (class full name) → 패키지.패키지.클래스 이름
ex) 문자열을 처리하는 클래스 → java.lang.String 키보드로부터 데이터를 읽어드리는 클래스 → java.util.Scanner

해당 API 또는 클래스가 어디에 있는지 구조를 알고 있어야 class full name을 통해 해당 클래스로 접근이 가능해진다.

728x90
반응형

+ Recent posts