Java学习2-3_面向对象高级

三、面向对象高级

1.1 继承

“给类进行等级层次的划分”

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

Java不支持多继承,但支持多重继承

1.1.1 特性
  1. 子类拥有父类非 private 的属性、方法。
  2. 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展
  3. 子类可以用自己的方式实现父类的方法。
  4. Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 A 类继承 B 类,B 类继承 C 类,所以按照关系就是 C 类是 B 类的父类,B 类是 A 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
  5. 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
1.1.2 子类实例化内存分析

子类在实例化的时候,首先在堆空间创建一个父类对象,然后子类在栈内存中拥有一个名字,子类中的super事实上时指向父类的堆空间中的地址。当调用子类对象访问器的时候,事实上是通过super修改父类中的对象

在这里插入图片描述

1.2 super

通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。

可以操作父类的构造方法、父类的属性、父类的方法

1.3 重写(override)

  1. 参数列表必须相同
  2. 返回类型必须相同
  3. 访问权限不能比父类中被重写的方法的访问权限更低
  4. 父类的成员方法只能被它的子类重写
  5. 声明未static和private的方法不能被重写,但是能够被再次声明

面试题:

Java中重写(Override)与重载(Overload)的区别

  1. 发生的位置:重载:一个类中;重写:子父类中
  2. 参数列表:重载:必须不同;重写:必须相同
  3. 返回类型:重载:与返回类型无关;重写:返回值类型必须一致
  4. 访问权限:重载:与访问权限无关;重写:返回值类型必须一致
  5. 异常处理:重载:与异常无关;重写:异常范围更小,但不能抛出新的异常
/*
 * 重写与重载
 */
class Animal {
    private String name;
    public void call() {
    }
    //重载,方法名相同,参数不同
    public void call(int time) {
    }
}

class Dog extends Animal {
    //重写,方法名与参数相同
    public void call() {
    }
}

1.4 final

  1. final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写。
  2. 实例变量也可以被定义为 final,被定义为 final 的变量不能被修改。被声明为 final 类的方法自动地声明为 final,但是实例变量并不是 final
  3. 理解:变量的本质就是一个“可操作的存储空间”,空间位置是确定的,里面放的东西不确定,可以通过变量名来访问“对应的存储空间”,从而操作这个“存储空间”存储的值。
  4. 一般用来修饰常量

1.5 抽象类

1.5.1 概念

抽象类必须使用abstract class声明一个抽象类中可以没有抽象方法。抽象方法必须写在抽象类或者接口中。

1.5.2 抽象方法

只声明而未实现的方法称为抽象方法(未实现指的是:没有“{ }”方法体),抽象方法必须使用abstract关键字声明。

/*
 * 抽象类
 */
abstract class ClassName {
    public abstract void methodName();//抽象方法
}
1.5.3 抽象特点
  1. 抽象类不能被实例化
    • 抽象类本身不能被实例化
    • 一个抽象类必须被子类所继承,被继承的子类(如果不是抽象类)则必须(覆写)重写抽象类中全部抽象方法。
  2. 抽象类可以有构造方法
    • 子类对象实例化的时候的流程与普通类的继承是一样的,都是先调用父类中的构造方法(默认无参数),之后再调用子类自己的构造方法
  3. 抽象类和普通类的区别
    • 抽象类必须用public或者protected修饰(如果用private修饰,那么子类则无法继承,也就无法实现其抽象方法)
    • 抽象类不能用new关键字实例化创建对象,但是再子类创建时,抽象父类也会被JVM实例化
    • 如果一个子类继承抽象类,那么必须实现其所有的抽象方法,那么子类也必须定义为abstract类

1.6 接口

1.6.1 概念

如果一个类中的全部方法都是抽象方法,全部属性都是全局常量,那么此时就可以将这个类定义成一个接口,伪代码如下

/*
 * 接口
 */
interface InterfaceName {
    全局常量;
    抽象方法;
}
1.6.2 面向接口编程思想

这种思想是接口是定义(规范,约束)与实现(名实分离的原则)的分离。

优点:

  1. 降低程序的耦合性
  2. 易于程序扩展
  3. 有利于程序维护
1.6.3 接口实现 implements

接口可以多实现

/*
 * 接口实现
 */
class SonClass implements FatherInterface1,FatherInterface3,FatherInterface3 {

}
1.6.4 接口继承
/*
 * 接口继承
 */
interface A extends B,C {

}

注意:一个接口如果想要使用,必须依靠子类。子类(如果不是抽象类的话)要实现接口中的所有抽象方法

1.6.5 接口和抽象类的区别
  1. 抽象类要被子类继承,接口要被类实现
  2. 接口只能声明抽象方法,抽象类中可以声明抽象方法,也可以写非抽象方法
  3. 接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量
  4. 抽象类使用继承来使用, 无法多继承。 接口使用实现来使用, 可以多实现
  5. 抽象类中可以包含static方法 ,但是接口中不允许(静态方法不能被子类重写,因此接口中不能声明静态方法)
  6. 接口不能有构造方法,但是抽象类可以有

1.7 多态

1.7.1 概述

多态就是对象的多种表现形式(多种体现形态)

1.7.2 多态的体现
  1. 对象的多态性,从概念上非常好理解,在类中有子类和父类之分,子类就是父类的一种形态 ,对象多态性就从此而来。
  2. 方法的重载 和 重写 也是多态的一种,不过是方法的多态(相同方法名的多种形态)。重载: 一个类中方法的多态性体现;重写: 子父类中方法的多态性体现。
1.7.3 多态的使用:对象的类型转换

向上转型:子类实例变为父类实例

向下转型:父类实力强制变为子类实例

1.8 instanceof

二元操作符(运算符),也是Java的保留关键字

作用:它的作用是判断其左边对象是否为其右边类的实例,返回的是boolean类型的数据。用它来判断某个对象是否是某个Class类的实例。

boolean result = object instanceof class;

1.9 Object类

Object类是所有类的父类(基类),如果一个类没有明确的继承某一个具体的类,则将默认继承Object类

1.9.1 Object多态

使用Object可以接收任意的引用数据类型

1.9.2 toString

Object的toString方法, 返回对象的内存地址,通常重写

1.9.3 equals

指示某个其他对象是否“等于”此对象。

Object的equals方法:实现了对象上最具区别的可能等价关系; 也就是说,对于任何非空引用值x和y ,当且仅当 x和y引用同一对象( x == y具有值true )时,此方法返回true 。

重写时的5个特性:

  1. 自反性:对于任何非空的参考值x,x.equals(x)应该返回true。
  2. 对称性:对于任何非空引用值x和y,x.equals(y)应该返回true当且仅当y.equals(x)回报true。
  3. 传递性:对于任何非空引用值x,y和z,如果x.equals(y)回报true个y.equals(z)回报true,然后x.equals(z)应该返回true。
  4. 一致性:对于任何非空引用值x和y,多次调用x.equals(y)始终返回true或始终返回false,前提是未修改对象上的equals比较中使用的信息
  5. 非空性:对于任何非空的参考值x ,x.equals(null)应该返回false

1.10 内部类

在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类

1.10.1 成员内部类

成员内部类是最普通的内部类,它的定义为位于另一个类的内部

特点: 成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)

注意:当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问 的是成员内部类的成员。如果要访问外部类的同名成员,需要通过:

OutClass.this.value
OutClass.this.mathod()

外部使用成员内部类

Outter outter = new Outter();
Outter.Inner inner = outter.new Inner();
1.10.2 局部内部类

局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或 者该作用域内

/**
 * 内部类
 */
class Person {
    public Person() {
    }

    //成员内部类
    class Man {
        public Man(){
        }

        public People getPerson() {
            //局部内部类
            class Student extends People {
                int age = 0;
            }
            return new Student();
        }
    }
}

注意:局部内部类不能有public、protected、private以及static修饰符

1.10.3 匿名内部类

伪代码如下

new 父类构造器(参数列表)|实现接口(){
	//匿名内部类的类体部分
}

使用匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一 个接口。同时它也是没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的引用,隐式引用

注意:

  1. 使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或 者实现一个接口。
  2. 匿名内部类中是不能定义构造函数的
  3. 匿名内部类中不能存在任何的静态成员变量和静态方法。
  4. 匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效
  5. 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法
  6. 只能访问final型的局部变量
1.10.4 静态内部类

静态内部类也是定义在另一个类里面的类,但是在类的前面多了一个关键字static。

静态内部类不需要依赖于外部类对象的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法。

/**
 * 内部类
 */
public class Test {
    public static void main(String[] args) {
        Outter.Inner inner = new Outter.Inner();
    }
}
class Outter {
    public Outter() {
    }
    static class Inner {
        public Inner() {
        }
    }
}

1.11 包装类

在Java中有一个设计的原则“一切皆对象”,那么这样一来Java中的一些基本的数据类型,就完全不符合于这种设计思 想,因为Java中的八种基本数据类型并不是引用数据类型,所以Java中为了解决这样的问题,引入了八种基本数据类型 的包装类

序号基本数据类型包装类
1intInteger
2charCharacter
3floatFloat
4doubleDouble
5booleanBoolean
6byteByte
7shortShort
8longLong

以上的八种包装类,可以将基本数据类型按照类的形式进行操作。 但是,以上的八种包装类也是分为两种大的类型的:

  • Number:Integer、Short、Long、Double、Float、Byte都是Number的子类表示是一个数字。
  • Object:Character、Boolean都是Object的直接子类。
1.11.1 装箱和拆箱

将一个基本数据类型变为包装类,那么这样的操作称为装箱操作。

将一个包装类变为一个基本数据类型,这样的操作称为拆箱操作。

JDK1.5,Java新特性增加了自动装箱和自动拆箱,可以通过包装类进行四则运算和自增自建操作

Float f = 10.3f;//自动装箱
float x = f;//自动拆箱
1.11.2 字符串转换

使用包装类可以将一个字符串变为指定的基本数据类型,一般在接收输入数据上使用较多

1.12 可变参数

一个方法中定义完了参数,则在调用的时候必须传入与其一一对应的参数,但是在JDK 1.5之后提供了新的功能,可以根据需要自动传入任意个数的参数,伪代码:

返回值类型 方法名称(数据类型…参数名称){
	//参数在方法内部 , 以数组的形式来接收
}

注意:可变参数只能出现在参数列表的最后。

1.13 递归

递归,在数学与计算机科学中,是指在方法的定义中使用方法自身。也就是说,递归算法是一种直接或者间接调用自身方法的算法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5kosCd1I-1600674464299)(D:\就职培训\学习笔记\Java学习2-3_面向对象高级.assets\image-20200920182740523.png)]

  1. 明确递归终止条件
  2. 给出递归终止时的处理办法

使用包装类可以将一个字符串变为指定的基本数据类型,一般在接收输入数据上使用较多

1.12 可变参数

一个方法中定义完了参数,则在调用的时候必须传入与其一一对应的参数,但是在JDK 1.5之后提供了新的功能,可以根据需要自动传入任意个数的参数,伪代码:

返回值类型 方法名称(数据类型…参数名称){
	//参数在方法内部 , 以数组的形式来接收
}

注意:可变参数只能出现在参数列表的最后。

1.13 递归

递归,在数学与计算机科学中,是指在方法的定义中使用方法自身。也就是说,递归算法是一种直接或者间接调用自身方法的算法。

在这里插入图片描述

  1. 明确递归终止条件
  2. 给出递归终止时的处理办法
  3. 提取重复的逻辑,缩小问题规模
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页