코드 그라데이션

20230127 자바 공부 본문

Java, SpringBoot 추가 공부

20230127 자바 공부

완벽한 장면 2023. 2. 3. 19:38

목차

객체지향 문법 1

# 클래스

- 클래스가 필요한 이유

- 클래스 멤버

- static

 

# 객체

- 객체의 비교

- 객체 멤버

 

# 생성자

- 생성자가 필요한 이유

- 기본생성자

 

클래스는 설계도
객체는 만들어 낸 대상

클래스는 무엇인가?
클래스 : 변수와 함수의 모음

클래스가 가지고 있는 변수 = 필드
클래스가 가지고 있는 함수 = 메서드

class Person {
  String name;
    
  void sayHello() {
    System.out.println("Hello, I'm + this.name);
  }
}

여기서 Person 클래스는 name이라는 변수와 sayHello() 라는 함수를 가지고 있다.

일단 현실의 문제를 푸는 건데, 
현실의 문제를 푼다는 건 현실 세계에 있는 대상을, 정보를 어쨌든 코드로 가져와야 된다는 말이다.

ex. 배달의민족 주문 : 메뉴와 가격, 행동 등 => 코드로 가져와야.
이걸 코드로 표현할 방법이 클래스라는 추상화된 개념이 있다는 것이다.

"변수 : 정보, 함수 : 행동"
------------

static
: 일단 블랙박스를 쳐 두되, 그냥 "얘는 클래스의 멤버구나" 생각하면 된다.

클래스의 특징 또 다른 한 가지는 하나만 존재한다는 것.
- 붕어빵 틀이 여러 개 있는 것이 아니라, 붕어빵 틀은 하나만 있고, 거기서 무한히 찍어내는 것.
객체는 그렇지 않지
- 모든 붕어빵이 다 다르지(팥의 양, 구움의 정도 등...)
=> 객체, 인스턴스의 멤버는 각각의 인스턴스마다 서로 독립적이다.

그런데 클래스 멤버는 클래스라는 "단 하나만 존재하는 것" 에 있는 값이기 때문에
객체랑 관련 없이 존재한다.

예시, 건물짓기
class Building {

	static int count = 0;
    
	String address;
    int height;
    int numberOfDoors; ....
    => 각각 다 다른 독립적인 값.
}

여기서 "건물을 몇 개 지었는지"를 묻는다면?
건물을 몇 개 지었느냐 => 객체에 각각 할당된 값이라고 볼 수 있어? 글쎄...
===> 건물 전체에 대한 공통적인 값이지. 하나만 존재
"이럴 때 static 을 쓴다!!!"

모든 인스턴스가 서로 다르게 가질 수 있는 값은 static을 안 붙이고 변수를 만들고,
그게 아니라 객체마다 달라지는 값이 아니고 클래스 전반에 걸쳐 하나만 관리하고 싶으면,
static을 붙여 써주는 것!!!
class Building {
    static int count = 0;  
    String address;
    int height;
    int numberOfDoors; ....
    
    public static void main(String[] args) {
    	// Building bulding; => 이렇게 하면 객체는 만들어지지 않은 상황, new를 써야지
        Building building = new Building(); // Building()는 사실 생성자다!
    	System.out.println(building.height);
        
        그런데 count는 static이 붙었기 때문에 클래스의 것이잖아요.
        그래서 그냥 아래와같이 써주기만 하면 된다.(객체 생성 없이 가져올 수 있다는 의미)
        System.out.println(Bulding.count);
    }    
}
main은 왜 static일 수 밖에 없을까? => 시작점이잖아!

main은 시작점, 그런데 main이 static이 아니라면? 누군가 main을 만들어주어야 한다.
애초에 그러면 시작조차 못하게 되는 건데... 말 자체가 안 되는 상황인거지.
그래서 얘는 무언가 만들어지기 전에 일단은 시작을 해야 하므로 static이다.

 

이해를 위한 예제

class Connection {
    private static Connection instance = null;
    public int count = 0;

    public static Connection getConnection() {
        if (instance == null) {
            instance = new Connection();
        }
        return instance;
    }

    public void count() {
        count++;
    }

    public int getCount() {
        return count;
    }
}
public class Main {
    public static void main(String[] args) {
        Connection con1 = Connection.getConnection(); 
        //Connection이 뭔지는 모르겠지만, getConnection이라는 메서드를 불러서 con1에 받았고,
        con1.count(); // 뭔지 모르겠지만 얘를 count 했어요. 이 과정을 세 번 했지
        Connection con2 = Connection.getConnection();
        con2.count();
        Connection con3 = Connection.getConnection();
        con3.count();

        System.out.println(con1.getCount()); // 아 con1의 count를 출력하는구나!

        // 그리고 나서 Connection 볼게요!
    }
}
// 윗부분 해석
클래스 Connection을 봤더니
필드가 두 개, 메서드는 세 개가 있다.
instance 필드는 static,  count 필드는 static 아니다.

getconnection() 을 하면, null인지 검사를 해서 인스턴스를 하나 만든다.
그리고 이름 그대로 getconnection을 하면 그냥 Connection을 반환 하는 거예요.

// 아래.
count()를 하면 count를 1 증가시키고,
getcount()를 하면 그냥 count를 반환하는 메서드

/*
이 때, count를 총 3번을 부르고, getCount()의 값이 얼마냐고 물으면(아래쪽에)
값이 뭐가 출력될까요???
 */

여기서 con이 총 3번 만들어졌고, 각각 1번씩 총 3번 count 되었으며, 여기서 count는 인스턴스다.
세 개 인스턴스에서 각각 count 했으면, 얘는 서로 독립적으로 존재하니까

count는 static이 아니다. 이 말인 즉, con이 3번 만들어졌으면, 3개가 독립적으로 존재(사실상 위랑 같은 말이네)
con1에서 count 를 1 증가시켰다고 해서 con2 의 값이 증가가 되는가? NO. 원래는 1이 맞아!


근데 여기서는 3이 출력된대!!!! 왜???
여기서 Connection con1 = Connection.getConnection();는 new를 하고 있지 않아.
클래스 이름에다 바로 get을 한 형태.

그럼 얘 getConnection()는 static 함수일까요, 인스턴스 함수일까요?
=> static 함수!
=> 클래스에서 바로 불러오니까.

다시 위를 가보면,
        if (instance == null) {
            instance = new Connection();
        }
        instance가 null일 경우에만 새 객체를 만들라고 했죠.

그럼 처음에는 당연히 한 번도 만든 적이 없으니까 null.
처음에 new 가 실행됨.

구런데...
private static Connection instance = null; 얘는 static 이다!
첫 번째에서 new를 만들었는데, 얘는 static이므로, 첫 번째가 끝나도 여전히 살아있는 상황이 됨!
(static이 아니었으면, 언제나 null이었을 거야.)

그래서 두번째는 null 이 아니기때문에 new를 하지 않고 instance를 바로 반환.
이 때 반환하는 애는 첫 번째가 받던 애 그 값 그대로.

그래서 함수 실행이 첫 번째 값이 1이었으니까, 여기서 1을 증가시켜서(count++;) 2가 된다.

최종적으로는 3이 출력되는 원리.

 

생성자

다시 Person으로 돌아가서

class Person {
	Stirng name;
    
    public static void main(String[] args) {
    	Person person = new Person();
}

사실 Person()는 함수라는 뜻!!!!
그런데 우리는 위에서 Person()이라는 함수를 만든 적이 없는걸.

생성자는 객체를 만들 때 반드시 필요한 존재지.
그래서 자바 컴파일러는 사용자가 생성자를 만들지 않으면 기본 생성자를 자동으로 만들어줌!!!

생성자 규칙 : 클래스명과 반드시 동일해야

즉,
class Person {
	Stirng name;
    
    Person() {
    	System.out.println("생성자")
    }
    
    public static void main(String[] args) {
    	Person person = new Person();
} // 이러면 아무 것도 안 했음에도, "생성자" 라는 단어가 출력됨.

생성자 찾는 방법(순서 아니다)
1. 클래스명과 똑같은지 본다.
2. 리턴이 없는 것(생성자 특징)을 찾는다
3. 대문자로 시작하는지를 본다.

사각형 안에 정사각형이 있듯이, 함수 안에 몇 가지 제약조건이 붙은 함수라고 생각하면 된다.
class Person {
	Stirng name;
    
    Person() {;}
    
    public static void main(String[] args) {
    	Person person = new Person();
        
        //(여기)
        
        person.name = "hello";
}

문제를 간단히하기 위해서, Person 클래스는 반드시 name을 가져야 한다고 가정해보자.

그런데 (여기) 사이에 코드가 있을 수 있죠.
(= 만드는 시점과 이름이 생성되는 시점이 얼마든지 다를 수 있다)

사람이라는 클래스가 name이 가장 중요한데, name이 설정되지 않는 순간이 있을 수도 있다는 이야기.
=> 이것을 막기 위해서 생성자가 존재한다.

생성자 안에다가 (이렇게)해버리면
class Person {
	Stirng name;
    
    Person(String name) { // (이렇게)
    	this.name = name;
    } 
    
    public static void main(String[] args) {
    	Person person = new Person(/*(여기2)*/ "Hello");
        

        
        person.name = "hello";
}

"난 만드는 시점에 name이 반드시 필요해" 라는 뜻이 된다.
그리고 "그 name을 나의 name으로 만들 거야" 가 된다.

그러면 반드시 (여기2)에 인자를 줘야 해요. name을 받는다고 했으니까.

즉, 객체를 만들 때 반드시 해줘야 하는 일이 있으면, 그런 걸 생성자 통해 한다는 거죠.
=> 생성자를 쓰는 이유.
변수는 똑같은 이름이 있으면 안 되지만,
함수는 가능하지.

이것이 메서드 오버로딩이었다.

이름이 똑같을지라도 매개변수의 개수가 다르거나 타입이 다르면 된다.

 

객체

객체는 값과 다르다.

지금 위 그림을 보면 a 사물함 안에 5는 그대로 담기지만, Person 클래스는 b 사물함 안에 못 담긴다.

Person이라는 클래스는 그 안에 담길 수 있는 것에 제한이 있나요? No. 
=> 무한히 만들어도 된다. => 크기를 측정할 수가 없다.
그래서 b안에는 화살표 시작점만 만들어놓고, 다른 곳의 넉넉한 공간 속에 값을 집어넣는다.
소위 "주소" 속된 말로 위칫값(화살표 시작점 = 주소)

class Person {
	String name;
    
    Person(String name) {
    	this.name = name;
    }
    
    
	public static void main(String[] args) {
        int a = 5;
        Person p = new Person(); // 이 때야 비로소 사람이 생김
        System.out.println(b.name);
    }
}

 

또 다른 예시

class Person {
	String id;
    
    Person() {;}
    
	public static void main(String[] args) {
        int a = 5;
		Person b = new Person("A")
        Person c = new Person("A")
        
        System.out.println(b==c) // 동일성 : 완전히 똑같냐
        ***equals : 동등성 => 물리적으로 같냐
        // System.out.println(b.equals(c)); // true 출력 
        
        // cf. String도 사실 객체이므로 비교할 때 equals 써줘야 한다.
    }
}

// 이 때 출력값은? false!!!

// 왜?
값을 가리키는 게 아니라 주소를 가리키므로, 주소가 같냐고 물어보는 꼴.
객체는 두 개 만들어진다
주소는 다르다! 그러므로 false 출력.

 

 

728x90
Comments