자바의 정석

객체 지향 프로그래밍 기본 개념

야생늑대 2022. 4. 10. 00:45
반응형

 

1. 객체 지향 프로그래밍  OOP : Object-Oriented Programming

 1) 객체를 만들고 이를 조합하여 완성된 프로그램을 만드는 기법.

 2) 객체지향 언어 = 프로그래밍 언어 + 객체지향개념(규칙) 

   ↓부가설명

더보기

 80년 초 기존의 프로그래밍언어로 빠른 변화를 쫓아가지 못해 소프트웨어의 위기가 옴.

 해결책으로 객체지향 언어를 도입(절차적  -->객체지향)

  객체지향의 장점 -

   코드의 재사용성이 높고 유지보수가 용이, 중복코드 제거 = 코드를 한번만들면 다른곳에서 쉽게 사용할 수

  있고,  소프트웨어가 변경되어도 적은노력으로 대응가능하다.

  C언어에 객체지향개념을 추가한게 C++이다.  하지만 너무 어려워서 확산이 많이 되지 않았다.

 1996년 JAVA가 C++에서 잘안쓰는 기능을 떼어내 쉽게만들면서 일반화되기시작

 

 3)객체지향의 핵심개념 

    ▶ 캡슐화

    ▶ 상속

    ▶ 추상화

    ▶ 다형성

 

* 객체지향 개념 공부방법.  (자바 의정석 기준)

초기에는 객체지향언어를 배워서 프로그램을 만드는게 중요하지

왜 그런 개념이 생겼는지가 중요한게 아니다.

(스포츠에서도 왜 그런 규칙이 생겼는지를 생각하기보다는 단지 규칙을 외우는게 중요하듯이)

우선 무조건 객체지향의 개념(규칙)을 외우자!!

객체지향의 개념과 규칙을 외우고나서 이론이 부족한 것같다고 디자인패턴이나 객체지향개념에 대한 이론서를 보는 것 보다는 서블릿,스프링,안드로이드로 실습, 응용을 하면서 실수를 반복하고 경험을 쌓는게 좋다.

객체지향언어는 설계를 하는 언어기때문에? 이론을 이해하려기보다는 많은 경험을 통해 이해도가 높아지고 설계를 할 수

있게된다.    

너무쉽고 간단하게 설명되어있는 책을 보고는 힘들다.  

(쉽게 설명하기 위해 중요한 부분을 빼고 설명되어있는 책도 있음)

 

 

 

 

클래스와 객체

 

클래스 == 설계도         (객체를 만들기 위한 설계도 역할)

            == 데이터 + 함수   ( 작업과 계산에 관련된 데이터와 메소드를 묶어 놓은 것)

            == 사용자 정의타입  (원하는 타입을 직접 만들 수 있다.)

클래스의 정의 - 클래스란 객체를 정의해 놓은 것

클래스의 용도 - 클래스를 객체를 생성하는데 사용

 

객체의 정의 - 실제로 존재하는 것. 사물 또는 개념

객체의 용도 - 객체가 가지고 있는 기능과 속성에 따라 다름

 

클래스 객체
제품 설계도 제품
TV설계도 TV
붕어빵 기계 붕어빵

클래스는 제품의 설계도

객체는 제품 이라고 생각하면 된다.

 

클래스가 왜 필요한가?

*객체를 생성하기 위해

객체가 왜 필요한가?

*객체를 사용하기 위해

객체를 사용한다는 것은?

*객체가 가진 속성과 기능을 사용하려고

 

설계도는 왜 만드는가 제품을 쉽게 만들기 위해

tv를 만들려면 tv설계도가 필요하듯이

 

객체와 인스턴스

객체 :  모든 인스턴스를 대표하는 일반적 용어    

인스턴스  : 특정 클래스로부터 생성된 객체 (예 : Tv인스턴스)

거의 같은 말   

클래스  -----> 인스턴스(객체)      = 인스턴스화 (제품생성)

(설계도)               (제품)

 

 

 4) 객체란 물리적으로 존재하는 것. 추상적이면서 식별 가능한 자신의 속성을 가지고 있는 것.

     ex) 자동차, 자전거, 사람, 책, 학과, 강의, 주문 등.

 5) 객체는 속성과 기능으로 구성되어 있다. 

    ex) 객체 = TV

          TV의 속성 (IV=인스턴스변수=필드)   =  색깔, 전원상태, 채널, 불륨, 크기 등

          TV의 기능 (메소드)  =  켜기, 끄기, 볼륨 높이기, 볼륨 낮추기, 채널 변경하기 등

 

          프로그래밍에서 속성은 필드로 정의하고  기능은메소드로 정의한다.

 

 6) 객체들은 다른 객체와 서로 상호작용하면서 동작하는데 이 상호작용 수단이 메소드다.

 

 7) 객체의 상호작용은 객체 간의 메소드 호출을 의미하며 매개 값과 리턴 값을 통해서 데이터를 주고받는다.

 

    ※ 메소드 호출은 다음과 값은 형태를 갖는다

  리턴 값 = 객체.메소드(매개값1, 매개 값 2,...);

 

객체의 생성과 사용

1.객체의 생성

클래스명 변수명;                  // 클래스의 객체를 참조하기 위한 참조변수를 선언

변수명 = new 클래스명();     // 클래스의 객체를 생성 후, 객체의 주소를 참조변수에 저장

 

Tv t;           t  <--- 참조변수( 리모콘)    // Tv 클래스 타입의 참조변수 t를 선언

t = new Tv();         new Tv()  <--- 객체         // Tv인스턴스를 생성한 후, 생성된 Tv인스턴스의 주소를 t에 저장

Tv  t = new Tvv();

 

객체를 다루기 위해 참조변수가 필요 (참조변수가 없으면 객체를 다룰방법이 없다.)

new 연산자가 객체와 참조변수를 연결해 준다.

참조변수를 선언한 후에 객체와 연결하는 작업 필요.

* new 연산자로 객체를 만들고 참조변수 와 연결해준다.

 

2. 객체의 사용 (객체의 멤버(변수,메소드)를 사용)

t.channel = 7;   // Tv인스턴스의 멤버변수 channel의 값을 7로 한다.

t.channelDown(); //Tv인스턴스의 메서드 channelDown()을 호출한다.

 

t --> 0x100                    0x100   -->    color , power , channel   필드

                                                          power()

                                                          channelUp()

                                                          channelDown()  메소드

new Tv()   -->    new연산자가   힙영역? 의 0x100이라는 주소에  Tv() 객체를 생성하고 

t 참조변수에 저장한다.

Tv() 객체를 담기위해서는  Tv 타입의 참조변수 필요

 

Tv t1 = new Tv();

Tv t2 = new Tv();

t2 = t1;    을 저장 하게되면  t2의 메모리주소에 t1의 메모리주소가 저장되어 원래 t2의 주소에 저장되어있던 객체는 사용할 수 없기 때문에 메모리에서 제거된다.

 

자바는 GC 가비지 컬렉터가 더 이상 사용되지 않거나 사용할 수 없는 메모리를 찾아서 메모리에서 제거해서 메모리가 낭비되는 것을 방지한다.  그래서 우리는 필요할 때 만들어서 사용하기만 하면된다.

 

하나의 인스턴스를 여러 개의 참조변수가 가리키는 경우(가능)

여러 인스턴스를 하나의 참조변수가 가리키는 경우(불가능)

 

참조변수에는 메모리 주소가 저장된다.

기본타입은 값 자체가 저장

 

 

 8) 객체 지향 프로그래밍 개발은 세 가지 단계가 있다.

     1단계  :  클래스를 설계.

     2단계  : 설계된 클래스를 가지고 사용할 객체를 생성.

     3단계  : 생성된 객체를 이용한다.

 

▶ 클래스에는 객체를 생성하기 위한 필드와 메소드가 정의되어 있다. 

▶ 클래스로부터 만들어진 객체를 해당 클래스의 인스턴스(instance)라고 한다.  그리고 이 과정을 인스턴스화라고 한다. 

▶ 하나의 클래스로부터 여러 개의 인스턴스를 만들 수 있다.

 

 

 9) 현실의 객체를 소프트웨어 객체로 설계하는 것을 객체 모델링 (Object medeling)이라고 한다.

 

 10) 회원관리를 객체 모델링해보면 다음과 같다.

    회원관리의 필드는  아이디, 비밀번호, 이름, 주소를 선언

	private String mid; 		//아이디
	private String mpw;			//비밀번호	
	private String mname;		//이름
	private String maddr;		//주소

 

  그리고 회원관리(MemberManager) 객체에 필요한 메소드는 회원가입, 회원 탈퇴, 내 정보 보기 등이 있다.

  이 중에 회원가입(memberJoin) 기능을 작성하면 다음과 같다. 

	public class MemberManager {
    public void memberJoin() {
		if(loginId.equals("")) {			
			System.out.println("\n[회원가입]");
			
			System.out.print("아이디>>");		
			String inId = scan.next();
			System.out.print("패스워드>>");
			String inPw = scan.next();
			System.out.print("이름>>");
			String inName = scan.next();
			System.out.print("주소>>");
			String inAddr = scan.next();
			
			Members members = new Members();
			
			members.setMid(inId);
			members.setMpw(inPw);
			members.setMname(inName);
            members.setMaddr(inAddr);
            }
         }
     }

   이렇게 회원관리와 상품관리 , 주문관리 등을 객체 모델링하여 조합하면 쇼핑몰 운영에 사용할 수 있는 완성된

    프로그램이 된다.    (쇼핑몰 운영과 회원관리, 상품관리, 주문관리는 집합 관계라고 볼 수 있다.)

    

 11) 회원가입 기능을 다른 객체에서 메소드 호출하려면 다음과 같이 작성한다.

	public static void main(String[] args) {

		OrderManager manager = new OrderManager();
			
				manager.memberJoin();
            }

  ※ 객체 생성, 객체의 사용(메소드 호출 )

    ▶ 객체 생성 - OrderManager manager = new OrderManager();     

      OrderManager 클래스 타입의 참조 변수 manager를 선언하고(인스턴스화)   OrderManager인스턴스를 생성한 후, 

      OrderManager인스턴스의 주소를 manager에 저장. 

    ▶ 객체의 사용 - manager.memberJoin();     

     OrderManager인스턴스의 메소드 memberJoin()을 호출한다.

       

 

하나의 소스파일에 여러 클래스 작성

 

올바른 작성 예

 

Hello2.java  //소스파일
public class Hello2{}
	   class Hello3{}

public class가 있는 경우, 소스파일의 이름은 반드시 public class의 이름과 일치해야 한다.

 

Hello2.java  //소스파일
       class Hello2{}
	   class Hello3{}

public class가 하나도 없는 경우, 소스파일의 이름은 'Hello2.java', 'Hello3.java' 둘 다 가능하다.

 

잘못된 작성 예

Hello2.java  소스파일이름
public class Hello2 { }
public class Hello3 { }

하나의 소스파일에 둘 이상의 public class가 존재하면 안된다. 각 클래스를 별도의 소스파일에 나눠서 저장하던가 아니면 둘 중의 한 클래스에  public을 붙이지 않아야 한다.

Hello3.java 소스파일이름
public class Hello2 { }
	   class Hello3 { }

소스파일의 이름이 public.class의 이름과 일치하지 않는다.

소스파일의 이름을 'Hello2.java'로 변경해야 맞다.

hello2.java 소스파일이름
public class Hello2 { }
	   class Hello3 { }

소스파일의 이름과 public class의 이름과 일치하지 않는다.

대소문자를 구분하므로 대소문자까지 일치해야한다.

그래서, 소스파일의 이름에서 'h'를 'H'로 바꿔야 한다.

 

main 메소드가 들어있는 클래스의 이름과 소스파일의 이름이 같아야 main메소드가 실행된다.

다르면 에러가 나진 않지만 이클립스가 일치하는 클래스를 찾지못해 실행이 되지않는다.

 

 

 

 

 

객체의 배열   == 참조변수 배열

Tv tv1, tv2, tv3;       ->>    Tv[] tvArr = new Tv[3];

Tv[] tvArr = new Tv[3];  // 길이가 3인 Tv타입의 참조변수 배열

Tv클래스 타입의 참조변수 (Tv객체를 담을 수 있는) 3개가 만들어진다. 

객체가 담기는게 아니므로 바로 사용할 수 있는게 아니고 객체를 각 참조변수에 지정해서 저장해줘야 사용가능하다.

 

tvArr[0] = new Tv();
tvArr[1] = new Tv();
tvArr[2] = new Tv();

 객체를 생성해서 배열의 각 요소에 저장

 

Tv[] tvArr = { new Tv(), new Tv(), new Tv() };

한번에 초기화

 

1.변수 : 하나의 데이터를 저장할 수 있는 공간

2. 배열 : 같은 종류의 여러 데이터를 하나로 저장할 수 있는 공간 

  (배열의 한계 : 같은종류만 가능)

3. 구조체 : 서로 관련된(관계된) 여러 데이터(종류 관계X) 를 하나로 저장할 수 있는 공간

4. 클래스 : 데이터와 함수의 결합 ( 구조체 + 함수)

함수--> 메소드 --> 명령문 묶음 --> 작업, 계산  -> 주로데이터를 가지고 작업,계산하므로 관련된 데이터와 메소드를 묶어 놓은 것

 

클래스의 정의(2)

사용자 정의 타입 - 원하는 타입을 직접 만들 수 있다.

 

 

선언위치에 따른 변수의 종류

class Variables{
		int iv;             // 인스턴스 변수 (필드)                  -- 클래스영역
        static int cv;  	// 클래스 변수 (static변수, 공유변수)     --   
        
        void method()
        {
        	int lv = 0;		// 지역변수                    --  메소드 영역
        }
}

iv 에  static 을 붙이면   cv 가된다.    static + iv    --->  cv

 

클래스영역에는  선언문만 가능하다.(변수와 메소드선언)

메소드를 시그니처만 선언하면  메소드선언  

내부블록까지 포함하면  메소드 정의   라고한다.

그렇기 때문에 프린트 메소드나  연산식은 불가능.

선언문의 순서는 상관없다.

일반적으로 변수선언을 먼저한다.

 

 

변수의 종류 선언위치 생성시기
클래스 변수  클래스영역 클래스가 메모리에 올라갈 때
인스턴스 변수 인스턴스가 생성되었을 때
지역 변수 클래스 영역 이외의 영역
(메소드, 생성자, 초기화 블럭 내부)
변수 선언문이 수행되었을 때

메소드 블럭내부의 지역변수 

- 메소드가 호출되면  생성  메소드가 끝날 때까지 유효하다(그때까지만 살아있다.)     =  변수의 범위 ( scope라고한다.) 

메소드 종료시 GC에 의해 자동 제거

 

iv는 클래스 전체에서 사용가능

iv의 생성시기 -인스턴스가 생성되었을 때 (***제일중요)

객체 = iv를 묶어 놓은 것 ( 변수 여러개 묶어 놓은 것)

 

cv는 객체를 생성하지 않아도 자동으로 만들어짐 

클래스가 메모리에 올라갈 때 자동 생성.

 

cv 아무때나 사용가능

iv 객체가 만들어 졌을 때, 객체 생성시 사용 가능

lv 메소드가 호출되었을 때

 

iv  개별속성에 사용

cv  공통속성에 사용

 

iv는 객체가 생성될 때마다 객체에 맞게 변경해서 사용할 변수

cv는 어디서든 변경없이 같은 값으로 사용하는 변수

cv는 변수를 사용할 때 참조변수가아닌 클래스이름으로 가져와서 사용한다.

참조변수로 사용해도 가능하지만 iv로 오해할 수 있음.

구별하기위해 클래스이름으로 사용하는게 좋다.

개념적으로는 cv도 객체의 속성이지만, 공유하는것이기때문에

클래스의 모든객체가 공유하는것이기 때문에 객체에 있지않고  따로 만들어서 값을 하나만 유지해서 사용(메모리낭비방지)

 

메서드란?

1.문장들을 묶어 놓은 것.

   -작업 단위로 문장들을 묶어서 이름 붙인 것

 2. 값(입력)을 받아서 처리하고, 결과를 반환(출력)

3. 메서드와 함수는 같은 말이지만  (근본적으로 같음)  

  메서드는 객체지향개념에서 함수를 지칭하는 용어.

   메서드는 꼭 클래스안에 있어야한다.  함수는 그런제약이 없음(클래스에 독립적, 따로 존재할 수 있음

* 블랙박스라고도 함

 

메서드의 장점

-코드의 중복을 줄일 수 있다.

코드의 관리가 쉽다.

코드를 재사용할 수 있다.

코드가 간결해서 이해하기 쉬워진다.

 

메소드의 작성

-반복적으로 수행되는 여러문장을 메서드로 작성 

- 하나의 메서드는 한가지 기능만 수행하도록 작성

(코드를 유지 보수할 때 용이)

(최소의 의미있는 작업단위로 나눠놔야 재사용성이 높아진다.)

 

메서드 = 선언부 +구현부

반환타입 메서드이름 (타입 변수명, 타입 변수명, ...)          --   선언부
{ 
              // 메서드 호출시 수행될 코드                 --  구현부
}

int add (int a, int b)
{
     	int result = a + b;
        return result;          /호출한 메서드로 결과를 반환한다.
}

// int의 출력값은  0~1개만 가능
// 여러개의 값을 return (반환) 받기 위해서는 배열, 객체로 묶어서 줘야한다.
//반환타입이 없으면(0개) void로 반환타입지정   (void는 없다는 뜻)

 

지역변수 : 메서드 내에 선언된 변수

int add(int x, int y){
	int result = x + y;
    return result;
}

int multiply(int x, int y){
	int result = x * y;
    return result;
}

두개의 메소드가 변수명이 같지만 서로 다른 메서드블록내에서 사용되고 제거되므로 겹치지 않는다. 

 

메서드의 호출

 

메서드를 호출해야 블록내의 문장들이 실행된다.

메서드이름(값1, 값2, ...);  //메서드를 호출하는 방법

print99danAll();     //void print00danAll()을 호출

int result = add(3, 5);  //int add(int x, int y)를 호출하고, 결과를 result에 저장

int add(int x, int y) // (매개변수 : parameter, 복사본) {  
	int result = x + y;
    return result;
}

메서드를 호출한 쪽에서 준 값을 메서드에 전달하는 중간매개체 역할을 한다고해서  매개변수(parameter)라고 한다.

int result = add(3, 5 );   // (인수: argument, 원본)

 

return문

실행 중인 메서드를 종료하고 호출한 곳으로 되돌아간다.

void printGugudan(int dan){
 if(!(2<=dan && dan <= 9)){
 return;    // dan의 값이 2~9가 아닌경우, 호출한 곳으로 그냥 되돌아간다.
 }
 for(int i=1; i<=9; i++){
 			System.out.println("%d * %d = %d%n", dan, i, dan * i );
 }
 
 return;  //반환타입이 void 이므로 생략가능. 컴파일러가 변환과정에서 자동추가한다.
 
}

 

 

 

반환타입이 void가 아닌 경우, 반드시 return문 필요

int multiply(int x, int y){
	int result = x * y;
    
    return result;
}

int max(int a, int b){
	if(a > b)
    	return a;		//조건식이 참일 때만 실행된다.  return문이 없다는 에러발생
}

 

if문이 참일 때는 return문이 있지만  false일 때 return값이 없기 때문에 아래와 같이 작성해줘야한다.

int max(int a, int b){
	if(a > b)
    	return a;	
    else{
    	return b;
    }
}

 

return하는 반환값은  메소드 반환타입하고 일치해야한다.

* 메소드반환타입으로 자동형변환되는 타입도 사용가능

 (메소드의 반환타입이 int 이면 return 값에  char, byte, shot 타입의 값도 반환가능 )

 

 

호출스택 (call stack)

 

스택(stack) : 밑이 막힌 상자. 위에 차곡차곡 쌓인다.

모든 프로그래밍언어에서 공통적이면서 매우중요한 개념

기본형 매개변수와 참조형매개변수 차이, 예외처리  에대한 개념을 이해하기 위해 필요

메서드 수행에 필요한 메모리가 제공되는 공간

메서드가 호출되면 호출스택에 메모리 할당, 종료되면 해제

스택에서 아래 있는 메서드가 위의 메서드를 호출,

맨 위의 메서드 하나만 실행 중, 나머지는 대기중이 된다.

(하나의 스택에서는 하나의 메서드만 실행)

 

기본형 매개변수

 

기본형(8개) 매개변수 - 변수의 값을 읽기만 할 수 있다. (read only)

값이 저장되어있는 변수를 받는다.?

package Home_6_18;

class data {
		int x;
}

class Ex_data{
	
	public static void main(String[] args) {
		
		data d = new data();
		d.x = 10;
		System.out.println("main() : x = " + d.x);
		
		change(d.x);
		System.out.println("After change(d.x)");
		System.out.println("main() : x = " + d.x);
	}
	static void change(int x) {
		
		x = 1000;
		System.out.println("change() : x = " + x);
	}
}

 

참조형 매개변수

변수의 값을 읽고 변경할 수 있다. (read & write)  

객체를 저장하고 있는 참조변수의 주소를 받는다.

package Home_6_18;

class data2 {
		int x;
}

class Ex_data{
	
	public static void main(String[] args) {
		
		data2 d = new data2();
		d.x = 10;
		System.out.println("main() : x = " + d.x);
		
		change(d);
		System.out.println("After change(d)");
		System.out.println("main() : x = " + d.x);
	}
	static void change(data2 d) { //참조형 매개변수
		
		d.x = 1000;
		System.out.println("change() : x = " + d.x);
	}
}

 

참조형 반환타입

package Home_6_18;

class Data3 {
		int x;
}

class Ex_data{
	
	public static void main(String[] args) {
		
		Data3 d = new Data3();
		d.x = 10;
		
		Data3 d2 = copy(d);
		
		System.out.println("d.x ="+d.x);
		System.out.println("d2.x = " + d2.x);
	}
	static Data3 copy(Data3 d) { //새로운 객체 tmp를 생성한다.
		Data3 tmp = new Data3();
		
		tmp.x = d.x; //d,x의 값을 tmp.x에 복사한다.
		
		return tmp;  // 복사한 객체의 주소를 반환한다.
	}
}

 

static 메서드와 인스턴스 메서드

class MyMath2 {
	long a, b;
    
    long add(){ // 인스턴스 메서드
    	return a + b;
    }
    
    static long add(long a, long b) { // 클래스 메서드 (static 메서드)
    	return a + b;
    }
    
}

인스턴스 메서드

- 인스턴스 생성 후, '참조변수.메소드이름()' 으로 호출

- 인스턴스 멤버(iv, im) 와 관련된 작업을 하는 메서드

- 메서드 내에서 인스턴스 변수(iv) 사용 가능

 

static 메서드 (클래스메서드)

-객체생성없이 '클래스이름. 메서드이름()으로 호출

-인스턴스 멤버(iv, im) 와 관련없는 작업을 하는 메서드

-메서드 내에서 인스턴스 변수(iv) 사용불가

 

 

객체를 만들어 사용하는 이유는  iv(인스턴스변수 : 필드) 를 사용하기 위해서. ( 객체는 iv묶음)

 

static 메서드(클래스메서드) 는 iv없이 매개변수를 받아 lv로 사용해서 블록내부에서 값을 처리한다.

iv가 필요없는 메소드. 

iv가 필요없이 lv만으로 처리하는 작업이나 계산의 경우에는 클래스메서드를 사용한다.

 

하지만 iv 를 호출한 참조변수에 맞게 변환해서 값을 동적으로 사용해야하는 경우에는 인스턴스 메서드를 사용한다.

 

 변수에서 cv(클래스 변수: static )는 공통속성에 사용하고 iv에는 개별속성 을 사용하지만

메서드는 명령문 집합.  메서드는 공통이냐 공통아니냐 가 아니고 iv를 쓰냐 안쓰냐의 차이만 있음. 메소드 내용은 같음.

모든객체에 공통적인 메서드라 static을 붙이는게 아님

 

package Home_6_18;

public class TestClass2 {

	int iv;			//인스턴스 변수
	static int cv;  // 클래스 변수 ,  언제나 사용가능
	
	void instanceMethod() {			// 인스턴스 메서드  (객체 생성 후 호출가능)
                                    // 객체가 생성됐다는 것은 iv가 존재한다는 것
		System.out.println(iv);		// 인스턴스 변수를 사용할 수 있다.
		System.out.println(cv);		// 클래스 변수를 사용할 수 있다.
	}
	
	static void staticMethod() {  // static 메서드
		System.out.println(iv);   // 에러!! 인스턴스 변수를 사용할 수 없다.
		System.out.println(cv);   // 클래스 변수는 사용할 수 있다.
	}
	
}

static 메서드는 객체생성없이 호출가능.

static 메서드 블록내에  iv를 사용하면 iv를 사용할 수 있는 객체가 없음.  에러!

 

메서드 간의 호출과 참조

 

static 메서드는 인스턴스 메서드(im)를 호출할 수 없다.

	class TestClass{
		
		void instanceMethod() {		}	     	// 인스턴스 메서드
		static void staticMethod() {	}// static 메서드		
		
		void instanceMethod2() {		// 인스턴스 메서드
			instanceMethod();
			staticMethod();			
		}	     
		
		static void staticMethod2() {	//static 메서드
			instanceMethod();	//에러!!! 인스턴스메서드를 호출할 수 있다.
			staticMethod();		// static메서드는 호출 할 수 있다.
		}
		
	}

인스턴스 메서드를 호출했다는 것은 객체가 만들어졌다는 것 ( 객체가 있어야 im 호출가능)

그래서 호출한 인스턴스 메서드 블록내에서 다른 인스턴스 메서드를 호출가능

 

하지만 static메서드의 블록에는 인스턴스 메서드를 호출할 수 없다.

  항상 호출가능한 static 메서드의 블록내에 객체가 만들어져 있는지 아닌지 알 수가 없는 상태에서

 객체를 필요로 하는 인스턴스메서드가 존재하면 에러가 발생한다

(항상 호출가능해야하는데 조건(객체가 있는지 없는지)이 생겨버림).

 

 오버로딩

 

한 클래스 안에 같은 이름의 메서드 여러 개 정의하는 것

void println()
void println(boolean x)
void println(char x)
void println(char[] x)
void println( double x)
void println(float x)
void println(Object x)
void println(String x)

 

  • 자바에서는 컴파일러가 매개변수가 어떤타입인지 확인하고 거기에 맞는 메소드를 연결해준다.
  • 이렇게 오버로딩을 지원하기 때문에 메소드 이름 하나로 여러가지 일을 할 수 있다.
  • 오버로딩을 지원하지 않으면 메소드의 이름이 전부 달라져야하기때문에 외우기도 힘들고 번거롭다.
  • 오버로딩이 된다는 건 굉장한 장점.

 

오버로딩이 성립하기 위한 조건

1. 메서드 이름이 같아야한다.

2. 매개변수의 개수 또는 타입이 달라야 한다.

3. 반환타입은 영향없다.ㅠ

int add(int a, int b) {return a+b;}
int add(int x, int y) {rturn x+y;}
// add(int, int ) is already defined 에러 발생 (이미 정의 되어있다. (메서드 중복정의))

▶ 위와 같은 코드는 매개변수 개수와 타입이 같기 때문에 오버로딩이 아니다. 

long add(int a, long b) {return a+b;}
long add(long a, int b) {return a+b;}
//메소드이름이 같고 매개변수 타입이 다르므로 오버로딩 성립

위와 같은 코드는 오버로딩은 성립하지만, 메소드 호출 시 add(3, 3) 같은 식으로 호출하면 ambigue(애매한, 모호한) 에러가 발생한다. 컴파일러가 둘 중 어떤 메소드를 호출해야하는지 알 수 없기 때문에.

 

오버로딩의 올바른 예 - 매개변수는 다르지만 같은 의미의 기능수행

 

 메소드는 대부분 어떤 작업 을 수행하는 것이기 때문에 대부분 동사가 많이 사용된다.

 ex) add, println, round, random

이름이 같다는것은 하는 작업이 같다는 뜻

정확한 명칭은 메서드 오버로딩이지만, 자바에는 메서드오버로딩뿐이므로 줄여서 오버로딩이라고 한다.

(연산자 오버로딩도있지만, 우리가 따로 구현할 수는 없고 그저 해놓은 걸 사용할 뿐임

 ex.) + 연산자  -->  1. 부호 역할, 2. 덧 셈 역할,  3. 문자열 결합 역할   3가지기능을 한다.)

 

생성자, 기본 생성자

생성자(constructor)

인스턴스가 생성될 때마다 호출되는  '인스턴스 초기화 메서드'

인스턴스 생성시 수행할 작업(iv 초기화)에 사용

생성자가 존재하는 목적은 객체 초기화(iv초기화) 

편리하게 iv를 초기화하기위해서 사용

이름이 클래스 이름과 같아야 한다.

 

클래스이름(타입 변수명, 타입 변수명, ...) {
	//인스턴스 생성 시 수행될 코드,
    // 주로 인스턴스 변수의 초기화 코드를 적는다.
}
class Card{
	
    Card() {	// 매개변수 없는 생성자 (기본생성자)
    			// 인스턴스 초기화 작업
    }

	Card(String kind, int number) {	//매개변수 있는 생성자
    	//인스턴스 초기화 작업
    }

}

같은 이름의 생성자 Card --> 생성자오버로딩 

메서드 오버로딩과 같지만, 리턴타입이 없다.(항상 반환값이 없으므로 void 안붙임)

대입문이기때문에 결과를 반환받을 필요가 없음.

모든 클래스는 반드시 생성자를 가져야 한다. 

우린 따로 생성자를 만들어주지 않고 객체를 만들수 있었다. 그 이유는 객체를 만들 때 생성자가 하나도 없으면 컴파일러과정에서 매개변수가 없는 기본생성자를 컴파일러가 자동으로 만들어 준다.

생성자를 사용하는 이유는 객체(인스턴스)를 만들어 필드(iv)를 초기화해주기위해서다.

생성자 오버로딩을 하는 이유는 좀 더 편리하게 필드를 선택해서 초기화하기 위해서다.?

 

 

 

인스턴스(객체) 생성 후 iv초기화( 기본생성자)

Time t =new Time();
t.hour = 12;
t.minute = 34;
t.second = 56;

인스턴스 생성 시 iv초기화에 사용할 매개 값을 주고 생성자호출

Time t = new Time(12, 35, 56);

 

전의 코드보다 훨씬 직관적이고 편리하게 한줄로 생성가능

객체가 여러개면 줄이 더 줄어듬

 

	class Data_1{
		int value;		
	}	
	class Data_2{
		int value;
		
		Data_2(int x){ //매개변수가 있는 생성자
			value = x;
		}
	}
public class Ex6_11 {
	public static void main(String[] args) {
		Data_1 d1 = new Data_1();
		Data_2 d2 = new Data_2();		// The constructor Data_2() is undefined 
       
	}
}

 

 

  • 클래스 Data_1() 객체는 생성자가 없기 때문에 기본생성자를 컴파일러가 자동으로 만들어준다.
  • 매개변수가 있는 생성자가 있으면  기본생성자를 자동으로 만들어 주지않는다.
  • 그래서 기본생성자로 인터페이스를 만들려고 하면 기본생성자를 찾을 수 없다는 에러가 발생한다.

컴파일할 수 없는 문제 ? : 생성자 Data_2() 를 찾을 수 없다.

▶ Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
The constructor Data_2() is undefined       

Unresolved (미해결의, 대답되지 않은)

compile 어휘등급 ( 명사: compilation ) 
1.동사 (여러 출처에서 자료를 따와) 엮다, 편집[편찬]하다
2.동사 컴퓨터 명령어를 번역[컴파일]하다

 

매개변수가 있는 생성자

public class Car {

	String color;    	// 색상
	String gearType;	// 변속기 종류 - auto(자동), manual(수동)
	int door;			// 문의 개수
		
	Car(){ }  // 기본 생성자
	
	Car(String c, String g, int d) { //매개변수가 있는 생성자 
		color = c;
		gearType = g;
		door = d;
	}	
}

기본생성자를 통한 iv초기화

Car c = new Car();
	c.color = "white";
	c.gearType = "auto";
	c.door = 4;

매개변수가있는 생성자를 통한 iv초기화

Car c = new Car("white", "auto", 4);

 

기본생성자와 매개변수가 있는 생성자는 똑같은 일을 한다. 

단지 매개변수가 있는 생성자를 한번 만들어 놓으면 객체를 생성하는 쪽에서 위와 같이 코드가 간결해진다.

 

  1. Car클래스를 담을 수 있는 c 참조변수(메모리주소)가 만들어 지고 
  2. new 연산자가 객체를 생성하고
  3. Car() 객체를 초기화를 한다.
  4. iv(필드)에 값 대입

생성자 this()

생성자에서 다른 생성자 호출할 때 사용

다른 생성자 호출 시 첫 줄에서만 사용가능

 

public class Car2 {
	String color;    	// 색상
	String gearType;	// 변속기 종류 - auto(자동), manual(수동)
	int door;			// 문의 개수
	
	Car2(){
		this("white","auto", 4); //
		//Car2(String color, String gearType, int door){} 호출
	}
	Car2(String color){
		this(color, "auto", 4);
		//Car2(String color, String gearType, int door){} 호출
	}
	Car2(String color, String gearType, int door){
		this.color = color;
		this.gearType = gearType;
		this.door = door;
	}	
}

3개의 생성자가 하는일은 모두 iv초기화  = 하는일이 비슷함. 이름이 같음

서로 호출하는 일이 잦다. (코드의 중복을 제거할 수 있다.)

※ 코드의 중복은 반드시 제거되야한다.

중복되는 코드가 있다면 한쪽에서 호출하도록 변경하면 코드의 중복이 제거된다

 

참조변수 this 

인스턴스 자신을 가리키는 참조변수

this() 생성자와는 전혀 연관이 없다.

인스턴스 메서드(생성자 포함)에서 사용가능

지역변수(lv)와 인스턴스 변수(iv)를 구별할 때 사용

현재 클래스의 필드를 사용할 때 this 참조변수를 사용해서 현재 클래스의 필드라는 것을 인식시켜주어야 한다.

같은 클래스내에서는 lv와 iv의 이름이 다르면 this를 생략해도 된다.

하지만 이름이 같을 때는 iv와 lv를 구별하기 위해 this 참조변수를 사용해서 작성해준다.

 

this  인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있다.

        모든 인스턴스메서드에 지역변수로 숨겨진 채로 존재한다.

this(), this(매개변수) 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용한다.

* this와 this()는 비슷하게 생겼을 뿐 완전히 다른 것이다. this는 '참조 변수'이고, this()는 '생성자'이다.

 

변수의 초기화

지역변수(lv)는 수동 초기화 해야함 (사용전 꼭!!!!!)

class InitTest {
	int x;		// 인스턴스 변수
    int y = x;	// 인스턴스 변수


	void methiod1() {
    	int = i;	// 지역변수
        int j = i;	// 에러. 지역변수를 초기화하지 않고 사용
    }
}

 

iv는 객체가 생성될 때 자동으로각 타입의 기본값으로 초기화되어 메모리에 저장된다

자료형 기본값
boolean false
char '\u0000'
byte, short, int 0
long 0L
float 0..0f
double 0.0d 또는 0.0
참조형 null

 

lv는 메소드가 호출되서 작업하는 동안만 존재 생명주기가 짧다. 그런데 매번 0으로 초기화해서 사용하기에는

성능이 떨어진다. (메소드는 빨리 실행되고 빨리 제거되야한다.)

(호출스택은 재사용이 빈번한 메모리. 아주 짧은 시간동안 같은 메모리 공간을 여러 메소드가 사용한다.

그런데 메소드가 호출될 때마다 메모리 공간을 0로 초기화하면 성능이 떨어진다.

성능을 높이려고 항상 0 으로 초기화 하지않고 새로운 값으로 덮어쓴다. 

그런데 덮어씌어지는 값이 뭔지 모른다. (메소드마다 다름)  그래서 초기화하지않고 사용하면 에러가 발생한다.

그렇기 때문에 수동으로(직접) 초기화 해서 사용해줘야한다.

 

 

멤버변수(iv,cv)의 초기화

1. 명시적 초기화(=)   <-- (=)대입연산자 사용해서 선언 시 (간단한 초기화)

class Car{
	int door = 4;		// 기본형(primitive type) 변수의 초기화
    Engine e = new Engine();	// 참조형(reference type) 변수의 초기화
}

참조형 변수가 갖을 수 있는 값은    null 이나  객체주소   둘 중 하나다.

Engine e;   <---  참조변수만 있는거지 객체가 없는 것

선언할 때는 객체주소를 적어줘야한다.

Engine e =new Engine();    

객체주소를 적어줘야 인스턴스가 생성(초기화)이 된다.

 

2. 초기화 블럭      (복잡한 초기화, 블록내에 여러문장 넣기)

iv -> 인스턴스 초기화 블럭 : { }   (거의 사용하지 않음, iv는 보통 생성자를 통해 초기화)

cv -> 클래스 초기화 블럭 : static { }

 

3. 생성자    ( iv초기화, 복잡한 초기화)  

	Car2(String color, String gearType, int door){
		this.color = color;
		this.gearType = gearType;
		this.door = door;
	}

cv,iv 초기화

1. 자동 초기화  

2. 간단 초기화    (명시적 초기화)

3. 복잡 초기화    ( cv - static{ } ,   iv - 생성자(iv초기화) )

public class StaticBlockTest {
	static int [] arr = new int[10];	//명시적 초기화
	
	static { // 클래스 초기화 블럭 - 배열 arr을 난수로 채운다.
		for(int i=0; i<arr.length; i++) {
			arr[i] = (int)(Math.random()*10)+1;
		}
	}	
}

 

클래스 변수 초기화 시점 : 클래스가 처음 로딩될 때 단 한번

인스턴스 변수 초기화 시점 : 인스턴스가 생성될 때 마다

public class InitTest {
	static int cv = 1;	//명시적 초기화
	int iv = 1;
	
	static {  cv = 2; }	//클래스 초기화 블럭
	{	iv = 2; }		//인스턴스 초기화 블럭
	
	InitTest(){	// 생성자
		iv = 3;
	}		
}

InitTest it = new InitTest(); 객체 생성시 초기화 순서

클래스 초기화 인스턴스 초기화
기본값 명시적 초기화 클래스
초기화 블럭
기본값 명시적
초기화
인스턴스 초기화 블럭 생성자
cv == 0 cv == 1 cv == 2  cv == 2
 iv == 0
cv == 2
iv == 1
cv == 2
iv == 2
cv == 2
iv == 3
1 2 3 4 5 6 7

초기화 순서

1. cv초기화  ---> iv초기화

2. 자동초기화 ---> 간단초기화  ---> 복잡초기화

 

 

상속(Inheritance)

기존의 클래스로 새로운 클래스를 작성하는 것.(코드의 재사용)

두 클래스를 부모와 자식으로 관계를 맺어주는 것.

class 자식클래스 extends 부모클래스 {
	//...
}

자손은 조상의 모든 멤버를 상속받는다. (생성자, 초기화 블록 제외)

           (부모의 부모도 상속)

자손의 멤버 개수는 조상보다 적을 수 없다.(같거나 많다.)

 

Child 클래스에는 멤버가 없지만 Parent 클래스를 상속하고 있기 때문에 

Parent 의 멤버인 age를 사용할 수 있다,

 

자손의 변경은 조상에 영향을 미치지 않는다.

public class Parent {
	int age;
}

class Child extends Parent { 
	void play() {
		System.out.println("놀자~");
	}	
}

Child 클래스에 play메소드를 추가하여도 조상 클래스에는영향이 없다.

Child클래스에 멤버가 하나 추가되었을 뿐.

 

포함관계

포함(composite) 이란?

클래스의 멤버로 참조변수를 선언하는 것

작은 단위의 클래스를 만들고, 이 들을 조합해서 새로운 클래스를 만든다.

 

클래스 간의 관계 설정하기

 

상속관계  ' ~은 ~이다(is~)'

포함관계 '~은 ~을 가지고 있다. (has ~a)'

 

상속은 여러가지 제액이 많기 때문에 꼭 필요할 때만 사용

90%정도는 포함  을 사용한다.

※ 프로그래밍 = 설계 90% + 코딩 10% 

 (많이 그려보고 설계능력을 기르자)

 

단일 상속 (Single Inheritance)

Java는 단일 상속만 허용한다. (C++은 다중상속 허용)

(다중상속이 장점도 있지만, 단점이 많기때문에 Java는 포기하고 단일 상속만 허용)

ex) 부모들이 서로 같은 메소드이름을 사용하는데 블럭내용이 다르면 어떤 메소드를 수행할지 몰라 충돌 에러가 발생할 수 있다.)

class TvDVD extends Tv, DVD {   //에러  조상은 하나만 허용된다. Tv,DVD 둘 중 하나만 가능
		//...
}

 

 비중이 높은 클래스 하나만 상속관계로, 나머지는 포함관계로 한다. (다중상속의 효과)

▶ 비중이 높은 Tv클래스를 상속하고 DVD 클래스를 포함한다. 

 

Object클래스 - 모든 클래스의 조상

부모가 없는 클래스는 자동적으로 Object클래스를 상속받게 된다. (컴파일러 과정에서 자동추가)

 모든 클래스는 Object클래스에 정의된 11개의 메서드를 상속받는다.

toString(), equals(Object obj), hashCode(), ... 

상속계층도의 상위에는 항상 Object클래스가 존재 그래서 모든 클래스는 Object클래스를 상속받는다.

 

 

오버라이딩(overriding)  ; override(덮어쓰다)

상속받은 조상의 메서드를 자신에 맞게 변경하는 것

class MyPoint3{
	int x;
	int y;
	String getLocation() {
		return "x:" + x + ", y :"+y;
	}	
}

class MyPoint3D extends MyPoint3{
	int z;
	
	// 조상의 getLocation()을 오버라이딩
	String getLocation() {
		return "x : " + x + ", y : "+ y+", z : "+z;
	}	
}

public class OverrideTest {

	public static void main(String[] args) {
		MyPoint3D p = new MyPoint3D();
		p.x = 3;
		p.y = 5;
		p.z = 7;
		System.out.println(p.getLocation());
	}

}

상속을 받은 getLocation() 메소드의 iv에는 z가 없기 때문에 자신에게 맞게 메소드에 iv z를 추가해서 오버라이딩

 

오버라이딩의 조건

선언부(시그니처?)가 조상클래스의 메서드와 일치해야 한다.

 접근 제어자를 조상클래스의 메섣보다 좁은 범위로 변경할 수 없다.

예외는 조상클래스의 메서드보다 많이 선언할 수 없다.

 

오버로딩 과 오버라이딩은 관계가 없다.

오버로딩 (overloading) : 기존에 없는 새로운 메서드를 정의 하는 것(new)   ;상속과 관계없음

오버라이딩(overriding) : 상속받은 메서드의 내용을 변경하는 것(change, modify) ; 상속받은 것을 변경

public class Parent {
	void parentMethod() { }
}

class Child extends Parent { 
	void parentMethod() { }     	 // 1. 오버라이딩
	void parentMethod(int i) { }	 // 2. 오버로딩	
	
	void childMethod() { }			 // 3. 메서드 정의
	void childMethod(int i) { }		 // 4. 오버로딩
	void childMethod() { }			 // 5. 중복정의 ; 에러
}

 

참조변수 super  (= this: lv와 iv 구별에 사용)

객체자신을 가리키는 참조변수. 인스턴스 메서드(생성자)내에만 존재 (static 메서드내에 사용불가)

조상의 멤버를 자신의 멤버와 구별할 때 사용

public class Ex7_2 {
	public static void main(String[] args) {
		Child2 c = new Child2();
		c.method();
	}
}

class Parent2 { int x = 10; /* super.x */ }

class Child2 extends Parent2 {
	int x = 20; //this.x
	void method() {
		System.out.println("x=" + x);
		System.out.println("this.x=" + this.x);
		System.out.println("super.x="+ super.x);
	}	
}
// 결과값
x=20
this.x=20
super.x=10

this.x 는 자신의 변수를 

super.x 는 조상의 변수를 사용한다.

public class Ex7_2 {
	public static void main(String[] args) {
		Child2 c = new Child2();
		c.method();
	}
}

class Parent2 { int x = 10; /* super.x와 this.x 둘다 가능 */ }

class Child2 extends Parent2 {
	void method() {
		System.out.println("x=" + x);
		System.out.println("this.x=" + this.x);
		System.out.println("super.x="+ super.x);
	}	
}

// 결과값
x=10
this.x=10
super.x=10

자신의 변수가 없을 때는(중복되는 값이 없을 때 ) this.x 도 상속받은 조상의 변수를 가리킨다.(x가 하나뿐임)

 

super() - 조상의 생성자  

조상의 생성자를 호출할 때 사용

조상의 멤버는 조상의 생성자를 호출해서 초기화

생성자, 초기화블럭은 상속이 안된다.

public class Point {
	int x, y;

Point(int x, int y){
	this.x = x;
	this.y = y;
}
}

class Point3D extends Point{
	int z;
	
	Point3D(int x, int y, int z){
		this.x = x;  // 조상의 멤버를 초기화
		this.y = y;	 // 조상의 멤버를 초기화
		this.z = z;
	}
}

 

자손의 생성자에서 조상의 멤버를 초기화 하려고 하면 에러발생

※ Implicit super constructor Point() is undefined. Must explicitly invoke another constructor

올바른 초기화 방법

public class Point {
	int x, y;

Point(int x, int y){
	this.x = x;
	this.y = y;
}
}

class Point3D extends Point{
	int z;
	
	Point3D(int x, int y, int z){
		super(x, y); // 조상클래스의 생성자 Point(int x, int y)를 호출
		this.z = z;	 // 자신의 멤버를 초기화
	}
}

조상이 선언한 멤버를 초기화 하려면 조상의 생성자를 호출해서 조상의 생성자가 조상의 멤버를 초기화하도록 해야한다.

 

 생성자의 첫 줄에 반드시 생성자를 호출해야 한다.

그렇지 않으면 컴파일러가 생성자의 첫 줄에 super();를 삽입

 

 

패키지( package)

서로 관련된 클래스의 묶음

클래스는 클래스 파일(*.class), 패키지는 폴더. 하위 패키지는 하위 폴더

클래스의 실제 이름(full name)은 패키지를 포함. (java.lang.String)

rt.jar는 클래스들을 압축한 파일(JDK설치경로 \jre\lib에 위치)

rt --> runtime  자바프로그램이 실행하는데 필요한 클래스들을 묶어 놓은 것

jar -- > 클래스 파일묶음

자바9 부터 없어짐     modul개념이 생김

 

패키지의 선언

패키지는 소스파일의 첫 번째 문장으로 단 한번 선언

같은 소스 파일의 클래스들은 모두 같은 패키지에 속하게 된다.

패키지 선언이 없으면 이름 없는 (unnamed) 패키지에 속하게 된다.(default package)

bin폴더 - 컴파일된 클래스 파일(*.class)이 있는곳 (패키지루트. 패키지시작폴더의 상위폴더)

src폴더 - 소스파일(*.java)이 있는곳

 

클래스 패스(classpath)

클래스 파일(*.class)의 위치를 알려주는 경로(path)

환경변수 classpath로 관리하며, 경로간의 구분자는 ' ; ' 를 사용

classpath(환경변수)에 패키지의 루트를 등록해줘야 함.

 

import문

class ImportTest {
	java.util.Date today = new java.util.Date();
    //...
}

클래스를 사용할 때는 패키지 이름을 설정해야하지만, (어느 패키지에 있는지 알 수 없음.)

import문을 통해 패키지이름을 생략할 수 있다.

import java.util.Date;

class ImportTest{
	Date today = new Date();
}

컴파일러에게 클래스가 속한 패키지를 알려준다.

java.lang 패키지의 클래스는 자바의 기본패키지라서 import하지 않고도 사용할 수 있다.

(원래는 써줘야하지만, 생략해도 사용가능하도록 되어있다.)

String, Object, System, Thread ...

import문을 선언하는 방법은 다음과 같다.

import 패키지명.클래스명;

또는

import 패키지명.*;      -->  모든클래스

 

import문은 패키지문과 클래스 선언의 사이에 선언한다.

package com.codechobo.book;

import java.text.SimpleDateFormat;
import java.util.*;

public class Package Test {
	public static void main(String[] args){
    	//java.util.Date today = new java.util.Date();
        Date today = new Date();
        SimpleDateFormat Date = new SimpleDateForm("yyyy/MM/dd");
    }
}

import문의 선언

import문은 컴파일 시에 처리되므로 프로그램의 성능에 영향없음.

import java.util.Calendar;
import java.util.Date;
import java.util.ArrayList;
import.java.util.*;

두 코드는 컴파일러를 위한 것이기 때문에 프로그램의 성능에는 영향이 거의없다.

보통 개발자들은 * 를 사용해 전체명시해서 사용하는 경우가 많고.

라이브러리나 API를 만드는 개발자들은 정확히 명시하는 경우가 많다.

하지만 다음의 두코드는 서로 의미가 다르다.

import java.util.*;
import java.text.*;
import java.*;

java.*;  --->  java 패키지의 모든 클래스를 의미   ( 패키지는 포함되지않는다.)

그래서 util 패키지와, text 패키지의 모든 클래스를 지정하려면  정확히 패키지명을 명시해줘야한다.

 

이름이 같은 클래스가 속한 두 패키지를 import할 때는 클래스 앞에 패키지명을 붙여줘야 한다.

import java.util.*;  // java.sql.Date
import java.text.*;	 // java.util.Date

public class ImportTest {
	public static void main(String[] args){
    	java.util.Date today = new java.util.Date();  (어떤패키지의 클래스인지 명시
    }
}

 

static import문

static멤버를 사용할 때 클래스 이름을 생략할 수 있게 해준다.

import static java.lang.Integer.*;		// Integer클래스의 모든 static메서드
import static java.lang.Math.random;	// Math.random()만. 괄호 안붙임.
import static java.lang.System.out;		// System.out을 out만으로 참조가능

System.out.println(Math.random());  -->>  out.println(random());
import static java.lang.System.out;
import static java.lang.Math.*;

class Ex7_6{
public static void main(String[] args) {
	//System.out.println(Math.random());
    out.println(random());
    
    //System.out.println("Math.PI : + Math.PI);
    out.println("Math.PI : " + PI);
}
}

사용하는 이유

코드가 길어졌을 때 클래스이름도 거추장스러울 수 있음 

import문을 통해 코드를 짧게 할 수 있다.

하지만 클래스이름이 있는게 명확히 알 수 있기 때문에 꼭 필요할 때만 사용하는 것이 좋다.

 

제어자 (modifier)

 

클래스와 클래스의 멤버(멤버 변수, 메서드)에 부가적인 의미 부여

접근 제어자   public, protected, (default), private

그 외 static, final, abstract, native, transient, synchrorized, volatile, strictfp)

 

하나의 대상에 여러 제어자를 같이 사용 가능(접근 제어자는 하나만)

public class ModifierTest{
	public static final int WIDTH = 200;
    
    public static void main(String[] args){
    	System.out.println("WIDTH="+WIDTH);
    }
}

순서는 상관없다.  보통 접근제어자를 맨 앞에 작성한다. (관례적)

 

static  (클래스의, 공통적인)

제어자 대상 의미
static 멤버변수 -모든 인스턴스에 공통적으로 사용되는 클래스 변수가 된다.
-클래스 변수는 인스턴스를 생성하지 않고도 사용 가능하다.
-클래스가 메모리에 로드될 때 생성된다.
메서드 -인스턴스를 생성하지 않고도 호출이 가능한 static 메서드가 된다.
-static메서드 내에서는 인스턴스 멤버들을 직접 사용할 수 없다.
class StaticTest {
	static int width = 200;   CV(클래스 변수) = static 변수
    static int height = 120;	CV(클래스 변수) = static 변수
    
    static {
    	// static변수의 복잡한 초기화 수행
    }
    
    static int max(int a, int b){  //클래스 메서드(static메서드)
    return a > b ? a : b;
    }
    
}

 

final - 마지막의, 변경될 수 없는

 

제어자 대상 의미
final 클래스 변경될 수 없는 클래스, 확장될 수 없는 클래스가 된다.
그래서 final로 지정된 클래스는 다른 클래스의 조상이 될 수 없다.
메서드 변경될 수 없는 메서드, final로 지정된 메서드는 오버라이딩을 통해 재정의 될 수 없다.
멤버변수 변수 앞에 final이 붙으면, 값을 변경할 수 없는 상수가 된다.
지역변수

상속계층도의 제일 마지막이라는 의미  ( 자식(자손)이 없음 

대표 final 클래스  = String, Math      (보안문제 때문에 ; )

final class FinalTest {			 	// 조상이 될 수 없는 클래스
	final int MAX_SIZE = 10;		// 값을 변경할 수 없는 멤버변수(상수)
    
    final void gerMaxSize() {		// 오버라이딩할 수 없는 메서드(변경불가)
    	final int LV = MAX_SIZE;	// 값을 변경할 수 없는 지역변수(상수)
        return MAX_SIZE;
    }
}

abstract  (추상의, 미완성의)

제어자 대상 의미
abstract 클래스 클래스 내에 추상 메서드가 선언되어 있음을 의미한다.
메서드 선언부만 작성하고 구현부는 작성하지 않은 추상 메서드임을 알린다.
abstract class AbstractTest {	// 추상 클래스(추상 메서드를 포함한 클래스)
 abstract void move();  		// 추상 메서드(구현부가 없는 메서드) 
}

미완성 메서드 ( 선언부는 있는데 구현부가 없음) = 미완성 클래스

AbstractTest a = new AbstractTest();  // 에러. 추상 클래스의 인스턴스 생성불가

객체(인스턴스)생성 불가.,  미완성 클래스기 때문에

※ 추상클래스를 상속받아서 완전한 클래스(구상 클래스)를 만든 후에 객체생성 가능

 

접근제어자(access modifier)

 

private  같은 클래스 내에서만 접근이 가능하다.

(default) 같은 패키지 내에서만 접근이 가능하다.

protected 같은 패키지 내에서. 그리고 다른 패키지의 자손클래스에서 접근이 가능하다.

public 접근 제한이 전혀 없다.

제어자 같은 클래스 같은 패키지 자손 클래스 전체
public O O O O
protected O O O  
(default) O O    
private O      
접근제한없음 같은패키지 + 자손(다른패키지) 같은 패키지 같은  클래스
         public                       >              protected                           >                  (default)                    >            private

class 앞에 붙일 수 있는 접근자는  public, (default)  두개 뿐.

멤버는 접근자 전부 사용가능.

public		class AccessModifierTest {
(default)		int iv;				// 멤버 변수 (인스턴스 변수)
        		static int cv;		// 멤버 변수 (클래스 변수)
public
protected		void method() {  }
(default)
}
package pkg1;

class MyParent {
	private 	int prv;	// 같은 클래스
    			int dft;	// 같은 패키지
    protected 	int prt;	// 같은 패키지 + 자손(다른 패키지)
    public		int pub;;	// 접근제한 없음.
    
    public void printMembers() {
    	System.out.println(prv);	// OK
    	System.out.println(dft);	// OK
        System.out.println(prt);	// OK
        System.out.println(pub);	// OK        
    }   
}

public class MyParentTest {
	public static void main(String[] args) {
    	MyParent p = new MyParent();
        System.out.println(p.prv);	// 에러
       	System.out.println(p.dft);	// OK
       	System.out.println(p.prt);	// OK
       	System.out.println(p.pub);	// OK
        }
}

 

 

private 접근자는 같은 클래스내에서만 사용가능한데 다른 클래스에서 iv로 사용하려고 해서 에러가 발생

다른패키지에서 사용

package pkg2;

class MyChild extends MyParent {
	public void printMembers() {
  		System.out.println(prv);	// 에러
    	System.out.println(dft);	// 에러
        System.out.println(prt);	// 에러
        System.out.println(pub);	// 에러            
        
}

부모 클래스가 접근제어자가 없으니 기본 접근제어자인 default 기 때문에 다른 패키지에서 상속할 수 없다.

상속하려면 해야할 작업이 많다.

1. 부모클래스를 public으로 변경해야한다.

2. 그리고 하나의 소스코드에서 public 는 한번만 사용가능하기때문에 부모클래스가 있는 패키지의  다른 클래스의

public접근제어자를 제거한다.

3. 소스파일의 이름과 public클래스의 이름이 같아야하기 때문에 변경해준다.

4. 패키지가 다르기 때문에 자식클래스가 있는 패키지에 부모클래스의 패키지를 import 해준다.

(import를 하지않고 부모클래스앞에 패키지명을 적어줘도된다.   pkg1.MyParent

5. 이렇게 해주고나면 protected(상속하는 관계기 때문에 가능)와, public 접근제어자인 멤버를 사용가능하다.

 

 

 

 

반응형

'자바의 정석' 카테고리의 다른 글

인스턴스 멤버와 정적 멤버  (0) 2022.04.15
메소드 Method  (0) 2022.04.12
생성자 Constructor  (0) 2022.04.12
필드 Field  (0) 2022.04.11
클래스 Class  (0) 2022.04.11