一、面向对象
8. 继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承格式
class 父类 {
}
class 子类 extends 父类 {
}
使用场景:多个相似的类,有相同的属性和方法,就可以把相同属性和方法集中在父类
公共父类: Wife.java
public class Wife {
private String name;
public int age;
public Wife(String wifeName, int wifeAge) {
name = wifeName;
age = wifeAge;
}
public void sleep(){
System.out.println(name+"在睡觉觉");
}
}
这个Wife类就可以作为一个父类,然后子类继承这个类之后,就具有父类当中的属性和方法,子类就不会存在重复的代码,维护性也提高,代码也更加简洁,提高代码的复用性
子类: Test.java
public class Test extends Wife {
private int wifeId;
public Test(String wifeName, int wifeAge, int wifeId) {
super(wifeName, wifeAge);
this.wifeId = wifeId;
}
public static void main(String[] args) {
Test test = new Test("一之濑千鹤", 18, 12138);
System.out.print(test.wifeId + ":" + test.age + "岁的");
test.sleep();
}
}
继承的特性
- 子类对象拥有父类对象中所有的属性和方法,但是父类对象中的私有属性和方法,子类是无法访问的(只是拥有,但不能使用)。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
- Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
需要注意的是 Java 不支持多继承,但支持多重继承。
深入继承
创建子类对象,会不会调用父类构造方法?会
|
创建子类对象,为什么会调用父类构造方法?
目的是将父类的属性存放在子类对象中
|
创建子类对象,会不会创建父类对象?不会
|
创建子类对象,先调用父类构造方法还是子类构造方法?
先调用子类构造方法
|
创建子类对象,先完成父类构造方法还是子类构造方法?
先完成父类构造方法
|
子类可以继承父类私有化的属性和方法吗?
可以,但不能直接访问
9. super - 父类
通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
作用 在子类中:
- super.属性:调用父类非私有化的成员变量
- super.方法:调用父类非私有化的成员方法
- super():调用父类非私有化的构造方法
A.java
public class A {
public String str1;
public A() {
str1 = "父类的成员属性";
}
public void method01() {
System.out.println("父类的成员方法");
}
}
Test.java
public class Test extends A {
public Test() {
//调用父类非私有化的构造方法
super();
}
public void fun() {
//调用父类非私有化属性
System.out.println(super.str1);
//调用父类非私有化方法
super.method01();
}
public static void main(String[] args) {
Test test = new Test();
test.fun();
}
}
10. 重写
含义:重写也叫做复写,将父类中方法在子类中重新编写一遍
子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
class Animal{
public void move(){
System.out.println("动物可以移动");
}
}
class Dog extends Animal{
//重写父类Animal里的move方法
public void move(){
System.out.println("狗可以跑和走");
}
public void bark(){
System.out.println("狗可以吠叫");
}
}
public class TestDog{
public static void main(String args[]){
Animal a = new Animal(); // Animal 对象
Animal d = new Dog(); // Dog 对象
a.move();// 执行 Animal 类的方法
d.move();//执行 Dog 类的方法
//d.bark(); //d引用类型为Animal,却调用Dog独有的bark方法
}
}
//运行结果
动物可以移动
狗可以跑和走
在上面例子中,尽管 d 属于Animal类型,但是它运行的是 Dog 类的move方法。这是由于在编译阶段,只是检查参数的引用类型。在运行时,JVM指定对象的类型并且运行该对象的方法。
d.move();之所以能编译成功,是因为 Animal 类中存在 move 方法,然而运行时,运行的是特定对象的方法。
若执行 Dog 类的方法d.bark();程序将抛出一个编译错误,因为d的引用类型Animal没有bark方法。
方法的重写规则
-
父类的成员方法只能被它的子类重写。
-
参数列表与被重写方法的参数列表必须完全相同。
-
返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类
(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
-
访问权限不能比父类中被重写的方法的访问权限更低。
例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
-
声明为 final 的方法不能被重写。构造方法不能被重写。
区别点 | 重载方法 | 重写方法 |
---|---|---|
参数列表 | 必须修改 | 一定不能修改 |
返回类型 | 可以修改 | 一定不能修改 |
异常 | 可以修改 | 可以减少或删除,一定不能抛出新的或者更广的异常 |
访问 | 可以修改 | 一定不能做更严格的限制(可以降低限制) |
11. 访问修饰符
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
- private : 在同一类内可见。注意:不能修饰外部类和接口
- default (即默认,什么也不写): 在同一包内可见。
- protected : 对同一包内的类和所有子类可见。 注意:不能修饰外部类和接口。
- public : 对所有类可见。
访问修饰符 | 本类 | 本包 | 其他包子类 | 其他包 |
---|---|---|---|---|
private | OK | |||
默认的 | OK | OK | ||
protected | OK | OK | OK | |
public | Ok | OK | OK | Ok |
protected 关键字详解
- 父类的 protected 成员是包内可见的,并且对子类可见;
- 若子类与父类不在同一包中,那么在子类中,子类实例可以访问其从父类继承而来的protected方法,但父类实例不能访问protected方法。
package test01;
public class A {
protected String str = "test01包中A类的protected属性";
protected void method(){
System.out.println("test01包中A类的protected方法");
}
}
package test02;
import test01.A;
public class Test extends A {
public static void main(String[] args) {
//创建父类对象
A a = new A();
//创建子类对象
Test test = new Test();
//编译报错,父类实例不能访问protected方法
// System.out.println(a.str);
//子类实例可以访问父类的protected属性和方法
System.out.println(test.str);
test.method();
}
}
12. 非访问修饰符
为了实现一些其他的功能,Java 也提供了许多非访问修饰符。
- static 修饰符,用来修饰类方法和类变量。
- final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
- abstract 修饰符,用来创建抽象类和抽象方法。
- synchronized 和 volatile 修饰符,主要用于线程的编程。