Campos estáticos
Quando denotamos uma variável em nível de classe, indicamos que o valor pertence a uma classe. Se você não fizer isso, o valor da variável será vinculado a um objeto criado usando esta classe. O que isso significa? E o fato é que se a variável não for estática, então cada novo objeto desta classe terá seu próprio valor desta variável, alterando o qual a alteramos exclusivamente em um objeto: Por exemplo, temos uma classe Car com um não -variável estática:public class Car {
int km;
}
Então no principal:
Car orangeCar = new Car();
orangeCar.km = 100;
Car blueCar = new Car();
blueCar.km = 85;
System.out.println("Orange car - " + orangeCar.km);
System.out.println("Blue car - " + blueCar.km);
A saída que obtemos é:
Orange car - 100
Blue car - 85
Como você pode ver, cada objeto possui sua própria variável, cuja alteração ocorre apenas para este objeto. Bom, se tivermos uma variável estática, então esse valor global é o mesmo para todos: Agora temos um Carro com uma variável estática:
public class Car {
static int km;
}
Então o mesmo código em main será enviado para o console:
Orange car - 85
Blue car - 85
Afinal, temos uma variável para todos nós e sempre a alteramos. Variáveis estáticas geralmente são acessadas não por uma referência de objeto - orangeCar.km, mas pelo nome da classe - Car.km
Bloco estático
Existem dois blocos de inicialização – regular e estático. O bloco destina-se a inicializar variáveis internas. Se o bloco for normal, as variáveis internas do objeto serão inicializadas com ele, mas se for estático, as variáveis estáticas (ou seja, variáveis de classe) serão atribuídas a eles. Exemplo de classe com bloco de inicialização estático:public class Car {
static int km;
static {
km = 150;
}
}
Método estático
Os métodos estáticos diferem dos métodos regulares porque também estão vinculados a uma classe em vez de a um objeto. Uma propriedade importante de um método estático é que ele só pode acessar variáveis/métodos estáticos. Como exemplo, vejamos uma classe que será uma espécie de contador que monitora as chamadas de métodos:public class Counter {
static int count;
public static void invokeCounter() {
count++;
System.out.println("Current counter value - " + count);
}
}
Vamos chamá-lo em main:
Counter.invokeCounter();
Counter.invokeCounter();
Counter.invokeCounter();
E obtemos a saída para o console:
Текущее meaning счётчика - 1
Текущее meaning счётчика - 2
Текущее meaning счётчика - 3
Classe estática em Java
Somente uma classe interna pode ser uma classe estática. Novamente, esta classe está vinculada à classe externa e, se a classe externa for herdada por outra classe, esta não será herdada. Além disso, esta classe pode ser herdada, assim como pode ser herdada de qualquer outra classe e implementar uma interface. Essencialmente, uma classe aninhada estática não é diferente de qualquer outra classe interna, exceto que seu objeto não contém uma referência ao objeto da classe externa que a criou. No entanto, isso torna uma classe estática mais semelhante a uma classe normal não aninhada, porque a única diferença é que ela está agrupada em outra classe. Em alguns casos, isso é uma vantagem para nós, pois a partir dele temos acesso às variáveis estáticas privadas da classe externa. Exemplo de uma classe estática aninhada:public class Vehicle {
public static class Car {
public int km;
}
}
Criando uma instância desta classe e definindo o valor da variável interna:
Vehicle.Car car = new Vehicle.Car();
car.km = 90;
Para usar métodos/variáveis/classes estáticas, não precisamos criar um objeto dessa classe. É claro que os modificadores de acesso devem ser levados em consideração. Por exemplo, os campos private
só são acessíveis dentro da classe em que são declarados. Os campos protected
estão disponíveis para todas as classes dentro de um pacote ( package ), bem como para todas as classes herdeiras fora do pacote. Para mais detalhes, confira o artigo “ privado vs protegido vs público ”. Suponha que exista um método estático increment()
na classe Counter
cuja tarefa seja incrementar o contador count
. Para chamar esse método, você pode usar uma invocação no formato Counter.increment()
. Não há necessidade de instanciar uma classe Counter
para acessar um campo ou método estático. Esta é a diferença fundamental entre objetos estáticos e não estáticos (membros da classe). Deixe-me lembrá-lo mais uma vez que os membros da classe estática pertencem diretamente à classe, não à sua instância. Ou seja, o valor de uma variável estática count
será o mesmo para todos os objetos do tipo Counter
. Posteriormente neste artigo, veremos os aspectos fundamentais do uso do modificador estático em Java, bem como alguns recursos que o ajudarão a compreender os principais conceitos de programação.
O que todo programador deve saber sobre o modificador Static em Java
Nesta seção, veremos os fundamentos do uso de métodos, campos e classes estáticos. Vamos começar com as variáveis.-
Você NÃO pode acessar membros não estáticos de uma classe dentro de um contexto estático, como um método ou bloco. Compilar o código abaixo resultará em um erro:
public class Counter{ private int count; public static void main(String args[]){ System.out.println(count); //compile time error }}
Este é um dos erros mais comuns cometidos por programadores Java, especialmente iniciantes. Como o método
main
é estático, mas a variávelcount
não, neste caso o métodoprintln
dentro do métodomain
gerará “Erro de tempo de compilação”. -
В отличие от локальных переменных, статические поля и методы НЕ потокобезопасны (Thread-safe) в Java. На практике это одна из наиболее частых причин возникновения проблем связанных с безопасностью мультипоточного программирования. Учитывая что каждый экземпляр класса имеет одну и ту же копию статической переменной, то такая переменная нуждается в защите — «залочивании» классом. Поэтому при использовании статических переменных, убедитесь, что они должным образом синхронизированы (synchronized), во избежание проблем, например таких How «состояние гонки» (race condition).
-
Статические методы имеют преимущество в применении, т.к. отсутствует необходимость каждый раз создавать новый an object для доступа к таким методам. Статический метод можно вызвать, используя тип класса, в котором эти методы описаны. Именно поэтому, подобные методы How нельзя лучше подходят в качестве методов-фабрик (
factory
), и методов-утorт (utility
). Классjava.lang.Math
— замечательный пример, в котором почти все методы статичны, по этой же причине классы-утorты в Java финализированы (final
). -
Другим важным моментом является то, что вы НЕ можете переопределять (
Override
) статические методы. Если вы объявите такой же метод в классе-наследнике (subclass
), т.е. метод с таким же именем и сигнатурой, вы лишь «спрячете» метод суперкласса (superclass
) instead of переопределения. Это явление известно How сокрытие методов (hiding methods
). Это означает, что при обращении к статическому методу, который объявлен How в родительском, так и в дочернем классе, во время компиляции всегда будет вызван метод исходя из типа переменной. В отличие от переопределения, такие методы не будут выполнены во время работы программы. Рассмотрим пример:class Vehicle{ public static void kmToMiles(int km){ System.out.println("Inside parent class/static method"); } } class Car extends Vehicle{ public static void kmToMiles(int km){ System.out.println("Inside child class/static method "); } } public class Demo{ public static void main(String args[]){ Vehicle v = new Car(); v.kmToMiles(10); }}
Вывод в консоль:
Внутри родительского класса/статического метода
Код наглядно демонстрирует: несмотря на то, что an object имеет тип
Car
, вызван статический метод из классаVehicle
, т.к. произошло обращение к методу во время компиляции. И заметьте, ошибки во время компиляции не возникло! -
Объявить статическим также можно и класс, за исключением классов верхнего уровня. Такие классы известны How «вложенные статические классы» (
nested static class
). Они бывают полезными для представления улучшенных связей. Яркий пример вложенного статического класса —HashMap.Entry
, который предоставляет структуру данных внутриHashMap
. Стоит заметить, также How и любой другой внутренний класс, вложенные классы находятся в отдельном файле .class. Таким образом, если вы объявor пять вложенных классов в вашем главном классе, у вас будет 6 файлов с расширением .class. Ещё одним примером использования является объявление собственного компаратора (Comparator
), например компаратор по возрасту (AgeComparator
) в классе сотрудники (Employee
). -
Модификатор static также может быть объявлен в статичном блоке, более известным How «Статический блок инициализации» (
Static initializer block
), который будет выполнен во время загрузки класса. Если вы не объявите такой блок, то Java соберёт все статические поля в один список и выполнит его во время загрузки класса. Однако, статичный блок НЕ может пробросить перехваченные исключения, но может выбросить не перехваченные. В таком случае возникнет «Exception Initializer Error». На практике, любое исключение возникшее во время выполнения и инициализации статических полей, будет завёрнуто Java в эту ошибку. Это также самая частая причина ошибки «No Class Def Found Error», т.к. класс не находился в памяти во время обращения к нему. -
Полезно знать, что статические методы связываются во время компиляции, в отличие от связывания виртуальных or не статических методов, которые связываются во время исполнения на реальном an objectе. Следовательно, статические методы не могут быть переопределены в Java, т.к. полиморфизм во время выполнения не распространяется на них. Это важное ограничение, которое необходимо учитывать, объявляя метод статическим. В этом есть смысл, только тогда, когда нет возможности or необходимости переопределения такого метода классами-наследниками. Методы-фабрики и методы-утorты хорошие образцы применения модификатора static. Джошуа Блох выделил несколько преимуществ использования статичного метода-фабрики перед конструктором, в книге «Effective Java», которая является обязательной для прочтения каждым программистом данного языка.
-
Важным свойством статического блока является инициализация. Статические поля or переменные инициализируются после загрузки класса в память. Порядок инициализации сверху вниз, в том же порядке, в Howом они описаны в исходном файле Java класса. Поскольку статические поля инициализируются на потокобезопасный манер, это свойство также используется для реализации паттерна
Singleton
. Если вы не используется списокEnum
HowSingleton
, по тем or иным причинам, то для вас есть хорошая альтернатива. Но в таком случае необходимо учесть, что это не «ленивая» инициализация. Это означает, что статическое поле будет проинициализировано ещё ДО того How кто-нибудь об этом «попросит». Если an object ресурсоёмкий or редко используется, то инициализация его в статическом блоке сыграет не в вашу пользу. -
Durante a serialização, assim como
transient
as variáveis, os campos estáticos não são serializados. Na verdade, se você salvar quaisquer dados em um campo estático, após a desserialização o novo objeto conterá seu valor primário (padrão), por exemplo, se o campo estático for uma variável do tipoint
, então seu valor após a desserialização será zero, se o tipofloat
é 0,0, se tipoObject
–null
. Honestamente, esta é uma das perguntas mais frequentes sobre serialização em entrevistas Java. Não armazene os dados mais importantes sobre um objeto em um campo estático! -
E finalmente, vamos falar sobre
static import
. Este modificador tem muito em comum com o operador padrãoimport
, mas ao contrário dele, permite importar um ou todos os membros estáticos de uma classe. Ao importar métodos estáticos, eles podem ser acessados como se estivessem definidos na mesma classe, da mesma forma que ao importar campos, podemos acessá-los sem especificar o nome da classe. Este recurso foi introduzido no Java versão 1.5 e, quando usado corretamente, melhora a legibilidade do código. Esta construção é mais frequentemente encontrada em testes JUnit , porque Quase todos os desenvolvedores de testes usamstatic import
métodos assert, por exemplo,assertEquals()
e suas duplicatas sobrecarregadas. Se nada estiver claro, seja bem-vindo para obter informações adicionais .
GO TO FULL VERSION