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;
🌟 多态在方法调用时使用了动态绑定,只要该方法不是 private
、static
和final
方法,就使用动态绑定。(父亲当了儿子,但仍然只能调用父亲自己的方法,如果该方法儿子也有,就调用儿子的。但不能调用儿子特有的方法。)
0.4 抽象类
🐼 引入:当父类方法不知道如何实现,比如动物类,可以有一个吃饭的方法,但是基于该类的子类,可以是不同的动物,那吃饭的方法就不同,这个时候,动物类的这个吃饭方法就不知道如何实现,就可以申明为抽象方法,拥有抽象方法的类,必须是抽象类,这种类往往一定会被继承,其抽象方法由子类实现
- 抽象类 用
abstract
关键字实现:abstract Animal {}
- 抽象方法没有方法体:
public abstract void eat();
- 抽象类的价值更多的在于设计,在框架和设计模式中使用较多
- 抽象类不能实例化
- 抽象类不一定要包含抽象方法,但有抽象方法就必须是抽象类
abstract
只能修饰类和方法,不能修饰其它的东西- 如果一个类继承了抽象类,则必须实现抽象类中所有的抽象方法,除非这个继承类也是一个抽象类
- 抽象方法不能用
private
、final
和static
来修饰,因为这些关键字和重写是冲突的
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
- [p]
例子如下:
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> 在外部类中提供一个方法,返回内部类的对象
- 外部其它类访问这个内部类:1> 创建对象
- [>] 内部类和外部类成员重名时,依然是就近访问原则,需要访问外部类的成员时,使用
外部类名.this.成员
4.3 静态内部类
- [>]
静态内部类
定义在外部类的成员位置,并且有static
修饰,可以访问外部类所有的静态成员,但不能直接访问非静态成员,并且可以添加任意访问修饰符 - [>] 外部其它类访问静态内部类:1> 因为是静态,所以可以通过类名访问,所以
new
对象时写为外部类名.内部类名
即可 2> 在外部类中编写一个方法返回静态内部类对象