9.继承
继承
继承概述
面向对象三大特征之一, 可以使得子类具有父类的属性和方法, 还可以在子类中重新定义, 追加属性和方法.
继承格式:
- public class 子类名 extends 父类名{}
范例
-
public class child extends parent{}
-
child: 子类,也称为派生类
-
parent: 父类,也称为基类, 超类
例子
demo
package classInherit;
public class Demo {
public static void main(String[] args) {
// 创建对象
parent p = new parent();
p.show();
child c = new child();
c.method();
c.show(); // 子类调用父类的show方法
}
}
child
package classInherit;
public class child extends parent { // 继承父类
public void method() {
System.out.println("子类method方法");
}
}
parent
package classInherit;
public class parent {
public void show() {
System.out.println("父类show方法");
}
}
继承的好处和弊端
好处
- 提高了代码的复用性(多个类相同的成员可以放到同一个类中)
- 提高了代码的维护性(如果方法的代码需要修改,修改一处即可)
弊端
- 类的耦合性增强, 当父类发生变化时子类实现也不得不跟随变化,削弱了子类的独立性
使用子类的场景
- 继承体现的关系: is
注意:
- 如果子类想要访问父类中的属性, 那么父类中的属性必须定义为public.
- 子类和父类中有相同的属性或方法,会优先使用子类的属性或方法.
继承中变量访问特点
在子类中访问一个变量
- 子类局部范围查找
- 子类成员范围找
- 父类成员范围找
如果都没有会报错
super关键字
super关键字和this关键字用法相似
- this: 代表本类对象的引用
- super: 代表父类存储空间的表示(可以理解为父类对象的引用)
关键字 | 访问成员变量 | 访问构造方法 | 访问成员方法 |
---|---|---|---|
this | this.成员变量: 访问本类成员变量 | this(...): 访问本类的构造方法 | this.成员方法(...): 访问本类成员方法 |
super | super.成员变量: 访问父类成员变量 | super(...): 访问父类构造方法 | super.成员方法(...): 访问父类成员方法 |
例子
package classInherit;
public class child extends parent { // 继承父类
// 身高
public int height = 175;
public int age = 30;
public void show() {
int age = 40;
System.out.println("子类method方法");
System.out.println(this.height);
// 访问age, 先局部,后子类,最后父类
System.out.println(age);
System.out.println("子类成员变量: " + this.age);
System.out.println("父类成员变量: " + super.age);
}
}
构造方法访问特点
子类中所有的构造方法默认都会访问父类中无参的构造方法
- 子类会继承父类的数据,可能还会使用父类的数据, 所以, 子类初始化之前, 一定要先完成父类数据的初始化
- 每一个子类构造方法的第一条语句默认都是: super(),
如果父类中没有无参改造方法, 只有带参构造方法, 子类构造方法直接会报错
- 可以在子类中通过super手动调用父类的带参构造方法来避免.
- 在父类中提供一个无参构造方法(推荐)
Parent
package classInherit.initialMethod;
public class Parent {
/*
public Parent() {
System.out.println("Parent中无参构造方法");
}
*/
public Parent(int age) {
System.out.println("Parent中带参构造方法");
}
}
child
package classInherit.initialMethod;
public class Child extends Parent { // 继承父类
public Child() {
super(20);
System.out.println("Child中无参构造方法");
}
public Child(int age) {
super(20);
System.out.println("Child中带参构造方法");
}
}
Demo
package classInherit.initialMethod;
public class Demo {
public static void main(String[] args) {
// 创建对象
Child c = new Child();
System.out.println("-----------手动分割----------");
Child c2 = new Child(20);
}
}
成员方法访问特点
通过子类对象访问一个方法
- 子类成员范围查找
- 父类成员范围查找
- 如果都没有会报错,(不考虑父亲的父亲)
parent
package classInherit.memberMethod;
public class Parent {
public void show() {
System.out.println("Parent中show方法被调用");
}
}
child
package classInherit.memberMethod;
public class Child extends Parent { // 继承父类
public void method() {
System.out.println("Child中method方法被调用");
}
public void show() {
super.show();
System.out.println("Child中show方法被调用");
}
}
demo
package classInherit.memberMethod;
public class Demo {
public static void main(String[] args) {
// 创建对象
Child c = new Child();
c.method();
c.show();
// c.test(); // 报错
}
}
方法重写
子类中出现了和父类中一模一样的方法申明, 内容但是方法内容不一致
- 当子类需要父类的功能, 而功能主体子类有自己特有内容时, 可以重写父类中的方法, 这样, 既沿袭了父类的功能, 又定义了子类特有的内容
@Override
- 是一个注解
- 可以帮助我们检查重写方法声明的正确性
Phone
package classInherit.methodRewrite;
public class Phone {
public void call(String name) {
System.out.println("给" + name + "打电话");
}
}
NewPhone
package classInherit.methodRewrite;
/*
新手机
*/
public class NewPhone extends Phone {
/*
public void call(String name) {
System.out.println("开启视频功能!");
// System.out.println("给" + name + "打电话");
super.call(name);
}
*/
@Override
public void call(String name) {
System.out.println("开启视频功能!");
// System.out.println("给" + name + "打电话");
super.call(name);
}
}
Demo
package classInherit.methodRewrite;
public class Demo {
public static void main(String[] args) {
// 创建对象,调用方法
Phone p = new Phone();
p.call("ryxiong");
System.out.println("-------");
NewPhone p2 = new NewPhone();
p2.call("ryxiong");
}
}
注意事项:
-
父类的私有方法, 子类无法访问, 所以也无法重写
-
子类方法访问权限不能更低(public > 默认 > 私有)
继承的注意事项
java中只支持单继承, 不支持多继承
java类中支持多层继承
GrandFather
package classInherit.inheritNotes;
public class GrandFather {
public void drink() {
System.out.println("爷爷爱喝酒");
}
}
Father
package classInherit.inheritNotes;
public class Father extends GrandFather {
public void sing() {
System.out.println("爸爸爱唱歌");
}
}
Mother
package classInherit.inheritNotes;
public class Mother {
public void dance() {
System.out.println("妈妈爱跳舞");
}
}
Son
package classInherit.inheritNotes;
public class Son extends Father {
}
案例
Person
package classInherit.inheritPractice;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Teacher
package classInherit.inheritPractice;
public class Teacher extends Person {
public Teacher() {
}
public Teacher(String name, int age) {
super(name, age);
}
public void teach() {
System.out.println("用爱成就每一位学员");
}
}
Demo
package classInherit.inheritPractice;
/*
测试类
*/
public class Demo {
public static void main(String[] args) {
// 创建老师类
Teacher t1 = new Teacher();
t1.setName("林青霞");
t1.setAge(30);
System.out.println(t1.getName() + "," + t1.getAge());
t1.teach();
// 带参构造方法
Teacher t2 = new Teacher("风清扬", 33);
System.out.println(t2.getName() + "," + t2.getAge());
t2.teach();
}
}
包
本质上就是文件夹
作用: 对类进行分类管理
包的定义格式
- 格式: package 包名; 多级包用.分开
- 范例: package com.itheima;
带包的java类编译和执行
- 手动建包
- 按照以前格式编译java文件: javac HelloWorld.java
- 手动创建包, 创建文件夹com/itheima/
- 将class文件放到文件夹com/itheima/下
- 带包执行 java com.itheima.HelloWorld
- 自动建包
- Javac -d . HelloWrold.java
- java com.itheima.HelloWorld
修饰符
修饰符权限
修饰符 | 同一类中 | 同一个包中子类无关类 | 不同包的子类 | 不同包的无关系 |
---|---|---|---|---|
private | ✔ | |||
默认 | ✔ | ✔ | ||
protected | ✔ | ✔ | ✔ | |
public | ✔ | ✔ | ✔ | ✔ |
pkgs.Parent
package modifier.pkgs;
public class Parent {
private void show1() {
System.out.println("private");
}
void show2() {
System.out.println("default");
}
protected void show3() {
System.out.println("protected");
}
public void show4() {
System.out.println("public");
}
public static void main(String[] args) {
// 创建父类对象,测试哪些方法可以使用
Parent p = new Parent();
p.show1();
p.show2();
p.show3();
p.show4();
}
}
pkgs.Child
package modifier.pkgs;
public class Child extends Parent {
public static void main(String[] args) {
// 创建Child对象,测试哪些方法可以使用
Child c = new Child();
c.show2();
c.show3();
c.show4();
}
}
pkgs.Demo
package modifier.pkgs;
public class Demo {
public static void main(String[] args) {
// 创建Parent类对象, 测试看看哪些可以使用
Parent p = new Parent();
p.show2();
p.show3();
p.show4();
}
}
test.Child
package modifier.test;
import modifier.pkgs.Parent;
public class Child extends Parent {
public static void main(String[] args) {
// 创建Child对象,测试看看哪些方法可以使用
Child c = new Child();
c.show3();
c.show4();
}
}
test.Demo
package modifier.test;
public class Demo {
public static void main(String[] args) {
// 创建Child对象,测试看看哪些方法可以使用
Child c = new Child();
c.show4();
}
}
final修饰符
表示最终, 可以修饰成员方法, 成员变量, 类
final特点:
- 修饰方法: 最终方法, 不能被重写
- 修饰变量: 变量为常量, 不能再次被赋值
- 修饰类: 该类为最终类, 不能被继承
parent
package modifier.finalDemo;
// 被final修饰的类,不能被继承
/*
public final class Parent {
public final void method() {
System.out.println("Parent method");
}
}
*/
public class Parent {
public final void method() {
System.out.println("Parent method");
}
}
child
package modifier.finalDemo;
public class Child extends Parent {
public final int age = 20; // 被final修饰的值不能被修改
public void show() {
// age = 100;
System.out.println(age);
}
/*
@Override // 被final修饰的方法不能重写
public void method() {
System.out.println("Child Method");
}
*/
}
Demo
package modifier.finalDemo;
public class Demo {
public static void main(String[] args) {
Child c = new Child();
c.method();
c.show();
}
}
final修饰局部变量
-
修饰基本类型: final修饰指的是基本类型的数据值不能发生改变
-
修饰引用类型: final修饰值得是引用类型地址值不能发生改变, 但是地址里面的内容可以发生改变.
Student
package modifier.finalDemo;
public class Student {
public int age = 20;
}
FinalDemo
package modifier.finalDemo;
public class FinalDemo {
public static void main(String[] args) {
// final修饰基本类型变量
final int age = 20;
// age = 100;
System.out.println(age);
// final修饰引用类型变量
final Student s = new Student();
s.age = 100; // s是指一个地址, 内容可以变, 但是地址不能变
System.out.println(s.age);
// s = new Student(); // final修饰后, 地址值不能改变
}
}
Static修饰符
static 关键字是静态的意思, 可以修饰成员方法, 成员变量
static 修饰的特点
-
被类的所有对象共享: 这也是我们判断是否使用静态关键字的条件
-
可以通过类名调用, 也可以使用对象名调用, 推荐使用类名
Student
package modifier.staticDemo;
public class Student {
public String name;
public int age;
// public String university;
public static String university; // 所有对象能够共享的属性, 用static修饰
public void show() {
System.out.println(name + "," + age + "," + university);
}
}
StaticDemo
package modifier.staticDemo;
public class StaticDemo {
public static void main(String[] args) {
// static属性直接通过类来赋值
Student.university = "传智大学";
Student s1 = new Student();
s1.name = "林青霞";
s1.age = 30;
// s1.university = "传智大学";
s1.show();
Student s2 = new Student();
s2.name = "风清扬";
s2.age = 33;
s2.show();
}
}
static访问特点
非静态成员方法
- 能访问静态的成员变量
- 能访问非静态的成员变量
- 能访问静态的成员方法
- 能访问非静态的成员方法
静态成员方法
- 能访问静态的成员变量
- 能访问讲台成员方法
静态成员只能访问静态成员
Student1
package modifier.staticDemo;
public class Student1 {
// 非静态成员变量
private String name = "林青霞";
// 静态成员变量
private static String university = "传智大学";
// 非静态成员变量
public void show1() {
}
// 非静态成员方法
public void show2() {
System.out.println(name);
System.out.println(university);
show1();
show3();
}
// 静态成员方法
public static void show3() {
}
// 静态成员方法
public static void show4() {
// System.out.println(name); // 无法访问
System.out.println(university);
// show1(); // 无法访问
show3();
}
}