- Переменная и метод скрытия в Java
- 2. Скрытие переменных
- 2.1. Сила местного
- 2.2. Скрытие и иерархия
- 3. Метод скрытия
- 3.1. Скрытие метода против переопределения
- 4. Заключение
- Variable Shadowing and Hiding in Java
- What Is Variable Shadowing?
- What Is variable Hiding?
- Variable Hiding Is Not the Same as Method Overriding
Переменная и метод скрытия в Java
В этом руководствеwe’re going to learn about variable and method hiding in the Java language.
Во-первых, мы поймем концепцию и цель каждого из этих сценариев. После этого мы рассмотрим варианты использования и рассмотрим различные примеры.
2. Скрытие переменных
Скрытие переменной происходит, когда мы объявляем свойство в локальной области видимости, имя которого совпадает с именем, которое у нас уже есть во внешней области.
Прежде чем перейти к примерам, давайте кратко рассмотрим возможные области видимости переменных в Java. Мы можем определить их со следующими категориями:
- локальные переменные — объявлены в куске кода, такого как методы, конструкторы, в любом блоке кода с фигурными скобками
- переменные экземпляра — определены внутри класса и принадлежат экземпляру объекта
- class или переменныеstatic — объявляются в классе с ключевым словомstatic. У них есть область уровня класса.
Теперь давайте опишем скрытие на примерах для каждой отдельной категории переменных.
2.1. Сила местного
Давайте посмотрим на классHideVariable:
public class HideVariable < private String message = "this is instance variable"; HideVariable() < String message = "constructor local variable"; System.out.println(message); >public void printLocalVariable() < String message = "method local variable"; System.out.println(message); >public void printInstanceVariable() < String message = "method local variable"; System.out.println(this.message); >>
Здесь у нас есть переменнаяmessage , объявленная в 4 разных местах. Локальные переменные, объявленные внутри конструктора и двух методов, скрывают переменную экземпляра.
Давайте проверим инициализацию объекта и вызов методов:
HideVariable variable = new HideVariable(); variable.printLocalVariable(); variable.printInstanceVariable();
constructor local variable method local variable this is instance variable
Здесь первые 2 вызова извлекают локальные переменные.
Чтобы получить доступ к переменной экземпляра из локальной области, мы можем использовать ключевое словоthis, как показано в методеprintInstanceVariable().
2.2. Скрытие и иерархия
Точно так же, когда и дочерний, и родительский классы имеют переменную с одинаковым именем, дочерняя переменная скрывает переменную от родительского.
Предположим, у нас есть родительский класс:
public class ParentVariable < String instanceVariable = "parent variable"; public void printInstanceVariable() < System.out.println(instanceVariable); >>
После этого мы определяем дочерний класс:
public class ChildVariable extends ParentVariable < String instanceVariable = "child variable"; public void printInstanceVariable() < System.out.println(instanceVariable); >>
Чтобы проверить это, давайте инициализируем два экземпляра. Один с родительским классом, а другой с дочерним, затем вызовите методыprintInstanceVariable() для каждого из них:
ParentVariable parentVariable = new ParentVariable(); ParentVariable childVariable = new ChildVariable(); parentVariable.printInstanceVariable(); childVariable.printInstanceVariable();
Вывод показывает скрытие свойства:
parent variable child variable
In most cases, we should avoid creating variables with the same name both in parent and child classes. Вместо этого мы должны использовать соответствующий модификатор доступа, напримерprivate and, предоставляющий для этой цели методы получения / установки.
3. Метод скрытия
Скрытие метода может происходить в любой иерархической структуре в Java. Когда дочерний класс определяет статический метод с той же сигнатурой, что и статический метод в родительском классе, тогда дочерний методhidesявляется методом в родительском классе. Чтобы узнать больше о ключевом словеstatic,this write-up is a good place to start.
Такое же поведение, включающее методы экземпляра, называется переопределением метода. Чтобы узнать больше о переопределении метода, просмотрите нашguide here.
Теперь давайте посмотрим на этот практический пример:
public class BaseMethodClass < public static void printMessage() < System.out.println("base static method"); >>
BaseMethodClass имеет единственный методprintMessage() static.
Затем давайте создадим дочерний класс с той же сигнатурой, что и в базовом классе:
public class ChildMethodClass extends BaseMethodClass < public static void printMessage() < System.out.println("child static method"); >>
ChildMethodClass.printMessage();
Результат после вызова методаprintMessage():
ChildMethodClass.printMessage() скрывает метод вBaseMethodClass.
3.1. Скрытие метода против переопределения
Скрытие не работает как переопределение, потому что статические методы не полиморфны. Переопределение происходит только с методами экземпляра. Он поддерживает позднюю привязку, поэтому какой метод будет вызываться, определяется во время выполнения.
On the other hand, method hiding works with static ones. Therefore it’s determined at compile time.
4. Заключение
In this article, we went over the concept of method and variable hiding in Java. Мы показали разные сценарии переменных скрытия и теневого копирования. Важной изюминкой статьи также является сравнение метода переопределения и сокрытия.
Как обычно, доступен полный кодover on GitHub.
Variable Shadowing and Hiding in Java
Join the DZone community and get the full member experience.
Java allows us to declare a variable whenever we need it. We can categorize all our variables into three categories, which have different-different scopes:
- Instance variables: defined inside a class and have object-level scope.
- Class variables: defined inside a class with the static keyword. They have class-level scope common to all objects of the same class.
- Local variables: defined inside a method or in any conditional block. They have block-level scope and are only accessible in the block where they are defined.
What Is Variable Shadowing?
Variable shadowing happens when we define a variable in a closure scope with a variable name that is the same as one for a variable we’ve already defined in an outer scope.
In other words, when a local variable has the same name as one of the instance variables, the local variable shadows the instance variable inside the method block.
In the following example, there is an instance variable named x , and inside method printLocalVariable() , we are shadowing it with the local variable x .
class Parent < // Declaring instance variable with name `x` String x = "Parent`s Instance Variable"; public void printInstanceVariable() < System.out.println(x); >public void printLocalVariable() < // Shadowing instance variable `x` with a local variable with the same name String x = "Local Variable"; System.out.println(x); // If we still want to access the instance variable, we do that by using `this.x` System.out.println(this.x); >>
What Is variable Hiding?
Variable hiding happens when we define a variable in a child class with the same name as one we defined in the parent class. A child class can declare a variable with the same name as an inherited variable from its parent class, thus hiding the inherited variable.
In other words, when the child and parent classes both have a variable with the same name, the child class’ variable hides the parent class’ variable.
In the following example, we are hiding the variable named x in the child class while it is already defined by its parent class.
class Child extends Parent < // Hiding the Parent class's variable `x` by defining a variable in the child class with the same name. String x = "Child`s Instance Variable"; @Override public void printInstanceVariable() < System.out.print(x); // If we still want to access the variable from the super class, we do that by using `super.x` System.out.print(", " + super.x + "\n"); >>
Variable Hiding Is Not the Same as Method Overriding
While variable hiding looks like overriding a variable (similar to method overriding), it is not. Overriding is applicable only to methods while hiding is applicable to variables.
In the case of method overriding, overridden methods completely replace the inherited methods, so when we try to access the method from a parent’s reference by holding a child’s object, the method from the child class gets called. You can read more about overriding on Everything About Method Overloading vs Method Overriding, Why We Should Follow Method Overriding Rules, and How Does the JVM Handle Method Overloading and Overriding Internally.
But in variable hiding, the child class hides the inherited variables instead of replacing them, so when we try to access the variable from the parent’s reference by holding the child’s object, it will be accessed from the parent class.
When an instance variable in a subclass has the same name as an instance variable in a super class, then the instance variable is chosen from the reference type.
public static void main(String[] args) throws Exception < Parent parent = new Parent(); parent.printInstanceVariable(); // Output - "Parent's Instance Variable" System.out.println(parent.x); // Output - "Parent's Instance Variable" Child child = new Child(); child.printInstanceVariable();// Output - "Child's Instance Variable, Parent's Instance Variable" System.out.println(child.x);// Output - "Child's Instance Variable" parent = child; // Or parent = new Child(); parent.printInstanceVariable();// Output - "Child's Instance Variable, Parent's Instance Variable" System.out.println(parent.x);// Output - Parent's Instance Variable // Accessing child's variable from parent's reference by type casting System.out.println(((Child) parent).x);// Output - "Child's Instance Variable" >
In above example, when we call the overridden method printInstanceVariable()onparent while holding the child’s object in it, we can see the output is:
Child’s Instance Variable, Parent’s Instance Variable
Because in the child class, the method is printing the child class’ x variable and super.x .
But when we call System.out.println(parent.variable); on the same parent reference that is holding the child’s object, it prints Parent’s Instance Variable because the new Child() object keeps the parent’s x as well as the child’s x and hides the parent’s x . So, in this case, x is chosen from the class that is the reference type.
But if we wanted to access the child’s variable even if we are using a parent reference, we can do that by using (Child) parent).variable .
When our variables are private or in another package and have default access, such variables are not visible outside of that class, and the child class cannot access them. So there no confusion — and that is why we should always stick to General Guidelines to create POJOs and declare our variables with private access (and also provide proper get/set methods to access them).
Do you want to know more about variable hiding?, In the article Why Instance Variable Of Super Class Is Not Overridden In SubClass, I have discussed why variables do not follow overriding, why variable hiding is not designed same as method overriding and why instance variable is chosen from reference type instead of the object? Please go ahead and read it.
You can find the complete code on this GitHub Repository and please feel free to provide your valuable feedback.
Published at DZone with permission of Naresh Joshi , DZone MVB . See the original article here.
Opinions expressed by DZone contributors are their own.