Java : 정적 메소드 사용시기


911

정적 메소드를 언제 사용해야하는지 궁금합니다. getter와 setter가 몇개 인 클래스, 메소드 또는 두 개가 있고 클래스의 인스턴스 객체에서만 해당 메소드를 호출 할 수 있기를 원한다고 가정하십시오. 이것이 정적 메소드를 사용해야 함을 의미합니까?

예 :

Obj x = new Obj();
x.someMethod

또는

Obj.someMethod

(정적 인 방법입니까?)

오히려 혼란 스러워요!

답변:


1458

하나의 규칙 : "자체가 아직 구성되지 않은 경우에도이 메서드를 호출하는 것이 합리적입니까?" 그렇다면 확실히 정적이어야합니다.

따라서 클래스 Car에는 메소드가있을 수 있습니다.

double convertMpgToKpl(double mpg)

... 누구도 빌드하지 않은 경우에도 35mpg가 변환되는 것을 알고 싶을 수 있기 때문에 정적 Car입니다. 그러나이 방법 (특정의 효율성을 설정 Car) :

void setMileage(double mpg)

... Car어떻게 구성 되기 전에 메소드를 호출 할 수 없기 때문에 정적 일 수 없습니다 .

(그렇지만, 그 반대는 항상 사실이 아닙니다. 때로는 두 개의 Car객체 를 포함하는 메소드가있을 수 있으며 여전히 정적이기를 원할 수 있습니다.

Car theMoreEfficientOf( Car c1, Car c2 )

이것은 비 정적 버전으로 변환 될 수 있지만 일부는 "권한있는"선택 Car이 더 중요하지 않기 때문에 호출자가 Car호출 할 객체로 하나를 선택하도록 강요해서는 안된다고 주장 합니다 방법에. 이 상황은 모든 정적 메소드 중 상당히 작은 부분을 차지합니다.)


325
여기 몇 가지 좋은 예가 있습니다. 그러나 "정적"은 인스턴스간에 변경되지 않는 것을 알고있을 때 종종 가치가 있다고 덧붙입니다. 이런 경우라면, 나는“단일 책임 원칙”을 고려할 것인데, 이는 클래스가 하나의 책임을 가져야하며 따라서 변경해야 할 단 하나의 이유가 있어야 함을 의미합니다. "ConvertMpgToKpl (double mpg)"함수 및 유사한 메소드를 자체 클래스로 이동하는 것을 고려해야합니다. 자동차 객체의 목적은 자동차의 인스턴스화를 허용하고 자동차 간의 비교를 제공하지 않는 것입니다. 클래스 외부에 있어야합니다.
잭 얀센

34
나는 오히려 방법을 생각합니다 Car#isMoreEfficientThan(Car). 넥타이로 돌아 오는 차가 임의적이지 않다는 장점이 있습니다. 메소드의 제목에 의해 넥타이로 반환되는 것이 분명합니다.
Cruncher

5
또한 일부 외부 리소스 (파일 시스템, 데이터베이스 등)를 사용하는 정적 메소드를 만드는 데주의를 기울일 것입니다.이 유형의 정적은 소비하는 메소드를 테스트하는 것이 끔찍합니다. 저는 개인적으로 "유틸리티"의 영역에서 정적을 유지하려고합니다.
Seth M.

7
실제로는 Comparator 로 구현해야합니다 .
Dogweather

3
@ B1KMusic 물론입니다. "타이에서 어떤 차가 반환되는지"의 의미는 "차에 착륙 한 차량에 대한 실제지도, 통과 된 차량에 대한 거짓지도"입니다. 모호함이 없습니다.
Cruncher

538

다음 시나리오에서만 정적 메소드를 정의하십시오.

  1. 유틸리티 클래스를 작성 중이고 변경되지 않아야하는 경우
  2. 메소드가 인스턴스 변수를 사용하지 않는 경우
  3. 작업이 인스턴스 생성에 의존하지 않는 경우.
  4. 모든 인스턴스 메소드가 쉽게 공유 할 수있는 코드가 있으면 해당 코드를 정적 메소드로 추출하십시오.
  5. 메소드 정의가 절대 변경되거나 대체되지 않을 것이라고 확신하는 경우. 정적 메서드는 재정의 할 수 없습니다.

45
좋은 점이지만 메소드를 작성 해야 할 이유가 아니라 메소드를 정적으로 만들 려면 요구 사항 입니다.
tetsuo

4
요구 사항에 대한 @Mohd 5 : 언제 메소드가 절대 변경되거나 무시되지 않을 것이라고 100 % 확신 할 수 있습니까? 정적 메소드를 작성하는 순간에 고려할 수없는 알 수없는 요소가 항상 있습니까?
PixelPlex

8
"유틸리티 클래스"는 추론하기가 매우 어렵습니다. 나쁜 점은 조만간 모든 것이 유틸리티처럼 보이기 시작한다는 것입니다. 그리고 테스트 케이스는 더 많은 작업이 필요합니다 (정적 유틸리티를 조롱하는 것은 어렵습니다). 먼저 물건을 선호하십시오.
Sergio

2
@Mohd이 답변은 내가 찾고있는 것입니다. 멀티 스레딩에서 정적 메서드를 사용하는 데 많은 문제가있었습니다. 당신이 (당신을 위해 예를 들어 100 엄지 손가락) 정교한 점 2, 3, 더 기쁘게 할 수
프라 카쉬 펜디 교수

정적 변수와 메소드를 사용하려면 "정적 클래스"가 발명되어야한다고 생각합니다.
Robert Rocha

182

정적 메소드를 사용해야하는 몇 가지 유효한 이유가 있습니다.

  • 성능 : 일부 코드를 실행하고 추가 객체를 인스턴스화하지 않으려면 정적 메소드로 입력하십시오. JVM은 또한 정적 메소드를 많이 최적화 할 수 있습니다 (정적 메소드는 빠르지 만 소스를 찾을 수 없으므로 JVM에서 사용자 정의 명령이 필요하지 않다고 선언하는 James Gosling을 읽었습니다. 그것은 완전히 거짓 일 수 있습니다). 그렇습니다. 미세 최적화이며 필요하지 않을 것입니다. 그리고 우리 프로그래머들은 필요하지 않은 것들이 시원하기 때문에 절대하지 않습니다.

  • 실용성 : new Util().method(arg), call Util.method(arg)또는 method(arg)정적 가져 오기 대신에 . 더 쉽고 짧습니다.

  • 메소드 추가 : 실제로 클래스 클래스에 removeSpecialChars()인스턴스 메소드 를 갖기를 원했지만 거기에 없습니다 (프로젝트의 특수 문자가 다른 프로젝트의 문자와 다를 수 있기 때문에), 추가 할 수 없습니다 (Java 이후) 제정신입니다), 그래서 당신은 유틸리티 클래스를 만들고 removeSpecialChars(s)대신에 호출s.removeSpecialChars() . 단.

  • 순도 : 몇 가지 예방 조치를 취하면 정적 메소드는 순수한 함수가됩니다 . 즉, 의존하는 유일한 것은 매개 변수입니다. 데이터 입력, 데이터 출력 상속에 대한 걱정이 없기 때문에 읽기 쉽고 디버그하기 쉽습니다. 인스턴스 메소드로도 수행 할 수 있지만 컴파일러는 정적 메소드 (인스턴스 속성에 대한 참조를 허용하지 않거나 메소드를 재정의하는 등)를 사용하여 조금 더 도움을 줄 것입니다.

싱글 톤을 만들려면 정적 메서드를 만들어야하지만 그렇지 않습니다. 두 번 생각하십시오.

더 중요한 것은 정적 메서드를 만들고 싶지 않습니까? 기본적으로 다형성은 창 밖으로 나옵니다 . 메소드를 재정의 하거나 인터페이스 (Java 8 이전) 에서 선언 할 수 없습니다 . 디자인에서 많은 유연성이 필요합니다. 또한 state 가 필요한 경우 조심하지 않으면 많은 동시성 버그 및 / 또는 병목 현상이 발생합니다.


1
static이 유용한 경우 여기에 나열된 많은 좋은 이유가 있습니다. 제가 생각할 수있는 또 하나의 방법은 그러한 방법에 대한 단위 테스트 작성은 단순합니다.
nilesh

@tetsuo 감사합니다! 귀하의 설명은 매우 명확하며 제공된 이유는 매우 논리적이며 많은 의미가 있습니다.
Deniss M.

3
그리고 우리 프로그래머들은 필요하지 않은 것들이 시원하기 때문에 절대하지 않습니다. +1
Scaramouche

정적 메소드는 완전한 이름의 함수가되었습니다. stackoverflow.com/questions/155609/…
Ivanzinho

나는 퍼포먼스가 아닌 퍼포먼스와 실용성에 동의합니다. 정적 메소드는 클래스의 정적 멤버 (비공개 일 수 있음)를 수정할 수 있습니다. 유용 할 수 있습니다. 예를 들어, "정적 동기화 된 int assignID () {return idNext ++;}"와 같은 메소드가있을 수 있습니다. 사실, 정적 방법은 부작용 측면에서 비 정적 방법과 마찬가지로 순수하거나 불완전 할 수 있습니다.
Adam Gawne-Cain

42

Misko의 기사를 읽은 후 정적 관점은 테스트 관점에서 좋지 않다고 생각합니다 . 대신 팩토리 가 있어야 합니다 ( Guice 와 같은 종속성 주입 도구를 사용 중일 수 있습니다 ).

내가 하나만 가지고 있는지 어떻게 확인합니까?

"내가 하나만 가지고 있는지 확인하는 방법"이라는 문제는 아주 좋은 단계입니다. 기본에서 단일 ApplicationFactory 만 인스턴스화하고 결과적으로 모든 싱글 톤의 단일 인스턴스 만 인스턴스화합니다.

정적 메소드의 기본 문제는 절차 코드입니다.

정적 메서드의 기본 문제는 절차 코드라는 것입니다. 절차 코드를 단위 테스트하는 방법을 모르겠습니다. 단위 테스트에서는 응용 프로그램을 개별적으로 인스턴스화 할 수 있다고 가정합니다. 인스턴스화하는 동안 실제 종속성을 대체하는 모의 / 친구와 종속성을 연결합니다. 절차 적 프로그래밍을 사용하면 객체가 없으므로 코드와 데이터가 분리되므로 "와이어"가 없습니다.


20
절차 코드를 단위 테스트 할 수 없다는 부분을 이해하지 못합니다. 정적 메소드를 클래스와 함께 "단위"로 사용하여 올바른 입력을 올바른 출력에 맵핑하는 테스트 케이스를 설정하지 않습니까?
tjb

2
그 기능을 테스트하기 위해 그렇게 할 수 있습니다. 그러나 테스트하려는 다른 클래스에서 이러한 정적 메서드를 사용할 때 클래스를 인스턴스화 할 수 없기 때문에 가짜 (모의 / 친구) 또는 다른 것을 가짜로 만들 수 없다고 생각합니다.
Alfred

4
@Alfred : 정적 메소드를 조롱 할 수있는 PowerMock 을 살펴보십시오 . PowerMock을 사용하면 조롱 할 수없는 메소드 종속성을 찾는 시나리오가 거의 없습니다.
Carles Sala

7
PowerMock을 사용하여 정적을 단위 테스트 할 수는 있지만 곧 Permgen 공간이 부족하다는 것을 알게 될 것입니다 (티셔츠를 입 었음). C에서 마이그레이션하지 않고 실제 OO 언어에서 10 년 이상의 경험을 바탕으로 알고 있지 않는 한 IT를 수행하지 마십시오. 내가 본 것 중 최악의 코드는 임베디드 개발자의 스태틱 사용에서 비롯된 것입니다. 대부분의 경우 우리는이 코드를 영원히 고착 시켰고 더 많은 코드를 추가하면 수정 불가능한 단일체에 더 단단히 고정되었습니다. 느슨한 커플 링 : 아니오, 테스트 가능 : 간신히, 수정 가능 : 절대. 기피!
user1016765

14
정적 상태에 의존하는 정적 메소드 테스트의 어려움을 이해할 수 있습니다. 하지만 테스트 할 때 무의 같은 정적 방법을 Math.abs()하거나 Arrays.sort(), 심지어 방법을 수행 할 수 있습니다 로 모든 종속성을 통과 , 나는 어떻게 것 이제까지 방해 단위 테스트가 표시되지 않습니다. 간단한 경험 법칙은 다음과 같습니다. 절차 적 논리를 모방해야 할 이유가 있다면 정적 방법으로 넣지 마십시오. 나는 밖으로 조롱하는 이유가 결코 Arrays.sort()Math.abs().
Andy

36

static방법은 호출 할 수 있도록 모든 개체를 필요로하지 않는 방법의 한 가지 유형의 초기화 할 것입니다. Java staticmain함수에서 사용되는 것을 보셨습니까 ? 객체가 생성되지 않은 상태에서 프로그램 실행이 시작됩니다.

다음 예제를 고려하십시오.

 class Languages 
 {
     public static void main(String[] args) 
     {
         display();
     }

     static void display() 
     {
         System.out.println("Java is my favorite programming language.");
     }
  }

실제로 가장 좋은 답변
Yahya

20

java의 정적 메소드는 클래스가 아닙니다 (인스턴스 아님). 그들은 인스턴스 변수를 사용하지 않으며 일반적으로 매개 변수에서 입력을 받아 조치를 수행 한 다음 결과를 반환합니다. 인스턴스 메소드는 오브젝트와 연관되며 이름에서 알 수 있듯이 인스턴스 변수를 사용할 수 있습니다.


12

정적 메소드는 인스턴스와 연관되지 않습니다. 그들은 수업에 속합니다. 정적 메소드는 두 번째 예입니다. 인스턴스 메소드가 첫 번째입니다.


1
객체의 상태 조작이 필요하지 않은 경우 정적 메소드를 사용해야합니다.
MastAvalons 2018 년

11

어떤 방법으로도 정적 키워드를 적용하면 정적 방법이라고합니다.

  1. 정적 메서드는 클래스의 개체가 아닌 클래스에 속합니다.
  2. 클래스의 인스턴스를 만들 필요없이 호출 된 정적 메서드
  3. 정적 메소드는 정적 데이터 멤버에 액세스하여 그 값을 변경할 수 있습니다.
  4. 정적 메소드는 클래스 도트 정적 이름의 이름을 사용하여 액세스 할 수 있습니다. . . 예 : Student9.change ();
  5. 클래스의 비 정적 필드를 사용하려면 비 정적 메서드를 사용해야합니다.

// 모든 객체의 공통 속성을 변경하는 프로그램 (정적 필드).

class Student9{  
 int rollno;  
 String name;  
 static String college = "ITS";  

 static void change(){  
 college = "BBDIT";  
 }  

 Student9(int r, String n){  
 rollno = r;  
 name = n;  
 }  

 void display (){System.out.println(rollno+" "+name+" "+college);}  

public static void main(String args[]){  
Student9.change();  

Student9 s1 = new Student9 (111,"Indian");  
Student9 s2 = new Student9 (222,"American");  
Student9 s3 = new Student9 (333,"China");  

s1.display();  
s2.display();  
s3.display();  
}  }

O / P : 111 인도 BBDIT 222 미국 BBDIT 333 중국 BBDIT


10

정적 메서드는 인스턴스와 연결되어 있지 않으므로 클래스의 비 정적 필드에 액세스 할 수 없습니다.

메소드가 클래스의 필드 (또는 정적 필드 만)를 사용하지 않는 경우 정적 메소드를 사용합니다.

클래스의 비 정적 필드를 사용하는 경우 비 정적 메서드를 사용해야합니다.


1
명확하고 짧고 간단한 답변.
Josi

8

정적 메소드는 클래스에서 호출되어야하고 인스턴스 메소드는 클래스의 인스턴스에서 호출되어야합니다. 그러나 그것은 실제로 무엇을 의미합니까? 다음은 유용한 예입니다.

자동차 클래스에는 Accelerate ()라는 인스턴스 메소드가있을 수 있습니다. 자동차가 실제로 존재하는 경우 (구성된 경우)에만 자동차를 가속 할 수 있으므로 이것이 인스턴스 방법입니다.

자동차 클래스에는 GetCarCount ()라는 count 메소드가있을 수도 있습니다. 생성 된 (또는 생성 된) 총 자동차 수를 반환합니다. 자동차가 구성되지 않은 경우이 메서드는 0을 반환하지만 여전히 호출 할 수 있어야하므로 정적 메서드 여야합니다.


6

실제로 클래스에서 정적 속성과 메서드를 사용합니다. 프로그램을 실행할 때까지 프로그램의 일부를 사용해야 할 때 프로그램이 실행될 때까지 있어야합니다. 그리고 정적 속성을 조작하려면 인스턴스 변수의 일부가 아니기 때문에 정적 메서드가 필요하다는 것을 알고 있습니다. 정적 메서드가 없으면 정적 속성을 조작하는 데 시간이 많이 걸립니다.


정적 변수에 상태를 유지하는 것은 멀티 스레딩 안전, 디버깅, 데이터 캡슐화 등과 같은 여러 가지 이유로 나쁜 일입니다. 정적 메서드는 순수한 기능이라면 괜찮습니다 (매개 변수로만 변경하지 않고 작업). 수학 계산과 같은 유틸리티 클래스가 좋은 예입니다.
블라디미르 데미 레프

5

클래스의 인스턴스없이 메소드에 액세스하려면 정적 메소드를 사용하십시오.


29
이것은 프로그램 설계에 대한 근거를 제공하지 않습니다.
adamjmarkham

4

공전: Obj.someMethod

사용 static당신이 방법은 클래스의 인스턴스없이 호출해야하는 방법, 즉에 클래스 수준의 액세스를 제공하려는 경우.


4

정적 메소드는 오브젝트에서 호출 할 필요가 없으며,이를 사용할 때입니다. 예 : Main ()은 정적이며 호출 할 객체를 만들지 않습니다.


1
예이! Java noobie 질문을 인터넷 검색하는 동안 내가 온 곳을 찾으십시오! 그것은 작은 세계입니다 :-)
Deepak

1
@Deepak 작은 세계 실제로 :)
Vaishak Suresh

4

정적 메소드 및 변수는 Java에서 '전역'함수 및 변수의 제어 버전입니다. classname.methodName()또는 로 액세스 할 수있는 메소드 classInstanceName.methodName(), 즉 클래스 이름과 클래스 인스턴스를 사용하여 정적 메소드 및 변수에 액세스 할 수 있습니다.

클래스는 static으로 선언 될 수 없습니다 (이해가되지 않기 때문에 클래스가 public으로 선언되면 어디서나 액세스 할 수 있음). 내부 클래스는 static으로 선언 될 수 있습니다.


3

다음과 같은 경우 정적 방법을 사용할 수 있습니다

  • 인스턴스에 대한 조치를 수행하지 않으려는 경우 (유틸리티 메소드)

    이 게시물의 위의 답변 중 일부에서 언급했듯이 마일을 킬로미터로 변환하거나 화씨에서 섭씨로 또는 그 반대로 온도를 계산합니다. 정적 메소드를 사용하는 이러한 예제를 사용하면 힙 메모리에서 완전히 새로운 객체를 인스턴스화 할 필요가 없습니다. 아래를 고려하십시오

    1. new ABCClass(double farenheit).convertFarenheitToCelcium() 
    2. ABCClass.convertFarenheitToCelcium(double farenheit)

    전자는 모든 메소드 호출, Performance, Practical에 대해 새로운 클래스 풋 프린트를 작성합니다 . 아래는 Math 및 Apache-Commons 라이브러리 StringUtils 클래스입니다.

    Math.random()
    Math.sqrt(double)
    Math.min(int, int)
    StringUtils.isEmpty(String)
    StringUtils.isBlank(String)
  • 간단한 기능으로 사용하고 싶습니다. 입력이 명시 적으로 전달되어 결과 데이터를 반환 값으로 가져옵니다. 상속, 객체 인스턴스화는 그림으로 나오지 않습니다. 간결하고 읽기 쉬운 .

참고 : 정적 메소드의 테스트 가능성에 반대하는 사람들은 거의 없지만 정적 메소드도 테스트 할 수 있습니다! jMockit을 사용하면 정적 메소드를 조롱 할 수 있습니다. 테스트 가능성 . 아래 예 :

new MockUp<ClassName>() {
    @Mock
    public int doSomething(Input input1, Input input2){
        return returnValue;
    }
};

3

정적 메소드는 클래스 오브젝트를 작성하지 않고 호출 할 수있는 Java의 메소드입니다. 그것은 수업에 속합니다.

인스턴스를 사용하여 메소드를 호출 할 필요가없는 경우 정적 메소드를 사용합니다.


2

정적 메소드를 언제 사용해야하는지 궁금합니다.

  1. static메소드 의 일반적인 용도 는 static필드 에 액세스하는 것 입니다.
  2. 그러나 변수 static를 참조하지 않고 메소드 를 가질 수 있습니다 static. static변수 를 참조하지 않는 헬퍼 메소드 는 java.lang.Math 와 같은 일부 Java 클래스에서 찾을 수 있습니다.

    public static int min(int a, int b) {
        return (a <= b) ? a : b;
    }
  3. 다른 유스 케이스에서는 이러한 메소드를 메소드와 결합하여 synchronized멀티 스레드 환경에서 클래스 레벨 잠금을 구현하는 것으로 생각할 수 있습니다.

getter와 setter가 몇개 인 클래스, 메소드 또는 두 개가 있고 클래스의 인스턴스 객체에서만 해당 메소드를 호출 할 수 있기를 원한다고 가정하십시오. 이것이 정적 메소드를 사용해야 함을 의미합니까?

클래스의 인스턴스 객체에서 메소드에 액세스해야하는 경우 메소드는 정적이 아니어야합니다.

Oracle 설명서 페이지에 자세한 내용이 있습니다.

인스턴스 및 클래스 변수 및 메소드의 모든 조합이 허용되는 것은 아닙니다.

  1. 인스턴스 메소드는 인스턴스 변수 및 인스턴스 메소드에 직접 액세스 할 수 있습니다.
  2. 인스턴스 메소드는 클래스 변수 및 클래스 메소드에 직접 액세스 할 수 있습니다.
  3. 클래스 메소드는 클래스 변수 및 클래스 메소드에 직접 액세스 할 수 있습니다.
  4. 클래스 메서드는 인스턴스 변수 나 인스턴스 메서드에 직접 액세스 할 수 없으며 개체 참조를 사용해야합니다. 또한 클래스 메소드는 참조 할 인스턴스가 없으므로 this 키워드를 사용할 수 없습니다.

일반 메소드를 통해 정적 필드에 액세스 할 수 없습니까? 그렇다면 이것은 A common use for static methods is to access static fields.논쟁이 아닙니다.
parsecer

2

정적 메소드에는 두 가지 주요 목적이 있습니다.

  1. 개체 상태가 필요없는 유틸리티 또는 도우미 메서드 인스턴스 변수에 액세스 할 필요가 없으므로 정적 메소드를 사용하면 호출자가 메소드를 호출하기 위해 오브젝트를 인스턴스화 할 필요가 없습니다.
  2. 카운터와 같이 클래스의 모든 인스턴스가 공유하는 상태입니다. 모든 인스턴스는 동일한 상태를 공유해야합니다. 해당 상태 만 사용하는 메소드는 정적이어야합니다.

1

일식에서 잠재적 정적 메소드를 감지하는 데 도움이되는 경고를 활성화 할 수 있습니다. (강조 표시된 줄 위에는 강조 표시하지 않은 것이 있습니다)

일식 설정


0

코드에서 메소드를 호출하는 객체를 작성하지 않으려는 경우 해당 메소드를 정적으로 선언하십시오. 정적 메소드는 호출 할 인스턴스가 필요하지 않지만 여기서 catch는 모든 정적 메소드가 JVM에 의해 자동으로 호출되는 것은 아닙니다. 이 특권은 런타임시 Java가 main () "public static void main [String ... args]"메소드 만 사용합니다. 이는 런타임에 JVM에서 시작점으로 찾은 Signature public "static"void main [] 메소드입니다. 코드 실행을 시작하십시오.

예:

public class Demo
{
   public static void main(String... args) 
   {
      Demo d = new Demo();

      System.out.println("This static method is executed by JVM");

     //Now to call the static method Displ() you can use the below methods:
           Displ(); //By method name itself    
      Demo.Displ(); //By using class name//Recommended
         d.Displ(); //By using instance //Not recommended
   }

   public static void Displ()
   {
      System.out.println("This static method needs to be called explicitly");
   }
} 

출력 :-이 정적 메소드는 JVM에 의해 실행됩니다.이 정적 메소드를 명시 적으로 호출해야합니다.이 정적 메소드를 명시 적으로 호출해야합니다.이 정적 메소드를 명시 적으로 호출해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.