Learning objectives:
Encapsulation, polymorphism
Learning content:
Encapsulation is one of the three characteristics of object-oriented. The reasonable encapsulation of the program makes the external call more convenient and more conducive to writing. At the same time, it is easier for implementers to modify and revise the code.
1. Function and meaning of encapsulation
What needs to be known to the user is exposed, and all that does not need to be known to the user is hidden. This is encapsulation. To be professional, encapsulation is to combine the attributes and operations of the object into an independent whole, and hide the interior of the object as much as possible to achieve details.
Our programming should pursue "high cohesion and low coupling". High cohesion means that the internal data operation details of the class are completed by themselves, and external interference is not allowed; Low coupling is to expose only a small number of methods for external use, so as to facilitate external calls as much as possible.
Specific advantages of encapsulation in programming:
- Improve code security
- Improve code reusability
- "High cohesion": encapsulate details, facilitate modification of internal code and improve maintainability
- "Low coupling": simplify external use, facilitate the use of callers, and facilitate expansion and cooperation.
Example 1 code demonstration without encapsulation
class Person { String name; int age; @Override public String toString(){ return "Person [name="+name+",age="+age+"]"; } } public class Test{ public static void main(String[] args){ Person p = new Person(); p.name = "Zhang San"; p.age = -45; //Age can be assigned arbitrarily in this way without any restrictions System.out.println(p); } }
2. Implementation of encapsulation – using access control characters
Java uses "access control characters" to control which details need to be encapsulated and which details need to be exposed. The four "access control characters" in Java are private, default, protected and public. They illustrate the encapsulation of object-oriented, so we should use them to minimize access rights as much as possible, so as to improve security.
The scope of access authority is shown in the table below.
- Private means private, which can only be accessed by its own class
- default means that there is no modifier, and only classes of the same package can access it
- protected means that it can be accessed by a package's class and subclasses in other packages
- public means that it can be accessed by all classes in all packages of the project
[note]
- If the parent class and the child class are in the same package, the child class can access the protected member of the parent class and the protected member of the parent object.
- If the subclass and the parent class are not in the same package, the subclass can access the protected member of the parent class, but not the protected member of the parent object.
3. Use details of package
- Property typically uses private access. After the property is private, corresponding get/set methods are provided to access relevant properties. These methods are usually public modified to provide assignment and reading operations for the property (Note: the get method of boolean variable starts with is!).
- Methods: some auxiliary methods only used for this class can be modified with private. It is hoped that the methods called by other classes can be modified with public.
Example 2 JavaBean encapsulation demonstration
public class Person{ //Attributes are usually decorated with private private String name; private int age; private boolean flag; //Provide public modified set/get methods for attributes public String getName(){ return name; } public void setName(String name){ this.name = name; } public int getAge(){ return age; } public void setAge(int age){ this.age = age; } public boolean isFlag(){ //Note: the property get method of boolean type starts with is return flag; } public void setFlag(boolean flag){ this.flag = flag; } }
Example 3 use of packaging
class Person { private String name; private int age; public Person() { } public Person(String name, int age) { this.name = name; // this.age = age;// You cannot directly assign values in the constructor. You should call the setAge method setAge(age); } public void setName(String name) { this.name = name; } public String getName() {return name; } public void setAge(int age) { //Judge whether the age is legal before assignment if (age > 130 || age < 0) { this.age = 18;//Illegal default value 18 } else { this.age = age;//Only legal can be assigned to attribute age } } public int getAge() { return age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } } public class Test2 { public static void main(String[ ] args) { Person p1 = new Person(); //p1.name = "Xiaohong"// Compilation error //p1.age = -45; // Compilation error p1.setName("Xiao Hong"); p1.setAge(-45); System.out.println(p1); Person p2 = new Person("Xiaobai", 300); System.out.println(p2); } }
4. Concept and implementation of polymorphism
Polymorphism refers to the same method call, which may have different behaviors due to different objects.
Key points of polymorphism:
- Polymorphism is the polymorphism of methods, not attributes (polymorphism has nothing to do with attributes)
- There are three necessary conditions for polymorphism: inheritance, method rewriting, and parent class reference pointing to child class objects.
- After the parent class reference points to the child class object, the method overridden by the child class is called with the parent class reference, and polymorphism occurs.
Example 4 polymorphism and type conversion
class Animal { public void shout() { System.out.println("A cry!"); } } class Dog extends Animal { public void shout() { System.out.println("Wang Wang!"); } public void seeDoor() { System.out.println("Watch the door .... "); } } class Cat extends Animal { public void shout() { System.out.println("Meow meow! "); } } public class TestPolym { public static void main(String[ ] args) { Animal a1 = new Cat(); // Upward can automatically transform //The specific method passed is to call the method of which class. It greatly improves the scalability of the program. animalCry(a1); Animal a2 = new Dog(); animalCry(a2); //a2 is the compilation type, and the Dog object is the runtime type. /*When writing a program, if you want to call a method of runtime type, you can only cast it. * Otherwise, it will not pass the compiler check.*/ Dog dog = (Dog)a2;//Cast down required dog.seeDoor(); } // With polymorphism, you only need to let the added class inherit the Animal class. static void animalCry(Animal a) { a.shout(); } /* If there is no polymorphism, we need to write many overloaded methods here. * Each time an animal is added, it is necessary to overload the shouting method of an animal. Very troublesome. static void animalCry(Dog d) { d.shout(); } static void animalCry(Cat c){ c.shout(); }*/ }
The above example shows a common usage of polymorphism: the parent class reference is used as the formal parameter of the method, and the actual parameter can be any subclass object, and different behavior modes can be realized through different subclass objects.
The main advantage of polymorphism is to improve the scalability of the code and comply with the opening and closing principle. However, it also has the disadvantage that it is unable to call the functions unique to subclasses. For example, I can't use the reference variable of the parent class to call the seeDoor() method unique to the Dog class.
5. Object casting
The parent class reference points to the child class object. We call this process upward transformation, which belongs to automatic type conversion.
The parent class reference variable after upward transformation can only call the method of its compiled type, not the method of its runtime type. At this time, we need to carry out type coercion, which we call downward transformation!
Example 5 object transformation
public class TestCasting { public static void main(String[] args){ Object obj = new String("Complete space"); //Upward can automatically transform // obj.charAt(0) cannot be called The compiler considers obj to be an Object type rather than a String type /*When writing a program, if you want to call a method of runtime type, you can only cast it. Otherwise, it cannot pass the compiler check */ String str = (String) obj; //Downward transformation System.out.println(str.charAt(0)); //Character at 0 index position System.out.println(obj == str); //They are the same object at runtime } }
During the downward transformation, the reference variable must be converted to the real subclass type (runtime type), otherwise the type conversion exception ClassCastException will occur. As shown in example 6.
public class TestCasting2 { public static void main(String[] args){ Object obj = new String("Complete space"); //The real subclass type is String, but it is transformed downward to StringBuffer here StringBuffer str = (StringBuffer) obj; System.out.println(str.charAT(0)); } }
To avoid this exception, we can use the instanceof operator for judgment, as shown in Example 7
Example 7 using instanceof in downward transformation
public class TestCasting2 { public static void main(String[] args){ Object obj = new String("Complete space"); if(obj instanceof String){ String str = (String)obj; System.out.println(str.charAt(0)); }else if(obj instanceof StringBuffer){ StringBuffer str = (StringBuffer)obj; System.out.println(str.charAt(0)); } } }