2015-06-23 10 views
45

Мой первый вопрос -Должны ли конструкторы всегда быть публичными?

class Explain() { 
     public Explain() { 
     } 
    } 

Должен ли конструктор всегда объявлен общественности?

Что делать, если я создаю конструктор private.

Я всегда видел, что конструкторы неявно public. Так почему полезен конструктор private? Или это вообще не полезно. Потому что никто никогда не мог назвать это или никогда не создавать объект (из-за конструктора private)! И это мой второй вопрос.

+3

@George Stocker Название является дубликатом, я согласен. Но на самом деле возникает вопрос: «Почему я хочу объявить частный конструктор?» В этом случае на этот вопрос отвечает только наименьший ответ в дубликате и только тангенциально. – Teepeemm

+0

@HashLeon Я попросил вас сузить свой вопрос; ваш первый вопрос - это дубликат того, на котором я его закрыл, а ваш второй вопрос - это дубликат этого вопроса: http: // stackoverflow.com/questions/17342815/what-is-use-of-private-constructor-in-java –

ответ

66

Нет, Конструкторы может быть public, private, protected или default (без модификатора доступа на всех).

Изготовление чего-то private не означает, что никто не сможет получить к нему доступ. Это просто означает, что никто за пределами класса не может получить к нему доступ. Так полезен и конструктор private.

Одним из вариантов использования конструктора private является использование одноэлементных классов. Класс singleton - это тот, который ограничивает количество создания объектов одним. Используя конструктор private, мы можем гарантировать, что за один раз может быть создано не более одного объекта.

Пример -

public class Database { 

    private static Database singleObject; 
    private int record; 
    private String name; 

    private Database(String n) { 
     name = n; 
     record = 0; 
    } 

    public static synchronized Database getInstance(String n) { 
     if (singleObject == null) { 
      singleObject = new Database(n); 
     } 

     return singleObject; 
    } 

    public void doSomething() { 
     System.out.println("Hello StackOverflow."); 
    } 

    public String getName() { 
     return name; 
    } 
} 

Более подробную информацию оaccess modifiers.

+1

Хороший ответ, но, похоже, это может быть усилено примером того, когда частные конструкторы полезны. Например. фабричные методы: http://jlordiales.me/2012/12/26/static-factory-methods-vs-traditional-constructors/ –

+7

@TomWright Это не так много заводских методов, но [шаблон построителя] (https: // en.wikipedia.org/?title=Builder_pattern), который часто использует частные конструкторы. –

+2

Конструктор 'private' не только обслуживает одноточие. Он обслуживает все виды шаблонов использования, где реализация хочет иметь полный контроль над созданием экземпляра. Обратите внимание, что все 'enum' имеют неявно 'private' constructors ... – Holger

9

Да, Конструкторы могут иметь любой модификатор доступа спецификатор/доступа.

Частные конструкторы полезны для создания классов singleton.

Singleton - Одиночный класс - это класс, в котором во время выполнения (за JVM) может быть создан только один объект.

Простой пример класса Синглтон -

class Ex { 
    private static Ex instance; 
    int a; 
    private Ex() { 
     a = 10; 
    } 
    public static Ex getInstance() { 
     if(instance == null) { 
      instance = new Ex(); 
     } 
     return instance; 
    } 
} 

Примечание для указанного класса, единственный способ получить объект (за пределами этого класса) является вызов функции деЫпзЬапсе(), который будет создайте только один экземпляр и сохраните его.

Также обратите внимание, что это не является потокобезопасным.

+7

Обратите внимание, что это не потокобезопасное. – questionare

+0

Кроме того, объявление «isntance» не будет соответствовать ссылочному «экземпляру», этот код не работает, так как переменная не является «static». Очевидно, вы никогда не пытались скомпилировать это. Кроме того, это бессмысленно. Поскольку классы инициализируются при их первом фактическом использовании, нет необходимости в создании такого ленивого создания. Просто напишите 'private static final Ex instance = new Ex();' и 'public static Ex getInstance() {return instance; } ', и это поле будет инициализировано, когда' getInstance() 'вызывается в первый раз. Тогда это даже поточно-безопасное. – Holger

+1

Извините, пропустил статический код для переменной экземпляра, добавив его сейчас. –

6

Конструкторы могут быть общедоступными, по умолчанию или частными, и все зависит от того, что вы хотите с ним делать.

Например, если вы определяете класс Singleton, вам лучше скрыть (что делает его закрытым, чтобы он был доступен только классу, где он принадлежит) конструктор, чтобы другие классы не могли создать экземпляр класса по их желанию.

Возможно, вы захотите объявить его по умолчанию, скажем, для целей тестирования, чтобы тестовые примеры в одном пакете могли получить к нему доступ.

Более подробная информация может быть найдена here

4

Конструкторы могут иметь все виды модификаторов доступа. Использование разных модификаторов доступа для конструкторов отличается.

Вы создаете конструктор public, если хотите, чтобы класс создавался из любого места.

Вы создаете конструктор protected, если вы хотите, чтобы класс был наследован и его унаследованные классы были созданы.

Вы создаете конструктор private, если вы хотите, чтобы класс создавался только из его собственных элементов, как правило, статический блок или статический метод. Это означает, что вы берете на себя управление экземпляром класса и применяете какое-то правило к экземпляру. Пример использования частного конструктора - шаблон одноэлементного дизайна.

3

Конструктор имеет быть по крайней мере, защищенной или даже частные, создавая, например, пользовательские классы фабрики, как:

public final class MyFactory { 
    private MyFactory(){} // this one prevents instances of your factory 
} 

public static void doSomething(){} // access that with MyFactory.doSomething 

Обратите внимание, что это только один пример, показывающий, когда конструктор не должен быть публичным.

+0

Я согласен, что они * должны *, но говорят, что они * имеют *, могут быть растяжками. –

+0

Почему вы хотите, чтобы конструктор был общедоступным в классе фабрики? –

+0

Я не сказал, что хочу, чтобы это было, я просто сказал, что это не обязательно. Я согласен, что это должно быть. Он будет компилироваться, и он будет запущен, и если кто-то сделает его экземпляр, это не обязательно конец его мира, из-за этого я не думаю, что это правильно сказать ** должно быть **. –

5

Существует не правило, что конструктор должен быть общедоступным. По сути, мы определяем его публично только потому, что хотим также создать его из других классов.

Частный конструктор означает: «Я не позволяю никому создавать мой экземпляр, кроме меня». Так обычно вы делаете это, когда вам нравится иметь одноэлементный узор.

Ниже приведен класс в JDK, который использует частный конструктор.

public class Runtime { 
    private static Runtime currentRuntime = new Runtime(); 

    public static Runtime getRuntime() { 
     return currentRuntime; 
    } 

    // Don't let anyone else instantiate this class 
    private Runtime() { 
    } 
} 
+0

Собственно, частный конструктор означает «Я не позволяю кому-либо создавать мой экземпляр _in этого пути, кроме меня». Класс может легко сочетать конструкторы с разными спецификаторами доступа. –

+0

Эй, Тед, абсолютно прав. Я хочу сказать, если есть только частный конструктор.Спасибо за точку :) –

5

Нет, конструкторы могут использовать любой модификатор доступа, в том числе закрытый. (A private конструктор означает, что только код внутри самого класса может создать объект этого типа, поэтому, если класс частного конструктора хочет разрешить экземпляр класса, который будет использоваться, класс должен предоставить статический метод или переменную, которая позволяет получить доступ к экземпляру созданного внутри класса.)

Пример

class Alpha { 
    static String s = " "; 
    protected Alpha() { s += "alpha "; } 
} 
class SubAlpha extends Alpha { 
    private SubAlpha() { s += "sub "; } 
} 
public class SubSubAlpha extends Alpha { 
    private SubSubAlpha() { s += "subsub "; } 
    public static void main(String[] args) { 
    new SubSubAlpha(); 
    System.out.println(s); 
    } 
} 

Выход выше программы будет

альфа subsub

4

Я согласен с предыдущими ответами, что Singleton - хороший пример класса, имеющего частный конструктор. Я бы рекомендовал, хотя другую реализацию: поточно безопасный Singleton:

/** 
* Thread safe singleton 
*/ 
public class Singleton { 

    private static volatile Singleton instance = null; 

    /** 
    * Private constructor 
    */ 
    private Singleton() { 
    } 

    /** 
    * Gets the Instance of the Singleton in a thread safe way. 
    * @return 
    */ 
    public static Singleton getInstance() { 
     if (instance == null) { 
      synchronized (Singleton.class) { 
       if (instance == null) { 
        instance = new Singleton(); 
       } 
      } 
     } 
     return instance; 
    } 
} 

Использование синглтона в потоке безопасного пути будет безопасно для вас много боли в параллельном коде.

+2

Это все еще совершенно не нужно. Просто напишите 'private static Singleton instance = new Singleton();' и забудьте о 'null'-проверках и' synchronized'. Классы инициализируются при их первом использовании, и, следовательно, уже подразумевается, что поле будет инициализировано, когда 'getInstance()' вызывается в первый раз. Это лениво и поточно-безопасно - бесплатно. – Holger

+0

О, и, кстати, вы код ** не ** поточно-безопасный, это двойная проверка блокировки против шаблона. Не объявляя переменную 'instance' как' volatile', она не работает. – Holger

+0

Уважаемый Холгер, спасибо за ваш комментарий! Вы правы: 'volatile' не хватало! Реализация, которую я предложил, все же позволяет вам инициализировать sth в конструкторе. Я использовал, чтобы инициализировать значения в кеш, поскольку я использовал singleton для кэширования ресурсов. –

0

Простым объяснением является отсутствие конструктора в классе, компилятор автоматически создает конструктор по умолчанию.

Конструктор не всегда объявляется открытым, он также может быть закрытым, защищенным или по умолчанию.

Частные конструкторы препятствуют тому, чтобы класс был полностью и четко выражен/представлен его вызывающими лицами. В этом случае частные конструкторы полезны. И если нам не нужен наш класс для подкласса, мы можем использовать частные конструкторы.

1

Большинство этих ответов относятся к одноточечному или заводскому классу. В другой раз, когда появляется частный конструктор (например), в java.lang.Math class, где все статично, и никто не должен когда-либо вызывать конструктор (включая сам класс). Имея частный конструктор, вы запрещаете кому-либо, кроме класса, вызвать конструктор. (Это не мешает кому-либо из класса вызвать конструктор, но затем они нарушают собственное правило.)

1

Другие отметили, что конструкторы могут иметь модификаторы доступа; аспект еще не упоминается в том, что аспект модификаторы на элементе управления конструктора две очень разные аспекты строительства, но не позволяют им управлять отдельно:

  1. Кто может создавать экземпляры из ClassName и каких конструкторов разрешено ли им пользоваться.
  2. Кому разрешено создавать расширения от ClassName и какие конструкторы им разрешено использовать.

Как Java, так и .NET требуют, чтобы ответы на эти два вопроса совпадали; если класс не final (или sealed) и позволяет конструктору использовать внешний код для создания новых экземпляров, тогда внешний код также будет иметь полную свободу использовать тот же самый конструктор для создания производных типов.

Во многих случаях может быть целесообразным, чтобы класс имел только конструкторы private-private (internal), но раскрывал общедоступные методы, возвращающие новые экземпляры. Такой подход может быть использован, если вы разрабатываете такой тип, как String с нуля; пакет, содержащий String, может определять его как абстрактный тип, но включает в себя конкретные производные типы, такие как AsciiString и UCS16String, которые хранят их содержимое как byte[] и Char[] соответственно; методы, возвращающие String, могут затем вернуть одну из производных в зависимости от того, содержат ли строки символы вне диапазона ASCII. Если ни String, ни любые производные типы не выставляют никаких конструкторов вне его пакета, и все производные типы внутри пакета будут вести себя как строка, как ожидается, будут вести себя, тогда код, который получает ссылку типа String, может ожидать, что он будет вести себя как строка (например, например, гарантируя, что любые наблюдения за его значением навсегда останутся верными). Однако использование конструкторов вне пакета позволило бы производным типам вести себя странным и причудливым образом (например, изменять их содержимое после того, как они были проверены и проверены).

С синтаксической точки зрения, будучи в состоянии сказать Fnord foo = new Fnord(123); немного лучше, чем того, чтобы сказать Fnord foo = Fnord.Create(123);, но класс Fnord, который требует последнего синтаксиса может поддерживать гораздо лучше контролировать процесс объектно-создание.