继承:对共性的抽取,实现代码的复用

可以把狗和猫这两个类中姓名,年龄,吃饭这些共同部分抽取出来,组成一个新的类

子类可以继承父类的成员属性和方法
子类也叫派生类
父类也叫基类,超类
子类要体现自己特有的属性
继承不要超过3层
class Base{
int a;
int b;
}
public class Derived extends Base {
int a;
int c;
public void method(){
a=10;
b=20;
c=30;
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
public static void main(String[] args) {
Derived derived=new Derived();
derived.method();
Base base=new Base();
System.out.println(base.a);
}
}
10//子类的a
20
30
0//父类的a
当子类和父类中有同名的成员变量时,优先访问子类(就近原则)
在子类中访问子类父类同名的成员属性,如果想访问父类的
super
输出结果:null正在看家护院!

public class Base {
public void methodA(){
System.out.println("Base中的methodA()");
}
}
public class Derived extends Base{
public void methodA(int a) {
System.out.println("Derived中的method(int)方法");
}
}
public void methodC(){
methodA(); // 没有传参,访问父类中的methodA()
methodA(20); // 传递int参数,访问子类中的methodA(int)
}
}
在子类方法中或通过子类对象访问方法时,当子类和父类存在同名的成员方法时,如果构成重载,则根据调用的方法的参数列表访问相对应的方法

说明重载可以发生在两个不同的类
每一个类都会生成自己的字节码文件
Java中只能继承一个类
super.data 访问父类的普通成员变量
super.func()调用父类的普通成员方法
super()调用父类的构造方法
super只能在非静态方法中使用
当我们没写构造方法时,编译器会默认给一个不带参数的构造方法。
子类构造对象时,要先调用父类的构造方法



虽然调用了父类的构造方法,但是没有生成父类的对象,只是帮助子类初始化从父类继承的属性


public class Test {
public static void main(String[] args) {
Dog dog=new Dog("hello",5,false);
System.out.println("==============================");
Cat cat=new Cat();
System.out.println("==============================");
Dog dog2=new Dog("hello",5,false);
}
}
Animal::static{}
Dog::static{}
Animal::{}
Animal(String , int)
Dog::{}
Dog(String , int ,boolean)
==============================
Cat::static{}
Animal::{}
Animal(String , int)
Cat::{}
Cat()
==============================
Animal::{}
Animal(String , int)
Dog::{}
Dog(String , int ,boolean)
静态代码块只会执行一次

package demo1;
public class TestDemo {
protected int a=10;
public void func(){
System.out.println(a);
}
}
package demo2;
import demo1.TestDemo;
public class Test extends TestDemo {
public void test(){
System.out.println(super.a);
}
public static void main(String[] args) {
Test t=new Test();
//t.test(); //10
//System.out.println(t.a); //10
}
}
说明不同包的子类可以访问
注:外部类的修饰符只有public或default,因为外部类的上一级是包,所以外部类的作用域是同一包和任何位置

继承: is a
组合: has a
class Student{
}
class Teacher{
}
class School{
public Student[] students;
public Teacher[] teachers;
}
Student , Teacher这两个类的实例是School这个类的字段
多态的条件:继承,向上转型,重写


静态绑定(早绑定):根据传入的参数决定调用哪个方法
编译时就确定好调用哪个方法。
public static void function(){
}
public static void function(int a){
}
public static void function(int a,int b){
}
public static void main(String[] args) {
function();
function(10);
function(10,20);
}
动态绑定(晚绑定):
运行时才确定好调用哪个方法。



public class Test {
public static void main2(String[] args) {
//1.直接赋值
Dog dog=new Dog("hello",5,false);
Animal animal1=dog;
Animal animal2=new Cat("hello",5);
animal1.eat();
}

public class Test {
public static Animal function2(){
return new Cat();
}
}
public static void main(String[] args) {
Animal animal=new Cat("hhh",3);
Cat cat=(Cat)animal;//向下转型
cat.catchMouse();
}

多态的好处:降低代码的"圈复杂度"。
圈复杂度:一段代码中条件语句和循环语句出现的个数
class Shape{
public void draw(){
System.out.println("画图形!");
}
}
class Rect extends Shape{
@Override
public void draw() {
System.out.println("画矩形!");
}
}
class Cycle extends Shape{
@Override
public void draw() {
System.out.println("画圆!");
}
}
class Flower extends Shape{
@Override
public void draw() {
System.out.println("画❀!");
}
}
如果我想要实现画一个圆,一个矩形,一个圆,一个矩形,一个花
不用多态,这样实现
public static void drawShapes(){
String[] strings={"cycle","rect","cycle","rect","flower"};
for (String x:
strings) {
if(x.equals("cycle")){
Cycle cycle=new Cycle();
cycle.draw();
}else if(x.equals("rect")){
Rect rect=new Rect();
rect.draw();
}else {
Flower flower=new Flower();
flower.draw();
}
}
}
public static void main(String[] args) {
drawShapes();
}
使用多态:
public static void drawShapes(){
Shape[] shapes={new Cycle(),new Rect(),new Cycle(),new Rect(),new Flower()};
for (Shape s:
shapes) {
s.draw();
}
}
public static void main(String[] args) {
drawShapes();
}
⭐⭐⭐⭐⭐⭐⭐分割线⭐⭐⭐⭐⭐⭐⭐⭐
class B {
public B() {
func();
}
public void func() {
System.out.println("B.func()");
}
}
class D extends B {
private int num = 1;
@Override
public void func() {
System.out.println("D.func() " + num);
}
}
public class Test {
public static void main(String[] args) {
D d = new D();
}
}
输出结果
D.func() 0
分析:构造D对象,调用父类B的构造方法,而B的构造方法内调用了重写的func方法,由于动态绑定,调用重写的子类方法,此时子类D还没有开始构造,num的值未初始化是0
得出结论:构造方法内部尽量只使用final,static方法,防止重写