What is program music? Examples and definition of program music. Generalizations

The object-oriented component of the C ++ language is very powerful. The C ++ language has a developed class apparatus that allows you to implement user-defined data types. Overloading built-in operators for user-defined types allows you to endow these types with all the capabilities that the language provides for built-in types. This gives reason to consider the C ++ built-in type system extensible.

A C ++ class is a generalization of C structures. A class differs from C structures in two respects. First, the class combines not only data, but functions. Secondly, the members of the class are endowed with access rights. Combining data and functions allows you to associate data and the operations that need to be performed with it. Access rights allow you to encapsulate (hide) the implementation of a class.

In C ++, user-defined types can be endowed with inheritance and polymorphism properties. This allows the programmer to design hierarchical software systems.

It is important that there is a standard approved in 1998, which defines the syntax of the C ++ language and its standard library.

Note that in object-oriented programming, the focus is on data, not on algorithms, as is the case in procedural programming.

Generalized programming

Generic programming is based on the use of so-called function templates and class templates. The use of such templates is due to the fact that data processing algorithms are often weakly dependent on the type of data they process. In this case, it is convenient to pass information about the type of data that should be processed through parameters that are called generic types. Let's give an example of a function template designed to exchange the values \u200b\u200bof two variables.

template void swap (T & a, T & b) (T temp \u003d a; a \u003d b; b \u003d temp;) int main () (double x \u003d 2; double y \u003d 3; swap (x, y); printf (“x \u003d% 0.4gy \u003d% 0.4g \\ n ”, x, y); int n \u003d 4; int m \u003d 5; swap (n, m); printf (“ n \u003d% dm \u003d% d \\ n ”, n, m); return 0;)

The code above begins by defining a template for the swap () function. A function template differs from a regular function definition by the additional prefix that begins with the reserved word template. The angle brackets contain the so-called list of template parameters. In the current example, this list contains only one element consisting of the reserved word class, the name of the template parameter T. The reserved word class indicates that the template parameter T is a generic type (there are other varieties of template parameters).

In the calling function which

Towards Object Oriented Programming

It is well known that the complexity of programming is primarily due to the complexity of the tasks being solved. The main way to overcome these difficulties is to decompose the problem. Decomposition consists in replacing the original problem with a set of other less complex problems, the joint solution of which should give the expected result.

It should be borne in mind that not every decomposition leads to success. In practice, we often come across a situation where the parts of the program responsible for solving individual subtasks work, but the whole program as a whole does not. This is the case when there are strong interconnections between the individual parts of the program.

The use of abstraction makes it possible to make the solution of individual problems relatively independent. Indeed, abstraction is associated with the selection of essential characteristics in some phenomenon, event or object. Ultimately, this should help to reduce the relationship between the individual components of the program.

In early programming languages, the so-called action abstraction, or procedural abstraction, found application. The abstraction of an action is implemented using subroutines (functions of the C language).

There are two main types of abstractions:

    Abstraction of action (procedural abstraction).

    Entity abstraction (abstract data type).

Action abstraction, or procedural abstraction, is implemented in C ++ using the apparatus of functions. Using functions, the programmer has the ability to expand the many built-in operations that are provided by the language.

When using procedural programming, this is the only supported abstraction. Consider the factors that provide support for the Action Abstraction language:

    the presence of a special syntactic structure designed to implement abstraction (function definition).

    the ability to separate the interface from the implementation.

    hiding the implementation of the algorithm that implements the action from the client.

Entity abstraction is closely related to the problem of creating custom data types. The fact is that in practice there is often a need to model concepts that exist in the subject area for which the program is being developed. This leads to the need to have a device that allows you to create custom data types. It is of interest to consider the following question: is it possible or not to implement an abstraction of entities in the C language type. From the above, an important fact can be noted that can negatively affect the attempt to implement the abstraction of action: in the C language there is no syntactic structure intended for these purposes.

First, let's look at a very important question of how you can describe the abstraction of entities. To do this, let's turn to a concept that is often used in modern programming. This is an abstract data type.

Last updated: 09/28/2017

With the release of version 2.0, the .NET framework began to support generics, as well as the creation of generic methods. To understand the specifics of this phenomenon, first take a look at a problem that may have arisen before the advent of generic types. Let's see an example. Let's say we define a class to represent a bank account. For example, it might look like this:

Class Account (public int Id (get; set;) public int Sum (get; set;))

The Account class defines two properties: Id - a unique identifier and Sum - the amount on the account.

Here the identifier is set as a numeric value, that is, bank accounts will have the values \u200b\u200b1, 2, 3, 4, and so on. However, it is not uncommon to use string values \u200b\u200bfor the identifier as well. Both numeric and string values \u200b\u200bhave their pros and cons. And at the time of writing the class, we may not know exactly what is better to choose for storing the identifier - a string or a number. Or, perhaps, this class will be used by other developers who may have their own opinion on this issue.

And at first glance, to get out of this situation, we can define the Id property as a property of type object. Since the object type is a universal type from which all types are inherited, respectively, we can store both strings and numbers in properties of this type:

Class Account (public object Id (get; set;) public int Sum (get; set;))

This class could then be used to create bank accounts in the program:

Account account1 \u003d new Account (Sum \u003d 5000); Account account2 \u003d new Account (Sum \u003d 4000); account1.Id \u003d 2; account2.Id \u003d "4356"; int id1 \u003d (int) account1.Id; string id2 \u003d (string) account2.Id; Console.WriteLine (id1); Console.WriteLine (id2);

Everything seems to work great, but this solution is not very optimal. The fact is that in this case we are faced with such phenomena as boxing and unboxing.

So, when assigning a value of type int to the Id property, this value is packed into the Object type:

Account1.Id \u003d 2; // boxing into int values \u200b\u200binto Object type

To get the data back into a variable of int types, you need to unpack:

Int id1 \u003d (int) account1.Id; // Unpacking into int type

Boxing involves converting an object of a value type (such as int) to type object. When packaging, the common language CLR wraps the value in an object of type System.Object and stores it in the managed heap. Unboxing, on the other hand, involves converting an object of type object to significant type... Packing and unpacking leads to performance degradation as the system needs to make the necessary transformations.

In addition, there is another problem - the problem of type safety. So, we get a runtime error if we write like this:

Account account2 \u003d new Account (Sum \u003d 4000); account2.Id \u003d "4356"; int id2 \u003d (int) account2.Id; // Exception InvalidCastException

We may not know what kind of object the Id represents, and when trying to get a number in this case, we will encounter an InvalidCastException.

These problems were intended to eliminate generic types. Generic types allow you to specify a specific type to be used. Therefore, let's define the Account class as generic:

Class Account (public T Id (get; set;) public int Sum (get; set;))

Angle brackets in class Account description indicate that the class is generic, and the type T, enclosed in angle brackets, will be used by that class. It is not necessary to use the letter T, it can be any other letter or character set. And now we do not know what kind of type it will be, it can be any type. Therefore, the parameter T in angle brackets in is also called universal parameter, since any type can be substituted for it.

For example, instead of the T parameter, you can use an int object, that is, a number that represents an account number. It can also be a string object, or any other class or structure:

Account account1 \u003d new Account (Sum \u003d 5000); Account account2 \u003d new Account (Sum \u003d 4000); account1.Id \u003d 2; // no packaging required account2.Id \u003d "4356"; int id1 \u003d account1.Id; // unpacking is not needed string id2 \u003d account2.Id; Console.WriteLine (id1); Console.WriteLine (id2);

Since the Account class is generic, when defining a variable after the type name in angle brackets, you must specify the type that will be used instead of the universal parameter T. In this case, the Account objects are typed with int and string types:

Account account1 \u003d new Account (Sum \u003d 5000); Account account2 \u003d new Account (Sum \u003d 4000);

Therefore, the first account1 object will have the Id property of type int, and the account2 object will have the string type.

When we try to assign the value of the Id property to a variable of a different type, we get a compilation error:

Account account2 \u003d new Account (Sum \u003d 4000); account2.Id \u003d "4356"; int id1 \u003d account2.Id; // compilation error

This avoids type safety problems. Thus, by using a generic version of the class, we reduce the execution time and the number of potential errors.

Default values

Sometimes it becomes necessary to assign some initial value to variables of generic parameters, including null. But we cannot assign it directly:

T id \u003d null;

In this case, we need to use the default (T) statement. It assigns null to reference types and 0 to value types:

Class Account (T id \u003d default (T);)

Generic Class Static Fields

When typing a generic class with a specific type, its own set of static members will be created. For example, the Account class defines the following static field:

Class Account (public static T session; public T Id (get; set;) public int Sum (get; set;))

Now we type the class with two types int and string:

Account account1 \u003d new Account (Sum \u003d 5000); Account .session \u003d 5436; Account account2 \u003d new Account (Sum \u003d 4000); Account .session \u003d "45245"; Console.WriteLine (Account .session); // 5436 Console.WriteLine (Account .session); // 45245

As a result, for Account and for Account its own session variable will be created.

Using multiple generic parameters

Generics can use multiple generic parameters at the same time, which can represent different types:

Class Transaction (public U FromAccount (get; set;) // from which account the transfer is public U ToAccount (get; set;) // to which account the transfer is public V Code (get; set;) // operation code public int Sum (get; set;) // transfer amount)

The Transaction class uses two generic parameters here. Let's apply this class:

Account acc1 \u003d new Account (Id \u003d 1857, Sum \u003d 4500); Account acc2 \u003d new Account (Id \u003d 3453, Sum \u003d 5000); Transaction , string\u003e transaction1 \u003d new Transaction , string\u003e (FromAccount \u003d acc1, ToAccount \u003d acc2, Code \u003d "45478758", Sum \u003d 900);

Here the Transaction object is typed with Account types and string. That is, the Account class is used as a universal parameter U. , and for the V parameter, the type string. At the same time, as you can see, the class with which Transaction is typed is itself generic.

Generalized methods

In addition to generic classes, you can also create generic methods that use generic parameters in the same way. For instance:

Class Program (private static void Main (string args) (int x \u003d 7; int y \u003d 25; Swap (ref x, ref y); Console.WriteLine ($ "x \u003d (x) y \u003d (y)"); // x \u003d 25 y \u003d 7 string s1 \u003d "hello"; string s2 \u003d "bye"; Swap (ref s1, ref s2); Console.WriteLine ($ "s1 \u003d (s1) s2 \u003d (s2)"); // s1 \u003d bye s2 \u003d hello Console.Read (); ) public static void Swap (ref T x, ref T y) (T temp \u003d x; x \u003d y; y \u003d temp;))

This defines a generic Swap method that takes parameters by reference and changes their values. Moreover, in this case, it does not matter what type these parameters represent.

In the Main method, we call the Swap method, type it with a certain type and pass some values \u200b\u200bto it.

Then in the form of parametric polymorphism in and its descendants, and then in many object-oriented languages \u200b\u200bsuch as C ++, Java, Object Pascal, Eiffel, languages \u200b\u200bfor the .NET platform and others.

Generic programming methodology

Generic programming is viewed as a programming methodology based on the separation of data structures and algorithms through the use of abstract descriptions of requirements. Abstract requirements descriptions are an extension of the concept of an abstract data type. Instead of describing a separate type, generic programming uses a description of a family of types that have a common interface and semantic behavior. The set of requirements describing the interface and semantic behavior is called concept (eng. concept). Thus, an algorithm written in a generic style can be applied to any type that satisfies its concepts. This opportunity is called polymorphism.

They say that the type simulates concept (is a model of the concept), if it satisfies its requirements. The concept is clarification another concept if it complements the latter. Concept requirements contain the following information:

  • Valid expressions (English valid expressions) - programming language expressions that must successfully compile for types that model a concept.
  • Associated types Associated types are auxiliary types that have something to do with the type that simulates the concept.
  • Invariants (eng. invariants) - such characteristics of types that must be constantly correct during execution. Usually expressed as preconditions and postconditions. Failure to fulfill a precondition entails unpredictability of the corresponding operation and can lead to errors.
  • Complexity guarantees (complexity guarantees) - maximum execution time of a valid expression or maximum requirements to various resources during the execution of this expression.

An alternative approach to defining generic programming, which can be called generic programming of data types (eng. datatype generic programming), was proposed by Richard Bird and Lambert Meertens. In it, data type structures are parameters of generic programs. For this, the programming language is entered new level abstraction, namely parametrization in relation to classes of algebras with variable signature. Although the theories of both approaches are independent of the programming language, the Masser-Stepanov approach, which focuses on the analysis of concepts, made C ++ its main platform, while generic programming of data types uses almost exclusively Haskell and its variants.

General mechanism

Generic programming tools are implemented in programming languages \u200b\u200bin the form of certain syntactic tools that make it possible to describe data (data types) and algorithms (procedures, functions, methods) parameterized by data types. A function or data type explicitly declares formal type parameters. This description is generalized and cannot be directly used in its original form.

In those places in the program where a generic type or function is used, the programmer must explicitly specify the actual type parameter that concretizes the description. For example, a generic procedure for swapping two values \u200b\u200bmight have a type parameter that specifies the type of the values \u200b\u200bit swaps. When a programmer needs to swap two integer values, he calls a procedure with an "integer" type parameter and two parameters - integers, when two strings - with a "string" type parameter and two parameters - strings. In the case of data, a programmer can, for example, describe a generic type "list" with a type parameter that determines the type of values \u200b\u200bstored in the list. Then, when describing real lists, the programmer must specify a generic type and a type parameter, thus obtaining any desired list using the same description.

When the compiler encounters a call to a generic type or function, it performs the necessary static type checking procedures, evaluates the possibility of a given instantiation, and, if positive, generates code by substituting the actual type parameter in place of the formal type parameter in the generic description. Naturally, for the successful use of generic descriptions, actual parameter types must satisfy certain conditions. If a generic function compares values \u200b\u200bof a parameter type, any concrete type used in it must support comparison operations; if it assigns values \u200b\u200bof a parameter type to variables, a specific type must provide correct assignment.

Generalized programming in languages

C ++

In the C ++ language, generic programming is based on the concept of "template", denoted keyword template... Widely applied in standard library C ++ (see STL) as well as third party boost libraries, Loki. Alexander Stepanov made a great contribution to the emergence of advanced generic programming tools in C ++.

As an example, we will give a template (generalization) of a function that returns greater importance of the two.

// Description of the function template template< typename T > T max (T x, T y) (if (x< y ) return y ; else return x ; } ... // Applying the function specified by the template int a \u003d max (10, 15); ... double f \u003d max (123.11, 123.12); ...

or a template (generalization) of a linked list class:

template< class T > class List (/ * ... * / public: void Add (const T & Element); bool Find (const T & Element); / * ... * /);

Java

Java has provided generic programming tools syntactically based on C ++ since J2SE 5.0. This language has generics or "containers of type T" are a subset of generic programming.

.NET

// http://digitalmars.com/d/2.0/template.html template Foo (T, R ...) // T is a type, R is a set of types (void Foo (T t, R r) (writeln (t); static if (r. length) // if more arguments Foo (r); // do the rest of the arguments )) void main () (Foo (1, "a", 6.8);) / +++++++++++++++ prints: 1 a 6.8 ++++++++++ +++++ /

Generic programming tools are implemented in programming languages \u200b\u200bin the form of certain syntactic tools that make it possible to describe data (data types) and algorithms (procedures, functions, methods) parameterized by data types. A function or data type has formal type parameters explicitly described. This description is generalized and cannot be directly used in its original form.

In those places in the program where a generic type or function is used, the programmer must explicitly specify the actual type parameter that concretizes the description. For example, a generic procedure for swapping two values \u200b\u200bmight have a type parameter that specifies the type of the values \u200b\u200bit swaps. When a programmer needs to swap two integer values, he calls a procedure with an "integer" type parameter and two parameters - integers, when two strings - with a "string" parameter and two parameters - strings. In the case of data, a programmer can, for example, describe a generic type "list" with a type parameter that determines the type of values \u200b\u200bstored in the list. Then, when describing real lists, the programmer must specify a generic type and a type parameter, thus obtaining any desired list using the same description.

When the compiler encounters a call to a generic type or function, it performs the necessary static type checking procedures, evaluates the possibility of a given instantiation, and, if positive, generates code by substituting the actual type parameter in place of the formal type parameter in the generic description. Naturally, for the successful use of generic descriptions, actual parameter types must satisfy certain conditions. If a generic function compares values \u200b\u200bof a parameter type, any concrete type used in it must support comparison operations; if it assigns values \u200b\u200bof a parameter type to variables, a specific type must provide correct assignment.

Implementation methods

There are two main ways to implement generic programming support in a compiler.

  • Generating new code for each instantiation. In this case, the compiler treats the generic description as a textual template for generating instantiations. When the compiler needs a new instantiation of a generic type or procedure, it creates a new instance of the type or procedure by mechanically adding the type parameter to it. That is, having a generalized function for the permutation of elements, the compiler, upon encountering its call for an integer type, will create a function for permutation of integers and substitute its call into the code, and then, upon encountering a call for a string type, it will create a function for permutation of strings that has nothing to do with the first. This method provides maximum performance, since the instantiations become different fragments of the program, each of them can be optimized for its own parameter type, and besides, no extra elementsassociated with checking or converting types at runtime. Its disadvantage is that with the active use of generic types and functions with different types-parameters, the size of the compiled program can grow very much, since even for those description fragments that for different types do not differ, the compiler generates separate code anyway. This drawback can be obscured by partial generation of the general code (the part of the generalized description, which does not depend on the types-parameters, is formatted in a special way, and the compiler generates a single code for all instantiations based on it). But this mechanism provides a natural opportunity to create special (usually - heavily manually optimized) instantiations of generic types and functions for some parameter types.
  • Generation of code that, at runtime, converts the actual type parameters to a single type, with which it actually works. In this case, at the stage of compiling the program, the compiler only checks the conformity of types and includes in the command code for converting a specific type-parameter to general type... The code that determines the functioning of a generic type or function is present in a compiled program in a single copy, and conversions and type checks are performed dynamically, while the program is running. In this variant, as a rule, more compact code is generated, but the program turns out to be on average slower than in the first variant, due to the need to perform additional operations and less optimization possibilities. In addition, dynamic information about types is not always included in the compiled code for parameter types (in the first version it is, if at all supported, since the instantiations for each parameter type are different), which determines some restrictions on the use of generic types and functions. There are similar restrictions, for example, in Java.

Generalized programming in languages

C ++

In C ++, generic programming is based on the concept of "template", denoted by the keyword template... It is widely used in the C ++ standard library (see STL), as well as in third-party boost libraries, Alexander Stepanov.

As an example, let's take a generic function that returns the larger value of two.

// Description of the template function template T max (T x, T y) (if (x< y) return y; else return x; } ... // Apply a template function int a \u003d max (10, 15); ... double f \u003d max (123.11, 123.12); ...

Java

Java has provided generic programming tools syntactically based on C ++ since J2SE 5.0. This language has generics or "containers of type T" are a subset of generic programming.

.NET

Example on

D

In the D language, generic programming tools have evolved significantly over C ++, both procedurally and object-oriented. Linguistic representation has also become much simpler.

An example of recursive generation based on D templates:

// http://digitalmars.com/d/2.0/template.html template Foo (T, R ...) // T is a type, R is a set of types (void Foo (T t, R r) (writefln (t); static if (r.length) // if more arguments Foo (r); // do the rest of the arguments )) void main () (Foo (1, "a", 6.8);) / +++++++++++++++ prints: 1 a 6.8 ++++++++++ +++++ /


Wikimedia Foundation. 2010.

See what "Generalized Programming" is in other dictionaries:

    generic programming - - [E.S. Alekseev, A.A. Myachev. English Russian dictionary on computer systems engineering. Moscow 1993] Topics information Technology in general EN generalized programmingGP ... Technical translator's guide

    Modern C ++ Design

    This article should be wikified. Please fill it out according to the rules of article formatting. Conventions ... Wikipedia

    This term has other meanings, see C. See also: C (programming language) C ++ Semantics: multiparadigm: object-oriented, generic, procedural, metaprogramming Execution type: compiled Introduced in ... Wikipedia

    This term has other meanings, see D. D Semantics: multi-paradigm: imperative, object-oriented, generic programming Execution type: compiler Introduced in: 1999 Author (s) ... Wikipedia

    See also: C (programming language) C ++ Semantics: multiparadigm: object oriented, generalized, procedural, metaprogramming Execution type: compiled Introduced in: 1985 Author (s): Björn Stroustrup ... Wikipedia

    This term has other meanings, see F (meanings). Correct title of this F # article. It is displayed incorrectly due to technical limitations. F # Language class: multi-paradigm: functional, object-oriented, ... ... Wikipedia

    This combination of symbols also often denotes a chord or key in F sharp major F м is a functional programming language general purpose... Developed by Don Syme at Microsoft Research, Cambridge. The F♯ structure is largely ... ... Wikipedia

    F # is a general-purpose functional programming language. Developed by Don Syme at Microsoft Research, Cambridge. The structure of F # is very similar to the structure of the .NET libraries and runtime. Some problems are solved ... ... Wikipedia

    This term has other meanings, see Loki (disambiguation). The Loki library for the C ++ programming language was written by Andrei Alexandrescu as part of the book Modern C ++ Design: Generalized Programming and Application Patterns ... ... Wikipedia

Books

  • Programming. Principles and Practice Using C ++, Stroustrup Bjarne. This book is not a C ++ language textbook, it is a programming textbook. Despite the fact that its author is the author of the C ++ language, the book is not devoted to this programming language; he plays in ...

Generic Programming Generic Programming is writing code that can be reused with many different types of objects.

In early versions of Java, this was accomplished through inheritance, the ArrayList containing an array of Object references. Whenever a value was retrieved, a cast had to be performed.

Generalized programming is a programming paradigm that describes data and algorithms in a way that can be applied to different types data without changing the description itself. It is supported in one form or another by different programming languages.

Generics represent the most significant change in language java programming since version 1.0. The introduction of generics in Java 5.0 is the result of the first Java Specification Requests (JSR 14), which were formulated in 1999. Generics were needed because they allow you to write safer code that is easier to read than code overloaded with Object variables. and type casts. Generics are especially useful for collection classes like the ubiquitous ArrayList.

Generics are similar - at least superficially - to templates in C ++. In C ++, as in Java, templates were first added to support strongly typed collections. However, other applications have been discovered over the years.

Generic programming capabilities first appeared in the 70s in the CLU and Ada languages, and then in many object-oriented languages \u200b\u200bsuch as C ++, Java, D, and languages \u200b\u200bfor the .NET platform. General mechanism Generic programming tools are implemented in the form of certain syntactic tools. A function or data type explicitly declares formal type parameters. This description is generalized and cannot be directly used in its original form.

In those places in the program where a generic type or function is used, the programmer must explicitly specify the actual type parameter that concretizes the description. When the compiler encounters a call to a generic type or function, it performs the necessary static type checking procedures, evaluates the possibility of a given instantiation, and, if positive, generates code by substituting the actual type parameter in place of the formal type parameter in the generic description.

Naturally, for the successful use of generic descriptions, actual parameter types must satisfy certain conditions. If a generic function compares values \u200b\u200bof a parameter type, any concrete type used in it must support comparison operations; if it assigns values \u200b\u200bof a parameter type to variables, a specific type must provide correct assignment. Implementation Methods There are two main ways to implement generic programming support in the compiler.

Generating new code for each instantiation. In this case, the compiler treats the generic description as a textual template for generating instantiations. When the compiler needs a new instantiation of a generic type or procedure, it creates a new instance of the type or procedure by mechanically adding the type parameter to it. That is, having a generalized function for the permutation of elements, the compiler, upon encountering its call for an integer type, will create a function for permutation of integers and substitute its call into the code, and then, upon encountering a call for a string type, it will create a function for permutation of strings that has nothing to do with the first. This method provides maximum performance. Its disadvantage is that with the active use of generic types and functions with different types-parameters, the size of the compiled program can grow very much, because even for those description fragments that do not differ for different types, the compiler still generates separate code. This drawback can be obscured by partial generation of the general code (the part of the generalized description, which does not depend on the types-parameters, is formatted in a special way, and the compiler generates a single code for all instantiations based on it). ... Generation of code that, at runtime, converts the actual type parameters to one type, with which it actually works. In this case, at the stage of compiling the program, the compiler only checks the conformity of types and includes in the command code for converting a specific type-parameter to a general type. The code that determines the functioning of a generic type or function is present in a compiled program in a single copy, and conversions and type checks are performed dynamically, while the program is running. In this variant, as a rule, more compact code is generated, but the program turns out to be on average slower than in the first variant, due to the need to perform additional operations and less optimization possibilities. In addition, dynamic information about types is not always included in the compiled code for parameter types (in the first version it is, if at all supported, since the instantiations for each parameter type are different), which determines some restrictions on the use of generic types and functions. There are similar restrictions in Java.

A generic class is a class with one or more type variables. class Pair () A type variable is used to specify the return type of methods and types of fields and local variables. You can then create an object of the generic type by substituting the type name for the type variable. Pair ()

Some restrictions on generics 1. Type parameters cannot take primitive types. 2. Arrays of parameterized types are not allowed. 3. You cannot create instances of variable types. 4. Not allowed in static context. The Purpose of Generic Programming Generic programming means writing code that can be reused with many different types of objects. This makes your code easier to read. You can immediately understand that this particular array-list contains String objects. The compiler can use this information successfully as well. No casting is required when calling get (). The compiler knows that the return type of this method is String, not Object: String filename \u003d files.get (0); The compiler also knows that the add () method on the ArrayList has a parameter of type String. This is much safer than dealing with a parameter of type Object. The compiler can now make sure that you do not insert an object of the wrong type. For example, the following statement will not compile: files.add (new File ("...")); // only String objects can be added to the ArrayList // Compilation error is much better than a runtime cast exception. This is the beauty of type parameters: they make your program easier to read and more secure. Generic classes like ArrayList are easy to use. And most Java programmers just use types like ArrayList - as if they were part of the language, like String arrays. (Of course, list arrays are better than simple arrays because they can expand automatically.) However, implementing a generic class is not easy. The programmers who will be using your code will try to substitute all sorts of classes for your type parameters. They expect everything to work without annoying restrictions and confusing error messages. It is your job as a generic programmer to anticipate all possible future uses for your class. Generic Code and the Virtual Machine The virtual machine does not deal with generic objects — all objects belong to generic classes. Whenever a generic type is defined, a corresponding raw type is automatically created. The name of this type is the same as the name of a generic type with type parameters removed. Variables of type are removed and replaced by the constraint types (or Object type if the variable is unconstrained). For example, a raw type for Pair looks like the one shown below. public class Pair (public Pair (Object first, Object second) (this.first \u003d first; this.second \u003d second;) public Object getFirst () (return first;) public Object getSecond () (return second;) public void setFirst (Object newValue) (first \u003d newValue;) public void setSecond (Object newValue) (second \u003d newValue;) private Object first; private Object second;) Since T is an unbounded type variable, it is simply replaced by Object. The result is a common class, like you might have implemented before, before generics were introduced to the Java programming language. Your programs contain different variants of Pair, such as Pair or Pair, but this “cleanup” turns them into a “raw” Pair type. A "raw" type replaces type variables with the first constraint, or Object if no constraints are provided. For example, a type variable in the Pair class has no explicit restrictions, and therefore the raw type replaces T with Object. Suppose a slightly different type is declared: public class Interval implements Serializable (public Interval (T first, T second) (if (first.compareTo (second)<= 0) { lower = first; upper = second; } else { lower = second; upper = first; } } ... private T lower; private T upper; } Сырой тип Interval выглядит следующим образом: public class Interval implements Serializable { public Interval(Comparable first, Comparable second) { ... } ... private Comparable lower; private Comparable upper; } Трансляция обобщенных выражений Когда ваша программа вызывает обобщенный метод, компилятор вставляет приведения, когда удаляется возвращаемый тип. Например, рассмотрим следующую последовательность операторов: Pair buddies = ...; Employee buddy = buddies.getFirst(); Подчистка getFirst() приведет к возврату типа Object. Компилятор автоматически вставит приведение к Employee. То есть компилятор транслирует вызов метода в две инструкции виртуальной машины. . Вызов сырого метода Pair.getFirst(). . Приведение возвращенного объекта Object к типу Employee. Приведения также вставляются при обращении к обобщенному полю. Предположим, что поля first и second были бы общедоступными, т.е. public. (Возможно, это нехороший стиль программирования, но вполне допустимый в Java.) Тогда в оператор Employee buddy = buddies.first; в результирующем байт-коде также будут вставлены приведения.

Did you like the article? To share with friends: