Java基础学习笔记(二)

本文详细介绍了Java中的继承机制、方法重写、多态性、抽象类、接口的概念以及内部类和代码块的使用。通过这些概念,提升了代码复用性和灵活性,展示了面向对象编程的核心特性。

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

目录

第八课-----继承

一、继承的含义

二、继承的格式

三、方法重写

第九课-----多态

一、多态的形式

二、多态的定义和前提:

三、 instanceof关键字

第十课-----抽象类与接口

一、抽象类概述

二、抽象类

三、接口

第十一课-----内部类与代码块

一、什么是内部类

二、内部类的分类

三、代码块


第八课-----继承

一、继承的含义

        继承描述的是事物之间的所属关系,这种关系是:`is-a` 的关系。例如,兔子属于食草动物,食草动物属于动物。可见,父类更通用,子类更具体。我们通过继承,可以使多种事物之间形成一种关系体系。

继承:就是子类继承父类的属性和行为,使得子类对象可以直接具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。

继承的好处

  1. 提高代码的复用性(减少代码冗余,相同代码重复利用)。
  2. 使类与类之间产生了关系。

二、继承的格式

通过 `extends` 关键字,可以声明一个子类继承另外一个父类,定义格式如下:

class 父类 {

    ...

}



class 子类 extends 父类 {

    ...

}

需要注意

  1. Java是单继承的,一个类只能继承一个直接父类,跟现实世界很像,但是Java中的子类是更加强大的。
  2. 继承实际上是子类相同的属性和行为可以定义在父类中,子类特有的属性和行为由自己定义,这样就实现了相同属性和行为的重复利用,从而提高了代码复用。
  3. 子类继承父类,就可以直接得到父类的成员变量和方法。
  4. 子类不能继承父类的构造方法。
  5. 子类可以继承父类的私有成员(成员变量,方法),只是子类无法直接访问而已,可以通过getter/setter方法访问父类的private成员变量。
  6. 子父类中出现了同名的成员变量时,子类会优先访问自己对象中的成员变量。如果此时想访问父类成员变量我们可以使用super关键字。
  7. super代表的是父类对象的引用,this代表的是当前对象的引用。
  8. 如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。

三、方法重写

概念:子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。

使用场景与案例

发生在子父类之间的关系。

子类继承了父类的方法,但是子类觉得父类的这方法不足以满足自己的需求,子类重新写了一个与父类同名的方法,以便覆盖父类的该方 法。

 @Override:注解,重写注解校验!

这个注解标记的方法,就说明这个方法必须是重写父类的方法,否则编译阶段报错。

建议重写都加上这个注解,一方面可以提高代码的可读性,一方面可以防止重写出错!

注意事项

  • 1. 方法重写是发生在子父类之间的关系。
  • 2. 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
  • 3. 子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。

第九课-----多态


 

一、多态的形式

多态是继封装、继承之后,面向对象的第三大特性。

多态是出现在继承或者实现关系中的。

多态体现的格式:

父类类型 变量名 = new 子类/实现类构造器;

变量名.方法名();

多态的前提:有继承关系,子类对象是可以赋值给父类类型的变量。例如Animal是一个动物类型,而Cat是一个猫类型。Cat继承了Animal,Cat对象也是Animal类型,自然可以赋值给父类类型的变量。

多态的使用场景:

  • 当一个方法的形参是一个类,我们可以传递这个类所有的子类对象。
  • 当一个方法的形参是一个接口,我们可以传递这个接口所有的实现类对象。
  • 而且多态还可以根据传递的不同对象来调用不同类中的方法。

二、多态的定义和前提:

多态: 是指同一行为,具有多个不同表现形式。

例如,Cat和Dog都是动物,都是吃这一行为,但是出现的效果(表现形式)是不一样的。

 前提:

  • 1. 有继承或者实现关系
  • 2. 方法的重写【意义体现:不重写,无意义】
  • 3. 父类引用指向子类对象【格式体现】

多态的运行特点:

调用成员变量时:编译看左边,运行看左边

调用成员方法时:编译看左边,运行看右边

代码示例:

Fu f = new Zi();

//编译看左边的父类中有没有name这个属性,没有就报错

//在实际运行的时候,把父类name属性的值打印出来

System.out.println(f.name);

//编译看左边的父类中有没有show这个方法,没有就报错

//在实际运行的时候,运行的是子类中的show方法

f.show();

多态的弊端:

我们已经知道多态编译阶段是看左边父类类型的,如果子类有些独有的功能,此时多态的写法就无法访问子类独有功能了。

多态的写法就无法访问子类独有功能了。

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型。

回顾基本数据类型转换:

  • 自动转换: 范围小的赋值给范围大的.自动完成:double d = 5;
  • 强制转换: 范围大的赋值给范围小的,强制转换:int i = (int)3.14

多态的转型分为向上转型(自动转换)与向下转型(强制转换)两种。

向上转型:多态本身是子类类型向父类类型向上转换(自动转换)的过程,这个过程是默认的。

  当父类引用指向一个子类对象时,便是向上转型。

  使用格式:

父类类型  变量名 = new 子类类型();

如:Animal a = new Cat();

原因:父类类型相对与子类来说是大范围的类型,Animal是动物类,是父类类型。Cat是猫类,是子类类型。Animal类型的范围当然很大,包含一切动物。所以子类范围小可以直接自动转型给父类类型的变量。

向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。

  一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。

使用格式:

子类类型 变量名 = (子类类型) 父类变量名;

如:Aniaml a = new Cat();

   Cat c =(Cat) a;  

三、 instanceof关键字

        为了避免ClassCastException的发生,Java提供了 `instanceof` 关键字,给引用变量做类型的校验,格式如下:

变量名 instanceof 数据类型

如果变量属于该数据类型或者其子类类型,返回true。

如果变量不属于该数据类型或者其子类类型,返回false。

所以,转换前,我们最好先做一个判断,代码如下:


public class Test {

    public static void main(String[] args) {

        // 向上转型  

        Animal a = new Cat();  

        a.eat();               // 调用的是 Cat 的 eat



        // 向下转型  

        if (a instanceof Cat){

            Cat c = (Cat)a;      

            c.catchMouse();        // 调用的是 Cat 的 catchMouse

        } else if (a instanceof Dog){

            Dog d = (Dog)a;      

            d.watchHouse();       // 调用的是 Dog 的 watchHouse

        }

    }  

}

第十课-----抽象类与接口

一、抽象类概述

​        父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明还有意义,而方法主体则没有存在的意义了(因为子类对象会调用自己重写的方法)。换句话说,父类可能知道子类应该有哪个功能,但是功能具体怎么实现父类是不清楚的(由子类自己决定),父类只需要提供一个没有方法体的定义即可,具体实现交给子类自己去实现。我们把没有方法体的方法称为抽象方法。Java语法规定,包含抽象方法的类就是抽象类。

抽象方法: 没有方法体的方法。

抽象类:包含抽象方法的类。


 

二、抽象类

        如果一个类包含抽象方法,那么该类必须是抽象类。注意:抽象类不一定有抽象方法,但是有抽象方法的类必须定义成抽象类。

定义格式:

abstract class 类名字 {



}

//代码举例:

public abstract class Animal {

    public abstract void run();

}

抽象类的使用:

要求:继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。

抽象类的特征:抽象类的特征总结起来可以说是有得有失

有得:抽象类得到了拥有抽象方法的能力。

有失:抽象类失去了创建对象的能力。

其他成员(构造方法,实例方法,静态方法等)抽象类都是具备的。

抽象类的细节:

  • 1. 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
  •     理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
  • 2. 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
  •     理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
  • 3. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
  •     理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
  • 4. 抽象类的子类,必须重写抽象父类中**所有的**抽象方法,否则子类也必须定义成抽象类,编译无法通过而报错。
  •  理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。
  • 5. 抽象类存在的意义是为了被子类继承。
  •    理解:抽象类中已经实现的是模板中确定的成员,抽象类不确定如何实现的定义成抽象方法,交给具体的子类去实现。

抽象类存在的意义:

​        抽象类存在的意义是为了被子类继承,否则抽象类将毫无意义。抽象类可以强制让子类,一定要按照规定的格式进行重写。

三、接口

概述

        我们已经学完了抽象类,抽象类中可以用抽象方法,也可以有普通方法,构造方法,成员变量等。那么什么是接口呢?接口是更加彻底的抽象,JDK7之前,包括JDK7,接口中全部是抽象方法。接口同样是不能创建对象的。

定义格式

//接口的定义格式:

interface 接口名称{

    // 抽象方法

}



// 接口的声明:interface

// 接口名称:首字母大写,满足“驼峰模式”

接口成分的特点:在JDK7,包括JDK7之前,接口中的只有包含:抽象方法和常量

抽象方法:

        使用`abstract` 关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。

定义格式:

//修饰符 abstract 返回值类型 方法名 (参数列表);

//代码举例:

public abstract void run();

​       注意:接口中的抽象方法默认会自动加上public abstract修饰程序员无需自己手写!!

​       按照规范:以后接口中的抽象方法建议不要写上public abstract。因为没有必要啊,默认会加上。

常量:

        在接口中定义的成员变量默认会加上: public static final修饰。也就是说在接口中定义的成员变量实际上是一个常量。这里是使用public static final修饰后,变量值就不可被修改,并且是静态化的变量可以直接用接口名访问,所以也叫常量。常量必须要给初始值。常量命名规范建议字母全部大写,多个单词用下划线连接。

实现接口的概述:

        类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 ` implements`关键字。

实现接口的格式:

/**接口的实现:

    在Java中接口是被实现的,实现接口的类称为实现类。

    实现类的格式:*/

class 类名 implements 接口1,接口2,接口3...{



}

从上面格式可以看出,接口是可以被多实现的。

类实现接口的要求和意义:

  • 1. 必须重写实现的全部接口中所有抽象方法。
  • 2. 如果一个类实现了接口,但是没有重写完全部接口的全部抽象方法,这个类也必须定义成抽象类。
  • 3. 意义:接口体现的是一种规范,接口对实现类是一种强制性的约束,要么全部完成接口申明的功能,要么自己也定义成抽象类。这正是一种强制性的规范。

接口与接口的多继承:

        Java中,接口与接口之间是可以多继承的:也就是一个接口可以同时继承多个接口。大家一定要注意:

类与接口是实现关系

接口与接口是继承关系

接口继承接口就是把其他接口的抽象方法与本接口进行了合并。

案例演示:

public interface Abc {

    void go();

    void test();

}



/** 法律规范:接口*/

public interface Law {

    void rule();

    void test();

}



 *

 *  总结:

 *     接口与类之间是多实现的。

 *     接口与接口之间是多继承的。

 * */

public interface SportMan extends Law , Abc {

    void run();

}

第十一课-----内部类与代码块
 

一、什么是内部类

        将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。可以把内部类理解成寄生,外部类理解成宿主。

 什么时候使用内部类:

一个事物内部还有一个独立的事物,内部的事物脱离外部的事物无法独立使用。

1. 人里面有一颗心脏。

2. 汽车内部有一个发动机。

3. 为了实现更好的封装性。

二、内部类的分类

按定义的位置来分:

  • 1. 成员内部内,类定义在了成员位置 (类中方法外称为成员位置,无static修饰的内部类)
  • 2. 静态内部类,类定义在了成员位置 (类中方法外称为成员位置,有static修饰的内部类)
  • 3. 局部内部类,类定义在方法内
  • 4. 匿名内部类,没有名字的内部类,可以在方法中,也可以在类中方法外。

成员内部类特点:

无static修饰的内部类,属于外部类对象的。

宿主:外部类对象。

内部类的使用格式:

 外部类.内部类。 // 访问内部类的类型都是用 外部类.内部类

获取成员内部类对象的两种方式:

方式一:外部直接创建成员内部类的对象

外部类.内部类 变量 = new 外部类().new 内部类();

方式二:在外部类中定义一个方法提供内部类的对象

编写成员内部类的注意点:

  • 1. 成员内部类可以被一些修饰符所修饰,比如: private,默认,protected,public,static等
  • 2. 在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量。
  • 3. 创建内部类对象时,对象中有一个隐含的Outer.this记录外部类对象的地址值。

注意:

  1. ​   内部类被private修饰,外界无法直接获取内部类的对象,只能通过3.3节中的方式二获取内部类的对象。
  2. ​   被其他权限修饰符修饰的内部类一般用3.3节中的方式一直接获取内部类的对象。
  3. ​   内部类被static修饰是成员内部类中的特殊情况,叫做静态内部类下面单独学习。
  4. ​   内部类如果想要访问外部类的成员变量,外部类的变量必须用final修饰,JDK8以前必须手动写final,JDK8之后不需要手动写,JDK默认加上。

静态内部类特点:

静态内部类是一种特殊的成员内部类。

有static修饰,属于外部类本身的。

总结:静态内部类与其他类的用法完全一样。只是访问的时候需要加上外部类.内部类。

拓展1:静态内部类可以直接访问外部类的静态成员。

拓展2:静态内部类不可以直接访问外部类的非静态成员,如果要访问需要创建外部类的对象。

拓展3:静态内部类中没有银行的Outer.this。

静态内部类对象的创建格式:

外部类.内部类  变量 = new  外部类.内部类构造器;

调用方法的格式:

  • 调用非静态方法的格式:先创建对象,用对象调用
  • 调用静态方法的格式:外部类名.内部类名.方法名();

局部内部类 :定义在方法中的类。

定义格式:

class 外部类名 {

    数据类型 变量名;

   

    修饰符 返回值类型 方法名(参数列表) {

        

        class 内部类 {

            // 成员变量

            // 成员方法

        }

    }

}

匿名内部类 :是内部类的简化写法。他是一个隐含了名字的内部类。开发中,最常用到的内部类就是匿名内部类了。

格式:

new 类名或者接口名() {

     重写方法;

};

包含了:

  • 继承或者实现关系
  • 方法重写
  • 创建对象

所以从语法上来讲,这个整体其实是匿名内部类对象。

如果我们希望定义一个只要使用一次的类,就可考虑使用匿名内部类。匿名内部类的本质作用是为了简化代码。

匿名内部类前提和格式:

匿名内部类必须继承一个父类或者实现一个父接口。

匿名内部类格式:

new 父类名或者接口名(){

    // 方法重写

    @Override

    public void method() {

        // 执行语句

    }

};

三、代码块

        在Java中,使用{}括起来的代码被称为代码块(Code block),根据其位置和声明的不同,可以分为:

  • 局部代码块。
  • 构造代码块。
  • 同步代码块。
  • 静态代码块。

局部代码块:

在方法中出现,可以限定变量生命周期,及早释放,提高内存利用率。

构造代码块:

在类中方法外出现,每次调用构造方法都会执行,并且在构造方法前执行。

Tip:

构造代码块与构造函数的区别:构造代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化,因为构造函数是可以多个的,运行哪个构造函数就会建立什么样的对象,但无论建立哪个对象,都会先执行相同的构造代码块。

也就是说,构造代码块中定义的是不同对象共性的初始化内容。

静态代码块:

在类中方法外出现,并加上static修饰,常用于给类进行初始化,在加载的时候就执行,并且静态代码块执行一次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值