- Concrete class는 인스턴스를 생성할 수 있다.
- Abstract class는 인스턴스를 생성할 수 없다.
package com.bitcamp.util;
public class ObjectList {
private static final int DEFUALT_CAPACITY = 10;
private int size;
protected Object[] elementData;
public ObjectList() {
elementData = new Object[DEFUALT_CAPACITY]; // this 생략
}
public ObjectList(int initialCapacity) {
elementData = new Object[initialCapacity];
}
public void add(Object e) {
if(size == elementData.length) {
grow();
}
elementData[size++] = e;
}
public Object[] toArray() {
Object[] arr = new Object[size];
for (int i = 0; i < arr.length; i++) {
arr[i] = elementData[i];
}
return arr;
}
public Object get(int index) {
if(index <0 || index >= size) {
return null;
}
return elementData[index];
}
public boolean remove(int index) {
if(index <0 || index >= size) {
return false;
}
for(int i=index+1;i<size;i++) {
elementData[i-1]=elementData[i];
}
elementData[--size] = null;
return true;
}
public int size() {
return size;
}
// private method는 밑에 두자
private void grow() {
int newSize = elementData.length + (elementData.length >> 1);
Object[] newArray = new Object[newSize];
for (int i = 0; i < elementData.length; i++) {
newArray[i] = elementData[i];
}
elementData = newArray;
}
}
@Override
public Board get(int boardNo) {
for (int i = 0; i < size(); i++) {
Board board = (Board)super.get(i);
if (board.no== boardNo) {
return board;
}
}
return null;
}
package com.bitcamp.board.dao;
import com.bitcamp.board.domain.Board;
import com.bitcamp.util.ObjectList;
// 게시글 목록을 관리하는 역할
//
public class BoardList extends ObjectList{
// 자동으로 증가하는 게시글 번호
private int boardNo = 0;
// 게시글을 저장할 때 자동으로 증가한 번호를 게시글 번호로 설정할 수 있도록
// add() 메서드를 재정의한다.
@Override
public void add(Object e) {
// 넘어오는 Object 객체를 Board로 형변환해줘야 한다!
Board board = (Board) e;
board.no = nextNo();
super.add(e);
}
// 목록에 인덱스로 해당 항목을 찾는 get() 메서드를 오버라이딩하여
// 게시글을 등록할 때 부여한 일련 번호로 찾을 수 있도록
// get() 메서드를 재정의(overriding)한다.
// => 오버라이딩 메서드의 리턴 타입은 원래 타입의 서브 클래스로 변경할 수 있다.
@Override
public Board get(int boardNo) {
for (int i = 0; i < size(); i++) {
Board board = (Board)super.get(i);
if (board.no== boardNo) {
return board;
}
}
return null;
}
// 수퍼 클래스의 remove()는 인덱스로 지정한 항목을 삭제한다.
/// 이것을 게시글 번호에 해당하는 항목을 삭제하도록 상속받은 메소드를 재정의(overriding)한다.
@Override
public boolean remove(int boardNo) {
for (int i = 0; i < size(); i++) {
Board board = (Board)super.get(i);
if (board.no == boardNo) {
return super.remove(i);
}
}
return false;
}
private int nextNo() {
return ++boardNo;
}
}
package com.bitcamp.board.dao;
import com.bitcamp.board.domain.Member;
import com.bitcamp.util.ObjectList;
// 회원 목록을 관리하는 역할
//
// ObjectList를 상속 후 메서드를 오버라이딩 할 필요가 있음을 확인하기 위해 회원 번호 대신 이메일로 접근한다.
public class MemberList extends ObjectList{
//private int memberNo = 0;
// 인덱스 대신 이메일로 회원 데이터를 찾을 수 있도록
// 메서드를 추가한다.
// 오버로딩: 파라미터 타입이나, 개수, 순서가 다르더라도 같은 기능을 수행하는 메서드에 대해 같은 이름을 부여함으로써 프로그래밍의 일관성을 제공하는 문법!
// 오버로딩을 하려면 메서드 끼리 같은 기능을 수행해야 한다!!!!!! -> 일관성 유지
// 얘는 수퍼 클래스에서의 get과 파라미터 타입이 다르므로 결론적으로 오버로딩을 한 것이다!
// 메서드 호출할 때 일관되게 사용할 수 있다. => 오버로딩!
public Member get(String email) {
for (int i = 0; i < size(); i++) {
Member member = (Member)get(i); // 여기는 BoardList와 달리, get과 메서드 이름이 달라서 super붙일 필요 없다!
if (member.email.equals(email)) {
return member;
}
}
return null;
}
// @Override
// public void add(Object e) {
// Member member = (Member)e;
// member.no = nextNo();
// super.add(member);
// }
// @Override: 컴파일러야, 수퍼 클래스의 메서드를 재정의하기 위해 다음 메서드를 만들었는데, 이거 제대로 검사했는지 확인해줄래?
// 근데 밑의 remove 메소드는 오버로딩이라 @Override를 붙여주면 오류가 나게 된다!
// 인덱스 대신 이메일로 회원 데이터를 찾아 삭제하는 메서드
// 수퍼 클래스로부터 상속 받은 메서드와 같은 일을 하며, 메서드 이름도 같다 -> 오버로딩!
public boolean remove(String email) {
for (int i = 0; i < size(); i++) {
Member member = (Member)get(i); // 여기는 BoardList와 달리, get과 메서드 이름이 달라서 super붙일 필요 없다!
if (member.email.equals(email)) {
return super.remove(i);
}
}
return false;
}
// private int nextNo() {
// return ++memberNo;
// }
}
// boardList 인스턴스에 들어 있는 데이터 목록을 가져온다.
Object[] list = this.boardList.toArray();
for (Object item : list) {
Board board = (Board)item;
Date date = new Date(board.createdDate);
String dateStr = formatter.format(date);
System.out.printf("%d\t%s\t%d\t%s\t%s\n",
board.no, board.title, board.viewCount, board.writer, dateStr);
}
}
private void onList() {
System.out.println("[회원 목록]");
System.out.println("이메일\t이름");
Object[] list = this.memberList.toArray();
for (Object item : list) {
Member member = (Member)item;
System.out.printf("%s\t%s\n", member.email, member.name);
}
}
private void onDetail() {
System.out.println("[회원 상세보기]");
String email = Prompt.inputString("조회할 회원의 이메일? ");
Member member = memberList.get(email);
if (member == null) {
System.out.println("해당 이메일의 회원이 없습니다!");
return;
}
System.out.printf("이름: %s\n", member.name);
System.out.printf("이메일: %s\n", member.email);
Date date = new Date(member.createdDate);
System.out.printf("등록일: %tY-%1$tm-%1$td %1$tH:%1$tM\n", date);
}
public class Exam0110 {
public static void main(String[] args) {
// String 레퍼런스
// - String은 자바 기본 타입이 아니다.
// - 클래스이다.
String s1; // s1은 String 인스턴스 주소를 담는 레퍼런스이다.
// String 인스턴스
// - 힙에 Hello 문자 코드를 저장할 메모리를 만들고 그 주소를 리턴한다.
// - 내용물의 동일 여부를 검사하지 않고 무조건 인스턴스를 생성한다.
// - 가비지가 되면 가비지 컬렉터에 의해 제거된다.
s1 = new String("Hello");
String s2 = new String("Hello");
// 인스턴스가 같은지를 비교해보면,
System.out.println(s1 == s2); // false => 서로 다른 인스턴스이다.
}
}
public class Exam0120 {
public static void main(String[] args) {
String s1 = new String("Hello");
String s2 = new String("Hello");
// 두 String 인스턴스는 분명히 서로 다르다.
System.out.println(s1 == s2);
// 두 인스턴스가 갖고 있는 문자열이 같은지를 비교하고 싶다면,
System.out.println(s1.equals(s2));
// equals()?
// - Object에 정의되어 있는 메서드이다.
// - 인스턴스가 같은지 비교한다.
//
// String의 equals()?
// - Object에서 상속 받은 것을 오버라이딩하였다.
// - 문자열이 같은지 비교한다.
//
}
}
String s1;
s1 = new String("Hello");
s2 = new String("Hello");
String x = "Hello";
String y = "Hello";
String s1 = new String("hello");
String s2 = s1.intern();
String s3 = "hello";
public class Exam0122 {
static class Member {
String name;
int age;
public Member(String name, int age) {
this.name = name;
this.age = age;
}
}
public static void main(String[] args) {
Member m1 = new Member("홍길동", 20);
Member m2 = new Member("홍길동", 20);
System.out.println(m1 == m2); // false
// Member 클래스는 Object에서 상속 받은 equals()를 오버라이딩 하지 않았다.
// 따라서 단순히 인스턴스가 같은지를 비교할 것이다.
System.out.println(m1.equals(m2)); // false
System.out.println(m1.toString());
System.out.println(m2.toString());
}
}
public class Exam0125 {
public static void main(String[] args) {
StringBuffer b1 = new StringBuffer("Hello");
StringBuffer b2 = new StringBuffer("Hello");
// StringBuffer 에 들어 있는 문자열을 비교하려면?
// - StringBuffer에서 String을 꺼내 비교하라!
//
// String s1 = b1.toString();
// String s2 = b2.toString();
// System.out.println(s1.equals(s2));
//
System.out.println(b1.toString().equals(b2.toString()));
}
}
String s1 = new String("Hello");
String s2 = s1.toString();
String s2 = s1; //위의 코드와 동일한 코드이다.
// => String이 오버라이딩한 toString()은 this 주소를 그대로 리턴한다.
System.out.println(s1 == s2); // true
public class Exam0141 {
public static void main(String[] args) {
Object obj = new String("Hello"); // 인스턴스 주소가 100이라 가정하자;
String x1 = (String) obj; // x1 <--- 100
// obj에 대해 toString()을 호출할 때,
// => 일단 obj 클래스에 선언된 멤버(필드와 메서드)만 사용할 수 있다.
// => 단 멤버는 실제 obj가 가리키는 클래스부터 찾아 올라 간다.
// => 위 예에서 obj가 가리키는 것은 String 이기 때문에
// => 이 경우 toString()을 호출할 때 String 클래스에서부터 찾는다.
// => String 클래스가 toString()을 오버라이딩 했기 때문에
// 결국 이 오버라이딩 메서드를 호출할 것이다.
String x2 = obj.toString(); // x2 <---- 100
System.out.println(x1 == x2);
// 레퍼런스를 통해 메서드를 호출할 때
// => 레퍼런스가 가리키는 객체의 클래스부터 메서드를 찾아 올라간다.
// => 따라서 obj가 가리키는 객체의 클래스가 String이기 때문에
// obj.toString()은 String 클래스부터 해당 메서드를 찾는다.
}
}
Object 클래스로 만든 객체는 사용하기 전에 무조건 내가 사용할 데이터 타입으로 형변환을 지정해줘야 한다.
형변환을 이용하고 사용하는 코드 한 번에 합쳐버리기 -> 괄호 이용
public class Exam0142 {
public static void main(String[] args) {
Object obj = new String("Hello");
String s = (String)obj;
String str2 = s.toLowerCase();
// obj가 String 객체를 가리키더라도
// obj의 타입이 Object이기 때문에 Object에 선언한 멤버만 사용할 수 있다.
// obj가 가리키는 원래 클래스의 메서드를 호출하고 싶다면
// 다음과 같이 원래 타입으로 형변환하라.
String str = ((String) obj).toLowerCase();
System.out.println(str);
// 또는 다음과 같이 원래 타입의 레퍼런스에 저장한 다음 사용하라.
String x1 = (String) obj;
str = x1.toLowerCase();
System.out.println(str);
}
}