당신은 주제를 찾고 있습니까 “자바 오브젝트 – Java – Object 클래스 (1/5) : 소개“? 다음 카테고리의 웹사이트 ppa.maxfit.vn 에서 귀하의 모든 질문에 답변해 드립니다: https://ppa.maxfit.vn/blog/. 바로 아래에서 답을 찾을 수 있습니다. 작성자 생활코딩 이(가) 작성한 기사에는 조회수 25,993회 및 좋아요 121개 개의 좋아요가 있습니다.
자바 오브젝트 주제에 대한 동영상 보기
여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!
d여기에서 Java – Object 클래스 (1/5) : 소개 – 자바 오브젝트 주제에 대한 세부정보를 참조하세요
http://opentutorials.org/module/516/6241
자바 오브젝트 주제에 대한 자세한 내용은 여기를 참조하세요.
java.lang.Object 클래스 – 코딩의 시작, TCP School
java.lang 패키지 중에서도 가장 많이 사용되는 클래스는 바로 Object 클래스입니다. Object 클래스는 모든 자바 클래스의 최고 조상 클래스가 됩니다. 따라서 자바의 모든 …
Source: www.tcpschool.com
Date Published: 6/1/2021
View: 4754
[JAVA] Object 클래스 – 오브젝트 클래스 – TROLL
Object클래스 : 단순하게 모든클래스(API 또는 내가 만든 등)는 Object클래스의 자식클래스이다. 즉, Object클래스가 자바에서 ‘최상의 클래스’ …
Source: choseongho93.tistory.com
Date Published: 2/13/2022
View: 7555
2. Java 자바 [API] – Object 클래스, Object 클래스의 메소드 1
1. 객체 비교 equals(). 형태. public boolean equals(Object obj) { . . . } – 매개 타입 : Object …
Source: kephilab.tistory.com
Date Published: 12/15/2021
View: 6537
[Java] Object 클래스 – velog
Object는 모든 클래스의 가장 최상위 클래스이다. 자바에서 제공하는 모든 클래스들은 계층 구조로 되어있고, 그 최상위로 올라가면 Object 라는 클래스가 …
Source: velog.io
Date Published: 7/24/2022
View: 5627
[자바, Java] 객체(Obejct)란? – 컴공생의 다이어리
객체는 속성과 동작으로 구성되어 있다. 사람을 예로 들어보면 사람의 속성으로는 이름, 나이 등이 있다. 그리고 동작으로는 달리다, 공부하다 등이 있다.
Source: computer-science-student.tistory.com
Date Published: 4/14/2022
View: 8579
Object 클래스 – Java
자바에서 모든 클래스는 사실 Object를 암시적으로 상속받고 있는 것이다. … 다시 말해서 자바의 객체는 위의 메소드들을 반드시 가지고 있다고 할 …
Source: opentutorials.org
Date Published: 1/29/2022
View: 6870
java에서 객체를 생성하는 다양한 방법 – Tecoble
이 글은 java 초심자들에게 추천합니다. 우리가 사용하는 java라는 언어는 객체지향 프로그래밍 언어입니다. 객체지향 프로그래밍이란 수행하고자 …
Source: tecoble.techcourse.co.kr
Date Published: 5/4/2022
View: 6587
[JAVA] 클래스란? 객체란? – 나만을 위한 블로그
객체 또는 오브젝트(Object)는 클래스에서 정의한 것을 토대로 메모리(실제 저장공간)에 할당된 것으로, 프로그램에서 사용되는 데이터 또는 식별자에 …
Source: onlyfor-me-blog.tistory.com
Date Published: 6/1/2021
View: 8513
[자바 ④] 자바 JAVA 이론 (객체 / 클래스 / 메소드 )
객체 Object = 인스턴스 Instance. 객체란 속성과 기능이 묶인 프로그램 단위를 말한다. 여기서 속성(attribute)는 객체가 가진 고유한 특성이고 …
Source: datamoney.tistory.com
Date Published: 7/17/2022
View: 9862
[Java] 클래스와 객체 – 개발하는 고라니
Java의 객체 지향 특성. 객체지향 언어는 실세계의 객체를 프로그램 내에 표현하기 위해 클래스(Class)와 객체(Object) 개념을 도입하였다.
Source: dev-gorany.tistory.com
Date Published: 12/10/2022
View: 5361
주제와 관련된 이미지 자바 오브젝트
주제와 관련된 더 많은 사진을 참조하십시오 Java – Object 클래스 (1/5) : 소개. 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.
주제에 대한 기사 평가 자바 오브젝트
- Author: 생활코딩
- Views: 조회수 25,993회
- Likes: 좋아요 121개
- Date Published: 2014. 3. 10.
- Video Url link: https://www.youtube.com/watch?v=yqP3_cajDf4
코딩교육 티씨피스쿨
Object 클래스
java.lang 패키지
java.lang 패키지는 자바에서 가장 기본적인 동작을 수행하는 클래스들의 집합입니다.
따라서 자바에서는 java.lang 패키지의 클래스들은 import 문을 사용하지 않아도 클래스 이름만으로 바로 사용할 수 있도록 하고 있습니다.
java.lang.Object 클래스
java.lang 패키지 중에서도 가장 많이 사용되는 클래스는 바로 Object 클래스입니다.
Object 클래스는 모든 자바 클래스의 최고 조상 클래스가 됩니다.
따라서 자바의 모든 클래스는 Object 클래스의 모든 메소드를 바로 사용할 수 있습니다.
이러한 Object 클래스는 필드를 가지지 않으며, 총 11개의 메소드만으로 구성되어 있습니다.
toString() 메소드
toString() 메소드는 해당 인스턴스에 대한 정보를 문자열로 반환합니다.
이때 반환되는 문자열은 클래스 이름과 함께 구분자로 ‘@’가 사용되며, 그 뒤로 16진수 해시 코드(hash code)가 추가됩니다.
16진수 해시 코드 값은 인스턴스의 주소를 가리키는 값으로, 인스턴스마다 모두 다르게 반환됩니다.
다음 예제는 toString() 메소드를 이용하여 인스턴스의 정보를 출력하는 예제입니다.
예제 Car car01 = new Car(); Car car02 = new Car(); System.out.println(car01.toString()); System.out.println(car02.toString()); 코딩연습 ▶
실행 결과 Car@15db9742 Car@6d06d69c
자바에서 toString() 메소드는 기본적으로 각 API 클래스마다 자체적으로 오버라이딩을 통해 재정의되어 있습니다.
equals() 메소드
equals() 메소드는 해당 인스턴스를 매개변수로 전달받는 참조 변수와 비교하여, 그 결과를 반환합니다.
이때 참조 변수가 가리키는 값을 비교하므로, 서로 다른 두 객체는 언제나 false를 반환하게 됩니다.
다음 예제는 equals() 메소드를 이용하여 두 인스턴스를 서로 비교하는 예제입니다.
예제 Car car01 = new Car(); Car car02 = new Car(); System.out.println(car01.equals(car02)); car01 = car02; // 두 참조 변수가 같은 주소를 가리킴. System.out.println(car01.equals(car02)); 코딩연습 ▶
실행 결과 false true
자바에서 equals() 메소드는 기본적으로 각 API 클래스마다 자체적으로 오버라이딩을 통해 재정의되어 있습니다.
clone() 메소드
clone() 메소드는 해당 인스턴스를 복제하여, 새로운 인스턴스를 생성해 반환합니다.
하지만 Object 클래스의 clone() 메소드는 단지 필드의 값만을 복사하므로, 필드의 값이 배열이나 인스턴스면 제대로 복제할 수 없습니다.
따라서 이러한 경우에는 해당 클래스에서 clone() 메소드를 오버라이딩하여, 복제가 제대로 이루어지도록 재정의해야 합니다.
이러한 clone() 메소드는 데이터의 보호를 이유로 Cloneable 인터페이스를 구현한 클래스의 인스턴스만이 사용할 수 있습니다.
다음 예제는 clone() 메소드를 이용하여 인스턴스를 복제하는 예제입니다.
예제 import java.util.*; class Car implements Cloneable { private String modelName; ① private ArrayList
owners = new ArrayList (); public String getModelName() { return this.modelName; } // modelName의 값을 반환함 public void setModelName(String modelName) { this.modelName = modelName; } // modelName의 값을 설정함 public ArrayList getOwners() { return this.owners; } // owners의 값을 반환함 public void setOwners(String ownerName) { this.owners.add(ownerName); } // owners의 값을 추가함 public Object clone() { try { ② Car clonedCar = (Car)super.clone(); ③ // clonedCar.owners = (ArrayList)owners.clone(); return clonedCar; ④ } catch (CloneNotSupportedException ex) { ex.printStackTrace(); return null; } } } public class Object03 { public static void main(String[] args) { ⑤ Car car01 = new Car(); car01.setModelName(“아반떼”); car01.setOwners(“홍길동”); ⑥ System.out.println(“Car01 : ” + car01.getModelName() + “, ” + car01.getOwners() + ”
“); ⑦ Car car02 = (Car)car01.clone(); ⑧ car02.setOwners(“이순신”); ⑨ System.out.println(“Car01 : ” + car01.getModelName() + “, ” + car01.getOwners()); ⑩ System.out.println(“Car02 : ” + car02.getModelName() + “, ” + car02.getOwners()); } } 코딩연습 ▶
실행 결과 Car01 : 아반떼, [홍길동] Car02 : 아반떼, [홍길동, 이순신] Car02 : 아반떼, [홍길동, 이순신]
위 예제의 ②번 라인에서는 부모 클래스의 clone() 메소드를 호출하여 clone() 메소드를 오버라이딩하고 있습니다.
⑤번 라인에서는 Car 클래스의 인스턴스인 car01을 생성하고, ⑦번 라인에서는 오버라이딩한 clone() 메소드를 호출하여 복제를 수행하고 있습니다.
하지만 ②번 라인처럼 clone() 메소드를 재정의하면, 필드의 값이 ①번 라인처럼 인스턴스일 때는 제대로 된 복제를 수행할 수 없습니다.
⑧번 라인에서는 복제된 인스턴스인 car02의 owners 필드에 새로운 값을 하나 추가합니다.
하지만 ⑨번 라인의 실행 결과를 보면, ⑦번 라인의 결과와는 달리 원본 인스턴스인 car01의 owners 필드에도 새로운 값이 추가되었음을 확인할 수 있습니다.
이처럼 단순히 부모 클래스의 clone() 메소드를 호출하여 clone() 메소드를 재정의하면, 배열이나 인스턴스인 필드는 복제되는 것이 아닌 해당 배열이나 인스턴스를 가리키는 주소값만이 복제되는 것입니다.
따라서 정확한 복제를 위해서는 ③번 라인처럼 배열이나 인스턴스인 필드에 대해서는 별도로 clone() 메소드를 구현하여 호출해야 합니다.
③번 라인의 주석을 해제하고 결과보기를 다시 실행하면, 다음과 같이 정확한 실행 결과가 출력될 것입니다.
실행 결과 Car01 : 아반떼, [홍길동] Car02 : 아반떼, [홍길동] Car02 : 아반떼, [홍길동, 이순신]
Object 메소드
Object 클래스의 메소드는 다음과 같습니다.
메소드 설명 protected Object clone() 해당 객체의 복제본을 생성하여 반환함. boolean equals(Object obj) 해당 객체와 전달받은 객체가 같은지 여부를 반환함. protected void finalize() 해당 객체를 더는 아무도 참조하지 않아 가비지 컬렉터가 객체의 리소스를 정리하기 위해 호출함. Class
getClass() 해당 객체의 클래스 타입을 반환함. int hashCode() 해당 객체의 해시 코드값을 반환함. void notify() 해당 객체의 대기(wait)하고 있는 하나의 스레드를 다시 실행할 때 호출함. void notifyAll() 해당 객체의 대기(wait)하고 있는 모든 스레드를 다시 실행할 때 호출함. String toString() 해당 객체의 정보를 문자열로 반환함. void wait() 해당 객체의 다른 스레드가 notify()나 notifyAll() 메소드를 실행할 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함. void wait(long timeout) 해당 객체의 다른 스레드가 notify()나 notifyAll() 메소드를 실행하거나 전달받은 시간이 지날 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함. void wait(long timeout, int nanos) 해당 객체의 다른 스레드가 notify()나 notifyAll() 메소드를 실행하거나 전달받은 시간이 지나거나 다른 스레드가 현재 스레드를 인터럽트(interrupt) 할 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함. 연습문제
[JAVA] Object 클래스 – 오브젝트 클래스
▶ Object 클래스 – 오브젝트 클래스
● Object클래스
: 단순하게 모든클래스(API 또는 내가 만든 class 등)는 Object클래스의 자식클래스이다.
즉, Object클래스가 자바에서 ‘최상의 클래스’이다.
Object클래스에는 다양한 메소드가 존재하는데, 어떤 클래스에서도 이 메소드를 호출할수있다.
● Object클래스 대표 메소드 종류
– equals() 메소드 : 두 객체가 동일한 객체라면 true를 리턴하고, 다르다면 false를 리턴합니다.
– hashCode() 메소드 : 객체의 메모리 번지를 이용해서 해시코드를 만들어 리턴한다.
객체마다 다른값을 가지고 있다.
– toString() 메소드 : 객체의 문자 정보를 리턴한다. 즉, 객체를 문자열로 표현한다.
class Car{ private int speed; private int gear; private String color; } public class Test { public static void main(String[] args) { Car obj = new Car(); System.out.println(“obj 객체는 ” + obj.getClass()+”로 생성되었다.”); } }
main메소드가 있는 Test클래스에서 Car클래스의 객체를 생성해줍니다.
obj인스턴스의 getClass메소드를 호출합니다.
getClass메소드는 Object클래스에 있는 메소드입니다. 위에서 말했듯이 내가 만든 클래스도 자바에서는 자동으로 Object클래스를 상속합니다. 그렇기에 getClass를 사용할수있습니다.
import java.util.ArrayList; public class Test { public static void main(String[] args) { ArrayList arr = new ArrayList(); arr.add(123); arr.add(“456”); arr.add(1.123); Object ob01 = arr.get(0); Object ob02 = arr.get(1); Object ob03 = arr.get(2); System.out.println(ob01.getClass()); System.out.println(ob02.getClass()); System.out.println(ob03.getClass()); } }
Test클래스에서 ArrayList 컬렉션클래스의 객체 arr를 생성해줍니다.
add메소드를 사용해서 3개의 값들을 저장합니다.
그리고 get메소드를 호출해서 0부터 2까지 저장한 값들을 리턴받아오는데 여기서 Object클래스로 받아주면 모두 받아올수있습니다. 이유는 Object클래스는 어떤 클래스든 전부 부모클래스이기에 데이터타입으로 받아올수있습니다.
그값들을 모두 getClass로 출력해줍니다.
class Car { private String model; public Car(String model) { this.model = model; } } public class Test { public static void main(String[] args) { Car car1 = new Car(“vm502”); Car car2 = new Car(“vm502”); if(car1.equals(car2)) { System.out.println(“하나의 Car이다.”); }else { System.out.println(“서로 다른 Car이다.”); } } }
이번에는 equals메소드를 실습해보겠습니다.
Car class의 생성자를 생성할때 매개변수로 String타입의 값을 받고 model필드에 저장해줍니다.
그러면 main메소드에 있는 Test클래스에서 car1와 car2를 각각 같은 String타입의 값을 넣어 만들어줍니다.
하지만, 각각 인스턴스를 생성해주었습니다.
그리고 car1.equals(car2)를 비교해주면 당연히 false가 리턴되면서 ‘서로 다른 Car이다.’라고 출력됩니다.
우선, equals메소드는 Object클래스의 메소드이기에 car1객체를 호출할수있습니다.
그리고 equals메소드는 객체하고만 비교해주기에 model의 값이 같다해도 엄연히 car1과 car2 이름부터 다르고
인스턴스가 다르기에 false가 리턴됩니다.
class Car{ private String model; private String year; public Car(String model, String year) { this.model = model; this.year = year; } public String toString() { return model + ” , ” + year; } } public class Test { public static void main(String[] args) { Car car1 = new Car(“first”, “2001”); Car car2 = new Car(“second”, “2018”); System.out.println(car1.toString()); System.out.println(car2.toString()); } }
이번에는 toString메소드를 실습해보겠습니다.
toString메소드는 Object클래스에 존재합니다. 이 메소드를 Car클래스에서 오버라이딩해서 소스를 짜보았습니다.
main메소드가 있는 Test클래스에서 Car클래스의 인스턴스를 car1과 car2를 생성해주고 인자값으로 first, 2001을 넘겨주고 second, 2018을 넘겨줍니다. 각각 객체에서 모델과 년도 필드가 저장되었을테고, 이 값들을 오버라이딩(재정의)한
toString메소드를 통해 출력해주면 각 객체의 필드들이 출력됩니다.
만약에 오버라이딩을 안했다면 그냥 객체의 문자정보를 출력해주는데 이는 사람이 알아볼수없는 클래스@16진수 해시코드로
구성된 문자정보를 콘솔창에 출력되는걸 확인할수있습니다.
반응형
2. Java 자바 [API] – Object 클래스, Object 클래스의 메소드 1
자바의 클래스를 선언할 때 extends 키워드로 다른 클래스를 상속하지 않으면
암시적으로 java.lang.Object 클래스를 상속하게 된다.
따라서 자바의 모든 클래스는 Object 클래스의 자식이거나 자손 클래스가 된다.
즉, Object는 자바의 최상위 부모 클래스에 해당된다.
최상위 Object 클래스는 모든 클래스가 상속한다.
– Object 클래스는 필드가 없고 메소드로 구성되어 있다.
이 메소드들은 모든 클래스들이 Object 클래스를 상속하므로, 모든 클래스에서 이용할 수 있다.
Object 클래스의 메소드들 1
1. 객체 비교 equals()
형태
public boolean equals(Object obj) { . . . }
– 매개 타입 : Object 로 모든 객체가 매개 값으로 대입될 수 있다.
(Object가 최상위 타입이므로 모든 객체는 Object 타입으로 자동 타입 변환될 수 있기 때문이다.)
– 리턴 타입 : boolean 두 객체가 동일한 객체라면 true, 그렇지 않으면 false 를 리턴한다.
equals() 메소드는 비교 연산자인 “==” 과 동일한 결과가 리턴 된다.
Object obj1 = new Object();
Object obj2 = new Object();
boolean result = obj1.equals(obj2); // 기준 객체 : obj1 비교 객체 : obj2 true 리턴
boolean result = (obj1 == obj2); // 위의 실행문과 동일한 결과 true 리턴
논리적으로 동등하다는 의미 : 같은 객체이건 다른 객체이건 상관없이 저장하고 있는 데이터가 동일함
예) String 객체의 equals() 메소드는 String 객체의 번지값을 비교하는 것이 아닌 문자열이 동일한지 조사해서
같다면 true, 그렇지 않다면 false를 리턴한다.
즉, String 클래스가 Object의 equals() 메소드를 재정의(오버라이딩)해서 번지 비교가 아닌
문자열 비교로 변경했기 때문이다.
Object 클래스의 equals() 메소드는 직접 사용되지 않고 하위 클래스에서 재정의(오버라이딩) 되어서
논리적으로 동등비교 시 이용된다.
예) Member 객체는 다르지만 id 필드 값이 같으면 논리적으로 동등한 객체로 취급하고 싶을 경우
Object 클래스의 equals() 메소드를 재정의해서 id 필드 값이 같음을 비교한다.
equals() 메소드를 재정의할 시,
매개값(비교 객체)이 기준 객체와 동일한 타입의 객체인지 먼저 확인해야 한다.
Object 타입의 매개 변수는 모든 객체가 매개값으로 제공될 수 있기 때문에 instanceof 연산자로
기준 객체와 동일한 타입인지 제일 먼저 확인해야 한다.
만약 비교 객체가 다른 타입이라면 equals() 메소드는 false를 리턴해야 한다.
비교 객체가 동일한 타입이라면 기준 객체 타입으로 강제 타입 변환해서 필드 값이 동일한지 검사한다.
예) Member.java : 객체 동등 비교 (equals 메소드 오버라이딩)
public class Member { public String id; public Member(String id) { this.id = id; } @Override // Object의 equals() 메소드 오버라이딩 public boolean equals(Object obj) { if(obj instanceof Member) { // 매개값 obj가 Member 타입인지 확인 Member member = (Member) obj; // Member 타입으로 강제 타입 변환 if(id.equals(member.id)) { // id 필드 값이 동일한지 검사, 동일하다면 true 리턴 return true; } } return false; // 매개값 obj가 Member 타입이 아니거나 id 필드값이 다른경우 false } }
MemberExample.java : 객체 동등 비교 실행 클래스
public class MemberExample { public static void main(String[] args) { Member obj1 = new Member(“blue”); Member obj2 = new Member(“blue”); Member obj3 = new Member(“red”); if(obj1.equals(obj2)) { // 매개값이 Member 타입이고 id 필드 값도 동일하므로 true System.out.println(“obj1 과 obj2는 동등합니다.”); } else { System.out.println(“obj1 과 obj2는 동등하지 않습니다.”); } if(obj1.equals(obj3)) { // 매개값이 Member 타입이지만, id 필드 값이 동일하지 않아 false System.out.println(“obj1과 obj2는 동등합니다.”); } else { System.out.println(“obj1과 obj3은 동등하지 않습니다.”); } } }
2. 객체 해시 코드 hashCode()
객체 해시코드 : 객체를 식별할 하나의 정수값
Object의 hashCode() 메소드는 객체의 메모리 번지를 이용해서 해시코드를 만들어서 리턴한다.
따라서 객체마다 다른 값을 가지고 있다.
논리적 동등 비교 시 hashCode()를 오버라이딩할 필요성이 있는데,
컬렉션 프레임워크에서 HashSet, HashMap, Hashtable은 아래와 같은 방법으로 두 객체가 동등한지 비교한다.
우선 hashCode() 메소드를 실행해서 리턴된 해시코드 값이 같은지 검사한다.
해시코드 값이 다르면 다른 객체로 판단하고, 같으면 equals() 메소드로 다시 검사한다.
따라서 hashCode() 메소드가 true 가 나와도 equals()의 리턴 값이 다르면 다른 객체가 된다.
key.java : Object의 hasCode() 메소드를 재정의 하지 않음
public class Key { public int number; public Key(int number) { // 생성자 this.number = number; } @Override // Object 의 equals() 재정의 public boolean equals(Object obj) { if(obj instanceof Key) { // Key 타입과 같다면 Key compareKey = (Key) obj; // 강제 타입 변환 if(this.number == compareKey.number) { // number 필드 값이 같으면 true return true; } } return false; } }
이런 경우 HashMap 의 식별키로 Key 객체를 사용하면 저장된 값을 찾아올 수 없다.
number 필드값이 같더라도 hashCode() 메소드에서 리턴하는 해시코드가 다르기 때문에 다른 식별키로
인식하기 때문이다.
“new Key(1)” 객체로 “홍길동” 을 저장하고 다시 “new Key(1)”객체로 저장된 “홍길동”을 읽으려고
시도했을 때 null이 나온다!!
KeyExample.java : 다른 키로 인식
public class KeyExample { public static void main(String[] args) { // Key 객체를 식별키로 사용해서 String 값을 저장하는 HashMap 객체 생성 HashMap
hashMap = new HashMap (); // 식별키 “new Key(1)” 로 “홍길동”을 저장함 hashMap.put(new Key(1), “홍길동”); // 식별키 “new Key(1)” 로 “홍길동”을 읽어옴 String value = hashMap.get(new Key(1)); System.out.println(value); // null 출력 } } 의도한 대로 “홍길동” 을 읽으려면 아래와 같이 재정의한 hashCode() 메소드를 Key 클래스에 추가한다.
Key.java : hashCode() 메소드 재정의 추가
public class Key { public int number; public Key(int number) { // 생성자 this.number = number; } @Override // Object 의 equals() 재정의 public boolean equals(Object obj) { if(obj instanceof Key) { // Key 타입과 같다면 Key compareKey = (Key) obj; // 강제 타입 변환 if(this.number == compareKey.number) { // number 필드 값이 같으면 true return true; } } return false; } @Override public int hashCode() { return number; } }
hashCode() 리턴값을 number 필드값으로 했기 때문에 저장할 때의 “new Key(1)”과
읽을 때의 “new Key(1)”은 같은 해시코드가 리턴된다.
저장할 때의 new Key(1) 과 읽을 때의 new Key(1) 은 사실 다른 객체이지만
HashMap은 hashCode()의 리턴값이 같고, equals() 리턴값이 true 가 나오지 때문에
동등 객체로 평가한다.
즉, 같은 식별키로 인식한다는 의미이다. 결론적으로 말해서 객체의 동등 비교를 위해서는
Object의 equals() 메소드만 재정의하지 말고 hashCode() 메소드도 재정의해서
논리적 동등 객체일 경우 동일한 해시코드가 리턴되도록 해야 한다.
Member.java : hashCode() 메소드 재정의 추가
public class Member { public String id; public Member(String id) { this.id = id; } @Override public boolean equals(Object obj) { if(obj instanceof Member) { Member member = (Member) obj; if(id.equals(member.id)) { return true; } } return false; } @Override public int hashCode() { return id.hashCode(); } }
id 필드값이 같을 경우, 같은 해시코드를 리턴하기 위해
String의 hashCode() 메소드의 리턴값을 활용한다. String 의 hashCode()는 같은 문자열일 경우
동일한 해시코드를 리턴한다.
3. 객체 문자 정보 toString()
Object 클래스의 toString() 메소드는 객체의 문자 정보를 리턴한다.
객체 문자 정보 : 객체를 문자열로 표현한 값
기본적으로 Object 클래스의 toString() 메소드는 “클래스명@16진수해시코드”로 구성된 문자 정보를 리턴
Object obj = new Object();
System.out.println(obj.toString());
[실행 결과]java.lang.Object@de6ced
toString() 메소드의 리턴값은 자바 어플리케이션에서 별 값어치가 없는 정보이므로,
Object의 하위 클래스는 toString() 매소드를 재정의(오버라이딩)하여
간결하고 유익한 정보를 리턴하도록 되어 있다.
예) java.util 패키지의 Date 클래스는 toString() 메소드를 오버라이딩하여
현재 시스템의 날짜와 시간 정보를 리턴한다.
String 클래스는 toString() 메소드를 오버라이딩하여 저장하고 있는 문자열을 리턴한다.
ToStringExample.java : 객체의 문자 정보
public class ToStringExample { public static void main(String[] args) { Object obj1 = new Object(); Date obj2 = new Date(); System.out.println(obj1.toString()); System.out.println(obj2.toString()); } }
[실행 결과]java.lang.Object@1b15692
Wed Nov 13 09:33:06 KST 2020
예) SmartPhone 클래스에서 toString() 메소드를 오버라이딩해서 제작회사와 운영체제를 리턴
smartPhone.java : 객체의 문자 정보 (toString()) 메소드
public class SmartPhone { private String company; private String os; public SmartPhone(String company, String os) { // 생성자 this.company = company; this.os = os; } @Override public String toString() { // toString 오버라이딩 return company + “, ” + os; } }
SmartPhoneExample.java : 객체의 문자 정보 실행 클래스
public class SmartPhoneExample { public static void main(String[] args) { SmartPhone myPhone = new SmartPhone(“구글”, “안드로이드”); String strObj = myPhone.toString(); System.out.println(strObj); // 구글, 안드로이드 출력 System.out.println(myPhone); // 구글, 안드로이드 출력 } }
System.out.println() 메소드를 콘솔에 출력하기 위해 사용되었다. 이 메소드의 메개값은 콘솔에 출력할 내용인데,
매개값이 기본 타입(byte, short, int, long, float, double, boolean)일 경우 해당 값을 그대로 출력한다.
만약 매개값으로 객체를 주면,
객체의 toString() 메소드를 호출해서 리턴값을 받아서 출력하도록 되어 있다.
[Java] Object 클래스
오늘은 자바의 Object 클래스에 대해 포스팅을 하려고 한다.
Object 클래스의 정적 메소드들 (toString(), equals()) 에 대해 알아보자.
Object
Object는 모든 클래스의 가장 최상위 클래스이다.
자바에서 제공하는 모든 클래스들은 계층 구조로 되어있고, 그 최상위로 올라가면 Object 라는 클래스가 존재한다.
우리가 일반적으로 생성하는 클래스들도 extends 로 직접 상속하지는 않았지만, 자바 컴파일러는 일반 클래스를 Object 의 하위 클래스로 자동으로 설정하게 되어있다.
결론? 자바 라이브러리 or 유저가 만든 모든 클래스는 Object 클래스를 상속 받아서 사용하게 된다.
따라서 자바의 모든 클래스는 Object 클래스의 모든 메소드를 바로 사용할 수 있다.
그러면 이러한 Object 클래스에는 어떠한 메소드가 있을까?
아래부터 하나씩 살펴보도록 하자.
toString() 메소드
: 객체가 가지고 있는 정보 or 값들을 문자열로 만들어 return 하는 메소드.
아래의 예시를 보자.
package study . test . java ; class Human { private int age ; public void setAge ( int age ) { this . age = age ; } public class ToStringExample { public static void main ( String [ ] args ) { Human human = new Human ( ) ; System . out . println ( human . toString ( ) ) ; } }
필자가 만든 Human 클래스로 객체를 만들어 toString() 메소드를 사용해 출력한 결과이다.
결과에는 이상한 정보가 담겨있다. 이 값은 순수 Object 클래스의 toString 결과값이다. 차례대로 패키지명, 클래스명, 그리고 구분자@와 함께 16진수 해시코드가 출력된 것이다.
이것만 가지고는 Human 클래스의 객체 human에 대한 유의미한 정보를 뽑아 낼 수 없다. 이것이 toString 메소드의 재정의 가 권장되는 이유이다.
아래처럼 String 클래스나, File 클래스 등 자바 API 클래스에서는 toString 메소드를 재정의 하여 의미있는 값을 리턴해준다.
아래의 예시를 보자.
package study . test . java ; public class ToStringExample { public static void main ( String [ ] args ) { String str = “ABCDEFG” ; System . out . println ( str . toString ( ) ) ; } }
String 클래스는 내부에서 toString을 재정의하기 때문에 자신이 가진 값을 그대로 리턴해주는 것을 알 수 있다.
그러면 앞에서 했던 Human 클래스의 toString 메소드도 재정의해서 사용해보자.
@Override public String toString ( ) { return “나이는 ” + age ; }
Human 클래스에서 Override/Implements method 항목을 이용해서 toString 메소드를 재정의하였다.
public class ToStringExample { public static void main ( String [ ] args ) { Human human = new Human ( ) ; human . setAge ( 25 ) ; System . out . println ( human . toString ( ) ) ; } }
필자가 재정의했던 toString 메소드가 잘 호출되었음을 출력값을 통해 알 수 있다.
toString() 메소드는 자동으로 호출이 된다? 😐
우리가 자주 사용하는 String 클래스를 보자.
String 클래스는 객체를 선언하여 toString 메소드 없이 그냥 객체 자체로 변수에 담긴 내용을 가져와서 사용했다.
아래의 코드를 보자.
public class ToStringExample { public static void main ( String [ ] args ) { String str = “세진세진” ; System . out . println ( str ) ; } }
참조변수 str은 String클래스의 객체의 주소를 가리킨다. 근데 객체임에도 불구하고, str 만 가지고 독단적으로 사용되어지고 있다.
바로 이 지점에서 toString 메소드가 자동으로 호출되는 것이다.
위에서 필자가 만들었던 Human 클래스를 가지고 똑같이 시도해보자.
public class ToStringExample { public static void main ( String [ ] args ) { Human human = new Human ( ) ; human . setAge ( 25 ) ; System . out . println ( human ) ; } }
마찬가지로, toString 메소드 없이 그냥 객체 주소가 담긴 참조변수만 print 했을 때 toString으로 재정의된 내용이 출력됨을 알 수 있다.
Tip ! toString 메소드가 자동으로 호출되는 경우? 😶 객체를 println , printf , 문자열 연결 연산자 ( + ) 구문에 넘길 때
, , 구문에 넘길 때 디버거가 객체를 출력할 때
equals() 메소드
: 두 객체를 비교하여 같으면 true, 다르면 false 를 리턴하는 메소드이다.
(기본적으로는 값 비교 . 재정의해서 사용할 수 있음.)
equals() 와 == 의 차이점 ? 😐 메소드 vs 연산자 equals() : Object 클래스에 정의된 메소드 .
(String, Integer 등의 하위 클래스에서 오버라이딩 되어있음.)
. (String, Integer 등의 하위 클래스에서 오버라이딩 되어있음.) == : 자바 언어 자체의 연산자 . 다시 말해서, equals() 메소드는 오버라이딩 가능하지만, == 는 오버라이딩이 불가능하다. 특정 언어들은 연산자도 오버라이딩이 가능하다고 하지만, 자바는 불가능하다. 값 비교 vs 주소값 비교 equals() : 기본적으로 값 비교 를 한다. 기본 타입에는 적용 불가.
를 한다. == : 기본적으로 주소값 비교 .(기본 타입에 대해서는 값 비교 .)
-> 참조 타입/기본 타입 전부 사용가능 !
아래의 예제를 참고하자.
package study . test . java ; public class TestExample { public static void main ( String [ ] args ) { int a = 10 ; int b = 10 ; System . out . println ( a == b ) ; Person person1 = new Person ( ) ; Person person2 = new Person ( ) ; Person person3 = person2 ; System . out . println ( person1 == person2 ) ; System . out . println ( person2 == person3 ) ; } }
처음으로 생성한 Person 객체가 0x100 주소에 생성되었다고 가정하자.
그러면 참조형 변수 person1의 값은 해당 주소값인 0x100이 된다.
그 다음으로 생성한 Person 객체의 참조형변수 person2는 0x200 의 값을 가진다고 가정하자. 그림으로 나타내면 다음과 같다.
int 타입인 변수 a,b 가 값을 비교하듯이 참조형 변수인 person1, person2, person3 가 주소값을 비교한다는 의미가 결국 해당 변수의 값을 비교하는 것이다.
다시 본문으로 돌아와서 equals() 메소드에 대해 알아보자.
equals() 역시 Object 클래스에 포함된 메소드이다. 하지만 기본 메소드를 그대로 사용할 경우 올바른 비교가 되지 않기 때문에, 실제 사용시에는 해당 클래스에 맞도록 오버라이딩 하여 사용한다.
먼저 Object 에 포함된 기본 equals() 메소드의 코드를 보면, 객체 자체를 관계 연산자 (==) 으로 비교한다. 따라서 내부적으로 같은 값을 가진 객체 2개라도, 다른 메모리 주소를 가지기 때문에 서로 다른 값으로 인식한다.
public boolean equals ( Object obj ) { return ( this == obj ) ; }
즉, 자기 자신을 비교하지 않는 이상 무조건 다른 값이 되는 것이다.
사용할 일은 그다지 없을 것으로 보인다.
이번에는 String 클래스 의 equals()메소드에 대해 알아보자.
보통 String 타입을 비교할 때는, 내용 이 같은지 비교한다고 설명한다.
그 이유는 String 클래스에서 equals() 메소드를 문자열 내용이 같은 경우 true를 리턴하도록 재정의했기 때문이다.
문자열 비교시 == 말고 equals() 를 사용하는 이유? 😧 기본 타입들 (int, char)은 Call by Value 형태로 기본적으로 대상에 주소값을 가지지 않는 형태로 사용된다. 하지만 String 은 기본타입이 아닌 클래스이다. 클래스는 기본적으로 Call by Reference 의 형태로 생성 시 주소값이 부여된다.
그렇기 때문에 String 타입을 선언했을 때는, 같은 값을 부여하더라도 서로간의 주소값이 다를 수 있다. public class compare { public static void main ( String [ ] args ) { String s1 = “abcd” ; String s2 = new String ( “abcd” ) ; if ( s1 == s2 ) { System . out . println ( “두개의 값이 같습니다.” ) ; } else { System . out . println ( “두개의 값이 같지 않습니다.” ) ; } } } == 연산자의 경우 객체의 주소값 을 비교하기 때문에
일반 객체처럼 Heap 영역에 생성된 String 객체와, 리터럴을 이용해 String Constant Pool 에 저장된 String 객체의 주소값은 다를 수 밖에 없다. 그러므로 두개의 값은 서로 다르다 는 결론이 나오게 된다.
이러한 경우가 발생할 수 있기 때문에, 자바에서 문자열을 비교하기 위해서는 equals() 메소드를 이용해 두개의 값을 비교해 주어야 한다. [참고] String 변수 생성시 주소할당 String 변수를 생성하는 2가지 방법 리터럴을 이용한 방식
new 연산자를 이용한 방식 위의 2가지 방식에는 큰 차이점이 있다. 리터럴을 사용하게 되면, String Constant Pool 이라는 영역에 존재하게 되고,
new 를 통해 생성하게 되면 Heap 영역에 존재하게 된다.
String을 리터럴로 선언할 경우 내부적으로 String의 intern() 메소드가 호출된다. 이 메소드는 주어진 문자열이 String Constant Pool에 존재하는지 검색하고, 있다면 그 주소값을 반환. 없다면 String Constant Pool에 넣고 새로운 주소값을 반환한다.
이번에는 equals() 메소드를 이용해 이전의 코드를 써보자.
public class compare { public static void main ( String [ ] args ) { String s1 = “abcd” ; String s2 = new String ( “abcd” ) ; if ( s1 . equals ( s2 ) ) { System . out . println ( “두개의 값이 같습니다.” ) ; } else { System . out . println ( “두개의 값이 같지 않습니다.” ) ; } } }
위의 코드처럼 String 클래스 안의 equals() 메소드를 사용하면, 두 비교대상의 주소값이 아닌 데이터값을 비교하기 때문에 어떻게 String을 생성하느냐에 따라 결과가 달라지지 않고 정확한 비교를 할 수 있다.
좀더 심화된 예제를 보자.
class Person { String name ; public Person ( String name ) { this . name = name ; } @Override public boolean equals ( Object obj ) { Person anotherObj = ( Person ) obj ; return ( this . name . equals ( anotherObj . name ) ) ; } }
package study . test . java ; public class EqualsExample { public static void main ( String [ ] args ) { String str1 = “hello” ; String str2 = “hello” ; System . out . println ( str1 == str2 ) ; System . out . println ( str1 . equals ( str2 ) ) ; String str3 = new String ( “abc” ) ; String str4 = new String ( “abc” ) ; System . out . println ( str3 == str4 ) ; System . out . println ( str3 . equals ( str4 ) ) ; Person person1 = new Person ( “kim” ) ; Person person2 = new Person ( new String ( “kim” ) ) ; Person person3 = person2 ; System . out . println ( person1 == person2 ) ; System . out . println ( person1 . equals ( person2 ) ) ; System . out . println ( person3 == person2 ) ; System . out . println ( person3 . equals ( person2 ) ) ; } }
str1 == str2는, 동일한 문자열을 String Constant Pool에서 곧바로 참조한 것이다. 동일한 String 문자열을 바로 참조할 경우 같은 주소값을 가질 수 있다. 그래서 결과는 true 이다.
이다. str1.equals(str2)는, String 객체의 equals() 메소드가 각 문자열의 글자를 하나씩 비교해서 동일했다고 판단하기 때문에 true 가 나온다.
str3, str4는 객체 2개를 만들고 각 객체의 멤버변수인 name에 문자열을 할당한다.
str3 == str4는, 서로 다른 주소값을 가지고 있기 때문에 false 이다.
이다. str3.equals(str4)는, abc 라는 동일한 문자열을 가진 String 객체이므로 재정의된 equals()의 결과로 true 가 된다.
그림으로 표현하면 아래와 같다.
그 다음은 Person 객체에 대한 내용이다.
첫번째 코드에서 Person 클래스의 equals() 메소드를 재정의 했다. 내용을 보면, 멤버변수인 name의 문자열이 동일한지를 비교하고 있다.
person1 == person2 는, 주소값 비교이기 때문에 false 이다.
person1.equals(person2)는, Person 클래스에서 재정의된 equals()를 사용한다. 따라서 두 객체의 name의 문자열이 kim으로 동일하기 때문에 true 이다.
person2는 name에 값을 할당할 때, new String(“kim”)으로 했기 때문에 새로운 String 객체를 생성한 것이다. 만약 equals()를 재정의할 때
return (this.name == anotherObj.name);
과 같이 했다면 결과는 false 가 될 것이다. name이 가리키는 주소값은 다르기 때문이다.
이다. person2는 name에 값을 할당할 때, new String(“kim”)으로 했기 때문에 새로운 String 객체를 생성한 것이다. 만약 equals()를 재정의할 때 과 같이 했다면 결과는 가 될 것이다. name이 가리키는 주소값은 다르기 때문이다. person2와 person3는 주소값이나 name에 할당된 문자열이 모두 같기 때문에 ==, equals() 의 결과가 모두 true 가 된다.
여기까지 String 클래스에서 재정의된 equals() 메소드에 대해 알아보았다.
[참고] equals의 재정의 메소드 만들기만드는 방법은 간단하다. 이클립스에서 자동완성 해주는 equals() 메소드를 사용하는 것이다.
(기본적으로 hashCode, equals 2가지를 동시에 쓰는 것을 권장하지만 단순 비교만 하는 경우라면 equals()만 사용해도 무방하다.)
package study . first ; public class Main { public static void main ( String [ ] args ) { Sub s1 = new Sub ( ) ; Sub s2 = new Sub ( ) ; System . out . println ( s1 . equals ( s2 ) ) ; } } class Sub { int x ; String a ; @Override public boolean equals ( Object obj ) { if ( this == obj ) return true ; if ( obj == null ) return false ; if ( getClass ( ) != obj . getClass ( ) ) return false ; Sub other = ( Sub ) obj ; if ( a == null ) { if ( other . a != null ) return false ; } else if ( ! a . equals ( other . a ) ) return false ; if ( x != other . x ) return false ; return true ; } }
내용을 간단히 살펴보면, 먼저 큰 단위로 객체 자체를 비교한다.
그 후 비교대상이 맞다면 필드를 비교한다. 3번째 if문을 보면, 형식과 값이 같더라도 클래스가 다르다면 다른 것으로 간주한다.
문자열은 문자열 비교 메소드를 사용해서 다시 비교하고, 원시타입은 그냥 비교해준다.
이정도의 원리만 알고 이클립스에서 만들어주는 메소드를 사용하면 될 것이라 생각한다.
글을 마치면서
toString 과 equals에 대해 공부를 했지만 까먹은 부분이 많았던 것 같다.
특히 == 와 equals의 차이는 알고있으면서도 막상 떠올리면 까먹어서 헷갈렸던 순간이 많았다. 이번에 정리하면서 다시한번 머릿속에 넣을 수 있어서 좋았다.
[자바, Java] 객체(Obejct)란?
728×90
객체(Obejct)란?
자바는 객체지향 프로그래밍(OOP; Object Oriented Programming) 언어 중 대표적인 언어이다. 객체지향 프로그래밍이라는 단어에서 객체란 무엇일까?
객체(Object)란 물리적으로 존재 하거나 추상적으로 생각 할 수 있는 것 중에서 자신과 다른 것을 식별가능한 것 을 말한다. 예를 들어 물리적으로 존재하는 학생, 회원 등과 추상적인 생산, 주문, 배송 등이 모두 객체가 될 수 있다.
객체의 구성
객체는 속성과 동작으로 구성되어 있다. 사람을 예로 들어보면 사람의 속성으로는 이름, 나이 등이 있다. 그리고 동작으로는 달리다, 공부하다 등이 있다.
자바에서는 이러한 객체의 속성을 필드(field), 동작을 메소드(method)라고 한다.
https://devuna.tistory.com/3
728×90
Object 클래스
상속
자바에서 상속이란 필수적이다. 여러분이 상속하건 하지 않았건 기본적인 상속을 하게 된다.
package org.opentutorials.javatutorials.progenitor; class O {}
위의 코드는 아래와 코드가 같다.
package org.opentutorials.javatutorials.progenitor; class O extends Object {}
자바에서 모든 클래스는 사실 Object를 암시적으로 상속받고 있는 것이다. 그런 점에서 Object는 모든 클래스의 조상이라고 할 수 있다. 그 이유는 모든 클래스가 공통으로 포함하고 있어야 하는 기능을 제공하기 위해서다.
API 문서를 보자.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html
메소드의 목록을 살펴보자.
위의 그림은 Object 클래스가 가지고 있는 메소드를 보여준다. 다시 말해서 자바의 객체는 위의 메소드들을 반드시 가지고 있다고 할 수 있다. 이 중에 중요하면서 입문 단계에서 이해할 수 있는 API들을 살펴보자.
toString
toString은 객체를 문자로 표현하는 메소드이다. 기본 예제인 계산기 코드를 보자.
package org.opentutorials.javatutorials.progenitor; class Calculator{ int left, right; public void setOprands(int left, int right){ this.left = left; this.right = right; } public void sum(){ System.out.println(this.left+this.right); } public void avg(){ System.out.println((this.left+this.right)/2); } } public class CalculatorDemo { public static void main(String[] args) { Calculator c1 = new Calculator(); c1.setOprands(10, 20); System.out.println(c1); } }
25라인에 아래 코드는 클래스 Calculator의 인스턴스 c1을 화면에 출력하고 있다.
System.out.println(c1);
필자의 결과는 아래와 같다. @ 뒤의 내용은 각자 다를 것이다.
org.opentutorials.javatutorials.progenitor.Calculator@11be650f
이것은 인스턴스 c1이 클래스 Calculator의 인스턴스라는 의미다. @ 뒤의 내용은 인스턴스에 대한 고유한 식별 값이라고 생각하자.
위의 정보도 유용한 정보이지만 클래스 설계자의 필요에 따라서 toString의 결과를 더욱 유용하게 만들 수 있다. 예를들어 계산기 인스턴스의 left, right 값을 알 수 있다면 개발을 좀 더 편하게 할 수 있을 것이다.
package org.opentutorials.javatutorials.progenitor; class Calculator{ int left, right; public void setOprands(int left, int right){ this.left = left; this.right = right; } public void sum(){ System.out.println(this.left+this.right); } public void avg(){ System.out.println((this.left+this.right)/2); } public String toString(){ return “left : ” + this.left + “, right : “+ this.right; } } public class CalculatorDemo { public static void main(String[] args) { Calculator c1 = new Calculator(); c1.setOprands(10, 20); System.out.println(c1); System.out.println(c1.toString()); } }
차이점
실행결과
left : 10, right : 20 left : 10, right : 20
클래스 Calculator에 toString을 재정의(overiding)했다. 그리고 인스턴스를 System.out.println의 인자로 전달하니까 toString을 명시적으로 호출하지 않았음에도 동일한 효과가 나고 있다. toString 메소드는 자바에서 특별히 취급하는 메소드다. toString을 직접 호출하지 않아도 어떤 객체를 System.out.print로 호출하면 자동으로 toString이 호출되도록 약속되어 있다.
이를 통해서 인스턴스 c1의 상태를 쉽게 파악할 수 있게 되었다.
equals
equals는 객체와 객체가 같은 것인지를 비교하는 API이다. 객체 간에 같고 다름은 필요에 따라서 달라질 수 있기 때문이다.
package org.opentutorials.javatutorials.progenitor; class Student{ String name; Student(String name){ this.name = name; } public boolean equals(Object obj) { Student _obj = (Student)obj; return name == _obj.name; } } class ObjectDemo { public static void main(String[] args) { Student s1 = new Student(“egoing”); Student s2 = new Student(“egoing”); System.out.println(s1 == s2); System.out.println(s1.equals(s2)); } }
결과는 아래와 같다.
false true
아래 코드를 보자.
System.out.println(s1 == s2);
결과는 false다.
그 이유는 s1과 s2가 서로 다른 객체이기 때문이다. 어찌 보면 당연한 결과다. 하지만 두 개의 객체가 논리적으로는 egoing이라는 값을 가지고 있기 때문에 객체를 만든 필자는 저 두 개의 객체가 같은 객체로 간주 되었으면 좋겠다. 이럴 때 클래스 Object의 메소드 equals를 overiding하면 된다.
public boolean equals(Object obj) { Student _obj = (Student)obj; return name == _obj.name; }
위의 코드 (Student)obj 는 메소드 equals로 전달된 obj의 데이터 타입이 Object이기 때문에 이를 Student 타입으로 형 변환하는 코드다. 아래 코드를 통해서 현재 객체의 변수 name과 equals의 인자로 전달된 객체의 변수 name을 비교한 결과를 Boolean 값으로 리턴하고 있다. 이 값에 따라서 두 개의 객체는 같거나 다른 것이 된다.
return name == _obj.name;
그런데 eqauls를 제대로 사용하기 위해서는 hashCode라는 클래스도 함께 구현해야 한다. 하지만 이에 대한 이야기는 우리 수업의 범위를 넘어서고 그 효용(사용 빈도)도 높지 않기 때문에 더 이상 설명을 하지 않겠다. 하지만 이 메소드의 취지를 이해하는 것은 또한 중요하기 때문에 언급을 하지 않을 수는 없었다. 메소드 equals에 대해서 필자가 권고하는 입장은 아래와 같다.
1. 객체 간에 동일성을 비교하고 싶을 때는 ==를 사용하지 말고 equals를 이용하자.
2. equals를 직접 구현해야 한다면 hashCode도 함께 구현해야 함을 알고 이에 대한 분명한 학습을 한 후에 구현하자.
3. equals를 직접 구현해야 한다면 eclipse와 같은 개발도구들은 equals와 hashCode를 자동으로 생성해주는 기능을 가지고 있다. 이 기능을 이용하는 것을 고려해보자. 아래 그림을 참고하자.
4. 그 이유가 분명하지 않다면 비교 연산자 == 은 원시 데이터형을 비교할 때만 사용하자.
원시 데이터 형(Primitive Data Type)이란 자바에서 기본적으로 제공하는 데이터 타입으로 byte, short, int, long, float, double, boolean, char가 있다. 이러한 데이터 타입들은 new 연산자를 이용해서 생성하지 않아도 사용될 수 있다는 특징이 있다.
finalize
finalize는 객체가 소멸될 때 호출되기로 약속된 메소드이다. 여기서는 이 메소드의 취지만 이해하면 된다. 많은 자바의 전문가들이 이 메소드의 사용을 만류하고 있다.
이 메소드 보다는 가비지 컬렉션(garbage collection)에 대해서 알아보자. 인스턴스를 만드는 것은 내부적으로는 컴퓨터의 메모리를 사용하는 것이다. 여기서 말하는 메모리는 RAM을 의미한다. 램은 가장 빠른 저장 장치이기 때문에 컴퓨터 프로그램들은 이 램에 저장된 후에 동작하게 된다. 하지만 램은 가격이 비싸고 용량이 적기 때문에 램은 컴퓨터에서 가장 소중한 저장 장치라고 할 수 있다. 그러므로 램의 적게 사용하는 프로그램이 좋은 프로그램이다. 그런 이유로 많은 프로그래밍 언어들이 램을 효율적으로 사용하기 위해서 더 이상 사용하지 않는 데이터를 램에서 제거할 수 있는 방법들을 제공한다.
하지만 자바에서는 이러한 방법이 제한적으로 제공되고 있는데 그것은 자동으로 해주기 때문이다. 이 작업을 자동화한 것을 가비지 컬렉션이라고 한다. 이를테면 어떤 인스턴스를 만들었고, 그것을 변수에 담았다. 그런데 그 변수를 사용하는 곳이 더 이상 없다면 이 변수와 변수에 담겨있는 인스턴스는 더 이상 메모리에 머물고 있을 필요가 없는 것이다. 자바는 이를 감지하고 자동으로 쓰지 않은 데이터를 삭제한다. 따라서 개발자가 사용하지 않는 데이터를 직접 삭제하는 작업을 하지 않아도 되는 것이다. 이것은 어려운 메모리 관리로부터 개발자들의 부담을 경감시킨 도약이라고 할 수 있다.
그럼에도 불구하고 좋은 에플리케이션을 만들기 위해서는 가비지 컬렉션에 대한 이해는 필요하다. 하지만 이는 우리 수업의 취지를 벗어나기 때문에 링크로 대체하겠다.
Java Garbage collection(NHN Hello world 블로그)
clone
clone은 복제라는 뜻이다. 어떤 객체가 있을 때 그 객체와 똑같은 객체를 복제해주는 기능이 clone 메소드의 역할이다. 예를 보자.
package org.opentutorials.javatutorials.progenitor; class Student implements Cloneable{ String name; Student(String name){ this.name = name; } protected Object clone() throws CloneNotSupportedException{ return super.clone(); } } class ObjectDemo { public static void main(String[] args) { Student s1 = new Student(“egoing”); try { Student s2 = (Student)s1.clone(); System.out.println(s1.name); System.out.println(s2.name); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } }
차이점
Student 예를 조금 변형했다. 결과는 아래와 같다. 복사에 성공했다.
egoing egoing
위의 코드에서 클래스 Student가 인터페이스 Cloneable을 구현하고 있는 것을 주의 깊게 살펴보자. 인터페이스 Cloneable의 코드는 실제 내용은 아래와 같다.
public interface Cloneable {}
비어있는 인터페이스다. 그럼에도 불구하고 이것을 사용한 이유는 클래스 Student가 복제 가능하다는 것을 표시하기 위한 것이다. 만약 이 인터페이스를 구현하지 않고 있는 클래스에 대한 복제를 시도하면 오류가 발생할 것이다.
만약 복사를 보다 정교하게 하고 싶다면 오버라이딩 한 메소드 clone를 직접 구현하면 된다. 하지만 이에 대한 논의는 우리 수업의 범위를 애매하게 넘어서는 것이기 때문에 필자는 설명하지 않는 것을 택하겠다.
이해해야 하는 것과 알아야 하는 것
Object 클래스를 놓고 생각해보자. 이 클래스가 모든 클래스의 부모라는 사실은 이해의 영역이 아니라 약속의 영역이다. 즉 자바를 만든 측과 자바를 사용하는 측의 약속이다. 그리고 이 클래스가 clone이나 toString과 같은 메소드를 가지고 있다는 것 또한 이해의 영역이 아니라 숙지해야 하는 영역이다. 한편 모든 클래스가 toString을 사용할 수 있고 또한 이 메소드를 새롭게 재정의 할 수 있다는 점은 이해의 영역이다. 어떤 지식을 배울 때는 이해해야 하는 것과 그냥 알아야 하는 것을 잘 분별하는 것이 중요하다.
java에서 객체를 생성하는 다양한 방법
이 글은 java 초심자들에게 추천합니다.
우리가 사용하는 java라는 언어는 객체지향 프로그래밍 언어입니다.
객체지향 프로그래밍이란 수행하고자 하는 프로그래밍 로직을 상태와 행위로 이루어진 객체들의 모임으로 수행해나가는 것입니다.
자연스레 우리는 java로 프로그래밍을 할 때 어떠한 행위 을 맡길 객체를 생성하게 되고, 행위를 수행할 책임 을 맡은 객체에게 상태 를 부여합니다.
이렇게 객체에 책임과 상태를 부여함으로써 현실 세계에서의 물건과 유사합니다.
예를 들어 학생이 24살 이라는 상태와 샐리 라는 이름을 가지고 있는 것을 생각할 수 있습니다.
그렇다면 이러한 객체를 생성하는 방법에는 어떤 것이 있을까요?
기본 생성자
가장 기본적으로 객체를 생성하는 방법을 알아봅시다.
예제의 객체는 Student 는 자신의 상태 인 나이와 이름을 가지고 있습니다.
Student 는 자신의 나이에서 입력받은 adder 를 더하는 행위 를 수행하는 addAge() 메서드를 가지고 있습니다.
이렇게 자신의 상태를 가지고 있는 객체는 그 상태를 초기화해주는 생성자가 필요합니다.
생성자까지 포함한 Student 객체의 코드는 아래와 같습니다.
public class Student { private int age ; private String name ; public Student ( String name , int age ) { this . name = name ; this . age = age ; } public void addAge ( int adder ) { this . age += adder ; } }
아래와 같은 코드로 Student 객체의 name 에는 “sally”, age 에는 24라는 상태를 부여할 수 있습니다.
Student student = new Student ( “sally” , 24 ) ;
만약 여기서 같은 변수를 가진 StudentRequest를 전달받아 Student로 변환해야하는 경우가 있다고 가정해봅시다.
StudentRequest studentRequest = new StudentRequest ( “student” , 23 ) ; Student student = new Student ( studentRequest . getName ( ) , studentRequest . getAge ( ) ) ;
이처럼 구현하기에는 가독성이 떨어지고 studentRequest의 정보가 불필요하게 공개되어 캡슐화라는 장점을 가진 객체지향 프로그램의 특성이 헤쳐진다는 단점이 있습니다.
주생성자와 부생성자를 만들어 생성자를 추가하는 방법으로 이를 해결할 수 있습니다.
주생성자/부생성자
Student와 같이 나이와 이름 상태를 가진 Person 객체를 Student 객체로 생성한다고 생각해봅시다.
getter를 사용해 다음과 같이 구현할 수 있습니다.
Person nick = new Person ( “nick” , 8 ) ; Student personToStudent = new Student ( nick . getName ( ) , nick . getAge ( ) ) ) ;
하지만 이렇게 구현하게 되면 person이 가진 속성을 getter로 공개해야 한다는 단점이 있습니다.
이를 주생성자/부생성자를 통해 해결할 수 있습니다.
public class Student { private String name ; private int age ; public Student ( String name , int age ) { this . name = name ; this . age = age ; } public Student ( Person person ) { this ( person . getName ( ) , person . getAge ( ) ) ; } }
위와 같이 구현하게 되면 Person 객체를 다음과 같이 간단하게 생성할 수 있습니다.
Person nick = new Person ( “nick” , 8 ) ; Student personToStudent = new Student ( nick ) ;
이 때 아래의 생성자를 부생성자라고 하고, 상단의 생성자를 주생성자라고 합니다.
생성자가 추가됨에 따라 유연하게 객체를 생성할 수 있어진 것을 알 수 있습니다.
이번에는 student 객체에 score라는 상태가 추가된다고 가정해보겠습니다.
하지만 같은 student 객체임에도 이 score가 불필요한 경우가 있다고 할 때, 새로운 클래스를 만들지 않고 생성할 수 있는 방법은 무엇이 있을까요?
이 경우에도 새로운 생성자를 추가해 해결할 수 있습니다.
public class Student { private String name ; private int age ; private int score ; public Student ( String name , int age ) { this . name = name ; this . age = age ; } public Student ( String name , int age , int score ) { this . name = name ; this . age = age ; this . score = score ; } public Student ( StudentRequest studentRequest ) { this ( studentRequest . getName ( ) , studentRequest . getAge ( ) ) ; } public void addAge ( int adder ) { this . age += adder ; } }
아래와 같이 주생성자와 부생성자를 활용하는 this를 이용해 코드의 중복을 피할 수도 있습니다.
public Student ( String name , int age , int score ) { this ( name , age ) ; this . score = score ; }
이처럼 생성자의 추가를 두려워하지 않으면 객체를 사용함에 있어 유연성과 확장성이 커진다는 것을 알 수 있습니다.
하지만 이와 같이 구현하는 경우, 첫번째 생성자를 이용하면 score에는 null 값이 들어가게 된다는 문제가 있습니다.
이렇게 생성자가 만들어진 경우 score의 사용이 필요한 객체임에도 개발자가 착각해서 잘못된 생성자를 사용한다면, score 사용 시에 null이 들어가있어 객체를 사용할 때 자칫하면 NullPointerException이 발생할 수 있습니다.
정적 팩토리 메서드를 가짐으로써 이 문제를 해결할 수 있습니다.
정적 팩토리 메서드
정적 팩토리 메서드란 객체의 생성자를 숨기면서 객체를 만들어낼 수 있는 메서드입니다.
구현은 다음과 같습니다.
public class Student { private String name ; private int age ; private int score ; public Student ( String name , int age ) { this . name = name ; this . age = age ; } private Student ( String name , int age , int score ) { this ( name , age ) ; this . score = score ; } public static Student withScore ( String name , int age , int score ) { return new Student ( name , age , score ) ; } }
정적 팩토리 메서드는 이름을 가짐으로써 객체 생성의 의도를 드러낼 수 있습니다.
그렇게 되면 여러 생성자가 생겼을 때 명확한 의도를 가진 이름으로 구분할 수 있습니다.
또한, 이 예제와는 무관하지만 여러 객체를 캐싱해두고 팩토리메서드를 사용하는 경우에는 메서드가 호출될 때마다 인스턴스를 새로 생성하지 않아도 된다는 장점이 있습니다.
지금은 예시를 위해 이해가 쉬운 함수명을 지었지만 정적 팩토리 메서드명을 짓는데도 개발자 간 이해를 돕기 위한 암묵적인 컨벤션이 존재하는데, 자세한 것은 Effective Java 의 아이템 01 – 생성자 대신 정적 팩토리 메서드를 고려하라 에서 참고할 수 있습니다.
결론
객체의 활용성이 커질수록 우리는 다양한 생성자를 만들며 객체를 유연하게 확장해갈 필요성이 있습니다.
다양한 생성자로 확장에 유리해진 객체는 더 많은 책임을 맡아 수행할 수 있습니다.
적재적소에 올바른 방법으로 생성자를 만들고, 이를 통해 객체를 만들며 프로그래밍하는 것은 어떨까요?
[JAVA] 클래스란? 객체란?
728×90
반응형
메서드에 이어 이번 포스팅에선 자바로 프로그래밍할 경우 빼먹을 수 없는 요소인 클래스에 대해 기록하려 한다.
먼저 클래스의 사전적 의미는 아래와 같다.
Class : 학급, 반, 수업, 수업
학창시절 1학년 5반, 2학년 4반처럼 5반, 4반을 클래스라고 한다. 즉 5반이란 속성을 가진 사람은 5반이라는 클래스에 모여 있고, 4반이란 속성을 가진 사람은 4반에 모여있다고 볼 수 있다.
그럼 자바에서는 왜 이 클래스라는 단어를 가져와서 사용하는 걸까? 아래는 영문 위키백과의 내용이다.
객체 지향 프로그래밍에서 클래스는 객체를 만들기 위한 확장 가능한 코드 템플릿 이며, 상태(멤버 변수) 및 동작(멤버 함수 or 메서드) 구현에 대한 초기값을 제공한다. 많은 언어에서 클래스명은 클래스의 이름(템플릿 자체), 클래스의 기본 생성자(객체를 생성하는 서브 루틴)의 이름 및 클래스를 인스턴스화해서 생성된 객체의 유형으로 사용된다.
클래스의 생성자에 의해 객체가 생성되면, 결과 객체를 클래스의 인스턴스라고 하고 객체의 특정 멤버변수를 인스턴스 변수라고 한다. 이는 클래스에서 공유되는 클래스 변수와 대조된다.
위의 두 줄이 클래스의 핵심적인 내용이다. 클래스는 객체란 걸 만들기 위한 확장 가능한 템플릿이고, 변수와 메서드 구현에 대한 초기값을 제공한다.
확장 가능하다는 건 무슨 뜻일까? 확장은 범위, 규모, 세력을 늘려서 넓힌다는 뜻이다. 즉 클래스는 처음 설정한 때 뿐 아니라, 나중에라도 변수와 메서드를 추가/삭제할 수 있다는 뜻이다.
그럼 간단한 예시를 통해 클래스를 확인해보자.
public class Body { public String arm; public String leg; public String eye; public String ear; public void listen() { System.out.println(“듣는 중”); } public void see() { System.out.println(“보는 중”); } public void grab() { System.out.println(“잡았다”); } public void walk() { System.out.println(“걷는다”); } }
이해를 돕기 위해 간단하게 구조만 짰다.
여기서 arm, leg, eye, ear는 Body 클래스가 가진 속성이다. 그 아래의 4개의 메서드는 Body 클래스가 수행할 수 있는 행동이다.
그럼 이 클래스는 어떻게 사용할까? Main이란 클래스를 만들고 여기서 Body 클래스를 사용해보겠다.
public class Main { public static void main(String[] args) { Body } }
Body를 써야 하니까 이렇게 선언해봤다. 그런데 아무것도 나오지 않는다.
???? 아니 Body 클래스 쓸 거라서 메인 메서드를 만들고 그 안에 Body를 썼는데, 왜 쓸 수 없는 건가?
여기서 다른 개념이 튀어나온다. 바로 객체다.
그럼 객체란 뭘까? 객체의 사전적 의미는 아래와 같다.
객체 : 의사나 행위가 미치는 대상, 문장 내에서 동사의 행위가 미치는 대상, 작용의 대상이 되는 쪽
그러니까 뭔가를 당하는 쪽이라는 뉘앙스가 있단 건 알겠다. 그런데 이것만으론 궁금증이 해소되지 않는다. 그래서 객체란 뭘까?
영문/한글 위키백과에선 객체를 아래와 같이 설명하고 있다.
객체는 변수, 데이터 구조, 함수, 메서드가 될 수 있으며 식별자가 참조하는 메모리의 값이다. 객체는 변수, 함수, 데이터 구조의 조합이 될 수 있다…(중략)…객체는 다형성, 상속이 추가된 추상 데이터 유형이다. 객체에는 상태(데이터)와 동작(코드)가 있다. 온라인 쇼핑 시스템에는 쇼핑 카트, 고객, 제품 같은 객체가 있다. 그리고 주문, 결제, 할인 제공 같은 동작을 지원한다.
객체 또는 오브젝트(Object)는 클래스에서 정의한 것을 토대로 메모리(실제 저장공간)에 할당된 것으로, 프로그램에서 사용되는 데이터 또는 식별자에 의해 참조되는 공간을 의미하며, 변수, 자료구조, 함수, 메서드가 될 수 있다.
프로그래밍 언어는 변수를 이용해 객체에 접근하므로 객체와 변수란 용어는 종종 함께 사용된다. 그러나 메모리가 할당되기 전까지 객체는 존재하지 않는다. 객체 지향 프로그래밍에서 객체는 클래스의 인스턴스다.
식별자가 참조하는 어쩌고같은 어려운 소리는 집어치우고, 상태(데이터)와 동작(코드)가 있다는 부분이 중요하다.
객체는 클래스를 기반으로 생성된다. A클래스에 변수, 메서드 등을 정의한 다음 메인 메서드 혹은 다른 B클래스에서 A클래스의 객체를 만들어야 A클래스에 정의된 변수와 메서드를 쓸 수 있다.
아래는 이것의 예시를 보여주는 간단한 코드다.
public class Main { public static void main(String[] args) { // Body 클래스의 객체 생성 Body body = new Body(); // 객체를 통해 Body 클래스의 속성에 값을 집어넣는다 body.arm = “팔”; body.ear = “귀”; body.eye = “눈”; body.leg = “다리”; System.out.println(“arm = ” + body.arm + “, ear = ” + body.ear + “, eye = ” + body.eye + “, leg = ” + body.leg); // 객체를 통해 Body 클래스의 메서드를 호출해 작동하도록 지시한다 body.see(); body.grab(); body.listen(); body.walk(); } }
클래스의 객체를 생성하는 방법은 메인 메서드 안의 첫 줄처럼 하면 된다.
객체를 만들고자 하는 클래스의 이름을 쓰고(Body) 객체로 쓸 변수의 이름(body)을 지정한 뒤, new Body();를 통해 객체를 만든다. 그리고 만들어진 객체를 변수에 대입해서 Body 클래스의 객체를 만든다.
객체를 만들었으니 이제 Body 클래스에 선언했던 변수, 메서드들을 메인 클래스에서 불러다 쓰거나 값을 넣을 수 있다.
위의 예시를 실행하면 아래의 결과가 콘솔에 출력된다.
Body 클래스로 돌아가보면 각 변수들을 초기화하지 않고 그냥 선언만 했다. 그리고 메인 메서드 안에서 각 변수에 값을 할당한 다음 println()으로 찍어보니, Body 클래스의 변수에 무사히 들어가진 것을 확인할 수 있었다. 메서드도 제대로 작동한다.
주의할 것은 Body 클래스에서 변수나 메서드 중 하나의 접근제어자를 private로 선언하면 Main 클래스에선 그것을 사용할 수 없다. 이유는 정말 간단하니 만약 모른다면 접근제어자를 검색해서 공부하면 된다.
반응형
[자바 ④] 자바 JAVA 이론 (객체 / 클래스 / 메소드 )
반응형
2021.06.17 – [IT 독학/JAVA] – [자바 ①] 자바 JAVA 이론 (객체지향언어 / 변수 / 연산자)
2021.06.18 – [IT 독학/JAVA] – [자바 ②] 자바 JAVA 이론 (제어문 / 조건문 / 반복문 / 분기문 )
2021.06.18 – [IT 독학/JAVA] – [자바 ③] 자바 JAVA 이론 (배열)
자바는 객체 지향 언어고 (참조 → 자바 ①)
객체 지향 언어에는 객체, 클래스, 메소드, 추상화, 캡슐화, 상속, 다형성 등의 특징을 가진다.
클래스 Class
클래스는 고유성을 가진 객체가 모여 개념화된 특성을 정의한 것이다.
클래스를 비유한 가장 유명한 예시가 바로 ‘붕어빵 틀’일 것이다.
이 붕어빵 틀에서 생성된 객체가 바로 붕어빵이다.
다시말해
클래스의 정의대로 객체가 연산자를 통해 메모리 영역에 생성되는 것이다.
객체는 클래스가 없으면 생성되지 못한다.
객체 Object = 인스턴스 Instance
객체란 속성과 기능이 묶인 프로그램 단위를 말한다.
여기서 속성(attribute)는 객체가 가진 고유한 특성이고 기능(function)은 객체의 행동 패턴을 말한다.
자바에서 보면 속성은 멤버변수고 기능은 메소드로 볼 수 있다.
메소드 Method
메소드는 객체 간에 교류되는 프로그램화한 명령 메시지 단위이다. 쉽게 말해 데이터(객체)의 동작 처리 내용을 말한다.
메소드의 선언은 [접근제한자] [반환형] [메소드명] ( 매개변수 ) { } 로 이루어진다.
접근제한자의 종류로는
– public / protected / default / private 이 있다.
클래스는 주로 public 으로 선언되어 패키지 안과 밖에서 모두 접근이 가능하게 한다.
속성 (멤버변수)는 주로 private 으로 선언되어 외부로부터 데이터 변질을 막는다.
메소드 표현식
메소드의 표현식은 매개변수 유무와 리턴값 유무에 따라 달라진다.
* 클래스와 객체
클래스와 객체의 개념이 헷갈릴 수 있다. 이렇게 붕어빵틀과 붕어빵들로 생각하면 이해하기 쉽다.
+ 참고
인프런 강의
https://inf.run/Cwif
패키지 Package
패키지는 클래스의 묶음이다.
클래스를 사용할 때 패키지를 import 해서 사용한다.
*클래스 생성
*객체 생성
+ 계좌 클래스 생성 후 객체 생성 예시
클래스 생성
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 package com.practice.object; //클래스 선언 public class Object_Test { //속성 (멤버 변수) 정의 private String name; private String acc_No; private String pwd; private int bankCode; private int balance; //기본 생성자 정의 public Object_Test(){} //매개변수 생성자 정의 public Object_Test( String name, String acc_No, String pwd, int bankCode, int balance) { this .name = name; this .acc_No = acc_No; this .pwd = pwd; this .bankCode = bankCode; this .balance = balance; } //기능 (메소드) 정의 //입금 기능 public void in ( int money) { if (money > 0 ) { balance + = money; System . out . println (name + “님의 계좌에 ” + money + “원이 입금되었습니다.” ); } else { System . out . println ( “오류” ); } } //출금 기능 public void out ( int money) { if (money < balance) { balance - = money; System . out . println (name + "님의 계좌에서 " + money + "원이 출금되었습니다." ); } else { System . out . println ( "잔액이 부족합니다." ); } } //잔액 조회 기능 public void display() { System . out . println (name + "님의 계좌에 잔액은 " + balance + "원 입니다." ); } //setter 메소드 : 필드에 변경할 값 전달받아 필드 값 변경하는 메소드 public void setName( String name) { this .name = name; } public void setAcc_No( String acc_No) { this .acc_No = acc_No; } public void setPwd( String pwd) { this .pwd = pwd; } public void setBankCode( int bankCode) { this .bankCode = bankCode; } public void setBalance( int balance) { this .balance = balance; } //getter 메소드 : 필드에 기록된 값 호출해 요청한 쪽으로 읽은 값 넘기는 메소드 public String getName() { return name; } public String getAcc_No() { return acc_No; } public String getPwd() { return pwd; } public int getBankCode() { return bankCode; } public int getBalance() { return balance; } } Colored by Color Scripter cs 객체 생성 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package com.practice.object; public class Object_Test_Run { public static void main( String [] args) { //객체 생성 (기본 생성자)' Object_Test a = new Object_Test(); //객체 생성 (매개변수 생성자) //매개변수 : String name, String acc_No, String pwd, int bankCode, int balance Object_Test b = new Object_Test( "홍길동" , "112-2233-4567-8" , "1234" , 20 , 0 ); //메소드 호출 //잔액조회 a.display(); b.display(); //입금 100만원 b. in ( 1000000 ); //출금 10만원 b. out ( 100000 ); //setter로 값 변경하기 a.setName( "황진이" ); a.setAcc_No( "620-1111-2222-9" ); a.setPwd( "9876" ); a.setBankCode( 15 ); a.setBalance( 10000 ); //getter로 값 조회 System . out . println (a.getName()); System . out . println (a.getAcc_No()); System . out . println (a.getPwd()); System . out . println (a.getBankCode()); System . out . println (a.getBalance()); } } Colored by Color Scripter cs + setter 메소드 setter 메소드는 멤버변수에 변경할 값을 전달받아 값을 변경하는 메소드이다. + getter 메소드 getter 메소드는 멤버변수의 값을 읽어 요청한 쪽으로 그 값을 넘기는 메소드이다. 반응형
[Java] 클래스와 객체
반응형
자바는 대표적인 객체지향 언어 중 하나이다. 그러나 ‘객체’가 무엇인지도 모르고 쓰는 경우가 있다. 우선 객체란 무엇일까? 사실 객체(Object)는 어려운 개념이 아니다. 우리 주변에 있는 모든 것이 객체이다. TV, PC, 노트북, 스마트폰, 사람, 의자 등등… 실세계는 객체들의 집합이다. 실세계의 객체들은 자신만의 고유한 특성(State)과 행동(Behavior)을 가지며 다른 객체들에게 행동을 요구하거나 정보를 주고받는 등 상호 작용을 하면서 살아간다. 컴퓨터 프로그램의 예를 들면, 테트리스 게임에 나오는 각 블록들, 한글 프로그램의 메뉴나 버튼들이다.
Java의 객체 지향 특성
객체지향 언어는 실세계의 객체를 프로그램 내에 표현하기 위해 클래스(Class)와 객체(Object) 개념을 도입하였다. 객체지향 언어는 다음과 같은 특성을 가진다.
● 캡슐화 (Encapsulation)
캡슐화란 객체를 캡슐로 싸서 내부를 보호하고 볼 수 없게 하는 것으로 객체의 가장 본질적인 특징이다. 캡슐로부터 보호받기 때문에 외부의 접근으로부터 안전하다. 객체는 캡슐화가 기본 원칙이지만, 외부와 상호작용을 위해 몇 부분만 공개 노출한다. (예: TV의 On/Off, 음량 조절 등)
Java에서 클래스는 객체의 모양을 선언한 ‘틀’이며 클래스 모양 그대로 생성된 ‘실체(Instance)’가 객체이다. Java는 필드(Field)와 메서드(Method)를 클래스 내에 모두 구현하므로 캡슐화를 통해 객체 내 필드에 대한 외부로부터의 접근을 제한한다.
● 상속 (Inheritance)
상속은 상위 개체의 속성이 하위 개체에 물려져 하위 개체가 상위 개체의 속성을 모두 가지는 관계이다. 상속을 이용하면 기존에 정의되어 있는 클래스의 모든 필드와 메소드를 물려받아 새로운 클래스를 생성할 수 있다.
기존에 정의되어있던 클래스를 부모 클래스(Parent Class) 또는 상위 클래스(Super Class), 기초 클래스(Base Class)라고도 한다.
상속을 통해 새롭게 작성되는 클래스를 자식 클래스(Child Class) 또는 하위 클래스(Sub Class), 파생 클래스(Derived Class)라고도 한다.
# 장점
기존에 작성된 클래스를 재활용
자식 클래스 설계 시 중복되는 멤버를 미리 부모 클래스에 작성해놓으면, 자식 클래스에서는 해당 멤버를 작성하지 않아도 됨
클래스 간 계층적 관계를 구성함으로써 다형성의 문법적 토대 마련
출처 http://www.tcpschool.com/java/java_inheritance_concept
● 다형성 (Polymorphism)
다형성이란 하나의 객체가 여러 가지 타입을 가질 수 있는 것을 의미한다. 자바에서는 이러한 다형성을 부모 클래스 타입의 참조 변수로 자식 클래스 타입의 인스턴스를 참조할 수 있도록 하여 구현하고 있다.
List
list = new ArrayList<>(); 또는 같은 이름의 메소드가 클래스 혹은 객체에 따라 다르게 구현되는 것을 말하기도 한다. 부모 클래스에 지정된 메서드를 자식 클래스가 상속을 받으면, 부모가 갖는 메서드를 그대로 사용할 수도 있지만, 메서드 오버라이딩(Method Overriding)을 하여 자식 클래스에서 자신의 특징에 맞게 동일한 이름으로 다시 구현할 수 있다.
메서드 오버로딩(Method Overloading)은 클래스 내에 같은 이름의 메서드를 여러개 만드는 것이다.
//메서드 오버로딩 void register(int a) { … } void register(int a, String b) { … } void register(int a, String b, Infomation c){ … } //메서드 오버라이딩 Class Parent{ int a; public void speak(String a){ System.out.println(a); } } Class Child extends Parent{ @Overriding public void speak(String a){ String b = “Hello World!”; System.out.println(a + b); } }
절차 지향 / 객체 지향
C처럼 실행하고자 하는 절차를 정하고, 이 절차대로 프로그래밍 하는 방법을 절차 지향 프로그래밍이라고 부른다. 절차 지향 프로그래밍은 목적을 달성하기 위한 일의 흐름에 중점을 둔다. 자판기 소프트웨어를 구현하는 경우를 보면 절차 지향 프로그래밍은 흐름도를 설계하고 흐름도상의 동작들을 함수로 작성하며, 흐름도에 따라 일련의 동작들이 순서대로 실행되도록 작성한다.
그러나 컴퓨터를 이용하여 문제를 해결하려는 실제 세상은 단순히 일련의 행위뿐 아니라 각 물체 간의 관계, 상호 작용 등 복잡하게 구성되어있다. 절차지향 언어로 실세계의 문제를 프로그래밍 하기에는 표현에 한계가 있다.
객체 지향 프로그래밍은 이러한 단점을 보완하고 실세계의 물체를 객체를 표현한다.
클래스와 객체
C 에서 구조체를 정의하기 위해 struct를 사용했다면, 자바에서는 ‘class’를 사용한다.
클래스는 다음과 같이 구성된다.
(접근 지정자) 클래스
(접근 지정자) 멤버 변수 = 필드 (접근 지정자) 멤버 함수 = 메서드
● 접근 지정자
자바에서 메서드는 반드시 접근 지정자와 함께 선언되어야 한다. 접근 지정자는 public/private/default/protected가 있다.
public > protected > default > private
클래스 내부 동일 패키지 하위 클래스 그 외의 영역 public O O O O protected O O O X default O O X X private O X X X
● 객체 생성
객체 생성은 객체에 대한 레퍼런스 변수 선언과 객체 생성의 두 과정으로 구분된다.
# 레퍼런스 변수 선언
객체를 생성하기 전 객체를 가리킬 레퍼런스 변수의 선언이 필요하다.
Class Student{ int kor; int eng; public static void main(String[] args){ Student student; //레퍼런스 변수 student 선언 } }
이 선언만으로는 Student 객체가 생성되지 않는다. 변수 student는 Student 타입의 객체를 가리키는 레퍼런스 변수일 뿐 객체 자체는 아니다.
# new 연산자로 객체 생성
student = new Student();
new 연산자는 Student 타입의 크기만한 메모리를 할당받아 메모리에 대한 레퍼런스 (주소)를 반환한다. 레퍼런스 값은 student에 대입된다.
# 객체 멤버 접근
//객체레퍼런스.멤버 int kor = student.kor; int eng = student.eng;
생성자
이번 절에서는 중요한 것을 알아보고자 한다. 생성자는 정말 기본적이지만 매우 중요하기 때문이다.
앞에서 클래스는 객체를 생성하기 위한 틀이며, 객체는 틀로 찍어낸 실체라고 하였는데, 생성자는 객체가 생성될 때 초기화를 위해 실행되는 메서드이다. 즉, 인스턴스 변수의 초기화를 위한 메서드라고 할 수 있다. 클래스를 가지고 객체를 생성하면 해당 객체는 메모리에 즉시 생성되지만 생성된 객체는 모든 인스턴스 변수가 아직 초기화되지 않은 상태이다.
클래스 변수와 인스턴스 변수는 별도로 초기화하지 않으면, 아래와 같은 값으로 초기화된다.
변수의 타입 초기값 char ‘\u0000’ byte / short / int 0 long 0L float 0.0f double 0.0 boolean false 배열 / 인스턴스 등 null
● 생성자의 특징
생성자의 이름은 클래스 이름과 동일하다
생성자를 여러 개 작성할 수 있다 (오버로딩이 가능하다)
생성자는 객체를 생성할 때 한 번만 호출된다
생성자에 리턴 타입을 지정할 수 없다 (반환 값이 없으나 void도 불가)
생성자는 초기화를 위한 데이터를 인자로 받을 수 있다.
● 기본 생성자 (Default Constructor)
기본 생성자란 매개 변수가 없고 또한 실행 코드가 없어 아무일도 하지 않고 단순 리턴하는 생성자이다.
기본 생성자는 만약 클래스에 아무런 생성자가 정의되어있지 않다면 컴파일러가 자동으로 생성해준다.
하지만 다른 생성자가 있다면 기본 생성자는 자동으로 생기지 않으므로 반드시 명시해주어야 한다.
Class Student{ int kor; int eng; public Student(){ //default 생성자 } }
● this 레퍼런스 / this()
this는 객체 자신에 대한 레퍼런스(주소)로서 메서드 안에서 사용된다. this는 컴파일러에 의해 자동으로 관리되므로, 개발자는 사용하기만 하면 된다.
public Student(){ kor = 10; eng = 20; } public Student(int kor, int eng){ this.kor = kor; this.eng = eng; } //this()를 사용한 생성자 public Student(int kor, int eng, int math){ this(kor, eng); this.math = math; }
위의 예제처럼 생성자의 매개변수 이름과 인스턴스 변수의 이름이 같을 경우 인스턴스 변수 앞에 ‘this’를 붙여 구분해야한다. 이러한 this 참조 변수를 사용할 수 있는 영역은 인스턴스 메서드뿐이며, 클래스 메서드에서는 사용할 수 없다. 모든 인스턴스 메서드에는 this 참조 변수가 숨겨진 지역 변수로 존재하고 있다.
this() 메서드는 생성자 내부에서만 사용할 수 있으며, 같은 클래스의 다른 생성자를 호출할 때 사용한다.
● 객체 치환 시 주의 사항
객체의 치환은 객체를 복사하는 것이 아니다. 다음의 예제를 보자.
public class CallbyReference { static class Student{ int kor, eng, math; public Student(int kor, int eng, int math) { this.kor = kor; this.eng = eng; this.math = math; } @Override public String toString() { return “Student [kor=” + kor + “, eng=” + eng + “, math=” + math + “]”; } } public static void main(String[] args) { Student s1 = new Student(10, 10, 10); Student s2 = new Student(20, 20, 20); System.out.println(“s1 : ” + s1.toString()); System.out.println(“s2 : ” + s2.toString()); System.out.println(“객체 치환 s1 -> s2”); s1 = s2; System.out.println(“s1 : ” + s1.toString()); System.out.println(“s2 : ” + s2.toString()); } } //s1 : Student [kor=10, eng=10, math=10] //s2 : Student [kor=20, eng=20, math=20] //객체 치환 s1 -> s2 //s1 : Student [kor=20, eng=20, math=20] //s2 : Student [kor=20, eng=20, math=20]
s1 = s2;
이 코드가 실행됨에 따라 원래 s1이 가리키던 객체는 아무도 가리키지 않으므로 더 이상 프로그램에서 접근할 수 없는 상태가 되었다. 따라서 이 객체는 가비지 (Garbage)가 되어 가비지 컬렉터에 의해 자동으로 수거된다.
즉, s1과 s2 모두 기존 s2가 가리키던 메모리 주소를 가리키고 있는 것이다.
메서드 (Method)
메서드에서는 개인적으로 상당히 중요한 개념에 대하여 다루고자 한다. 앞에서 언급한 메서드 오버로딩에 대해 다루고, 메서드의 인자를 전달할 때의 방식을 알아보자. 인자를 전달하는 방식은 아래와 같이 2가지가 있다.
> 값에 의한 호출 (Call by Value)
> 참조에 의한 호출 (Call by Reference)
자바의 메서드 호출 시 인자 전달 방식(argument passing)은 ‘값에 의한 호출’이다. 호출하는 실인자의 값이 복사되어 메서드의 매개 변수에 전달된다.
● 기본 타입 (Primitive Type)의 값이 전달되는 경우 : Call by Value
매개 변수가 byte, char, int ,double 등 기본 타입으로 선언되는 경우, 호출자(Caller)가 건네는 값이 메서드의 매개 변수에 복사되어 전달된다.
public class CallbyValue { static void increase(int val) { val += 10; System.out.println(“val : ” + val); } public static void main(String[] args) { int k = 10; increase(10); System.out.print(“k : ” + k); } } //val : 20 //k : 10
● 객체가 전달되는 경우 : Call by Reference
메서드의 매개 변수가 클래스 타입인 경우, 객체가 아니라 객체의 레퍼런스 (주소)값이 전달된다. Class / Interface / Array 3 가지 경우에는 참조에 의한 호출이 이루어진다.
public class CallbyReference { static class Student{ int kor, eng, math; public Student(int kor, int eng, int math) { this.kor = kor; this.eng = eng; this.math = math; } @Override public String toString() { return “Student [kor=” + kor + “, eng=” + eng + “, math=” + math + “]”; } } static void increase(Student s) { s.eng += 10; s.math += 20; } public static void main(String[] args) { Student student = new Student(10, 10, 10); System.out.println(“increase 호출 전”); System.out.println(student.toString()); increase(student); System.out.println(“increase 호출 후”); System.out.println(student.toString()); } } //increase 호출 전 //Student [kor=10, eng=10, math=10] //increase 호출 후 //Student [kor=10, eng=20, math=30]
● 메서드 오버로딩 (Method Overloading)
클래스 내에 이름이 같지만 매개 변수의 타입이나 개수가 서로 다른 여러 개의 메서드를 작성할 수 있다. 이는 다형성의 한 종류이다.
메서드 이름이 동일하여야 한다
메서드 매개 변수의 개수나 타입이 서로 달라야 한다
접근 지정자나 리턴 타입은 메서드 오버로딩에 해당되지 않는다
static 그리고 final
● static vs non-static
non-static static 선언 class Sample{
int n;
void g() {…}
} class Sample{
static int n;
static void g() {…}
} 공간적 특성 – 객체마다 별도 존재
– 인스턴스 멤버 – 클래스당 하나 생성
– 객체 내부가 아닌 별도의 공간에 생성
– 클래스 멤버 시간적 특성 – 객체 생성시 생김
– 객체가 생길 때 멤버도 생김
– 객체 생성 후 멤버 사용 가능
– 객체가 사라지면 멤버도 사라짐 – 클래스 로딩 시 멤버 생성
– 객체가 생기기 전 이미 생성
– 객체가 생기기 전 사용 가능
– 객체가 사라져도 멤버는 존재
– 멤버는 프로그램이 종료 시 사라짐 공유의 특성 – 공유 X
– 멤버는 객체 내 각각 공간 유지 – 동일한 클래스의 모든 객체들에 의해 공유 O
– 클래스 이름으로 접근 가능
– 객체의 멤버로 접근 가능
# static의 활용
전역 변수 / 전역 함수
공유 멤버를 만들고자 할 때
# static 메서드의 제약
static 메서드는 반드시 static 변수만 사용 (생성되는 시기가 다르므로) 반대로 non-static 메서드는 static 변수도 사용 가능
static 메서드에서는 this를 사용할 수 없다 static 메서드는 객체 없이도 존재하기 때문 / this는 자기자신 객체를 지정하므로
● final
1) 클래스
클래스 앞에 final이 붙으면 상속받을 수 없다.
2) 메서드
메서드 앞에 final이 붙으면 더 이상 오버라이딩 할 수 없다.
3) 필드
필드 앞에 final이 붙으면 더 이상 수정할 수 없다. 즉 상수가 된다.
static final int PI = 3.14; //상수는 대문자로 표기하는 것이 관례
객체지향 프로그래밍
프로그램이란?
– 프로그램은 코딩(절차를 다루는 부분)과 절차를 나누고 정리하는 부분으로 구성되어 있다고 볼 수 있다
프로그램은 구조적인 방법과 객체지향적인 방법이 있다.
구조적인 방법과 객체지향 방법은 절차를 나누고 정리하는 방법에서 어떤 차이가 있을까?
절차를 나누는 방법(함수를 나누는 기준)에서의 차이
구조적인 방법 코드의 크기나 중첩 및 복잡도가 높아지는 부분에서 코드를 잘라 함수로 만든다.
객체지향 방법 객체가 주체가 되어 객체가 서비스하는 단위를 함수로 만든다.
(함수를) 정리하는 방법에서의 차이
구조적인 방법 데이터구조가 사용되면 함수가 외부 코드로부터 영향을 받는 이상현상이 발생하게된다. 따라서 데이터구조를 사용하는 함수들을 하나로 묶어야 하는 필요성이 발생한다.
객체지향 방법 객체라는 실세계에 반영함으로써 캡슐화 된 함수를 그 객체의 행위로 보는 방식으로 정리한다.
# References
TCPschool’s Java
명품 자바 에센셜.황기태.생능 출판
반응형
키워드에 대한 정보 자바 오브젝트
다음은 Bing에서 자바 오브젝트 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.
이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!
사람들이 주제에 대해 자주 검색하는 키워드 Java – Object 클래스 (1/5) : 소개
- 생활코딩
- Java
- 자바
- Object
- toString
- equals
- clone
- Cloneable
- finalize
Java #- #Object #클래스 #(1/5) #: #소개
YouTube에서 자바 오브젝트 주제의 다른 동영상 보기
주제에 대한 기사를 시청해 주셔서 감사합니다 Java – Object 클래스 (1/5) : 소개 | 자바 오브젝트, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.