Java学习日志Day11_继承实例_多态_继承多态实例_抽象类初窥

这篇博客主要探讨了Java中的继承、多态和抽象类。在继承中,详细解释了成员方法的访问规则,并强调了final关键字的作用。关于多态,介绍了其前提条件、成员访问特点以及多态的优势和劣势。对于抽象类,解释了其概念、特点,以及如何通过抽象类强制子类实现抽象方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、继承

  1. 继承中的成员方法的访问:
    如果子类和父类的成员方法名称不一致,分别访问即可!
    子类和父类的成员方法名称一致,
    子类中存在,访问子类的;
    如果不存在,访问父类,如果父类没有,报错!
举例:
//定义一个父类
class Fu{
    public void method(){
        System.out.println("method fu...");
    }
}
//子类
class Zi extends  Fu{
    public void show(){
        System.out.println("show zi...");
    }
    public void method(){
        System.out.println("method zi...");
    }
}
//测试类
public class ExtendsDemo {
    public static void main(String[] args) {
        //创建子类对象
        Zi z = new Zi() ;
        z.show();
        z.method();
    }
}
  1. 成员方法的分类:
    是否存在返回值,是否带参

根据具体需求然后定义相对应的功能!
参数类型:
基本类型/引用类型
返回值类型:
基本类型/引用类型

举例:
//定义一个父类
class Father{

    //带参的,没有返回值类型
    public void show(String str){
        System.out.println(str);
    }
    //带参的,有返回值类型的
    public String method(int num){
        return "helloworld"+num ;
    }
}

//子类
class Son extends  Father{
    //子类的成员方法
    //不带参的,没有返回值的
    public void function(){
        System.out.println("function son...");
    }

    //不带参的,有返回值的
    public String function2(){
        return "JavaEE" ;
    }
}

//测试类
public class ExtendsDemo2 {
    public static void main(String[] args) {

        //创建子类对象
        Son s = new Son() ;
        s.show("helloworld,javaee");
        String str = s.method(100);
        System.out.println(str);

        s.function();
        String str2 = s.function2();
        System.out.println(str2);
    }
}
  1. final关键字修饰基本类型/引用类型的区别
    final:本身:最终的,无法更改的 状态修饰符

    当final修饰基本数据类型,基本数据类型的值不能再改变,只能赋值一次!

    开发中,定义基本数据类型的常量:
    在一个类的成员位置:
    public static final int xxx = xx ;

    当final修饰引用数据类型,引用数据类型的地址值不能在改变!

    在开发中, 在一个类中引用类一个类的实例!

举例:
class Demo{

    //传统定义方式
    public static final int s1 = 100 ;
    public static final int s2 = 200 ;
    public static final int s3 = 300 ;
    public static final int s4 = 400 ;

    public static final String str1 = "FRONT" ;
    public static final String str2 = "BEHIND" ;
    public static final String str3 = "LEFT" ;
    public static final String str4 = "RIGHT" ;

    //常量:引用类型
    public static final Student s = new Student() ; //静态实例变量

}
enum  Demo2{ //枚举类型(JDK5以后的枚举)

    //一堆字符串常量
    FRONT,BEHIND,LEFT,RIGHT;

}

//定义学生类
class Student{
     int age = 20 ; //成员位置
}


//测试类
public class FinalDemo {
    public static void main(String[] args) {

        //定义一个变量:
        int num = 100 ;
        System.out.println(num);//这是一个变量
        System.out.println("--------------------");

        //定义final修饰的变量
        final int num2 ;//final修饰的基本数据类型的变量
        num2 = 200 ; //只能赋值一次,常驻内存(已经是常量:自定义常量)
        System.out.println(num2);
       // num2 = 300 ;

        System.out.println("---------------------");
        int x = 100 ;
        x = 1000 ;
        System.out.println(Demo.s1) ;
        System.out.println(Demo.s2) ;
        System.out.println(Demo.s3) ;
        System.out.println(Demo.s4) ;

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

        //创建一个学生类对象;
        //改变当前类中的成员变量:依然可以更改,但是此时不能在重新new对象了
       final Student s = new Student() ;//com.qf.extends_01.Student@1540e19d
        System.out.println(s);
        s.age = 30 ;
        System.out.println(s.age);
        s.age  = 25 ;
        System.out.println(s.age);
        
       // s = new Student() ; 不能重新进行实例化了(final修饰之后,学生对象的地址值无法改变的!)
    }
}

二、多态:一个事物在不同时刻体现的不同形态(内存中的变化)

举例:
水是一个事物
水,固态,也可以是气态,也是液体!

猫是一个事物
猫也可以叫做动物

  1. 要使用多态,要遵循它的前提条件:
    1)必须存在继承关系 (没有继承关系,不谈多态!)
    2)必须有方法重写 (子类继承父类,需要将父类的功能覆盖掉),使用子类的功能;
    3)必须存在父类引用指向子类对象(“向上转型”)
    class Fu{}
    class Zi extends Fu{}
    之前:Zi zi = new Zi() ;
    现在:多态: Fu f = new Zi() ;
  2. 在多态中,的成员访问特点:
    Fu f = new Zi() ;
    非静态
    成员变量:编译看左,运行看左
    成员方法:编译看左,运行看右 :由于存在子类重写父类的功能,所以使用的子类的功能
    静态方法: 静态的东西都是跟当前类有关系:优先进内存(随着类的加载而加载)
    静态方法–算不上方法重写:编译看左,运行看左
    构造方法:父类先初始化,然后子类在进行初始化
    孔子装爹
举例:
//父类
class Fu{
    public Fu(){
        System.out.println("这是父类的无参构造方法");
    }
    int num = 20 ;
    public void show(){

        System.out.println("show Fu");
    }

    //静态方法
    public static void function(){
        System.out.println("function Fu");
    }
}
//子类
class Zi extends  Fu{
    public Zi(){
        //super();
        System.out.println("这是Zi类的无参构造方法");
    }
    int num = 30 ;
    //重写
    public void show(){
        System.out.println("show Zi");
    }

    //静态方法
    public static void function(){
        System.out.println("function Zi");
    }
}

//测试类
public class DuoTaiDemo {
    public static void main(String[] args) {


        //父类引用指向子类对象
        Fu f = new Zi() ;  //向上转型
        System.out.println(f.num);
       // System.out.println(f.num2); num2在Fu类中不存在
        f.show() ;
        f.function();
       // Fu.function();
    }
}
  1. 多态的好处是什么?
    1)可以提高代码的复用性 (是由继承保证的)
    2)可以提高代码的扩展性(多态完成:父类引用指向子类对象:Fu f = new Zi()) ;
举例:
//动物类
class Animal{
    //吃
    public void eat(){
        System.out.println("动物都需要吃饭...");
    }
    //睡
    public void sleep(){
        System.out.println("动物困了都需要休息...");
    }
}
//定义狗类
class Dog extends  Animal{
    public void eat(){
        System.out.println("狗吃骨头...");
    }
    public void  sleep(){
        System.out.println("狗躺着睡觉...");
    }
}
//定义猫类
class Cat extends  Animal{
    public void eat(){
        System.out.println("猫吃鱼...");
    }
    public void  sleep(){
        System.out.println("猫趴着睡觉...");
    }
}

//猪类
class Pig extends  Animal{
    public void eat(){
        System.out.println("猪吃白菜...");
    }
    public void  sleep(){
        System.out.println("猪卧着睡觉...");
    }

}

//优化2:定义一个动物工具类
class AnimalTool{
    //构造方法私有化
    private AnimalTool(){}
    //定义功能:养狗
    /*
    public static void createDog(Dog d){ //形式参数 狗类型
        d.eat();
        d.sleep();
    }

    //养猫
    public static void createCat(Cat c){
        c.eat();
        c.sleep();
    }

    //养猪
    public static void createPig(Pig p){
        p.eat();
        p.sleep();
    }

     */

    public static void createAnimal(Animal a){ //实际参数传递:Animal a= new Cat() ;
                                                                //Animal a = new Dog ();
        a.eat();
        a.sleep();
    }
}

//测试类
public class DuoTaiDemo2 {
    public static void main(String[] args) {

        //之前的写法
        //喜欢狗,养了一只狗
        Dog d = new Dog() ;  //内存是狗         Animal a = new Dog() ;//内存是狗 :狗是动物
        d.eat();
        d.sleep();
        Dog d2 = new Dog() ;
        d2.eat();
        d2.sleep();
        System.out.println("----------------------");
        //养一只猫
        Cat c = new Cat() ;
        c.eat();
        c.sleep();
        Cat c2 = new Cat() ;
        c2.eat();
        c2.sleep();

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

        //优化1: 需要提供 名字createCat(Cat c)  /createDog(Dog d)
        //测试
        createDog(d);
        createDog(d2);
        createCat(c);
        createCat(c2);
        System.out.println("=======------------------======================");

        //上面的优化可以使用:但是不好:
        //当前具体动物类越来越多的时候,createXXX(具体动物类型 参数名) 越来越多,代码量大!

        //继续优化2:
        //单独定义一个类: 针对动物操作的工具类:AnimalTool
        /*
        AnimalTool.createDog(d);
        AnimalTool.createCat(c);
        Pig pig = new Pig() ;
        AnimalTool.createPig(pig);
        */

        //上面虽然可以,但是很麻烦,动物类越来越多,功能也越来越多,没有丝毫扩展,代码量很大

        //父类引用指向子类对象 :Animal a = new Cat() / new Dog() /new Pig() ;

        //方法的参数参数如果是父类型,
        AnimalTool.createAnimal(d);
        AnimalTool.createAnimal(c);
        AnimalTool.createAnimal(new Pig());
    }

    //定义养猫和养狗的功能
    public static void createCat(Cat c){ //形式参数 猫类型  ---->实际传递---需要当前这个类的对象
        c.eat();
        c.sleep();
    }

    public static void createDog(Dog d){ //形式参数 狗类型
        d.eat();
        d.sleep();
    }
}
  1. 多态的弊端:
    不能访问子类的特有功能!

    向上转型:父类引用指向子类对象

    如果能够使用子类型,就可以访问它的功能!

    解决方案:
    1)子类 引用 指向自己本身:子类对象
    虽然可以访问,但是多态中,不推荐,因为重新new 对象,消耗堆内存空间
    2) 将父类引用强制转换为子类引用 :向下转型 ,前提:必须存在向上转型
    Fu f = new Zi() ;//向上转型
    Zi z = (Zi)f ; //向下转型
    推荐2) :不会重新在堆内存中开辟空间,结束内存空间!

举例:
class Father{

    public void show(){
        System.out.println("show Father...");
    }
}
//子类
class Son extends  Father{
    public void show(){
        System.out.println("show Zi...");
    }

    //子类的特有功能
    public void playGame(){
        System.out.println("可以玩游戏...");
    }
}
//测试类
public class DuoTaiDemo3 {
    public static void main(String[] args) {

        //多态的创建对象
        Father father = new Son() ; //向上转型:父类引用指向子类对象
        father.show() ;
       // father.playGame() ;

        Son s  = new Son() ;
        s.playGame();

        Son s2 = (Son) father; //向下转型
        s2.playGame();
    }
}
  1. 多态的向下转型,如果使用不当,会出现异常!

    ClassCastException:类转换异常:
    堆内存中的变化 和接收的类型不匹配!
    类转换异常

举例:
//父类
class Animal2{
}
//子类
class Cat2 extends  Animal2{
}
class Dog2 extends  Animal2{}

//测试类
public class DuoTaiDemo4 {
    public static void main(String[] args) {
            //多态创建对象
        Animal2 a = new Cat2() ; //堆内存中猫的实例 (猫是动物)
        Cat2 c = (Cat2)a ; //将猫还原了  (猫是猫)  向下转型

        a = new Dog2() ;//堆内存中是狗的实例(狗是动物)
        Dog2 d = (Dog2)a; //还原成狗了

     //  Cat2 c2 = (Cat2)a; //ClassCastException:类转换异常:属于运行时期异常!
    }
}

```java
综合练习:

/*需求:
   设计程序:
           有一个台灯:Lamp ,台灯有开灯的功能on,
           它里面有一个灯泡属性bubble ,灯泡有发亮的功能,红灯泡,绿灯泡分别可以发红光,可以发绿光,
 
       使用面向编程方式去设计这个程序
 
     分析:
           台灯--->是一个真实事物           --->定义台灯类
           灯泡--->也是真实事物            --->定义灯泡类
 */

//台灯类
public class Lamp {

    //灯泡属性
    private Bubble bubble ;//灯泡属性


    //开灯的功能
    public  void on(Bubble bubble){ //开灯,灯泡要发亮
            bubble.shine();
    }
}

//创建灯泡类
public class Bubble {


    //发亮的功能
    public void shine(){
        System.out.println("灯泡可以发亮");
    }
}

public class GreenBubble extends Bubble {

    @Override
    public void shine() {
        System.out.println("灯泡可以发绿光了...");
    }
}

public class RedBubble extends  Bubble {

        //发亮:发红光
        public void shine(){
            System.out.println("灯泡可以发红光...");
        }
}

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


        //创建台灯类对象
        Lamp lamp = new Lamp() ;
        //父类引用指向子类对象
        Bubble bubble = new RedBubble() ;
        lamp.on(bubble);
        Bubble bubble2 = new GreenBubble() ;
        lamp.on(bubble2);
        System.out.println("-----------------");

        lamp.on(new RedBubble()) ;

        lamp.on(new GreenBubble()) ;
    }
}

三、抽象类

  1. 什么是抽象类?
    在现实世界存在真实事物,本身就是概括性的事物,这个时候,为了将具体的事物的功能给出具体体现,那么当前概括性的事物中
    加入抽象-----abstract,并且它里面的一些功能仅仅只是声明,并不给出具体体现!
举例:
           猫狗案例---->抽取动物类 :父类  (概括性的)/睡的功能   ---- 只有具体的猫和狗,才有具体的吃的,睡的功能!
 
   java提供了关键字----> 在类上加入一个修饰:   abstract
   abstract class 抽象类名{
 
   }

如果一个类中有抽象方法,那么这个类一定是抽象类;
如果一个类是抽象类,不一定有抽象方法!

  1. 什么叫抽象方法?
    抽象方法就是没有方法体的方法;

    public  abstract 返回值类型 方法名(形式参数);
    
  2. 抽象类有一个特点:
    抽象类不能实例化-----不能 new

    抽象类的子类:
    1)是抽象类,也不能实例化!
    如果仅仅存在父类,和子类,这个子类还是抽象类—毫无意义! new 不了!
    2)研究的具体类: 可以实例化的!
    对象的创建还是子类创建的!

                       抽象的父类名 对象名 = new 子类名() ;   //抽象类多态
    

    抽象类的本质---->就是强制子类必须要将父类的中抽象功能,重写!

举例:
/*猫狗案例---继承版---->改造
                               Animal:抽象类 + 多态进行测试!
                                   eat() ;
                                   sleep();
         
                     分析:
                            从具体到抽象
                                   猫: 姓名,年龄,颜色
                                   行为:吃,睡,玩游戏
         
                                   狗:姓名,年龄,颜色
                                   行为:吃,睡,看门
         
                                 将猫和狗中共有特性抽取到一个独立的事物:动物事物
                                   Animal--->抽象类:abstract修饰
                                       属性:姓名,年龄,颜色
                                       行为:吃,睡 ----定义抽象方法 :public abstract ....
        
        
                                  猫和狗都继承自Animal
                                          猫:玩游戏:特有功能
                                          狗:看门:特有功能
        
        
                     代码实现:
                          从抽象到具体
        
                              定义抽象的Animal
                              定义子类
                              测试类:多态
         									进行测试*/
//抽象的父类
public abstract class MyAnimal {

    private String name ;//姓名
    private int age ;//年龄
    private String color ;//颜色

    //无参构造方法
    public MyAnimal() {
    }

    //有参构造
    public MyAnimal(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    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 String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
    //吃:只有具体的动物:才能吃的是什么,eat方法:仅仅是一个声明,没有方法体
    public abstract  void eat() ;	//抽象类要定义抽象方法的时候,abstract不能省略!
    public abstract  void sleep() ;
}

public class MyCat extends MyAnimal {

    //有参/无参

    public MyCat() {
        //super() ;
    }

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

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

    @Override
    public void sleep() {
        System.out.println("猫趴着睡觉");
    }

    //特有功能
    public void playGame(){
        System.out.println("猫和老鼠玩游戏...");
    }
}

public class MyDog extends MyAnimal {
    public MyDog() {
    }

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

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

    @Override
    public void sleep() {
        System.out.println("狗躺着睡觉");
    }
    //特有功能
    public String lookDoor(){
        return  "狗可以看门" ;
    }
}

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

        //多态进行测试
        //创建一只狗
        //无参构造+setXXX(xx)
        MyAnimal ma = new MyDog() ;//向上转型
        ma.setName("小黑");
        ma.setAge(5);
        ma.setColor("黑色");
        System.out.println(ma.getName()+"---"+ma.getAge()+"---"+ma.getColor());
        ma.eat();
        ma.sleep();
      //  ma.lookDoor() ;//父类中不存在

        MyDog mydog = (MyDog) ma ;
        mydog.lookDoor() ;

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

        //方式2:有参构造直接赋值
        ma = new MyDog("哮天犬",100,"黑色") ;
        System.out.println(ma.getName()+"---"+ma.getAge()+"---"+ma.getColor());
        ma.eat();
        ma.sleep();
        MyDog mydog2 = (MyDog) ma ; //向下转型
        mydog2.lookDoor() ;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

igfff

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值