객체배열이란?

객체 배열은 레퍼런스 변수에 대한 배열이다.

배열이 같은 자료형들의 변수를 하나의 묶음으로 다루는 것이라면, 객체 배열은 Example 클래스의 인스턴스들을 배열로 다루는 것이다.
객체배열 목적
  • 생성한 인스턴스도 배열을 이용해서 관리하면 동일한 타입의 여러 개 인스턴스를 연속 처리 할 수 있어 편리하다.
  • 또한 반환값은 1개의 값만 반환할 수 있어 동일한 타입의 여러 인스턴스를 반환해야 하는 경우도 객체 배열을 이용할 수 있다.
객체배열의 선언과 할당

 

클래스명 배열명[]   =   new 클래스명[배열크기]

(↑ 선언부)

클래스명[] 배열명    =   new 클래스명[배열크기]

                          (↑ 할당부)

      Example[] arr    =   new Example[2];

 

객체배열의 저장구조

 

arr라는 객체 배열은 arr[0], arr[1]이라는 참조형 변수에 대한 배열이고, 각 변수들은 Example의 인스턴스에 대한 주소를 참조하고 있다.

 

▼예시 : Car 클래스에서 modelName과 maxSpeed 인스턴스를 다루고 있다.

public class Car {
	
	private String modelName;
	private int maxSpeed;
	
	public Car(String modelName, int maxSpeed) {
		this.modelName = modelName;
		this.maxSpeed = maxSpeed;
	}
	
	public void driveMaxSpeed() {
		System.out.println(modelName + "이(가) 최고 시속 " + maxSpeed + "km/h로 달려갑니다.");
	}

}

 

▼ 객체배열을 사용하지 않으면 5대의 인스턴스를 각각 다루고, 1대의 값만 반환한다.

public class Application {

	public static void main(String[] args) {
    
        /* 자동차 5대 인스턴스를 생성 */
		Car car1 = new Car("페라리", 300);
		Car car2 = new Car("람보르기니", 350);
		Car car3 = new Car("롤스로이스", 250);
		Car car4 = new Car("부가티베이론", 400);
		Car car5 = new Car("포터", 450);
		
		car1.driveMaxSpeed();
		car2.driveMaxSpeed();
		car3.driveMaxSpeed();
		car4.driveMaxSpeed();
		car5.driveMaxSpeed();

 

▼ carArray라는 객체배열을 사용하여 5대의 인스턴스를 연속처리 할 수 있다.

Car[] carArray = new Car[5];	carArray 선언과 할당
System.out.println(carArray);   //[Lcom.greedy.section01.init.Car;@762efe5d
System.out.println(carArray[0]); //carArray[0]은 아직 Car 객체를 참조하지 않는 상태로 null 값이다.
carArray[0].driveMaxSpeed();  

//null 값을 가지는 레퍼런스 변수를 대상으로 참조 연산자를 사용하면 java.lang.NullPointerException이 발생한다.

 

▼ carArray 객체배열에 인덱스를 이용하여 Car 객체 참조하여 초기화 :  배열명[i] = new 클래스명();

		carArray[0] = new Car("페라리", 300);
		carArray[1] = new Car("람보르기니", 350);
		carArray[2] = new Car("롤스로이스", 250);
		carArray[3] = new Car("부가티베이론", 400);
		carArray[4] = new Car("포터", 450);

 

▼ carArray 객체배열은 배열이므로 반복문을 사용할 수 있다.

		for(int i = 0; i < carArray.length; i++) {
			carArray[i].driveMaxSpeed();
		}

 

▼ 향상된 for문도 사용할 수 있다.

		for(Car car : carArray) {
			car.driveMaxSpeed();
		}

 

▼ 객체 배열도 할당과 동시에 초기화 할 수 있다 : 클래스명[] 배열명 = {new 클래스명(), new 클래스명()...};

		Car[] carArray2 = {
				new Car("페라리", 300),
				new Car("람보르기니", 350),
				new Car("롤스로이스", 250),
				new Car("부가티베이론", 400),
				new Car("포터", 500)
		};

'LECTURE > JAVA' 카테고리의 다른 글

12.컬렉션  (0) 2023.01.06
11.제네릭  (0) 2023.01.06
08.상속  (0) 2023.01.06
06.클래스와 객체  (0) 2023.01.06
05.배열  (0) 2023.01.06

클래스와 인스턴스(=객체)

  • 클래스

1)객체를 추상화 한 것으로 인스턴스를 생성 할 목적으로 정의해 놓은 소스 코드 작성 단위

ex)자동차, 버스, 택시 등등

바퀴의 수, 문의 개수 여러가지 요소들을 뽑아내(추상화) → ‘클래스’ 로 정의

Car taxi = new Car();

Car bus = new Car();

2)객체를 생성하는데 사용하기 위해 객체를 정의해 놓음

객체란 클래스에 정의된 내용대로 메모리에 생성된 것이다. 객체를 사용한다는 것은 객체가 가지고 있는 속성과 기능을 사용하는 것.

클래스가 제품 설계도라면 객체는 제품이다.

 

객체의 구성요소

객체는 속성과 기능, 두 종류의 구성요소로 이루어져 있다. 객체지향 프로그래밍에서는 속성과 기능을 각각 변수와 메서드로 표현한다.

필드,멤버변수(속성)

메소드(기능)

 

객체와 인스턴스

클래스로부터 객체를 만드는 과정을 클래스의 인스턴스화라고 하며, 어떤 클래스로부터 만들어진 객체를 그 클래스의 인스턴스라고 한다.

객체가 포괄적인 의미이나 그 차이를 예시로 들자면, ‘책상은 객체이다.’ 와 ‘책상은 책상 클래스의 인스턴스이다.’ 가 각각 자연스러운 문맥이다.

 

객체의 생성과 사용

 

Member member = new Member();

Member 클래스 타입의 참조변수 member를 선언하면, 참조변수 member를 위한 공간이 할당된다. (stack)

연산자 new 에 의해 Member 클래스의 인스턴스가 메모리의 빈 공간에 생성된다. (heap)

대입연산자 = 에 의해서 생성된 객체의 주소값이 참조변수 member에 저장된다. 인스턴스를 다루기 위해서는 참조변수가 반드시 필요하다.

인스턴스는 참조변수를 통해서만 다룰 수 있으며, 참조변수의 타입은 인스턴스의 타입과 일치해야 한다.

member.변수 = 7;

member.메소드() {

}

 

 

클래스 

1.사용자 정의 자료형

- 클래스는 서로 다른 자료형의 데이터들을 사용자(개발자)정의로 하나로 묶어 새로운 타입을 정의할 수 있다.

(같은 자료형만을 묶을 수 있는 배열과 달리 다른 자료형들의 값을 하나로 묶을 수 있다.)

- 클래스 내부에 메소드를 작성하지 않고 바로 변수를 선언할 수도 있다. -> 전역변수(필드=인스턴스 변수=속성)

 

 2. 다른 곳에서 위의 사용자 정의 자료형 사용하기

1) 변수 선언 및 객체 생성

- new 연산자로 객체를 heap 영역에 할당하면 클래스에 정의한 필드와 메소드대로 객체가 생성된다.

- 필드에 접근하기 위해서는 레퍼런스명.필드명으로 접근한다. '.'은 참조 연산자라고 하는데, 레퍼런스 변수가 참조하고 있는 주소로 접근한다는 의미를 가진다.( 열은 인덱스로 접근, 객체는 필드명으로 접근한다.)

-> heap 에 생성되기 때문에 JVM 기본값으로 초기화 된다.

 

2) 필드에 접근해서 변수 사용하듯 사용할 수 있다.

 

캡슐화 (encapsulation)

  • 필드에 직접 접근할 때 생길 수 있는 문제점

1. 필드에 올바르지 않은 값이 들어가도 통제가 불가능하다.

 ex) hp에 음수가 올 수 없는데 필드에 직접 접근하여 음수를 넣을 수 있다.

 -> 잘못된 값을 검증하여 필드 값을 수정하는 메소드를 작성하여 위의 문제를 해결 가능하긴 함.

ex) 0보다 작은 경우 0으로 변경하는 메소드 작성.

 

2. 필드명을 변경할 경우 직접 필드에 접근하는 코드는 모두 컴파일 에러를 발생시킨다.

- 클래스의 일부를 수정 했지만 사용하는 곳에선 전부 수정해야 하기에 유지보수에 악영향

  • 위의 두 문제점 해결방법

- 접근 제한자 : 클래스 혹은 클래스의 멤버에 참조 연산자로 접근할 수 있는 범위를 제한하는 키워드

public
모든 패키지에 접근 허용
protected
동일 패키지에 접근 허용. 단, 상속 관계에 있는 경우 다른 패키지에서도 접근 가능.
default
동일 패키지에서만 접근 허용. (작성하지 않는 것이 default)
private
해당 클래스 내부에서만 접근 허용

    위의 4가지 접근 제한자는 클래스의 멤버(필드, 메소드)에 모두 사용 가능하다.

    단, 클래스 선언 시 사용하는 접근 제한자는 public 과 default만 가능하다.

- 필드에 직접 접근하지 않고 메소드를 이용하여 간접 접근한다.

1.필드에 접근제한자를 붙여 직접 접근을 막아서 옳지 않은 값을 넣지 못하게 한다. 2. 간접 접근을 할 수 있는 메소드를 만들어 name이 kind로 바뀌거나 음수 값을 넣더라도 처리 가능하게 한다.

 

 

객체 지향 언어 OOP

(Object Oriented Programming)

소프트웨어 방법론의 한 종류

현실 세계는 사물이나 개념처럼 독립되고 구분되는 각각의 객체로 이루어져 있으며, 발생하는 모든 사건들은 객체 간의 상호작용이라는 세계관을 프로그래밍 언어에 도입하여 만들어진 언어이다.

-> 만들어진 객체를 조금 더 확장해서 객체 간 상호작용, 서로 메세지를 보낼 수 있다. (method로 구현)

- 특징 및 장점

1. 코드의 재사용성이 높다.

새로운 코드를 작성할 때 기존의 코드를 이용하여 쉽게 작성할 수 있다.

2. 코드의 관리가 용이하다.

코드간의 관계를 이용해서 적은 노력으로 쉽게 코드를 변경할 수 있다.

3. 신뢰성 높은 프로그래밍을 가능하게 한다.

제어자와 메서드를 이용해서 데이터를 보호하고 올바른 값을 유지하도록 하며, 코드의 중복을 제거하여 코드의 불일치로 인한 오동작을 방지할 수 있다.

 

추상화

객체를 설계하기 위해서 복잡한 현실 세계를 프로그램의 목적에 맞게 단순화 하는 추상화라는 기법을 적용하게 된다.

추상화란?

공통된 부분을 추출하고 공통되지 않은 부분은 제거한다는 의미를 가지며, 추상화의 목적은 유연성을 확보하기 위함이다.

- 유연성 확보는 여러 곳에 적용 될 수 있는 유연한 객체를 의미하며, 즉 재사용성이 높아질 수 있게 한다는 의미이다.

- 객체의 재사용성이 증가하면 중복 작성되는 코드를 줄일 수 있으며, 오류 발생 가능성을 감소시키고 유지보수성을 증가시킨다.

 

예시) 차의 시동을 키는 것은 car 와 carracer 의 공통속성 이므로 필드에 작성한다.

시동을 키는 작동 방식은 startUP 메소드에 숨긴다.

public class Car {
	
	private boolean isOn;	//초기에는 시동이 꺼진 false 상태
	
	public void startUp() {
	/* 시동 걸기 - 시동이 걸려있는 상태인 경우에는 할 일이 없고, 시동이 걸려있지 않은 경우에만 시동을 건다. */
		if(isOn) {
			System.out.println("이미 시동이 걸려있습니다.");
		} else {
			isOn = true;
			System.out.println("시동을 걸었습니다. 이제 출발할 준비가 완료 되었습니다.");
		}
	}

 

카레이서는 car.startup 만을 호출해서 시동을 걸 수 있다. carracer2, carrace3도 똑같이 시동을 걸 수 있다. -> 재사용성

public class CarRacer {
	
	/* CarRacer가 상호 작용할 Car 클래스를 CarRacer는 알고 있어야 한다.
	 * 알고 있다는 의미는 필드에 가지고 있다는 의미를 가진다.
	 * */
	private Car car = new Car();
	
	public void startUp() {
		car.startUp();
	}

 

DTO

 행위 위주가 아닌 여러 데이터를 하나로 뭉치기 위한 객체(Data Transfer Object)

필드명을 그대로 사용한 설정자와 접근자로 인해 캡슐화의 원칙에 일부 어긋나기는 하지만, 매번 추상화를 하지 않고 미리 모든 필드에 대한 접근 가능성을 염두에 두고 작성해두는 관례로 인해 많이 사용된다.

- 모든 필드를 private로 직접 접근을 막고, 각 필드 값을 변경하거나 반환하는 메소드를 세트로 작성한다.

- 메소드는 설정자(setter), 접근자(getter)들로 구성된다.

public class MemberDTO {
	
	// 취급하려고 하는 회원 정보를 구상해서 필드를 작성한다. MemberDTO에 묶어둘 데이터들
	private int number;
	private String name;
	private int age;
	private double height;
	private boolean isActivated;
  •  설정자(setter) 작성 규칙 
    : 필드 값을 변경할 목적의 매개변수를, 변경하려는 필드와 같은 자료형으로 선언
    호출 당시 전달되는 매개변수의 값을 이용하여 필드의 값을 변경

    [표현식]
     public void set필드명(매개변수) {
     필드 = 매개변수;
       }
	public void setNumber(int number) {
	  this.number = number;
	}
  • this
    • 모든 인스턴스의 메소드에 숨겨진 채 존재하는 레퍼런스 변수로, 할당된 인스턴스의 주소가 저장되어 인스턴스 자신을 가리킨다.
    • 객체 자신을 메소드에 전달하거나 리턴하기 위해 사용된다.
    • 객체 생성자 내에서 사용할 경우, 다른 생성자를 호출한다.
    • 매개 변수와 객체 자신이 가지고 있는 변수의 이름이 같은 경우 이를 구분하기 위해 자신의 변수에 this를 사용한다.
  •     접근자(getter) 작성 규칙 : 필드의 값을 반환 받을 목적의 메소드 집합을 의미한다.
     각 접근자는 하나의 필드에만 접근하도록 한다.
     필드에 접근해서 기록된 값을 return을 이용하여 반환하며, 이 때 반환 타입은 반환하려는 값의 자료형과 일치시킨다.
       
      [표현식]
      public 반환형 get필드명() {
       return 필드명;
     }
	public int getNumber() {
	return number;
	}
    
    /* boolean의 접근자는 get으로 시작하지 않고 is로 시작하는 것이 일반적인 관례이다. */
	public boolean isActivated() {
		return isActivated;
	}

MemberDTO의 getter, setter 메소드를 이용

public class Application {

	public static void main(String[] args) {

		MemberDTO member = new MemberDTO();
		member.setNumber(1);
        
        System.out.println("회원번호 : " + member.getNumber());
        
        }
        
        
        //출력
        회원번호 : 1

 

생성자

  • 생성자(Constructor)란?

객체가 new 연산자를 통해 Heap 메모리 영역에 할당될 때 1회성으로 호출되는 리턴타입이 없는 메소드

1. 인스턴스 생성 시점에 수행할 명령이 있는 경우에 쓰인다.

2. 매개변수 생성자의 경우 인스턴스 생성 시 바로 필드 초기화하는 목적으로 여러 개의 setter 메소드를 호출한 것과 같은 효과를 가질 수 있다.

-> 주목적

3. 작성한 생성자 이외에는 인스턴스 생성 방법을 제공하지 않는다는 의미 (인스턴스 생성 방법 제한)

 

  • 생성자 작성 규칙

생성자의 선언은 메소드 선언과 유사하지만 반환값이 없으며 생성자명을 클래스명과 동일해야 함

작성 위치는 문법적으로 클래스 내부에 작성하면 되지만, 통상적으로 필드 선언부와 메소드 선언부 사이에 작성하는 것이 관례

public class User {
	
	/* 필드 선언부 */
	private String id;
	private String pwd;
	private String name;
	private java.util.Date enrollDate;
    
    // 기본 생성자
    //클래스 내에 생성자가 정의 되어 있지 않다면 컴파일러에 의해 기본 생성자가 자동으로 추가된다.
    // 하지만 생성자가 하나라도 정의 되어 있다면 컴파일러는 기본 생성자를 자동으로 추가하지 않으므로 주의한다.
    public User() {};
    
    /* 초기화 할 필드가 여러 개 있는 경우, 초기화 하고 싶은 필드의 갯수별로 생성자를 여러 개 만들 수 있다. */
	
    /* 매개변수가 있는 생성자 1 */
	public User(String id, String pwd, String name) {
		this.id = id;
		this.pwd = pwd;
		this.name = name;      
	}
	
	/* 매개변수가 있는 생성자 2 */
	public User(String id, String pwd, String name, java.util.Date enrollDate) {
		/* this() : 동일 클래스 내에 작성한 다른 생성자 메소드를 호출하는 구문 
		 * this()는 가장 첫 줄에 선언해야 하며, 그렇지 않은 경우 컴파일 에러 발생 */
		this(id, pwd, name);      // User(String id, String pwd, String name)와 같다.
		this.enrollDate = enrollDate;
	}
    
    
    
    /* 메소드 선언부 */
	/* getter, setter 작성해야 하지만 생략 */
	
	/* 모든 필드가 가지고 있는 값을 문자열로 만들어 반환하는 메소드 */
	public String getInformation() {
		return "User [id=" + this.id + ", pwd=" + this.pwd + ", name=" + this.name + ", enrollDate="
				+ this.enrollDate + "]";
	}

 

호출할 시 초기화한 필드에 대한 매개변수를 넣어서 호출한다.

        /* 기본 생성자 호출 */
		User user1 = new User();
		System.out.println(user1.getInformation());
		
		/* 매개변수 생성자 1 호출 */
		User user2 = new User("user01", "pass01", "유관순");
		System.out.println(user2.getInformation());
		
		/* 매개변수 생성자 2 호출 */
		User user3 = new User("user02", "pass02", "홍길동", new java.util.Date());
		System.out.println(user3.getInformation());
		
		/* 정의 되지 않은 형식의 생성자는 호출 불가능 */
		//User user4 = new User("user03", "pass03");

 

오버로딩

동일한 메소드명으로 다양한 종류의 매개변수에 따라 다르게 처리해야하는 것을 관리하기 위해 사용하는 기술 

  • 오버로딩 사용 이유

- 동일한 기능의 메소드를 매개변수에 따라 다르게 이름을 정의하면 복잡하고 관리하기 어려워진다.

- 따라서 동일한 이름으로 다양한 종류의 매개변수에 따라 처리해야 하는 여러 메소드를 동일한 이름으로 관리하기 위해 사용한다.

* EX) System.out.println() 메소드는 모든 데이터 타입에 대해 출력할 수 있도록 메소드가 오버로딩 되어 있다.

  • 오버로딩의 조건

- 메소드의 시그니처(signature)가 다르면 다른 메소드로 인식한다. (매개변수의 타입, 개수, 순서가 달라야 함)

- 파라미터 선언부가 다르게 작성 되어야 하며 접근제한자나 반환형, 매개변수 이름은 오버로딩 성립 요건에 해당하지 않는다.

 => 접근제한자나 반환형만 바뀌고 매개변수의 타입, 개수, 타입의 순서가 같으면 오버로딩되지 않는다.

 

매개변수의 이름만 바뀌었기 때문에 오버로딩 되지않아 컴파일 에러 발생

파라미터

메소드의 파라미터 선언부에는 다양한 종류의 값을 인자로 전달하여 호출 가능하다.

매개변수(parameter)로 사용 가능한 자료형

1. 기본 자료형

 2. 기본 자료형 배열 : 이 때엔 배열의 주소가 전달되는 얕은 복사가 일어나기에 인자로 전달하는 배열과 매개변수로 전달 받은 배열은 서로 동일한 배열을 가리킨다.

 3. 클래스 자료형

 4. 클래스 자료형 배열 // 추후 학습

 5. 가변인자 : 인자로 전달하는 값의 개수가 정해져 있지 않은 경우 가변 인자를 활용할 수 있으며 배열로 취급

 

가변 인자 배열은 몇 개가 전달 될지 모르는 상황이기 때문에 예시의 경우 이름과 구분하기 위해 뒤쪽에 작성해야 하며 앞 쪽에 작성하는 경우 에러가 발생한다.

pt.testVariableLengthArrayParameter("홍길동");	// 가변 인자는 전달하지 않아도 된다.
pt.testVariableLengthArrayParameter("유관순", "축구", "농구", "배구");
pt.testVariableLengthArrayParameter("신사임당", new String[] {"테니스", "서예"});	
                                                //배열의 형태로도 전달 가능하다.
public void testVariableLengthArrayParameter(String name, String... hobby) {
		
		System.out.println("이름 : " + name);
		System.out.println("취미의 개수 : " + hobby.length);
		System.out.println("취미 : " + Arrays.toString(hobby));
		
	}
    
    //출력
    이름 : 홍길동
	취미의 개수 : 0
	취미 : []
	이름 : 유관순
	취미의 개수 : 3
	취미 : [축구, 농구, 배구]
	이름 : 신사임당
	취미의 개수 : 2
	취미 : [테니스, 서예]

 

static

- static이란?

정적 메모리 영역에 프로그램이 start될 시 할당 하고자 할 때 사용하는 키워드로, static 필드나 메소드는 인스턴스 생성 없이 사용 가능

- 여러 인스턴스가 공유해서 사용할 목적으로 만드는 것

final

- final이란? 변경 불가의 의미를 담고 있는 키워드 메소드에서는 종단의 의미를 지님

- 따라서 초기 인스턴스가 생성 되고 나면 기본 값이 필드에 들어가게 되는데, 그 초기화 이후 값을 변경할 수 없기 때문에 선언하면서 바로 초기화를 해주어야 한다

- 클래스 필드의 final 변수는 선언과 동시에 초기화 하거나 생성자를 통한 초기화를 해야 함

- 상수 필드

생성자를 이용한 초기화는 불가능하다.

생성자는 인스턴스가 생성 되는 시점에 호출 되기 때문에 그 전에는 초기화가 일어나지 못한다.

static은 프로그램이 시작 될 때 할당 되기 때문에 결국 초기화가 되지 않은 상태로 선언 된 것과 동일하다.

 

singleton

- 싱글톤 패턴(singleton pattern)이란? 클래스의 인스턴스 사용시 메모리 공간에 있는 하나의 인스턴스를 공유해서 사용하는 디자인 패턴

(생성 된 하나의 인스턴스만을 사용)

하나의 법인카드 사용

클래스에서의 변수

- 변수의 종류

클래스에서의 변수는 아래와 같이 구분한다.

  1. 클래스 변수 : static 키워드를 가지고 필드에 선언하는 변수, 메모리의 static영역 사용
  2. 멤버 변수(인스턴스 변수) : static 키워드 없이 필드에 선언하는 변수, 메모리의 heap영역 사용
  3. 지역 변수 : 메소드, 생성자, 초기화 블록 내부에서 선언하는 변수

 

변수 생성시기 소멸시기
클래스변수 프로그램 시작 시 프로그램 종료 시
멤버변수 (인스턴스 변수) 인스턴스 생성 시 참조하지 않을 시 (GC 가 추후 제거)
지역변수 메소드 호출 시 메소드 종료시

 

초기화 순서



/* 1. 필드를 초기화 하지 않으면 JVM이 정한 기본 값으로 객체가 생성된다. */
//	private String name;
//	private int price;
//	private static String brand;
	
	/* 2. 명시적 초기화 */
	private String name = "갤럭시";
	private int price = 1000000;
	private static String brand = "삼송";
	
	/* 3. 초기화 블록 */
	/* 인스턴스 초기화 블록 */
	{
		name = "사이언";
		price = 600000;
		
		/* 인스턴스 초기화 블럭이 동작하는 시점에는 이미 초기화가 진행 된 정적 필드에
		 * 인스턴스 초기화 블럭에서 대입한 값으로 덮어쓰게 되는 것이다. */
		brand = "사과";		
		
	}
    
    /* static 초기화 블록 */
	static {
		brand = "헬지";
		
		/* static 초기화 블록에서는 non-static 필드를 초기화 하지 못한다.
		 * 정적 초기화 블럭의 동작 시점(프로그램 실행 시)에는 인스턴스가 아무것도 존재하지 않기 때문에
		 * 존재하지 않는 인스턴스 변수에 초기화 하는 것은 시기상 불가능하다. */
//		name = "아이뽕";
//		price = 2000000;
	}
	
	/* 4. 생성자 */
	public Product() {}

'LECTURE > JAVA' 카테고리의 다른 글

12.컬렉션  (0) 2023.01.06
11.제네릭  (0) 2023.01.06
08.상속  (0) 2023.01.06
07. 객체 배열  (0) 2023.01.06
05.배열  (0) 2023.01.06

배열

같은 자료형의 변수들을 하나의 묶음으로 다루는 것. int끼리 double끼리

배열은 저장된 값마다 인덱스 번호가 부여됨. (0부터 시작)

배열 선언과 할당

  • 배열 선언

자료형[] 배열명;

int[] arr;

자료형 배열명[];

int arr[];

  • 배열 할당
    • 메모리에 공간을 만든다.

배열명 = new 자료형[배열크기];

       arr = new int[100];

  • 배열 선언과 할당

자료형[] 배열명 = new 자료형[배열크기];

/* hashCode() : 일반적으로는 객체의 주소값을 10진수로 변환하여 생성한 객체의 고유한 정수값을 반환한다.
		 * */
		System.out.println("iarr의 hashcode : " + iarr.hashCode());
		System.out.println("carr의 hashcode : " + carr.hashCode());
		
		/* 배열의 길이를 알 수 있는 기능을 필드로 제공하고 있다. 
		 * 필드는 뒤에서 다시 다룬다. (일종의 변수)
		 * 참고로 String 문자열의 길이는 메소드로 제공하고 있기 때문에 문자열.length()로 사용한다.
		 * */
		System.out.println("iarr2의 길이 : " + iarr2.length);
		System.out.println("carr2의 길이 : " + carr2.length);

배열 초기화

  • 인덱스를 이용한 초기화
    • arr[0] = 1;
  • for문을 이용한 초기화 
for(int i = 0; i < arr.length; i++) {
		arr[i] = i;
}
  • 선언과 동시에 초기화
    • 중괄호 활용
    int[] arr = {1, 2, 3, 4, 5};
  • int[] arr = new int[] {1, 2, 3, 4, 5};
  • String fruit[] = {”사과”, “포도”, “참외”}; ->new int[] 생략 가능

 

배열 저장구조

  • 배열은 참조 변수(레퍼런스 변수), 주소값을 참조한다. 실제값X
  • int 값들은 heap 영역에 할당되고, 그 위치를 arr 이라는 참조 변수가 저장함


2차원 배열

자료형이 같은 1차원 배열들의 묶음으로 주로 테이블 형태의 데이터를 담는데 사용된다.

인덱스 번호 두 개 부여

int[][] arr = new int[3][4]

[][] → 2차원 배열이라는 표시

[3] → 행 [4] → 열

3개의 1차원 공간, 각 공간에 4칸씩

 

2차원 배열 선원과 할당

  1. 배열의 주소를 보관할 레퍼런스 변수 선언 (stack)

자료형[][] 배열명;

자료형 배열명[][];

자료형[] 배열명[];

int[][] iarr1;

2. 여러 개의 1차원 배열의 주소를 관리하는 배열을 생성 (heap)

iarr1 = new int[3][];

3. 주소를 관리하는 배열의 인덱스마다 배열을 할당 (heap)

iarr1[0] = new int[5];

iarr1[1] = new int[5];

iarr1[2] = new int[5];

→ 정변 배열 : 서로 같은 길이의 여러 배열

→ 가변 배열 : 서로 다른 길이의 여러 배열

2.3번 동시 진행 가능

iarr2 = new int[3][5];


  • 자료 할당

자료형[][] 배열명 = new 자료형[행크기][열크기];

레퍼런스 배열 →> 1차원 배열의 주소값 저장

: 두 1차원 배열은 연속 X , 따로따로 저장해서 보관

  • 정변 배열

자료형[][] 변수명 = new 자료형 [할당할 배열의 갯수][할당할 배열의 길이]

/* 각 배열의 인덱스에 접근, 값 대입 후 출력*/

int value = 1;
		for(int i = 0; i < iarr.length; i++) {
			for(int j = 0; j <iarr[i].length; j++) {
				iarr[i][j] = value++;
			}
		}
/* 값 출력 */
		for(int i = 0; i < iarr.length; i++) {
			for(int j = 0; j < iarr[i].length; j++) {
				System.out.print(iarr[i][j] + " ");
			}
			System.out.println();
		}
  • 가변 배열
자료형[][] 변수명 = new 자료형[할당할 배열의 갯수][];
변수명[배열 인덱스] = new 자료형[배열의 길이];
//값 대입, 인덱스를 이용한 초기화
iarr[0][0] = 1; 
iarr[0][1] = 2; 
iarr[0][2] = 3;
   //좌표개념
//반복문을 이용해 값을 대입하고 출력, 정변 배열과 같음
for(int i = 0; i < iarr.length; i++) {
			
			for(int j = 0; j < iarr[i].length; j++) {
				System.out.print(iarr[i][j] + " ");
			}
			
			System.out.println();
		}

2차원 배열 초기화

  • 인덱스를 이용한 초기화

arr[0][0] = 1;

arr[1][1] = 2;

  • for문을 이용한 초기화
for(int i = 0; i < iarr1.length; i++) {
			
			for(int j = 0; j < iarr1[i].length; j++) {
				arr[i][j] = j;			
			}
		}
  • 선언과 동시에 초기화

int[][] arr = {{1, 2, 3, 4},{5, 6, 7, 8}};

String fruit[][] = {{”사과”, “딸기”, “석류”},{”바나나”, “참외”, “레몬”}};

int[] arr1 = {1, 2, 3, 4, 5};		
int[] arr2 = {6, 7, 8, 9, 10};		
int[][] arr3 = {arr1, arr2};

배열의 출력

  1. 각 배열의 인덱스에 차례로 접근해서 값 출력
  • 대표로 0번 인덱스만
for(int i = 0; i < iarr1[0].length; i++) {
			System.out.print(iarr1[0][i] + " ");
		}			
	System.out.println();
  • 중첩 for문을 이용해서 배열 값 출력
for(int i = 0; i < iarr1.length; i++) {
			
			for(int j = 0; j < iarr1[i].length; j++) {
				System.out.print(iarr1[i][j] + " ");
			}
			
			System.out.println();

 

배열 복사

  • 얕은 복사

객체의 주소 값만 가져와 참조형 변수에 저장하고 하나의 객체를 두 변수가 참조하는 것.

서로 같은 배열을 참조하고 있기 때문에 복사본의 배열을 변경하더라도 원본 배열도 변경된다.

/* 얕은 복사를 확인할 원본 배열 생성 */
		int[] originArr = {1, 2, 3, 4, 5};
		
		/* 원본 배열을 복사 배열에 복사 */
		int[] copyArr = originArr;

얕은 복사의 활용 : 주로 메소드 호출 시 인자로 사용하는 경우와 리턴 값으로 동일한 배열을 리턴하고 싶은 경우

String[] names = {"유관순", "홍길동", "신사임당"};
		System.out.println("names의 hashcode : " + names.hashCode());
		
		/* print 메소드의 인자로 names 전달 */
		print(names);
		
		/* 리턴 값으로도 활용 */
		String[] animals = getAnimals();
		System.out.println("리턴 받은 animals의 hashcode : " + animals.hashCode());
  • 깊은 복사

새로운 배열 객체를 생성하여 기존 배열의 데이터를 복사하는 것.

서로 같은 값을 가지고 있지만, 서로 다른 배열이기 때문에 하나의 배열을 변경해도 다른 배열에 영향을 주지 않는다.

깊은 복사 하는 방법 4가지

/* 원본 배열 */
		int[] originArr = {1, 2, 3, 4, 5};
		
		/* 1. for문을 이용한 동일한 인덱스 값 복사 */
		int[] copyArr1 = new int[10];
		
		for(int i = 0; i < originArr.length; i++) {
			copyArr1[i] = originArr[i];
		}
		
		print(originArr);
		print(copyArr1);
		
		/* 2. Object의 clone()을 이용한 복사 */
		int[] copyArr2 = originArr.clone();
		print(copyArr2);
		
		/* 3. System의 arraycopy()를 이용한 복사 */
		int[] copyArr3 = new int[10];
		
		/* 원본 배열, 복사를 시작할 인덱스, 복사본 배열, 복사를 시작할 인덱스, 복사할 길이의 의미를 가진다. */
		System.arraycopy(originArr, 0, copyArr3, 3, originArr.length);
		
		print(copyArr3);
		
		/* 4. Arrays의 copyOf()를 이용한 복사 */
		/* '시작' 인덱스부터 원하는 길이만큼만 복사해서 사용 가능하다. */
		int[] copyArr4 = Arrays.copyOf(originArr, 10);
		print(copyArr4);

 

정렬

  • 값을 서로 변경하기
  • 변수는 하나의 값만 저장 가능하므로 값을 대입하면 이전의 값은 소멸되다는 점 때문에 임시변수를 하나 만듦

 💡 int temp = num1;

num1 = num2;

num2 = temp;

  • 배열의 인덱스에 있는 값도 서로 변경 가능
int[] arr = {2, 1, 3};
		
		int temp2 = arr[0];
		arr[0] = arr[1];
		arr[1] = arr[2];
		arr[2] = temp2;
		
		for(int num : arr) {
			System.out.print(num + " ");
		}

- 오름차순으로 정렬

1. Arrays.sort();

int[] iarr = {2, 5, 4, 6, 1, 3};
		
		int[] copy = iarr.clone();
		System.out.println("copy 정렬 전 : " + Arrays.toString(copy));
		Arrays.sort(copy);
		System.out.println("copy 정렬 후 : " + Arrays.toString(copy));

Arrays.toString(iarr) → [1, 2, 3] 형태로 구현하는 메소드

2.인덱스를 한 개씩 증가시키는 반복문

		 * 첫 번째 인덱스는 비교할 필요가 없으므로 1번 인덱스부터 비교를 시작한다. */
		for(int i = 1; i < iarr.length; i++) {
			
			/* 인덱스가 증가할 때마다 처음부터 해당 인덱스 - 1 까지의 값을 비교하는 반복문 */
			for(int j = 0; j < i; j++) {
				
				/* 오름차순 정렬을 위한 처리 
				 * 내림차순으로 구현하고자 한다면 부등호 방향을 반대로 처리 */
				if(iarr[i] < iarr[j]) {
					
					/* 값 위치 변경 */
					int temp = iarr[i];
					iarr[i] = iarr[j];
					iarr[j] = temp;
					
				}
			}

1번 인덱스 값부터 시작해서 i -1 번 인덱스 까지 비교한다. 

 

- 배열 중복 제거 아이디어

int[] arr = new int[10];
		
		for(int i = 0; i < arr.length; i++) {
			arr[i] = (int)(Math.random() * 20) + 1;
			
			/* 현재 랜덤 값을 채운 인덱스 이전의 인덱스를 확인하는 반복문 */
			for(int j = 0; j < i; j++) {
				
				/* 현재 랜덤 값 arr[i]와 이전 인덱스의 값 arr[j]가 같다면 중복 */
				if(arr[i] == arr[j]) {
					System.out.println(i + "인덱스에 " + arr[i] + "중복 값 발생");
					i--;
				}
				
			}

 

중복값이 발생한다면 i-- 시킨 후 반복문으로 돌아가 다시 중복이었던 i인덱스의 랜덤값을 뽑는다.

'LECTURE > JAVA' 카테고리의 다른 글

12.컬렉션  (0) 2023.01.06
11.제네릭  (0) 2023.01.06
08.상속  (0) 2023.01.06
07. 객체 배열  (0) 2023.01.06
06.클래스와 객체  (0) 2023.01.06

<두 수의 나눗셈>

문제 설명

정수 num1num2가 매개변수로 주어질 때, num1num2로 나눈 값에 1,000을 곱한 후 정수 부분을 return 하도록 soltuion 함수를 완성해주세요.

 

class Solution {
    public int solution(int num1, int num2) {
        int answer = 0;
        return (int)((double) num1 / num2 * 1000);
    }
}

문제 풀이 및 메모

나누고 곱한 후 정수 부분을 return하라고 해서 우선 소수점 부분까지 계산되도록 double 형으로 변환시켰다.

그리고 int 형으로 다시 변환하여 완성


<숫자 비교하기>

문제 설명

정수 num1num2가 매개변수로 주어집니다. 두 수가 같으면 1 다르면 -1을 retrun하도록 solution 함수를 완성해주세요.

   public int solution(int num1, int num2) {
       
        if (num1==num2){
            int answer = 1;
            return  answer;
        } else {
            int answer = -1;
            return answer;
        }
    } 
}

문제 풀이 및 메모

solution 문법을 몰라서 헤맨 문제...

처음엔 일단 아무렇게나 작성했는데 역시나 오류가 떴고

int answer = 0;
if (num1==num2){
return 1
} else {
return -1
}
 

다른 사람들이 질문한 걸 찾아보면서 작성해봤다. 맨 처음 int answer = 0 부분은 예시였다는 걸 여기서 깨닳음 ㅎㅎ

앞에 사칙연산 코드에서 다 지워도 상관없는 거였다.

<두 수의 합>

문제 설명

정수 num1num2가 주어질 때, num1num2의 합을 return하도록 soltuion 함수를 완성해주세요.

제한사항

  • -50,000 ≤ num1 ≤ 50,000
  • -50,000 ≤ num2 ≤ 50,000
class Solution {
    public int solution(int num1, int num2) {
        int answer = -1;
        return num1 + num2;
    }  
}

풀이 및 메모

solution함수를 처음 봐서 문제 푸는 걸 헤맸다.

풀이를 찾아보니 return 값에 들어갈 식을 작성하면 되는 거였다.

도움말을 다시 한 번 읽어보니

solution 함수에는 문제 설명에 나오는 입력값이 매개변수로 주어지며, 이를 활용해 적절한 값을 return 해야 합니다.

<주의> solution을 호출하는 코드(예. c++의 main함수)는 작성하지 않아도 됩니다.

라고 적여있었다. 일단 식을 작성하는 것에 의의를 둬야겠다.

 


 

<두 수의 차>

문제 설명

정수 num1num2가 주어질 때, num1에서 num2를 뺀 값을 return하도록 soltuion 함수를 완성해주세요.

class Solution {
    public int solution(int num1, int num2) {
        int answer = 0;
        return num1 - num2;
    }
}

풀이 및 메모

위에 합과 동일하게 풀이!

int answer 의 대입값의 차이는 뭘까?

<두 수의 곱>

문제 설명

정수 num1, num2가 매개변수 주어집니다. num1num2를 곱한 값을 return 하도록 solution 함수를 완성해주세요.

 

class Solution {
    public int solution(int num1, int num2) {
        int answer = 0;
        return num1 * num2;
    }
}

<몫 구하기>

문제 설명

정수 num1, num2가 매개변수로 주어질 때, num1num2로 나눈 몫을 return 하도록 solution 함수를 완성해주세요.

 

class Solution {
    public int solution(int num1, int num2) {
        int answer = 0;
        return num1 / num2;
    }
}

다른 사람 풀이를 보면 체크가 안되네..

문제

두 자연수 A와 B가 주어진다. 이때, A+B, A-B, A*B, A/B(몫), A%B(나머지)를 출력하는 프로그램을 작성하시오.

입력

두 자연수 A와 B가 주어진다. (1 ≤ A, B ≤ 10,000)

출력

첫째 줄에 A+B, 둘째 줄에 A-B, 셋째 줄에 A*B, 넷째 줄에 A/B, 다섯째 줄에 A%B를 출력한다.

제출

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		
		long a = sc.nextLong();
		long b = sc.nextLong();
		
		System.out.println(a + b);
		System.out.println(a - b);
		System.out.println(a * b);
		System.out.println(a / b);
		System.out.println(a % b);
	}

}

메모

문제

두 정수 A와 B를 입력받은 다음, A/B를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 A와 B가 주어진다. (0 < A, B < 10)

출력

첫째 줄에 A/B를 출력한다. 실제 정답과 출력값의 절대오차 또는 상대오차가 10-9 이하이면 정답이다.

제출

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		
		int a = sc.nextInt();
		int b = sc.nextInt();
		
		System.out.println((double)a / b);

	}

}

메모

  • 수정사항
  1. 실수형 double 로 출력하라는 뜻이었다.
  2. (double) (a/b) -> 정수이기 때문에 괄호 없이 (double)a/b 로 수정해야함.

문제

두 정수 A와 B를 입력받은 다음, AXB를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 A와 B가 주어진다. (0 < A, B < 10)

출력

첫째 줄에 AxB를 출력한다.

제출

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		
		int a = sc.nextInt();
		int b = sc.nextInt();
		
		System.out.println(a * b);

	}

}

메모

+ Recent posts