Здесь много правильных ответов, но я хотел добавить это (для полноты):
Если вы в нижней части файла cpp реализации выполняете явное инстанцирование всех типов, которые будут использоваться шаблоном с, компоновщик сможет найти их как обычно.
Изменить: добавление примера явного создания экземпляра шаблона. Используется после того, как шаблон определен, и определены все функции-члены.
template class vector<int>;
Это создаст экземпляр (и, следовательно, сделает доступным для компоновщика) класс и все его функции-члены (только). Подобный синтаксис работает для функций шаблона, поэтому, если у вас есть перегрузки операторов, не являющихся членами, вам может понадобиться сделать то же самое для них.
Вышеприведенный пример бесполезен, поскольку вектор полностью определен в заголовках, за исключением случаев, когда common include file (precompiled header?) использует extern template class vector<int>
, чтобы не создавать его из всех других (1000?) файлов, которые используют вектор.
Поскольку статика инициализируется в порядке, указанном в исходном коде.
Проверьте это:
class MyClass {
private static MyClass myClass = new MyClass();
private static MyClass myClass2 = new MyClass();
public MyClass() {
System.out.println(myClass);
System.out.println(myClass2);
}
}
Это напечатает:
null
null
myClassObject
null
РЕДАКТИРОВАТЬ
Хорошо, давайте нарисуем это, чтобы быть немного яснее.
Это ясно?
РЕДАКТИРОВАТЬ 2
Как указал Варман, ссылка на себя будет нулевой, пока она инициализируется. Что имеет смысл, если вы думаете об этом.
Давайте попробуем по-другому объяснить это ...
Это последовательность, которую JVM проходит, когда вы впервые ссылаетесь на класс MyClass
.
static { ... }
. myClass
новым экземпляром MyClass
. MyClass
уже загружен (байт-код) и находится в процессе инициализации , поэтому пропускает инициализацию. obj
, которое все еще равно null
(поскольку оно не является частью инициализированных переменных кучи и конструктора). obj
в новый экземпляр Object
. obj
будет не null
, а ссылкой на экземпляр Object
. Помните, что Java указывает, что переменной final
присваивается значение один раз. Дело не в том, что ему гарантируется присвоение значения, когда код ссылается на него, если только вы не убедитесь, что код ссылается на него после того, как оно назначено.
Это не ошибка. Это определенный способ обработки использования класса во время его собственной инициализации. Если бы это было не так, то JVM пошла бы в бесконечный цикл. См. Шаг № 3.3 (если JVM не пропускает инициализацию для класса, который находится в процессе инициализации, он просто продолжит инициализировать его - бесконечный цикл).
Обратите внимание, что все это происходит в том же потоке, который сначала ссылается на класс. Во-вторых, JVM гарантирует, что инициализация будет завершена до того, как любой другой поток сможет использовать этот класс.
Это потому, что Java выполняет статический раздел в порядке его объявления. В вашем случае последовательность
Когда выполняется # 1, объект obj все еще не инициализирован, поэтому он печатает ноль. Попробуйте следующее, и вы увидите разницу:
class MyClass {
private static final Object obj = new Object();
private static MyClass myClass = new MyClass();
public MyClass() {
System.out.println(obj); // will print null once
}
}
Вообще говоря, лучше избегать такой конструкции все вместе. Если вы пытаетесь создать синглтон, вот как должен выглядеть этот фрагмент кода:
class MyClass {
private static final MyClass myClass = new MyClass();
private Object obj = new Object();
private MyClass() {
System.out.println(obj); // will print null once
}
}
это потому, что статические поля инициализированы в том же порядке, который они определили.
@Pyrolistical
, поскольку начальная часть первого статического поля myclass не полностью построена ... полученный результат -
null null testInitialize.MyObject@70f9f9d8 null