Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of Polymorphism, Abstract Class and Interface in Java

2025-01-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

Editor to share with you the example analysis of polymorphisms, abstract classes and interfaces in Java. I believe most people don't know much about it, so share this article for your reference. I hope you will gain a lot after reading this article. Let's learn about it together.

1. Polymorphism 1. Upward transformation

What is upward transformation? To put it simply,

Assigns the subclass object to the reference of the parent object

What does this mean? we can look at the following code

/ / suppose Animal is the parent class and Dog is the subclass public class TestDemo {public static void main (String [] args) {Animal animal=new Animal ("animal"); Dog dog=new Dog ("Erha"); animal=dog;}}

Where the object of the subclass reference dog is assigned to the reference of the parent class, and the above code can also be simplified to

Public class TestDemo {public static void main (String [] args) {Animal animal=new Dog ("Erha");}}

This is actually the same as the above code, which is called "upward transformation", which assigns the reference of the subclass object to the reference of the parent class.

In fact, more may be used after the upward transformation, so when do we need to use it?

Direct assignment

Methods to transfer parameters

Method returns

The direct assignment is what the above code looks like. Next, let's take a look at an example of a method passing parameters.

/ / suppose Animal is the parent class and Dog is the subclass public class TestDemo {public static void main (String [] args) {Animal animal=new Dog ("Erha"); func (animal);} public static void func1 (Animal animal) {}}

We write a function where the parameter is the reference to the parent class, and the argument passed is the object referenced by the subclass. It can also be written as

Public class TestDemo {public static void main (String [] args) {Animal animal=new Animal (animal); Dog dog=new Dog ("Erha"); func (dog);} public static void func1 (Animal animal) {}}

So what does the method return look like? In fact, it is also very simple, such as

/ / suppose Animal is the parent class and Dog is the subclass public class TestDemo {public static void main (String [] args) {} public static Animal func2 () {Dog dog=new Dog ("Erha"); return dog;}}

In the func2 method, the object of the subclass is returned to the reference of the parent class. There is also a way to return

Public class TestDemo {public static void main (String [] args) {Animal animal=func2 ();} public static Dog func2 () {Dog dog=new Dog ("Erha"); return dog;}}

The return value of the method is a reference to the subclass and then assigned to the object of the parent class, which is also called "upward transformation".

So since the reference to our parent class points to the object referenced by the child class, can the parent class use some of the methods of the child class? Try it

Class Animal {public String name; public Animal (String name) {this.name=name;} public void eat () {System.out.println (this.name+ "eat" + "(Animal)");}} class Dog extends Animal {public Dog (String name) {super (name);} public void eatDog () {System.out.println (this.name+ "eat" + "(Dog)") }} public class TestDemo {public static void main (String [] args) {Animal animal1=new Animal ("animal"); Animal animal2=new Dog ("Erha"); animal1.eat (); animal2.eatdog ();}}

The result is no.

Because the reference type of animal is essentially Animal, you can only use members and methods in your own class.

two。 Dynamic binding

So can our animal2 use the eatDog method in the Dog class? Actually, we can, as long as we change the name of the eatDog to eat.

Class Dog extends Animal {public Dog (String name) {super (name);} public void eat () {System.out.println (this.name+ "eat" + "(Dog)");}}

The modified part of the code is as above. At this point, our previous animal2 calls eat directly, and you can get the following result

This means that at this time

Animal1.eat () actually calls the method of the parent class

What animal2.eat () actually calls is the method of the subclass

So why is it that after changing eatDog to eat, animal2.eat calls the methods of the subclass?

That's what we're going to rewrite next.

3. Method rewriting

What is rewriting?

The subclass implements the method of the parent class with the same name, and

Method name is the same

The return value of the method is generally the same

Method has the same parameter list

To meet the above situation is called: rewrite, overwrite, overwrite (Override)

Note:

The rewritten method cannot be a sealed method (that is, a method modified by final). We have seen the keyword final before, and the method modified by him is called the sealing method, which can no longer be rewritten, such as

/ / if this is the method public final void eat () {System.out.println (this.name+ "want to eat") in the parent class;}

This kind of method cannot be overridden

The access modifier qualifier permission of the subclass must be greater than or equal to the permission of the parent class, but the parent class cannot be modified by private

Method cannot be modified by static

In general, for overridden methods, you can use the @ Override annotation to display the specified. What's the advantage of adding him? Look at the following code

/ / if the following eat is the overridden method class Dog extends Animal {@ Override private void eat () {/ /...}}

When we see that eat is written as ate, then the compiler will find that there is no ate method in the parent class, and will compile an error, indicating that it cannot constitute an override.

The return value can be modified when overridden, and the method name and parameter type and number cannot be modified. Only if the return value is a class type, the overridden method can modify the return value type and must be a subclass of the return value of the parent method, or it will not be modified, which is the same as the return type of the parent class.

Knowing this, everyone must have a concept of rewriting. At this point, let's recall the overloading we learned before, and we can make a table for comparison.

Distinguishing overloading (Overload) overriding (Override) concept method name is the same, parameter list is different, return value is not required method name is the same, parameter list is the same, return type is generally the same scope overload is not necessary in a class (inheritance) inheritance relationship restrictions methods without permission requirements overridden methods cannot have stricter access control permissions than parent classes

The result of comparison is that there is no relationship between the two.

At this point, we don't seem to have explained what the title of the previous section is dynamic binding.

So what is dynamic binding? The conditions that occur are as follows

Upward transformation occurs (parent class references need to reference subclass objects)

Call the override method with the same name of the child class and the parent class through the parent class reference

Then why is it called dynamic? After disassembly, we can find out

At compile time: the method of the parent class is called

But at run time: the method of the subclass is actually called

So this is actually a dynamic process, and you can also call it runtime binding.

4. Downward transformation

Now that we have introduced the upward transformation, there must be no shortage of downward transformation. When will it turn down? If you think about the upward transformation, you can guess that it is

Assigns the parent class object to the reference of the subclass object

So changing it to the code is

/ / suppose Animal is the parent class and Dog is the subclass public class TestDemo {public static void main (String [] args) {Animal animal=new Animal ("animal"); Dog dog=animal;}}

However, it is not possible to write this way as mentioned above, and it will report an error.

Why? We can think of it this way.

Dogs are animals, but animals can not be said to be dogs, which is equivalent to an inclusive relationship.

Therefore, the object of the dog can be assigned directly to the animal, but not to the dog.

We can use cast so that the above code doesn't get it wrong.

Public class TestDemo {public static void main (String [] args) {Animal animal=new Animal ("animal"); Dog dog= (Dog) animal;}}

Let's then run the eat method with a dog reference

Public class TestDemo {public static void main (String [] args) {Animal animal=new Animal ("animal"); Dog dog= (Dog) animal; dog.eat ();}}

An error occurred after running

Animals cannot be converted into dogs!

So what are we supposed to do? We have to remember one thing:

The premise of using a downward transition is that an upward transition must take place.

Public class TestDemo {public static void main (String [] args) {Animal animal=new Dog ("Erha"); Dog dog= (Dog) animal; dog.eat ();}}

There will be no problem!

As we mentioned above, the premise of using downward transformation is that upward transformation takes place. In fact, we can understand that when we use the upward transformation, some functions can not be achieved, so we use the downward transformation to improve the code (emmm, purely personal folly). Like...

/ / suppose I have a housekeeping method in my Dog class, guardpublic class TestDemo {public static void main (String [] args) {Animal animal=new Dog ("Erha"); animal.guard ();}}

The above code will report an error because there is no guard method in the Animal class. So we have to borrow the downward transformation.

Public class TestDemo {public static void main (String [] args) {Animal animal=new Dog ("Erha"); Dog dog = animal; dog.guard ();}}

Note:

In fact, the downward transformation is not often used, and you may accidentally make some mistakes when using it. If our above code continues to use some of the unique methods of other animals, we will report an error if we forget that they have not undergone an upward transformation.

To avoid this error: we can use instanceof

Instanceof: you can determine whether a reference is an instance of a class. If so, return true. If not, return false, as shown in

Public class TestDemo {public static void main (String [] args) {Animal animal=new Dog ("Erha"); if (animal instanceof Bird) {Bird bird= (Bird) animal; bird.fly ();}

The above code first determines whether the reference to Animal is an instance of Bird. We know that it should be an instance of Dog, so we return false.

5. Keyword super

In fact, the super keyword has been explained in the previous chapter. Here, I will use a table to compare this and super, which is easy to understand.

6. Call the override method (pit) in the constructor

Next, let's look at a piece of code, and you can guess what the result is!

Class Animal {public String name; public Animal (String name) {eat (); this.name=name;} public void eat () {System.out.println (this.name+ "eating (Animal)");}} class Dog extends Animal {public Dog (String name) {super (name);} public void eat () {System.out.println (this.name+ "eating (Dog)") }} public class TestDemo {public static void main (String [] args) {Dog dog=new Dog ("Erha");}}

As a result,

If you don't guess correctly, there are usually two doubts:

The eat method is not called, but why is the result like this?

Why null?

Answer:

Doubt 1: because the subclass inherits the parent class needs to help the parent class construct methods, so when the subclass creates an object, it constructs the parent class constructor and executes the parent class's eat method

Doubt 2: since the parent class constructor executes the eat method first, and the assignment of name is in the later step, most of the name at this time is null.

Conclusion:

The overridden method can be called in the constructor, and dynamic binding occurs

7. Understanding polymorphism

At this point, we are finally going to formally introduce one of our key polymorphisms today! So what is polymorphism? In fact, it is the same idea as inheritance. We can look at a piece of code first.

Class Shape {public void draw () {}} class Cycle extends Shape {@ Override public void draw () {System.out.println ("draw a circle ⚪");}} class Rect extends Shape {@ Override public void draw () {System.out.println ("draw a square ♦");}} class Flower extends Shape {@ Override public void draw () {System.out.println ("draw a flower") }} public class TestDemo {public static void main (String [] args) {Cycle shape1=new Cycle (); Rect shape2=new Rect (); Flower shape3=new Flower (); drawMap (shape1); drawMap (shape2); drawMap (shape3);} public static void drawMap (Shape shape) {shape.draw ();}}

We find that when the drawMap method is used by the caller, the draw method is called by the parent class, and the final representation is different. And this kind of thought is called polymorphism.

To put it more simply, polymorphism is

A citation can show many different forms.

Polymorphism is a kind of thought, and there are two prerequisites to realize it.

Upward transformation

Call the override method with the same name

And the inheritance of an idea always has its unique benefits, so what are the benefits of using polymorphism?

1) the cost of using the class by class callers is further reduced.

Encapsulation is so that the caller of the class does not need to know the implementation details of the class

Polymorphism allows the caller of a class to not even know what the type of the class is, as long as the object has a method.

2) it can reduce the cyclomatic complexity of the code and avoid using a large number of if-else statements.

Cyclomatic complexity:

Is a way to describe the complexity of a piece of code. You can think of the number of conditional statements and loop statements in a piece of code as "cyclical complexity". The more this number, the more complex it is to understand.

We can look at a piece of code.

Public static void drawShapes () {Rect rect = new Rect (); Cycle cycle = new Cycle (); Flower flower = new Flower (); String [] shapes = {"cycle", "rect", "cycle", "rect", "flower"}; for (String shape: shapes) {if (shape.equals ("cycle")) {cycle.draw () } else if (shape.equals ("rect")) {rect.draw ();} else if (shape.equals ("flower")) {flower.draw ();}

This code means to print circles, squares, circles, squares, and flowers, respectively. If we don't use polymorphism, we usually write this method. With polymorphism, the code appears simple, such as

Public static void drawShapes () {/ / We created an array of Shape objects. Shape [] shapes = {new Cycle (), new Rect (), new Cycle (), new Rect (), new Flower ()}; for (Shape shape: shapes) {shape.draw ();}}

We can understand the above code through the following diagram

On the whole, it looks a lot easier to use polymorphic code.

3) strong scalability

As in the above drawing code, if we want to add a new shape, the cost of using polymorphism is also relatively low, such as

/ / add triangle class Triangle extends Shape {@ Override public void draw () {System.out.println ("△");}}

If we use polymorphism, we can add a new class to our extended code. In the case where polymorphism is not used, the if-else statement needs to be modified, so the cost of modification will be higher.

8. Summary

So far, the three major features of object-oriented: encapsulation, inheritance, and polymorphism have all been introduced. As my personal understanding is also limited, so the speech may not be good and insufficient. I hope you can understand it more.

Next, we will introduce abstract classes and interfaces, which will also be further applied to polymorphism, so we can practice a lot and deepen our understanding of our thoughts.

Second, abstract class 1. Concept

We just wrote a graphic code above, in which the definition of the parent class is like this

Class Shape {public void draw () {}}

We found that there is no content in the draw method in the parent class, and the drawing is done through the draw methods of various subclasses.

Like the above code, which has no actual work, we can design it as an abstract method through abstract, and the class that contains the abstract method is the abstract class.

This is the code after the design.

Abstract class Shape {public abstract void draw ();} 2. Matters needing attention

Methods and classes are decorated by abstract

Other data members and member methods can be defined in abstract classes, such as

Abstract class Shape {public int a; public void b () {/ /...} public abstract void draw ();}

But to use these members and methods, you need to rely on subclasses to use the super

Abstract classes cannot be instantiated

Abstract methods cannot be modified by private

Abstract methods cannot be modified by final, they cannot coexist with abstract

If the subclass inherits the abstract class, but does not need to override the abstract method of the parent class, you can decorate the subclass with abstract, as shown in

Abstract class Shape {public abstract void draw ();} abstract Color extends Shape {}

At this point, both ordinary and abstract methods can be defined in this subclass.

An abstract class A can be inherited by another abstract class B, but if another ordinary class inherits abstract class B, that ordinary class needs to override all abstract methods in An and B.

3. The meaning of abstract classes

We need to know that the meaning of abstract classes is to be inherited.

You know from the considerations that the abstract class itself cannot be instantiated, and if you want to use it, you can only create subclasses to inherit, such as

Abstract class Shape {public int a; public void b () {/ /...} public abstract void draw ();} class Cycle extends Shape {@ Override public void draw () {System.out.println ("draw a ⚪");}} public class TestDemo {public static void main (String [] args) {Shape shape=new Cycle ();}

Note that the subclass needs to override all abstract methods of the parent class, otherwise the code will report an error

3. The role of abstract classes

So why use an abstract class if it can't be instantiated?

The use of abstract classes is equivalent to the effectiveness of a compiler.

What do you mean? For example, according to the above drawing code, the actual work is actually done by the subclass. if you accidentally misuse the parent class, the parent class will not report an error if it is not an abstract class, so the parent class is designed as an abstract class. it will report an error when the parent class is instantiated, so let's find the error as soon as possible.

III. Interface

We introduced abstract classes above, which can contain ordinary methods and members in addition to abstract methods.

Interfaces can also contain methods and fields, but only abstract methods and static constants.

1. rule of grammar

We can rewrite the above Shape into an interface with the following code

Interface IShape {public static void draw ();}

The specific grammar rules are as follows:

The interface is defined using interface

The naming of an interface usually begins with an uppercase I

The methods in the interface must be abstract and decorated by public, so the abstract method can simplify the code to

Interface IShape {void draw ();}

If you write it this way, the default is public abstract.

The interface can also contain static constants modified by public, and public static final can be omitted, as shown in

Interface IShape {public static final int axi10; public static int baked 10; public int cantilever 10; int dumped 10;}

Interfaces cannot be instantiated separately and need to be inherited by subclasses like abstract classes, but implements inheritance is used in interfaces, such as

Interface IShape {public static void draw ();} class Cycle implements IShape {@ Override public void draw () {System.out.println ("draw a circle in advance");}}

Unlike extends, which means "extension", implements means "implementation", which means that there is nothing at present and everything needs to be constructed from scratch.

The class of the underlying interface needs to override all abstract methods in the interface

A class can implement multiple interfaces using implements, each separated by a comma, as shown in

Interface A {void func1 ();} interface B {void func2 ();} class C implements Override public void func1 B {@ Override public void func1 () {} @ Override public void func2 {}}

Note that this class overrides all abstract methods of all inherited interfaces and uses ctrl + I in IDEA to quickly implement the interface.

The relationship between interfaces and interfaces can be maintained using extends, which means "extension", that is, one interface extends the functionality of other interfaces, such as

Interface A {void func1 ();} interface B {void func2 ();} interface D implements Override public void func1 B {@ Override public void func1 () {} @ Override public void func2 {} void func3 ();}

Note:

At the beginning of JDK1.8, the method in an interface can be a normal method, but only if the method is modified by default (that is, the default method for this interface), as shown in

Interface IShape {void draw (); default public void func () {System.out.println (default method);}} 2. Implement multiple interfaces

As we mentioned earlier, inheritance in Java is single inheritance, that is, a class can inherit only one parent class.

However, multiple interfaces can be implemented at the same time, so we can achieve the similar effect of multi-inheritance through multiple interfaces.

Then understand it through the code!

Class Animal {public String name; public Animal (String name) {this.name=name;}} class Bird extends Animal {public Bird (String name) {super (name);}}

At this point, the subclass Bird inherits the parent class Animal, but can no longer inherit other classes, but can continue to implement other interfaces, such as

Class Animal {public String name; public Animal (String name) {this.name=name;}} interface ISwing {void swing ();} interface IFly {void fly ();} class Bird extends Animal implements ISwing,IFly {public Bird (String name) {super (name);} @ Override public void swing () {System.out.println (this.name+ "swimming") } @ Override public void fly () {System.out.println (this.name+ "flying");}}

The above code is equivalent to the implementation of multiple inheritance, so the emergence of the interface solves the problem of Java single inheritance very well.

And we can feel that the interface seems to have a certain property, so with the interface, the users of the class do not have to pay attention to the specific type, but only pay attention to whether the class has a certain capability, such as

Public class TestDemo {public static void fly (IFly flying) {flying.fly ();} public static void main (String [] args) {IFly iFly=new Bird (Flying Bird); fly (iFly);}}

Because the flying bird itself has the property of flying, we don't have to pay attention to the specific type, because as long as it can fly, it can realize the property of flying, such as Superman can also fly, we can define a class of Superman.

Class SuperMan implements IFly {@ Override public void fly () {System.out.println ("Superman is flying");}} public class TestDemo {public static void fly (IFly flying) {flying.fly ();} public static void main (String [] args) {fly (new SuperMan ());}}

Note:

The subclass inherits the parent class before implementing the interface

3. Inheritance of interface

As described in the syntax rules, interfaces and interfaces can be maintained using extends, which allows one interface to extend the functions of other interfaces.

I won't repeat it here.

Let's learn some more interfaces to deepen our understanding of the interfaces.

4. Comparable interface

We have previously introduced the sort method in the Arrays class, which can help us sort, such as

Public class TestDemo {public static void main (String [] args) {int [] array= {2pje 9pc 4je 1je 7}; System.out.println ("before sorting:" + Arrays.toString (array)); Arrays.sort (array); System.out.println ("after sorting:" + Arrays.toString (array));}}

And then I want to sort the attributes of a student.

First I implemented a Student class and overridden the toString method

Class Student {private String name; private int age; private double score; public Student (String name, int age, double score) {this.name = name; this.age = age; this.score = score } @ Override public String toString () {return "Student {" + "name='" + name +'\'+ ", age=" + age + ", score=" + score +'}';}}

Then I wrote an array and assigned some properties to the student array.

Public class TestDemo {public static void main (String [] args) {Student [] student=new Student [3]; student [0] = new Student ("Zhang San", 18LJ 96.5); student [0] = new Student ("Li Si", 19Med 99.5); student [0] = new Student ("Wang Wu", 17J 92.0);}}

So can we sort directly through the sort function? Let's write the following code first

Public class TestDemo {public static void main (String [] args) {Student [] student=new Student [3]; student [0] = new Student ("Zhang San", 18lle 96.5); student [1] = new Student ("Li Si", 19lle 99.5); student [2] = new Student ("Wang Wu", 17jue 92.0); System.out.println ("before ranking:" + student); Arrays.sort (student) System.out.println ("after sorting:" + student);}}

But the end result is

Let's analyze it.

ClassCastException: type conversion exception, saying that Student cannot be converted to java.lang.Comparable

What does this mean? We thought that since Student is our custom type, it contains multiple types, so how does the sort method sort it? There seems to be no basis.

At this point, I found Comparable by reporting an error.

You can know that this is supposed to be an interface, so we can try to inherit our Student class to this interface, where the following

< T >

It actually means generics, which is changed here to

< Student >

Just do it.

Class Student implements Comparable {public String name; public int age; public double score; public Student (String name, int age, double score) {this.name = name; this.age = age; this.score = score } @ Override public String toString () {return "Student {" + "name='" + name +'\'+ ", age=" + age + ", score=" + score +'}';}}

But not yet, because inheritance needs to override the abstract method of the interface, so after searching, we found

The added rewriting method is

@ Overridepublic int compareTo (Student o) {/ / New comparison rules}

This should be where the rules are set. Let's take a look at the exchange in the sort method.

That is, if the left value at this time is greater than the right value, then swap

So if I want to sort the age of the students, the method after rewriting should be

@ Overridepublic int compareTo (Student o) {/ / New comparison rule return this.age-o.age;}

Run the code again at this point, and the result is

At this point, we can feel more deeply that an interface is actually a certain attribute or capability, and the above Student class inherits this comparative interface and has the ability to compare.

Disadvantages:

When we compare the names of the above code, we need to change the rewriting method to

@ Overridepublic int compareTo (Student o) {/ / New comparison rule return this.name.compareTo (o.name);}

When we compare the scores of the above code, we need to change the rewriting method to

@ Overridepublic int compareTo (Student o) {/ / New comparison rule return int (this.score-o.score);}

We find that when we want to modify something to compare, we may have to change the method of rewriting. This limitation is relatively large.

To address this defect, the following interface Comparator appears

4. Comparator interface

We can also see a comparison method in the definition of the sort method, where there are two parameter arrays and objects of Comparator

The Comparator interface is used here.

What is this interface? We can first define an age comparison class AgeComparator, which is specifically used to compare age, and let him inherit this class.

Class AgeCompartor implements Comparator {}

By holding down ctrl and clicking on it, we can jump to its definition, and we can find that there is a method in it

This is different from the compareTo in the above Comparable, so I'll rewrite it first.

Class AgeCompartor implements Comparator {@ Override public int compare (Student o1, Student o2) {return o1.ageMuro2.age;}}

Let's write the following code as described in the sort method

Public class TestDemo {public static void main (String [] args) {Student [] student=new Student [3]; student [0] = new Student ("Zhang San", 18lle 96.5); student [1] = new Student ("Li Si", 19lle 99.5); student [2] = new Student ("Wang Wu", 17jue 92.0); System.out.println ("before ranking:" + Arrays.toString (student)); AgeComparator ageComparator=new AgeComparator () Arrays.sort (student,ageComparator); System.out.println ("after sorting:" + Arrays.toString (student));}}

In this way, we can normally compare the age of the students, and at this point we want to sort the names again, so we can create a name comparison class NameComparator.

Class NameComparator implements Comparator {@ Override public int compare (Student o1, Student O2) {return o1.name.compareTo (o2.name);}}

And we just need to change the parameter ageComparator of the sort method to nameComparator.

We can think of the above AgeComparator and NameComparator as comparators, and the limitation of using Comparator is much less than Comparable. If we want to compare an attribute, we only need to add its comparator.

5. Cloneable interface and deep copy

First of all, we can look at the code like this.

Class Person {public String name= "LiXiaobo"; @ Override public String toString () {return "Person {" + "name='" + name +'\'+'}';}} public class TestDemo {public static void main (String [] args) {Person person=new Person ();}}

So what is cloning? It should be to make a copy, such as

So since I'm talking about the Cloneable interface this time, I'll inherit it!

Class Person implements Cloneable {public String name= "LiXiaobo"; @ Override public String toString () {return "Person {" + "name='" + name +'\'+'}';}}

But we found that even after inheritance, we could not find a method of cloning through the reference we created. At this point, we can click on the definition of Cloneable.

That's awesome! there's nothing!

We found that the Cloneable interface is an empty interface (also known as the tag interface), and the purpose of this interface is: if a class implements this interface, it proves that it can be cloned.

Before using it, we also need to rewrite the cloning method of Object (all classes inherit from the Object class by default)

How to rewrite the cloning method? Through ctrl + o, you can see

Then choose clone, and the rewritten code becomes

Class Person implements Cloneable {public String name= "LiXiaobo"; @ Override public String toString () {return "Person {" + "name='" + name +'\'+'}';} @ Override protected Object clone () throws CloneNotSupportedException {return super.clone ();}}

And at this point we can see a clone method

After clicking on it, we found that we still reported an error.

The reason is that because the rewritten clone method throws an exception, there are two ways to solve this problem. Let's introduce a simpler one today.

Method 1: place the mouse over the clone, hold down Alt + enter, and you will see

Just click on the red box, but you will find that you still report an error after clicking, because the return value of the overridden method is Object, and the compiler will think it is unsafe, so you can force it to Person. At this point, we output the copy of the clone and find that there is no problem.

And by printing the address, the copy is different from the original address.

At this point, the simple cloning process is over. But then let's go a little deeper and add shaping a to the original code of the Person class.

Class Person implements Cloneable {public String name= "LiXiaobo"; public int axi10; @ Override public String toString () {return "Person {" + "name='" + name +'\'+'}'; @ Override protected Object clone () throws CloneNotSupportedException {return super.clone ();}}

At this point, we will print through person and person respectively. The code is as follows.

Public class TestDemo3 {public static void main (String [] args) throws CloneNotSupportedException {Person person=new Person (); Person person1= (Person) person.clone (); System.out.println (person.a); System.out.println (person1.a); System.out.println ("#"); person1.a=50; System.out.println (person.a) System.out.println (person1.a);}}

The results are as follows

We found that in this case, person1 is a complete copy, and modifying it has nothing to do with person.

But let's look at the following situation, where we define a Money class and create it in Person

Class Money {public int money=10;} class Person implements Cloneable {public String name= "LiXiaobo"; public Money money=new Money (); @ Override public String toString () {return "Person {" + "name='" + name +'\'+'}'; @ Override protected Object clone () throws CloneNotSupportedException {return super.clone ();}}

Then we modify the value of money in person1, as follows

Public class TestDemo3 {public static void main (String [] args) throws CloneNotSupportedException {Person person=new Person (); Person person1= (Person) person.clone (); System.out.println (person.money.money); System.out.println (person1.money.money); System.out.println ("#"); person.money.money=50; System.out.println (person.money.money) System.out.println (person1.money.money);}}

The result this time is

Why is that? We can analyze the following pictures.

Because the object of person is cloned, only the money of (0x123) is cloned, but the money of (0x456) is not cloned, so even if the cloned copy of the previous money points to it, it will be changed if you change the money of the copy.

The above situation is actually called a shallow copy, so how to turn it into a deep copy?

We just need to clone a copy of the object that the money reference points to.

Steps:

The Money class also implements the Cloneable interface and overrides the cloning method

Class Money implements Cloneable {public int money=10; @ Override protected Object clone () throws CloneNotSupportedException {return super.clone ();}}

Modify the cloning method in Person

@ Overrideprotected Object clone () throws CloneNotSupportedException {Person personClone= (Person) super.clone (); personClone.money= (Money) this.money.clone (); return personClone;} is all the contents of the article "sample Analysis of Polymorphisms, Abstract classes and Interfaces in Java". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report