To find out what the difference is between early (static) And late (dynamic) binding in Java, you need to first understand what it is tying . Linking means there is a connection between the link and the code. For example, a variable you reference is bound to the code in which it is defined. Likewise, the method being called is bound to the location in the code where it is defined.

There are two types of method binding in the Java language: early binding (also called static) and late binding (respectively, dynamic) tying . Calling a method in Java means that the method is bound to specific code, either at compile time or at run time, when the program runs and objects are created. As the name suggests, static linking is more static in nature as it happens at compile time, meaning the code “knows” which method to call after compiling the Java source code into class files. And since this refers to the early stage of the program's life cycle, it is also called early binding. On the other hand, dynamic linking occurs at runtime, after the program is run by the Java Virtual Machine. In this case, which method to call is determined by the specific object, so the information is not available at compile time because objects are created at run time. And since this happens late in the program's life cycle, it is called late binding in Java. Let's look at a few more differences to understand this better and also be able to answer this very popular question asked in Java interviews.

Early and Late Binding in Java

There are many differences between static and dynamic binding in Java, but the most important is how the JVM uses them. Have you ever wondered how the JVM decides which method to call when there is more than one method with the same name in scope? If you've ever used method overloading or overriding, you know that in Java you can have multiple methods with the same name. In the case of Java virtual machine The JVM uses both static and dynamic binding to select the desired method.

Example of static and dynamic binding in Java

In this program, you will see that binding of virtual methods does not occur at compile time using static binding, since this would call a method from the superclass, as happens with static methods that are bound early. If a method from a subclass is called, a specific object was used to bind the function at runtime, and hence dynamic binding is used to bind virtual functions. public class Main ( public static void main (String args) ( // Example of static and dynamic binding in Java Insurance current = new CarInsurance () ; // Dynamic object based binding int premium = current. premium(); // Static binding based on class String category = current. category(); System. out. println("premium: " + premium); System. out. println("category: " + category) ; ) ) class Insurance ( public static final int LOW = 100 ; public int premium () ( return LOW; ) public static String category () ( return "Insurance" ; ) ) class CarInsurance extends Insurance ( public static final int HIGH = 200 ; public int premium () ( return HIGH; ) public static String category () ( return "Car Insurance" ; ) ) Execution results: premium : 200 category : Insurance As you can see, calling the premium() method resulted in the execution of a method from the subclass, while calling the category() method resulted in the execution of the superclass method. This is because premium() is a virtual method that is resolved by late binding, while category() is a static method that is resolved by compile-time static binding on the class name.
Interested in reading about Java? Join the group!

Differences between early and late binding in Java

Now that you've got the hang of it and understand how Java binds method calls and how static and dynamic binding works, let's recap the key differences between early and late binding in Java:
  1. Static linking occurs at compile time, while dynamic linking occurs at run time.

  2. Because static linking occurs early in a program's life cycle, it is called early binding. Likewise, dynamic binding is also called late binding because it occurs later in the program's execution.

  3. Static binding is used in Java language to resolve overloaded methods while dynamic binding is used in Java language to resolve overridden methods.

  4. Likewise, private, static, and terminal methods are resolved using static binding because they cannot be overridden, while all virtual methods are resolved using dynamic binding.

  5. In the case of static binding, it is not concrete objects that are used, but type information, that is, the type of the reference variable is used to discover the desired method. On the other hand, dynamic binding uses a specific object to find the desired method in Java.
Here's a good exercise based on the concepts of static and dynamic binding in Java. Can you answer the question: "What will be output when the following program is executed?" What will this program output? Collection, Set or HashSet? That's all we wanted to tell you about the differences between early (static) And late (dynamic) binding in Java. This is one of the best Java phone interview questions because it provides quite a few opportunities to test the candidate's depth of knowledge. Always remember that private , static And final methods communicate using static binding , A virtual – dynamic . Likewise, the best example of static binding is method overloading, while overriding is dynamic.

Mar 23, 2010 dec5e

In PHP 5.3 this appeared interesting opportunity, like late static binding. What follows is a slightly free translation of the description from the official manual.

Since PHP 5.3.0, the language has introduced a feature called late static binding, which can be used to reference a callable class in the context of static inheritance.

This feature was called "late static binding". "Late binding" means that static:: will not be resolved relative to the class where the method is defined, but will be evaluated at runtime. "Static binding" means it can be used in calls static methods(but not limited to them only).

Limitations self::

Example #1: Using self::

The example will output:

Using Late Static Binding

Later static linking attempts to solve this limitation by introducing keyword, which refers to the class originally called during execution. That is, a keyword that will allow B to be referenced from test() in the previous example. It was decided not to introduce a new word, but to use the already reserved static .

Example #2: Simple use of static::

The example will output:

Note: static:: does not work like $this for static methods! $this-> follows inheritance rules, but static:: does not. This distinction is clarified below.

Example #3: Using static:: in a non-static context

test(); ?>

The example will output:

Note: Late static binding stops the call resolution process. Static calls using the parent:: or self:: keywords pass on the call information.

Example #4: Transferring and not transferring calls

The example will output

Edge Cases

There are many in various ways call a method in PHP, such as callbacks or magic methods. Because late static binding is resolved at runtime, this can lead to unexpected results in so-called edge cases.

Example #5 Late static binding in magic methods

foo; ?>

This paragraph, despite its brevity, is very important - almost all professional programming in Java it is based on the use of polymorphism. At the same time, this topic is one of the most difficult for students to understand. Therefore, it is recommended to carefully re-read this paragraph several times.

Class methods are marked with the static modifier for a reason - for them, when compiling the program code, static linking. This means that in the context of which class the method name is specified in the source code, the link is placed to the method of that class in the compiled code. That is, it is carried out method name binding at the place of call with executable code this method. Sometimes static linking called early binding, since it occurs at the compilation stage of the program. Static linking in Java it is used in one more case - when a class is declared with the final modifier (“final”, “final”).

Object methods in Java are dynamic, that is, they are subject to dynamic linking. It occurs at the stage of program execution directly during a method call, and at the stage of writing this method it is not known in advance from which class the call will be made. This is determined by the type of object for which this code works - which class the object belongs to, from which class the method is called. This binding occurs long after the method code has been compiled. Therefore, this type of binding is often called late binding.

Call-based programming code dynamic methods, has the property polymorphism– the same code works differently depending on what type of object calls it, but does the same things at the level of abstraction related to source code method.

To explain these words, which are not very clear at first reading, let’s consider the example from the previous paragraph - the work of the moveTo method. Inexperienced programmers think that this method should be overridden in every descendant class. This can actually be done, and everything will work correctly. But such code will be extremely redundant - after all, the implementation of the method will be in all descendant classes Figure exactly the same:

public void moveTo(int x, int y)( hide(); this.x=x; this.y=y; show(); );

Moreover, this case does not take advantage of polymorphism. So we won't do that.

It is also often puzzling why abstract class Figure write an implementation of this method. After all, the calls to the hide and show methods used in it, at first glance, should be calls abstract methods– that is, they seem to be unable to work at all!

But the hide and show methods are dynamic, which, as we already know, means that the association of the method name and its executable code is done at the program execution stage. Therefore, the fact that these methods are specified in the class context Figure, does not mean that they will be called from the class Figure! Moreover, you can guarantee that the hide and show methods will never be called from this class. Let us have variables dot1 of type Dot and circle1 of type Circle , and they are assigned references to objects of the corresponding types. Let's look at how the dot1.moveTo(x1,y1) and circle1.moveTo(x2,y2) calls behave.

When dot1.moveTo(x1,y1) is called, a call occurs from the class Figure moveTo method. Indeed, this method in the Dot class is not overridden, which means it is inherited from Figure. In the moveTo method, the first statement is a call to the dynamic hide method. The implementation of this method is taken from the class of which the dot1 object calling this method is an instance. That is, from the Dot class. Thus, the point is hidden. Then the coordinates of the object are changed, after which it is called dynamic method show. The implementation of this method is taken from the class of which the dot1 object calling this method is an instance. That is, from the Dot class. Thus, a dot is shown at the new location.

For calling circle1.moveTo(x2,y2) everything is absolutely similar - the dynamic methods hide and show are called from the class of which the circle1 object is an instance, that is, from the Circle class. Thus, it is the circle that is hidden in the old place and shown in the new one.

That is, if the object is a point, the point moves. And if the object is a circle, the circle moves. Moreover, if someday someone writes, for example, an Ellipse class that is a descendant of Circle and creates an object Ellipse ellipse=new Ellipse(…), then calling ellipse.moveTo(…) will move the ellipse to a new location. And this will happen in accordance with the way the hide and show methods are implemented in the Ellipse class. Note that the compiled polymorphic code of the class will work a long time ago Figure. Polymorphism is ensured by the fact that references to these methods are not placed in the code of the moveTo method at compile time - they are configured to methods with such names from the class of the calling object immediately at the time the moveTo method is called.

There are two types of object-oriented programming languages: dynamic methods– actually dynamic and virtual. According to the principle of operation, they are completely similar and differ only in the implementation features. Call virtual methods faster. Calling dynamic ones is slower, but the service table dynamic methods(DMT – Dynamic Methods Table) takes up slightly less memory than a table virtual methods(VMT – Virtual Methods Table).

It may seem like a challenge dynamic methods is not time efficient due to the length of time it takes to search for names. In fact, no name lookup is done during the call, but a much faster mechanism is used using the mentioned table of virtual (dynamic) methods. But we will not dwell on the specifics of the implementation of these tables, since in Java there is no distinction between these types of methods.

6.8. Base class Object

The Object class is the base class for all Java classes. Therefore, all its fields and methods are inherited and contained in all classes. The Object class contains the following methods:

  • public Boolean equals(Object obj)– returns true in the case when the values ​​of the object from which the method is called and the object passed through the obj reference in the list of parameters are equal. If the objects are not equal, false is returned. In the Object class, equality is treated as reference equality and is equivalent to the comparison operator "==" . But in descendants this method can be overridden, and can compare objects by their contents. For example, this happens for objects of shell numeric classes. This can be easily checked with code like this:

    Double d1=1.0,d2=1.0; System.out.println("d1==d2 ="+(d1==d2)); System.out.println("d1.equals(d2) ="+(d1.equals(d2)));

    The first line of output will give d1==d2 =false , and the second will give d1. equals(d2)=true

  • public int hashCode()– issues hash code object. A hash code is a conditionally unique numeric identifier associated with an element. For security reasons, you cannot give the object's address to an application program. Therefore, in Java, a hash code replaces the address of an object in cases where for some purpose it is necessary to store tables of object addresses.
  • protected Object clone() throws CloneNotSupportedException – the method copies an object and returns a link to the created clone (duplicate) of the object. In the descendants of the Object class, it is necessary to redefine it, and also indicate that the class implements the Clonable interface. Trying to call a method from a non-clonable object causes raising an exception CloneNotSupportedException("Clone is not supported"). Interfaces and exception situations will be discussed later.

    There are two types of cloning: shallow (shallow), when the values ​​of the fields of the original object are copied one-to-one into the clone, and deep (deep), in which new objects are created for fields of a reference type, cloning the objects to which the original fields refer. In shallow cloning, both the original and the clone will reference the same objects. If the object has fields only primitive types, there is no difference between shallow and deep cloning. The implementation of cloning is carried out by the programmer developing the class; there is no automatic cloning mechanism. And it is at the class development stage that you should decide which cloning option to choose. In the vast majority of cases it is required deep cloning.

  • public final Class getClass()– returns a reference to a metaobject of type class. With its help, you can obtain information about the class to which an object belongs and call its class methods and class fields.
  • protected void finalize() throws Throwable – called before the object is destroyed. Must be overridden in those descendants of Object in which it is necessary to perform some auxiliary actions before destroying the object (close a file, display a message, draw something on the screen, etc.). This method is described in more detail in the corresponding paragraph.
  • public String toString()– returns a string representation of the object (as adequately as possible). In the Object class, this method produces a string of the object's fully qualified name (with the package name), followed by an "@" character, and then a hexadecimal hash code of the object. Most standard classes override this method. For numeric classes, the string representation of the number is returned, for string classes – the contents of the string, for character classes – the character itself (and not the string representation of its code!). For example, the following code snippet

    Object obj=new Object(); System.out.println(" obj.toString() gives "+obj.toString()); Double d=new Double(1.0); System.out.println(" d.toString() gives "+d.toString()); Character c="A"; System.out.println("c.toString() gives "+c.toString());

    will provide a conclusion

    obj.toString() gives java.lang.Object@fa9cf d.toString() gives 1.0 c.toString() gives A

There are also methods notify(), notifyAll(), and several overloaded variants of the method wait, designed to work with threads. These are discussed in the section on threads.

6.9. Designers. Reserved words super and this. Initialization blocks

As already mentioned, objects in Java are created using the reserved word new, followed by a constructor - a special subroutine that creates an object and initializes the fields of the created object. The return type is not specified for it, and it is neither an object method (called through the class name when the object does not yet exist) nor a class method (the object and its fields are accessible in the constructor through the this reference). In fact, the constructor, in combination with the new operator, returns a reference to the object being created and can be considered a special type of method that combines the features of class methods and object methods.

If the object does not require any additional initialization when it is created, you can use the constructor, which is present by default for every class. This is the class name, followed by empty parentheses - without a list of parameters. There is no need to specify such a constructor when developing a class; it is present automatically.

If initialization is required, constructors with a list of parameters are usually used. We looked at examples of such constructors for the Dot and Circle classes. The Dot and Circle classes were inherited from abstract classes, in which there were no constructors. If there is inheritance from a non-abstract class, that is, one that already has a constructor (even a default constructor), some specificity arises. The first statement in a constructor must be a call to the constructor from the superclass. But it is done not through the name of this class, but using a reserved word super(from "superclass"), followed by the list of parameters required for the grandparent constructor. This constructor initializes the data fields that are inherited from the superclass (including from any earlier ancestors). For example, let's write a FilledCircle class - a descendant of Circle , an instance of which will be drawn as a colored circle.

package java_gui_example; import java.awt.*; public class FilledCircle extends Circle( /** Creates a new instance of FilledCircle */ public FilledCircle(Graphics g,Color bgColor, int r,Color color) ( super(g,bgColor,r); this.color=color; ) public void show())( Color oldC=graphics.getColor(); graphics.setColor(color); graphics.setXORMode(bgColor); graphics.fillOval (x,y,size,size); graphics.setColor(oldC); graphics.setPaintMode(); ) public void hide())( Color oldC=graphics.getColor(); graphics.setColor(color); graphics.setXORMode( bgColor); graphics.fillOval(x,y,size,size); graphics.setColor(oldC); graphics.setPaintMode();

In general, the logic for creating complex objects: the parent part of the object is created and initialized first, starting from the part inherited from the Object class, and further along the hierarchy, ending with the part belonging to the class itself. This is why usually the first constructor statement is a call to the grandparent constructor super ( parameter list), since accessing an uninitialized part of an object that belongs to the parent class can lead to unpredictable consequences.

In this class, we use a more advanced way of drawing and “hiding” shapes compared to previous classes. It is based on the XOR (exclusive or) drawing mode. This mode is set using the setXORMode method. In this case, repeated output of the figure to the same place leads to the restoration of the original image in the output area. The transition to normal painting mode is carried out using the setPaintMode method.

They are very often used in constructors

Binding- substitution of specific function calls into program codes - class methods. Only makes sense for derived classes.

Usually the compiler has the necessary information to determine which function is meant. For example, if a program encounters a call to obj.f(), the compiler uniquely selects the function f() depending on the type of the destination obj. If the program uses pointers to instances of the class:ptr->f(), the choice of function - class method is determined by the type of the pointer.

If function selection is done at compile time, we are dealing with static linking.

In this case, a function - a method of the base class - will be called for the pointer to the base class, even if the pointer to the base class is assigned the value of the address of the instance of the derived class.

If the function selection is performed at the program execution stage, we are dealing with dynamic linking.

In this case, if, during program execution, the pointer to the base class is assigned the address of an instance of the base class, the base class method will be called; If the pointer to the base class is assigned the address of an instance of the derived class, the method of the derived class will be called.

Virtual functions

By default, derived classes are statically linked. If dynamic binding is to be used for any class methods, such methods must be declared virtual .

Virtual functions:

    have the virtual keyword in the prototype in the base class;

    mandatory class member functions:

    All derived classes must have the same prototype (specifying the word virtual in derived classes is not necessary).

If any methods in derived classes have the same name as in the base class, but a different list of parameters, we have overloaded functions.

Example: Point and Circle classes.

virtual void print();

class Circle: public Point(

void print(); // you can virtual void print();

void Point::print()

cout<< "Point (" << x << ", " << y << ")";

void Circle::print()

cout<< "Circle with center in "; Point::print();

cout<< "and radius " << rad;

Usage:

Point p1(3,5), p2(1,1), *pPtr;

Cicle c1(1), c2(p2, 1);

pPtr = pPtr->print(); // get: Point (3, 5)

pPtr = pPtr->print(); // get:

Circle with center in Point (1, 1) and radius 1

Dynamic Binding Example: List

The most common use of dynamic binding is with container classes that contain a pointer to a base class; Such container classes can include information related to both the base and any derived classes.

Let's consider an example - a list containing both points and circles.

// constructor

Item():info(NULL), next(NULL)()

Item(Point *p):info(p), next(NULL)()

List():head(NULL)()

void insert(Point *p)(p->next = head; head = p;)

void List::print()

for(Item *cur = head; cur; cur = cur->next)(

cur->info->print();

cout<< endl;

Using the class:

Point *p = new Point(1,2);

mylist.insert(p);

p = new Cycle(1,2,1);

mylist.insert(p);

Circle with center in Point (1, 2) and radius 1

This paragraph, despite its brevity, is very important - almost all professional programming in Java is based on the use of polymorphism. At the same time, this topic is one of the most difficult for students to understand. Therefore, it is recommended to carefully re-read this paragraph several times.

Class methods are marked with the static modifier for a reason - for them, when compiling the program code, static linking. This means that in the context of which class the method name is indicated in the source code, a link is placed to the method of that class in the compiled code. That is, it is carried out method name binding at the place of call with executable code this method. Sometimes static linking is called early binding, since it occurs at the compilation stage of the program. Static binding in Java is used in one more case - when a class is declared with the final modifier (“final”, “final”),

Object methods in Java are dynamic, that is, they are subject to dynamic linking. It occurs at the stage of program execution directly during a method call, and at the stage of writing this method it is not known in advance from which class the call will be made. This is determined by the type of object for which this code works - which class the object belongs to, from which class the method is called. This binding occurs long after the method code has been compiled. Therefore, this type of binding is often called late binding.

Program code based on calling dynamic methods has the property polymorphism– the same code works differently depending on what type of object calls it, but does the same things at the level of abstraction related to the source code of the method.

To explain these words, which are not very clear at first reading, let’s consider the example from the previous paragraph - the work of the moveTo method. Inexperienced programmers think that this method should be overridden in every descendant class. This can actually be done, and everything will work correctly. But such code will be extremely redundant - after all, the implementation of the method will be exactly the same in all derived classes of Figure:

public void moveTo(int x, int y)(

Moreover, this case does not take advantage of polymorphism. So we won't do that.

It is also often puzzling why an implementation of this method should be written in the abstract Figure class. After all, the calls to the hide and show methods used in it, at first glance, should be calls to abstract methods - that is, it seems they cannot work at all!

But the hide and show methods are dynamic, which, as we already know, means that the association of the method name and its executable code is done at the program execution stage. Therefore, the fact that these methods are specified in the context of the Figure class does not mean that they will be called from the Figure class! Moreover, you can guarantee that the hide and show methods will never be called from this class. Let us have variables dot1 of type Dot and circle1 of type Circle, and they are assigned references to objects of the corresponding types. Let's look at how the dot1.moveTo(x1,y1) and circle1.moveTo(x2,y2) calls behave.

When dot1.moveTo(x1,y1) is called, the moveTo method is called from the Figure class. Indeed, this method in the Dot class is not overridden, which means it is inherited from Figure. In the moveTo method, the first statement is a call to the dynamic hide method. The implementation of this method is taken from the class of which the dot1 object calling this method is an instance. That is, from the Dot class. Thus, the point is hidden. Then the coordinates of the object are changed, after which the dynamic show method is called. The implementation of this method is taken from the class of which the dot1 object that calls this method is an instance. That is, from the Dot class. Thus, a dot is shown at the new location.

For calling circle1.moveTo(x2,y2) everything is absolutely similar - the dynamic methods hide and show are called from the class of which the circle1 object is an instance, that is, from the Circle class. Thus, it is the circle that is hidden in the old place and shown in the new one.

That is, if the object is a point, the point moves. And if the object is a circle, the circle moves. Moreover, if someday someone writes, for example, an Ellipse class that is a descendant of Circle, and creates an Ellipse object ellipse=new Ellipse(...), then calling ellipse.moveTo(...) will move the ellipse to a new location. And this will happen in accordance with the way the hide and show methods are implemented in the Ellipse class. Note that the polymorphic code of the Figure class that was compiled a long time ago will work. Polymorphism is ensured by the fact that references to these methods are not placed in the code of the moveTo method at compile time - they are configured to methods with such names from the class of the calling object immediately at the time the moveTo method is called.

In object-oriented programming languages, two types of dynamic methods are distinguished - actually dynamic and virtual. According to the principle of operation, they are completely similar and differ only in the implementation features. Calling virtual methods is faster. Calling dynamic ones is slower, but the Dynamic Methods Table (DMT) takes up slightly less memory than the Virtual Methods Table (VMT).

It may seem that calling dynamic methods is not time efficient due to the length of time it takes to look up names. In fact, no name lookup is done during the call, but a much faster mechanism is used using the mentioned table of virtual (dynamic) methods. But we will not dwell on the specifics of the implementation of these tables, since in Java there is no distinction between these types of methods.

Base class Object

The Object class is the base class for all Java classes. Therefore, all its fields and methods are inherited and contained in all classes. The Object class contains the following methods:

public Boolean equals(Object obj)– returns true in the case when the values ​​of the object from which the method is called and the object passed through the obj reference in the list of parameters are equal. If the objects are not equal, false is returned. In the Object class, equality is treated as reference equality and is equivalent to the “==” comparison operator. But in descendants this method can be overridden, and can compare objects by their contents. For example, this happens for objects of shell numeric classes. This can be easily checked with code like this:

Double d1=1.0,d2=1.0;

System.out.println("d1==d2 ="+(d1==d2));

System.out.println("d1.equals(d2) ="+(d1.equals(d2)));

The first line of output will give d1==d2 =false and the second d1.equals(d2) =true

public int hashCode()- issues hash code object. A hash code is a conditionally unique numeric identifier associated with an element. For security reasons, you cannot give the object's address to an application program. Therefore, in Java, a hash code replaces the address of an object in cases where for some purpose it is necessary to store tables of object addresses.

protected Object clone() throws CloneNotSupportedException– the method copies an object and returns a link to the created clone (duplicate) of the object. In the descendants of the Object class, it is necessary to redefine it, and also indicate that the class implements the Clonable interface. Attempting to call a method from an object that does not support cloning causes a CloneNotSupportedException to be thrown. Interfaces and exception situations will be discussed later.

There are two types of cloning: shallow (shallow), when the values ​​of the fields of the original object are copied one-to-one into the clone, and deep (deep), in which new objects are created for fields of a reference type, cloning the objects to which the original fields refer. In shallow cloning, both the original and the clone will reference the same objects. If an object has fields of only primitive types, there is no difference between shallow and deep cloning. The implementation of cloning is carried out by the programmer developing the class; there is no automatic cloning mechanism. And it is at the class development stage that you should decide which cloning option to choose. In the vast majority of cases, deep cloning is required.

public final Class getClass()– returns a reference to a metaobject of type class. With its help, you can obtain information about the class to which an object belongs and call its class methods and class fields.

protected void finalize() throws Throwable– Called before an object is destroyed. Must be overridden in those descendants of Object in which it is necessary to perform some auxiliary actions before destroying the object (close a file, display a message, draw something on the screen, etc.). This method is described in more detail in the corresponding paragraph.

public String toString()– returns a string representation of the object (as adequately as possible). In the Object class, this method produces a string of the object's full name (with the package name), followed by an '@' character, and then a hexadecimal hash code of the object. Most standard classes override this method. For numeric classes, the string representation of the number is returned, for string classes – the contents of the string, for character classes – the character itself (and not the string representation of its code!). For example, the following code snippet

Object obj=new Object();

System.out.println(" obj.toString() gives "+obj.toString());

Double d=new Double(1.0);

System.out.println(" d.toString() gives "+d.toString());

Character c="A";

System.out.println("c.toString() gives "+c.toString());

will provide a conclusion

obj.toString() gives java.lang.Object@fa9cf

d.toString() gives 1.0

c.toString() gives A

There are also methods notify(), notifyAll(), and several overloaded variants of the method wait, designed to work with threads. These are discussed in the section on streams.


Related information.