Ch02. 객체지향입문 03

하파타카·2022년 8월 27일
0

패캠JAVA, Spring과정

목록 보기
7/20

16. static 변수

static 변수란?

  • 여러 인스턴스에서 공통으로 사용하는 변수
  • 여러 클래스에서 공유하는 기준값이 필요한 경우
  • 인스턴스가 생성될 때 만들어지는 변수(Heap메모리 사용)가 아닌, 프로그램이 처음 메모리에 로딩될 때 메모리영역(Stack메모리 사용)을 할당받음.
    프로그램의 실행이 종료되는 순간 메모리공간을 반환함.
    (상수, 리터럴처럼 static변수도 처음부터 메모리를 잡음)
  • 인스턴스 생성과 관계없이 사용할 수 있어 보통 클래스이름으로 직접 참고함.
    예 - System.out.println(클래스이름.static변수);

일반 멤버변수로 생성 시 다른 클래스끼리 할당되는 메모리공간부터 다르기때문에 공유할 수가 없게 됨
=> static 변수를 이용하여 해결

예제

회사에 사원이 입사할 때 사번을 순차적으로 부여하는 예제(1001, 1002, 1003 ...)

-Employee.java-

public class Employee {
	
	public static int serialNum = 1000;
	
	private int employeeId;
	private String employeeName;
	private String department;
	
	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;
	}
}

-EmployeeTest.java-

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(employeeKim.serialNum);
	}
}

serialNum변수가 static변수가 아니었을 경우 각 변수들마다 각각의 Heap메모리에 공간을 할당받으므로 공유가 불가능했음.

예제2

위와 같은 예제를 생성자를 이용하여 생성자가 호출될 때마다 serialNum을 증가시킴
이때 멤버변수인 serialNum을 그대로 사번으로 사용하면 모든 사원이 같은 사번을 공유하게 되므로 생성된 사번을 인스턴스변수에 저장하여 사원마다 모두 다른 사번을 사용할 수 있게 한다.

-Employee.java-
예제1에서 생성자를 추가.

public Employee() {
	serialNum++;
	employeeId = serialNum; 
}

-EmployeeTest.java-

public class EmployeeTest {

	public static void main(String[] args) {
		
		Employee employeeLee = new Employee();
		employeeLee.setEmployeeName("이순신");
		
		Employee employeeKim = new Employee();
		employeeKim.setEmployeeName("김좌진");
		
		System.out.println(employeeLee.getEmployeeName() + "," + employeeLee.getEmployeeId());
		System.out.println(employeeKim.getEmployeeName() + "," + employeeKim.getEmployeeId());

	}
}

참고

public class EmployeeTest {

	public static void main(String[] args) {
		
//		Employee employeeLee = new Employee();
//		employeeLee.setEmployeeName("이순신");
//		
//		Employee employeeKim = new Employee();
//		employeeKim.setEmployeeName("김좌진");
		System.out.println(Employee.serialNum);
		
//		System.out.println(employeeLee.getEmployeeName() + "," + employeeLee.getEmployeeId());
//		System.out.println(employeeKim.getEmployeeName() + "," + employeeKim.getEmployeeId());

	}
}

static클래스는 클래스가 로딩될 때 이미 메모리에 올라가있기 때문에 위처럼 객체를 만들지 않아도 사용할 수 있다.
단, 접근 시 객체명이 아닌 클래스명을 이용하는것을 권장함.

멤버변수, 지역변수, 전역변수 등 개념정리

참고
static변수 = 클래스 변수 = 정적 변수
모두 같은 말이니 용어의 사용에 주의하자.


17. static메서드의 사용과 변수의 유효범위

  • static메서드에서는 인스턴스의 생성과 무관히게 클래스 이름으로 호출될 수 있음(16번의 예제2를 참고)
  • static메서드에서는 인스턴스변수를 사용할 수 없음.
    => 인스턴스가 생성되지 않은 상태에서 static메서드가 사용될 수 있으므로 메모리에 올라있지 않을 수 있는 인스턴스 변수의 사용자체가 불가능한 것.

출처-패캠java,spring과정 박은종강사님 자료

  • static변수는 프로그램이 메모리에 있는 동안 계속 메모리영역을 차지하므로 크기를 최소화 하는것이 좋음.
  • 클래스 내부의 여러 메서드에서 사용하는 변수는 멤버 변수로 선언하는 것이 좋음

18. static응용-싱글톤 패턴

싱글톤 패턴이란?

  • 프로그램에서 인스턴스가 단 한 개만 생성되어야 하는 경우 사용하는 디자인 패턴
  • static 변수, 메서드를 활용하여 구현가능

각 인스턴스와 그에 따른 멤버변수마다 모두 다른 값을 가지면 안되는 경우가 있음.
예-시간(모든 객체마다 시간개념이 다를 경우 문제발생), 회사(사원은 다수이지만 회사는 유일)

예제

-Company.java-

public class Company {

	private static Company instance = new Company();	// 유일한 객체 선언
	
	private Company() {		}
	
	public static Company getInstance() {
		// static메서드로 선언했기 때문에 외부에서 호출 시 인스턴스를 생성하지 않아도 호출가능
		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();
		System.out.println(calendar);
	}
}

JVM이 할당해 준 Heap메모리의 주소가 출력됨.
주소가 같은 하나의 인스턴스임을 확인가능.


19.복습문제(static, 싱글톤)

설명에 따른 객체를 구현하여 테스트 코드가 실행되도록 구현하기

자동차 공장이 있습니다. 자동차 공장은 유일한 객체이고, 이 공장에서 생산되는 자동차는 제작될 때마다 고유의 번호가 부여됩니다. 
자동차 번호가 10001부터 시작되어 자동차가 생산될 때마다 10002, 10003 이렇게 번호가 붙도록 자동차 공장 클래스, 자동차 클래스를 구현하세요
다음 CarFactoryTest.java 테스트 코드가 수행 되도록 합니다.

-CarFactoryTest.java-

public class CarFactoryTest {

	public static void main(String[] args) {
		CarFactory factory = CarFactory.getInstance();
		Car mySonata = factory.createCar();
		Car yourSonata = factory.createCar();
		
		System.out.println(mySonata.getCarNum());     //10001 출력
		System.out.println(yourSonata.getCarNum());   //10002 출력
	}
}

못풀겠다...아무래도 더 간단한 예제 풀어보고 다시 풀어야할듯.
객체를 생성하고 기능구현을 위한 관계설계를 못하겠음.


20.배열(Array)

배열이란?

  • 동일한 자료형의 순차적 자료 구조
  • 생성 시 길이를 지정해야하며, 그에 따른 공간이 메모리에 할당됨
  • 인덱스 연산자[]를 이용하여 빠른 참조가 가능
  • 물리적 위치와 논리적 위치가 동일
  • 배열의 순서는 0부터 시작
  • 자바에서는 객체 배열을 구현한 ArrayList를 많이 활용함
int[] arr1 = new int[10];
int arr2[] = new int[10];
  • 배열과 함께 사용되는 향상된 for문
for (자료형 변수명 : 배열명) {
	//내용
}

선언한 변수에 배열의 값들이 0번 index의 값부터 마지막 index의 값까지 차례로 대입되는 for문.

예제

public class ArrayTest {

	public static void main(String[] args) {
		
		int[] arr = new int[10];
		int total = 0;
		
		for (int i = 0, num = 1; i < arr.length; i++) {
			arr[i] = num++;
		}
		
		for (int num : arr) {
			total += num;
		}

		System.out.println("total = " + total);
	}
}

public class CharArrayTest {
	
	public static void main(String[] args) {
		
		char[] alphabets = new char[26];
		char ch = 'A';
		
		for (int i = 0; i < alphabets.length; i++) {
			alphabets[i] = ch++;
		}
		
		for (char alpha : alphabets) {
			System.out.println(alpha + ", " + (int)alpha);
		}
	}
}


21. 객체배열 사용하기

  • 기본 자료형 배열의 경우 선언과 함께 메모리의 크기가 할당되지만, 객체 배열의 경우 객체의 주소가 들어갈 메모리만 할당되고 각 요소의 객체는 생성하여 저장해야 함.

-Book.java-

public class Book {
	
	private String title;
	private String author;
	
	public Book() {		}
	
	public Book(String title, String author) {
		this.title = title;
		this.author = author;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public void showInfo() {
		System.out.println(title + ", " + author);
	}
}

-BookTest.java-

public class BookTest {

	public static void main(String[] args) {

		Book[] library = new Book[5];
		
		for(int i=0; i<library.length; i++) {
			System.out.println(library[i]);
		}
	}

}


모두 null이 출력됨을 확인할 수 있음.
객체가 할당되는게 아니라는 의미.

위의 예제에서 BookTest.java클래스만 수정.
-BookTest.java-

public class BookTest {

	public static void main(String[] args) {

//		Book[] library = new Book[5];

//		for(int i=0; i<library.length; i++) {
//			System.out.println(library[i]);
//		}

		Book[] library = new Book[5];
		
		library[0] = new Book("태백산맥1", "조정래");
		library[1] = new Book("태백산맥2", "조정래");
		library[2] = new Book("태백산맥3", "조정래");
		library[3] = new Book("태백산맥4", "조정래");
		library[4] = new Book("태백산맥5", "조정래");
		
		for(Book book : library) {
			System.out.println(book);
			book.showInfo();
		}	
	}
}


객체를 생성하여 넣었을때는 제대로 데이터가 출력됨.

객체배열 복사

  • System.arrayCopy(src, srcPos, dest, destPos, length) 자바에서 제공되는 배열 복사 메서드를 사용하여 복사
  • 복사는 객체를 복사하는게 아니라 배열이 가진 주소값을 복사하는 것.
    얕은복사라고 부르며, 하나의 배열의 주소를 바꾸었을때 복사된 모든 배열의 주소가 바뀌게 됨.

위 예제에서 Book.java클래스는 그대로 사용.
-ObjectCopyTest.java-

public class ObjectCopyTest {

	public static void main(String[] args) {
		Book[] library = new Book[5];
		Book[] copyLibrary = new Book[5];
		
		library[0] = new Book("태백산맥1", "조정래");
		library[1] = new Book("태백산맥2", "조정래");
		library[2] = new Book("태백산맥3", "조정래");
		library[3] = new Book("태백산맥4", "조정래");
		library[4] = new Book("태백산맥5", "조정래");
		
		System.arraycopy(library, 0, copyLibrary, 0, 5);
		
		library[0].setAuthor("박완서");
		library[0].setTitle("나목");
		
		System.out.println("=== library ===");
		for(Book book : library) {
			System.out.println(book);
			book.showInfo();
		}
		
		System.out.println("\n=== copyLibrary ===");
		for(Book book : copyLibrary) {
			System.out.println(book);
			book.showInfo();
		}
	}
}

만약 하나의 배열에만 값을 변경하고싶다면 새로운 객체를 생성한 후 다시 배열에 객체를 넣어야 함.

public class ObjectCopyTest {

	public static void main(String[] args) {
		Book[] library = new Book[5];
		Book[] copyLibrary = new Book[5];
		
		library[0] = new Book("태백산맥1", "조정래");
		library[1] = new Book("태백산맥2", "조정래");
		library[2] = new Book("태백산맥3", "조정래");
		library[3] = new Book("태백산맥4", "조정래");
		library[4] = new Book("태백산맥5", "조정래");
		
		copyLibrary[0] = new Book();
		copyLibrary[1] = new Book();
		copyLibrary[2] = new Book();
		copyLibrary[3] = new Book();
		copyLibrary[4] = new Book();
		
		// 객체를 새로 생성하여 배열에 객체자체를 새로 입력
		for(int i = 0; i<library.length; i++) {
			copyLibrary[i].setAuthor(library[i].getAuthor());
			copyLibrary[i].setTitle(library[i].getTitle());
		}
		
		// arraycopy를 사용해 배열의 주소값만을 복사
//		System.arraycopy(library, 0, copyLibrary, 0, 5);
		
		library[0].setAuthor("박완서");
		library[0].setTitle("나목");
		
		System.out.println("=== library ===");
		for(Book book : library) {
			System.out.println(book);
			book.showInfo();
		}
		System.out.println("\n=== copyLibrary ===");
		for(Book book : copyLibrary) {
			System.out.println(book);
			book.showInfo();
		}
	}
}


22. 2차원배열 사용하기

  • 평면을 구현하는 배열.
  • 실제 메모리에는 하나의 행으로 저장된다.
  • 사용
int[][] arr = {{1,2,3}, {4,5,6}}
자료형 [][] 배열이름 = new int[행갯수][열갯수]

예제

public class TwoDimensionTest {

	public static void main(String[] args) {
		
		int [][] arr = {{1,2,3}, {1,2,3,4}};
		int [][] arr2 = new int [3][4];
		
		int i, j;
		
		for(i=0; i<arr.length; i++) {
			for(j=0; j<arr[i].length; j++) {
				System.out.print(arr[i][j] + ", ");
			}
			System.out.println("\t" + arr[i].length);
		}
		System.out.println();
		
		for(i=0; i<arr2.length; i++) {
			for(j=0; j<arr2[i].length; j++) {
				System.out.print(arr2[i][j] + ", ");
			}
			System.out.println("\t" + arr2[i].length);
		}
	}
}


직접 값을 넣어준 배열arr은 출력했을때 기입된 값이 나오지만
값 없이 크기만 선언한 배열arr2를 출력하면 값은 모두 0인 3행 4열의 2차원 배열이 출력된다.


23. 객채배열 ArrayList

java.util패키지에서 제공하는 ArrayList

  • 객체배열을 더 효율적으로 관리하기 위해 java에서 제공하는 클래스
  • 기존의 배열선언과 사용방식은 배열의 길이를 정하고 요소의 갯수가 배열의 길이보다 커지면 배열을 재할당하는 과정이 필요했음

ArrayList주요메서드

boolean add(E e) : 요소 하나를 배열에 추가함. E는 요소의 자료형을 의미.
int size() : 배열에 추가된 요소 전체 갯수를 반환
E get(int index) : 배열의 index 위치에 있는 요소 값을 반환
E remove(int index) : 배열의 index 위치에 있는 요소값을 제고하고 그 값을 반환
boolean isEmpty() : 배열이 비어있는지 확인

예제

ch21.Book클래스를 import하여 사용.

-ArrayListTest.java-

package ch23;

import java.util.ArrayList;

import ch21.Book;

public class ArrayListTest {

	public static void main(String[] args) {
		
		ArrayList<Book> library = new ArrayList<>();
		
		library.add(new Book("태백산맥1" , "조정래"));	// 객체를 생성하여 add로 ArrayList에 추가
		library.add(new Book("태백산맥2" , "조정래"));
		library.add(new Book("태백산맥3" , "조정래"));
		library.add(new Book("태백산맥4" , "조정래"));
		library.add(new Book("태백산맥5" , "조정래"));
		
		for (int i = 0; i < library.size(); i++) {
			library.get(i).showInfo();
		}
	}
}


F1을 누르면 java에서 제공되는 메서드에 대한 자세한 영문설명을 볼 수 있음.
좋은 개발자가 되기 위해선 제공하는 도움말 Help를 꼭 살펴보자.


24. ArrayList를 활용한 성적산출 프로그램

강의보며 따라하는 예제.
나중엔 문제만 보고 풀어보자.

1001학번 Lee와 1002학번 Kim, 두 학생이 있습니다. 
Lee 학생은 국어와 수학 2과목을 수강했고, Kim 학생은 국어, 수학, 영어 3 과목을 수강하였습니다.
Lee 학생은 국어 100점, 수학 50점입니다. 
Kim 학생은 국어 70점, 수학 85점, 영어 100점입니다. 
Student와 Subject 클래스를 만들고 ArrayList를 활용하여 두 학생의 과목 성적과 총점을 출력하세요

-Student.java-

package ch24;

import java.util.ArrayList;

public class Student {

	int studentId;
	String studentName;
	
	ArrayList<Subject> subjectList;

	Student(int studentId, String studentName) {
		this.studentId = studentId;
		this.studentName = studentName;
		
		subjectList = new ArrayList<>();
	}
	
	public void addSubject(String name, int point) {
		Subject subject = new Subject();
		subject.setName(name);
		subject.setScorePoint(point);
		
		subjectList.add(subject);
		
	}
	
	public void showScoreInfo() {
		int total = 0;
		
		for(Subject subject : subjectList) {
			total += subject.getScorePoint();
			System.out.println(studentId + "학생의 " + subject.getName() + "과목의 성적은 " + subject.getScorePoint() + "점 입니다.");
		}
		System.out.println(studentName + "학생의 총점은 " + total + "점 입니다.");
	}
}

-Subject.java-

package ch24;

public class Subject {
	
	private String name;
	private int scorePoint;
	
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getScorePoint() {
		return scorePoint;
	}
	public void setScorePoint(int scorePoint) {
		this.scorePoint = scorePoint;
	}
	
}

-StudentTest.java-

package ch24;

public class StudentSubjectTest {

	public static void main(String[] args) {

		Student studentLee = new Student(1001, "LEE");

		studentLee.addSubject("국어", 100);
		studentLee.addSubject("수학", 50);

		Student studentKim = new Student(1002, "KIM");
		
		studentKim.addSubject("국어", 70);
		studentKim.addSubject("수학", 86);
		studentKim.addSubject("영어", 100);
		
		studentLee.showScoreInfo();
		System.out.println("\n==========================================\n");
		studentKim.showScoreInfo();
		
	}

}



원래는 객체지향, 자바의 데이터형에 대한 선택강의가 더 있지만 기간안에 본강의를 다 들어야 소장권이 나와서 스프링으로 넘어감.
선택강의는 소장권 얻어서 볼 예정. 그래서 꼭 소장권을 따야함.

profile
천 리 길도 가나다라부터

0개의 댓글