JAVA/이것이 자바다

이것이 자바다 ch 6 클래스

본이qq 2022. 9. 5. 14:55

1.객체

 - 객체는 각각 독립적으로 존재하고, 다른 객체와 상호 작용을 하면서 동작한다.

 - 객체들 사이의 상호작용 수단은 메소드이다. 

 - 객체는 개별적으로 사용될 수 있지만, 대부분 다른 객체들과 관계를 맺고 있다. 

2.객체 지향 프로그래밍의 특징 

 - 캡슐화, 상속, 다형성 

 1) 캡슐화

   -객체의 필드, 메소드를 하나로 묶고 실제 구현 내용을 감추는 것을 말한다. 외부 객체는 객체 내부의 구조를 알지 못하며 객체가 노출해서 제공하는 필드와 메소드만 이용할 수 있다. (외부의 잘못된 사용으로 손상되는 것을 막기 위해)

 2) 상속

   - 상속은 상위 객체를 재사용해서 하위 객체를 쉽고 빨리 설계할 수 있도록 도와주고, 이미 잘 개발된 객체의 코드를 사용해서 새로운 객체를 만들기 때문에 코드의 중복을 줄여준다. 

 3) 다형성

   - 다형성은 같은 객체이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질을 말한다. 

   - 다형성은 하나의 타입에 여러 객체를 대입함으로써 다양한 기능을 이용할 수 있도록 해준다. (부모 클래스 또는 인터페이스의 타입 변환)

   - 부모 타입에는 모든 자식 인스턴스가 대입 가능 // 인터페이스 타입에는 모든 구현 객체가 대입 가능 

   - 다형성의 효과로 객체는 부품화가 가능하다. 

 

3. 객체와 클래스

- 메모리에서 사용하고 싶은 객체가 있다면 우선 설계도로 해당 객체를 만드는 작업이 필요하다.

- 자바에서는 설계도가 바로 클래스이다. 클래스에는 객체를 생성하기 위한 필드와 메서드가 정의되어 있다. 

- 클래스로부터 만들어진 객체를 해당 클래스의 인스턴스라고 한다. 

- 객체 지향 프로그래밍의 3단계 : 클래스를 설계한다 -> 설계된 클래스를 가지고 객체를 생성한다 -> 그 객체를 이용한다.

4.클래스 선언

- 사용하고자 하는 객체를 구상한다. 

- 그 객체의 대표 이름을 하나 정하고 이것을 클래스 이름이라고 한다. 

- 클래스이름을 정했다면 '클래스이름.java'로 소스 파일을 생성한다

- 소스파일을 생성했다면 다음과 같이 클래스를 선언한다. 

   public class 클래스이름{
           

      }
- 일반적으로 소스 파일 하나당 하나의 클래스를 선언하지만 두 개 이상의 클래스도 선언이 가능하다. 

  (다만 소스파일의 이름과 동일한 이름의 클래스에만 public 을 붙일 수 있다)

 

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

- 클래스를 선언한 다음, 컴파일했다면 (이클립스에서는 저장) 클래스로부터 객체를 생성할 수 있다. 

- 클래스 변수 = new 클래스();

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 객체와 s2객체는 비록 같은 클래스로부터 생성되었지만, 각각의 객체는 자신만의 고유한 데이터를 가지면서 메모리에서 활동한다.

    완전히 독립된 서로 다른 객체이다.

 

 

6. 클래스의 구성 멤버 

- 필드, 생성자, 메소드 

- 필드 : 필드는 객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳이다. 

- 생성자 : 객체 생성시 초기화를 담당한다. 클래스 이름으로 되어있고 리턴값이 없다. 

- 메소드 : 메소드를 호출하면 중괄호 블록 안에 있는 코드들이 일괄적으로 실행이 된다. 

  메소드는 객체 간의 데이터 전달 수단이다. 외부로부터 매개값을 받을 수도 있고, 실행 후 어떤 값을 리턴할 수도 있다. 

 

 

7.필드

- 필드의 선언은 클래스의 중괄호 블록 어디에서든 존재할 수 있다.

- 생성자 선언과 메소드 선언의 앞뒤 어떤 곳에서도 필드 선언이 가능하지만, 생성자와 메소드의 중괄호 블록 내에서는 불가능하다. 

  생성자와 메소드의 블록 내부에 선언된 것은 모두 '로컬 변수'이다. 

 

8.생성자

- 클래스 내부에 생성자 선언을 생략했다면, 컴파일러는 중괄호 블록 내용이 비어있는 기본생성자(디폴트 생성자)를 자동 추가한다 

- 생성자 선언

 

클래스(매개변수 선언, ...){
	//객체의 초기화 코드
}

 

- 클래스에 생성자가 명시적으로 선언되어 있을 경우에는 반드시 선언된 생성자를 호출해서 객체를 생성해야한다. 

 

9.필드 초기화

- 객체가 생성될때 필드는 기본 초기값으로 초기화된다.

-만약 다른 값을 주고 싶다면 하나는 필드를 선언할때 초기값을 주는방법이고, 하나는 생성자에서 초기값을 주는 방법이다. 

 

10.생성자 오버로딩 

-생성자 오버로딩이란 매개변수를 달리하는 생성자를 여러 개 선언하는 것을 말한다. 

public class Car{
	Car(){...}
    Car(String model){...}
    Car(String model, String color){...}
    Car(String model, String color, int maxSpeed){...}
}

- 생성자 오버로딩시 주의할 점은 매개변수의 타입과 개수 그리고 선언된 순서가 똑같을 경우, 매개변수의 이름만 바꾸는 것은 생성자 오버로딩이라고 볼 수 없다. 

Car(String model, String color){...}
Car(String color, String model){...}

 

11. 다른 생성자 호출 (this())

-this()는 자신의 다른 생성자를 호출하는 코드로 반드시 생성자의 첫줄에서만 허용된다. 

-this()의 매개값은 호출되는 생성자의 매개변수 타입에 맞게 제공해야한다. 

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;
       }

 

 

 

12.메소드

- 메소드 선언은 선언부(리턴타입, 메소드이름, 매개변수선언)와 실행 블록으로 구성된다. 

 

리턴타입 메소드이름([매개변수 선언, ...]){

          실행할 코드를 작성하는 곳 

}

 

<매개변수의 수를 모를 경우>

- 매개변수를 배열 타입으로 선언한다

  int sum1(int[] values){ }

int [] values = {1,2,3};
int result = sum1(values);
int result = sum1(new int[] {1,2,3,4,5});

-> 매개변수를 배열 타입으로 선언하면 메소드를 호출하기 전에 배열을 생성해야하는 불편함이 있다. 

-그래서 리스트만 넘겨주는 방법도 있다

int sum2(int ... values){ }

int result = sum2(1,2,3);
int result = sum2(1,2,3,4,5);
int [] values = {1,2,3};
int result = sum1(values);
int result = sum1(new int[] {1,2,3,4,5});

-> ...으로 선언된 매개변수의 값은 위처럼 리스트로 나열해줘도 되고, 배열을 직접 매개값으로 사용할 수도 있다. 

 

 

 

 

13. 

<리턴값이 있는 메소드 >

-메소드 선언에 리턴 타입이 있는 메소드는 반드시 리턴문을 사용해서 리턴값을 지정해야 한다. 

 만약 return 문이 없다면 컴파일 오류가 발생한다. return 문이 실행되면 메소드는 즉시 종료된다. 

-return문의 return 값은 리턴 타입이거나 리턴 타입으로 변환될 수 있어야 한다. 

 예를 들어 return 타입이 int인 plus() 메소드에서 byte, short, int 타입의 값이 리턴되어도 상관없다. byte와 short는 int로 자동 타입 변환되어 리턴되기 때문이다. 

 

<리턴값이 없는 메소드>

- void로 선언된 리턴값이 없는 메소드에서도 return 문을 사용할 수 있다. 

return;

위와 같이 return 문을 사용하면 메소드 실행을 강제 종료시킨다. 

 

 

14.메소드 오버로딩

- 클래스 내에 같은 이름의 메소드를 여러 개 선언하는  것을 메소드 오버로딩이라고 한다. 

- 메소드 오버로딩의 조건은 매개 변수의 타입, 개수, 순서 중 하나가 달라야한다.

-메소드 오버로딩이 필요한 이유는 매개값을 다양하게 받아 처리할 수 있도록 하기 위함이다. 

-메소드 오버로딩 시 주의할 점은 매개 변수의 타입과 개수, 순서가 똑같을 경우 매개 변수 이름만 바꾸는 것은 메소드 오버로딩이라고 볼 수 없다. 또한 리턴 타입만 다르고 매개 변수가 동일하다면 이것 또한 메소드 오버로딩이 아니다. 

 

 

15.인스턴스 멤버와 this

-인스턴스 멤버란 객체를 생성한 후 사용할 수 있는 필드와 메소드를 말하는데 이들을 각각 인스턴스 필드, 인스턴스 메소드 라고 부른다. 

public class car{
	//필드
    int gas;
    
    //메소드
    void setSpeed(int speed){...}
}

gas필드와 setSpeed 메소드는 인스턴스 멤버이기 때문에 외부 클래스에서 사용하기 위해서는 우선 Car 객체(인스턴스)를 먼저 생성하고 참조변수 myCar 또는 yourCar로 접근해야한다. 

Car myCar = new Car();
myCar.gas = 10;
myCar.setSpeed(60);

Car yourCar = new Car();
yourCar.gas = 20;
yourCar.setSpeed(80);

 

-객체 외부에서 인스턴스 멤버에 접근하기 위해 참조변수를 사용하는 것처럼 마찬가지로 객체 내부에서도 인스턴스 멤버에 접근하기 위해 this 를 사용할 수 있다. 주로 생성자와 메소드의 매개 변수 이름이 필드와 동일한 경우, 인스턴스 멤버인 필드임을 명시하고자 할 때 사용된다. 

public class car{
	//필드
    String model;
    int speed;
    
    //생성자
    Car(String model){
    	this.model = model;
    }
    
    //메소드
    void setSpeed(int speed){
    	this.speed = speed;
    }
    
    void run(){
    	for(int i=10; i<=50; i+=10){
        	this.setSpeed(i);
            System.out.println(this.model + "가 달립니다.(시속:" + this.speed + "km/h");
        }
    }
  }

 

 

16.정적 멤버와 static

-정적 멤버는 클래스에 고정된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메소드를 말한다. 

-이들을 각각 정적 필드, 정적 메소드라고 부른다. 

-정적 멤버는 객체(인스턴스)에 소속된 멤버가 아니라 클래스에 소속된 멤버이기 때문에 클래스 멤버라고도 한다.

 

17.정적 멤버 선언

-필드와 메소드 선언 시 static 키워드를 추가적으로 붙이면 된다. 

public class 클래스 {
	//정적 필드 
    static 타입 필드[= 초기값];
    
    //정적 메소드
    static 리턴타입 메소드(매개변수 선언....,){...}
}

 

- 정적 필드와 정적 메소드는 클래스에 고정된 멤버이므로 클래스의 로딩이 끝나면 바로 사용할 수 있다. 

- '객체마다' 가지고 있어야할 데이터라면 인스턴스 필드로 선언하고, 객체마다 가지고 있을 필요성이 없는 '공용적인' 데이터라면 정적 필드로 선언하는 것이 좋다. 

-예를 들어 원의 넓이나 둘레를 구할 때 필요한 파이는 공용적인 데이터이므로 정적 멤버로 선언하는 것이 좋다

-메소드의 경우는 인스턴스 필드를 사용하는 메소드라면 인스턴스로, 인스턴스 필드를 이용하지 않는다면 static 메소드로 선언하는 것이 좋다. (예: Calculator의 덧셈 뺄셈 기능의 메소드는 외부에서 주어진 매개값을 가지고 수행하므로 static, 클래스 내에 인스턴스 필드인 색깔을 변경하는 메소드는 인스턴스 메소드로 선언한다.

 

 

18.정적 멤버의 사용

- 클래스이름.필드;

  클래스이름.메소드(매개값...); 으로 사용한다.

 

 

19.정적 초기화 블록

- 정적 필드는 다음과 같이 필드 선언과 동시에 초기값을 주는 것이 보통이다. 

static double pi = 3.14159;

- 그러나 계산이 필요한 초기화 작업이 있을 수 있다. 

  인스턴스 필드는 생성자에서 초기화 하지만, 정적 필드는 객체 생성 없이도 사용이 가능해야 하므로 생성자로 초기화할 수 없다. 

- 따라서 자바는 정적 필드의 초기화 작업을 위해 정적 블록을 제공한다. 

static{
	...
 }

- 위와 같은 형태의 정적 블록은 클래스 내에 여러개가 선언되어도 괜찮다.

public class Television{

	static String company = "Samsung";
    static String model = "LCD";
    static String info;
    
    static{
    	info = company + "-" + model;
     }

}

-> info 필드는 정적 블록에서 company와 model값을 서로 연결해서 초기값으로 설정한다. 

 

<정적 메소드와 블록 사용시 주의할 점>

-정적 멤버들은 객체가 없어도 실행된다는 특징 때문에, 이들 내부에 인스턴스 필드나 인스턴스 메소드를 사용할 수 없다. 

-또한 객체 자신의 참조인 this 키워드도 사용이 불가능하다. 

-정적 메소드와 정적 블록에서 인스턴스 멤버를 사용하고 싶다면 다음과 같이 객체를 먼저 생성하고 참조 변수로 접근해야한다.

static void Method3(){
	ClassName obj = new ClassName();
    obj.field1 = 10;
    obj.method();  //ClassName 클래스 내에서 field1과 method()는 인스턴스 멤버이다.
}

 

-main() 메소드에도 동일한 규칙이 적용된다. main()메소드도 정적 메소드이기때문에 객체 생성없이 인스턴스 멤버를 사용할 수 없다.

(객체를 먼저 생성한 후에 사용해야함)

 

 

 

20.싱글톤 

- 전체 프로그램에서 단 하나의 객체만 만들도록 보장해야할 때, 이 객체를 싱글톤이라고 한다. 

- 즉 클래스 외부에서 new 연산자로 생성자를 호출할 수 없도록 막아야 한다. (생성자가 호출된 횟수만큼 객체가 생성되기 때문에)

public class 클래스{
	//정적 필드
    private static 클래스 singleton = new 클래스();
    
    //생성자
    private 클래스(){}
    
    //정적 메소드
    static 클래스 getInstance() { return singleton;}
}

-외부에서 객체를 얻는 유일한 방법은 getInstance() 메소드를 호출하는 방법이다. getInstance() 메소드는 단 하나의 객체만 리턴하기 때문에 아래 코드에서 변수1과 변수2는 동일한 객체를 참조한다.

클래스 변수1 = 클래스.getInstance();
클래스 변수2 = 클래스.getInstance();

->heap 영역에는 싱글톤이라는 이름의 객체가 1개 있고, getInstance메소드로 리턴받은 객체 또한 이 싱글톤 객체이다. 

 

 

21. final 필드와 상수 

- final 필드는 최종적인 필드란 뜻인데, 초기값이 저장되면 이것이 최종값이 되어서 프로그램 실행 도중에 수정할 수 없다는 것이다. 

final 타입 필드 [= 초기값];

- final 필드에 초기값을 주는 방법은 두 가지 뿐이다. 첫째는 필드 선언시 주는 방법이고 둘째는 생성자에서 주는 방법이다. 

- 단순 값이라면 필드 선언시에 주는 것이 가장 간단하고, 객체 생성 시에 외부 데이터로 초기화해야한다면 생성자를 통해 초기화하는 것이 맞다. (만약 초기화되지 않은 final필드를 그대로 두면 컴파일 에러가 발생한다.)

 

-상수 (static final) => 상수는 static 이면서 final이다. 
- 일반적으로 '불변의 값'을 상수라고 부른다. 그렇다면 final 필드를 상수라고 불러도 되지 않을까? no

- 왜냐하면 '불변의 값'은 객체마다 저장될 필요가 없는 공용성을 띠고 있으며, 여러 가지 값으로 초기화될 수 없기 때문이다. 

-final 필드는 객체마다 저장되고, 여러 가지 값으로 초기화될 수 있기 때문에 상수라고 부를 수 없다. 

-static final 필드는 객체마다 저장되지 않고, 클래스에만 포함된다. 

 

-상수 선언 시 초기값이 단순 값이라면 선언 시에 주는 것이 일반적이지만 복잡한 초기화일 경우 정적 블록에서도 할 수 있다. 

public clss Earth{
	static final double EARTH_RADIUS = 6400;
    static final double EARTH_SURFACE_AREA;
    
    static{
    	EARTH_SURFACE_AREA = 4 * Math.PI * EARTH_RADIUS + EARTH_RADIUS;
    }

}

 

 

22. 접근제한자

-public : 적용대상자(클래스, 필드, 생성자, 메소드) 접근할 수 없는 클래스(없음)

-protected : 적용대상자(필드, 생성자, 메소드) 접근할 수 없는 클래스(자식 클래스가 아닌 다른 패키지에 소속된 클래스)

-default : 적용대상자(클래스, 필드, 생성자, 메소드) 접근할 수 없는 클래스(다른 패키지에 소속된 클래스)

-private : 적용대상자(필드, 생성자, 메소드) 접근할 수 없는 클래스( 모든 외부 클래스)

 

22-1. 클래스의 접근 제한자 

- public 과 default 단 두가지이다. 

-클래스를 선언할 때 public 을 생략했다면 클래스는 default 접근 제한을 가진다. 

  ->같은 패키지 내에서는 아무 제한 없이 사용할 수 있지만, 다른 패키지에서는 사용할 수 없도록 제한된다. 

- public 접근 제한자를 붙였다면 다른 패키지에서 아무런 제한 없이 사용가능하다. (인터넷에 배포되는 오픈 라이브러리 클래스들도 모두 public 접근 제한자를 갖고 있다.)

 

22-2 생성자의 접근 제한자

 -클래스에 생성자를 선언하지 않으면 컴파일러에 의해 자동으로 클래스의 접근 제한자와 동일한 접근제한자가 생성된다. 

   (클래스의 접근 제한자가 public이면 생성자도 public, default면 default)

 

22-3 필드와 메소드의 접근 제한 

package sec13.exam03_field_method_access.package1;

public class A{
	//필드
    public int field1;	//public 접근 제한
    int field2; //default 접근 제한 
    private int field3; //private 접근 제한 
    
    //생성자
    public A(){
    	field1 = 1; //(o)
        field2 = 1; //(o)
        field3 = 1; //(o)
        
        method1(); //(o)
        method2(); //(o)
        method3(); //(o)
       }
       
    //메소드
    public void method1();//public 접근 제한
    void method2(); //default 접근 제한 
    private void method3(); //private 접근 제한

 

-> 같은 패키지 내 다른 클래스 : public , default 접근 가능 , private 접근 불가

->다른 패키지 내 클래스 : public만 접근 가능, default, private 접근 불가 

 

 

 

 

23.어노테이션 

- 어노테이션은 메타데이터라고 볼 수 있다. 

- 메타데이터란 컴파일 과정과 실행 과정에서 코드를 어떻게 컴파일하고 처리할 수 있을지를 알려주는 정보이다. 

@AnnotationName

 

- 어노테이션의 용도 세 가지 

  1) 컴파일러에게 코드 문법 에러를 체크하도록 정보를 제공

  2) 소프트웨어 개발 툴이 빌드나 배치 시 코드를 자동으로 생성할 수 있도록 정보를 제공 

  3) 실행 시(런타임 시) 특정 기능을 실행하도록 정보를 제공