[JAVA] 객체 지향 입문 - 2

WOOK JONG KIM·2022년 8월 30일
0

패캠_java&Spring

목록 보기
3/103
post-thumbnail

this

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

객체간 협력 예시

학생이 버스를 탄다 -> 학생이 가진돈 down -> 버스 승객수 & 수입 UP

// Student.java

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(1000);
		this.money -= 1000;
	}
	
	public void takeSubway(Subway subway) {
		subway.take(1200);
		this.money -= 1200;
	}
	
	public void showInfo() {
		System.out.println(studentName+"님의 남은 돈은" + money + "원 입니다.");
	}
}
// Bus.java

package ch14;

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(busNumber + "번 버스의 승객은 "+passengerCount + "명 이고, 수입은" + money+"원 입니다");
		
	}

}
// Subway.java

package ch14;

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 + "원 입니다");

	}
}
package ch14;

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);
		Bus bus500 = new Bus(500);
		
		studentJ.takeBus(bus100);
		
		Subway greenSubway = new Subway(2);
		studentT.takeSubway(greenSubway);
		
		studentJ.showInfo();
		studentT.showInfo();
		
		bus100.showBusInfo();
		greenSubway.showSubwayInfo();
		
		bus500.showBusInfo();
	}

}

Static 변수

  • 여러 인스턴스가 공유하는기준값이 필요한 경우

  • 인스턴스가 생성될 때 만들어지는 변수가 아닌, 처음 프로그램이 메모리에 로딩될 때 메모리를 할당

  • 클래스 변수, 정적변수라고도 함(vs. 인스턴스 변수)
  • 인스턴스 생성과 상관 없이 사용 가능하므로 클래스 이름으로 직접 참조

package ch16;

public class Employee {

		public static int serialNum = 1000;
		
		private int employeeId;
		private String employeeName;
		private String department;
        
        //증가된 사번을 각각 부여하기 위해 employeeId에 대입!
		
		public Employee() {
			
			serialNum++;
			employeeId = serialNum;
		}
        
        // private 멤버변수 접근 위해 get/set 사용
		
		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);
		
	}
}

static 변수는 프로그램이 process 되는 순간 데이터 영역에 할당되고 프로그램 unload시 사라진다

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

  • static 메서드는 인스턴스 생성과 무관하게 클래스 이름으로 호출 될 수 있음
  • 인스턴스 생성 전에 호출 될 수 있으므로 static 메서드 내부에서는 인스턴스 변수를 사용할 수 없음
public static void setSerialNum(int serialNum) {
		int i = 0; // 지역변수는 상관 X
		
		employeeName = "Lee";  //오류발생
		Employee.serialNum = serialNum;
	}

변수의 유효 범위와 메모리

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

디자인 패턴 - Singleton

  • 특정 용도로 객체를 하나만 생성하여, 공용으로 사용하고 싶을 때 사용하는 디자인 유형
  • 객체를 오직 하나만 생성되도록 보장, getInstance() 메서드를 통해서만 다른 클래스에서 객체에 접근할 수 있도록 해주는 클래스

이해 예시

회사에서 직원들이 모두 사용하는 정수기가 있다고 하자.

정수기의 이름을 간단하게 A라고 하겠다.

정수기를 사용할 때마다 정수기의 물의 양을 1만큼 감소한다고 하자. 이를 코드로 구현하려면 어떻게 해야 할까?

​정수기 A는 분명히 회사에 1개만 존재하기 때문에 매번 사용할 때마다 기존의 물의 양을 알 수 있어야 한다.

정수기를 사용할 때마다 객체를 매번 생성해야 하는데 어떻게 기존의 물의 양을 알 수 있을까?

정수기 A 객체를 static을 사용해서 선언하면 메모리에 정수기 A가 프로그램 종료 시까지 할당이 되면서 매번 정수기를 사용할 때마다 정수기를 생성하지 말고 정수기 A의 메모리에 접근하여 물의 양을 1만큼 감소시켜주면 되는 것이다.

먼저 정수기의 객체와 생성자는 외부에서 접근 및 생성하지 못하도록 private으로 선언해준다.

다만, 정수기 객체는 static를 붙여 만약 어떠한 방법으로 접근했다면 동일한 객체이도록 보장해준다.

package Single;

public class WaterPurifier {
	// private으로 선언하여 외부에서 접근 및 생성X
		private static WaterPurifier waterPurifier;
		private int amount;
		
		//private으로 선언하여 외부에서 접근X
		private WaterPurifier() { setAmount(100); }
		
		// static 변수를 접근하도록 하기 위해  static	 메서드로 선
		public static WaterPurifier getInstance() {
			// 초기 호출 시 객체 생성
			if (waterPurifier == null) {
					waterPurifier = new WaterPurifier();
			}
			
			return waterPurifier;
		}
		
		public int getAmount() {
			return amount;
		}
		
		public void setAmount(int amount) {
			this.amount = amount;
		}
		
		// 사용할 때 마다 물 양 감
		public void useWaterPurifier() {
			amount--;
		}
		
		

}

-출처 : https://sorjfkrh5078.tistory.com/107

구현 예시

// Car.java
package ch19;

public class Car {
	private static int carNum = 10000;
	private int own_carNum;
	
	public Car() {
		carNum++;
		own_carNum = carNum;
	}
	
	public int getCarNum() {
		return own_carNum;
	}
	
	private void setCarNum(int own_carNum) {
		this.own_carNum = own_carNum;
	}
}
// CarFactory.java

package ch19;

public class CarFactory {
	private static CarFactory carFactory;
	
	private CarFactory() {
	
	}
	
	public static CarFactory getInstance() {
		if (carFactory == null) {
			carFactory = new CarFactory();
		}
		
		return carFactory;
	}
	
	public Car createCar() {
		Car car = new Car();
		return car;
	}
	
}
// CarFactorytest.java

package ch19;

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 출력
		}
	}


배열(array)

  • 동일한 자료형의 순차적 자료 구조
  • 인덱스 연산자[ ]를 이용하여 빠른 참조가 가능
  • 물리적 위치와 논리적 위치가 동일

선언하기

int[] arr1 = new int[10];

int[] numbers = {10, 20, 30};            // new int[]  생략 가능 

int[] ids; 
ids = new int[] {10, 20, 30};            // 선언후 배열을 생성하는 경우는 new int[] 생략할 수 없음

enhanced for

배열의 n개 요소를 0 부터 n-1까지 순차적으로 순회할 때 간단하게 사용할 수 있음

for( 변수 : 배열) {

}

객체 배열 사용

  • 기본 자료형 배열은 선언과 동시에 배열의 크기만큼의 메모리가 할당되지만,
    객체 배열의 경우엔 요소가 되는 객체의 주소가 들어갈(4바이트, 8바이트) 메모리만 할당되고(null) 각 요소 객체는 생성하여 저장해야 함

생성 예시

public class BookArrayTest {

	public static void main(String[] args) {

		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(int i =0; i<library.length; i++) {
			System.out.println(library[i]);
			library[i].showBookInfo();
		}
	}
}

얕은 복사

  • 객체 주소만 복사되어 한쪽 배열의 요소를 수정하면 같이 수정 됨

  • 즉, 두 배열이 같은 객체를 가리킴

System.arrayCopy(src, srcPos, dest, destPos, length)

public class ObjectCopy {

	public static void main(String[] args) {

		Book[] library = new Book[5];
		Book[] copyLibaray = 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, copyLibaray, 0, 5);
		
		System.out.println("======copy library=========");
		for( Book book : copyLibaray ) {
			book.showBookInfo();
		}
		
		library[0].setTitle("나목");
		library[0].setAuthor("박완서");
		
		System.out.println("======library=========");
		for( Book book : library) {
			book.showBookInfo();
		}
		
		System.out.println("======copy library=========");
		
		for( Book book : copyLibaray) {
			book.showBookInfo();
		}
	}

깊은 복사

각각의 객체를 생성하여 그 객체의 값을 복사하여 배열이 서로 다른 객체를 가리키도록 함

public class ObjectCopy2 {

	public static void main(String[] args) {

		Book[] library = new Book[5];
		Book[] copyLibaray = 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", "조정래");
		
		copyLibaray[0] = new Book();
		copyLibaray[1] = new Book();
		copyLibaray[2] = new Book();
		copyLibaray[3] = new Book();
		copyLibaray[4] = new Book();
		
		// 리턴 값 얻은 뒤 설정
        
        for(int i = 0; i< library.length; i++) {
			copyLibaray[i].setTitle(library[i].getTitle());
			copyLibaray[i].setAuthor(library[i].getAuthor());
		}
		
		
		library[0].setTitle("나목");
		library[0].setAuthor("박완서");
	
		System.out.println("======library=========");
		for( Book book : library) {
			book.showBookInfo();
		}
		
		System.out.println("======copy library=========");
		for( Book book : copyLibaray) {
			book.showBookInfo();
		}
	}
}

다차원 배열 사용

  • 이차원 이상으로 구현 된 배열

public class TwoDimensionTest {

	public static void main(String[] args) {
		int[][] arr = { {1,2,3}, {4,5,6,7}};
		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();
		}
	}
}

행의 개수만큼 돌 때 => arr.length
열의 개수만큼 돌 때 => arr[i].length


ArrayList

  • java.util 패키지에서 제공

  • 객체 배열을 좀더 효율적으로 관리하기 위해 자바에서 제공해 주는 클래스

ArrayList 활용 예시

// subject.java

package ch25;

public class Subject {
	private String subjectName;
	private int subjectScore;
	
	public String getSubjectName() {
		return subjectName;
	}
	public void setSubjectName(String subjectName) {
		this.subjectName = subjectName;
	}
	public int getSubjectScore() {
		return subjectScore;
	}
	public void setSubjectScore(int subjectScore) {
		this.subjectScore = subjectScore;
	}

}
// student.java

package ch25;

import java.util.ArrayList;

public class Student {
	int studentID;
	String studentName;
	
	ArrayList<Subject>subjectList;
	
	
	public Student(int studentID, String studentName) {
		this.studentID = studentID;
		this.studentName = studentName;
		
		subjectList = new ArrayList<Subject>();
	}
	
	public void addSubject(String subjectName, int subjectScore) {
		Subject subject = new Subject();
		
		subject.setSubjectName(subjectName);
		subject.setSubjectScore(subjectScore);
		subjectList.add(subject);
	}
	
	public void showStudentInfo()
	{
		int total = 0;
		
		for(Subject s : subjectList) {
			
			total += s.getSubjectScore();
			System.out.println("학생" + studentName +"의" +s.getSubjectName() + "과목 성적은" + 
											s.getSubjectScore() +"입니다");
			}
			System.out.println("학생 " +studentName + "의 총점은 "+ total +"입니다. ");
	}
	
}
//StudentTest.java

package ch25;

public class StudentTest {

	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("수학", 85);
		studentKim.addSubject("영어", 100);
		
		studentLee.showStudentInfo();
		System.out.println("======================================");
		studentKim.showStudentInfo();
	}
}
profile
Journey for Backend Developer

0개의 댓글