자바 Modifier와 생성자 - accidentlywoo/java GitHub Wiki

자바 Modifier와 생성자


  1. static 예약어, final 예약어, abstract 예약어의 기능을 이해하고 직접 활용할 수 있다.
  2. 생성자의 기능을 이해하고, this 예약어의 의미와 활용 방법을 설명할 수 있다.

static 예약어

클래스 변수

static 예약어

  • 멤버 변수와 메서드 앞에 붙일 수 있는 modifier로서, 활용 방법을 제어함
  1. static 예약아가 붙지 않는 인스턴스 변수 생성된 인스턴스마다 그 안에 클래스의 인스턴스 변수들이 포함됨 일반적인 멤버 변수를 인스턴스 변수라고 부름

  2. static 예약어가 붙는 클래스 변수 클래스로부터 생성된 인스턴스에 포함되지 않는 변수 많은 인스턴스를 생성하더라도 메모리에 하나의 변수만 존재함. 객체를 생성하지 않고도 접근할 수 있는 변수

  • 클래스 변수가 필요한 이유는? 동일한 값을 가지고 있는 변수를 인스턴스 변수로 선언한다.-> 메모리에 불필요한 영향
class Employee3 {
	String name;
	int employeeNo;
	int age;
	String companyName;
}

public class EmployeeTest {
	public static void main(String[] args) {
		Employee3 woo = new Employee3();
		woo.name = "우연희";
		woo.employeeNo = 1234;
		woo.age = 27;
		woo.companyName = "S전자";
		
		Employee3 lee = new Employee3();
		lee.name = "이선영";
		lee.employeeNo = 12345;
		lee.age = 30;
		lee.companyName = "S전자";
		
		Employee3 park = new Employee3();
		park.name = "박재성";
		park.employeeNo = 1234567;
		park.age = 28;
		park.companyName = "S전자";
	}
}

park.companyName = "S전자";모두 동일 -> 메모리를 불필요하게 사용하고 있음

  • 인스턴스 변수 클래스로부터 객체가 생성될 때마다 각 객체의 변수들이 생성됨 한 객체의 값이 변경되어도, 다른 객체의 값에 영향을 주지 않음

  • 클래스 변수 클래스로부터 생성된 모든 객체들이 하나의 클래스 변수를 공유함 객체가 생성될 때 메모리 영역을 할당하지 않고, 클래스가 로딩되는 과정에서 메모리에 한 번만 할당되는 멤버임 -> 클래스 변수의 값이 변경되는 경우, 클래스로부타 생성된 모든 객체에서 변경된 값을 사용 가능함.

class Employee3 {
	String name;
	int employeeNo;
	int age;
	static String companyName = "S전자";
}

public class EmployeeTest {
	public static void main(String[] args) {
		Employee3 woo = new Employee3();
		woo.name = "우연희";
		woo.employeeNo = 1234;
		woo.age = 27;
		
		Employee3 lee = new Employee3();
		lee.name = "이선영";
		lee.employeeNo = 12345;
		lee.age = 30;
		
		Employee3 park = new Employee3();
		park.name = "박재성";
		park.employeeNo = 1234567;
		park.age = 28;
	}
}

클래스 변수의 접근

클래스 변수는 일반적으로 객체 참조 변수 이름으로 접근하기보다는 클래스 이름을 통해서 접근함 -> 객체를 생성하지 않고도 클래스 변수에 접근 가능함.

지금까지 사용했던 자바 출력문은 모드 System클래스의 out이라는 클래스 변수를 이용

클래스 메서드

메서드에서도 static 예약어를 사용 가능함 인스턴스를 생성하지 않고도 사용 가능함

integer 클래스의 parseInt() 메서드가 대표적인 클래스 메서드임

int age = Integer.parseInt("36");

클래스로부터 인스턴스를 생성하지 않고 호출이 가능함 인스턴스 변수는 인스턴스를 생성해야만 메모리가 잡히기 때문에 클래스 메서드에서 사용이 불가능함

클래스 메서드에서는 클래스 메서드만 호출이 가능함.

변수와 final

final예약어 사용 --변수 선언--> 할당된 값을 변화시킬 수 없음

final이 붙은 변수는 단 한 번 초기화가 가능하지만, 초기화 이후에는 값을 변경할 수 없는 상수임.

클래스로부터 생성된 모든 객체들이 동일한 값을 가지는 경우 -> 공통된 값을 가지는 변수를 클래스 변수로 선언하여 메모리를 효율적으로 사용함

클래스 변수의 값을 변경할 수 있도록 허용하는 경우 -> static 예약어의 의미가 상실되므로, final 예약어를 결합하여 사용함으로써 초기화된 값을 변경할 수 없게 함

static 예약어의 의미 상싱 + final예약어와 결합 ->한번 초기화된 값을 변결할 수 없게 함

class Employee3 {
	String name;
	int employeeNo;
	int age;
	final static String companyName = "S전자";
}

public class EmployeeTest {
	public static void main(String[] args) {
		Employee3 woo = new Employee3();
		woo.name = "우연희";
		woo.employeeNo = 1234;
		woo.age = 27;
		//woo.companyName = "A전자"; error
	}
}

Employee클래스로부터 생성된 모든 인스턴스는 변경되지 않는 동일한 회사명을 갖음. 상수의 이름은 일반 인스턴스 변수와 구분하기 위해서 모두 대문자로 선언함 여러 단어가 결합된 경우라면 단어와 단어 사이에 '_'를 이용하여 선언

companyName -> COMPANY_NAME

메서드와 final

class 부모 {
  public void method(){}
}

class 자식 extends 부모 {
  public void method(){}
}

-> 메서드 재정의 가능

class 부모 {
  public final void method(){}
}

class 자식 extends 부모 {
  public void method(){}
}

-> 메서드 재정의 불가

메서드 재정의(Overriding)는 상속 구조에서 부모 클래스의 메서드와 동일한 모양의 메서드를 자식 클래스에서 상속 받지 않고 새롭게 정의하는 것을 말함

final 예약어를 사용함으로써, 메서드 재정의(Overriding)를 금지함

클래스와 final

클래스를 선언할 때 클래스 앞에 final 예약어를 추가하면 상속을 금지하는 의미임

final class Car {
  String name;
  int speed;
}

-> Car클래스를 final 클래스로 선언하여, 자식 클래스를 가지지 못함

클래스 앞에 붙은 final 예약어는 상속 금지를 의미함.

추상 메서드

abstract 예약어는 클래스와 메서드를 선언할 때 사용하는 Modifier임

클래스 선언부에서 abstract 사용 시 -> 추상 클래스로 선언함

메서드를 선언할 때 abstract 사용 시 -> 추상 메서드를 정의함

메서드의 시그니처(리턴 타입, 메서드명, 매개변수)만 정의되고 구체적인 행위, 즉 블록({}) 부분은 정의되지 않는 메서드를 의미함.

returnType name({argType argName,...]){...} //일반 메서드
abstract returnType name({argType argName,...]); //

추상 메서드를 선언할 때는 abstract 예약어는 메서드 앞에 붙여야 함 메서드의 구체적인 행위를 표현하는 블록({}) 부분을 생략함 메서드의 기본 형식인 리턴 타입, 메서드명, 매개변수가 선언되어 있어서, 메서드의 기본적인 기능은 유추 가능함

추상 클래스

추상 메서드를 포함하고 있는 클래스는 추상 클래스로 선언되어야 함 -> 추상 클래스가 추상 메서드를 포함하지 않을 수도 있음

abstract class AbstractClass {
  public abstract void methodA(){...}
  public abstract void methodB(){...}
}
abstract class AbstractClass {
  public void methodA(){...}
  public void methodB(){...}
}

자바는 추상 메서드와 추상 클래스를 왜 지원하는 것일까?

추상 클래스와 상속이 결합되어야 정확하게 추상 클래스를 이해할 수 있음

abstract class SuperClass {
  public void methodA(){
    sysout("methodA")
  }
  public abstract void methodB();
}

class SubClass extends SuperClass {
}

상속은 부모 클래스의 모든 변수와 메서드가 자식 클래스로 상속되어 들어오는 개념

SubClass가 컴파일 되지 않기 때문에 문제발생

  1. 부모 클래스로부터 methodA(), methodB()가 상속됨
  2. 자식 클래스인 SubClass에는 구현되지 않은 methodB()가 추상 메서드로 있는 것과 동일함
  3. 자식 클래스인 SubClass는 추상 클래스로 선언되어야 하거나, methodB()를 재정의 해야 한다.
abstract class SuperClass {
  public void methodA(){
    sysout("methodA")
  }
  public abstract void methodB();
}

class SubClass extends SuperClass {
  public void methodB() {
    sysout("methodB");
  }
}

생성자

생성자의 개념

생성자(Constructor)는 클래스로부터 객체를 생성할 때 호출되며, 객체의 멤버 변수를 초기화하는데 사용되는 메서드임 객체를 생성할 때 객체에 필요한 값들을 초기화하는 개념은 배열과 동일함

정수형 배열객체를 생성하고 적절한 값들을 초기화하는 경우

int[] scoreList = new int[5];
scoreList[0] = 89;
scoreList[1] = 100;
scoreList[2] = 75;
scoreList[3] = 99;
scoreList[4] = 63;

자바의 모든 객체는 new라는 객체 생성 연산자를 통해서 생성됨 --초기화 과정의 단순화-->

int[] scoreList = {89, 100, 75, 99, 63};

객체 생성 및 생성된 객체에 필요한 데이터를 초기화하는 과정을 단순화하여 코드의 양을 줄이는 역할 수행 -> 생성자

class Employee{
  String name;
  int number;
  int age;
  String title;
  String dept;
  String grade;
}

Employee kim = new Employee();

단순히 객체만 생성하는 것이 프로그램 관점에서 의미가 없음 생성된 객체의 멤버 변수들은 실제 직원 객체에 해당하는 값들로 채워져야 함

Employee woo = new Employee();
woo.name = "여니";
woo.number = 12345;
.
.
.

-> 개귀찮

생성자를 통해 복잡한 작업을 한 줄로 처리 가능함

class Employee{
  String name;
  int number;
  int age;
  String title;
  String dept;
  String grade;

  public Employee(String n1, int n2, int a, String t, String d, String g){
     name = n1;
     number = n2;
     age = a;
     title = t;
     dept = d;
     grage = g;
  }
}

Employee 객체 생성 시 적절한 값을 설정한 예

Employee kim = new Employee("김",1234,34,"과장","개발부","B+");

생성자의 특징

생성자는 클래스와 같은 이름을 가진 특별한 메서드로서 객체 생성 시 멤버 변수의 초기화를 담당함 일반 멤버 메서드와 달리 반환향(Return Type)이 없음 -> void도 허용되지 않음 생성자는 이름은 같지만 매개변수를 달리하여 여러 개를 중복정의(Overloading)할 수 있음 생성자는 키워드 'new'와 항상 같이 사용됨 -> 생성자는 객체를 생성할 경우에 사용되므로 "new 생성자()"와 같은 구문으로 호출됨 명시적으로 작성하지 않을 경우, 기본 생성자가 제공됨

생성자를 선언하는 방법

[access modifier] class명 ([argument list]){
  ...
}

생성자는 클래스와 같은 이름으로 선언됨 생성자 안에서는 객체의 초기화에 필요한 코드가 기술됨 생성자의 선언 부분에는 접근 권한과 관련된 Modifier가 올 수 있음 -> public, protected, private

기본 생성자(Default Constructor)

클래스에 생성자가 하나도 정의되지 않은 경우, 컴파일러에 의해 자동으로 생성되는 생성자 -> 클래스 내 생성자가 하나라도 정의되어 있는 경우에는 기본 생성자가 자동으로 제공되지 않음

매개변수 없는 생성자 기본생성자 사용 --객체 생성--> 생성된 객체의 멤버 변수 초기화(일정한 규칙에의해 초기화됨)

멤버 변수의 기본 초기 값 byte,short,int = 0 long = 0L float = 0.0F double = 0.0D char = '\u0000' (NULL) boolean = false 참조형 = null

class Employee{
  String name;
  int number;
  int age;
  String title;
  String dept;
  String grade;
}

기본 생성자 자동 추가

this의 의미

생성자나 메서드의 매개변수 이름이 객체 변수의 이름과 같다면? 객체 변수 이름 앞에 this를 사용해서 구별함

public class Employee {
  String name;
  int number;

  public Employee(String name, int age){
     name = name;
     age = age;
  }
}

멤버 변수와 매개변수 이름이 동일하면, 매개변수로 받은 값을 멤버 변수에 할당할 수 없음 -> 멤버 변수에는 아무런 값이 할당되지 못하는 문제 발생

public class Employee {
  String name;
  int number;

  public Employee(String n, int a){// 생성자의 매개변수를 멤버변수와 다르게 선언함
     name = name;
     age = age;
  }
}

매번 매개변수 이름을 유일한 이름으로 만들기 어렵고, 가독성도 떨어짐 -> 매개변수로 선언된 n과 a변수의 이름만 봐서는 어떤 값들이 넘어오는지 알 수 없음 -> this예약어 사용 멤버 변수와 매개변수 이름을 구분할 수 있고, 프로그램의 가독성을 높임

public class Employee {
  String name;
  int number;

  public Employee(String name, int age){
     this.name = name;
     this.age = age;
  }
}

this를 사용하여 멤버 변수와 매개변수 이름을 구분하여 프로그램의 가독성을 높임