0 类-超类-子类

0.0 定义子类

💡一个新类继承一个已存在的类,已存在的类称为超类父类新的类称为子类,通过关键字 extends 实现继承Java 是单继承制,不允许同时继承两个类

class A extends B {}

0.1 覆盖方法

💡超类的方法对子类来说并不一定适用,因此可以提供一个新的方法来覆盖超类中的这个方法。编写覆盖方法时需要考虑域的访问权限类方法的访问权限中有介绍:private默认 权限对子类的访问进行了限制

🌟因为子类不能访问超类的私有域,所以在覆盖方法时,如果需要修改超类的私有域,可以使用 super 关键字调用超类的公共方法进行修改

public class Employee {  
    private String name;  
    private double salary;  
    ......
    public double getSalary() {  
        return salary;  
    }
}
 
public class Manager extends Employee {
    private double bonus;
    ......
    public double getSalary() {
        return super.getSalary() + this.bonus;
    }
}

0.2 子类构造器

  • [”] 由于子类不能访问超类的私有域,因此在子类构造器中,可以通过 super 调用超类的构造器。使用 super 调用构造器的语句必须是子类构造器的第一条语句
  • [”] 如果子类的构造器没有显式的调用超类的构造器则将自动调用超类的无参构造器。如果超类没有无参构造器,子类又没有显式的调用,则编译器将报告错误

0.3 多态

  • [”] 一个子类的引用可以赋值给一个父类的变量,但一个父类的引用赋值给一个子类的变量时,必须进行强制类型转换(父亲可以当儿子,但儿子不能够主动当自己的父亲)
class A {...}
class B extend A {...}
 
// 正确(父亲可以当儿子)
A a = new B();
 
// 错误(儿子不能主动当自己的父亲)
B b = new A();
 
// 正确(强制类型转换后可以当自己的父亲)
A a = new A();
B b = (B)a;

🌟 多态在方法调用时使用了动态绑定,只要该方法不是 privatestaticfinal方法,就使用动态绑定。(父亲当了儿子,但仍然只能调用父亲自己的方法,如果该方法儿子也有,就调用儿子的。但不能调用儿子特有的方法。

0.4 抽象类

🐼 引入:当父类方法不知道如何实现,比如动物类,可以有一个吃饭的方法,但是基于该类的子类,可以是不同的动物,那吃饭的方法就不同,这个时候,动物类的这个吃饭方法就不知道如何实现,就可以申明为抽象方法,拥有抽象方法的类,必须是抽象类这种类往往一定会被继承,其抽象方法由子类实现

  • 抽象类abstract 关键字实现:abstract Animal {}
  • 抽象方法没有方法体:public abstract void eat();
  • 抽象类的价值更多的在于设计,在框架和设计模式中使用较多
  • 抽象类不能实例化
  • 抽象类不一定要包含抽象方法,但有抽象方法就必须是抽象类
  • abstract 只能修饰类和方法,不能修饰其它的东西
  • 如果一个类继承了抽象类,则必须实现抽象类中所有的抽象方法,除非这个继承类也是一个抽象类
  • 抽象方法不能用 privatefinalstatic 来修饰,因为这些关键字和重写是冲突的

1 Object类-类祖

Object 类在 Java 中是所有类的父类,所以其默认方法是所有类都有的。该类不需要显式的继承,默认就会继承。

  • [”] 部分方法:
  • clone():创建并返回此对象的一个副本
  • equals(Object obj):指示其它某个对象与此对象是否“相等”
    • == 是一个比较运算符,也判断相等
      • 可以判断基本数据类型,也可以判断引用数据类型
      • 基本类型,就判断值是否相等
      • 引用类型,判断地址是否相等
    • equals() 只能判断引用类型,其默认判断地址是否相同,往往会在子类中重写此方法,用于判断一些内容是否相同
  • hashCode():返回该对象的哈希码值(主要根据对象地址来计算的,但是不能完全等价于地址)
  • toString():返回该对象的字符串表示
    • 默认返回:全类名+@+哈希值的十六进制 (全类名:包名+类名)
    • 该方法一般会被子类重写,用于输出对象的属性
    • 当直接输出一个对象时,该方法会被默认调用
  • finalize():当一个对象没有任何引用的时候,对象的垃圾回收器会调用该方法
    • 一般重写后用于释放资源(比如数据库连接等)
    • 垃圾回收机制的调用由系统决定,可以通过 System.gc() 主动出发垃圾回收机制

2 接口

接口

⚙️ 接口 interface 就是给出一些没有实现的方法,封装到一起,然后某个类要实现某个接口的时候,就必须按规定实现这个接口中规定的方法

interface Usb {
    // 属性
    // 方法
}
 
class A implements Usb {
    // 自己的属性和方法
    // 必须实现接口的抽象方法
}
  • JDK7.0 前,接口中所有的方法都没有方法体,默认都是抽象方法
  • JDK8.0 后,接口中可以有静态方法默认方法,也就是说接口中可以有具体的方法实现
    • 静态方法:例: public static void say() {}
    • 默认方法:例: default public void say() {}
  • 接口不能被实例化
  • 接口中所有方法是 public 方法,也都是 抽象方法,所以这两个关键字可以省略
  • 一个普通类实现接口,必须实现该接口所有的抽象方法,不能只实现一部分
  • 抽象类实现接口,可以不用实现接口方法
  • 一个类可以同时实现多个接口
  • 接口中的所有属性只能是 final,而且是 public static final 修饰符,必须初始化,也因为有 static 关键字,所以可以通过 接口名.属性 直接访问
  • 接口不能继承类,但是可以继承多个接口,例: interface A extends B,C {}
  • 接口权限的修饰符只能是 public默认(不写)
  • 当子类继承了一个父类,并实现了一个接口,父类中有一个属性于接口中的一个常量相同,这个时候使用该变量需要明确指定,使用父类属性用 super,使用接口因为是常量,直接通过接口名调用

🦄🦄🦄 接口 也有 多态 ,和类的多态类似,可以将编译类型设置为接口类型,但运行类型为实现该接口的类,其方法调用也一样,通过实际的运行类型开始查找

3 lambda表达式

lambda表达式

lambda 表达式的使用,是在 Java 编码的过程中可以传递 代码片段 。其表达形式为:参数 箭头() 表达式

  • [”] 函数式接口

🌟 对于只有一个抽象方法的接口,需要这种接口的对象时,就可以提供一个lambda表达式。这种接口称为函数式接口。

  • [”] 方法引用(用::操作符分隔方法名与对象或类名)
    • [p] object::instanceMethod
    • [p] Class::staticMethod
    • [p] Class::instanceMethod

例子如下:

System.out::println
等价于:
(x) -> System.out.println(x)
 
Math::pow
等价于:
(x, y) -> Math.pow(x, y)
 
String::compareToIgnoreCase
等价于:
(x, y) -> x.compareToIgnoreCase(y)

🌟 构造器的引用方法引用很类似,只不过方法名为 new

// 例子
Person[] people = stream.toArray(Person[]::new);

4 内部类

  • [*] 内部类 是定义在另一个类中的类,内部类具有一下特点:
    • [p] 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据
    • [p] 内部类可以对同一个包中的其他类隐藏起来
    • [p] 当想要定义一个 回调函数 且不想编写大量代码时,使用 匿名(anonymous)内部类 比较便捷

4.0 局部内部类

  • [>] 局部内部类 定义在 方法或代码块中,它可以直接访问外部的所有成员,包括私有
  • [>] 该类不能添加访问修饰符,但是可以用 final 关键字修饰
  • [>] 该类的作用域:仅在定义该类的方法体或代码块中
  • [>] 外部其它类是不能访问内部类的
  • [>] 外部类和局部类成员重名时,默认就近访问原则,如果需要访问外部类的重名成员,可以使用 外部类名.this.成员 去访问

4.1 匿名内部类

  • [>] 匿名内部类 定义在方法或代码块中,该类没有名字(系统底层是有的),且同时直接是一个对象。其外部类的成员访问、修饰符、作用域和上面相同
  • [>] 因为接口不能实例化,所以在匿名内部类 new 一个接口的时候,系统底层其实也是通过一个类去实现该接口,只不过这个类的名字我们不知道,所以叫匿名
new/接口(参数列表) {
    类体
}

4.2 成员内部类

  • [>] 成员内部类 定义在外部类的成员位置,并且没有 static 修饰,可以直接访问外部类的所有成员,包括私有,并且可以添加任意的访问修饰符
  • [>] 外部类访问成员内部类,需要先创建对象,才能调用具体的方法
    • 外部其它类访问这个内部类:1> 创建对象 外部类对象.内部类名 var = 外部类对象.new 内部类名(); 2> 在外部类中提供一个方法,返回内部类的对象
  • [>] 内部类和外部类成员重名时,依然是就近访问原则,需要访问外部类的成员时,使用 外部类名.this.成员

4.3 静态内部类

  • [>] 静态内部类 定义在外部类的成员位置,并且 static 修饰,可以访问外部类所有的静态成员,但不能直接访问非静态成员,并且可以添加任意访问修饰符
  • [>] 外部其它类访问静态内部类:1> 因为是静态,所以可以通过类名访问,所以 new 对象时写为 外部类名.内部类名 即可 2> 在外部类中编写一个方法返回静态内部类对象