10 заметок о модификаторе static в java

1 Знакомство с интерфейсами

Сегодня у вас прямо день знаний. Еще одна новая и интересная тема — это интерфейсы.

Интерфейс — это дитя Абстракции и Полиморфизма. Интерфейс очень напоминает абстрактный класс, у которого все методы абстрактные. Он объявляется так же, как и класс, только используется ключевое слово .

Вот несколько полезных фактов об интерфейсах:

1. Объявление интерфейса

  1. Вместо слова пишем .
  2. Содержит только абстрактные методы (слово писать не нужно)
  3. На самом деле у интерфейсов все методы –

2. Наследование интерфейсов

Интерфейс может наследоваться только от интерфейсов. Зато родителей у интерфейса может быть много. Еще говорят, что в Java есть множественное наследование интерфейсов. Примеры:

3. Наследование классов от интерфейсов

Класс может наследоваться от нескольких интерфейсов (и только от одного класса). При этом используется ключевое слово . Пример:

Класс ChessItem объявлен абстрактным: он реализовал все унаследованные методы, кроме . Т.е. класс содержит один абстрактный метод — .

Технически между словами и нет никакой разницы: и то, и то — это наследование. Так было сделано, чтобы повысить читабельность кода. В английском языке принято говорить, что классы наследуются (), а интерфейсы реализуются ()

4. Переменные

И самое важное: в интерфейсах нельзя объявлять переменные (хотя статические можно). А зачем же нужны интерфейсы? Когда их используют? У интерфейсов есть два сильных преимущества по сравнению с классами:

А зачем же нужны интерфейсы? Когда их используют? У интерфейсов есть два сильных преимущества по сравнению с классами:

3 Удаление и добавление модификатора static

Из статической в обычную

Что будет, если мы возьмем статическую переменную и превратим ее в обычную: удалим у нее модификатор ? Например, у переменной .

Измененный код будет выглядеть так:

А в памяти мы получим такую картину:

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

Из обычной в статическую

Можно сделать и наоборот: добавить перед обычными переменными класса модификатор , и тогда они исчезнут у всех объектов и появятся у статического объекта. Допустим, мы решили сделать переменные и статическими. Тогда код будет выглядеть так:

А в памяти мы получим уже такую картину:

Статический блок

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

// Java program to demonstrate the use of static blocks
import java.util.*;
public class BlockExample{
// static variable
static int j = 10;
static int n;

// static block
static {
System.out.println("Static block initialized.");
n = j * 8;
}

public static void main(String[] args)
{
System.out.println("Inside main method");
System.out.println("Value of j : "+j);
System.out.println("Value of n : "+n);
}
}

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

Вывод:

Static block initialized
Inside main method
Value of j:10
Value of n : 80

Статическая переменная

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

Теперь давайте разберемся с этим на примере.

// Java program demonstrate execution of static blocks and variables

import java.util.*;

public class VariableExample
{
// static variable
static int j = n();

// static block
static {
System.out.println("Inside the static block");
}

// static method
static int n() {
System.out.println("from n ");
return 20;
}

// static method(main !!)
public static void main(String[] args)
{
System.out.println("Value of j : "+j);
System.out.println("Inside main method");
}
}

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

Вывод:

from n
Inside the static block
Value of j: 20
Inside main method

Выделение памяти

Коротко о том, как происходит выделение памяти со стороны кода в фоновом режиме:

  • Каждый раз при создании объекта в Java он сохраняется в heap памяти.
  • Примитивы и локальные переменные хранятся в stack памяти, переменные-члены — в heap.
  • При многопоточности каждый поток имеет собственный stack, но находится в общей куче (heap). О многопоточности поговорим во второй части.
  • При вызове какого-либо метода все методы и переменные помещаются в stack. По завершении вызова указатель стека (stack) уменьшается.
  • 32-разрядная операционка тратит не более 4GB RAM на Java-приложения. В 64-разрядной затраты памяти на те же элементы увеличиваются вдвое.
  • Примитивный тип int тратит в 4 раза меньше памяти, чем Integer.

Графическое представление распределения памяти

Таблица ниже перечисляет различные типы данных и их диапазоны хранимых значений:


Типы данных и диапазоны значений

Синтаксис

static final datatype identifier_name = constant;
  • Модификатор static делает переменную доступной без загрузки экземпляра ее определяющего класса.
  • Последний модификатор делает переменную неизменной.

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

  • Когда мы объявим переменную «var» только как статическую, все объекты одного класса смогут получить доступ к этому ‘var’ и изменить его значения.
  • Когда мы объявляем переменную только как final, для каждого отдельного объекта будет создано несколько экземпляров одного и того же значения константы, и это неэффективно / нежелательно.
  • Когда мы используем как static, так и final, тогда «var» остается статичным и может быть инициализирован только один раз, что делает его надлежащей константой, которая имеет общую ячейку памяти для всех объектов своего содержащего класса.

Пример

static final int MIN_AGE = 18;

Допустим, нам нужно определить, кто имеет право на получение постоянных водительских прав в группе людей. Мы уже знаем, что минимальный возраст для получения постоянных водительских прав составляет 18 лет.

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

import java.util.*;
public class DrivingLicense{
     public static void main(String [] args){
          Scanner sc = new Scanner(System.in);
          static final int MIN_AGE = 18; //Minimum age requirement
          int[] list = new int;
          System.out.println("Enter the age of people:");
          for(int i=0;i<5;i++){
                list = sc.nextInt();
          }
          System.out.println("Result for eligibility:");
          for(int i=0;i<5;i++) { 
          if(list >= MIN_AGE)
                System.out.println(i + " is Eligible");
          else
                System.out.println(i + " is Not Eligible");
          }
     }
}

Вывод:

Зачем нужны?

Константы делают вашу программу более легкой для чтения и понимания, когда ее читают другие. Использование их также повышает производительность, поскольку константы кэшируются как JVM, так и вашим приложением.

3 Особенности статических классов

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

Если вы работаете с внутренним статическим классом внутри его класса-родителя, вообще не заметите никакой разницы с тем, если бы этот внутренний класс был бы самым обычным классом (не вложенным и не статическим).

Пример:

Внутренний статический класс Point Обычный класс Point

Если вы возьмете какой-то вложенный статический класс и вынесете его из его класса родителя, все, что изменится, так это то, что новый класс потеряет способность обращаться к переменным и методам бывшего класса-родителя.

Пример:

Внутренний статический класс Point Обычный класс Point

Метод в обычном классе не может обращаться к переменной класса !

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

Ну а если разобраться, что тут удивительного? Модификатор прямо говорит, что к переменным и методам, обозначенным этим модификатором, можно обращаться только изнутри их класса. Внутренний статический класс находится внутри класса-родителя? Да, тогда никаких проблем: обращайтесь сколько хотите.

3 Тип String

Тип позволяет хранить текстовые строки.

Чтобы задать какую-то текстовую строку, в Java надо написать текст строки, а с обеих сторон поставить двойные кавычки. Пример:

Код Пояснение
будет содержать текст
будет содержать текст
будет содержать текст

Выглядит несложно, правда? Ну если так, тогда вот еще один интересный факт.

Строки в Java можно склеивать с помощью знака плюс — . Пример:

Код Пояснение
будет содержать
будет содержать пустую строку — вообще без символов.
будет содержать

Обратите внимание на последний пример: мы сложили строку и число. Тут тоже все просто: число будет преобразовано в строку, затем две строки будут склеены

При сложении строк и чисел, всегда получается строка.

Абстрактный класс и интерфейс

  • В интерфейсе отсутствует код реализации, а все методы являются абстрактными. То есть, все методы объявляются, но ни один не определяется.
  • В абстрактном классе есть исполняемые и абстрактные методы.
  • Класс реализует сколько угодно интерфейсов, но расширяет только один абстрактный класс.
  • Методы абстрактного класса могут быть или не быть абстрактными.
  • Абстрактный класс не может превратиться в экземпляр, но может стать подклассом.
  • Все абстрактные методы должны определяться в подклассе, то есть, подкласс является абстрактным.
  • Создавать экземпляры из интерфейса нельзя. Их можно реализовывать в других классах или расширять другими интерфейсами.
  • Переменные интерфейсов конечные и статические. По умолчанию, все методы интерфейса публичные и абстрактные.
  • Интерфейс не может содержать реализацию и не может превращаться в подкласс. Все переменные должны быть постоянными.

Обычный внутренний класс

Внутренний класс определяется в области действия внешнего класса.

Чтобы создать объект внутреннего класса, должен существовать объект внешнего класса.

Внутренний и внешний класс имеют доступ ко всем членам класса друг друга (даже ).

Следующий пример демонстрирует объявление обычного внутреннего класса:

Внутри метода внешнего класса, объект внутреннего класса создается как обычно:

Если мы создаем объект внутреннего класса не в методах внешнего класса или в статических методах внешнего класса, необходимо использовать объект внешнего класса:

или

Если необходимо получить ссылку на внутренний класс во внутреннем классе, используем слово :

Если необходимо получить ссылку на объект внешнего класса, запишите имя внешнего класса, за которым следует точка, а затем ключевое слово :

Обычный внутренний класс является таким же членом внешнего класса, как и переменные и методы. Следующие модификаторы могут быть применены к обычному внутреннему классу:

  • – но преобразует его во вложенный класс

Если метод описан как (явно либо неявно), то JVM гарантирует, что результаты вычисления выражений с и в пределах метода будут одинаковыми на всех платформах. Модификатор для класса и интерфейса указывает на то, что все методы класса/интерфейса будут .

Static Variables

In Java, when we create objects of a class, then every object will have its own copy of all the variables of the class. For example,

Here, both the objects test1 and test2 will have separate copies of the variable age. And, they are different from each other.

However, if we declare a variable static, all objects of the class share the same static variable. It is because like static methods, static variables are also associated with the class. And, we don’t need to create objects of the class to access the static variables. For example,

Here, we can see that we are accessing the static variable from the other class using the class name.

Example 2: Java static and non-static Variables

Output:

min + 1 = 6
max + 1 = 11

In the above program, we have declared a non-static variable named min and a static variable named max inside the class Test.

Inside the Main class, we can see that we are calling the non-static variable using the object of the class (). However, we are calling the static variable by using the class name ().

Note: Static variables are rarely used in Java. Instead, the static constants are used. These static constants are defined by keyword and represented in uppercase. This is why some people prefer to use uppercase for static variables as well.

Интерфейсы и наследование

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

public interface MySuperInterface {

    public void saiHello();

}
public interface MySubInterface extends MySuperInterface {

    public void sayGoodbye();
}

MySubInterface расширяет MySuperInterface. Это означает, что MySubInterface наследует все поля и методы от MySuperInterface. Это означает, что если класс реализует MySubInterface, этот класс должен реализовать все методы, определенные как в MySubInterface, так и в MySuperInterface.

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

Вот пример интерфейса Java, который наследуется от нескольких интерфейсов:

public interface MySubInterface extends
    SuperInterface1, SuperInterface2 {

    public void sayItAll();
}

Как и при реализации нескольких интерфейсов, не существует правил для того, как вы обрабатываете ситуацию, когда несколько суперинтерфейсов имеют методы с одинаковой сигнатурой(имя + параметры).

4 Статические переменные

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

В 11-м уровне мы разберем устройство статических переменных и методов и поймем причины таких ограничений.

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

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

Пример:

Код Доступность переменных

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

Статические и окончательные модификаторы

  • Статический модификатор в основном используется для управления памятью.
  • Это также позволяет переменной быть доступной без загрузки какого-либо экземпляра класса, в котором она определена.
  • Последний модификатор означает, что значение переменной не может измениться. Как только значение назначено переменной, другое значение не может быть переназначено той же переменной.

С помощью модификатора final типы данных Primitive, такие как int, float, char, byte, long, short, double, Boolean, можно сделать неизменяемыми / неизменяемыми. Вместе, как мы поняли ранее, эти модификаторы создают постоянную переменную.

Примитивы и оболочки типов

Переменная примитивного типа всегда содержит его значение. В Java существует 8 примитивных типов: , , , , , ,  and .

Класс-оболочка — это класс, объект которого оборачивает или содержит примитивные типы данных. При создании объекта в классе-оболочкепоявляется поле для хранения примитивных типов данных, а также других поддерживающих и операционных методов. Если использовать не сами примитивы, а Object-оболочки для примитивных типов данных, то процесс выполняется медленнее. Дополнительные ресурсы тратятся на создание экземпляра объекта, вызовы методов и т.д. За каждым из этих примитивных типов закреплен свой класс: Byte, Short, Integer, Long, String, Boolean, Float и Double.

Методы по умолчанию в интерфейсах

В JDK 8 в интерфейсы ввели методы по умолчанию — это методы, у которых есть реализация. Другое их название — методы расширения. Классы, реализующие интерфейсы, не обязаны переопределять такие методы, но могут если это необходимо. Методы по умолчанию определяются с ключевым словом .

Интерфейс объявляет метод по умолчанию с базовой реализацией:

Класс , реализующий этот интерфейс, не переопределяет метод — так можно. 

А если класс не устраивает реализация по умолчанию, он переопределяет этот метод: 

Создаем два объекта классов и , и вызываем для каждого метод . Для объекта класса  вызовется метод, реализованный в интерфейсе, а для объекта класса — его собственная реализация:

Результат выполнения:

Java Static переменная

Статическая переменная — это та, которая связана с классом, а не с экземпляром (объектом) этого класса. Они инициализируются только один раз, в начале выполнения. Единый экземпляр, который будет использоваться всеми экземплярами класса, и к нему можно получить доступ непосредственно по имени класса и не нуждается в каком-либо объекте. Одним из распространенных применений static является создание постоянного значения, которое привязано к классу.

Например, если у вас есть переменная: private static int stc = 0; и вы увеличиваете его (stc ++) в одном экземпляре, это изменение будет отражено во всех экземплярах. stc теперь будет 1 во всех случаях.

Синтаксис объявления поля

Синтаксис:

       type name  ;

Характеристика полей:

  1. Сначала модификатор доступа может быть объявлен для него. Он определяет, какие классы объектов могут получить доступ к полю. В приведенном выше примере Employee не было модификаторов доступа.
  2. Тип данных должен быть назначен. В приведенном выше примере Employee использовались типы данных String, int и Date.
  3. Может быть статическим. В Java статические поля принадлежат классу, а не экземплярам класса. Таким образом, все экземпляры любого класса будут иметь доступ к одной и той же переменной статического поля.
  4. Нестатическое значение может быть различным для каждого объекта (экземпляра) класса.
  5. Может быть объявлено как окончательное или нет. В первом случае не может изменить свое значение. Во-втором — должно иметь начальное значение, назначенное ему, и после установки значение не может быть изменено снова. Окончательное поле часто также объявляется статическим, объявляемым как static и final, также называемым «константой».
  6. Имеет имя. Вы можете выбрать это имя свободно, но есть некоторые ограничения на то, какие символы могут содержать имя.
  7. Можете при желании установить начальное значение для него.

Некоторые из приведенных выше вариантов более подробно описаны в следующих разделах.

Реализация

В следующем примере я реализовал несколько из рассмотренных выше методов.

package edureka;

import java.io.Console;
import java.lang.*;
import java.util.*;

public class SystemClassMethods {

	public static void main(String[] args) {
		String a[]= {"D","P","R","E","K","A"}; //source array  
        String b[]= {"E","D","U","V","O","I","D","L","E","A","R","N","I","N","G"};  //destination array  
        String src[],dest[];  
        
        int srcPos,destPos,length;
        src=a;
        srcPos=2;
        dest=b;
        destPos=3;
        length=4;
        
        System.out.print("Source array:"); 
        
        for(int i=0;i<src.length;i++) {System.out.print(a);}  
        System.out.println(); 
        
        System.out.print("Destination array:");         
        for(int i=0;i<dest.length;i++) {System.out.print(b);}  
        System.out.println();  
        System.out.println("Source Position:"+srcPos);  
        System.out.println("Destination Position:"+destPos);  
        System.out.println("Length:"+length);  
        System.arraycopy(src, srcPos, dest, destPos, length); //use of arraycopy() method 
        
        System.out.println("After Copying Destination Array: "); 
        for(int i=0;i<b.length;i++)  
        {
        	System.out.print(b);  
        }  
        System.out.println();
        
        
        System.out.println("---------Implementing NanoTime Method----------");
        System.out.println("Current time in nanoseconds = "+System.nanoTime());  

        
        System.out.println();
        System.out.println("---------Implementing getProperties() Method----------");
        System.out.println("Your System property for user");  
        Properties p = System.getProperties();  
        System.out.println(p.getProperty("user.name")); //property to get User's account name  
        System.out.println(p.getProperty("user.home")); //property to get User's home directory  
        System.out.println(p.getProperty("user.dir")); //property to get User's current working directory 
        
        System.out.println();
        System.out.println("---------Implementing console() Method----------");
        Console console = System.console();

        if(console != null){
            Calendar c = new GregorianCalendar();
            console.printf("Welcome %1$s%n", "Edureka"); 
            console.printf("Current time is: %1$tm %1$te,%1$tY%n", c); 
            console.flush();
        } else{
        	//No console is attached when executed in Eclipse
        	System.out.println("No Console attached");
        }
        
        System.out.println();
        System.out.println("---------Implementing getSecurityManager() Method----------");
        SecurityManager secManager = System.getSecurityManager();
        if(secManager == null){
        	System.out.println("SecurityManager is not configured");
        }
        SecurityManager mySecManager = new SecurityManager();
        
        System.setSecurityManager(mySecManager);
        secManager = System.getSecurityManager();
        if(secManager != null){
        	System.out.println("SecurityManager is now configured");
        }        
   }

}

Иерархии параметризованных классов

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

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

Например:

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

Общий синтаксис

public static final int MAX_VALUE = 1000;

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

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

Пример 1

public class ExampleSetOne {
     private static final int MAX=10;
     public static void main(String[] args){
           System.out.println("Final variable MAX="+MAX);
           ESO e = new ESO();
           e.printMAX();
     }
}
class ESO{
     private static final int MAX=20;
     void printMAX(){
          System.out.print("Final variable MAX changed="+MAX);
     }
}

Вывод:

Пример 2

public class ExampleSetTwo {
      public static final int MAX = 10;
      public static void main(String[] args) {
            printMAX();
            MAX = 20;
            printMAX();
      }
      void printMAX() {
            System.out.print("Final variable MAX changed=" + MAX);
      }
}

Вывод:

Разница между статическим вложенным классом и не статическим вложенным классом

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

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector