728x90

인터페이스(구현을 위한 껍데기로 틀을 잡아주는 역할을 한다)와 추상 클래스(abstract 추상 메소드가 하나라도 있는 클래스)는 용도가 다르다.

 

인터페이스는 내부기능을 조작하는 접속장치, 지침서의 역할을 한다. 

추상 클래스는 추상적으로 객체의 공통되는 특징을 가져와 새로운 클래스로 만드는 용으로 쓴다.

 

인터페이스는 선언된 추상메소드들로 구현을 하기 위해 쓰이고

추상클래스는 상속을 통해 확장하기 위해 쓴다.

 

(인터페이스에 정의한 몸통이 없는 메소드가 바로 구현되지 않은 추상 메소드이다.

인터페이스를 구현해 사용하고자 하는 클래스에서 인터페이스에 정의된 메소드들을 구현해줘야 한다. implements)

 

  인터페이스 abstract 클래스 클래스
선언시 사용하는 예약어 interface abstract class class
구현 안 된 메소드 포함가능 여부 가능(필수) 가능 불가
구현된 메소드 포함 가능 여부 불가 가능 가능(필수)
static 메소드 선언 가능여부 불가  가능 가능
final 메소드 선언 가능 여부  불가  가능 가능
상속(extends) 가능 불가 가능 가능
구현(implements) 가능 가능 불가 불가

 출처: 자바의 신

 

자바에서는 단일 상속만 가능하다. 다중상속과 같은 기능을 인터페이스를 통해 구현할 수 있다.

(상속이란 부모에 선언된 변수와 메소드에 대한 사용권을 갖는 것을 말한다. extends를 사용해 확장하거나 implements를 사용해 구현한 경우가 상속에 속한다. )

 

인터페이스는 다중 구현이 가능하다. 

즉 class A에 implements 인터페이스 1, 인터페이스2,, 가 가능하다.

class A에서 인터페이스 여러 개의 추상메서드들을 사용가능한 것이다. 

인터페이스 다중 구현 시 중복된 메서드가 있으면 반드시 하위 클래스에서 재정의 해야한다.

 

 

인터페이스의 목적

1. 설계

2. 은닉 ( 클래스를 통해 실제 구현한 객체를 인터페이스 뒤에 가리고 소통한다.)

 

 

인터페이스는 그 자체로는 구현되지 않아서 인터페이스로 생성자를 불러 객체를 생성하려고 하면 컴파일 에러가 난다. 

인터페이스의 변수는 public static final로 자동선언된다. 

인터페이스의 메소드도 마찬가지로 public abstract으로 자동선언된다. 

 

? 왜 인터페이스의 변수는 static final로 선언될까 ? 

Java 인터페이스는 자체적으로 인스턴스화할 수 없기 때문에 인터페이스 변수는 정적이다. 변수의 값은 인스턴스가 존재하지 않는 정적 컨텍스트에서 할당되어야 한다. 객체 생성 시점이 아닌 컴파일 될때 메모리할당하는 static을 사용한다. 한번만 초기화하는 final을 통해 이후에도 값이 새로 할당되지 않도록 한다.

 

static과 final 개념

 

static : 고정의, 정적인

-> 값이 고정되어있다.

->해당 데이터의 메모리 할당을 컴파일 시간에 하고 프로그램이 끝날 때까지 static 데이터는 메모리 수명이 유지된다. 

-> non-static 변수는 새 객체를 생성할 때마다 초기화하고 메모리에 담는데 static변수는 계속 같은 값을 쓴다!

 

final : 최종의, 마지막의 -> 한 번만 초기화 가능하다

-> 변수로 final 선언하면 생성자나 연산자로 한번만 초기화되어 변하지 않는 상수값 할당됨

-> 클래스를 final로 선언하면 상속불가 extends X( 상속계층에서 마지막 클래스 됨)

-> 메소드를 final로 선언하면 오버라이딩 불가 @Override X

 

static final : 고정된 최종!!

-> 값을 바꿀 수 없는 상수가 된다.

-> 상수이므로 생성과 동시에 초기화가 된다. (초기화란 값을 할당)

 

 

 

참고문헌:

 

https://djkeh.github.io/articles/Why-should-final-member-variables-be-conventionally-static-in-Java-kor/

 

왜 자바에서 final 멤버 변수는 관례적으로 static을 붙일까?

자바 final, static 키워드와 코딩 best practice 되짚어보기

djkeh.github.io

 

https://stackoverflow.com/questions/2430756/why-are-interface-variables-static-and-final-by-default

 

Why are interface variables static and final by default?

Why are interface variables static and final by default in Java?

stackoverflow.com

https://byjus.com/gate/difference-between-abstract-class-and-interface-in-java/

 

Difference between Abstract Class and Interface in Java

Difference between Abstract Class and Interface in JAVA. The Abstract class and Interface both are used to have abstraction. An abstract class contains an abstract keyword on the declaration whereas an Interface is a sketch that is used to implement a clas

byjus.com

https://velog.io/@codren/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EB%8B%A4%EC%A4%91-%EA%B5%AC%ED%98%84%EA%B3%BC-%EC%83%81%EC%86%8D

 

인터페이스 다중 구현과 상속

인터페이스의 다중 구현과 중복 상황, 인터페이스 상속, 인터페이스 구현과 상속

velog.io

 

728x90
728x90

https://stackoverflow.com/questions/7026507/why-are-static-variables-considered-evil

 

Why are static variables considered evil?

I am a Java programmer who is new to the corporate world. Recently I've developed an application using Groovy and Java. All through the code I wrote used quite a good number of statics. I was asked...

stackoverflow.com

 

 

static은 정적의 , 고정의 라는 뜻으로 static 으로 선언되면 프로그램이 종료되기 전까지 메모리를 차지한다. 

전역변수처럼 상위에 고정되어 있다. 그래서 객체 생성 없이 꺼내서 사용하기에는 편리하나 관리하기가 불편하고 

사용하지 않을 때 가비지로 수집되지 않아 메모리 누수가 발생할 수 있다. 

객체들의 자율적인 협력을 지향하는 객체지향 프로그램에 맞지 않다. 

 

위 글에서 다시 보려고 적어둔 내용!

 

Java에서 정적 메소드를 사용할 때의 몇 가지 기본적인 장점과 단점을 요약하면 다음과 같습니다.

장점:

  1. 전역적으로 액세스 가능합니다. 즉, 특정 개체 인스턴스와 연결되지 않습니다.
  2. JVM당 하나의 인스턴스입니다.
  3. 클래스 이름을 사용하여 접근할 수 있습니다(객체가 필요하지 않음).
  4. 모든 인스턴스에 적용할 수 있는 단일 값을 포함합니다.
  5. JVM 시작 시 로드되고 JVM이 종료되면 종료됩니다.
  6. 객체의 상태를 수정하지 않습니다.

단점:

  1. 정적 멤버는 사용 여부에 관계없이 항상 메모리의 일부입니다.
  2. 정적 변수의 생성과 소멸을 제어할 수 없습니다. 유용하게도 프로그램 로드 시 생성되고 프로그램 언로드 시(또는 JVM이 종료될 때) 삭제됩니다.
  3. 동기화를 사용하여 정적 스레드를 안전하게 만들 수 있지만 추가 노력이 필요합니다.
  4. 한 스레드가 다른 스레드의 기능을 중단시킬 수 있는 정적 변수의 값을 변경하는 경우.
  5. 사용하기 전에 "정적"을 알아야 합니다.
  6. 정적 메서드를 재정의할 수 없습니다.
  7. 직렬화가 제대로 작동하지 않습니다. (직렬화란? - 객체를 저장, 전송할 수 있는 바이트 스트림으로 변환하는 것 : 직렬화에 대한 설명 )
  8. 런타임 다형성에는 참여하지 않습니다. 
  9. 많은 수의 정적 변수/메서드를 사용하는 경우 메모리 문제가 있습니다(어느 정도까지는 아니지만 그다지 많지는 않을 것 같습니다). 프로그램이 끝날 때까지 가비지 수집되지 않기 때문입니다.
  10. 정적 메서드도 테스트하기 어렵습니다.

 

정적 변수를 사용했을 시 나타나는 문제점

 

테스트 실행

정적은 일련의 단위 테스트를 함께 실행할 때(예: 지속적 통합 서버에서) 실제 문제를 일으킵니다. 한 테스트에서 다른 테스트까지 열려 있는 네트워크 소켓 개체의 정적 맵을 상상해 보세요. 첫 번째 테스트에서는 포트 8080에서 소켓을 열 수 있지만 테스트가 중단되면 맵을 지우는 것을 잊었습니다. 이제 두 번째 테스트가 시작되면 포트가 여전히 사용 중이므로 포트 8080에 대한 새 소켓을 생성하려고 하면 충돌이 발생할 가능성이 있습니다. 또한 정적 컬렉션의 소켓 참조가 제거되지 않고 (WeakHashMap을 제외하고) 가비지 수집 대상이 되지 않아 메모리 누수가 발생한다고 상상해 보세요.

이는 지나치게 일반화된 예이지만 대규모 시스템에서는 이 문제가 항상 발생합니다. 사람들은 동일한 JVM에서 소프트웨어를 반복적으로 시작하고 중지하는 단위 테스트를 생각하지 않지만 이는 소프트웨어 설계에 대한 좋은 테스트이며 고가용성을 향한 열망이 있다면 알아야 할 사항입니다.

 

미묘한 버그

스레드를 다룰 때는 정적 개체를 사용하여 데이터를 저장하는 것보다 스레드 시작 단계에서 초기화된 개체를 사용하는 것이 좋습니다. 이렇게 하면 스레드가 시작될 때마다 개체의 새 인스턴스(잠재적으로 새로운 구성 포함)가 생성되고 스레드의 한 인스턴스에서 다음 인스턴스로 데이터가 흘러나오는 것을 방지할 수 있습니다.

스레드가 종료되면 정적 개체가 재설정되거나 가비지 수집되지 않습니다. (정적 개체는 프로그램이 종료되어야 생명주기가 끝이 나기 때문에)"EmailCustomers"라는 스레드가 있고 스레드가 시작되면 이메일 주소 목록으로 정적 문자열 컬렉션을 채운 다음 각 주소에 이메일을 보내기 시작한다고 가정해 보세요. 스레드가 어떻게든 중단되거나 취소되어 고가용성 프레임워크가 스레드를 다시 시작한다고 가정해 보겠습니다. 그런 다음 스레드가 시작되면 고객 목록을 다시 로드합니다. 그러나 컬렉션은 정적이므로 이전 컬렉션의 이메일 주소 목록이 유지될 수 있습니다. 이제 일부 고객은 중복된 이메일을 받을 수 있습니다.

728x90
728x90

https://school.programmers.co.kr/learn/courses/30/lessons/12938

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

답지 안보고 풀었을 때 쾌감이란~

모든 문제가 이렇게 잘 풀렸으면 좋겠다 

 

정말 코테는 종이 없으면 못풀겠다 

갤탭씨에게 감사인사를 드립니다. 

 


문제 풀이

 

{} 집합에 어떤 수가 올지, 몇 개가 올지는 모르지만 

 

조건 

집합 안의 수 합이 S가 되는 애들

그리고 집합 수끼리 곱한 수가 최대인 애들을 return 해라 

 

처음에는 {} 집합 안에 있는 수를 주는 줄 알았다. 

매개변수를 보니 n 집합 안의 수의 갯수, s 집합 안의 수들의 합  

이렇게 두가지만 주어졌다. 

 

집합 안의 수들의 곱이 최대인 애가 답이라서 

합해진 S를 찢어서 곱해봤다. 

 

총합S 나누기 집합갯수 를 했을 때 몫이 0보다 작거나 0이면 바로 return -1

나눴을 때 나머지 없이 몫이 떨어지면 간단! [몫, 몫, 몫] 이렇게 몫이 n개 있으면 됐다.

나머지가 있으면 나머지를 처리해야했다. 집합끼리 곱했을 때 최대가 되도록!

 

 

(처음에는 n이 2개라고 가정하고 식을 써봤다. 곱한 최대값을 어떻게 비교할지가 막막해서. 그런데 막상 보니까 나머지 없이 잘 나눠떨어지는 애들은 전부 집합이 몫으로 같음. 이걸보니 집합끼리 수 차이가 작을수록 모두 곱했을 때 결과가 크구나가 보였다. 기준을 몫으로 나눠떨어지는 애들 아닌애들로 처리해야함이 보였다.)

 

<막혔던 부분>

인덱스 초과를 자꾸 시켰다. 

문제1. answer 답 배열에 몫을 n번 저장하면 되는데  n번을 while안에서 1씩 없애주면서 n 반복해서 넣어주었다. 

넣는 값을 s//n로 해놔서 n이 값이 변경되었다.  

k =n으로 해서 k를 하나씩 빼줬다. 지금 보니 그냥 s//n 몫을 제대로 선언하는게 나을듯

 

문제2. 아직 answer 에 값 넣지도 않았는데 나머지를 처리한다고 answer[0] = 값을 할당했다. 이렇게 했다.  아직 0번째 값은 없는데.. answer은 빈 배열인데요.. 그리고 답은 (집합의 수는) 작은 수부터 정렬을 원해서 나머지를 뒤에서부터 넣어줘야했다. 

 

나머지를 1씩 쪼개서 맨뒤에서부터 하나씩 더해줬다. 

range로 범위정할 때 잘 안돼서 찾아봤다. 

my_list = [1, 2, 3, 4, 5]

for i in range(len(my_list) - 1, -1, -1):
    print(my_list[i])

시작: len(my_list_ -1)

맨 뒤!

범위: -1

맨뒤! 앞에서 조회하는 range와 마찬가지로 범위는 하나 더 한 값으로 써준다. 근데 얘는 마이너스가 붙은.. 맨뒤에서 첫번째까지 

스텝: -1

한번 작동할 때마다 인덱스를 1칸씩 이동한다. 

 

 

 

결과 

def solution(n, s):
    answer = []
    max =0
    if s//n <=0:
        return [-1]
    elif s%n ==0:
        k = n
        while(k>0):
            answer.append(s//n)
            k -= 1
    elif s%n >0:
        k = n
        while(k>0):
            answer.append(s//n)
            k-= 1
        for i in range( len(answer)-1, len(answer)-s%n-1,-1):
            answer[i] += 1
            
            
            
    return answer

 

 

앗!!

얏호~

게비스콘~~

 

시간초과돼서 찾았는데 print 있어서 그랬네 짜슥아~~!! 

 

728x90
728x90

https://school.programmers.co.kr/learn/courses/30/lessons/178870#

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

처음에는 이중 for문으로 풀었다. 테스트 코드는 통과하였으나 

시간 초과가 났다. 

 

어떻게 애들을 더해서 k를 비교할까 고민하다가 

처음에 이중for문으로 생각한 방법은 이렇게 시작 인덱스를 줄여서 더해가다가 k 값과 비교해서 해야지~였다.

def solution(sequence, k):
    answer = []
    min_difference = float('inf')
    selected_numbers =None
    for i in range(len(sequence)):
        total_sum =0
        for j in range(i, len(sequence)):
            total_sum+= sequence[j]
            if total_sum ==k: 
                if (abs(j-i) < min_difference):
                    min_difference = abs(j-i)
                    selected_numbers = (i,j)
                    break

    return selected_numbers

 

문제는 조회하는 배열의 최대 길이가

 

5 ≤ sequence의 길이 ≤ 1,000,000

 

였기에 이중포문을 하면 이차시간으로 계산되어 제곱이 되어 초과된다. 

 

시간복잡도 참고)

출처:&nbsp;https://jeleedev.tistory.com/70

그다음에 for문을 사용하지 않고 어떻게 맨앞자리 인덱스를 줄일지 고민했다. 

여기서 오래 막혔다. 

시간초과 없애려고 이중포문 없애고 해봤는데

i부터 j까지 계속 더해지는거 i를 조작못했다.

 

2차 시도 (사실 2차는 아니긴한데..)

    index = 0
    start = 1
    
    for i in range(start, len(sequence)):
        sequence[index] += sequence[i]
        print("sequence[index]:",sequence[index])
        if i == len(sequence)-1:
            index += 1
            start +=1

    return selected_numbers

이 코드는 그저 처음부터 끝까지 더하기만 한다. 

 

 

처음에 포인터로 시작과 끝을 가리키는 방법을 쓰려했는데 for문으로 어차피 다 조회하니까 시작만 

가리키면 되겠다고 생각해서 반복문에 집착한 것이 나의 실수였다..결국 한참 헤매다가 답지를 봤다.

 

최종 코드 

def solution(sequence, k):
    answer =[]
    start = 0
    end =0
    min = 1000000000
    total = sequence[0]
    while (start <= end < len(sequence)):
        if (total == k):
        
            if min > end- start+1:
                min = end - start+1
                answer =[start, end]
            total -= sequence[start]
            start += 1
        elif (total < k):
            end+= 1
            if end< len(sequence):
                total += sequence[end]  
        elif (total > k):
            total -= sequence[start]
            start += 1
          
    return answer

1.  start end 시작과 끝 두 포인터의 관계 설정이 중요

start <= end

시작포인터와 끝포인터는 같은 곳에서 시작하고 만나서 같을 수는 있어도 넘어서는 안된다. 

나는 계속 전체 배열의 길이만 넘지 말라고 맞춰서 리스트에서 벗어나는 에러가 발생했다. 

 

2. 전체 배열의 값을 더하는 total을 어떻게 처리할지

total 정의할 때 sequence[0] 첫번째 값을 할당하고 시작하면 된다. 

total은 구하고자 하는 k값을 기준으로 나뉜다. 

 

<바로 생각하기 힘들었던 부분>

1. total == k일 때 시작과 끝 두사이 거리가 최소인 값을 찾고 나서 

배열 끝까지 다시 시작과 끝을 움직여야 하는데 

end를 움직여도 될거라 생각했다. 

그렇게 한 결과 end값이 먼저 배열범위보다 커져버려서 테스트 통과를 못했다. 

전체에서 start인덱스의 값을 빼주고 start인덱스를 옮기는 것으로 수정했다. 

 

2. while범위에서 배열의 범위만큼 돌라고 했으니 문제 없을거라 생각했지만

end를 하나씩 추가하고  그 값을 sequence의 인덱스로 넣기 위해 조건을 안 걸면 저렇게 에러가 났다. 

 

 

 

결론 반복문에 그만 집착하고 효율적인 풀이를 생각해보자

컴퓨터가 우리 뇌구조랑 비슷하겠다는 생각을 했다. 생각한게 맞을 수도 있으니 포기말고 구현해봐라

 

728x90

'코딩테스트 > 프로그래머스' 카테고리의 다른 글

프로그래머스 Lv.3 최고의 집합  (0) 2023.09.07
728x90

 

875. Koko Eating Bananas

 

Koko Eating Bananas - LeetCode

Can you solve this real interview question? Koko Eating Bananas - Koko loves to eat bananas. There are n piles of bananas, the ith pile has piles[i] bananas. The guards have gone and will come back in h hours. Koko can decide her bananas-per-hour eating sp

leetcode.com

수업 때 들은 내용 복습 겸 다시 풀었다. 

 

--

코코는 바나나 먹는 걸 좋아해요. n개의 바나나 더미가 있고, i번째 더미에는 [i]개의 바나나가 있습니다. 경비원은 떠났고 몇 시간 후에 다시 올 것입니다.

코코는 시간당 바나나 섭취 속도 k를 결정할 수 있습니다. 매 시간마다 그녀는 바나나 더미를 선택하고 그 더미에서 k개의 바나나를 먹습니다. 더미에 k개 미만의 바나나가 있으면 대신에 바나나를 모두 먹고 이 시간 동안 더 이상 바나나를 먹지 않습니다.

코코는 천천히 먹는 것을 좋아하지만 경비원이 돌아오기 전에 바나나를 모두 먹고 싶어합니다.

그녀가 h 시간 내에 모든 바나나를 먹을 수 있도록 최소 정수 k를 반환합니다.

 

--

 

 

수업때 받은 코드로 풀이

 

원숭이가 주인이 오기 전 h 시간동안 바나나를 먹으려고 한다. 

pile 바나나 더미  = [ 30, 11, 23, 4, 20] 

h = 5

 

원숭이가 5시간 내에 먹을 수 있는 최소 바나나 갯수 k 를 구해야한다. 

 

예를 들어 원숭이가 1시간에 20송이를 먹을 수 있다고 치자

30송이는 20송이 + 10송이이다. 그러면 이 원숭이는 "그녀는 바나나 더미를 선택하고 그 더미에서 k개의 바나나를 먹습니다. 더미에 k개 미만의 바나나가 있으면 대신에 바나나를 모두 먹고 이 시간 동안 더 이상 바나나를 먹지 않습니다."

이 조건에 의해 30송이를 먹는데 2시간이 걸리는 셈이다. 

 

그러면 1시간에 20송이를 먹는 원숭이는 

2시간 + 1시간 + 2시간 + 1시간 + 1시간 = 총 7시간이 걸린다. 5시간 내에 먹기 실패~!

 

이걸 바이너리 서치를 이용해 풀어보자

우리가 구해야할 k의 범위를 정하고 

중간값 m을 지정해 그 m으로 piles 안에 있는 바나나를 먹었을 때 h보다 크면 실패!

h보다 작거나 같으면 시간 안에 먹기 성공!!

 

left 1, right0 을 준 건 초기화를 위함

isEdible이 true면 그 중간값이 답이다

right로 리턴하는 까닭은  m 변수 선언이 로컬로 되어있어서. 

 

중간값을 구할 때 나는 보통 (left + right ) /2 로 구하는데 이번에 다른 방법을 알았다.

 

class Solution {
    public int minEatingSpeed(int[] piles, int h) {
        int left =1 , right =0;
     
        for (int p: piles){
            right = Math.max(right, p);
      
        }
        while(left < right){
             
            int m = left +(right -left)/2;
           
            if ( isEdible(m, piles,h)){
                right = m;
         
            } else{
                left = m + 1;
            
            }
        }
     
        return right;
    }
    private boolean isEdible(int unit, int[] piles, int h){
    
        int curHour = 0;
        for (int p: piles){
          
            curHour += p /unit + (p%unit > 0 ? 1:0);
          
            if (curHour > h){

                return false;
            }
        }
        return true;
    }
}

 

int m = left + (right - left) /2;

로 하는 이유는 오버플로우를 방지하기 위해!

만약 left와 right가 각각 int의 최대범위값을 가지고 있다면 기존 코드대로 하면 나누기 2를 하기 전에 오버플로우 현상이 발생한다. 

 

728x90

'코딩테스트 > 릿코드' 카테고리의 다른 글

1680. Concatenation Of Consecutive BinaryNumbers  (0) 2024.08.01
728x90

https://shanepark.tistory.com/400

 

[MacOS] M1 맥북 도커로 ORACLE DB 실행하기

Intro M1 맥북을 처음 구입 한 이후로 약 1년 반동안, 오라클 데이터베이스를 띄우기 위해 참 많은 노력을 했었습니다. 원래부터 Oracle이 MacOS를 정식 지원을 하지는 않았지만, 그나마 이전의 맥북에

shanepark.tistory.com

이 블로그를 보고 따라했다 정말 감사하다. 

 

나는 저번에 도커로 오라클 설치 시도를 했다가 실패했는데 

기존에 포트번호를 쓰고 있는 곳이 있는지 이런 에러가 떠서 추가적인 작업이 필요했다. 

 

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

이 밑에 1521이 이미 쓰이고 있다는 이야기도 같이 찍혔다. 

 

그래서 

 sudo lsof -i :1521

로 1521 쓰고 있는 PID 번호 확인하고 (PID 는 Process ID 의 줄임말로 운영체제에서 프로세스를 식별하기 위해 부여하는 번호를 의미)

 

kill -9 50797

없앴다.

그리고 실행되어있던 colima 를 멈추고 

colima stop

 

이미 설치해 놨던 걸 찾아서 

 

 실행되고 끝난 docker container를 포함하여 출력하는 명령문

docker ps -a

 

 

다시 실행했다. 

docker start [컨테이너 이름]

 

 

728x90

+ Recent posts