ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] 생성자, 패키지
    언어/Java 2024. 11. 6. 10:33

    https://www.inflearn.com/course/%EA%B9%80%EC%98%81%ED%95%9C%EC%9D%98-%EC%8B%A4%EC%A0%84-%EC%9E%90%EB%B0%94-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard

     

    김영한의 실전 자바 - 기본편 강의 | 김영한 - 인프런

    김영한 | 실무에 필요한 자바 객체 지향의 핵심 개념을 예제 코드를 통해 쉽게 학습합니다., 국내 개발 분야 누적 수강생 1위, 제대로 만든 김영한의 실전 자바[사진][임베딩 영상]단순히 자바 문

    www.inflearn.com

    아래 내용은 위 링크에서 더 자세히 볼 수 있습니다.

    생성자

    package construct;
    
    public class MethodInitMain2 {
        public static void main(String[] args) {
            MemberInit member1 = new MemberInit();
            initMember(member1, "user1", 15, 90);
    
            MemberInit member2 = new MemberInit();
            initMember(member2, "user2", 16, 80);
            
            MemberInit[] members = {member1, member2};
    
            for (MemberInit s : members) {
                System.out.println(s.name + s.age + s.grade);
            }
        }
        static void initMember(MemberInit member, String name, int age, int grade) {
            member.name = name;
            member.age = age;
            member.grade = grade;
        }
    }
    • 지금까지 배운 내용으로 위 까지는 무리없다.
    • 위 소스 코드를 객체 지향적으로 설계하기 위해서는 기능과 속성이 하나에 있어야 한다.
    package construct;
    
    public class MemberInit {
        String name;
        int age;
        int grade;
    
        void initMember(String name, int age, int grade) {
            this.name = name;
            this.age = age;
            this.grade = grade;
        }
    }
    
    // 다른 
    package construct;
    
    public class MethodInitMain3 {
        public static void main(String[] args) {
            MemberInit member1 = new MemberInit();
            member1.initMember("user1", 15, 90);
    
            MemberInit member2 = new MemberInit();
            member2.initMember("user2", 16, 80);
    
            MemberInit[] members = {member1, member2};
    
            for (MemberInit s : members) {
                System.out.println(s.name + s.age + s.grade);
            }
        }
    }
    • this
      • initMember()의 코드에서 메서드의 매개변수에 정의한 name 과 Member의 멤버 변수의 이름이 name으로 둘 다 똑같다.
      • 둘이 어떻게 구분?
        • 못하지 그래서 this 를 써줘야한다.
    this.name = name; // 1. 오른쪽의 name은 매개변수에 접근
    this.name = "user"; // 2. name 매개변수의 값 사용
    0x001.name = "user"; // 3. this. 은 인스턴스 자신의 참조값을 뜻함.
                     	따라서 인스턴스의 멤버 변수에 접근
    • this를 제거하면 둘 다 매개변수를 뜻해서 멤버변수의 값이 변경되지 않는다.
    • this를 쓰지 않은 경우도 있는 데 java가 해준거임.

    생성자 도입

    • 생성자는 메서드와 비슷하지만 다음과 같은 차이가 있다.
      • 생성자의 이름은 클래스 이름과 같아야 한다. 따라서 첫 글자도 대문자로 시작한다.
      • 생성자는 반환 타입이 없다. 비워두어야 한다.
      • 나머지는 메서드와 같다.

    [원래라면]

    MemberInit member1 = new MemberInit();
            member1.name = "user1";
            member1.age = 15;
            member1.grade = 90;

    [생성자 도입]

    MemberConstruct member1 = 
    new MemberConstruct("user1", 15, 90);
    
    package construct;
    
    public class MemberConstruct {
        String name;
        int age;
        int grade;
    
        MemberConstruct(String name, int age, int grade) {
            System.out.println("생성자 호출 name = " + name + ", age= " + age + ", grade =" + grade);
            this.name = name;
            this.age = age;
            this.grade = grade;
        }
    }

    [생성자 호출]

    new 생성자 이름(생성자에 맞는 인수 목록)
    new 클래스 이름 (생성자에 맞는 인수 목록)
    
    • 생성자 이름이 클래스 이름이기 때문에 둘 다 맞는 표현

    <aside> 💡

    ctrl + P

    매개 변수로 인수를 뭘 넣어야 하지 볼 수 있음

    </aside>

    • 생성자 덕분에 객체를 생성하면서 동시에 생성 직후에 필요한 작업을 한 번에 처리할 수 있다.
    • 메서드를 실수로 호출하지 않아도 컴파일이 된다. (유령회원이 생기겠지)
    • 하지만 생성자는 직접 정의한 생성자를 반드시 호출해야 된다. 그렇지 않으면 컴파일 오류가 발생…!
    • 생성자를 사용하면 필수값 입력을 보장할 수 있다.

    <aside> 💡

    좋은 프로그램은 무한한 자유도가 주어지는 프로그램이 아니라 적절한 제약이 있는 프로그램이다.

    </aside>


    기본 생성자

    • 매개변수가 없는 생성자를 기본 생성자라 한다.
    • 클래스에 생성자가 하나도 없으면 자바 컴파일러는 매개변수가 없고, 작동하는 코드가 없는 기본 생성자를 자동으로 만들어준다.
    • 생성자가 하나라도 있으면 자바는 기본 생성자를 만들지 않는다.
    package construct;
    
    public class MemberDefaultMain {
        public static void main(String[] args) {
            MemberDefault memberDefault = new MemberDefault();
        }
    }
    
    package construct;
    
    public class MemberDefault {
        String name;
    }
    
    • 위 소스 코드에서 볼 수 있듯.. 안 만들면 자동으로 기본 생성자를 만들어 준다. 아니면 아래 처럼 하나라도 생성자가 만들어졌으면 기본으로는 절대 안만든다.
    package construct;
    
    public class MemberDefault {
        String name;
        
        MemberDefault() {
    	    sout("생성자 호출");
        }
    }
    

    <aside> 💡

    정리

    1. 생성자는 반드시 호출되어야 한다.
    2. 생성자가 없으면 기본 생성자가 제공된다.
    3. 생성자가 하나라도 있으면 기본 생성자가 제공되지 않는다. 이 경우 개발자가 정의한 생성자를 직접 호출해야 한다. </aside>

    생성자 - 오버로딩과 this

    • 생성자를 오버로딩 한 덕분에 성적 입력이 꼭 필요한 경우에는 grade 가 있는 생성자를 호출하면 되고, 그렇지 않은 경우네는 grade 가 없는 생성자를 호출하면 된다. grade 가 없는 생성자를 호출하면 성적은 default 값으로 넣어준 값이 된다.
    package construct;
    
    public class ConstructMain2 {
        public static void main(String[] args) {
            MemberConstruct member1 = new MemberConstruct("user1", 15, 90);
            MemberConstruct member2 = new MemberConstruct("user2", 16);
    
            MemberConstruct[] members = {member1, member2};
    
            for (MemberConstruct member : members) {
                System.out.println("name: " + member.name + ", age: " + member.age + ", grade: " + member.grade);
    
            }
        }
    }
    
    package construct;
    
    public class MemberConstruct {
        String name;
        int age;
        int grade;
    
        MemberConstruct(String name, int age) {
            this(name, age, 50);
        }
    
        MemberConstruct(String name, int age, int grade) {
            System.out.println("생성자 호출 name = " + name + ", age= " + age + ", grade =" + grade);
            this.name = name;
            this.age = age;
            this.grade = grade;
        }
    }
    
    • 위 소스 코드는 첫 번째 생성자 내부에서 두 번째 생성자를 호출한다.
    • this() 를 사용하면 생성자 내부에서 다른 생성자를 호출할 수 있다. 이 부분을 잘 활용하면 중복을 제거할 수 있다.
    MemberConstruct(String name, int age) {
            // this(name, age, 50);
            // 만약 위 중복이 있다면...
            this.name = name;
            this.age = age;
            this graadre = 50;
        }
    
        MemberConstruct(String name, int age, int grade) {
            System.out.println("생성자 호출 name = " + name + ", age= " + age + ", grade =" + grade);
            this.name = name;
            this.age = age;
            this.grade = grade;
        }
    
    • this() 는 생성자 코드의 첫 줄에만 작성할 수 있다.

    패키지

    package pack;
    
    public class PackageMain1 {
        public static void main(String[] args) {
            Data data = new Data();
            pack.a.User user = new pack.a.User();
        }
    }
    
    • 사용자와 같은 위치: PackageMain1 과 Data 는 같은 pack 이라는 패키지에 소속되어 있다. 이렇게 같은 경로에 있는 경우 패키지 경로를 생략해도 된다.
    • 사용자와 다른 위치: PackageMain1 과 User 는 서로 다른 패키지이다. 경로가 다르면 pack.a.User 와 같이 패키지 전체 경로를 포함해서 클래스를 적어줘야 한다.

    패키지 import

    <aside> 💡

    경로를 어캐 다 설정해주냐 → import

    참고로 특정 패키지를 포함한 모든 패키지를 import 하고 싶다면 import *을 하면 된다.

    ex) import pack.a.*; pack의 a안의 모든 클래스 가져오기

    </aside>

    package pack;
    
    import pack.a.User;
    
    public class PackageMain2 {
        public static void main(String[] args) {
            Data data = new Data();
            User user = new pack.a.User();
        }
    }
    
    • 코드 첫 줄에는 apckage를 사용하고 , 다음 줄에는 import 를 사용할 수 있다.
    • import 를 사용하면 다른 패키지에 있는 클래스를 가져와서 사용할 수 있다.
    • import 를 사용한 덕분에 코드에서는 패키지 명을 생략하고 클래스 이름만 적을 수 있다.

    클래스 이름 중복

    pack.a.User
    pack.b.User
    
    • 이름이 같은 경우 어떻게 하냐
    • 뭐 해결 방법이라긴 애매하다
    package pack;
    
    import pack.a.User;
    
    public class PackageMain3 {
        public static void main(String[] args) {
            User userA = new User();
            pack.b.User userB= new pack.b.User();
        }
    }
    
    • import 는 이름이 겹칠 때, 하나만 되기 때문에 다른 놈은 경로를 적어줘야지 뭐…
    • 자주 사용하는 놈을 import 해주자.

    패키지 규칙

    • 패키지는 실제 폴더위치와 같아야 함.
    • 패키지 일흠은 모두 소문자
    • 패키지 이름의 앞 부분에는 일반적으로 회사의 도메인 이름을 거꾸로 사용한다. com.company.myapp
      • 외부 라이브러리를 사용하게 되면 같은 패키지에 같은 클래스 이름이 존재할 수도 있다.
      • 내가 오픈소스나 라이브러리를 만들어서 외부에 제공한다면 꼭 지키자.
      • 내가 만든 애플리케이션을 다른 곳에 공유하지 않고, 직접 배포한다면 보통 문제가 되지 않는다.

    패키지와 계층 구조

    • a
      • b
      • c

    위는 3개의 패키지가 존재한다.

    계층 구조상 a 패키지 하위에 a.b 패키지와 a.c 패키지가 있다.

    그런데 이것은 우리 눈에 보기에 계층 구조를 이룰 뿐이다. a 패키지와 a.b a.c 패키지는 서로 완전히 다른 패키지이다. 따라서 a 패키지의 클래스에서 a.b 패키지의 클래스가 필요하면 import 해서 사용해야 한다. 반대도 마찬가지이다.

    <aside> 💡

    패키지가 계층 구조를 이루더라도 모든 패키지는 서로 다른 패키지이다.

    사람이 이해하기 쉽게 계층 구조를 잘 활용해서 패키지를 분류하는 것은 좋다. 참고로 카테고리는 보통 큰 분류에서 세세한 분류로 점점 나뉘어 진다.

    </aside>


    패키지 활용

    [전체 구조도]

    • com.helloshop
      • user
        • User
        • UserService
      • product
        • Product
        • ProductService
      • order
        • Order
        • OrderService
        • OrderHistory

    '언어 > Java' 카테고리의 다른 글

    [Java] 자료구조(스택, 힙), static  (1) 2024.11.09
    [Java] 접근제어자  (1) 2024.11.08
    [Java] 객체 지향 프로그래밍  (4) 2024.11.06
    [Java] 변수와 초기화, null, nullPointerException  (0) 2024.11.05
    [Java] 기본형 vs 참조형  (0) 2024.11.05
Designed by Tistory.