[19일차] 참조 타입 & 클래스

2023. 1. 17. 21:59데이터 엔지니어링 과정/java

목차
1. 배열
2. 열거 타입
3. 객체 지향 프로그래밍
4. 필드
5. 생성자

1. 배열

1. 명령 라인 입력

  • String[] args의 역할
public static void main(String[] args) {···}

명령 라인(명령 프롬프트)에서 위 코드를 java 명령어로 실행하면
JVM은 길이가 0인 String 배열을 먼저 생성하고, main 메소드를 호출할 때 매개값으로 전달한다.
main()메소드는 String[] arg 매개 변수를 통해서 명령 라인에서 입력된 데이터의 수(배열의 길이)와 입력된 데이터(배열의 항목 값)을 알 수 있게 된다.

  • 💻 main() 메소드의 매개 변수
package sec02.exam05;

public class MainstringArrrayArgument {
	public static void main(String[] args) {
		if (args.length != 2) {
			System.out.println("값의 수가 부족합니다.");
			
			System.exit(0); // 프로그램 강제 종료
		}
		
		String strNum1 = args[0];
		String strNum2 = args[1];
		
		int num1 = Integer.parseInt(strNum1);
		int num2 = Integer.parseInt(strNum2);
		
		int result = num1 + num2;
		System.out.println(num1 + " + " + num2 + " = " + result);
	}
}

>>> 값의 수가 부족합니다.

2. 다차원 배열

  • 2차원 배열은 수학의 행렬 같은 모양으로, 가로 세로 인덱스를 사용
  • ❗주의할 점❗ 배열의 정확한 길이를 알고 인덱스를 사용해야 한다!
  • 배열 속의 배열
package sec02.exam06;

public class ArrayInArrayExample {

	public static void main(String[] args) {
		int[][] mathScores = new int[2][3];
		for (int i=0; i<mathScores.length; i++) {
			for (int k=0; k<mathScores[i].length; k++) {
				System.out.println("mathScores["+i+"]["+k+"]="+mathScores[i][k]);
			}
		}
		System.out.println();
		
		int[][] englishScores = new int[2][];
		englishScores[0] = new int[2];
		englishScores[1] = new int[3];
		for (int i=0; i<englishScores.length; i++) {
			for (int k=0; k<englishScores[i].length; k++) {
				System.out.println("engslihScores["+"]["+k+"]="+englishScores[i][k]);
			}
		}
		System.out.println();
		
		int[][] javaScores = {{95,80}, {92, 96, 80}};
		for (int i=0; i<javaScores.length; i++) {
			for (int k=0; k<javaScores[i].length; k++) {
				System.out.println("javaScores["+i+"]["+k+"]="+javaScores[i][k]);
			}
		}
	}
}

>>> mathScores[0][0]=0
>>> mathScores[0][1]=0
>>> mathScores[0][2]=0
>>> mathScores[1][0]=0
>>> mathScores[1][1]=0
>>> mathScores[1][2]=0

>>> engslihScores[0][0]=0
>>> engslihScores[0][1]=0
>>> engslihScores[1][0]=0
>>> engslihScores[1][1]=0
>>> engslihScores[1][2]=0

>>> javaScores[0][0]=95
>>> javaScores[0][1]=80
>>> javaScores[1][0]=92
>>> javaScores[1][1]=96
>>> javaScores[1][2]=80

3. 객체를 참조하는 배열

  • 기본 타입 (byte, char, short, int, long, float, double, boolean) 배열은 각 항목에 직접 값을 갖고 있지만,
  • 참조 타입(클래스, 인터페이스) 배열은 각 항목에 객체의 번지를 가지고 있음
  • ex) String은 클래스이므로, 각 항목에 문자열이 아니라, String 객체의 번지를 가지고 있음
  • 즉, String[] 배열은 String 객체를 참조!
  • String[] 배열의 항목도 결국 String 변수와 동일하게 취급되어야 함
  • 💻 객체를 참조하는 배열
package sec02.exam07;

public class ArrayReferenceObjectExample {
	public static void main(String[] args) {
		String[] strArray = new String[3];
		strArray[0] = "Java";
		strArray[1] = "Java";
		strArray[2] = new String("Java");
		
		System.out.println(strArray[0] == strArray[1]);
		System.out.println(strArray[0] == strArray[2]);
		System.out.println(strArray[0].equals(strArray[2]));
	}
}

>>> true
>>> false
>>> true

4. 배열 복사

  • 배열은 한 번 생성하면 크기를 변경할 수 없음
  • ➡ 더 많은 저장 공간이 필요하다면, 더 큰 배열을 새로 만들고 이전 배열로부터 항목 값들을 복사해야 함
  • for문 사용
  • 💻 for문으로 배열 복사
package sec02.exam08;

public class ArrayCopyByForExample {

	public static void main(String[] args) {
		int[] oldIntArray = {1, 2, 3};
		int[] newIntArray = new int[5];
		
		for (int i=0; i<oldIntArray.length; i++) {
			newIntArray[i] = oldIntArray[i];
		}

		for (int i=0; i<newIntArray.length; i++) {
			System.out.print(newIntArray[i] + ", ");
		}
	}
}

>>> 1, 2, 3, 0, 0,
  • System.arraycopy() 사용
    • 형식 
      System.arraycopy(원본배열, 원본배열 시작 인덱스, 새 배열, 붙여놓을 인덱스, 복사할 개수)
  • 💻 System.arraycopy()로 배열 복사
package sec02.exam09;

public class ArrayCopyExample {
	public static void main(String[] args) {
		String[] oldStrArray = {"java", "array", "copy"};
		String[] newStrArray = new String[5];
		
		System.arraycopy(oldStrArray, 0, newStrArray, 0, oldStrArray.length);
		
		for (int i=0; i<newStrArray.length; i++) {
			System.out.print(newStrArray[i] + ", ");
		}
	}
}

>>> java, array, copy, null, null,

5. 향상된 for문

  • 반복 실행을 하기 위한 루프 카운터 변수와 증감식을 사용하지 않음
  • for문의 괄호()에는 배열에서 꺼낸 항목을 저장할 변수 선언과 콜론(:) 그리고 배열을 나란히 작성
  • for문의 반복 횟수배열의 항목 수
  • 💻 향상된 for문
package sec02.exam10;

public class AdvancedForExample {
	public static void main(String[] args) {
		int[] scores = {95, 71, 84, 93, 87};
		
		int sum = 0;
		for (int score : scores) {
			sum+=score;
		}
		System.out.println("점수 총합 = "+sum);
		
		double avg = (double) sum / scores.length;
		System.out.println("점수 평균 = "+ avg);
	}
}

>>> 점수 총합 = 430
>>> 점수 평균 = 86.0

 

2. 열거 타입

0. 열거 타입
: 한정된 값인 열거 상수 중에서 하나의 상수를 저장하는 타입

ex) 요일(월, 화, 수, 목, 금, 토, 일), 계절(봄, 여름 ,가을, 겨울)

1, 열거 타입 선언

  • 열거 타입 이름 정하기
    • 관례적으로 첫 글자를 대문자로 하고, 나머지는 소문자로 구성
      만약 여러 단어로 구성된 이름이라면 각 단어의 첫 글자는 대문자로 하는 것이 관례
  • 소스 파일 생성
    • 열거 타입 선언
      - 열거 타입을 선언하는 public enum 키워드를 반드시 소문자로 작성
      - 이때 열거 타입 이름은 소스 파일 이름과 대소문자가 모두 일치해야 함
    • 열거 상수 선언
      - 열거 타입의 값으로 사용됨
      - 모두 대문자로 작성
      - 여러 단어로 구성될 경우에는 단어 사이를 밑줄(_)로 연결
  • 💻 열거 타입 선언
package sec03.exam01;

public enum Week {
	MONDAY,
	TUESDAY,
	WEDNESDAY,
	THURSDAY,
	FRIDAY,
	SATURDAY,
	SUNDAY
}

2. 열거 타입 변수

  • 열거 타입 변수 선언
열거타입 변수;
  • 열거 상수 저장
    • 단독으로 사용할 수 없고 반드시 '열거타입.열거 상수' 형태로 사용
    • 열거 타입이 참조 타입이기 때문에, null 값도 저장 가능
    • 열거 객체로 생성
  • 💻 열거 타입과 열거 상수
package sec03.exam02;

import java.util.Calendar;

public class EnumWeekExample {
	public static void main(String[] args) {
		Week today = null;
		
		Calendar cal = Calendar.getInstance();
		int week = cal.get(Calendar.DAY_OF_WEEK);
		
		switch(week) {
		case 1:
			today = Week.SUNDAY; break;
		case 2:
			today = Week.MONDAY; break;
		case 3:
			today = Week.TUESDAY; break;
		case 4:
			today = Week.WEDNESDAY; break;
		case 5:
			today = Week.THURSDAY; break;
		case 6:
			today = Week.FRIDAY; break;
		case 7:
			today = Week.SATURDAY; break;
		}
		
		System.out.println("오늘 요일 : "+today);
		
		if (today == Week.SUNDAY) {
			System.out.println("일요일에는 축구를 합니다.");
		} else {
			System.out.println("열심히 자바 공부를 합니다.");
		}
	}
    
>>> 오늘 요일 : TUESDAY
>>> 열심히 자바 공부를 합니다.

 

3. 객체 지향 프로그래밍

0. 객체

(1) 정의 : 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있으면서 식별 가능한 것
(2) 객체 구성 요소

  • 속성 ➡ 필드
  • ex) 사람 - 이름, 나이
  • ex) 자동차 - 색깔, 모델명
  • 동작 ➡ 메소드
    ex) 사람 - 웃다, 걷다
    ex) 자동차 - 달린다, 멈추다

(3)객체 모델링 : 현실 세계의 객체를 소프트웨어 객체로 설계하는 것

1. 객체의 상호작용

객체들은 각각 독립적으로 존재하고, 다른 객체와 서로 상호작용을 하면서 동작한다.
객체들 사이의 상호작용 수단은 메소드이고, 객체가 다른 객체의 기능을 이용하는 것이 바로 메소드 호출이다.
객체의 상호작용은 객체 간의 메소드 호출을 의미한다.
매개값과 리턴값을 통해서 데이터를 주고 받는다.

2. 객체 간의 관계

객체 간의 관계는 크게 세가지로 분류된다.
(1) 집합 관계

  • 하나는 부품이고 하나는 완성품에 해당하는 관계
  • ex) 자동차는 엔진, 타이어, 핸들 등으로 구성된다.
  • 자동차와 부품들은 집합 관계라고 볼 수 있다.

(2) 사용 관계

  • 객체 간의 상호작용으로, 다른 객체의 메소드를 호출하여 원하는 결과를 얻어낸다.
  • ex) 사람은 자동차를 사용하므로 사람과 자동차는 사용 관계라고 볼 수 있다.
  • 사람은 자동차를 사용할 때 달린다, 멈춘다 등의 메소드를 호출하는 것이다.

(3) 상속 관계

  • 상위(부모) 객체를 기반으로 하위(자식) 객체를 생성하는 관계를 말한다.
  • 상위 객체는 종류를 의미하고, 하위 객체는 구체적인 사물에 해당한다.
  • ex) "자동차는 기계의 한 종류이다"에서 기계(상위)와 자동차(하위)는 상속 관계에 있다고 볼 수 있다.

3. 객체와 클래스

(1) 클래스

  • 설계도와 같은 존재
  • 객체를 생성하기 위한 필드와 메소드가 정의되어 있음
  • 클래스로부터 만들어진 객체를 인스턴스라고 부름

(2) 객체 지향 프로그래밍 개발 세단계
① 클래스 설계
② 설계된 클래스를 가지고 사용할 객체 생성
③ 생성된 객체 이용

4. 클래스 선언

(1) 식별자 작성 규칙

  • 하나 이상의 문자로 이루어져야 함
  • 첫 글자는 대문자로
  • 첫 글자에는 숫자 올 수 없음
  • $ _ 외의 특수 문자는 사용 불가
  • 자바 키워드 사용 불가
  • 영어 대소문자 구분
  • 서로 다른 단어가 혼합된 이름을 사용한다면, 각 단어의 첫 글자는 대문자로 작성

(2) 소스 파일 생성

  • 클래스이름.java

(3) 클래스 선언
❗반드시 소문자로 작성할 것❗

public class 클래스 이름 {
}

5. 객체 생성과 클래스 변수

클래스로부터 객체를 생성하려면 new 연산자를 사용하면 된다.
new는 클래스로부터 객체를 생성하는 연산자이다.
new 연산자 뒤에는, 클래스() 형태를 갖는 생성자가 온다.
new 연산자로부터 생성된 객체는 메모리 힙 영역에 생성된다.

  • 💻 클래스 선언
package sec01.exam01;

public class Student {
}
  • 💻 클래스로부터 객체 생성
package sec01.exam01;

public class StudentExample {
	public static void main(String[] args) {
		Student s1 = new Student();
		System.out.println("s1 변수가 Student 객체를 참조합니다.");
		
		Student s2 = new Student();
		System.out.println("s2 변수가 또 다른 Student 객체를 참조합니다.");
	}
}

>>> s1 변수가 Student 객체를 참조합니다.
>>> s2 변수가 또 다른 Student 객체를 참조합니다.

🔎 Student와 StudentExample 클래스의 용도
클래스에는 두 가지 용도가 존재한다.
하나는 다른 클래스에서 이용할 목적으로 설계된 라이브러리용, 다른 하나는 실행용이다.

6. 클래스의 구성 멤버

필드, 생성자, 메소드가 있다. 생략되거나 복수의 개수로 작성 될 수 있는 구성 요소이다.
(1) 필드

  • 객체의 데이터가 저장되는 곳
  • 생성자와 메소드 전체에서 사용되며, 객체가 소멸되지 않는 한 객체와 함께 존재

(2) 생성자

  • 객체 생성 시 초기화 역할 담당
  • new 연산자로 호출되는 특별한 중괄호 {} 블록
  • 메소드와 비슷하지만, 클래스 이름으로 되어 있고 리턴 타입이 없음

(3) 메소드

  • 객체의 동작에 해당하는 실행 중괄호 {} 블록
  • 메소드를 호출하게 되면 중괄호 블록에 있는 모든 코드들이 일괄적으로 실행됨
  • 객체 간의 데이터를 전달하는 수단
  • 필드를 읽고 수정하는 역할 & 다른 객체를 생성해서 다양한 기능 수행

 

4. 필드

0. 필드 정의

: 객체의 고유 데이터, 객체가 가져야 할 부품, 객체의 현재 상태 데이터를 저장하는 곳

1. 필드 선언

클래스 중괄호 {} 블록 어디서든 존재할 수 있다.
하지만, 생성자와 메소드 중괄호 {} 블록 내부에 선언된 것은 로컬 변수가 된다.
(1) 타입

  • 필드에 저장할 데이터의 종류 결정
  • 기본 타입(byte, short, int, long, float, double, boolean)과 참조타입(배열, 열거, 인터페이스) 모두 가능

(2) 초기값

  • 필드 선언 시 생략 가능
  • 초기값이 지정되지 않은 경우, 객체 생성 시 기본 초기값으로 설정
분류 타입 초기값
기본 타입 정수 타입 byte 0
char /u0000(빈 공백)
short 0
int 0
long 0L
실수 타입 float 0.0F
double 0.0
논리 타입 boolean false
참조 타입 배열 null
클래스(String 포함)
인터페이스

 

2. 필드 사용

필드값을 읽고 변경하는 작업이다.
클래스 내부의 생성자와 메소드에서 바로 사용이 가능하나, 클래스 외부에서 사용할 경우에는 반드시 객체를 생성하고 참조 변수를 통해 사용해야 한다.
도트(.) 연산자는 객체 접근 연산자이다.

  • 💻 Car 클래스 필드 선언
package sec02.exam01;

public class Car {
	//필드
	String company = "현대자동차";
	String model = "그랜저";
	String color = "검정";
	int maxSpeed = 350;
	int speed;
}
  • 💻 외부 클래스에서 Car 필드값 읽기와 변경
package sec02.exam01;

public class CarExample {
	public static void main(String[] args) {
		//객체 생성
		Car myCar = new Car();
		
		//필드값 읽기
		System.out.println("제작회사: "+myCar.company);
		System.out.println("모델명: "+myCar.model);
		System.out.println("색깔: "+myCar.color);
		System.out.println("최고속도: "+myCar.maxSpeed);
		System.out.println("현재속도: "+myCar.speed);
		
		//필드값 변경
		myCar.speed = 60;
		System.out.println("수정된 속도: "+myCar.speed);
	}
}

>>> 제작회사: 현대자동차
>>> 모델명: 그랜저
>>> 색깔: 검정
>>> 최고속도: 350
>>> 현재속도: 0
>>> 수정된 속도: 60
  • 💻 필드 자동 초기화
package sec02.exam02;

public class FieldInitValue {
	//필드
	byte byteField;
	short shortField;
	int intField;
	long longField;
	
	boolean booleanField;
	char charField;
	
	float floatField;
	double doubleField;
	
	int[] arrField;
	String referenceField;
}
  • 💻 필드값 출력
package sec02.exam02;

public class FieldInitValueExample {
	public static void main(String[] args) {
		FieldInitValue fiv=new FieldInitValue();
		
		System.out.println("byteField: " + fiv.byteField);
		System.out.println("shortField: " + fiv.shortField);
		System.out.println("intField: " + fiv.intField);
		System.out.println("longField: " + fiv.longField);
		System.out.println("booleanField: " + fiv.booleanField);
		System.out.println("charField: " + fiv.charField);
		System.out.println("floatField: " + fiv.floatField);
		System.out.println("doubleField: " + fiv.doubleField);
		System.out.println("arrField: " + fiv.arrField);
		System.out.println("referenceField: " + fiv.referenceField);
	}
}

>>> byteField: 0
>>> shortField: 0
>>> intField: 0
>>> longField: 0
>>> booleanField: false
>>> charField:

5. 생성자

0. 생성자 & 객체 초기화

  • 생성자 :  new 연산자로 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화 담당
  • 객체 초기화 : 필드를 초기화하거나 메소드를 호출해서 객체를 사용할 준비를 하는 것
    • new 연산자에 의해 생성자가 성공적으로 실행되면
      힙 영역에 객체가 생성되고
      객체의 번지가 리턴
      리턴된 객체의 번지는 클래스 변수에 저장

1. 기본 생성자

  • 모든 클래스는 생성자가 반드시 존재하며, 생성자를 하나 이상 가질 수 있음
  • 클래스 내부에 생성자 선언을 생략했다면,
    컴파일러는 중괄호 {} 블록 내용이 비어 있는 기본 생성자를 바이트 코드에 자동 추가
  • 클래스가 public으로 선언되면 기본 생성자도 public이 붙음
    클래스가 public 없이 선언되면 기본 생성자도 public이 붙지 않음
  • 클래스에 생성자를 선언하지 않아도 new 연산자 뒤에 기본 생성자를 호출해서 객체 생성 가능
  • 클래스에 명시적으로 선언한 생성자가 1개라도 있다면,
    컴파일러는 기본 생성자를 추가하지 않음

2. 생성자 선언

  • 생성자를 명시적으로 선언하는 이유
    : 객체를 다양한 값으로 초기화하기 위하여
  • 클래스에 생성자가 명시적으로 선언되어 있다면,
    반드시 선언된 생성자를 호출해서 객체 생성해야 함
  • 💻 생성자 선언
package sec03.exam01;

public class Car {
	//생성자
	Car(String color, int cc) {	
	}
}
  • 💻 생성자를 호출해서 객체 생성
package sec03.exam01;

public class CarExample {
	public static void main(String[] args) {
		Car myCar = new Car ("검정",3000);
	}
}

3. 필드 초기화

  • 필드를 선언할 때 초기값을 주는 방법
    • 동일한 클래스로부터 생성되는 객체들은 모두 같은 값을 갖게 됨
    • 객체 생성 후 초기값을 변경할 수 있지만, 객체 생성 시점에는 필드의 값이 모두 같음
  • 생성자에서 초기값을 주는 방법
    • 객체 생성 시점에 외부에서 제공되는 다양한 값들로 초기화되어야 하는 상황에 사용
    • 일반적으로 필드와 동일한 이름을 갖는 매개 변수를 사용
      ➡ 이 경우, 동일한 이름의 매개 변수가 사용 우선순위가 높기 떄문에 생성자 내부에서 해당 필드에 접근 불가
      ➡ 필드 앞에 this. 을 붙이면 됨
  • 💻 생성자에서 필드 초기화
package sec03.exam02;

public class Korean {
	//필드
	String nation = "대한민국";
	String name;
	String ssn;
	
	//생성자
	public Korean(String n ,String s) {
		name = n;
		ssn = s;
	}
}
  • 💻 객체 생성 후 필드값 출력
package sec03.exam02;

public class KoreanExample {
	public static void main(String[] args) {
		Korean k1 = new Korean("박자바","011225-1234567");
		System.out.println("k1.name : " + k1.name);
		System.out.println("k1.ssn : "+k1.ssn);
		
		Korean k2 = new Korean ("김자바", "930525-0654321");
		System.out.println("k2.name : " + k2.name);
		System.out.println("k2.ssn : " + k2.ssn);
	}
}

>>> k1.name : 박자바
>>> k1.ssn : 011225-1234567
>>> k2.name : 김자바
>>> k2.ssn : 930525-0654321

4. 생성자 오버로딩

  • 매개 변수를 달리하는 생성자를 여러 개 선언하는 것
  • 주의할 점
    매개 변수의 타입과 개수 그리고 선언된 순서가 똑같은 경우, 매개 변수 이름만 바꾸는 것은 생성자 오버로딩이 아님
  • 💻 생성자의 오버로딩
package sec03.exam03;

public class Car {
	//필드
	String company = "현대자동차";
	String model;
	String color;
	int maxSpeed;
	
	//생성자
	Car() {
	}
	
	Car(String model) {
		this.model = model;
	}
	
	Car (String model, String color) {
		this.model = model;
		this.color = color;
	}
	
	Car(String model, String color, int maxSpeed) {
		this.model = model;
		this.color = color;
		this.maxSpeed = maxSpeed;
	}
}
  • 💻 객체 생성 시 생성자 선택
package sec03.exam03;

public class CarExample {
	public static void main(String[] args) {
		Car car1 = new Car();
		System.out.println("car.company : " + car1.company);
		System.out.println();
		
		Car car2 = new Car("자가용");
		System.out.println("car2.company : "+ car2.company);
		System.out.println("car2.model : " + car2.model);
		System.out.println();
		
		Car car3 = new Car("자가용", "빨강");
		System.out.println("car3.company : "+ car3.company);
		System.out.println("car3.model : " + car3.model);
		System.out.println("car3.color : " + car3.color);
		System.out.println();
		
		Car car4 = new Car("택시", "검정", 200);
		System.out.println("car4.company : "+ car4.company);
		System.out.println("car4.model : " + car4.model);
		System.out.println("car4.color : " + car4.color);
		System.out.println("car4.maxSpeed : " + car4.maxSpeed);
		System.out.println();
	}
}

>>> car.company : 현대자동차
>>> 
>>> car2.company : 현대자동차
>>> car2.model : 자가용
>>> 
>>> car3.company : 현대자동차
>>> car3.model : 자가용
>>> car3.color : 빨강
>>> 
>>> car4.company : 현대자동차
>>> car4.model : 택시
>>> car4.color : 검정
>>> car4.maxSpeed : 200

5. 다른 생성자 호출: this()

  • 생성자의 오버로딩이 많아질 경우,
    필드 초기화 내용은 한 생성자에만 집중적으로 작성하고
    나머지 생성자는 초기화 내용을 가지고 있는 생성자를 호출하는 방법으로 개선 가능
  • this()
    • 다른 생성자를 호출하는 코드
    • 반드시 생성자의 첫 줄에서만 허용
    • 매개값은 호출되는 생성자의 매개 변수에 맞게 제공되어야 함
    • this() 다음에는 추가적인 실행문이 올 수 있음
  • 💻 다른 생성자를 호출해서 중복 코드 줄이기
package sec03.exam04;

public class Car {
	String company = "현대자동차";
	String model;
	String color;
	int maxSpeed;
	
	//생성자
	Car() {
	}
	
	Car(String model) {
		this(model, "은색", 250);
	}
	
	Car (String model, String color) {
		this(model, color, 250);
	}
	
	Car(String model, String color, int maxSpeed) {
		this.model = model;
		this.color = color;
		this.maxSpeed = maxSpeed;
	}
}
  • 💻 객체 생성 시 생성자 선택
package sec03.exam04;

public class CarExample {
	public static void main(String[] args) {
		Car car1 = new Car();
		System.out.println("car1.company : " + car1.company);
		System.out.println();
		
		Car car2 = new Car("자가용");
		System.out.println("car2.company : "+ car2.company);
		System.out.println("car2.model : " + car2.model);
		System.out.println();
		
		Car car3 = new Car("자가용", "빨강");
		System.out.println("car3.company : "+ car3.company);
		System.out.println("car3.model : " + car3.model);
		System.out.println("car3.color : " + car3.color);
		System.out.println();
		
		Car car4 = new Car("택시", "검정", 200);
		System.out.println("car4.company : "+ car4.company);
		System.out.println("car4.model : " + car4.model);
		System.out.println("car4.color : " + car4.color);
		System.out.println("car4.maxSpeed : " + car4.maxSpeed);
		System.out.println();
	}
}

>>> car1.company : 현대자동차
>>> 
>>> car2.company : 현대자동차
>>> car2.model : 자가용
>>> 
>>> car3.company : 현대자동차
>>> car3.model : 자가용
>>> car3.color : 빨강
>>> 
>>> car4.company : 현대자동차
>>> car4.model : 택시
>>> car4.color : 검정
>>> car4.maxSpeed : 200