代码块,继承;方法的重写与重载的区别;final关键字;多态;向下转换(案例:孔子装爹)

代码块

  • 代码块的概述
    在Java中,使用{}括起来的代码被称为代码块;
  • 代码块分类
    根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块
  • 代码块的应用
  1. 局部代码块
    在方法中出现;限定变量生命周期,及早释放,提高内存利用率
  2. 构造代码块
    在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
  3. 静态代码块
    在类中方法外出现,加了static修饰
    在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且只执行一次。

案例

public class Student {
    static int num=100;

    public Student() {
        //你可以在这里面执行一些业务逻辑
        System.out.println("这是一个空参构造");
    }

    {
        System.out.println("这是一个构造代码块");
    }
    //静态代码块,随着类的加载而加载,且静态代码块只执行一次。静态代码块里面只能访问静态变量

    static{
        //进行一些初始化的工作。
        System.out.println(num);
        System.out.println("这是一个静态代码块");
    }
}

public class MyTest {
    public static void main(String[] args) {
        //代码块:就是被一对{}大括号所括起来的内容
        //代码块根据定义的位置不同分为:局部代码块,构造代码块,静态代码块,同步代码块(后面讲)
        //局部代码块:定义在方法中的代码块
        int b=100;
        {
            //局部代码块,可以尽早的释放空间和资源
            int a=100;
            System.out.println("这是一个局部代码块");
            System.out.println(a);
            System.out.println(b);
        }

        //System.out.println(a);
        System.out.println(b);

    }
}

public class MyTest2 {
    public static void main(String[] args) {
        //构造代码块,在创建对象时执行,优先于构造方法执行,每创建一个对象都会执行
        Student student = new Student();
        Student student2 = new Student();
        Student student3 = new Student();
        Student student4 = new Student();
    }
}

public class MyTest3 {
    public static void main(String[] args) {

        new Student();
        new Student();
        new Student();
    }
}

注意创建了一个student类,然后开始引用这个类;注意输出!同时还需要注意区别静态代码块对着类的引用而输出一次而构造代码块随着创建对象而运行输出一次,每创建一个就输出一次,并且先于构造方法先输出;

代码块面试题

class Student {
		static {
			System.out.println("Student 静态代码块"); //3
		}
		
		{
			System.out.println("Student 构造代码块"); //4 6
		}
		
		public Student() {
			System.out.println("Student 构造方法"); //5 7
		}
	}

	class StudentDemo {
		static {
			System.out.println("StudentDemo的静态代码块");//1
		}
		
		public static void main(String[] args) {
			System.out.println("我是main方法");//2
			
			Student s1 = new Student();
			Student s2 = new Student();
		}
	}

继承

  • 继承概述
    多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
  • 继承格式
    通过extends关键字可以实现类与类的继承
    class 子类名 extends 父类名 {}
    单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。
  • 继承的好处和弊端

好处:

  1. 提高了代码的复用性
  2. 提高了代码的维护性
  3. 让类与类之间产生了关系,是多态的前提

弊端:

  1. 类的耦合性增强了。

    开发的原则:高内聚,低耦合。
    耦合:类与类的关系
    内聚:就是自己完成某件事情的能力

  • Java中类的继承特点(单继承多层继承)
  1. Java只支持单继承,不支持多继承。
    有些语言是支持多继承,格式:extends 类1,类2,…
  2. Java支持多层继承(继承体系)
  • 继承的注意事项
  1. 子类只能继承父类所有非私有的成员(成员方法和成员变量)
  2. 子类不能继承父类的构造方法,但是可以通过super(待会儿讲)关键字去访问父类构造方法。
  3. 不要为了部分功能而去继承
  • 什么时候使用继承
    继承其实体现的是一种关系:“is a” .
    采用假设法。
    如果有两个类A,B。只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承。

案例

案例一:

public class MyTest {
    public static void main(String[] args) {
        //生活中的继承:儿子可以继承老子的继承
        //Java中的继承:子类可以继承父类的成员,并且可以使用
        //通过一个关键字 extends 来产生继承关系
        Zi zi = new Zi();
        System.out.println(zi.num);
        zi.show();

    }
}



class Fu{
    int num=100;
    public void show(){
        System.out.println("这是一个show方法");
    }
}

class Zi extends Fu{

}

案例二:

public class Animal {
    String name;
    int age;

    public void eat() {
        System.out.println("吃饭饭");
    }

    public void sleep() {
        System.out.println("睡觉觉");
    }


}

public class Cat extends Animal{

    public void catcheMouse(){
        System.out.println("抓老鼠");
    }
}

public class Dog extends Animal{

    public void lookDoor() {
        System.out.println("看门");
    }
}

public class MyTest {
    public static void main(String[] args) {
        //继承的思想:将所有子类的共性功能,向上抽取到父类当中,为了实现代码的复用性,和维护性。
        //继承的好处:提高了代码的复用性和维护性
        //继承的弊端:增加了耦合性,让类跟类之间产生了关系
        //软件的设计的原则:高内聚,低耦合
        //高内聚:一个类,单独完成某个功能的能力
        //耦合:一个类要完成某个功能,得去依赖某些类
        Cat cat = new Cat();
        cat.name = "汤姆";
        cat.age = 1;
        System.out.println(cat.name);
        System.out.println(cat.age);
        cat.sleep();
        cat.eat();
        cat.catcheMouse();
        System.out.println("----------------------");
        Dog dog = new Dog();
        dog.name = "旺财";
        dog.age = 10;
        System.out.println(dog.name);
        System.out.println(dog.age);
        dog.sleep();
        dog.eat();
        dog.lookDoor();
    }
}

案例三:

public class Person {
    String name;
    int age;

    public void eat() {
        System.out.println("吃饭");
    }

    public void sleep() {
        System.out.println("睡觉");
    }
}

public class Teacher extends Person{

    public void teache(){
        System.out.println("教书");
    }
}

public class Student extends Person{

    public void talkLove(){
        System.out.println("谈恋爱");
    }
}

public class MyTest {
    public static void main(String[] args) {
        Student student = new Student();
        student.name="张三";
        student.age=19;
        System.out.println(student.name+"==="+student.age);
        student.sleep();
        student.eat();
        student.talkLove();
        System.out.println("-----------------");
        Teacher teacher = new Teacher();
        teacher.name="沈某某";
        teacher.age=10;
        System.out.println(teacher.name+"==="+teacher.age);
        teacher.sleep();
        teacher.eat();
        teacher.teache();

    }
}

案例四:

public class MyTest extends Object{
    public static void main(String[] args) {
        //继承的注意事项:
        //1.在我们Java中只支持单继承,但是支持多层继承
        //Object是所有类的顶层父类,所有类都是直接,或简介继承自他
        //2.父类私有的成员,子类不能继承。
        //3.构造方法,不参与继承
        //4.不要为了部分功能而去继承,会增加耦合性
        Zi zi = new Zi();
        System.out.println(zi.a);
        System.out.println(zi.b);
       // System.out.println(zi.c);
       // Fu fu = new Fu();
       // fu.show();
       // Zi zi1 = new Zi();
       // zi1.show();


    }
}

class A extends Object{
    int a=100;

    private void show(){
        System.out.println("这是一个私有的方法");
    }

}

class Fu extends A{
    int b=200;
    private int c=10;

}


class Zi extends Fu{


}


  • 继承中成员变量的关系
    A:子类中的成员变量和父类中的成员变量名称不一样
    B:子类中的成员变量和父类中的成员变量名称一样
    在子类中访问一个变量的查找顺序(“就近原则”)
    a: 在子类的方法的局部范围找,有就使用
    b: 在子类的成员范围找,有就使用
    c: 在父类的成员范围找,有就使用
    d:如果还找不到,就报错

案例五:

public class MyTest {
    public static void main(String[] args) {
        B b = new B();
        int num=1;
        b.show(num);
        //变量的访问原则:遵循就近原则,先在局部找这个变量,找到就使用,如果局部没找到,去本类的成员位置找,找到就使用
        //如果本类的成员位置没找到,去父类的成员位置找,找到就使用。
    }
}

class A{
    int num=100;
}

class B extends A{
    int num=200;
    public void show(int num){
        //就近访问原则
        System.out.println(num); //1
        System.out.println(this.num);//200
        //System.out.println(new A().num);//100
        System.out.println(super.num);//100
    }

}

  • this和super的区别和应用
    this 和 super 的区别:
    this 代表的是本类对象的引用
    super代表的是父类存储空间的标识(可以理解成父类的引用,可以操作父类的成员)
  • this和super的使用
  1. 调用成员变量
    this.成员变量 调用本类的成员变量
    super.成员变量 调用父类的成员变量
  2. 调用构造方法
    this(…) 调用本类的构造方法
    super(…) 调用父类的构造方法
  3. 调用成员方法
    this.成员方法 调用本类的成员方法
    super.成员方法 调用父类的成员方法
  • 继承中构造方法的关系
    子类中所有的构造方法默认都会访问父类中空参数的构造方法

    原因:
    因为子类会继承父类中的数据,可能还会使用父类的数据。
    所以,子类初始化之前,一定要先完成父类数据的初始化。

    其实:
    每一个构造方法的第一条语句默认都是:super()
    在这里简单的提一句,Object类。否则有人就会针对父类的构造方法有疑问。Object再没有父类了。

  • 继承中构造方法的注意事项
    父类没有无参构造方法,子类怎么办?
    a: 在父类中添加一个无参的构造方法
    b:子类通过super去显示调用父类其他的带参的构造方法
    c:子类通过this去调用本类的其他构造方法
    本类其他构造也必须首先访问了父类构造
    注意事项
    super(…)或者this(….)必须出现在第一条语句上

案例六:

public class MyTest {
    public static void main(String[] args) {
        //构造方法,不参与继承。
       // new Father();
        //我们在创建子类对象时,会先去执行父类的空参构造,,为什么?
        //因为有了继承关系后,那么我们在初始化子类时,先要完成父类数据的初始化,因为,我们子类要去继承父类的数据,可能还会要使用父类的数据,所以肯定先要让父类的构造方法执行,来完成对父类数据的初始化,然后在完成自己的数据的初始化。
        //在每个类的构造方法的第一行,都会默认有一条语句 super() 调用父类的空参构造,先完成父类数据的初始化

       //Son son = new Son();
        Son son = new Son(10);
    }
}

class Father{
    int num=1000;
    public Father() {
        super();
        System.out.println("这是父类的空参构造");
    }
}

class Son extends Father{
    int b=10;
    public Son() {
        super();
        System.out.println("这是子类的空参");

    }

    public Son(int b) {
        super();
        this.b = b;
        System.out.println("子类有参构造执行了");
    }
}

案例七:

public class MyTest {
    public static void main(String[] args) {
        //Zi zi = new Zi();
        //Zi zi = new Zi(1009);
        ////假如我父类里面没有提供空参构造怎么办?
        ////1.那子类可以去调父类有参构造
        ////2.先用this(参数)本类的有参构造,然后你调用的那个构造又去调用父类的有参构造
        //System.out.println(zi.num);
        Zi zi = new Zi();

    }
}

class Fu{
    int num=10;

    public Fu() {
        super();
        System.out.println("父类的空参构造执行了");
    }

    public Fu(int num) {
        super();
        this.num = num;
        System.out.println("父类的有参构造执行了");
    }
}

class Zi extends Fu{
    int num=100;
    public Zi() {
        super(10);
       // this(10000);
        System.out.println("子类的空参构造执行了");
    }

    public Zi(int num) {
        super(num);
        System.out.println("子类的有参构造执行了");
    }
}

面试题:

看程序写结果

class Fu{
		public int num = 10;
		public Fu(){
			System.out.println("fu");
		}
	}
	class Zi extends Fu{
		public int num = 20;
		public Zi(){
			System.out.println("zi");
		}
		public void show(){
			int num = 30;
			System.out.println(num);//30
			System.out.println(this.num);//20
			System.out.println(super.num);//10
		}
	}
	class Test {
		public static void main(String[] args) {
			Zi z = new Zi();
			z.show();
		}
	}

看程序写结果

class Fu {
		static {
			System.out.println("静态代码块Fu"); //1
		}

		{
			System.out.println("构造代码块Fu"); //3
		}

		public Fu() {
			System.out.println("构造方法Fu"); //4
		}
	}

	class Zi extends Fu {
		static {
			System.out.println("静态代码块Zi"); //2
		}

		{
			System.out.println("构造代码块Zi"); //5
		}

		public Zi() {
			System.out.println("构造方法Zi"); //6
		}
	}

	Zi z = new Zi(); 请执行结果。

final关键字

  • final关键字修饰特点
    修饰类: 被修饰类不能被继承
    修饰方法: 被修饰的方法不能被重写
    修饰变量: 被修饰的变量不能被重新赋值,因为这个量其实是一个常量

案例

案例一:

public class MyTest {
    public static final int A=10; //公共的静态常量
    public static void main(String[] args) {
        //final 最终的,可以修饰类,变量,可以修饰成员方法
        //final 修饰变量,此变量为常量
        //
        final int NUM=100; //自定义常量  常量的命名字母全部大写
        System.out.println(A);
        System.out.println(MyTest.A);
        System.out.println(NUM);
    }
}

案例二:

import java.util.Scanner;
public class MyTest2 {
    public static void main(String[] args) {
        //final 修饰类,此类不能被继承
        new Scanner(System.in);

    }
}

final class A{

}

案例三:

public class MyTest3 {
    public static void main(String[] args) {
        //final 修饰方法,此方法不能被重写,子类可以原封不动的继承下去用,就是不能重写

        new Zi().test();
    }
}

class Fu{

    public void show(){}
    public final void test(){
        System.out.println("这是父类的final");
    }
}

class Zi extends Fu{
    @Override
    public void show() {
        super.show();
    }


}

案例四:

public class MyTest {
    public static void main(String[] args) {
        //final 修饰基本数据类型,指的是这个值不能再次被改变
        final int NUM=100;
        //final 修饰引用数据类型,指的是这个地址值,不能再次被改变
       final MyClass myClass = new MyClass();
        System.out.println(myClass);
        //myClass=new MyClass();
        //System.out.println(myClass);
    }
}
class MyClass{

}

注意
基本类型,是值不能被改变
引用类型,是地址值不能被改变

方法重写

  • 什么对方法重写?
    子类中出现了和父类中一模一样的方法声明(方法名,参数列表,返回值类型),也被称为方法覆盖,方法复写。

  • 方法重写的应用
    当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。
    这样,即沿袭了父类的功能,又定义了子类特有的内容。

案例

案例一:

public class MyTest {
    public static void main(String[] args) {
        //方法重写:当子类出现了和父类一摸一样的方法(方法名,参数列表一样,返回值类型一样)就会发生子类的方法覆盖父类的方法,我们也称之为方法重写
        //为什么要有方法重写的这种机制。如果说子类对父类的方法实现不满意,那么子类就可以覆盖他,或者说,子类想要对父类的方法的实现功能进行扩展,也可以使用方法重写的这种机制

        Zi zi = new Zi();
        zi.show();
        zi.test();

    }
}

class Fu {
    int num2=100;
    public void show(){
        System.out.println("我是父类的show方法");
    }
}
class Zi extends Fu{
    int num=200;

    public void test(){
        System.out.println("我是子类的test方法");
    }

    public void show() {
        System.out.println("我是子类的show方法");
    }
}

案例二:

public class Animal {
    public void sleep() {
        System.out.println("睡觉");
    }

    public void eat() {
        System.out.println("吃饭");
    }
}

public class Cat extends Animal {


    public void cathchMouse(){
        System.out.println("抓老鼠");
    }
}

public class Dog extends Animal{

    public void lookDoor(){
        System.out.println("看门");
    }

    public void eat(){
        System.out.println("狗爱吃盖浇饭");
    }
}

public class MyTest {
    public static void main(String[] args) {
        new Cat().eat();
        new Dog().eat();
    }
}

  • 方法重写的注意事项
  1. 父类中私有方法不能被重写
    因为父类私有方法子类根本就无法继承
  2. 子类重写父类方法时,访问权限不能更低
    最好就一致
  3. 父类静态方法,子类也必须通过静态方法进行重写
    其实这个算不上方法重写,但是现象确实如此;

案例三:

public class MyTest {
    public static void main(String[] args) {
        new IPhone().call();
    }
}

class Phone{

    public void call(){
        System.out.println("打电话");
    }
}

class IPhone extends Phone{
    public void call() {
       super.call();
        System.out.println("视频");
    }
}

案例四:

public class MyTest {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.test();
        zi.show();
        //静态方法不算重写
        //zi.haha();
        Zi.haha();
        Fu.haha();

    }

}

class Fu {
    public void show() {
        System.out.println("父类的show方法");
    }

    public void test() {
        System.out.println("父类的test方法");
    }

    public static void haha() {
        System.out.println("这是父类的静态方法");
    }

}

class Zi extends Fu {
    @Override //注解 可以检测此方法是否是重写父类的(ctrl+o)
    public void show() {
        System.out.println("子类的show方法");
    }

    @Override
    public void test() {
        System.out.println("子类的test方法");
    }


    public static void haha() {
        System.out.println("这是子类的静态方法");
    }

    public void hehe() {
    }

}

案例五:

public class Person {
    public String name;
    public int age;
    public void eat(){
        System.out.println("吃饭");
    }
    public void sleep(){
        System.out.println("睡觉");
    }

}

public class Teacher extends Person {
    @Override
    public void eat() {
        System.out.println("老师爱吃油泼面");
    }

    @Override
    public void sleep() {
        System.out.println("我喜欢晚上睡觉");
    }

    public void sing() {
        System.out.println("唱歌");
    }
}

public class Student extends Person{

    public void palyGame(){
        System.out.println("玩游戏");
    }

    //Ctrl+O 重写父类的方法

    @Override
    public void eat() {
        System.out.println("学生爱吃麻辣烫");
    }

    @Override
    public void sleep() {
        super.sleep();
        System.out.println("我不仅睡觉,还要打呼噜");
    }
}
public class MyTest {
    public static void main(String[] args) {
        Student student = new Student();
        student.name="张三";
        student.age=13;
        student.sleep();
        student.eat();
        student.palyGame();

        System.out.println("-----------------");

        Teacher teacher = new Teacher();
        teacher.name="沈某某";
        teacher.age=19;
        teacher.eat();
        teacher.sleep();
        teacher.sing();
    }
}

案例六:

public class MyTest {
    public static void main(String[] args) {
        //重写的注意事项:
        //1.父类私有的方法,子类无法重写,私有的方法子类都无法继承,何谈重写
        //2.子类在重写父类方法时,权限修饰符不能比父类的低,要比父类的高或者一样,最好一样
        // public>protected>缺省的>private
        //3.静态方法,不参与重写
    }
}

class Fu {
    protected void show() {
        System.out.println("这是父类的show方法");
    }
    public static void test(){

    }
}

class Zi extends Fu {

    @Override
    public void show() {
        System.out.println("这是子类的show方法");
    }

    public static void test() {

    }
}

注意:public>protected>缺省的>private

方法重载和方法重写

  • 方法重载和方法重写
    方法重载:允许一个类中,出现多个同名方法,只要参数个数 或参数类型不同即可
    方法重写:有继承情况下,子类出现了和父类一模一样的方法就会发生方法重写

多态

  • 概述
    某一个事物,在不同时刻表现出来的不同状态。
    举例:
    Cat c=new Cat();
    Animal a=new Cat();
    猫可以是猫的类型。猫 m = new 猫();
    同时猫也是动物的一种,也可以把猫称为动物。 动物 d = new 猫();

  • 多态前提

  1. 要有继承关系。
  2. 要有方法重写。 其实没有也是可以的,但是如果没有这个就没有意义。
  3. 要有父类引用指向子类对象。
    父 f = new 子();

案例

案例一:

public class MyTest {
    public static void main(String[] args) {
        //面向对象的三大特征:封装,继承,多态
        //继承是多态的前提。
        //多态:指的是某个事物,在某个时刻,所表现出来的不同状态
        //猫是一个事物,猫可以是一只猫,猫是一种动物
        //猫 cat=new 猫();
        ////多态的写法,前提是猫要继承动物
        //动物 an=new 猫();
        //动态的三个必要条件
        //1.要有继承
        //2.要有方法重写,可以没有,但是多态就没有意义
        //3.父类引用指向子类对象
        //Cat cat = new Cat();
        //cat.sleep();
        //cat.eat();
       // Animal anima=new Animal();
        //多态,父类引用指向的是子类对象
        Animal an=new Cat();
        an.sleep();
        an.eat();
        an.show();
    }
}

class Animal{
    public void eat(){
        System.out.println("吃饭");
    }

    public void sleep() {
        System.out.println("睡觉");
    }

    public void show() {
        System.out.println("父类中的show方法");
    }
}

class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫爱吃鱼");
    }

    @Override
    public void sleep() {
        System.out.println("猫爱白天睡觉");
    }
}

案例二;

public class Animal {
    public void eat(){
        System.out.println("吃饭");
    }
}
public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫爱吃小鱼干");
    }
}

public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗爱吃骨头肉");
    }
}
public class Tiger extends Animal{
    @Override
    public void eat() {
        System.out.println("老虎爱吃鸡肉");
    }
}

public class 大象 extends Animal{
    @Override
    public void eat() {
        System.out.println("大象爱吃草");
    }
}
public class MyUtils {
    //构造方法私有化
    private MyUtils() {
    }

    //public static void testEat(Cat cat) {
    //    cat.eat();
    //}
    //
    //public static void testEat(Dog dog) {
    //    dog.eat();
    //}
    //
    //public static void testEat(Tiger tiger) {
    //    tiger.eat();
    //}
    //
    //public static void testEat(大象 x) {
    //    x.eat();
    //}

    public static void testEat(Animal an) {
     //an=new Cat() ;
    //an = new Dog();
        an.eat();
    }
}

public class MyTest {
    public static void main(String[] args) {
        //多态的好处:1.提高代码的复用性(继承来保证的)
        //2.提高了代码的扩展性
        Cat c1 = new Cat();

        MyUtils.testEat(c1);

        Dog d1 = new Dog();

        MyUtils.testEat(d1);

        Tiger tiger = new Tiger();
        MyUtils.testEat(tiger);
        大象 象 = new 大象();
        MyUtils.testEat(象);
    }

}

注意
多态的好处:
1. 提高代码的复用性(继承来保证的)
2. 提高了代码的扩展性

  • 多态中的成员访问特点
    A:多态中的成员访问特点
    a:成员变量
    编译看左边,运行看左边。
    b:构造方法
    创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化。
    c:成员方法
    编译看左边,运行看右边。
    d:静态方法
    编译看左边,运行看左边。
    (静态和类相关,算不上重写,所以,访问还是左边的)

案例三:

public class MyTest {
    public static void main(String[] args) {
        //以多态的形式来访问成员变量 使用的还是父类的变量
        //编译看左边,运行也看左边
        Fu fu = new Zi();
        System.out.println(fu.num);//100
        //多态的形式访问成员方法 编译看左边,运行看右边
        //
        fu.show();//zi类
        Fu.hehe();//父类

    }
}

class Fu{

    int num = 100;
    public void show(){
        System.out.println("父类的show方法");
    }
    public static void hehe(){
        System.out.println("父类的静态方法");
    }
}
class Zi extends Fu{
    int num=10;

    @Override
    public void show() {
        System.out.println("子类重写过后的show方法");
    }

    public static void hehe() {
        System.out.println("子类类的静态方法");
    }
}

注意:
出了成员方法是编译看左边执行看右边外,成员变量和静态方法都是编译看左边执行也看左边;

  • 多态的好处
    a:提高了代码的维护性(继承保证)
    b:提高了代码的扩展性(由多态保证)
  • 多态的好处和弊端
    多态的好处:提高了代码的扩展性
    多态的弊端:不能访问子类独有的功能和属性

案例四;

public class MyTest {
    public static void main(String[] args) {
        //多态的好处,提高了代码的扩展性
        //多态的弊端,不能访问子类独有的功能和属性
        Fu fu = new Zi();
        System.out.println(fu.a);
        //System.out.println(fu.num);
        fu.show();
        //父类引用不能直接访问子类独有的方法
       // fu.test();
        //我们可以向下转型

        Zi zi= (Zi) fu; //向下转型
        System.out.println(zi.num);
        zi.test();

    }
}

class Fu{
    int a=10;
    public void show(){
        System.out.println("父类的show方法");
    }
}

class Zi extends Fu{
    int num=10;
    @Override
    public void show() {
        System.out.println("子类重写了父类的show方法");
    }
    public void test(){
        System.out.println("子类一个特有的方法");
    }
}

注意多态和向下转型是相对应的,多态可以理解为向上转型;

  • 多态的向下转型
    把父类的引用强制转换为子类的引用。(向下转型)

案例五:

public class MyTest {
    public static void main(String[] args) {
        Cat cat = new Cat();
        Animal an=cat; //多态就是向上转型
        an.eat();
        //an.cacheMouse();
        Cat c= (Cat) an; //向下转型
        c.eat();
        c.cacheMouse();

        Dog dog = new Dog();
        an=dog;
        Dog d= (Dog) an; //向下转型
        d.lookDoor();
        an.eat();
       // an=new Tiger();
        Tiger t= (Tiger) an;
        //ClassCastException 类型转换异常
        t.goSwimming();

    }

}

class Animal{

    public void eat(){
        System.out.println("吃饭");
    }
}

class Cat extends Animal{

    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
    public void cacheMouse(){
        System.out.println("猫抓老鼠");
    }
}

class Dog extends Animal{

    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
    public void lookDoor(){
        System.out.println("狗看门");
    }
}

class Tiger extends Animal{
    @Override
    public void eat() {
        System.out.println("老虎不吃素");
    }
    public void goSwimming(){
        System.out.println("老虎去游泳");
    }

}

案例六;
案例演示:
孔子装爹
孔子爹,是西开的一个高级讲师,会讲授java 李四闻名而来,请孔子爹到家里给他讲java,就留孔子一个人在家,这时候张三也来让孔子爹来讲java 孔子爹这时候不在家,那孔子又不想失去这个学生,所以孔子,假扮成他爹,给张三 讲论语,讲完之后,孔子好累,玩游戏休息下,那么卸下这套装备,去玩游戏

public class MyTest {
    public static void main(String[] args) {
        
        孔子爹 坑爹 = new 孔子();
        System.out.println(坑爹.age);
        坑爹.teache();
        //向下转型,做回他自己
        孔子 k = (孔子) 坑爹;
        System.out.println(k.age);
        k.playGame();

        //  老师 学生 都属于人类  睡觉和吃饭  学生睡觉打呼噜  老师睡觉要搂老婆  学生个性功能玩游戏,老师个性功能教书
    }
}

class 孔子爹 {
    int age = 60;
    public void teache() {
        System.out.println("讲授java");
    }
}

class 孔子 extends 孔子爹 {
    int age = 30;

    @Override
    public void teache() {
        System.out.println("讲授论语");
    }

    public void playGame() {
        System.out.println("玩王者荣耀");
    }
}

案例七:

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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 void eat(){
        System.out.println("吃饭");
    }
    public void sleep(){
        System.out.println("睡觉");
    }
}

public class Teacher extends Person{

    public Teacher() {
        super();
    }

    public Teacher(String name, int age) {
        super(name, age);
    }

    @Override
    public String getName() {
        return super.getName();
    }

    @Override
    public void setName(String name) {
        super.setName(name);
    }

    @Override
    public int getAge() {
        return super.getAge();
    }

    @Override
    public void setAge(int age) {
        super.setAge(age);
    }

    @Override
    public void eat() {
        System.out.println("老师爱吃燃面");
    }

    @Override
    public void sleep() {
        System.out.println("老师独守空房");
    }

    public void teache(){
        System.out.println("教书");
    }
}

public class Student extends Person{
    public Student() {
        super();
    }

    public Student(String name, int age) {
        super(name, age);
    }

    @Override
    public String getName() {
        return super.getName();
    }

    @Override
    public void setName(String name) {
        super.setName(name);
    }

    @Override
    public int getAge() {
        return super.getAge();
    }

    @Override
    public void setAge(int age) {
        super.setAge(age);
    }

    @Override
    public void eat() {
        System.out.println("学生爱吃麻辣烫");
    }

    @Override
    public void sleep() {
        System.out.println("睡觉打呼噜");
    }

    public void playGame(){
        System.out.println("玩游戏");
    }
}

public class MyTest {
    public static void main(String[] args) {
        Person p = new Student();
        p.setName("张三");
        p.setAge(23);
        System.out.println(p.getName() + "===" + p.getAge());
        p.eat();
        p.sleep();
        //向下转型
        Student student = (Student) p;
        student.playGame();

        System.out.println("--------------");
        p=new Teacher();
        p.setName("沈某某");
        p.setAge(10);
        System.out.println(p.getName()+"==="+p.getAge());
        p.eat();
        p.sleep();
        Teacher teacher= (Teacher) p;
        teacher.teache();

        System.out.println("--------------");
         p= new Student("李四", 24);
        System.out.println(p.getName()+"==="+p.getAge());
        p.sleep();
        p.eat();

    }
}

案例八:

public class MyTest {
    public static void main(String[] args) {
        Fu fu = new Zi();
        System.out.println(fu.num);//100
        fu.show();//zi show
        Zi zi= (Zi) fu;
        System.out.println(zi.num);//20
        zi.test();//zi test
    }
}

class Fu{
    int num=100;
    public void show(){
        System.out.println("fu show");
    }

}

class Zi extends Fu{
    int num=20;

    @Override
    public void show() {
        System.out.println("zi show");
    }
    public void test(){
        System.out.println("zi test");
    }
}

案例九:

class A {
	public void show() {
		show2();
	}

	public void show2() {
		System.out.println("我");
	}
}

class B extends A {
	public void show2() {
		System.out.println("爱");
	}
}

class C extends B {
	public void show() {
		super.show();
	}

	public void show2() {
		System.out.println("你");
	}
}
public class DuoTaiTest4 {
		public static void main(String[] args) {
			A a = new B();
			a.show();
			
			B b = new C();
			b.show();
		}
	}

注意输出是:

总结

  • 继承和多态
    继承:子类可以继承父类的非私有成员(成员变量,成员方法) extends
    继承就是为了提高代码的复用性和维护性
    继承的弊端,会产生耦合性。不要为了部分功能而去继承
    继承的注意事项,1.父类私有的成员,子类不能继承。
    构造方法不参与继承
    java只支持单继承,但是支持多层继承,顶层父类Object

  • 当我们在初始化子类时,先要初始化父类的数据,因为子类要继承父类的数据还有使用
    因为在每个类的构造方法中的第一行有一条默认语句 super() 默认调用父类的空参构造

  • super 父类空间的一个标识,你可以理解为父类的一个引用 利用super 可以访问父类的数据(构造方法,成员变量和成员方法)

  • 变量的访问原则,遵循就近原则,先在局部找,局部找不到,去本类成员位置找,如果找不到,去父类成员位置找,如果如果找不到就报错

  • 方法重写:当子类出现了和类一模一样的方法时(方法名,参数列表,返回值类型)就会发生方法覆盖现象
    为什么要要有方法重写:就是子类对父类功能的实现不满意,或者说我们父类功能的基础上去扩展。

  • final的使用

  • 方法重写注意事项:私有方法不能重写
    静态方法不参与重写
    重写时子类方法的权限修饰符要比父类的高,或者一样
    父类的final修饰的方法子类不能重写

  • 多态:要有继承,要有方法重写,父类引用指向子类对象
    向下转型

你可能感兴趣的:(代码块,继承;方法的重写与重载的区别;final关键字;多态;向下转换(案例:孔子装爹))