Чтобы быть конкретным, я пробовал этот код:
package hello;
public class Hello {
Clock clock = new Clock();
public static void main(String args[]) {
clock.sayTime();
}
}
Но это дало ошибку
Cannot access non-static field in static method main
Итак, я изменил объявление clock на это:
static Clock clock = new Clock();
И это сработало. Что значит поставить это ключевое слово перед объявлением? Что именно он будет делать и / или ограничивать с точки зрения того, что можно сделать с этим объектом?
Что такое загрузчик классов?




Члены static принадлежат классу, а не конкретному экземпляру.
Это означает, что существует только один экземпляр поля static[1], даже если вы создаете миллион экземпляров класса или не создаете ни одного. Он будет использоваться всеми экземплярами.
Поскольку методы static также не принадлежат конкретному экземпляру, они не могут ссылаться на члены экземпляра. В приведенном примере main не знает, на какой экземпляр класса Hello (и, следовательно, на какой экземпляр класса Clock) следует ссылаться. Члены static могут относиться только к членам static. Члены экземпляра, конечно, могут получить доступ к членам static.
Примечание: Конечно, члены static могут получить доступ к членам экземпляра через ссылку на объект.
Пример:
public class Example {
private static boolean staticField;
private boolean instanceField;
public static void main(String[] args) {
// a static method can access static fields
staticField = true;
// a static method can access instance fields through an object reference
Example instance = new Example();
instance.instanceField = true;
}
[1]: В зависимости от характеристик времени выполнения, он может быть по одному для ClassLoader, AppDomain или потока, но это не относится к делу.
В .NET вы также можете изменить это поведение с помощью атрибута [ThreadStatic], который делает статическое значение локальным для определенных потоков.
Я знаю, что это старый пост, но для таких новичков, как я, он может быть полезен.
Разве вы не смогли бы получить доступ к instance.instanceField, поскольку это частный var? Или это действительно так, потому что вы создали экземпляр объекта внутри собственного класса? Для меня это звучит как рекурсивный кошмар, но я новичок в Java.
Если на статический член класса ссылаются 2 разных потока, то сколько экземпляров существует у этого статического члена? Мне кажется, что это 2, но если вам нужен один и тот же экземпляр во всех потоках, необходимо использовать ключевое слово volatile. Это верно?
..и сохраняется ли значение, если не осталось экземпляров класса?
Статический означает, что вам не нужно создавать экземпляр класса для использования методов или переменных, связанных с классом. В вашем примере вы можете вызвать:
Hello.main(new String[]()) //main(...) is declared as a static function in the Hello class
напрямую, вместо:
Hello h = new Hello();
h.main(new String[]()); //main(...) is a non-static function linked with the "h" variable
Изнутри статического метода (который принадлежит классу) вы не можете получить доступ к каким-либо членам, которые не являются статическими, поскольку их значения зависят от вашего экземпляра класса. Нестатический объект Clock, который является членом экземпляра, будет иметь другое значение / ссылку для каждого экземпляра вашего класса Hello, и поэтому вы не можете получить к нему доступ из статической части класса.
Отличное объяснение статического контекста :)
Это означает, что в Hello есть только один экземпляр «clock», а не по одному на каждый отдельный экземпляр класса «Hello» или более того, это означает, что будет одна общая ссылка на «часы» среди всех экземпляров класс "Привет".
Итак, если бы вы произнесли «новое приветствие» в любом месте вашего кода: A- в первом сценарии (до изменения, без использования "static") он будет создавать новые часы каждый раз, когда вызывается "new Hello", но B - во втором сценарии (после изменения с использованием «static») каждый экземпляр «new Hello» по-прежнему будет совместно использовать и использовать начальную и ту же ссылку «clock», созданную первым.
Если вам не нужны "часы" где-то за пределами main, это тоже будет работать:
package hello;
public class Hello
{
public static void main(String args[])
{
Clock clock=new Clock();
clock.sayTime();
}
}
Это более обычный способ сделать это. Программа main() должна быть автономной.
Во втором случае он будет создавать новый экземпляр Clock каждый раз, когда вызывается основной метод, верно?
Во втором случае, clock static, он создаст его только один раз. В моем примере, где часы находятся внутри main, тогда да, он будет создавать их каждый раз при вызове main. Но обычно main вызывается только один раз при запуске программы, и когда она завершается, все освобождается.
Я не могу понять, как можно сделать новые часы в основном методе? как вы говорите, он будет создавать его каждый раз при вызове main, но есть только один метод main. как этот основной метод может относиться к разным экземплярам часов? Немного сложно понять, как можно создать новый экземпляр clock в основном и использовать его метод sayTime (), но невозможно сделать экземпляр из основного и использовать sayTime (). как все бесплатно, когда main вызывается один раз? @PaulTomblin
@ user5621266 Я использовал метод main только потому, что это сделал OP. Если бы вместо этого это был общедоступный метод, который был вызван из другого места, а экземпляр класса Hello создавался более одного раза, тогда он мог бы создать экземпляр Clock для каждого экземпляра Hello, если только clock не был статическим.
Статический делает член часов членом класса, а не членом экземпляра. Без ключевого слова static вам нужно будет создать экземпляр класса Hello (который имеет переменную-член clock), например
Hello hello = new Hello();
hello.clock.sayTime();
статические методы не используют никаких переменных экземпляра того класса, в котором они определены. Очень хорошее объяснение различия можно найти на эта страница
Поле может быть присвоено классу или экземпляру класса. По умолчанию поля являются переменными экземпляра. При использовании static поле становится переменной класса, поэтому существует один и только один clock. Если вы вносите изменения в одном месте, это видно везде. Переменные экземпляра изменяются независимо друг от друга.
Это обсуждение до сих пор игнорировало соображения загрузчика классов. Строго говоря, статические поля Java используются всеми экземплярами класса для данного загрузчик классов.
Об этом упомянул Апокалисп в комментариях к ответу Мерхдада.
Хорошая точка зрения. Многие люди этого не знают, но как только вы начнете возиться с загрузчиками классов, это станет очень важным.
Все это правда, но это не дает ответа на вопрос. Его следовало опубликовать как комментарий.
Также можно подумать о статических членах, не имеющих указателя this. Они распределяются между всеми экземплярами.
Ключевое слово static в Java означает, что переменная или функция совместно используются всеми экземплярами этого класса, поскольку они принадлежат тип, а не самими объектами.
Итак, если у вас есть переменная: private static int i = 0;, и вы увеличиваете ее (i++) в одном экземпляре, изменение будет отражено во всех экземплярах. i теперь будет 1 во всех случаях.
Статические методы можно использовать без создания экземпляра объекта.
«Совместное использование между всеми экземплярами» создает неправильное впечатление, IMO - оно предполагает, что у вас делать должен быть экземпляр объекта.
(В то время как на самом деле экземпляры любой не нужны, потому что статическое поле и т. д. Принадлежит тип.)
@Jon Skeet static принадлежит типу, а не объекту? Подскажите поподробнее? Введите тип данных: int, double, ...?
@truongnm: введите как в классе, который объявляет переменную / метод.
Ключевое слово static означает, что что-то (поле, метод или вложенный класс) связано с тип, а не с каким-либо конкретным пример типа. Так, например, вы вызываете Math.sin(...) без какого-либо экземпляра класса Math, и действительно, вы не могу создаете экземпляр класса Math.
Для получения дополнительной информации см. соответствующий фрагмент Oracle Java Tutorial.
Примечание
Java, к сожалению, позволяет вы можете получить доступ к статическим членам, как если бы они были членами экземпляра, например.
// Bad code!
Thread.currentThread().sleep(5000);
someOtherThread.sleep(5000);
Это делает его смотрю так, как будто sleep является методом экземпляра, но на самом деле это статический метод - он всегда переводит текущий поток в спящий режим. Лучше всего прояснить это в вызывающем коде:
// Clearer
Thread.sleep(5000);
Другой пример: System.out.println () выглядит как метод класса, но на самом деле это метод экземпляра. Поскольку out является экземпляром PrintStream в классе System.
@LeslieCheung: Нет, для меня это не похоже на метод класса, поскольку System.out мне не нравится имя типа.
Я пристрастился к статическим методам (только по возможности) в "вспомогательных" классах.
Вызывающему классу не нужно создавать другую переменную-член (экземпляр) вспомогательного класса. Вы просто вызываете методы вспомогательного класса. Также улучшен вспомогательный класс, поскольку вам больше не нужен конструктор и не нужны переменные-члены (экземпляры).
Наверное, есть и другие преимущества.
Базовое использование статических членов ...
public class Hello
{
// value / method
public static String staticValue;
public String nonStaticValue;
}
class A
{
Hello hello = new Hello();
hello.staticValue = "abc";
hello.nonStaticValue = "xyz";
}
class B
{
Hello hello2 = new Hello(); // here staticValue = "abc"
hello2.staticValue; // will have value of "abc"
hello2.nonStaticValue; // will have value of null
}
Вот как вы можете иметь общие значения для всех членов класса, не отправляя экземпляр класса Hello другому классу. И при статике вам не нужно создавать экземпляр класса.
Hello hello = new Hello();
hello.staticValue = "abc";
Вы можете просто вызывать статические значения или методы по имени класса:
Hello.staticValue = "abc";
Ключевое слово static используется для обозначения поля или метода как принадлежащих самому классу, а не экземпляру. Используя ваш код, если объект Clock является статическим, все экземпляры класса Hello будут совместно использовать этот член данных (поле) Clock. Если вы сделаете его нестатичным, каждый отдельный экземпляр Hello может иметь уникальное поле Clock.
Вы добавили метод основной в свой класс Hello, чтобы можно было запустить код. Проблема в том, что метод основной является статическим и поэтому не может ссылаться на нестатические поля или методы внутри него. Вы можете решить эту проблему двумя способами:
Hello статическими, чтобы на них можно было ссылаться внутри метода основной. Это действительно не лучший вариант (или неправильная причина делать поле и / или метод статическими)Hello внутри основного метода и получите доступ ко всем его полям и методам так, как они были изначально задуманы.Для вас это означает следующее изменение вашего кода:
package hello;
public class Hello {
private Clock clock = new Clock();
public Clock getClock() {
return clock;
}
public static void main(String args[]) {
Hello hello = new Hello();
hello.getClock().sayTime();
}
}
main() - это статический метод, который имеет два основных ограничения:
this() и super() нельзя использовать в статическом контексте.
class A {
int a = 40; //non static
public static void main(String args[]) {
System.out.println(a);
}
}
Output: Compile Time Error
К статическим переменным можно получить доступ только в статических методах, поэтому, когда мы объявляем статические переменные, эти методы получения и установки будут статическими методами.
статические методы - это уровень класса, к которому мы можем получить доступ, используя имя класса
Ниже приведен пример методов получения и установки статических переменных:
public class Static
{
private static String owner;
private static int rent;
private String car;
public String getCar() {
return car;
}
public void setCar(String car) {
this.car = car;
}
public static int getRent() {
return rent;
}
public static void setRent(int rent) {
Static.rent = rent;
}
public static String getOwner() {
return owner;
}
public static void setOwner(String owner) {
Static.owner = owner;
}
}
В Java ключевое слово static можно рассматривать просто как указание на следующее:
"without regard or relationship to any particular instance"
Если вы подумаете о static таким образом, станет легче понять его использование в различных контекстах, в которых он встречается:
Поле static - это поле, которое принадлежит классу, а не какому-либо конкретному экземпляру.
Метод static - это метод, не имеющий понятия о this; он определен в классе и не знает ни о каком конкретном экземпляре этого класса, если ему не передана ссылка
Класс-член static - это вложенный класс без какого-либо представления или знания об экземпляре его включающего класса (если ему не передана ссылка на экземпляр включающего класса)
Статический в Java:
Статический - это модификатор без доступа. Ключевое слово static принадлежит классу, а не экземпляру класса. может использоваться для присоединения переменной или метода к классу.
Статическое ключевое слово МОЖЕТ использоваться с:
Методика
Переменная
Класс вложен в другой класс
Блок инициализации
НЕЛЬЗЯ использовать с:
Класс (не вложенный)
Конструктор
Интерфейсы
Метод Локальный внутренний класс (отличие от вложенного класса)
Методы внутреннего класса
Переменные экземпляра
Локальные переменные
Пример:
Представьте себе следующий пример, в котором переменная экземпляра с именем count увеличивается в конструкторе:
package pkg;
class StaticExample {
int count = 0;// will get memory when instance is created
StaticExample() {
count++;
System.out.println(count);
}
public static void main(String args[]) {
StaticExample c1 = new StaticExample();
StaticExample c2 = new StaticExample();
StaticExample c3 = new StaticExample();
}
}
Выход:
1 1 1
Поскольку переменная экземпляра получает память во время создания объекта, каждый объект будет иметь копию переменной экземпляра, если она увеличивается, она не будет отражаться на других объектах.
Теперь, если мы используем измените счетчик переменных экземпляра на статический, программа выдаст другой результат:
package pkg;
class StaticExample {
static int count = 0;// will get memory when instance is created
StaticExample() {
count++;
System.out.println(count);
}
public static void main(String args[]) {
StaticExample c1 = new StaticExample();
StaticExample c2 = new StaticExample();
StaticExample c3 = new StaticExample();
}
}
Выход:
1 2 3
В этом случае статическая переменная получит память только один раз, если какой-либо объект изменит значение статической переменной, он сохранит свое значение.
Статический с финалом:
Глобальная переменная, объявленная как окончательный и статический, остается неизменной на протяжении всего выполнения. Потому что статические члены хранятся в памяти классов и загружаются только один раз за все выполнение. Они общие для всех объектов класса. Если вы объявите статические переменные как final, ни один из объектов не сможет изменить свое значение, поскольку оно является окончательным. Поэтому переменные, объявленные как final и static, иногда называют константами. Все поля интерфейсов называются константами, поскольку по умолчанию они являются окончательными и статическими.
Ресурс изображения: Конечная статика
Понимание статических концепций
public class StaticPractise1 {
public static void main(String[] args) {
StaticPractise2 staticPractise2 = new StaticPractise2();
staticPractise2.printUddhav(); //true
StaticPractise2.printUddhav(); /* false, because printUddhav() is although inside StaticPractise2, but it is where exactly depends on PC program counter on runtime. */
StaticPractise2.printUddhavsStatic1(); //true
staticPractise2.printUddhavsStatic1(); /*false, because, when staticPractise2 is blueprinted, it tracks everything other than static things and it organizes in its own heap. So, class static methods, object can't reference */
}
}
Второй класс
public class StaticPractise2 {
public static void printUddhavsStatic1() {
System.out.println("Uddhav");
}
public void printUddhav() {
System.out.println("Uddhav");
}
}
//Here is an example
public class StaticClass
{
static int version;
public void printVersion() {
System.out.println(version);
}
}
public class MainClass
{
public static void main(String args[]) {
StaticClass staticVar1 = new StaticClass();
staticVar1.version = 10;
staticVar1.printVersion() // Output 10
StaticClass staticVar2 = new StaticClass();
staticVar2.printVersion() // Output 10
staticVar2.version = 20;
staticVar2.printVersion() // Output 20
staticVar1.printVersion() // Output 20
}
}
здесь был задан вопрос о выборе слова «статика» для этого понятия. Этот вопрос был обманут, но я не думаю, что этимология была четко рассмотрена. Так...
Это связано с повторным использованием ключевых слов, начиная с C.
Рассмотрим объявления данных в C (внутри тела функции):
void f() {
int foo = 1;
static int bar = 2;
:
}
Переменная foo создается в стеке при входе в функцию (и уничтожается при завершении функции). Напротив, бар присутствует всегда, поэтому он «статичен» в смысле обычного английского - он никуда не денется.
В Java и подобных языках используется та же концепция данных. Данные могут быть выделены для каждого экземпляра класса (для каждого объекта) или один раз для всего класса. Поскольку Java стремится иметь знакомый синтаксис для программистов C / C++, ключевое слово static здесь уместно.
class C {
int foo = 1;
static int bar = 2;
:
}
Наконец, мы подошли к методам.
class C {
int foo() { ... }
static int bar() { ... }
:
}
С концептуальной точки зрения существует экземпляр foo () для каждого экземпляра класса C. Существует только один экземпляр bar () для всего класса C. Это аналогично случаю, который мы обсуждали для данных, и, следовательно, с использованием 'static 'снова является разумным выбором, особенно если вы не хотите добавлять в свой язык больше зарезервированных ключевых слов.
Еще раз помните, что есть один экземпляр static на класс на CLASSLOADER.