-
[Java] 생성자, 패키지언어/Java 2024. 11. 6. 10:33
김영한의 실전 자바 - 기본편 강의 | 김영한 - 인프런
김영한 | 실무에 필요한 자바 객체 지향의 핵심 개념을 예제 코드를 통해 쉽게 학습합니다., 국내 개발 분야 누적 수강생 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> 💡
정리
- 생성자는 반드시 호출되어야 한다.
- 생성자가 없으면 기본 생성자가 제공된다.
- 생성자가 하나라도 있으면 기본 생성자가 제공되지 않는다. 이 경우 개발자가 정의한 생성자를 직접 호출해야 한다. </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
- user
'언어 > 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