First, inheritance
Inheritance in Java uses the keyword extends, which is slightly different from the syntax of C#.
1. Subclass constructor
java automatically inserts calls to the parent constructor in the constructor of the child class, that is, the initialization of the parent class is completed before the child class can access the parent class.
If you want to call a parent constructor with parameters, you should use the super keyword.
/** * @author Chen Jing * @date 18/1/17 */ public class Product { private String name; public Product(String name) { this.name = name; System.out.println("[Product constructor]"); } } public class Bread extends Product { private int price; public Bread(String name, int price) { super(name);//Call the parent constructor this.price = price; System.out.println("[Bread constructor]"); } }
Let's create an instance of the Bread class and see the order of calls.
@Test public void testConstructor(){ Bread bread=new Bread("Caterpillar bread",10); }
Print results:
[Product constructor]
[Bread constructor]
2. Calling parent class methods
Subclasses cannot directly access the private domain of the parent class. If you want to access it, you can only use the get accessor exposed by the parent class. Subclasses also need to use super keywords to call methods in their parent classes.
public class Product { private String name; public String getName() { return name; } public Product(String name) { this.name = name; } } public class Bread extends Product { public Bread(String name) { super(name); } public void display(){ System.out.println(getName()); } }
Then write a unit test:
@Test public void testPrivate(){ Bread bread=new Bread("Caterpillar bread"); bread.display();//Caterpillar bread }
It's important to note that super is not a reference to an object and can't assign super to a variable. It's just a special keyword that tells the editor to call methods in the parent class.
3. On Heavy Load
If there are overloaded methods in the parent class and the subclass is overloaded, will the methods in the parent class be overridden? In fact, methods in both parent and child classes can be overloaded normally and will not be overridden.
First, add the method getDescription():
public class Product { ...... public String getDescription() { return "[Product]name="+name; } }
The method is then overloaded in subclasses:
public class Bread extends Product { ...... public String getDescription(String storeName) { return "[Bread]storename="+storeName; } }
Add a unit test:
public class ExtendClassTests { @Test public void testOverload(){ Bread bread=new Bread("Bean paste bread",9); System.out.println(bread.getDescription()); System.out.println(bread.getDescription("Delicious")); } }
Output:
[Product]name = bean paste bread
[Bread] store name = how delicious it is
4. Succession Criteria
Inheritance criteria: use inheritance as little as possible. Generally, inheritance is used to express the difference between behaviors, and combination is used to express the change of state.
Two. Polymorphism
1. Variable polymorphism
In Java, object variables are polymorphic. A Product variable can refer to either a Product object or an object of a Product subclass.
@Test
public void testParent(){
Product product=new Bread("Caterpillar bread",10);
product.display();
//Mandatory Type Conversion
if(product instanceof Bread){
Bread brand=(Bread)product;
brand.display("Delicious");
}
}
Because Bread instances are upgraded to Product types, you can no longer call the Bread.getDescription(String storeName) method.
If you need to cast a parent class to a subclass, you need to first detect the object type through instanceof. We'd better avoid using forced type conversion as much as possible.
2. Dynamic binding
Dynamic binding is a method that is called at runtime according to the type of object. In java, dynamic binding is the default behavior, and there is no need to add additional keywords to achieve polymorphism.
Write a demo to see that the display method is overloaded in both parent and child classes.
public class Product { private String name; public Product(String name) { this.name = name; } public void display() { System.out.println("[Product]getDescription()"); } } public class Bread extends Product { private int price; public Bread(String name, int price) { super(name); this.price = price; } @Override public void display() { System.out.println("[Bread]getDescription()"); } public void display(String storeName) { System.out.println("[Bread]getDescription(String storeName)"); } }
Add unit tests:
@Test public void dynamicBind(){ Product product=new Product("product"); product.display(); //[Product]getDescription() Bread bread=new Bread("Caterpillar",9); bread.display(); //[Bread]getDescription() bread.display("maimai"); //[Bread]getDescription(String storeName) Product product1=bread; product1.display(); //[Bread]getDescription() }
The virtual machine creates a method table for each class, listing the signatures of all methods and the methods actually invoked. In this way, when a method is invoked dynamically, it is only necessary to look up the method table to quickly find the method that is actually invoked.
Product:
display()->Product.display()
Bread:
display()->Bread.display()
display(String name)->Bread.display(String name)
For complete source code, see: https://github.com/cathychen00/cathyjava /_08_extend
3. Abstract Classes
The abstract keyword is used to define abstract methods, which have only declarations and no method body.
Classes containing abstract methods are called abstract classes. If a class contains one or more abstract methods, it must be defined as abstract classes.
If a class inherits from an abstract class, it must provide implementation for all abstract methods in the abstract class, otherwise the class must also be defined as an abstract class.
Look at a scenario: We have some scheduled tasks, the workflow is similar, only a specific part of the details are different. We can define an abstract base class BaseJob, encapsulate different parts as abstract methods, and implement them in subclasses.
public abstract class BaseJob { public void run(){ System.out.println("==START "+getDescription()+"=="); String lastJobId=getLastJobId(); execute(lastJobId); writeLog(); System.out.println("==END "+getDescription()+"=="); } protected abstract String getDescription(); protected abstract void execute(String jobId); private void writeLog() { System.out.println("write log to DB"); } private String getLastJobId() { return "job1221"; } }
public class ArticleJob extends BaseJob { @Override protected String getDescription() { return "Grasp the Tasks of Articles"; } @Override protected void execute(String jobId) { System.out.println("Grabbing News Articles on Sites jobid="+jobId); } public static void main(String[] args) { BaseJob articleJob=new ArticleJob(); articleJob.run(); } }
Create unit tests and call ArticleJob to see.
@Test public void articleJob(){ BaseJob articleJob=new ArticleJob(); articleJob.run(); }
Operation results:
== START Crawl Article Task== Grab the news article jobid=job1221 write log to DB == END Grab Article Task==
When adding a timed task that conforms to the process again, you only need to create a new class to implement BaseJob.
Complete examples: https://github.com/cathychen00/cathyjava /09_abstract