Java (4)

Tony Kim·2021년 9월 13일

Java

목록 보기
4/5
post-thumbnail

Java (4) : constructor, access modifier, encapsulation, collaboration, static

1. 생성자 (Constructor)

생성자 (constructor)
heap에 인스턴스 메모리 생성

생성자
• 생성자 기본 문법 <class_name>([<argument_list]) { [<statements] }
• 객체를 생성할 때 new 키워드와 함께 사용 - new Student();
• 생성자는 일반 함수처럼 기능을 호출하는 것이 아니고 객체를 생성하기 위해 new 와 함께 호출 됨
• 객체가 생성될 때 변수나 상수를 초기화 하거나 다른 초기화 기능을 수행하는 메서드를 호출 함
• 생성자는 반환 값이 없고, 클래스의 이름과 동일
• 대부분의 생성자는 외부에서 접근 가능하지만, 필요에 의해 private 으로 선언되는 경우도 있음

기본 생성자 (default constructor)
• 클래스에는 반드시 적어도 하나 이상의 생성자가 존재
• 클래스에 생성자를 구현하지 않아도 new 키워드와 함께 생성자를 호출할 수 있음
• 클래스에 생성자가 하나도 없는 경우 컴파일러가 생성자 코드를 넣어 줌 = public Student(){}
• 매개 변수가 없음, 구현부가 없음

초기화 과정을 하기위해 생성자 사용시 () {} 값 넣음

ex)

package ch06;
ㅤ
public class Student {
ㅤ
  public int studentNumber;
  public String studentName;
  public int grade;
ㅤ
  public Student() {} // 생성자 overloading 
  ㅤ
  public Student(int studentNumber, String studentName, int grade) {
    	this.studentNumber = studentNumer; // this 붙여주기!, this는 public가져왔고 오른쪽은 매개변수 & 이름 같게하는게 좋음
	this.studentName = studentName;
	this.grade = grade;
     }
ㅤ
public String showStudentInfo();
ㅤ
   return studentName + “학생의 학번과 학년은” + studentNumber + grade + “입니다.”
}
-> 얘는 메인 아님

메인으로 클래스 생성

public class StudentTest {
ㅤ
  public static void main(String[] args) {
ㅤ
    Student studentLee = new Student();
    studentLee.studentID = 54321;
    studentLee.setStudentName(“Kim”);
    studentLee.address = “경기도 성남시”;
    system.out.println(studentLee.showStudentInfo());
  // 멤버변수는 초기화, string은 null값, int는 0

OR

Student studentKim = new Student(12345, “kim”, 3);
System.out.println(studentKim.showStudentInfo()); 
}
*멤버변수만 가능! 지역변수는 호출될 때 초기화가 안 됨

클라이언트 코드 : 서비스를 사용하는 쪽 모듈 & 객체를 가져다 쓰는 쪽
서비스 코드 : 서비스 제공하는 객체 모듈

default 생성자 안되게 설정할 수도 있음

생성자 오버로딩 (overloading)

참조 자료형 변수

변수의 자료형
1) 기본 자료형 : int, long, float, double
2) 참조 자료형 : String, Date, Student // 생성해서 사용
*String은 예외

참조 자료형 정의하여 사용하기

ex)

package ch09;
ㅤ
public class Student {
  int studentID;
  String studentName;
ㅤ
  Subject Korea;
  Subject math;
ㅤ
  Student (int studentId, String StudentName) {
    this. studentId = studentId;
    this. studentName = studentName;
ㅤ
    korea = new Subject();
    math = new Subject();
    }
ㅤ
  public void setKoreaSubjecct(String name, int score) {
 ㅤ
    korea.subjectName = name;
    korea.score = score;
ㅤ}
ㅤ
  public void setMathSubject(String name, int score) {
ㅤ
    math.subjectName = name;
    mat.score = score;
}
ㅤ
  public void showScoreInfo() {
    int total = korea.score + math.score;
    System.out.println(studentName + “학생의 총점은” + total + “점입니다.”)
  }
}
package ch09:
ㅤ
public class SubjectTest {
ㅤ
public static void main(String[] args) {
  student studentLee = new Student(100, “Lee”)
  studentLee.setKoreaSubject(“국어”, 100);
  studentLee.setMathsubject(“수학”, 99);
  studentLee.showScoreInfo();
}




2. 접근 제어 지시자(access modifier)와 정보은닉(infomation hiding)

접근 제어 지시자 (accesss modifier)

  • 클래스 외부에서 클래스의 멤버 변수, 메서드, 생성자를 사용할 수 있는지 여부를 지정하는 키워드

private : 같은 클래스 내부에서만 접근 가능 ( 외부 클래스, 상속-상위하위- 관계의 클래스에서도 접근 불가)

default (아무것도 X) : 같은 패키지 내부에서만 접근 가능 ( 상속 관계라도 패키지가 다르면 접근 불가) 다른 패키지인 경우 import 하여 사용

protected : 같은 패키지나 상속관계의 클래스에서 접근 가능하고 그 외 외부에서는 접근 할 수 없음

public : 클래스의 외부 어디서나 접근 할 수 있음

get()/ set() 메서드

  • private 으로 선언된 멤버 변수 (필드)에 대해 접근, 수정할 수 있는 메서드를 public으로 제공
  • get() 메서드만 제공 되는 경우 read-only 필드
  • 이클립스에서 자동으로 생성됨

SET과 GET의 차이점

set = 설정, get = 값을 가져오는 것
ㅤ
User-id 라는 변수를 선언을 한다고 가정했을 때, User-id의 변수에 어떠한 값(ID)에 저장(set)을 한다.
ㅤ
User-id 에 저장된 값을 불러오는 것이 get이다.
ㅤ
쉽게 설명하면,
ㅤ
돼지저금통을 만든다  > 변수 선언
 ㅤ
그 안에 돈을 저축한다 > set
ㅤ
그 안에 돈이 얼마나 들어 있는지 본다 > get

SET과 GET 사용이유

결국에는, SET, GET 메소드를 사용하는 이유는 외부로부터 변수값에 직접적으로 접근하는것을 막기 위해서다. 직접 접근하개 되면 값이 변하게 되고 그러면 데이터 무결성이 깨질 수 있기 때문이다.
ㅤ
대표적으로 자바에서는 함수를 통해 값을 전달받고, 전달하고 방식을 권장하고 있다. 
ㅤ
또한 클래스 내에서 변수 private(캡슐화, 정보은닉)를 선언해서 외부에서 접근할 수 없도록 한다.
출처 : https://akdl911215.tistory.com/261

정보 은닉(infomation hiding)

  • private으로 제어한 멤버 변수도 public 메서드가 제공되면 접근 가능하지만 변수가 public으로 공개되었을 때보다
    private 일때 각 변수에 대한 제한을 public 메서드에서 제어 할 수 있다.
public void setMonth(int month) {
		ㅤ
		if ( month < 1 || month > 12) {
			isValid = false;
		}
		else {
			this.month = month;
		}
	}

• 객체 지향 프로그램에서 정보 은닉은 필요한 외부에서 접근 가능한 최소한의 정보를 오픈함으로써 객체의 오류를 방지하 클라이언트 객체가 더 효율적으로 객체를 활용할 수 있도록 해준다.

ex)

package ch10;
ㅤ
public class Birthday {
ㅤ
  private int day;     //초기값 0
  private int month;
  private int year;
ㅤ
  private boolean isValid;  // 초기값 false
ㅤ
  public int getDay() {
    return day;
  }
ㅤ
  public void setDay(int day) {
ㅤ
    if (day <1 || day >30) {
     isValid = false;
     }
    else {
     isValid = true;
     this.day = day
    }
ㅤ
  public int getMonth() {
    return month;
   }
ㅤ
  public void setMonth(int day) {
 ㅤ
  if (month <1 || month >12)
   {
    isValid = false;
   }
  else {
    isValid = true;
    this.day = day
   }
  }
  public int getYear() {
    return Year;
  }
ㅤ
  public void setYear(int day) {
   this.year = year
  }
  ㅤ   //get set : 마우스 오른쪽 + source + generate getters and setters
  ㅤ
  public void showDate() {
    if (isVlaid) {
      System.out.println( year + “년” + month + “월” + day + “일 입니다.”);
	}
    else {
      System.out.println(“유효하지 않은 날짜입나디.”);
    }
} 
package ch10;
ㅤ
public class BirthdayTest {
ㅤ
public static void main (Stirng[] args) {
  Birthday date = new BirthDay();
  date.setYear(2019);
  date.setMonth(13);
  date.setDay(30);
  }
}

private의 경우 메소드 쪽에 (get set 함수 쪽) 제한을 걸면서 오류를 방지할 수 있음
-> 외부에서 해당 값에 접근할 수 없음.




3. 캡슐화 (encapsulation)

캡슐화 (encapsulation)
정보 은닉을 활용한 캡슐화

  • 꼭 필요한 정보와 기능만 외부에 오픈함
  • 대부분의 멤버 변수와 메서드를 감추고 외부에 통합된 인터페이스만을 제공하여 일관된 기능을 구현 하게 함
  • 각각의 메서드나 멤버 변수를 접근함으로써 발생하는 오류를 최소화 한다.

-> 일관된 하나의 공개된 메서드(함수)에만 접근하도록 하는 것

레포트 만들기 예제

public class MakeReport {
ㅤ
	StringBuffer buffer = new StringBuffer();
	ㅤ
	private String line = "===========================================\n";
	private String title = "  이름\t   주소 \t\t  전화번호  \n";
    ㅤ
	private void makeHeader()
	{
		buffer.append(line);
		buffer.append(title);
		buffer.append(line);
	}
	ㅤ
	private void generateBody()
	{
		buffer.append("James \t");
		buffer.append("Seoul Korea \t");
		buffer.append("010-2222-3333\n");
		ㅤ
		buffer.append("Tomas \t");
		buffer.append("NewYork US \t");
		buffer.append("010-7777-0987\n");
	}
	ㅤㅤ
	private void makeFooter()
	{
		buffer.append(line);
	}
	ㅤ
	public String getReport()
	{
		makeHeader();
		generateBody();
		makeFooter();
		return buffer.toString();
	}
}
public class TestReprt {
ㅤ
	public static void main(String[] args) {
ㅤ
		MakeReport report = new MakeReport();
		String builder = report.getReport();
ㅤ
		System.out.println(builder);
	}
ㅤ
}

StringBuffer

  • string class 쭉 이어서 쓸 수 있음
  • 내부에 늘어날 수 있는 버퍼 클래스
  • 필드에서 가장 많이 씀 (string builder와 함께)

this가 하는 일

  • 인스턴스 자신의 메모리를 가리킴 (인스턴스 내부의 메모리,주소값)
  • 생성자에서 생성자 여러 개 있을 때 또 다른 생성자를 호출 할때 사용
  • 자신의 주소(참조값)을 반환 함

생성자에서 다른 생성자를 호출 하는 this

public class Person {
ㅤㅤ
  String name;
  int age; 
ㅤㅤ
  public Person () {
    this (“이름없음”, 1);  
    // 아직 인스턴스 생성된 것이 아니기 때문에 
       이전에 다른 코드 쓸 수 없음
  }
ㅤㅤ
  public Person(String name, int age) {
    this.name = name; 
    this.age = age;  
  }ㅤ
}

자신의 주소를 반환하는 this

public class Person {
ㅤ
	String name;
	int age;
	ㅤ
	public Person() {
		this("이름없음", 1);
	}
	ㅤ
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	ㅤ
	public Person getPerson() {
		return this;
	}
	ㅤ
	public static void main(String[] args)
	{
		Person p = new Person();
		p.name = "James";
		p.age = 37;
		ㅤ
		Person p2 = p.getPerson();
		System.out.println(p);
		System.out.println(p2);
	}
}
[this]
- 클래스에 생성자가 여러 개인 경우, 
  this를 이용하여 생성자에서 다른 생성자를 호출할 수 있음
- 생성자에서 다른 생성자를 호출하는 경우, 
  인스턴스의 생성이 완전하지 않은 상태이므로 
  this() statement 이전에 다른 statement를 쓸 수 없음




4. 객체간의 협력 (collaboration)

  • 객체 지향 프로그램에서 객체 간에는 협력이 이루어짐
  • 협력을 위해서는 필요한 메시지를 전송하고 이를 처리하는 기능이 구현되어야함
  • 매개 변수로 객체가 전달되는 경우가 발생

Student

package ch14;
ㅤ
public class Student {
  String studentName;
  int money;
ㅤ
  public Student(String studentName, int money) {
    this.studentName = studentName;
    this.money = money;
  }
ㅤ
  public void takeBus(Bus bus) {
    bus.take(1)0;
    this.moeney -= 1000;
  }
ㅤ
  public void takesubway (Subway subway) {
    subway.take(1200);
    this.money -= 1200;
  }
ㅤ
  public void showBusInfo() {
    System.out.println(busNumber + "번 버스의 승객은 " + passengerCount + "명 이고, 수입은 " + money + "원 입니다");
	}

Bus

public class Bus {
  int busNumber;
  int passengerCount;
  int money;
ㅤ
  public Bus(int busNumber) }
    this. busNumber = busNumber;
  }
ㅤ
  public void take(int money) {
    this.money += money;
    passengerCount++;
  }
ㅤㅤ
  public void showBusinfo() {
    System.out.println(lineNumber + "번 버스의 승객은 " + passengerCount + "명 이고, 수입은 " + money + "원 입니다");
  }
}

Subway

public class Subway {
ㅤㅤ
	int lineNumber;
	int passengerCount;
	int money;
	ㅤ
	public Subway(int lineNumber) {
		this.lineNumber = lineNumber;
	}
	ㅤㅤ
	public void take(int money) {
		this.money += money;
		passengerCount++;
	}
	ㅤㅤㅤ
	public void showSubwayInfo() {
		System.out.println(lineNumber + "번 지하철의 승객은 " + passengerCount + "명 이고, 수입은 " + money + "원 입니다");
	}
}

Take

public class TakeTransTest {
ㅤ
	public static void main(String[] args) {
		Student studentJ = new Student("James", 5000);
		Student studentT = new Student("Tomas", 10000);
		ㅤ
		Bus bus100 = new Bus(100);
		ㅤ
		Subway subwayGreen = new Subway(2);
		ㅤ
		studentJ.takeBus(bus100);
		studentT.takeSubway(subwayGreen);
		ㅤ
		studentJ.showInfo();
		studentT.showInfo();
		ㅤ
		bus100.showBusInfo();
				ㅤ
		subwayGreen.showSubwayInfo();
	}
ㅤ
}

공통으로 사용하는 변수가 필요한 경우
• 여러 인스턴스가 공유하는 기준 값이 필요한 경우
• 학생마다 새로운 학번 생성
• 카드회사에서 카드를 새로 발급할때마다 새로운 카드 번호를 부여
• 회사에 사원이 입사할때 마다 새로운 사번이 필요한




5. static 변수

static 변수
동일한 클래스에서 생성된 여러 인스턴스 공유

static 변수 선언과 사용하기
static int serialNum;
• 인스턴스가 생성될 때 만들어지는 변수가 아닌, 처음 프로그램이 메모리에 로딩될 때 메모리를 할당
• 클래스 변수, 정적변수라고도 함(vs. 인스턴스 변수)
• 인스턴스 생성과 상관 없이 사용 가능하므로 클래스 이름으로 직접 참조

과정

프로그램을 구동시키면 프로그램이 메모리에 올라가는데,
메모리에 올라간 상태 = 프로세스 (thread상태로 돌아감)

메모리 올라갈 때 두가지 영역

데이터 영역
처음부터 메모리 잡음 (상수, 리터럴, static)
-> 프로세스 로딩되는 순간 데이터 영역에 잡히고,  프로그램이 다 끝나서 메모리에서 unload되는 순간 없어짐 
ㅤ
코드 영역
명령어집합
ㅤ
인스턴스가 생성될때마다 메모리 할당 – heap (동적) 
GC (garbage collector) 에 의해 제거

ex)

public class Employee {
ㅤㅤ
	public static int serialNum = 1000;
	ㅤㅤ
	private int employeeId;
	private String employeeName;
	private String department;
	ㅤ
	public Employee() // default 생성자
	{
		serialNum++;
		employeeId = serialNum;
	}
ㅤ
	public int getEmployeeId() {
		return employeeId;
	}
	public void setEmployeeId(int employeeId) {
		this.employeeId = employeeId;
	}
	public String getEmployeeName() {
		return employeeName;
	}
	public void setEmployeeName(String employeeName) {
		this.employeeName = employeeName;
	}
	public String getDepartment() {
		return department;
	}
	public void setDepartment(String department) {
		this.department = department;
	}
	ㅤ
}
public class EmployeeTest {
ㅤ
	public static void main(String[] args) {
		Employee employeeLee = new Employee();
		employeeLee.setEmployeeName("이순신");
		System.out.println(employeeLee.serialNum);
		ㅤ
		Employee employeeKim = new Employee();
		employeeKim.setEmployeeName("김유신");
		employeeKim.serialNum++;
		ㅤ
		System.out.println(employeeLee.serialNum);
		System.out.println(employeeKim.serialNum);
		ㅤ
	}
}

참고) 인스턴스와 상관없이 사용 가능하기 때문에 class이름으로 참조해서 사용가능
-> System.out.println(employee.serialNum);

static 메서드

private static int serialNum = 1000;
ㅤ
public static int getSerialNum() {
	return serialNum;
}
ㅤ
public static void setSerialNum(int serialNum) {
	Employee.serialNum = serialNum;
}
ㅤ
System.out.println(Employee.getSerialNum());

static 메서드(클래스 메서드)에서는 인스턴스 변수를 사용할 수 없다

  • static 메서드는 인스턴스 생성과 무관하게 클래스 이름으로 호출 될 수 있음
  • 인스턴스 생성 전에 호출 될 수 있으므로 static 메서드 내부에서는 인스턴스 변수를 사용할 수 없음

Employee.java

public static void setSerialNum(int serialNum) {
  int i = 0;
ㅤ	
  employeeName = "Lee";  //오류발생 (만약 다른 곳에서 호출할 때 인스턴스가 생성되어있지 않을 수도 있을 수 있는데,
static 메서드는 인스턴스 유무와 상관없이 호출될 수 있어야하기 때문
ㅤ
  Employee.serialNum = serialNum;
  }

EmployeeTest2.java

public class EmployeeTest2 {
	ㅤㅤ
  public static void main(String[] args) {
	ㅤ
        System.out.println(Employee.getSerialNum());
	Employee.setSerialNum(1003);
 	System.out.println(Employee.getSerialNum());
    ㅤ
	}
}

변수의 유효 범위와 메모리

  • 변수의 유효 범위(scope)와 생성과 소멸(life cycle)은 각 변수의 종류마다 다름
  • 지역변수, 멤버 변수, 클래스 변수는 유효범위와 life cycle, 사용하는 메모리도 다름

  • static 변수는 프로그램이 메모리에 있는 동안 계속 그 영역을 차지하므로 너무 큰 메모리를 할당하는 것은 좋지 않음
  • 클래스 내부의 여러 메서드에서 사용하는 변수는 멤버 변수로 선언하는 것이 좋음
  • 멤버 변수가 너무 많으면 인스턴스 생성 시 쓸데없는 메모리가 할당됨
  • 상황에 적절하게 변수를 사용해야 함

싱글톤 패턴이란?

  • 프로그램에서 인스턴스가 단 한 개만 생성되어야 하는 경우 사용하는 디자인 패턴
  • static 변수, 메서드를 활용하여 구현 할 수 있음
    싱글톤 패턴으로 회사 객체 구현하기
  • 생성자는 private으로 선언
    private Company() {}
  • 클래스 내부에 유일한 private 인스턴스 생성 (컴파일러가 default 제공 X)
    private static Company instance = new Company(); // singleton
  • 외부에서 유일한 인스턴스를 참조할 수 있는 public 메서드 제공 (외부에서 class메서드로 참조가능)
public static Company getInstance() {
		    ㅤ
	if( instance == null) {
		instance = new Company();
	}
	return instance;
		    ㅤ
}

CompanyTest.java

public class CompanyTest {
    ㅤ
	public static void main(String[] args) {
		Company company1 = Company.getInstance();
		    ㅤ
		Company company2 = Company.getInstance();
		    ㅤ
		System.out.println(company1);
		System.out.println(company2);
		    ㅤ
		//Calendar calendar = Calendar.getInstance();
	}
}

본 게시글은 fastcampus 박은종강사 수업을 듣고 개인적으로 정리한 내용임을 밝힘.

profile
Back-end-dev

0개의 댓글