이것이 자바다 ch 6 클래스
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) 실행 시(런타임 시) 특정 기능을 실행하도록 정보를 제공