1.1继承定义:
- 继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接
访问父类中的非私有的属性和行为。
1.2 继承的好处:
- 提高代码的复用性。
- 类与类之间产生了关系,是多态的前提。
1.3 继承的格式:
class 父类 {
...
}
class 子类 extends 父类 {
...
}
1.4 父类不可被继承的内容:
- 构造方法子类不会继承
- 因为构造方法名和类名一致,父类和字节类名肯定不一样,所以父类的构造方法复制到子类中肯定用不了了
- 父类的私有内容子类不能使用(私有只有本类能用)
- 父类中的私有成员变量,要提供get/set给子类用
public class Demo {
public static void main(String[] args) {
// 创建子类
Zi z = new Zi();
z.num1 = 10;
// z.num2 = 20; // 父类的私有成员变量子类不能使用
z.setNum2(20);
z.getNum2();
z.test01();
// z.test02(); // 父类的私有成员方法子类不能使用
}
}
class Fu {
public Fu() {
}
int num1;
private int num2;
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
public void test01() {
System.out.println("test01");
}
private void test02() {
System.out.println("test02");
}
}
class Zi extends Fu {
/*public Fu() {
}*/
}
1.5 继承后的特点-成员变量:
- 成员变量重名(0.01%实际开发中一般不重名)
- 自己有用自己的,自己没有用父类的(就近原则):局部变量->本类成员变量->父类成员变量
- super表示父类的内容
- 成员变量不重名(99.99%实际开发中一般不重名)
- 自己有用自己的,自己没有用父类的(就近原则)
public class Demo {
public static void main(String[] args) {
/* Zi1 z1 = new Zi1();
System.out.println(z1.num2); // 200
System.out.println(z1.num1); // 10*/
Zi2 z2 = new Zi2();
z2.test();
}
}
// ------------------成员变量重名(0.01%)----------------------
// 自己有用自己的,自己没有用父类的(就近原则) : 局部变量 -> 本类成员变量 -> 父类成员变量
// super表示父类的内容
class Fu2 {
int num3 = 30;
}
class Zi2 extends Fu2 {
int num3 = 400;
public void test() {
int num3 = 5000;
System.out.println(num3); // 5000
System.out.println(this.num3); // 400
System.out.println(super.num3); // 30
}
}
// ------------成员变量不重名(99.99%)----------
// 自己有用自己的,自己没有用父类的(就近原则)
class Fu1 {
int num1 = 10;
}
class Zi1 extends Fu1 {
int num2 = 200;
}
1.6 继承后的特点-成员方法:
- 当有了继承后,不管是成员变量还是成员方法,都是就近原则(自己有的用自己的,自己没有用父类的)
public class Demo{
public static void main(String[] args) {
// Zi1 z1 = new Zi1();
// z1.test01(); // Fu1 test01
// z1.test02(); // Zi1 test02
Zi2 z2 = new Zi2();
z2.test03(); // Zi2 test03
}
}
// ----------------成员方法重名(很少数)----------------------
// 自己有就用自己的,自己没有就用父类的(就近原则)
class Fu2 {
public void test03() {
System.out.println("Fu2 test03");
}
}
class Zi2 extends Fu2 {
public void test03() {
System.out.println("Zi2 test03");
}
}
// ----------------成员方法不重名(大多数)----------------------
// 自己有就用自己的,自己没有就用父类的(就近原则)
class Fu1 {
public void test01() {
System.out.println("Fu1 test01");
}
}
class Zi1 extends Fu1 {
public void test02() {
System.out.println("Zi1 test02");
}
}
2.1方法重写:
- 回顾方法重载(overload):同一个类中,方法名相同,参数列表不同
- 方法重写(override):子类中的方法和父类的方法重名
- 什么时候使用方法重写:子类和父类具有相同的功能,但是子类的功能比父类的功能更加强大,就使用方法的重写。
- 方法重写注意事项:
- 是子类和父类之间的事情
- 方法名要相同
- 参数列表要相同
- 返回值类型要相同
- 子类方法的权限要大于等于父类方法的权限
- 四个权限:public > protected > 默认的 >private
public class Demo{
public static void main(String[] args) {
NewPhone np = new NewPhone();
np.sendMessage();
np.call();
np.callDispaly();
}
}
/*
1. 老手机:
发短信
打电话
来电显示(显示来电号码)
2. 智能手机:
发短信
打电话
来电显示(显示来电号码,显示来电姓名,显示头像)
*/
class OldPhone {
public void sendMessage() {
System.out.println("发短信");
}
public void call() {
System.out.println("打电话");
}
// 来电显示(显示来电号码)
public void callDispaly() {
System.out.println("显示来电号码");
}
}
// 智能手机是由老手机发展过来的,发短信和打电话还是以前的功能,只不过来电显示功能更加强大了,所以我们用智能手机去继承老手机
class NewPhone extends OldPhone {
// 新手机的来电显示比老手机的来电显示要强大,我们重新写过来电显示的方法
@Override // 检测方法是不是重写方法
public void callDispaly() {
// 来电显示(显示来电号码,显示来电姓名,显示头像)
super.callDispaly(); // 调用父类的方法
System.out.println("显示来电姓名");
System.out.println("显示头像");
}
}
2.2 继承后的特点-构造方法:
- 回顾:一个类不写构造方法,默认赠送有一个无参构造
- 当有了继承关系后:
- 子类所有的构造方法都会先调用到父类的无参构造
- 为什么要走父类构造方法:
- 因为父类中可能有成员变量需要通过构造方法来赋值,所以先走父类的构造方法。
- 为什么走父类无参构造:
- java在95年就设计好了,它不知道我们今天会有什么样的构造方法,但是默认有一个无参构造,所以就走无参构造
- 子类的构造方法是如何去调用父类的无参构造:
- 在子类构造方法的第一行,默认有一个super();
- super():表示调用父类构造方法
- 继承后标准构造方法写法:
- 子类的无参调用父类的无参构造。
- 子类的有参构造调用父类的有参构造,自己的成员变量自己赋值。
public class Person {
private String name;
private int age;
public Person() {
System.out.println("父类 Person无参构造");
}
public Person(String name, int age) {
System.out.println("父类 Person有2个参数构造");
this.name = name;
this.age = age;
}
public void eat() {
System.out.println(name + "在吃饭");
}
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;
}
}
public class Demo {
public static void main(String[] args) {
/*
父类 Person无参构造
子类 无参构造
*/
// Student s1 = new Student();
/*
父类 Person无参构造
子类 有3个参数构造
*/
Student s2 = new Student("lily", 18, 100);
}
}
public class Student extends Person {
private double score;
// 1. 子类的无参调用父类的无参构造
public Student() {
super();
System.out.println("子类 无参构造");
}
// 2. 子类的有参构造调用父类的有参构造,自己的成员变量自己赋值
public Student(String name, int age, double score) {
super(name, age); // 子类有参调用父类有参
this.score = score; // 自己的成员变量自己赋值
System.out.println("子类 有3个参数构造");
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}
2.3 this和super总结:
- this代表本类内容,super代表父类内容:
this.num1 本类的成员变量
super.num1 父类的成员变量this.eat(); 本类的方法
super.eat(); 父类的方法this(); 调用本类构造方法
super(); 调用父类的构造方法this(); 只能放在构造方法第一行
super(); 只能放在构造方法第一行super()和this()都只能放在构造方法第一行,构造方法第一行到底放什么?
默认是super();
子类的构造方法能够直接或间接调用到父类的构造方法即可。
2.4 继承的特点:
- 继承的特点:
- java中类只能单继承,一个类只有一个父类
- 一个类可以有多个子类
- 支持多层继承
- 注意:
- 子类和父类是相对的概念
- 一个类没有继承父类,其实是继承Object类(超类)
//class Fu1 extends Object{}
class Fu1 {}
class Fu2 {}
class Zi1 extends Fu1 {}
// 1. Java中类只能单继承,一个类只有一个父类
// class Zi2 extends Fu1, Fu2 {}
// 2. 一个类可以有多个子类
class Zi2 extends Fu1 {}
class Zi3 extends Fu1 {}
// 3. 支持多层继承
class Sun extends Zi1 {}
public class Demo09 {
public static void main(String[] args) {
Fu1 f = new Fu1();
// f.
}
}
3.1 抽象方法和抽象类的定义:
- 普通方法格式:
修饰符 返回值类型 方法名(参数列表){ }
- abstract关键字:表示抽象
- 抽象方法格式:修饰符 abstract 返回值类型 方法名(参数列表);
- 和普通方法对比:
- 在返回值类型前面添加abstract
- 把方法体的{}换成分号;
- 抽象方法需要放在抽象类中
- 抽象类的格式:
abstract class 类名{ }
- 抽象类就是在以前的标准类基础上增加了抽象方法。
- 抽象方法没有方法体,是无法执行的。
- 抽象类的使用步骤:
- 定义一个类继承抽象类。
- 重写抽象方法。
- 创建子类。
- 父类中抽象的work方法是有必要存在的
- 如果父类不写抽象方法,子类也可以不写work方法,子类功能就缺失了
- 如果父类添加了抽象方法 ,强制子类要去重写这个方法,保存功能完整
public abstract class Employee {
private String id;
private String name;
private double salary;
public Employee() {
}
public Employee(String id, String name, double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
// 抽象方法需要放在抽象类中
// 抽象方法(工作)
public abstract void work();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
//定义一个类继承抽象类
public class Cook extends Employee {
//继承后标准构造方法写法:
//1.子类的无参调用父类的无参构造。
public Cook() {
}
//2.子类的有参构造调用父类的有参构造,自己的成员变量自己赋值。
public Cook(String id, String name, double salary) {
super(id, name, salary);
}
// 2. 重写抽象方法
public void work() {
System.out.println(getName() + "厨师炒菜多加点盐...");
}
}
public class Waiter extends Employee {
@Override
public void work() {
System.out.println("服务客人...");
}
}
// 1. 定义一个类继承抽象类
public class Manager extends Employee {
public Manager() {
super();
}
public Manager(String id, String name, double salary) {
super(id, name, salary);
}
// 2. 重写抽象方法
public void work() {
System.out.println(getName() + "经理管理其他人");
}
}
public class Demo {
public static void main(String[] args) {
// 因为抽象方法没有代码,即使创建出了对象也无法调用抽象方法,所以不能创建对象
/*Employee e = new Employee();
e.work();*/
// 3. 创建子类
Manager m = new Manager("jl001", "Tony", 10000);
m.work();
Cook c = new Cook("cs002", "库克", 1);
c.work();
Waiter w = new Waiter();
// w.work();
}
}
4.1抽象类的特点总结:
import java.awt.*;
/*
了解
1. 抽象类不能创建对象
2. 抽象类中有构造方法,给抽象类中的成员变量赋值
3. 抽象方法需要放在抽象类中,但是抽象类中可以没有抽象方法
4. 子类需要重写抽象类中的所有方法, 如果只重写一部分还是抽象类
*/
// 抽象方法需要放在抽象类中
abstract class Fu {
public abstract void work();
}
// 但是抽象类中可以没有抽象方法.让我们用子类
abstract class Zi {
}
// 4. 子类需要重写抽象类中的所有方法, 如果只重写一部分还是抽象类
abstract class Fu2 {
public abstract void test01();
public abstract void test02();
}
// 子类需要重写抽象类中的所有方法
class Zi2 extends Fu2 {
public void test01() {
}
public void test02() {
}
}
// 如果只重写一部分还是抽象类
abstract class Zi3 extends Fu2 {
public void test01() {
System.out.println("重写");
}
// 如果只重写部分抽象方法.另外的抽象方法还在, 需要放在抽象类中
}
public class Demo11 {
public static void main(String[] args) {
// Component
}
}