인스턴스 생성이 왜 그런가?


17

지난 6 개월 정도 동안 C #을 배웠으며 이제는 Java를 탐구하고 있습니다. 내 질문은 인스턴스 생성에 관한 것입니다 (실제로 언어로). 이 예제를 보자

Person Bob = new Person();

객체가 두 번 지정된 이유가 있습니까? 이 적을 수 있을까요 something_else Bob = new Person()?

컨벤션에서 팔로우한다면 다음과 같습니다.

int XIsAnInt;
Person BobIsAPerson;

아니면 다음 중 하나 일 것입니다.

Person() Bob;
new Person Bob;
new Person() Bob;
Bob = new Person();

나는 "그것이 끝나는 방식"보다 더 나은 대답이 있다면 궁금하다고 생각합니다.


26
Person이 하위 유형 인 경우 어떻게 LivingThing됩니까? 당신은 쓸 수 LivingThing lt = new Person()있습니다. 상속 과 인터페이스를 찾으십시오 .
xlecoustillier 2019

2
Person Bob"reference " 형식 의 변수Person호출 Bob합니다. 객체를 new Person()만듭니다 Person. 참조, 변수 및 객체는 서로 다른 세 가지입니다!
user253751

5
당신은 중복에 의해 화가 있습니까? 그럼 왜 쓰지 var bob = new Person();않습니까?
200_success

4
Person Bob();C ++에서 가능하며 다음과 거의 같은 의미입니다.Person Bob = Person();
user60561

3
@ user60561 아니오, 인수를 취하지 않고 Person을 리턴하는 함수를 선언합니다.
Nikolai

답변:


52

something_else Bob = new Person ()이 있습니까?

예, 상속 때문입니다. 만약:

public class StackExchangeMember : Person {}

그때:

Person bob = new StackExchangeMember();
Person sam = new Person();

밥도 사람이며, 어리석은 사람은 다른 사람과 다르게 대우 받고 싶지 않습니다.

또한 Bob에게 다음과 같은 강력한 기능을 부여 할 수 있습니다.

public interface IModerator { }
public class StackOverFlowModerator : StackExchangeMember, IModerator {}

IModerator bob = new StackOverFlowModerator();

그래서, Golly에 의해, 그는 다른 중재자와 다른 대우를받는 것을지지 않을 것입니다. 그리고 그는 시크릿 모드에서 모든 사람들이 줄을 서도록 포럼을 몰래 들여다보고 싶어합니다.

StackExchangeMember bob = new StackOverFlowModerator();

그런 다음 가난한 1st 포스터를 발견하면 보이지 않는 망토를 벗습니다.

((StackOverFlowModerator) bob).Smite(sam);

그리고 나서 그는 모든 결백하고 행동 할 수 있습니다.

((Person) bob).ImNotMeanIWasJustInstantiatedThatWay();

20
객체 이름을 소문자로 입력하면 훨씬 명확 해집니다.
Monica와의 가벼움 경주

38
사양의 좋은 예; 상속의 나쁜 예. 이것을 읽는 다른 사람에게는 상속을 사용하여 사용자 역할을 해결하려고 시도하지 마십시오.
Aaronaught

8
@Aaronaught가 맞습니다. 다른 유형의 사람들을 위해 별도의 클래스를 만들지 마십시오. 비트 필드를 사용하십시오 enum.
Cole Johnson

1
@Aaronaught 모두하지 말아야 할 것을 말하는 것은 매우 좋지만, 사람들이 대신해야 할 것을 말하지 않으면 도움이되지 않습니다.
Pharap

5
@Pharap : 몇 가지 다른 질문 에서 정확히 했어요 . 간단한 대답은 사용자 (인증 / 신원)와 보안 정책 (권한 / 권한)이 별도의 문제로 취급되어야하며 보안 정책의 표준 모델은 역할 기반 또는 클레임 ​​기반이라는 것입니다. 상속은 실제로 인증을 수행하는 객체 (예 : LDAP 구현 및 SQL 구현)를 설명하는 데 더 유용합니다.
Aaronaught

34

첫 번째 코드 줄을 가져 와서 살펴 보겠습니다.

Person Bob = new Person();

첫 번째 Person형식 사양입니다. C #에서는 간단히 말해서 이것을 피할 수 있습니다.

var Bob = new Person();

컴파일러는 생성자 호출에서 변수 Bob의 유형을 유추 합니다 Person().

그러나 다음과 같이 작성하고 싶을 수도 있습니다.

IPerson Bob = new Person();

Person의 전체 API 계약을 이행하지 않고 interface로 지정된 계약 만 이행하는 경우 IPerson.


2
+1 : IPerson다른 IPerson구현에 복사 / 붙여 넣을 수있는 코드를 작성할 때 실수로 개인 메서드를 사용하지 않도록 코드 에서 예제를 수행합니다.
Cort Ammon-복원 모니카

@CortAmmon 나는 당신이 거기에 오타가 있다고 생각합니다. 분명히 당신은 그 코드에 복사 / 붙여 넣기가 아니라 "다형성으로 작업하십시오"를 의미했습니다 : D
Benjamin Gruenbaum

@BenjaminGruenbaum 확실히 다형성의 정의를 위해 ;-)
Cort

@CortAmmon 어떻게 실수로 개인 메소드를 호출 하겠습니까? 확실 internal합니까?
Cole Johnson

@ColeJohnson 어느 쪽이든. 필자는 private인스턴스화되는 클래스의 일부인 팩토리 메소드 인 의미있는 곳에서 실행되는 특정 사례에 대한 생각을 썼습니다 . 내 상황에서 개인 가치에 대한 접근은 표준이 아닌 예외가되어야합니다. 나는 오래 지속될 코드에서 작업합니다. 내가 이렇게하면 개인 방법을 직접 사용할 수 없을뿐만 아니라 다음 개발자가 수십 곳을 복사하고 붙여 넣은 후 개발자가 복사 한 후 누군가가 기회를 볼 확률을 줄입니다. 전용 메소드를 "정상"동작으로 사용하십시오.
Cort

21
  1. 이 문법은 C ++의 레거시와 비슷하지만 두 가지 모두를 가지고 있습니다.

    Person Bob;

    Person *bob = new Bob();

    첫 번째는 현재 범위 내에서 개체를 만들고 두 번째는 동적 개체에 대한 포인터를 만듭니다.

  2. 당신은 확실히 가질 수 있습니다 something_else Bob = new Person()

    IEnumerable<int> nums = new List<int>(){1,2,3,4}

    여기서는 로컬 변수의 유형을 나타내는 두 가지 다른 작업을 수행하고 있으며 nums'List'유형의 새 객체를 만들고 거기에 넣으려고한다고 말합니다.

  3. C # 종류의 변수는 대부분 변수 유형이 입력 한 것과 동일하기 때문에 동의합니다.

    var nums = new List<int>();
  4. 일부 언어에서는 F # 에서와 같이 변수 유형을 명시하지 않도록 최선을 다합니다 .

    let list123 = [ 1; 2; 3 ]

5
두 번째 예제가 새로운 Bob 객체에 대한 포인터를 생성한다고 말하는 것이 더 정확할 것입니다. 물건이 저장되는 방식은 기술적으로 구현 세부 사항입니다.
Robert Harvey

4
"첫 번째는 스택에 로컬 개체를 만들고 두 번째는 힙에 개체를 만듭니다." 오,이 잘못된 정보가 다시는 아닙니다.
Monica와의 가벼움 경주

@lightnessRacesinOrbit 더 나은가?
AK_

1
@AK_ "동적"은 "힙"(힙이 플랫폼에서 사용하는 메모리 모델 인 경우)을 의미하지만 "자동"은 "스택"과는 매우 다릅니다. 그렇게 new std::pair<int, char>()하면 멤버 firstsecond페어 의 멤버 는 자동 스토리지 기간을 갖지만 힙에 동적 스토리지 스토리지 pair오브젝트의 멤버로 할당 될 수 있습니다.
복원 Monica Monica

1
@AK_ : 그렇습니다.이 이름들은 의미하는 바를 정확히 암시 하지만이 "스택"대 "힙"넌센스는 그렇지 않습니다 . 그게 요점입니다. 당신이 그것들을 혼동한다는 사실은 단지 우리가 그들에게 가르쳐야 할 필요성을 강화 시켜서, 당신이 친숙하기 때문에 부정확하거나 부정확 한 용어에 의존하지 않도록합니다!
Monica와의 가벼움 경주

3

int x와 사이에는 큰 차이가 Person bob있습니다. 은 intint입니다 int그것은 항상이어야 int하고, 이외 될 수 없다 int. int선언 할 때 초기화하지 않아도 ( int x;) 여전히 int기본값으로 설정됩니다.

Person bob그러나을 선언하면 bob특정 시점에서 이름 이 실제로 참조 할 수 있는 많은 유연성 이 있습니다. 그것은 참조 수 Person, 또는 다른 클래스, 예를 참조 할 수 Programmer에서 파생 Person; null전혀 객체를 참조하지 않아도 될 수 있습니다 .

예를 들면 다음과 같습니다.

  Person bob   = null;
  Person carol = new Person();
  Person ted   = new Programmer();
  Person alice = personFactory.functionThatReturnsSomeKindOfPersonOrNull();

언어 설계자들은 Person carol = new Person()더 적은 수의 기호에서 와 동일한 것을 달성 할 수있는 대체 구문을 만들 수 있었지만 여전히 허용해야했습니다 Person carol = new Person() (또는 위의 네 가지 예 중 하나를 불법으로 만드는 이상한 규칙을 만들었습니다). 그들은 매우 간결한 코드를 작성하는 것보다 언어를 "간단하게"유지하는 데 더 관심이있었습니다. 그것은 더 짧은 대안 구문을 제공하지 않기로 한 그들의 결정에 영향을 미쳤을 수도 있지만, 어쨌든 그것은 필요하지 않았고 그것들을 제공하지 않았습니다.


1

두 선언은 다를 수 있지만 종종 동일합니다. Java에서 일반적으로 권장되는 패턴은 다음과 같습니다.

List<String> list = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();

이들 변수 list와이 map인터페이스를 이용하여 선언 ListMap코드 특정 구현을 인스턴스화있다. 이 방법으로 나머지 코드는 인터페이스에만 의존하며 인스턴스화 할 다른 구현 클래스를 쉽게 선택할 TreeMap수 있습니다. 나머지 코드는 인터페이스 HashMap외부 에있는 API의 일부에 의존 할 수 없기 때문 Map입니다.

두 유형이 다른 또 다른 예는 인스턴스화 할 특정 서브 클래스를 선택한 팩토리 메소드에서 기본 유형으로 리턴하여 호출자가 "정책"선택과 같은 구현 세부 사항을 알 필요가없는 경우입니다.

타입 추론은 소스 코드 리던던시를 고칠 수 있습니다. 예를 들어 자바

List<String> listOne = Collections.emptyList();

형식 유추와 선언으로 올바른 종류의 목록을 구성합니다.

static <T> List<T> emptyList(); 

일부 언어에서는 형식 유추가 더 진행됩니다 (예 : C ++).

auto p = new Person();

BTW Java 언어는 bobnot 등의 소문자 식별자 이름을 사용하기위한 강력한 규칙을 설정합니다 Bob. 이것은 package.Class vs. Class.variable과 같은 많은 모호성을 피합니다.
Jerry101

... 그리고 이것이 당신이있는 이유 clazz입니다.
CVn

아니요 . 키워드 clazz이기 때문에 사용되므로 class식별자로 사용할 수 없습니다.
Jerry101

명명 규칙이 원래대로 존재하지 않으면 문제가되지 않습니다. Class완벽하게 유효한 식별자입니다.
cHao

... 등이다 cLaSs, cLASS하고 cLASs.
el.pescado

1

평신도의 말로 :

  • 인스턴스화에서 선언을 분리하면 누가 객체를 만드는지와 누가 객체를 만드는지 분리 할 수 ​​있습니다.
  • 그렇게하면 인스턴스화 된 유형이 선언 유형의 하위 유형 인 한 변수를 사용하는 모든 코드가 작동하기 때문에 polyporphism이 활성화됩니다
  • 강력한 형식의 언어 var = new Process()에서는 변수를 먼저 선언하지 않고 단순히 형식을 나타내는 변수를 선언해야합니다 .

0

또한 무슨 일이 일어나고 있는지에 대한 통제 수준에 관한 것입니다. 객체 / 변수 선언이 자동으로 생성자를 호출하는 경우 (예 :

Person somePerson;

이었다 자동으로 같은

Person somePerson = new Person(blah, blah..);

그러면 정적 생성자 메서드를 사용하여 기본 생성자가 아닌 객체를 인스턴스화 할 수 없습니다. 즉, 새 객체 인스턴스의 생성자를 호출하지 않으려는 경우가 있습니다.

이 예는 Joshua BlochEffective Java (아이템으로 충분하게 항목 1!)에 설명되어 있습니다.


책과 관련하여 내 C # 책과 Java 책은 Joyce Farrell의 책입니다. 그것은 코스가 지정한 것입니다. 또한 C # 및 Java의 다양한 YouTube 비디오를 모두 보완하고 있습니다.
Jason Wohlgemuth

나는이 : 어디에서 왔는지 단지에 대한 참조를주고, 비판하지 않은
데이비드 Scholefield
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.