언어/JAVA

클래스

빨대도둑 2022. 11. 15. 10:29

객체란 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있고 다른 것과 식별 가능한 것을 말한다. 객체는 속성과 동작으로 구성된다. 그리고 자바는 이 속성과 동작들을 각각 필드와 메서드라고 부른다

 

객체

객체들은 독립적으로 존재하고, 다른 객체와 서로 상호작용하면서 동작한다. 객체들 사이의 상호작용 수단은 메소드이다. 객체가 다른 객체의 기능을 이용하는 것이 메서드 호출이다

리턴값=전자계산기객체.메소드(매개값1,매개값2,...);

int result=Calculater.add(10,20);

 

<객체 관계>

상위 관계는 부모 객체를 기반으로 하위 객체는 생성하는 관계를 말한다. 일반적으로 상위 객체는 종류를 의미하고 하위객체는 구체적인 사물에 해당한다. 객체 지향 프로그래밍(OOP: object oriented programming)는 만들고자 하는 완성품인 객체를 모델링하고 집합 관계에 있는 부품 객체와 사용 관계에 있는 객체를 하나씩 설계한 후 조립하는 방식으로 프로그램을 개발하는 기법이다. 

 

<객체 지향 프로그래밍>

객체 지향 프로그램의 특징으로 캡슐화, 상속, 다형성을 들 수 있다. 

 

<캡슐화>

객체의 필드, 메소드를 하나로 묶고, 실제 구현 내용을 감추는 것을 말한다. 외부 객체는 객체 내부의 구조를 알지 못하며 객체가 노출해서 제공하는 필드와 메서드만 이용할 수 있다.

필드와 메소드를 캡슐화하여 보호하는 이유는 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록 하는 데 있다. 

접근 제한자는 객체의 필드와 메소드의 사용 범위를 제한함으로써 외부로부터 보호한다.

 

<상속>

객체지향프로그래밍에서 부모 역할의 상위 객체와 자식역할의 하위 객체가 있다. 상위 객체는 자기가 가지고 있는 필드와 메서드를 하위 객체에게 물려주어 하위 객체가 사용할 수 있도록 해준다. 

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

 

<다형성>

다형성은 같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질을 말한다. 코드 측변에서 보면 다형성은 하나의 타입에 여러 객체를 대입함으로써 다양한 기능을 이용할 수 있도록 해준다. 

자바는 다형성을 위해 부모 클래스 또는 인터페이스의 타입변환을 허용한다. 부모 타입에는 모든 자식 객체가 대입될 수 있고, 인터페이스 타입에는 모든 구현 객체가 대입될 수 있다. 

 

 

객체/클래스

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

 

<객체 지향 프로그래밍의 3가지 단계>

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

main( )메소드가 없는 클래스는 객체 생성 과정을 거쳐 사용해야 한다.

 


클래스

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

자바에서는 이 *설계도가 클래스(class)*이다.

 

<클래스 선언>

  • 하나 이상의 문자로 이루어져야 한다
  • 첫 번째 글자는 숫자가 올 수 없다
  • '$', '_'외의 특수문자는 사용할 수 없다
  • 자바 키워드는 사용할 수 없다
  • 관례적으로 클래스 이름이 단일 단어라면 첫 분자를 대문자로 하고 나머지는 소문자로 한다.
  • 만약 다른 단어가 혼합된 이름이라면 각 단어의 첫 문자는 대문자로 한다
  • 클래스 이름도 영어 대문자를 구분한다.
public class 클래스이름{
}

public class Stock{
}

public class Kospi{
}
public class Kosdaq{
}

> 가급적이면 소스파일 하나당 동일한 이름의 클래스 하나를 선언하는 것이 좋다

 

객체생성

클래스를 선언한 다음 객체를 생성해야 한다

클래스로부터 객체를 생성하는 방법은 new연산자를 사용하면 된다.

new 클래스();

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

클래스 변수=new 클래스();
//클래스 선언
public class Stock{}
Stock kospi=new Stock;
stock kosdaq=new Stock;

클래스는 API용과 실행용 2가지의 용도가 있다

라이브러리(API)용: 다른 클래스에서 이용할 목적으로 설계. 프로그램 전체에서 사용되는 클래스가 100개라면 99개는 라이브러리이고 단 하나만 실행 클래스이다. 실행 클래스는 프로그램 실행 진입점인 main() 메서드를 제공하는 역활을 한다.

대부분의 객체 지향 프로그래밍은 라이브러리와 실행 클래스가 분리되어 있다.

 

 


클래스의 구성멤버

<필드>

필드는 객체의 고유 데이터, 부품객체, 상태 정보를 저장하는 곳이다. 선언 형태는 변수와 비슷하지만 필드를 변수라고 부르지는 않다. 변수는 생성자와 메서드 내에서만 사용되고 생성자와 메소드가 실행 종료되면 자동 소멸된다. 하지만 필드는 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재한다

타입 필드 = 초기값;

String company="hyundai";
String model="avante";
int maxSpeed=300;
int productionYear;
int CurrentSpeed;
boolean enginStart;

필드 선언 시 주의점

  • 필드 선언은 클래스 {중괄호} 블록 어디서든 존재할 수 있다. 생성자 선언과 메소드 선언의 앞과 뒤 어느 곳에서든 선언이 가능하다.
  • 생성자와 메소드 중괄호 블록 내부에는 선언될 수 없다.
  • 생성자와 메소드 중괄호 블록 내부에서 선언된 것은 모두 로컬 변수가 된다.

필드 사용

  • 필드를 사용한다는 것은 필드 값을 읽고, 변경하는 작업을 말한다.
  • 클래스 내부의 생성자나 메서드에서 사용할 경우 단순히 필드 이름으로 읽고 변경하면 되지만 클래스 외부에서 사용할 경우 우선적으로 클래스로부터 객체를 생성한 뒤 필드를 사용해야 한다.
  • 필드는 객체에 소속된 데이터이므로 객체가 존재하지 않으면 필드도 존재하지 않는다.
public class Car{
int price=50000;
}
//외부에서 클래스 값 읽는 법
Public class CarEx{
	Car mycar= new Car;
	mycar.price=100000;
}

 


<생성자>

  • 생성자는 new연산자와 같이 사용되어 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당한다.
  • 생성자를 실행시키지 않고는 클래스로부터 객체를 만들 수 없다.
  • 생성자는 new연산자로 호출되는 {중괄호} 블록이다.
  • 생성자의 역할은 객체 생성 시 초기화를 담당한다. 필드를 초기화하거나 메서드를 호출해서 객체를 사용할 준비를 한다.
  • 생성자는 메서드와 비슷하게 생겼지만, 클래스 이름으로 되어 있고 리턴 타입이 없다.

 

기본 생성자

모든 생성자는 생성자가 반드시 존재하며, 하나 이상을 가질 수 있다.

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

public 클래스() {}

클래스가 public class로 선언되면 기본 생성자에도 public이 붙지만 클래스가 public 없이 class로만 선언되면 기본생성자에도 public이 붙지 않는다.

//소스파일(Car.java)
public class Car{}

//바이트 코드 파일(Car.class)
public class Car{
	class Car(){}
}
Car mycar=new Car;
//Car==기본 생성자

클래스에 생성자를 선언하지 않아도 new연산자 뒤에 기본 생성자를 호출해서 객체를 생성할 수 있다.

하지만 클래스에 명시적으로 선언한 생성자가 한 개라도 있다면 컴파일러는 기본 생성자를 추가하지 않는다.

명시적으로 생성자를 선언하는 이유: 객체를 다양하게 초기화하기 위해서

 

생성자 선언

//생성자 블록
클래스 (매개변수 선언){
객체의 초기화 코드
}

public class Car{
Car (String model,int modelCode){}
}
//생성자 호출해서 객체 생성
public class CarEx{
	public static void main(String[] args){
		Car myCar=new Car("Avante",365478);
	}
}

 


<필드 초기화>

//필드
public class Stock{
String name="samsung eletric";
String code="005930";
String ssn;
}

Stock s1= new Stock();
Stock s2= new Stock();

//생성자
public kospi(String n, String c){
naem=n;
code=c;
}
  • 클래스로부터 객체가 생성될 때 필드는 기본 초기값으로 자동 설정된다.
  • 만약 다른 값으로 초기화를 하고 싶다면 필드를 선언할 때 초기화 하거나, 생성자에서 초기값을 주면 된다.
  • 필드를 선언할 때 초기값을 주게 되면 동일한 클래스로부터 생성되는 객체들은 모두 같은 데이터를 가진다. 객체 생성 후 변경할 수 있지만, 동일한 클래스로부터 생성되는 객체들은 모두 같은 데이터를 가진다.

 

보통 매개변수의 이름은 초기화시킬 필드 이름과 비슷하거나 동일한 이름을 가진다.

필드 앞에 this를 사용해서 필드와 동일한 이름을 가지는 매개변수를 선언한다. 그러면 생성자 내부에서 필드에 접근할 수 있다.

this. 필드는 this라는 참조 변수로 필드를 사용하라는 것과 같은 의미이다

객체의 필드는 하나가 아니라 여러 개가 있고 이 필드를 모두 생성자에서 초기화한다면 생성자의 매개 변수의 수는 객체의 필드 수만큼 선언돼야 한다.

그러나 실제로는 중요한 몇 개 필드만 매개 변수를 통해서 초기화되고 나머지 필드들은 필드 선언 시에 초기화하거나 생성자 내부에서 임의의 값 또는 계산된 값으로 초기화한다.

public Car(String model,String modelCode){
	this.model=model;
	this.modelCode=modelCode;
}
//this.model에서 model==필드이다
//=model에서 model==매개 변수이다

 

생성자 오버로딩

생성자 오버로딩은 매개 변수를 달리하는 생성자를 여러 개 생성하는 것이다.

외부에서 제공되는 다양한 데이터를 이용해서 객체를 초기화하려면 생성자도 다양화되어야 한다.

자바는 다양한 방법으로 객체를 생성할 수 있게 생성자 오버로딩(Overloading)을 제공한다.

public class 클래스{
	클래스(타입 매개변수1, 타입 매개변수2){
	...
}

 클래스(타입 매개변수1, 타입 매개변수2){
...
	}
}

생성자 오버로딩 시 주의할 점

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

public class Car{
	Car(){}
	Car(String model){}
	Car(String model, String modelCode){}
	Car(String model, String modelCode, int price){}
}
Car car1=new Car();
Car car2=new Car("Avante");
Car car3=new Car("Avante","CN7");
Car car4=new Car("Avante","Cn7",3000);

 

다른 생성자 호출

생성자 오버로딩이 많아지면 생성자 간의 중복된 코드가 발생할 수 있다. 매개 변수의 수만 달리하고 필드의 초기화 내용이 비슷한 생성자에서 이러한 현상이 많이 발생한다.

이러한 경우⇒ 필드 초기화 내용은 한 생성자에 집중적으로 작성하고 나머지 생성자는 초기화 내용을 가지고 있는 생성자를 호출하는 방법으로 개선할 수 있다

클래스(매개변수선언){
	this(매개변수,...,값);
	실행문;
}
public class Car{
	String company="hyundai";
	String model;
	String modelCode;
	int price;

//생성자
	Car(){}

	Car(String model){
		tihs(model,"CN7","3000");
	}
	Car(String model,modelCode){
		tihs(model,modelCode,"3000");
	}
	Car(String model,modelCode,price){
		tihs(model,modelCode,3000);
	}
Car car1=new Car();
System.out.println(car1.company);
Car car4=new Car();
System.out.println(car1.company);
System.out.println(car1.model);
System.out.println(car1.modelCode);
System.out.println(car1.price);

 


<메서드>

메서드는 객체의 동작에 해당하는 {중괄호}블록을 말한다. 중괄호 블록은 이름을 가지고 있는데이것이 메소드 이름이다. 메소드를 호출하게 되면 중괄호 블록에 있는 모든 코드들이 일괄적으로 실행된다. 메소드는 필드를 읽고 수정하는 역할도 하지만 다른 객체를 생성해서 다양한 기능을 수행하기도 한다. 메소드는 객체 간의 데이터 전달의 수단으로 사용된다. 외부로부터 매개값을 받을 수 있고 실행 후 어떤 값을 리턴할 수 도 있다.

 

메소드

메소드는 객체의 동작에 해당하는 {중괄호}블록을 말한다. 중괄호 블록은 이름을 가지고 있는데 이것이 메소드 이름이다. 메소드를 호출하게 되면 중괄호 블록에 있는 모든 코드들이 일괄적으로 실행된다

메소드는 필드를 읽고 수정하는 역할도 하지만 다른 객체를 생성해서 다양한 기능을 수행한다. 메소드는 객체 간의 데이터 전달의 수단으로 사용된다. 외부로부터 매개값을 받을 수도 있고 실행 후 어떤 값을 리턴할 수도 있다.

 

<메서드 선언>

리턴타입 메소드이름 ([매개변수선언]){
실행 코드}

리턴타입=메소드가 리턴하는 결과타입 표시
매개변수선언=메소드가 실행할 때 필요한 데이터를 받기 위한 변수
void Circle(){
double radius(int x, int y){}}

Circle();
double result=rsdius(10,10);
  • 메소드 이름은 숫자로 시작하면 안 되고 $와_를 제외한 특수 문자를 사용하지 말아야 한다
  • 관례적으로 메서드명은 소문자로 작성한다
  • 서로 다른 단어가 혼합된 이름이라면 뒤이어 오는 단어의 첫 글자는 대문자로 작성한다
void run()
void EnginName()
String company()
int[] getPrice()

 

<메서드 선언>

매개 변수는 메서드가 실행할 때 필요한 데이터를 외부로부터 받기 위해 사용된다

double math(int x, int y)

double result=math(10,20);

byte b1=20;
byte b2=50;
double reuslt=math(b1,b2);

 

<매개변수의 수를 모르는 경우 배열로 선언>

int math(int[] values){}

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

int result=sum2(1,2,3);
int reuslt=sum2(1,2,3,4,5,6,7);

int[] value={11,22,33};
int result=sum2(value);
int result=sum2(new int[] {11,22,33,44,55});

 

<return>

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

return 리턴값;

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

 

리턴 값이 없으면 return을 사용해서 강제종료한다.

return;

 

<메서드 호출>

메서드는 클래스 내,외부의 호출에 의해 실행된다. 클래스 내부의 다른 메소드에서 호출할 경우에는 단순한 메소드 이름으로 호출하면 되지만, 클래스 외부에서 호출할 경우에는 우선 클래스로부터 객체를 생성한 뒤, 참조 변수를 이용해서 메서드를 호출해야 한다.

메소드(매개값,...);

void citizen(String n1, int p1){
citizen("no",1002);
}
타입변수= 메소드(매개값);

 

<외부에서 호출할 때>

클래스 참조변수=new 클래스(매개값);

Car myCar= new Car();
myCar.enginOn();
MyCar.km();
int rpm=myCar.enginOn();

 


<오버라이딩>

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

class 클래스{
리턴타입 메소드이름 (타입변수){}

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

double div(double x, double y){
double result=x/y;
return result;
}

 

인스턴스 멤버 this

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

객체 외부에서 인스턴스 멤버에게 접근하기 위해 참조 변수를 사용하는 것과 마찬가지로 객체 내부에서도 인스턴스 멤버에 접근하기 위해 this를 사용할 수 있다. 

 

정적 멤버 static

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

public class 클래스{
정적필드
static 타입필드 [=초기값];

정적 메소드
static 리턴 타입 메소드(매개변수 선언){}
}
public calss Cal{
String color;
ststic double pi=3.141592;
}

public class Cal{
String color;
void setColor(String color){this.color=color;}
static int plus(int x, int y){return x+y;}
static int minus(int x, int y){return x-y;}
}

 

<정적 멤버>

클래스.필드;
크래스.메소드(매개값);

double r1=10*10*Cal.pi;

 

<주의점>

객체가 없어도 실행된다는 특징 때문에 이들 내부에 인스턴스 필드나 인스턴스 메소드를 사용할 수 없다. 또한 객체 자신의 참조인 this 키워드도 사용이 불가능하다. 

 


싱글톤

프로그램에서 단 하나의 객체만 만들도록 보장해야 하는 경우가 있는데, 단 하나만 생성된다고 해서 이 객체를 싱글톤이라고 한다. 

싱글톤을 만들려면 클래스 외부에서 new 연산자로 생성자를 호출할 수 없도록 막아야 한다. 생성자를 호출한 만큼 객체가 생성되기 때문이다.

생성자를 외부에서 호출할 수 없도록 하려면 생성자 앞에 private 접근 제한자를 붙여주면 된다. 

public class 클래스{
정적필드
private static 클래스 singleton=new 클래스();

생성자
private 클래스(){}

정적메소드
static 클래스 Instance(){
return singleton;
}
}

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

 

final

<final필드>

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

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

final String nation="korea";

 

<final 상수>

불변의 값을 저장하는 필드를 상수라고 한다. 

static final 타입상수[=초기값];

static final 타입상수;
static{
상수=초기값;
}

static final double PI=3.151592;

static{....
Circlr=r*r*PI;
}

 


접근제한자

라이브러리 클래스를 설계할 때 외부 클래스에서 접근할 수 있는 멤버와 접근할 수 없는 멤버로 구분해서 필드, 생성자, 메서드를 설계하는 것이 바람직하다. 객체 생성을 막기 위해 생성자를 호출하지 못하게 하거나 객체의 특정 데이터를 보호하기 위해 해당 필드에 접근하지 못하도록 막아야 한다.

접근제한 적용대상 접근할 수 없는 클래스
public 클래스, 필드, 생성자, 메소드 없음
protected 필드, 생성자, 메소드 자식 클래스가 아닌 다른 패키지에 소속된 클래스
default 클래스, 필드, 생성자, 메소드 다른 패키지에 소속된 클래스
private 필드, 생성자, 메소드 모든 외부 클래스

 

패키지

클래스를 체계적으로 관리하기 위해 패키지를 사용한다. 패키지는 단순 파일 시스템의 폴더 기능한 하는 것이 아니라 클래스의 일부분이다. 패키지는 클래스를 유일하게 만들어주는 식별자 역할을 한다.

상위패키지.하위패키지.클래스

car.hyundai.avante


//실제 사용하려면
import car.hyundai.avante

 

setter/getter

객체지향 프로그래밍에서는 메서드를 통해서 데이터를 변경하는 방법을 선호한다. 메소드는 매개값을 검증해서 유효한 값만 데이터로 저장할수 있기 때문에 데이터는 외부에서 접근할 수 없도록 막고, 메소드는 공개해서 외부에서 메소드를 통해 데이터에 접근하도록 유도한다. 이러한 역할을 setter가 한다

private 타입 filedName

//getter
public 리턴타입 getFieldName(){
return fieldName;
}

//setter
public vodi setFieldName(타입 fieldName){
this.fildName=fieldName;
}


//타입이 boolean인 경우
priviate boolean stop;

//getter
public boolean stop(){
return stop;
}

//setter
public vodi setStop(boolean stop){
this.stop=stop;
}

 

어노테이션

어노테이션은 메타데이터이다. 애플리케이션이 처리해야 할 데이터가 아니라 컴파일 과정, 실행과정에서 어떻게 컴파일하고 처리할 것인지 알려주는 정보이다

@AnnotationName

 

<용도>

  • 컴파일러에 코드 문법 에러를 체크하도록 정보 제공
  • 소프트웨어 개발 툴이 빌드나 배치 시 코드를 자동으로 생성할 수 있도록 정보제공
  • 실행 시 특정 기능을 실행하도록 정보 제공