Catalog
- 1. Recognition of polymorphism from eating roasted yam
- 2. Preconditions for polymorphism
- 3. Manifestation of polymorphism
- 4. Upward transformation
- 5. Downward transformation
- 6. Re analysis of upward and downward transformation
- 7. The subtlety between polymorphism and constructor
- 8. Advantages of polymorphism
- 9. Analyze the nine questions at the beginning
- 10. Finally, let's formally analyze the nine questions
@
In my opinion, polymorphism is the third feature of object-oriented, which makes it difficult for many Xiaobai students and beginners to cross the gap. Because polymorphism has a lot of detailed knowledge, it is really difficult to understand polymorphism without taking time. So, if you think you have fully understood polymorphism, you may as well do the following procedures, if you can answer all correctly, that's OK, polymorphism is really not a problem for you! If you get down in the fourth, you can read this article, which may help you, and may help you to see the charm of polymorphism again.
package Polymorphic; //Grandfather class class Ye { public String show(Sun obj) { return ("Ye and Sun"); } public String show(Ye obj) { return ("Ye and Ye"); } } //Papa class class Fu extends Ye { public String show(Fu obj) { return ("Fu and Fu"); } public String show(Ye obj) { return ("Fu and Ye"); } } //Son class class Zi extends Fu { } //Grandchildren class Sun extends Fu { } public class PolymorphicTest { public static void main(String[] args) { Ye y = new Ye(); Ye y2 = new Fu(); //Upward Fu f = new Fu(); Zi z = new Zi(); Sun s = new Sun(); System.out.println("First question " + y.show(f)); System.out.println("Second questions " + y.show(z)); System.out.println("Third questions " + y.show(s)); System.out.println("Fourth questions " + y2.show(f)); //Hang up here??? System.out.println("Fifth questions " + y2.show(z)); System.out.println("Sixth questions " + y2.show(s)); System.out.println("Seventh questions " + f.show(f)); System.out.println("Eighth questions " + f.show(z)); System.out.println("Ninth questions " + f.show(s)); } }
First write down the answers in a small book, and then compare them with the following results
First question Ye and Ye Ye and Ye Third question Ye and Sun Fu and Ye Fifth question Fu and Ye Ye and Sun Fu and Fu Fu and Fu Ye and Sun
If you are surprised or puzzled by the above results, Congratulations, you can learn new knowledge again and successfully move forward to the architect! Well, let's see the charm of polymorphism again!
1. Recognition of polymorphism from eating roasted yam
It's not that we are eating roasted yam now. We should take an interesting route to study. After all, the best teacher is always interested. Let's go, how to be interesting.
Xiaoming's mother's mood is very unstable. When she is in a good mood, she would like to spend a hundred million yuan on Xiaoming. When she is in a bad mood, she would like to play Muggle, but Xiaoming never knows her mother's mood changes. Today, an old man is selling roasted yams, and he is still dancing laser rain while baking. He can't help it. Xiao Ming loves laser rain very much. He can't help it. He thinks silently that the yams just baked don't smell. The yams baked by laser rain don't smell. So I couldn't help saying to my mother, "Mom, I want to eat roasted yam". At this time, here, here, here, here he is, here it really comes.... you excite a hammer... It's the code:
package Polymorphic; class Matcher{ public void matcherSpeak(){ System.out.println("Would you like to roast yams?"); } } class HappyMother extends Matcher { public void matcherSpeak(){ System.out.println("Happy mother said: eat, eat big, one train enough"); } } class SadMother extends Matcher { public void matcherSpeak(){ System.out.println("Unhappy mother said: eat your silly skin and see if I'm going home and you're done"); } } class VeryHappyMother extends Matcher { public void matcherSpeak(){ System.out.println("The extremely happy mother said: buy and buy. We'll buy all the baked yams. By the way, I'll buy you home and show you the laser rain every day"); } } public class UnderstandPolymorphic{ public static void main(String[] args) { Matcher m = new HappyMother(); m.matcherSpeak(); m = new SadMother(); m.matcherSpeak(); m = new VeryHappyMother(); m.matcherSpeak(); } } //Operation result: //Happy mother said: eat, eat big, one train enough //Unhappy mother said: eat your silly skin and see if I'm going home and you're done //The extremely happy mother said: buy and buy. We'll buy all the baked yams. By the way, I'll buy you home and show you the laser rain every day
Mother heard Xiaoming want to bake yam this same behavior, showing different forms of expression, this is polymorphism. The professional definition of polymorphism is: the specific type of the reference variable defined in the program and the method call sent through the reference variable are not determined when programming, but only during the operation of the program. This situation is called polymorphism. Yes, it is true that the skull is a little big, so I choose to define polymorphism simply: polymorphism refers to the same behavior with multiple different manifestations . Why is there such a subtle change? Then we must understand the premise of polymorphism.
2. Preconditions for polymorphism
If polymorphism can not meet the following three preconditions, then we can also play with the polymorphism of calf
- Inheritance or implementation
- Method rewriting [meaning expression: no rewriting, no meaning]
Subclass redefines some methods in the parent class. When these methods are called, the subclass's methods will be called. - The parent class reference points to the child class object (it can also be said that the transformation is upward) [reflected in the format]
Looking back at the example of roasted yam, we can see that there are indeed inheritances. We also rewrite the motherSpeak() method, and the most critical code is
Matcher m = new HappyMother();
That is, the so-called parent class reference points to the child class object, which is actually an upward transformation! It's OK that the concept of upward transformation is not clear, which will be explained in detail below.
3. Manifestation of polymorphism
The format of polymorphism: parent class / parent interface type variable name = new subclass object; variable name. Method name ();
When using polymorphic method to call a method, first check whether the method exists in the parent class. If not, compilation error occurs. If yes, the method after subclass rewriting is executed. That is to say, the method defined separately by subclass is lost during upward transformation. Compile error The code is as follows:
package Demo; class Matcher{ public void matcherSpeak(){//=========================Parent matcherSpeak() method System.out.println("Eat roasted yams?"); } } class HappyMother extends Matcher { public void matcherSpeak(){//=========================Subclass matcherSpeak() method System.out.println("Happy mother said: eat, eat big, a snake skin bag is enough"); } public void fatherSpeak(){//=========================The unique fatherSpeak() method of subclass System.out.println("Happy mother said: eat, eat big, a sack is enough"); } } public class Test { public static void main(String[] args) { Matcher m=new HappyMother(); m.matcherSpeak(); m.fatherSpeak(); //Compilation failed, unable to resolve fatherSpeak method } }
The analysis is as follows:
Of course, this is only an entry-level example. Let's take a look at a somewhat horizontal example
package Demo; class Matcher{ public void matcherSpeak(){ System.out.println("Would you like to roast yams?"); } } class HappyMother extends Matcher { public void matcherSpeak(){ System.out.println("Happy mother said: eat, eat big, one train enough"); } } class SadMother extends HappyMother{ public void tt(){ System.out.println("ttttttt"); } } public class Test { public static void main(String[] args) { Matcher mm=new SadMother(); mm.matcherSpeak(); } //Running result: happy mother said: eat, eat big, is one train enough }
With the first foundation, it's not hard to understand. Let's go on
package Demo; class Matcher{ public void matcherSpeak(){ System.out.println("Would you like to roast yams?"); } } class HappyMother extends Matcher { } class SadMother extends HappyMother{ public void tt(){ System.out.println("ttttttt"); } } public class Test { public static void main(String[] args) { Matcher mm=new SadMother(); mm.matcherSpeak(); } //Running result: would you like to roast yam? }
Here, let's go back to this sentence:
When a method is called in a polymorphic way, first check whether the method exists in the parent class. If not, the method is compiled incorrectly. If so, the method after the subclass rewriting is executed
You may say that there are no such methods in the subclass. How to execute the method after subclass rewriting? It seems to be looking for the method in the parent class. In fact, there are these methods in the subclass. This method inherits from the parent class, but it does not cover the method, so it is not explicitly written in the subclass. It looks like a method in the parent class is called, but in fact it is called in the subclass. It's time to supplement the knowledge of students' inheritance. Please refer to the following article [java foundation] java inheritance starts from "my father is Li Gang"
4. Upward transformation
Upward Transformation: polymorphism itself is the process of upward transformation from subclass type to parent type, and this process is the default. You can understand this process as automatic conversion of basic types from small types to large types without coercion When a parent class reference points to a child class object, it is an upward transformation Upward transformation format:
Parent type variable name = new subclass type (); for example: father f = new son();
For example, the example of roasted yam is a typical example of upward transformation
5. Downward transformation
Downward Transformation: the process of downward transformation from parent type to child type, which is mandatory. This process can also be understood as the automatic conversion of basic types, and the conversion of large types to small types needs to be forced. For a subclass object that has been transformed upward, the parent class reference can be converted to a subclass reference, and the forced type conversion format can be used, and the down conversion format can be used:
Father father = new Son();
Subclass type variable name = (subclass type) parent variable name; for example: Son s =(Son) father;
I don't know if you have found that the premise of the downward transformation is that the parent object points to the child object (that is, before the downward transformation, it has to first transform upward). Of course, the downward transformation has its significance. Next, we will explain the significance of the downward transformation.
Here, let's explain why we need to make a downward transformation? As mentioned above, when a method is called in a polymorphic way, first check whether the method exists in the parent class, and if not, compile the error. That is, you cannot call a method that is owned by a subclass and not owned by a parent. Compilation is wrong, let alone running. This is also a little bit of "little trouble" brought by polymorphism. Therefore, if you want to call subclass specific methods, you must do a downward transformation.
package Demo; class Matcher{ public void eat(){ System.out.println("Would you like to roast yams?"); } } class XiongHaiZi extends Matcher { public void eat(){ System.out.println("Mom, I want to eat roasted yam"); } public void eatSuLi(){//============================Subclass specific eatSuLi methods System.out.println("Ma Ma, I want to eat crisp pears as big as Muggles"); } } public class Test { public static void main(String[] args) { Matcher m = new XiongHaiZi();//Upward transformation XiongHaiZi x = (XiongHaiZi)m;//Downward transformation x.eatSuLi();//Execute subclass specific methods } //Running result: Ma Ma, I want to eat crisp pear as big as Muggle }
OK, let's talk about the downward transformation here... Wait, do you really think it's over? I'm sure not. There is another knowledge to be said about the downward transformation. Before we talk about it, let's look at a program first
package Demo; class Matcher{ public void eat(){ System.out.println("Would you like a roast pig?"); } } class Boy extends Matcher { public void eatKaoYang(){ System.out.println("Mom, I'd like to have roast mountain pig"); } } class Girl extends Matcher { public void eatKaoYang(){ System.out.println("Mom, I'd like to have roast mountain pig 2333"); } } public class Test { public static void main(String[] args) { Matcher g = new Girl();//Upward transformation compilation passed Boy x = (Boy)g;//Downward transformation x.eatKaoYang();//Compile passed, but run ClassCastException } //Run result: run ClassCastException }
This code can be compiled, but at runtime, ClassCastException and type conversion exception are reported! This is because clearly created a Girl type object, runtime, of course, can not be converted to a Boy object. These two types have no inheritance relationship and do not meet the definition of type conversion To avoid ClassCastException, Java provides the instanceof keyword to verify the type of reference variables.
Use of instanceof
Format of instanceof:
Variable name instanceof data type
Use of instanceof
Returns true if the variable belongs to the data type.
Returns false if the variable does not belong to the data type.
Therefore, before conversion, we'd better use instanceof to make a judgment first. The code is as follows:
package Demo; class Matcher{ public void eat(){ System.out.println("Would you like to roast yams?"); } } class Boy extends Matcher { public void eatKaoYang(){ System.out.println("Boy: Mom, I want to eat roast sheep"); } } class Girl extends Matcher { public void eatKaoYang(){ System.out.println("Girl: Mom, I want to roast the whole sheep 2333"); } } public class Test { public static void main(String[] args) { Matcher g = new Girl();//Upward transformation if(g instanceof Girl){ Girl x = (Girl)g;//Downward transformation x.eatKaoYang(); //=====================Call Girl's eatKaoYang() method }else if(g instanceof Boy){ //Non execution Boy x = (Boy)g;//Downward transformation x.eatKaoYang(); //=====================Call Boy's eatKaoYang() method } } } //Running result: Girl: Mom, I want to roast whole sheep 2333
Well, here you go. What do you get?
6. Re analysis of upward and downward transformation
After reading it, is it not clear enough to move up and down? The problem of polymorphic transformation is not complicated. Just remember one thing: the parent class reference points to the child class object. What is a parent reference to a child object? Let's take a look at the following example
There are two classes, Father is the parent class, and Son class inherits from Father.
First example:
// f1 reference to a Son object Father f1 = new Son(); // This is called upcasting // f1 still points to the Son object Son s1 = (Son)f1; // This is called downcasting
Second example:
// f1 now points to the parent object Father f2 = new Father(); Son s2 = (Son)f2; // Error, subclass reference cannot point to parent object
You may ask, in the first example: Son s1 = (Son)f1; why is it right. It's very simple because f1 points to a subclass object, Father f1 = new Son(); the subclass s1 reference can point to a subclass object of course.
While f2 is passed to a family object, the family f2 = new family(); the subclass s2 reference cannot point to the parent object.
7. The subtlety between polymorphism and constructor
Direct code:
package Polymorphic; class EatKaoShanYao { EatKaoShanYao () { System.out.println("Before eating roasted yam..."); eat(); System.out.println("After eating roasted yam(The bear child is confused)...."); } public void eat() { System.out.println("7 I like to eat roasted yam at the age of half a year"); } } public class KaoShanYao extends EatKaoShanYao { private String Weight = "110 Jin"; public KaoShanYao(String Weight) { this.Weight = Weight; System.out.println("Weight of bear child:" + this.Weight); } public void eat() { // Subclass override parent method System.out.println("The weight of the bear child before eating the roasted yam is:" + this.Weight); } //Main method public static void main(String[] args) { EatKaoShanYaok = new KaoShanYao("250 Jin"); } }
Children's shoes can try to think about the running results, and then look at the following output results
Operation result: Before taking the roasted yam The weight of bear child before eating roasted yam is: null After taking the roasted yam (the bear child is in a state of stupor) Weight of bear child: 250 Jin
Are you confused? What's the result? You see, the bear boy is confused again, Why?
The reason is very simple, because when creating a subclass object, the constructor of the parent class will be called first, and the polymorphic method covered by the subclass will be called in the constructor of the parent class. Because the parent class does not know what the property value of the subclass object is (the subclass has not been initialized when the parent class is initialized first), the property of String type is temporarily initialized to the default value of null, however Then call the constructor of the subclass (at this time, the subclass constructor has the initial Weight attribute, so the subclass constructor knows that the Weight of the bear child is 250).
If there is something you don't understand, you can tell me in time. The landlord is always there. And if there is something wrong with the landlord, please tell me in time. Be sure to tell me!!!
8. Advantages of polymorphism
After talking about polymorphism for so long, I don't think its advantages are obvious. But let's talk about the advantages of polymorphism in the actual development process. In the actual development, the type of parent class as the formal parameter of the method, passing the sub class object to the method, and calling the method, can more reflect the multi-state expansibility and convenience.
In order to better compare the advantages of polymorphism, the following program does not use polymorphism, the code is as follows:
package Demo; //Parent: Animal class Animal{ public void eat(){ System.out.println("eat"); } } //Feline class Cat { //Method rewriting public void eat(){ System.out.println("Cats eat cat bones"); } public void call(){ System.out.println("Cat cry"); } } //Dogs class Dog { public void eat(){ System.out.println("Dogs eat dog bones"); } public void call(){ System.out.println("dog's bark"); } } //Tools for animal operation class AnimalTool{ private AnimalTool(){}//Private the constructor of a tool class to prevent others from creating objects of that class. //Call cat's function public static void catLife(Cat c){ //Tool class, the method is written as static, and then directly used in the test class: tool class name. Method. c.eat(); c.call(); } //Call dog function public static void dogLife(Dog d){ d.eat(); d.call(); } } public class Test{ public static void main(String[] args){ Cat c= new Cat(); AnimalTool.catLife(c); Dog d= new Dog(); AnimalTool.dogLife(d); } } //Operation result: //Cats eat cat bones //Cat cry //Dogs eat dog bones //dog's bark
There are only two animals written here. If there is another animal, pig, you need to define a pig class, provide two methods for pig, and then add the corresponding XXLife method to the tool class. These three steps are all necessary. Moreover, for each additional animal, you need to add a corresponding XXLife method to the tool class, which is very troublesome to maintain. After all, there are thousands of animal types Ten thousand! Crash, it's OK to save you with polymorphism. Use polymorphism code as follows:
package Demo; //Parent: Animal class Animal{ public void eat(){ System.out.println("eat"); } public void call(){ System.out.println("call"); } } //Feline class Cat extends Animal { //Method rewriting public void eat(){ System.out.println("Cats eat cat bones"); } public void call(){ System.out.println("Cat cry"); } } //Dogs class Dog extends Animal { public void eat(){ System.out.println("Dogs eat dog bones"); } public void call(){ System.out.println("dog's bark"); } } //Tools for animal operation class AnimalTool{ private AnimalTool(){}//It's best to keep the constructor of a tool class private to prevent others from creating objects of that class. This class is a tool class. //Call all animal functions public static void animalLife(Animal a){ //Tool class, the method is written as static, and then directly used in the test class: tool class name. Method. a.eat(); a.call(); } } public class Test{ public static void main(String[] args){ Cat c= new Cat(); AnimalTool.animalLife(c); Dog d= new Dog(); AnimalTool.animalLife(d); //Operation result: //Cats eat cat bones //Cat cry //Dogs eat dog bones //dog's bark } }
Note: the above animal classes all inherit the animal parent class
At this time, we need to analyze again. If there is another Animal pig, we need to define a pig class, provide two methods for pig, and then inherit the Animal parent class. At this time, we don't need to add the corresponding XxLife method to the tool class, just write one animalLife method, and each more Animal doesn't need to add the corresponding XxLife method to the tool class, which is optimistic to maintain Now.
Because of the support of polymorphism, the Animal type of the animalLife method is the parent type of Cat and Dog. The parent type receives the child object. Of course, the Cat object and Dog object can be passed to the method When the eat and call methods are executed, polymorphism specifies that the method overridden by the subclass is executed, so the effect is naturally the same as that of the eat and call methods in the subclass of Animal, so the above two methods can be completely replaced by animalLife Not only substitution, but also extensibility. No matter how many subclasses appear later, we don't need to write the method of XxLife, which can be done directly by using animalLife Therefore, the advantage of polymorphism is that it can make the program easier to write and has good extension.
9. Analyze the nine questions at the beginning
Seeing this, I believe that children's shoes should have a certain understanding of polymorphism, and should be very confident to solve the opening problem. I can tell you very responsibly that you still can't solve these problems. Don't ask me why I know. You can try to do it again. The code is pasted below:
package Polymorphic; //Grandfather class class Ye { public String show(Sun obj) { return ("Ye and Sun"); } public String show(Ye obj) { return ("Ye and Ye"); } } //Papa class class Fu extends Ye { public String show(Fu obj) { return ("Fu and Fu"); } public String show(Ye obj) { return ("Fu and Ye"); } } //Son class class Zi extends Fu { } //Grandchildren class Sun extends Fu { } public class PolymorphicTest { public static void main(String[] args) { Ye y = new Ye(); Ye y2 = new Fu(); //Upward Fu f = new Fu(); Zi z = new Zi(); Sun s = new Sun(); System.out.println("First question " + y.show(f)); System.out.println("Second questions " + y.show(z)); System.out.println("Third questions " + y.show(s)); System.out.println("Fourth questions " + y2.show(f)); //Hang up here??? System.out.println("Fifth questions " + y2.show(z)); System.out.println("Sixth questions " + y2.show(s)); System.out.println("Seventh questions " + f.show(f)); System.out.println("Eighth questions " + f.show(z)); System.out.println("Ninth questions " + f.show(s)); } //Print results: //First question Ye and Ye //Ye and Ye //Third question Ye and Sun //Fu and Ye //Fifth question Fu and Ye //Ye and Sun //Fu and Fu //Fu and Fu //Ye and Sun }
To understand the above example, children's shoes must understand this sentence: when a parent class object references a variable to refer to a child class object, the type of the referenced object determines whose member method to call, and the type of the referenced variable determines the callable method. First, the method will be found in the parent class of the callable method, the method covered in the execution subclass will be found, and the method ready-made in the operator class will also be found in the parent class. It is not necessarily that there are ready-made methods in the execution subclass, but the subclass method that rewrites the method found in the parent class (the subclass here is the class method finally decided to call) . Are you dizzy? It's hard to understand that it's not the mouth, but the head. I haven't heard the word. Cough, it's not a big problem. The landlord will explain it to you in a popular way so that you can understand it.
Do you remember how to define the upward transformation of the previous definition of the landlord?
[v8 prompt] upward Transformation: polymorphism itself is the process of upward transformation from subclass type to parent type, and this process is the default. You can understand this process as automatic conversion of basic types from small types to large types without coercion When a parent class reference points to a child class object, it is an upward transition
But do you really understand? What is a parent object referencing a variable referencing a child object? In fact, we have to find out from the following sentence
Definition of upward Transformation: polymorphism itself is the process of upward transformation from subclass type to parent type, and this process is the default
Just like Father f = new Son(); some children's shoes will say that this f is also an object reference of the parent class? What if it's literally a reference to a subclass, but the type of the reference is the parent type? At this point, you are very wrong.
Let's simplify the definition of upward transformation as follows:
The process of converting a subclass type to a parent type by default
Do you understand now? This sentence can be understood as the code of "Father f = new Son()" originally was "Father f = (Father) new Son()", but this transformation process is automatic by default. Generally speaking, new Son() is actually new Father in essence, so f is actually the reference of parent class object! At this time, I'd like to open up and understand the following passage
When a parent object references a variable references a child object
The parent object refers to F, and the child object refers to new Son (), so the total is when f refers to new Son()
The type of the referenced object determines whose member method to call, and the reference variable type determines the callable method.
The type of the referenced object here refers to the Son type in the new Son() object, and the reference variable type refers to the type of f, the type of Father
Well, to sum up, when: F references new Son(), Son decides to call its member method, and Father decides to call the method in Father. So take the example of Father f = new Son(), which is simply
10. Finally, let's formally analyze the nine questions
The first three don't involve polymorphism (upward transformation), so only methods of yeye's own class will be called. Here, as long as you have the knowledge of inheritance, it's OK.
Before the fourth question, is your answer "Fu and Fu"? Come on, let's have a multi-faceted outlook on life!
Analysis of the fourth question: firstly, Ye y2 = new Fu(); upward transformation, so we will first find the show(f) method in the parent Ye class of the fu class, find the show(Ye obj) method, and then go back to the fu class to see if there is a show(Ye obj) rewrite method. We find that the fu class has a show(Ye obj) method (rewrite), so we finally execute "Fu and Ye". What do you get?
In fact, the fifth question is almost the same as the fourth one, the fourth one is y2.show(f); the fifth one is y2.show(z); but the method parameters of show are different, the same is that f and Z find show(Ye obj) method in the Ye class, so the final results of the fourth and fifth questions are the same!
Analyzing the sixth question, the sixth question is actually quite interesting. First, y2.show(s), find show(Sun obj) in the Ye class, and then check whether there is any override in the subclass. It is found that there is no show(Sun obj) override method. Are you sure? Don't forget that this is inheritance. By default, there is a method of the parent class ye in the subclass Fu, but it's not represented on the surface. From another perspective, a show(Sun obj) method is rewritten by default in the fu class, even if it's not written, it also exists, so the running result is "Ye and Sun"
The seventh and eighth questions will not be analyzed, after all, there is no upward transformation (polymorphism).
Finally, I will analyze the ninth question. Some children's shoes are about to hit the landlord. The ninth question does not involve the upward transformation (polymorphism). The landlord is a star (* *). Of course, even if the landlord carries the black pot, he will also analyze the ninth question ~ that's how proud she is ~. It does not involve the upward transformation (polymorphism). The reason I want to talk about is very simple, because I think it is still necessary! First of all, f.show(s) does not involve polymorphism. It only calls methods of its own class (Fu), but you will find that there is no show(s) in Fu. Alas, I ran the language you reorganized, and forgot? This is inheritance. It has the show(Sun obj) method duck in the default parent class Ye! Well here, I summed up a point, you are polymorphic and no problem, but your inheritance knowledge is weak, no no no, the landlord has to make up for you, still hesitant what duck, come to make up for the inheritance knowledge!!! [java foundation] java inheritance starts from "my father is Li Gang"
At the end of this article, I'm just a person's understanding of polymorphism. The landlord is just a java Xiaobai. It's OK to call me Laobai. It's not necessarily all right. If there's any mistake, please let me know. Thank you very much! Welcome to correct~
Finally, if this article is helpful to you, please give me some love and support~
You are welcome to pay attention to my public address, explore technology, yearn for technology and pursue technology.