[즐거운 자바 강의] 섹션4 - 객체지향 문법 (3)
1. 생성자
- 메소드와 비슷
- return type이 없다. 클래스 이름과 같아야한다.
① 기본생성자
매개변수가 0개인 생성자
public class Car {
public Car(){
System.out.println("자동차가 한대 생성됩니다.");
}
}
클래스 작성시 생성자를 하나도 만들지 않았다면 기본생성자가 생성된다
public class Car2Exam02 {
public static void main(String[] args) {
Car c1 = new Car();
System.out.println(c1);
}
}
② 이름을 가지고 인스턴스를 만들어지게 하고 싶을때
public abstract class Car2 {
//생성자는 return type이 없어야함
public Car2(String name){
super();
System.out.println("Car2() 생성자 호출");
}
}
public class Bus2 extends Car2 {
public Bus2(){
super("Bus!"); //부모의 기본 생성자를 호출하는 코드가 자동으로 삽입
// 이 코드가 자동으로 들어간다
System.out.println("Bus2 기본 생성자");
}
}
2. 추상 클래스
1) 추상클래스란?
= 미완성된 클래스
[예제] 추상클래스인 Car2와 Bus2를 작성하자
[코드1]
public abstract class Car2 {
//생성자는 return type이 없어야함
public Car2(String name){
super();
System.out.println("Car2() 생성자 호출");
}
//추상메소드 car2를 만든 사람은 run()이라는 메소드가 필요하다고 생각을 했다
//run()은 자동차마다 다르게 구현할 것 같다
public abstract void run();
}
public class Bus2 extends Car2 {
public Bus2(){
super("Bus!"); //부모의 기본 생성자를 호출하는 코드가 자동으로 삽입
// 이 코드가 자동으로 들어간다
System.out.println("Bus2 기본 생성자");
}
//부모가 가지고 있는 추상메소드는 자식에서 반드시 구현을 해줘야한다
@Override
public void run() {
System.out.println("후륜구동으로 동작한다.");
}
}
public class Car2Exam02 {
public static void main(String[] args) {
//Car2 c = new Car2("urstory"); //car2가 추상class라서 오류
Bus2 b = new Bus2();
b.run();
}
}
[코드2]
public class Car2Exam02 {
public static void main(String[] args) {
//Car2 c = new Car2("urstory"); //car2가 추상class라서 오류
Bus2 b = new Bus2();
b.run();
SportsCar s1 = new SportsCar("SportsCar!!");
s1.run();
}
}
public class Bus2 extends Car2 {
public Bus2(){
super("Bus!"); //부모의 기본 생성자를 호출하는 코드가 자동으로 삽입
// 이 코드가 자동으로 들어간다
System.out.println("Bus2 기본 생성자");
}
//부모가 가지고 있는 추상메소드는 자식에서 반드시 구현을 해줘야한다
@Override
public void run() {
System.out.println("후륜구동으로 동작한다.");
}
}
public class SportsCar extends Car2{
//부모가 기본생성자가 없기때문에 반드시 super()을 호출한다.
public SportsCar(String name) { //car2가 기본생성자가 없기때문에 에러
super(name); // 생성자를 만들어주고 부모의 생성자에 값 전달해줘야함
}
@Override
public void run() { //car2가 추상생성자라 오류
System.out.println("사륜구동");
}
}
→
[코드3]
public class Car2Exam02 {
public static void main(String[] args) {
//Car2 c = new Car2("urstory"); //car2가 추상class라서 오류
Bus2 b = new Bus2();
b.run();
SportsCar s1 = new SportsCar("SportsCar!!");
s1.run();
Car2 c = new Bus2(); // car2의 자손만가능
c.run(); // -->후륜구동으로동작한다
//Car2 c = new SportsCar(); // car2의 자손만가능
//c.run(); // --> 사륜구동으로동작한다
Car2[] array = new Car2[2]; // car2를 2개 참조할 수 있는 배열을 선언
array[0]= new Bus2();
array[1] = new SportsCar("SportsCar!");
for (Car2 c2 : array){
c2.run();
}
}
}
→
2) 템플릿 메소드 패턴(Template Method Pattern)
템플릿 메소드: 정해진 순서에 따라 실행되는 메소드
[코드1]
package com.example.fw;/*
controller의 종류가 여러개
초기화 - 항상 같은코드
실행 - 이거만 다른코드가 실행
마무리 - 항상 같은코드
*/
public abstract class Controller {
public void init(){
System.out.println("초기화하는 코드");
}
public void close(){
System.out.println("마무리하는 코드");
}
public abstract void run(); //메번 다른 코드
//내가 가지고 있는 메소드를 호출한다.
//어떤 순서를 가지고 있다. 이런 메소드를 템플릿 메소드라고 한다.
public void execute(){
this.init();//초기화
this.run();//실행
this.close();//마무리
}
}
추상클래스 상속받을때는 항상 오버라이드 필수!
package com.example.myproject;
import com.example.fw.Controller;
public class FirstController extends Controller{
@Override
public void run() {
System.out.println("별도로 동작하는 코드 111111");
}
}
package com.example.main;
import com.example.fw.Controller;
import com.example.myproject.FirstController;
public class ControllerMain {
public static void main(String[] args) {
Controller c1 = new FirstController();
c1.execute();
}
}
→ 출력
+
[주의사항1]
c1.init();
하면 init만 출력 → .execute()만 호출해야함!
[해결방법]
public이 아닌 protected로 코드 수정
package com.example.fw;
public abstract class Controller {
//protected는 같은 package이거나 상속받았을 때 사용 가능
protected void init(){
System.out.println("초기화하는 코드");
}
protected void close(){
System.out.println("마무리하는 코드");
}
protected abstract void run(); //메번 다른 코드
//내가 가지고 있는 메소드를 호출한다.
//어떤 순서를 가지고 있다. 이런 메소드를 템플릿 메소드라고 한다.
public void execute(){
this.init();//초기화
this.run();//실행
this.close();//마무리
}
}
[주의사항2]
init을 오버라이드
package com.example.myproject;
import com.example.fw.Controller;
public class FirstController extends Controller{
@Override
public void run() {
System.out.println("별도로 동작하는 코드 111111");
}
@Override
protected void init() {
System.out.println("내맘대로 init");
}
}
[해결방법]
abstract의 반대인 final 사용 → 오버라이드 불가
package com.example.fw;
public abstract class Controller {
protected final void init(){
System.out.println("초기화하는 코드");
}
protected final void close(){
System.out.println("마무리하는 코드");
}
protected abstract void run(); //메번 다른 코드
public void execute(){
this.init();//초기화
this.run();//실행
this.close();//마무리
}
}
final 클래스
= 부모가 될 수 없는 클래스
- 대표 예시) String 클래스(=불변클래스)
package com.example;
public class StringExam {
public static void main(String[] args) {
String str1="Hello";
String str2="Hello";
String str3= new String("Hello");
String str4= new String("Hello");
if (str1 == str2)
System.out.println("str1==str2");
if (str1 == str3)
System.out.println("str1==str3");
if (str3 == str4)
System.out.println("str3==str4");
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
System.out.println(str4);
}
}
→ 출력:
[이유]
"==" : 같은곳을 참조하는지?
- new로 생성하지 않으면 Hello가 상수처럼 취급됨 → 같은 객체 참조
- new로 생성하면 메모리상에 다른 영역 차지함 → 다른 객체 참조
→ String을 사용할때는 new 사용하지 말것 (메모리 용량 절약)
".equals()" : 같은 값을 가지는지?
if (str1.equals(str2)){
System.out.println("str1과 str2는 값이 같다."); //true
}
2. 접근 제한자
private 쓰는 이유?
메서드가 너무 길때 메서드가 분리 필요!
외부에서 호출하는 것이아니라 내부에서 구조적으로 나누고 싶을때 private 사용
→ 메서드 이름만 봐도 코드가 어떤 코드인지 알 수 있음