第二章Java面向对象:

1️⃣认识类与对象:

面向过程

关于面向过程思想思考问题时,我们首先思考“怎么按步骤实现?

”并将步骤对应成方法, 一步一步,最终完成。 这个适合简单任务,不需要过多协作的情况下。比如,如何开车?

我们很容易就列出实现步骤:

点火 --发动----挂挡----踩油门----走你;

面向对象的思想

面向对象的思想是符合人类的思维模式;

面向对象 可以进行分类;并且用于分析或者开发;

可以把一个庞大的需求 分类处理;

类里的具体描述,使用面向过程来处理;

并且在Java当中有一个定义为万物皆对象;

把现实世界中的具体事务看作成一个一个对象来进行处理问题;

它是一种设计者思维;是把开发人员当成管理者或者设计者;

面向过程 ---咱们程序员属于执行者;而面向对象的思维---是从执行者变成管理者;

面向过程是一种“执行者思维”,解决简单问题可以使用面向过程。

面向对象是一种“设计者思维”,解决复杂、需要协作的问题可以使用面向对象

面向对象编程的指导思想、小结:

⚫ 把现实世界的具体事物全部看成一个一个的对象来解决问题。

⚫ 按照面向对象编程来设计程序:程序代码符合人类思维习惯,更易理解、更简单、更易维护。

类和对象的概念

那么什么是类 和对象呢?

咱们首先来了解什么是类:

  • 在java中有一个定义叫做万物皆对象;我们人认识世界,其实就是面向对象的;首先分类是人们认识世界的一个很自然的过程,在日常生活中会不自觉地进行分类

  • 比如:人类 ; 动物类;物品类;蔬菜类;

  • 而咱们区分的类别;每一个类都有它们特有的特征或者属性;

  • 比如 人类;可以实现直立行走;唱歌;学习;

  • 比如 车类--可以驾驶;、

  • 但是类只是一种泛指;不能代表某个具体的人或者事物;它只是包含对象特有的属性和行为;

而类里的对象;才是真实存在的具体实例。

所以我们可以把类看做:是对象共同特征的描述。

对象:是能够看得到摸的着的真实存在的实体

总结:

类是用于描述同一类型的对象的一个抽象概念;(咱们可以理解成图纸架构;实际去施工或者美化是由对象去完成),类中定义了这一类对象所应具有的共同的属性、方法。

属性和方法

属性——对象具有的各种特征

每个对象的每个属性都拥有特定值、事物的特征,

例如:苹果手机、华为手机

都是属于手机类---但是不是同一个对象:都有(品牌,价格,尺寸)

方法、行为:在类中通过成员方法来体现;

行为是指 这个对象能做什么? 手机可以用来上网冲浪。打游戏。打电话。发短信。等等;

类的定义步骤:

①定义类

②编写类的成员变量

③编写类的成员方法

public class 类名 {
    1、成员变量(代表属性) 
    2、成员方法(代表行为)
    3.还有一种是局部变量
   
* 成员变量和局部变量
 成员变量和局部变量的区别【理解】
类中位置不同:成员变量(类中方法外)局部变量(方法内部或方法声明上)
内存中位置不同:成员变量(堆内存)局部变量(栈内存)
生命周期不同:成员变量(随着对象的存在而存在,随着对象的消失而消失)局部变量(随着方法的调用而
存在,醉着方法的调用完毕而消失)
初始化值不同:成员变量(有默认初始化值)局部变量(没有默认初始化值,必须先定义,赋值才能使用)
}
​
public class Student { }
String name;
double height;
// 属性 (成员变量)
// 行为(方法)
public void study(){
}
public void run(){
}
​
成员变量的完整定义格式是:
  * 修饰符 数据类型 变量名称 = 初始化值;
  * 一般无需指定初始化值,存在默认值。
 类名首字母建议大写,且有意义,满足“驼峰模式”。
    
 一个Java文件中可以定义多个class类,且只能一个类是public修饰,
 而且public修饰的类名必须成为代码文件名。
 实际开发中建议还是一个文件定义一个class类。
   public class Car { }
    class Tyre { // 一个Java文件可以同时定义多个class }
    class Engine { }
    class Seat { } 
    
    
    
    上面的类定义好后,没有任何的其他信息,就跟我们拿到一张张图纸,但是纸上没有任 何信息,这是一个空类,没有任何实际意义。所以,我们需要定义类的具体信息。对于一个 类来说,一般有三种常见的成员:属性 field、方法 method、构造器 constructor。这三 种成员都可以定义零个或多个。

类方法:

方法用于定义该类或该类实例的行为特征和功能实现。

学习方法首先我们要学会

  • 怎么定义方法

  • 怎么调用方法

  • 方法的参数传递机制

  • 方法其他常见形式、技术

方法完整格式:
[修饰符] 方法返回值类型 方法名(形参列表) {
         方法体代码(需要执行的功能代码)•
         return 返回值;•
           }
           
形参是形式参数
实参是实际参数
​
1. 形参:方法定义中的参数
等同于变量定义格式,例如:int number
2. 实参:方法调用中的参数
等同于使用变量或常量,例如: 10 number
​
​
​
注意:
* 方法的修饰符:暂时都使用public static 修饰。
* 如果方法没有返回值,返回值类型为void
* 方法如果申明了具体的返回值类型;返回值类型可以是类类型String  int类型,内部必须使用return返回对应类型的数据
* 形参列表可以有多个,甚至可以没有; 如果有多个形参,多个形参必须用“,”隔开,且不能给初始化值
​
​
* 那我声明完方法要执行,如何进行?
* 必须进行调用;调用格式:方法名称(…)。
​
public static void method ( ) { // 方法体; }
调用方法:
可以直接使用方法名(); 
方法之间允许相互调用,不需要知道方法的具体实现,实现重用,提高效率  
method();
方法必须先定义,后调用,否则程序将报错

构造方法

构造器也叫构造方法(constructor),用于对象的初始化。构造器是一个创建对象时被自

动调用的特殊方法,目的是对象的初始化。构造器的名称应与类的名称一致。Java 通过 new

关键字来调用构造器,从而返回该类的实例,是一种特殊的方法。

构造器的分类

⚫ 无参数构造器(默认存在的):初始化的对象时,成员变量的数据均采用默认值。

⚫ 有参数构造器:在初始化对象的时候,同时可以为对象进行赋值。

[修饰符] 类名(形参列表){ //n 条语句 }
通过 new 关键字调用!! 
构造器虽然有返回值,但是不能定义返回值类型(返回值的类型肯定是本类),不能 在构造器里使用 return 返回某个值。 
如果我们没有定义构造器,则编译器会自动定义一个无参的构造函数。如果已定义 则编译器不会自动添加!
构造器的方法名必须和类名一致!

构造器的作用是什么?使用中有哪些注意点(>=3条)

构造器作用是什么?

用来初始化类的对象的;并返回对象的地址;

1.构造器要用过new关键字调用;在new自动调用类的构造器;

2.构造器不能定义返回值类型;并且于类名同名;系统给一个默认的无参构造;如果自己声明

系统默认提供自动失效

3.子类不可以调用父类构造器;

4.一旦定义有参构造;默认提供的无参构造 自动失效了。需要在次声明无参构造;

构造器于类名类名同名

面试题1:

面向过程和面向对象的区别:
回答:
两者都是软件开发思想,先有面向过程,后有面向对象。在大型项目中,针 对面向过程的不足推出了面向对象开发思想
​

面试题2:

什么是类;什么是对象
类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对 象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特 定类型的对象中的方法和变量的软件模板
​
  什么是对象
​
是当前类里具体实例;它是一种能看的见摸得着的;
​
并且它自身有属性和行为;
​
并且每一个对象属性;默认初始值不同;
​
什么是属性:
​
•                     属性就是对象具有的特征 
​
 例子:  华为手机:型号--价格--尺寸--像素值
​
什么是行为:
​
•                      在类中以方法进行体现;
​
行为是指对象能够做什么?
​
华为手机----{打电话;发短信;拍照片;看视频;打游戏}

面试题3:

* 成员变量和局部变量
 成员变量和局部变量的区别【理解】
 
类中位置不同:成员变量(类中方法外)局部变量(方法内部或方法声明上)
内存中位置不同:成员变量(堆内存)局部变量(栈内存)
生命周期不同:成员变量(随着对象的存在而存在,随着对象的消失而消失)局部变量(随着方法的调用而
存在,醉着方法的调用完毕而消失)
初始化值不同:成员变量(有默认初始化值)局部变量(没有默认初始化值,必须先定义,赋值才能使用)
}

面试题4:

创建对象的机制
​
new关键字;
​
分配对象空间;并对对象的成员变量初始化 0&null;
​
执行属性值的显示初始化;
​
执行构造方法;
​
返回对象的一个地址给相关变量; 

面试题5

什么是形参  什么是实参
   形参:
​
•             形参只是一种形式参数,没有具体值,只是声明了一中参考类型: 
​
•             int   整数 ;  String 字符串;
​
   实参:
​
•            实际参数
​
•            int==10;
​
•            String=张三;3

面试题6

构造器的作用是什么?使用中有哪些注意点(>=3条)
​
构造器作用是什么?
​
用来初始化类的对象的;并返回对象的地址;
​
1.构造器要用过new关键字调用;在new自动调用类的构造器;
​
2.构造器不能定义返回值类型;并且于类名同名;系统给一个默认的无参构造;如果自己声明
​
系统默认提供自动失效
​
3.子类不可以调用父类构造器;
​
4.一旦定义有参构造;默认提供的无参构造 自动失效了。需要在次声明无参构造;
​
构造器于类名类名同名

2️⃣ 方法与方法重载

如果方法不需要返回结果,不需要接收参数,应该怎么办,要注意什么?

  • 方法不需要返回结果,则申明返回值类型为void;方法不需要参数,则形参列表可以不写。

  • 方法没有申明返回值类型,内部不能使用return返回数据。

  • 方法如果没有形参列表,调用的时候则不能传入参数值,否则报错。

this 最常的用法或者使用场景:

就是在程序中产生二义性之处,应使用 this 来指明当前对象;普通方法中,this 总是指

向调用该方法的对象。构造方法中,this 总是指向正要初始化的对象。

构造方法重载与方法重载

构造方法也是方法,只不过有特殊的作用而已。与普通方法一样,构造方法也可以重载。

重载的定义:方法的重载也是一种多实现的体现;可读性好,方法名称相同提示是同一类型的功能,通过形参不同实现功能差异化的选择,这是一种专业的代码设计

同一个类中,出现多个方法名称相同,但是形参列表是不同的,那么这些方法就是重载方法

重载的定义: 1.同一个类 2.多个方法的方法名字相同 3.参数列表不同 参数个数不同 参数的数据类型不同 不同数据类型的参数顺序不同 方法的重载和修饰符和返回值无关

只要是同一个类中,方法名称相同、形参列表不同,那么他们就是重载的方法

案例:方法重载
俄乌冲突:
开发武器系统,功能需求如下:
可以默认发一枚武器。
可以指定地区发射一枚武器。
可以指定地区发射多枚武器
    
    public class Test {•  
        /**(1)默认发一枚武器。*/•   
        public static void fire(){
            System.out.println(“默认发射一枚武器给米国!");•  
                               }•   
  /** (2)可以指定地区发射一枚武器。 */• 
       public static void fire(String location){•
           System.out.println("给"+location+"发射一枚武器!");•
       }•   
/**(3)可以指定地区发射多枚武器。*/•   
   public static void fire(String location , int nums){• 
       System.out.println("给"+location+"发射"+nums+"枚武器!");•
   }•}
​
调用方法的时候,
会通过参数的不同来区分调用的是哪个方法
fire();•fire("米国");•fire("岛国" , 1000);
​

面试题:

什么是方法重载:
同一个类中,出现多个方法名称相同,但是形参列表是不同的,那么这些方法就是重载方法
​
重载的定义:
1.同一个类
2.多个方法的方法名字相同
3.参数列表不同
          参数个数不同
          参数的数据类型不同
          不同数据类型的参数顺序不同
          方法的重载和修饰符和返回值无关
​
只要是同一个类中,方法名称相同、形参列表不同,那么他们就是重载的方法
​

3️⃣封装与继承

封装概述

面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的方式。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。

这个就是我们说的“高内聚,低耦合”的体现之一:

  • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;

  • 低耦合:仅对外暴露少量的方法用于使用

封装的设计思想:

隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的讲,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。

封装的设计思想的应用

(1)类的封装:把属性和方法封装到类的内部,外部通过调用方法完成指定的功能,不需要了解类的内部实现

(2)组件的封装:例如支付宝等支付组件,对外只提供使用接口,我们不需要也无法了解内部的实现

(3)系统的封装:例如我们使用操作系统等,我们只需要知道怎么用,不需要了解内部的实现

属性隐藏起来,若需要访问某个属性,提供公共方法对其访问。对外提供便捷的接口

属性封装的目的
  • 隐藏类的实现细节

  • 让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里面加入控制逻辑,限制对成员变量的不合理访问。

  • 可以进行数据检查,从而有利于保证对象信息的完整性。

  • 便于修改,提高代码的可维护性。

实现步骤
  1. 使用 private 修饰成员变量

private 数据类型 变量名 ;

代码如下:

public class Student {
  private String name;
  private int age;
}

提供 getXxx方法 / setXxx 方法,可以访问成员变量,

public class Student {
  private String name;
  private int age;
​
  public void setName(String n) {
    name = n;
  }
​
  public String getName() {
    return name;
  }
​
  public void setAge(int a) {
    age = a;
  }
​
  public int getAge() {
    return age;
  }
}

访问权限控制

  • 访问权限控制

  • 类的访问控制

  • 类成员的访问控制

什么是权限修饰符?

权限修饰符:是用来控制一个成员能够被访问的范围的。 可以修饰成员变量,方法,构造器,内部类,不同权限修饰符修饰的成员能够被访问的范围将受到限制。

权限修饰符的分类和具体作用范围:

权限修饰符:(private -> 缺省 -> protected - > public )

修饰符同一 个类中同一个包中其他类不同包下的子类不同包下的无关类
private
缺省
protected
public
两⼤类

访问修饰符: 限定类、属性或⽅法是否可以被程序⾥的其他部分访问和调⽤的修饰符 private < default < protected < public ⾮访问修饰符:⽤来修饰或者辅助功能, 例如 :static、final、abstract、synchronized等 主要记住: 外部类修饰符: public或者为默认 ⽅法、属性修饰符:private、default、protected、public

  • public - 公开对外部可⻅

  • protected - 对包和所有⼦类可⻅

  • private - 仅对类内部可⻅

属性或者成员变量,都⽤private修饰,不⽤其他的,这个是java开发的约束属性或者成员变量,都⽤private修饰,不⽤其他的,这个是java开发的约束

static修饰符(静态关键字:static)

static是静态的意思,可以用来修饰

  • 成员变量 静态变量,可以直接通过类名访问

  • 成员方法 静态方法,可以直接通过类名访问

  • 代码块 静态代码块,当Java虚拟机加载类时,就会执行该代码块

使⽤static声明的变量(静态变量),

可以直接使⽤ 类名.变量名访问 ⼀个类不管创建了多少个对象,

static修饰成员变量表示该成员变量只在内存中只存储一份,可以被共享访问、修改。(即 地址不更改;不论调用多少次;地址不会发生改变)

数值默认值是0,布尔型默认值是false,引⽤类型默认值是null

  • ⽣命周期 在第⼀次被访问时创建,在程序结束时销毁

  • 声明为public类型,⼀般这样声明 public static final 存储在⽅法区,和堆栈不⼀样的⼀个空间

public class User { // 成员变量  
    public static int onlineNumber= 161;            
    private String name;
    private int age;
    …•}
​
注意事项:

成员变量可以分为2类

  • 静态成员变量(有static修饰,属于类,内存中加载一次): 常表示如在线人数信息、等需要被共享的信息,可以被共享访问。

  • 实例成员变量(无static修饰,存在于每个对象中):常表示姓名name、年龄age、等属于每个对象的信息。

  • 成员方法的2分类: 静态成员方法(有static修饰,属于类),建议用类名访问,也可以用对象访问。

  • 实例成员方法(无static修饰,属于对象),只能用对象触发访问。 在实例方法里不允许定义static变量

    代码块分为 :静态代码块:
    格式:static{}

    特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次 使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用。

  • 构造代码块(了解,用的少):
  • 格式:{}

    特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行 使用场景:初始化实例资源。

面试题:

Java中目前学习涉及到的四种权限修饰符都有什么?并说明各自的权限范围
​
分类  一种类访问权限修饰      类成员访问访问权限修饰
​
2种:public 和 默认的
​
public :  最公开的访问权限:项目下的所有类都可以访问;
​
default:不是同一个包下 能不能访问?不能访问;同一个类中 同一个包下其他类
​
​
​
4种成员变量:
​
public  公开的
​
default 在别的包下能访问吗:不能
​
protected 同一包下的子类
​
private  最严厉的;只有在同一类种可以访问

继承

继承的由来

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类中无需再定义这些属性和行为,只需要和抽取出来的类构成某种关系。如图所示:

Java中提供一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起父子关系。

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

要符合面向对象的思想;车类继承飞机类;

必须满足同类别 相同的属性和行为;把这些共性的属性放到父类中定义;子类可以拥有独有的属性和行为;如果子类独有的属性和行为定义到父类中;其他子类是不是也要实现;

会导致其他子类也实现这种行为; 显然也是不合符面向对象思想;

并且Java 当中不允许多继承;只能单根继承;也就是说一个类只能由一个直接父类;多层继承

object 顶级父类;

继承的理解
  • 继承:就是子类继承父类的属性行为,使得子类对象具有与父类相同的属性、相同的行为。而子类可以拥有独有的方法;让功能更具体;

继承的好处
  • 类与类之间产生了关系,是学习多态的前提

  • 当子类继承父类后,就可以直接使用父类公共的属性和方法了。因此,用好这个技术可以很好的我们提高代码的复用性 。提高代码的扩展性

继承中成员变量访问特点

在子类方法中访问一个变量,采用的是就近原则。

  1. 子类局部范围找

  2. 子类成员范围找

  3. 父类成员范围找

  4. 如果都没有就报错(不考虑父亲的父亲…)

Super关键字

super关键字来访问父类的成员

格式:

super.父类成员变量/父类成员方法

访问父类构造方法

(1)使用super关键字,super代表父类对象 (2)在子类构造方法中调用且必须是第一句 (3)不可以访问父类中定义为private的属性和方法

面试题:

this&super关键字:
this:代表本类对象的引用
super:代表父类存储空间的标识(可以理解为父类对象引用)
this和super的使用分别
成员变量:
this.成员变量 - 访问本类成员变量
super.成员变量 - 访问父类成员变量
成员方法:
this.成员方法 - 访问本类成员方法
super.成员方法 - 访问父类成员方法
构造方法:
this(…) - 访问本类构造方法
super(…) - 访问父类构造方法
2.3 继承中构造方法的访问特点(理解)
注意:子类中所有的构造方法默认都会访问父类中无参的构造方法
子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化,
原因在于,每一个子类构造方法的第一条语句默认都是:super()
问题:如果父类中没有无参构造方法,只有带参构造方法,该怎么办呢?
1. 通过使用super关键字去显示的调用父类的带参构造方法
2. 在父类中自己提供一个无参构造方法
​

面试题:

继承规范是什么?
要符合面向对象的思想;车类继承飞机类;
​
必须满足同类别 相同的属性和行为;把这些共性的属性放到父类中定义;子类可以拥有独有的属性和行为;如果子类独有的属性和行为定义到父类中;其他子类是不是也要实现;
​
会导致其他子类也实现这种行为; 显然也是不合符面向对象思想;
​
并且Java 当中不允许多继承;只能单根继承;也就是说一个类只能由一个直接父类;多层继承
​
object 顶级父类;
​
​

4️⃣ 方法重写于多态

方法重写:

  • 在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法

  • 当子类需要父类的功能,但父类的该功能不完全满足自己的需求时。子类可以重写父类中的方法。(手机发短信 打电话; 重写后: 聊QQ 看视频)

  • 重写(Override):在继承关系当中.方法名相同,参数列表相同。返回值类型相同或者是其子类;访问权限不能严于父类;

  • 父类的静态方法不能被子类覆盖为非静态方法,父类的非静态方法不能被子类覆盖为静态方法

  • 子类可以定义与父类同名的静态方法,以便在子类中隐藏父类的静态方法(注:静态方法中无法使用super)

  • 覆盖、覆写。方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。

  • 父类的私有方法不能被子类覆盖。不能抛出比父类方法更多的异常

    另外还要注意以下几条:

    • 重写的方法可以使用 @Override 注解来标识。

    • 父类的成员方法只能被它的子类重写。

    • 声明为 final 的方法不能被重写。

    • 声明为 static 的方法不能被重写,但是能够再次声明。

    • 构造方法不能被重写。

    • 子类和父类在同一个包中时,子类可以重写父类的所有方法,除了声明为 private 和 final 的方法。

    • 子类和父类不在同一个包中时,子类只能重写父类的声明为 public 和 protected 的非 final 方法。

面试题:方法重写vs方法重载

比较项位置方法名参数表返回值访问修饰符
方法重写子类相同相同相同或是其子类不能比父类更严格
方法重载同类相同不相同无关
.多态的概述(记忆)
  • 什么是多态

    • 同一个对象,在不同时刻表现出来的不同形态

    • 多态的前提

      • 要有继承或实现关系

      • 要有方法的重写

      • 要有父类引用指向子类对象

多态中的成员访问特点(记忆)

父类类型 对象名称 = new 子类构造器; 向上转型
 接口   对象名称 = new 实现类构造器;
成员访问特点
成员变量
编译看父类,运行看父类
成员方法
编译看父类,运行看子类
/**
    父类
 */
public class Animal {
    public String name = "动物名称";
    public void run(){
        System.out.println("动物可以跑~~");
    }
}
public class Dog extends Animal{
    public String name = "狗名称";
    @Override
    public void run() {
        System.out.println("🐕跑的贼溜~~~~~");
    }
}
public class Tortoise extends Animal{
    public String name = "乌龟名称";
​
    @Override
    public void run() {
        System.out.println("🐢跑的非常慢~~~");
    }
}
​
    public static void main(String[] args) {
        // 目标:先认识多态的形式
        // 父类  对象名称 = new 子类构造器();
        Animal a = new Dog();
        a.run(); // 方法调用:编译看左,运行看右
        System.out.println(a.name); // 方法调用:编译看左,运行也看左,动物名称
​
        Animal a1 = new Dog();
        a1.run();
        System.out.println(a1.name); // 动物名称
    }
}
​
  • 优势 在多态形式下,右边对象可以实现解耦合,便于扩展和维护。 定义方法的时候,使用父类型作为参数,该方法就可以接收这父类的一切子类对象,体现出多态的扩展性与便利。

  • 多态下会产生的一个问题: 多态下不能使用子类的独有功能

向上转型

此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法,不是父类的方法 此时通过父类引用变量无法调用子类特有的方法

自动类型转换(从子到父):子类对象赋值给父类类型的变量指向。 强制类型转换吗(从父到子) 此时必须进行强制类型转换:子类 对象变量 = (子类)父类类型的变量 作用:可以解决多态下的劣势,可以实现调用子类独有的功能。 注意: 如果转型后的类型和对象真实类型不是同一种类型,那么在转换的时候就会出现

总结:

  • 引用数据类型的类型转换,有几种方式? 自动类型转换、强制类型转换。

  • 强制类型转换能解决什么问题?强制类型转换需要注意什么。

    • 可以转换成真正的子类类型,从而调用子类独有功能。

    • 有继承关系/实现的2个类型就可以进行强制转换,编译无问题。

    • 运行时,如果发现强制转换后的类型不是对象真实类型则报错。 类型转换异常:ClassCastException

面试题:

多态中怎么理解向上转型和向下转型 需要注意的是什么:
自己查;

7️⃣抽象类和接口

什么是抽象类:

在Java中abstract是抽象的意思,如果一个类中的某个方法的具体实现不能确定,就可以申明成abstract修饰的抽象方法(不能写方法体了),这个类必须用abstract修饰,被称为抽象类。

提问:什么是抽象 - 抽象是从众多的事物中抽取出共同的、本质性的特征;

  • 使用场景:

  • 当我们在做子类共性功能抽取时,有些方法在父类中并没有具体的体现,这个时候就需要抽象类了!

  • 在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类!

  • 简单来说当系统中出现同一个功能多处在开发,而该功能中大部分代码是一样的,只有其中部分可能不同的时候。

  • 抽象的使用总结与注意事项

    • 抽象类可以理解成类的不完整设计图,是用来被子类继承的。

    • 一个类如果继承了抽象类,那么这个类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。

了解抽象类和普通类的区别

如果类中有抽象字段或者抽象方法, 那么该类就是一个抽象类.

  • 抽象字段: 没有初始化值的变量就是抽象字段.

  • 抽象方法: 没有方法体的方法就是一个抽象方法.

  • 抽象方法是什么样的?

  • public abstract void toHospital() ;

  • 只有方法签名,没有方法体,使用了abstract修饰。 方法签名由方法名称和一个参数列表(方法的参数顺序和类型)组成

  • 抽象类的成员特点(记忆) 成员的特点 成员变量 既 可以是变量也可以是常量 构造方法 空参构造 有参构造 成员方法 抽象方法 普通方法

抽象类中可以没有抽象方法,但包含了抽象方法的类必须被定义为抽象类 如果子类没有实现父类的所有抽象方法,子类必须被定义为抽象类;

不能用abstract修饰变量、代码块、构造器.没有抽象构造方法,也没有抽象静态方法 抽象类中可以有非抽象的构造方法,创建子类的实例时可能调用

面试题:

final和abstract是什么关系?
​
* 互斥关系
* abstract定义的抽象类作为模板让子类继承,final定义的类不能被继承。
* 抽象方法定义通用功能让子类重写,final定义的方法子类不能重写。

接口

接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用。 Java中的接口更多的体现在对行为的抽象!

 ```java
 接口用关键字interface来定义
 public interface 接口名 {
        // 常量
        // 抽象方法
 } 
 
 JDK8之前接口中只能是抽象方法和常量,没有其他成分了。
 接口不能实例化。
 接口中的成员都是public修饰的,写不写都是,因为规范的目的是为了公开化。
 * 接口是用来被类实现(implements)的,实现接口的类称为实现类。实现类可以理解成所谓的子类;    public class 类名 implements 接口名 {}
​
* 接口如何实例化呢?参照多态的方式,通过实现类对象实例化,这叫接口多态。
  多态的形式:具体类多态,抽象类多态,接口多态。
    
接口的注意事项
  • 1、接口不能创建对象

  • 2、一个类实现多个接口,多个接口中有同样的静态方法不冲突。

  • 3、一个类继承了父类,同时又实现了接口,父类中和接口中有同名方法,默认用父类的。

  • 4、一个类实现了多个接口,多个接口中存在同名的默认方法,不冲突,这个类重写该方法即可。

  • 5、一个接口继承多个接口,是没有问题的,如果多个接口中存在规范冲突则不能多继承。

  • 类与类的关系 继承关系,只能单继承,但是可以多层继承

  • 类与接口的关系 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接

  • 接口与接口的关系 继承关系,可以单继承,也可以多继承

抽象类和接口的区别(记忆)
  • 成员区别

    • 抽象类 变量,常量;有构造方法;有抽象方法,也有非抽象方法

    • 接口 常量;抽象方法

  • 关系区别

    • 类与类 继承,单继承

    • 类与接口 实现,可以单实现,也可以多实现

    • 接口与接口 继承,单继承,多继承

      • 设计理念区别

        • 抽象类 对类抽象,包括属性、行为

        • 接口 对行为抽象,主要是行为

8️⃣ 异常

异常是程序在“编译”或者“执行”的过程中可能出现的问题,

比如:数组索引越界、空指针异常、 日期格式化异常,算法异常;

注意异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行.

异常也不是指逻辑代码错误而没有得到想要的结果,例如:求a与b的和,你写成了a-b

常⻅程序错误分三种:

  (1)编译时异常:Java.lang.Exception

  (2)运行期异常:Java.lang.RuntimeException

  (3)错误:Java.lang.Error

对于异常,一般有两种解决方法:

  • 一是遇到错误就终止程序的运行。

  • 另一种方法是由程序员在编写程序时,就考虑到错误的检测、错误消息的提示,以及错误的处理。

使用异常

我们平常说的异常就是指Exception,异常一旦出现,我们就要对代码进行更正,修复程序。

异常(Exception)的分类:是根据在编译时期还是运行时期去检查异常

  • 编译时期异常:checked异常。在编译时期,就会检查,如果没有处理异常,则编译失败。(如日期格式化异常);必须显示处理,否则程序就会发生错误,无法通过编译

  • 运行时期异常:runtime异常。在运行时期,检查异常.在编译时期,运行异常不会被编译器检测到(不报错)。(如数组索引越界异常,类型转换异常)。无需显示处理,也可以和编译时异常一样处理

  • 编译时异常

    • 都是Exception类及其子类

  • 运行时异常

    • 都是RuntimeException类及其子类

    简单理解:编译阶段就是语法语义有可能出现异常;程序不会启动;

    运行时异常就是运行时候;通过编译阶段;中间出现了错误;

Java中如何进行异常处理

Java的异常处理是通过5个关键字来实现的:

  • try :捕获异常:执行可能产生 异常的代码

  • catch:捕获异常 返回捕获的异常信息

  • finally:无论是否发生异常,代码总能执行

  • throw:手动抛出异常;当前捕获⾃⼰处理;位于方法体内部,可作为单独语句使用;抛出一个异常对象,且只能是一个

  • throws:声明方法可能要抛出的各种异常 ;用在方法上,可以将方法内部出现的异常抛出去给本方法的调用者处理。这种方式并不友好,发生异常的方法自己不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡。

Finally关键字
  • ⽤来创建在 try 代码块后⾯执⾏的代码块

  • finally 代码块中的代码总会被执⾏

  • ⼀般⽤于资源回收释放等操作

小结:

  • try-catch-finally结构中try语句块是必须的,catch、finally语句块均可选,但两者至少出现之一

  • 面试题:try-catch块中存在return语句,是否还执行finally块? 如果执行,说出执行顺序

即使 try 和 catch 块中存在 return 语句,finally 语句也会执行。是在执行完finally语句后再通过 return 退出。

  • try-catch- finally块中, finally块唯一不执行的情况是什么?

finally 语句块只有一种情况是不会执行的,那就是在执行finally 之前遇到了System.exit(0)结束程序运行。

throws

抛出异常格式:

方法 throws 异常1 ,异常2 ,异常3 ..{•}
规范做法:
方法 throws Exception{•}代表可以抛出一切异常,
​
    
这种方式并不好,发生异常的方法自己不处理异常,
main()方法声明的异常由Java虚拟机处理
如果异常最终抛出去给虚拟机将引起程序死亡。
    
后期异常处理方式—— 前两者结合    
方法直接将异通过throws抛出去给调用者
调用者收到异常后直接捕获处理。
    
 * 在开发中按照规范来说第三种方式是最好的:底层的异常抛出去给最外层,最外层集中捕获处理。
​
    
    
 演示案例:
    
public class ExceptionDemo {
 public static void main(String[] args) {
 System.out.println("开始");
 // method();
try {
method2();
}catch (ParseException e) {
e.printStackTrace();
}
System.out.println("结束");
}
//编译时异常
public static void method2() throws ParseException {
String s = "2048-08-09";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sdf.parse(s);
System.out.println(d);
}
//运行时异常
public static void method() throws ArrayIndexOutOfBoundsException {
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
}
}
​

throw

Java程序的执行过程中如出现异常,会生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常

  • 由虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例对象并抛出——自动抛出

  • 由开发人员手动创建:Exception exception = new ClassCastException();——创建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样,但是一旦throw抛出,就会对程序运行产生影响了。

在java中,提供了一个throw关键字,它用来抛出一个指定的异常对象。那么,抛出一个异常具体如何操作呢?
  1. 创建一个异常对象。封装一些提示信息(信息可以自己编写)。

  2. 需要将这个异常对象告知给调用者。怎么告知呢?怎么将这个异常对象传递到调用者处呢?通过关键字throw就可以完成。throw 异常对象。

    throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。

throw new NullPointerException("要访问的arr数组不存在");
​
throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");
public class ThrowDemo {
    public static void main(String[] args) {
        //2.创建一个数组 
        int[] arr = {2,4,52,2};
        //根据索引找对应的元素 
        int index = 4;
        int element = getElement(arr, index);
​
        System.out.println(element);
        System.out.println("over");
    }
    /*
     * 1.根据 索引找到数组中对应的元素
     */
    public static int getElement(int[] arr,int index){ 
        if(arr == null){
            /*
             判断条件如果满足,当执行完throw抛出异常对象后,
             方法已经无法继续运算。
             这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。 
              */
            throw new NullPointerException("要访问的arr数组不存在");
        }
        //判断  索引是否越界
        if(index<0 || index>arr.length-1){
             /*
             判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续运算。
             这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。 
              */
             throw new ArrayIndexOutOfBoundsException("哥们,角标越界了~~~");
        }
        int element = arr[index];
        return element;
    }
}

Java异常链是什么

  • 一种面向对象的编程技术,将捕获到的异常重新封装到一个新的异常中,并重新抛出。

有什么用

  • 可以保留每一层的异常信息,用户查看异常的时候,能够从顶层异常信息看到底层异常信

怎么用

  • catch异常之后,将异常作为参数生成一个新的异常并抛出。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值