D+32-인터페이스.다중구현,접근제한자2.protected,부모함수접근범위,컬렉션프레임워크.List,ArrayList,Vector,LinkedList,속도비교

Bku·2024년 2월 8일

학원 일기

목록 보기
30/67
post-thumbnail

인터페이스

인터페이스

추상메서드만으로 이루어져 있는 클래스를 인터페이스라고 한다. 엄밀히 말하면 클래스가 아니고 인터페이스 자체이다. 메서드의 본체가 존재하지 않으니 '나는 타입만 빌려줄게 본체는 자식 너네가 채워라'같은 방식이다.

인터페이스의 특징

  1. 인터페이스에서 속성을 만들면 자동으로 전역상수가 된다(무조건 전역상수이어야 한다).
  2. 추상메서드만 존재하기 때문에 인스턴스를 생성할 수 없고, 모든 함수를 오버라이딩 해주어야한다.
  3. 역시 모두 추상메서드이기에 메서드에 abstract를 붙여줄 필요가 없다.

인터페이스 코드

인터페이스 1

public interface RemoteControl {
    static final int MAX_VOLUME = 10;

    static final int MIN_VOLUME = 1;

    void turnOn();
    void turnOff();

    void setVolume(int volume);
}

인터페이스 2

public interface Searchable {
    void search(String url);
}

자식 클래스

public class SmartTelevision implements RemoteControl{
    private int volume;

    @Override
    public void turnOn() {
        System.out.println("스마트 텔레비젼의 전원을 켭니다.");
    }

    @Override
    public void turnOff() {
        System.out.println("스마트 텔레비젼의 전원을 끕니다.");
    }

    @Override
    public void setVolume(int volume) {
        if (volume > RemoteControl.MAX_VOLUME) {
            System.out.println("최대 볼륨은 10입니다.");
            this.volume = volume;
            volume = 10;
        } else if (volume < RemoteControl.MIN_VOLUME) {
            System.out.println("최소 볼륨은 1입니다.");
            this.volume = volume;
            volume = 1;
        }else {
            this.volume = volume;
        }
        System.out.println("현재 볼륨: " + volume);
    }
}

main클래스

public class SmartApplication {
    public static void main(String[] args) {
        RemoteControl remoteControl = new SmartTelevision();
		
        remoteControl.turnOn();
        remoteControl.setVolume(30);
        remoteControl.setVolume(5);
        remoteControl.setVolume(-10);
         //다중구현
        Searchable searchable = new SmartTelevision();
        searchable.search("http...");

        remoteControl.turnOff();
    }
}

결과

오버라이딩 된 메서드가 호출됐다.

인터페이스를 사용하는 이유

  1. 추상메스와 같이 명칭 표준화를 위해 사용할 수 있다. 또한 꼭 만들어야하는 함수들을 만들수 있게 한다.
  2. 타입만 빌려주고 기능은 다르게 할 수 있다.
  3. 추상메서드와는 다르게 다중구현이 가능해진다. 왜 가능한 지는 잠시 뒤 알아보자.

다중 구현

인터페이스는 클래스와 달리 다중상속이 가능하다. 일반 클래스에서 다중 상속이 안 되는 이유는 부모함수를 호출시 이름이 같은 메서드라면 어떤 부모에서 가져오는지를 알 수 없기때문이다.

하지만 인터페이스는 어차피 속이 빈 함수이기에 함수 이름이 같아도 의미가 없다. 그러므로 다중구현이 가능하다.

매개변수로 다형성 표현

인터페이스

public interface Soundable {
    String sound();
}

자식 클래스1

public class Dog implements Soundable{
    @Override
    public String sound( ) {
        return "멍멍";
    }
}

자식 클래스2

public class Dog implements Soundable{
    @Override
    public String sound( ) {
        return "멍멍";
    }
}

main클래스

public class SoundableApplication {
    public static void main(String[] args) {
        Cat cat = new Cat();
        Dog dog = new Dog();
        print(cat);
        print(dog);



    }
    static void print(Soundable animal){
        System.out.println(animal.sound());
    }
}

메인클래스에 함수를 만들고 거기에 부모타입 매개변수를 이용하여 다형성을 해주었다.
결과

매개변수에 자식 인스턴스를 넣어 서로 다른 함수가 호출되게 했다.

접근제한자 2

protected

protected는 default처럼 같은 패키지 안의 클래스에서는 사용이 가능하지만 다른 패키지에서의 사용은 금지된다. 단, 다른 패키지에서도 자신을 상속받는 클래스에서는 사용이 가능하게 된다.

코드

부모클래스
4개의 접근제한자를 모두 사용해서 어떤 것이 어떤 클래스에서 생성이 안되는 지를 확인해보자.

자식 클래스1
같은 패키지안의 자식 클래스여서 private인 no빼고는 에러가 나지 않는다.

자식 클래스2
다른 패키지의 자식 클래스여서 protected는 에러가 나지 않지만 default인 name도 추가적으로 불가하다.

부모 함수의 접근 제한 범위

부모 클래스 public함수

자식 클래스 default함수
컴파일 에러가 발생하는 것을 볼 수 있다.

부모 클래스 default함수

자식 클래스 default함수

오버라이딩 된 함수는 부모의 함수보다 더 넓거나 같은 범위의 접근제한만을 사용할 수 있다.

이유

객체 지향 프로그래밍의 다형성 개념에 따라 자식 클래스가 부모 클래스를 대체할 수 있어야 하므로 자식 클래스의 접근 제어 수준이 부모 클래스보다 좁아질 수 없기 때문입니다.

컬렉션 프레임 워크

컬렉션 프레임 워크란

자바에서 사용되는 자료구조를 통칭하는 것으로 여러가지 값을 저장하는 구조들이다. 우리가 배운 배열도 이 자료구조 중 하나다.

ArrayList

향상된 배열로 배열과 달리 자동으로 크기가 증가되어 크기를 미리 정해줄 필요가 없다.

ArrayList 특징

  1. 크기가 자동으로 정해진다.
  2. 값 추가, 삭제, 조회 등을 함수를 통해 할 수 있다.
  3. 중간에 배열의 값이 사라지면 자동으로 배열이 당겨져 크기가 작아진다.

ArrayList코드 사용법

public class ArrayListApplication {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
		// 값추가
        list.add("Java");
        list.add("JDBC");
        list.add("JSP");
		// 출력
        System.out.println(list);
         // 수정
        list.set(0, "자바"); // index 자리의 값을 위 값으로 변경해준다.
        System.out.println(list);
        // 삭제
        list.remove(0);// 인덱스 값으로 삭제 가능
        System.out.println(list);
        // 배열 값 조회
        System.out.println(list.get(0));
        // 배열 크기 확인
        System.out.println(list.size());
    }
}

ArrayList는 제네릭 함수로 인스턴스 생성시 타입을 정해줄 수 있다. 그냥 List말고 ArrayList타입으로 호출도 가능한데 List를 추천한다고 한다.

함수 기능들은 백준 문제풀이 시리즈 arraylist편에 있으니 참고.

List의 정체

여기서 List는 인터페이스이고 이걸 구현하는 자식 중 하나가 ArrayList이다. 나머지 둘은 Vector와 LinkedList이다. 이 셋 중에 가장 많이 사용하는 것이 ArrayList이다.

Vector

ArrayList보다 먼저 존재했고 비슷한 기능을 가진다. 그런데 ArrayList보다 성능이 떨어져 선호되지 않는다.

equals와 hashCode함수 재정의

String값을 비교할 때에 자주 사용하던 함수이다. String에서는 이 함수가 자바에서 미리 재정의를 해준다. 그런데 이것을 일반 인스턴스를 비교할때 사용하면 참조값을 비교하게 되서 엉뚱한 결과가 나오게 되므로 재정의가 필요하다.(인텔리제이에서 자동으로 해줌)

public class Board {
    String subject;
    String content;
    String writer;

    public Board(String subject, String content, String writer) {
        this.subject = subject;
        this.content = content;
        this.writer = writer;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Board board = (Board) o;
        return Objects.equals(subject, board.subject) && Objects.equals(content, board.content) && Objects.equals(writer, board.writer);
    }

    @Override
    public int hashCode() {
        return Objects.hash(subject, content, writer);
    }
}

alt + insert로 자동 생성 해줄 수 있다.

vector 코드

메인 클래스에 만들어보자.

public class BoardApplication {
    public static void main(String[] args) {
        List<Board> list = new Vector<>();
        
        // 추가
        list.add(new Board("제목", "내용", "작성자"));
        list.add(new Board("제목2", "내용2", "작성자"));
        list.add(new Board("제목3", "내용3", "작성자"));
        list.add(new Board("제목4", "내용4", "작성자"));
        list.add(new Board("제목5", "내용5", "작성자"));
        // 출력
        System.out.println(list);
        // 삭제
        list.remove(2);
        list.remove(3);
        System.out.println(list);
        // 값 가져오기
        System.out.println(list.get(0));
    }
}

결과

참조값이 나온다. 원래 list에서 문자열이나 숫자나 실수는 그냥 출력하면 값이 나왔는데 일반 클래스에서는 그렇지 않다.

toString 함수 재정의

이유는 문자열이나 기본 타입은 자동으로 toString함수가 재정의 되어 있다. 하지만 우리가 만든 클래스는 그걸 만들지 않았기 때문에 board클래스에서 toString을 재정의 해주면된다.

이것도 alt + insert로 자동생성이 가능하다.

public class Board {
    String subject;
    String content;
    String writer;

    @Override
    public String toString() {
        return "Board{" +
                "subject='" + subject + '\'' +
                ", content='" + content + '\'' +
                ", writer='" + writer + '\'' +
                '}';
    }
 }


재정의 후에는 값이 잘 보인다.

vector의 쓰임

멀티쓰레드 환경에서 사용함.멀티쓰레드란 프로그램안에 여러개의 프로그램이 독립적으로 실행되는 것이다. 주로 채팅에 멀티쓰레드를 사용한다(메세지를 보내면서 받기도 해야하니까).

ArrayList와 LinkedList

속도 성능 비교

성능 속도는 다음의 방법으로 구할 수 있다.

1) 처음 시간:
2) 실행: 예) 반복문
3) 종료 시간 : 종료시간 - 처음시간 = 걸린시간

으로 소요 시간을 구하면된다.

public class LinkedListApplication {
   public static void main(String[] args) {
       List<String>list = new ArrayList<>();
       List<String>list2 = new LinkedList<>();

//        1) 처음 시간:
//        2) 실행: 예) 반복문
//        3) 종료 시간 : 종료시간 - 처음시간 = 걸린시간
       long startTime;
       long endTime;

//        1) 처음시간 : 전역 객체인 System 클래스 (시간표시, 강제종료 System.in등) 활용
       startTime = System.nanoTime(); // 나노단위의 초를 센다.

//        2) 실행 : 예) 반복문
       for (int i = 0; i < 10000; i++) {
//            add 에 인덱스 번호를 넣어주면 그 순서에 값을 넣어줌
           list2.add(0,String.valueOf(i));
       }
//       3) 종료 시간 : 종료시간 - 처음시간 = 걸린시간
       endTime = System.nanoTime();
       System.out.println("걸린시간: " + (endTime-startTime));

// ---------------------linkedList측정---------------------------
//        1) 처음 시간
               startTime = System.nanoTime();

//        2) LinkedList 실행
       for (int i = 0; i < 10000; i++) {
//            중간에 추가
           list2.add(0, String.valueOf(i)); // 정수 -> 문자열로 변환해서 추가
       }
//        3) 끝 시간
       endTime = System.nanoTime();
       System.out.println("LinkedList 걸린시간 : " + (endTime-startTime));
   }
}


LinkedList가 빠른 것을 확인할 수있다.

ArrayList의 속도

이 배열은 값을 끝에 추가하면 속도가 빠르다. 하지만 중간에 값을 추가한다면 속도가 현저하게 줄어든다. 이것을 보완하기 위해 LinkedList가 있다.

LinkedList의 속도

이 배열은 값을 끝에 추가하는 것은 ArrayList보다 느리다. 하지만 중간에 값을 추가 할 때는 더 빠르다.

그래서 값을 끝에 추가해야하는 프로그램을 만드는 경우라면 Array를 중간에 값을 삽입하는 경우가 많은 프로그램은 Linked를 사용하면된다.

profile
기억보단 기록

0개의 댓글