1 继承
1.1 概述
在现实生活中,说到继承,多会想到子女继承父辈的财产、事业等。在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关联体系。
在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类或基类,子类会自动拥有父类所有可继承的属性和方法。
1.2 特点
- 使用extends关键字来表示继承关系
- 相当于子类把父类的功能复制了一份
- Java只支持单继承
- 继承可以传递(爷爷/儿子/孙子这样的关系)
- 父类的私有成员也会被继承,但由于私有限制访问,所以子类不能使用父类的私有资源
- 继承多用于功能的修改,子类可以在拥有父类功能的同时,进行功能拓展
- 像是is a的关系
1.2.1 继承案例练习
public class ExtendsDemo {
public static void main(String[] args) {
Animal a = new Animal();
Cat c = new Cat();
MiaoMiao m = new MiaoMiao();
// 利用对象调用方法
a.eat();
c.eat();
m.eat();
/**
* 3、继承还具有传递性,爷爷的功能会传给爸爸,爸爸的功能会传给儿子
*/
}
}
/**
* 1、我们通过extends关键字建立子类与父类的继承关系
* 格式:子类 extends 父类
* 2、java只支持单继承,一个字类只能有一个父类,但是一个父类可以有多个子类
*/
// 创建爷爷类
/**
* 6、继承是is a的关系,比如:小猫是小动物,MiaoMiao是一只小猫
* 继承要求子类必须是父类的一种下属类型,依赖性非常强,强耦合
*/
class Animal {
public void eat() {
System.out.println("小动物Animal吃啥都行~");
}
}
// 创建爸爸类,并与Animal类建立继承关系
class Cat extends Animal {
int a = 10;
private int b = 100;
}
// 创建孙子类,并与Cat类建立继承关系
class MiaoMiao extends Cat {
/**
* 4、子类可以拥有自己独有的方法,实现了功能的拓展,青出于蓝而胜于蓝
*/
public void studyjava() {
System.out.println("这是一只会编程的猫");
/** 5、子类继承父类以后,可以使用父类所有非私有资源
* 注意:这个私有资源是由于子类不可见而不能使用的,不是因为没有继承
* 因为子类在继承了父类以后,相当于把父类的功能完全赋值了一份
*/
System.out.println(a);
//System.out.println(b);
}
}
2 super关键字
我们可以把super看作是父类的对象:Father super = new Father();
- 当父类的成员变量与子类的变量同名时,使用super指定父类的成员变量
- 使用super在子类构造方法的第一行调用父类构造方法的功能
super();–调用的是父类的无参构造
super(参数);–调用的是父类对应参数的构造方法
注意:在构造方法里,出现的调用位置必须是第一行
2.2 继承的用法
2.2.1 练习:super之继承中成员变量使用
/**
* 本类用于测试继承中成员变量的使用
*/
public class TestExtends1 {
public static void main(String[] args) {
Father f = new Father();
Son s = new Son();
s.eat();
}
}
// 创建父类
class Father {
int count = 1;
int sum = 2;
}
// 创建子类
class Son extends Father {
int sum = 100;
public void eat() {
int sum = 10;
System.out.println(sum);// 打印局部变量sum
System.out.println(this.sum); // 打印成变量sum
/**
* 在子类中使用父类的sum资源,需要使用super进行指定
* super表示父类的对象,可以理解成Father super = new Father();
*/
System.out.println(count);
System.out.println(super.sum);// 使用父类重名的成员变量
}
}
2.2.2 super之继承中构造方法的使用
/**
* 1、子类创建对象时,默认会先去调用父类的构造方法
* 2、原因是由于子类构造函数第一行默认存在super()--表示调用父类的无参构造
* 3、当父类没有无参构造时,可以通过super(参数)调用父类的其他含参构造
* 4、构造方法不可以被继承,因为语法的原因,构造方法要求与类名同名,所以不符合要求
*/
public class TestExtends2 {
public static void main(String[] args) {
Father2 f2 = new Father2("红烧肉");
Son2 s2 = new Son2();
}
}
class Father2 {
// public Father2() {
// System.out.println("我是Father2无参构造");
// }
public Father2(String s) {
System.out.println("爸爸爱吃" + s);
}
}
class Son2 extends Father2 {
public Son2() {
super("狮子头");
System.out.println("我是Son2的无参构造");
}
}
3 方法重写Override
- 继承以后,子类就拥有了父类的功能
- 在子类中,可以添加子类特有的功能,也可以修改父类的原有功能
- 子类中方法的签名与父类完全一样时,会发生覆盖/复写的现象
- 注意: 父类的私有方法不能被重写
- 重写的要求:两同两小一大
两同:方法名 参数列表 要完全一致
两小:
子类返回值类型小于等于父类的返回值类型(注意此处说的是继承关系,不是值大小)
子类抛出异常小于等于父类方法抛出异常
一大:子类方法的修饰符权限要大于等于父类被重写方法的修饰符权限
3.1 练习:继承中成员方法的使用
/**
* 方法的重写:继承后子类对父类的功能不满意,就可以重写父类的功能
* 重写的语法规则:两同,两小,一大
* 一大:子类方法的修饰符范围 >= 父类方法的修饰符范围--这里指的是访问控制符
* 两同:方法名相同,参数列表相同
* 两小:子类方法的返回值类型 <= 父类方法的返回值类型
* 子类方法抛出的异常类型 <= 父类方法抛出的异常类型
* 注意:1、如果父类方法的返回值类型是void,子类保持一致即可
* 2、子类不可以重写父类的私有方法,还是因为不可见
*/
public class TestExtends3 {
public static void main(String[] args) {
Father3 f3 = new Father3();
Son3 s3 = new Son3();
f3.eat();
/**
* 1、继承后,子类可以使用父类的非私有资源
*/
s3.eat();
/**
* 3、如果子类对父类的功能进行重写,调用的是重写后的功能
*/
}
}
class Father3 {
public void eat() {
System.out.println("爸爸爱吃肉");
}
public void play() {
System.out.println("吕布爱貂蝉");
}
}
class Son3 extends Father3 {
public void studyJava() {
System.out.println("拓展学习Java的功能");
}
/** 4、@Override:这是一个注解,可以理解成一个标签,标记这个方法是一个重写的方法 */
@Override
public void eat() {
System.out.println("儿子爱吃蔬菜");
}
}
4 static关键字
4.1 概念
是java中的一个关键字
用于修饰成员(成员变量和成员方法)
4.2 特点
- static可以修饰成员变量和方法
- 被static修饰的资源称为静态资源
- 静态资源随着类的加载而加载,最先加载,优先于对象进行加载
- 静态资源可以通过类名直接调用,也被称作类资源
- 静态被全局所有对象共享,值只有一份
- 静态资源只能调用静态资源
- 静态区域内不允许使用this与super关键字
4.2.1 static关键字入门案例练习
public class TestStatic1 {
public static void main(String[] args) {
/**
* 3、静态资源可以通过类名直接调用
* 原因,静态资源优先于对象进行加载,它是随着类的加载而加载的
* 比对象先加载进入内存,所以没对象时也可以通过类名直接调用
*/
System.out.println(Student.name);
Student.study();
Student s = new Student();
System.out.println(s.sno);
System.out.println(s.name);
s.study();
s.name = "鹌鹑蛋罐头";
System.out.println(s.name);
System.out.println(Student.name);
/**
* 4、静态资源被全局所有对象共享
*/
Student s2 = new Student();
System.out.println(s2.name);
System.out.println(Student.name);
s2.name = "牛肉罐头";
System.out.println(s.name);
System.out.println(s2.name);
System.out.println(Student.name);
}
}
class Student {
/**
* 1、可以通过static关键字来修饰成员变量与方法,修饰方法一般写在权限修饰符之后
* 2、被static修饰的资源称作静态资源
*/
int sno;
static String name;
public static void study() {
System.out.println("别闹?学Java呢~");
}
public void speak() {
System.out.println("会要大声说出来");
}
}
4.2.2 static静态调用关系
/**
* 总结:
* 1、普通资源既可以调用普通资源,也可以调用静态资源
* 2、静态资源只能调用静态资源
*/
public class TeatStatic2 {
}
class Teacher {
String name;
public void teach() {
System.out.println("正在授课ing....");
/**
* 1、普通资源能否调用静态资源?----可以
*/
System.out.println(age);
ready();
}
static int age;
public static void ready() {
System.out.println("正在备课ing...");
/**
* 2、静态资源调用普通资源
*/
//System.out.println(name);
//teach();
}
public static void eat() {
System.out.println("正在吃饭中ing...");
/**
* 3、静态资源能否调用静态资源
*/
System.out.println(age);
ready();
}
}
5 静态代码块、构造代码块、局部代码块
5.1 静态代码块格式
静态资源随着类的加载而加载,并且只被加载一次,一般用于项目的初始化
特点: 被static修饰,位置在类里方法外
5.2 三种代码块的比较
- 静态代码块:在类加载时就加载,并且只被加载一次,一般用于项目的初始化
- 构造代码块:在创建对象时会自动调用,每次创建对象都会被调用,提取构造共性
- 局部代码块:方法里的代码块,限制局部变量的范围
5.2.3 静、构、局代码块练习
/**
* 总结:
* 执行顺序:
* 静态代码块——>构造代码块——>构造方法【对象创建成功】——>局部代码块
*/
public class TestStaticBlock {
// 6、创建对象
public static void main(String[] args) {
Person p = new Person();
// 7、触发局部代码块
p.play();
}
}
// 1、创建Person类
class Person {
// 8、创建静态代码块
/**
* 位置:类里方法外
* 执行时机:静态代码块也属于静态资源,随着类的加载而加载,优先于对象加载,而且静态资源只会加载一次
* 作用:用于加载哪些第一时间就加载,并且只加载一次的资源
*/
static {
System.out.println("我是静态代码块");
}
// 2、创建构造代码块
/**
* 位置:类里方法外
* 执行时机:每次创建对象时被触发,并且优先于构造方法执行
* 作用:用于提取所有构造方法的共性功能
*/
{
System.out.println("我是构造代码块");
}
// 5、创建构造方法
public Person() {
System.out.println("我是无参构造");
}
// 3、创建普通方法
public void play() {
System.out.println("我是一个普通方法");
// 4、创建局部代码块
/**
* 位置:方法里
* 执行时机:执行本局部代码块在的方法是才会执行
* 作用:用于限制变量的作用范围
*/
{
System.out.println("我是局部代码块");
}
}
}
总结:
执行顺序:静态代码块——>构造代码块——>构造方法【对象创建成功】——>局部代码块
6 final关键字
6.1 概述
- 是java提供的一个关键字
- final是最终的意思
- final可以修饰类,方法,字段(属性)
初衷:java出现继承后,子类可以更改父类的功能,当父类功能不许子类改变时,可以利用final关键字修饰父类。
6.2 特点
- 被final修饰的类,不能被继承
- 被final修饰的方法,不能被重写
- 被final修饰的字段是个常量,值不能被修改
- 常量的定义形式:final 数据类型 常量名 = 值
6.2.1 final入门案例
public class TestFinal {
public static void main(String[] args) {
Son s = new Son();
//s.name = "干饭人"; // 会报错,因为常量的值不能被修改
}
}
/**
* 1、final表示最终,可以用来修饰类
* 但是被final修饰类是最终类,无法被继承
* 也就是没有子类,他自己就是叶子节点
*/
//final class Father {
class Father {
// 定义父类的普通方法
/**
* 2、final可以用来修饰方法,被final修饰的方法是这个方法的最终实现,不可以被重写
*/
// final public void work() {
// System.out.println("在车间上班");
// }
public void work() {
System.out.println("在车间上班");
}
}
class Son extends Father {
/**
* final可以用来修饰“变量”,注意其实不是“变量”,而是常量
* 常量的值是不可以被更改的
* 定义常量时必须给常量同时赋值,不能先定义在赋值,不符合语法
*/
final String name = "打工人";
final int a = 0;
@Override
public void work() {
System.out.println("在格子间上班");
}
}
7 拓展
7.1 his与super的区别
this代表的是本类对象的引用,我们可以把this看作是Cat this = new Cat();
super代表的是父类对象的引用,我们可以把super看作是Father super = new Father();
当本类的成员变量与局部变量同名时,需要使用this.变量名指定本类的成员变量
当本类的成员变量与父类的成员变量同名时,需要使用super.变量名指定父类的成员变量
this可以实现调用本类构造方法的功能,不能互相调用,需要写在构造方法首行
this();表示调用本类的无参构造 this(参数);表示调用本类的对应参数的构造
super也可以实现调用父类构造方法的功能
super();表示调用父类的无参构造 super(参数);表示调用父类的对应参数的构造
注意:super的使用前提是继承,没有父子类关系,就没有super
注意:this调用构造方法或者super调用构造方法,都必须出现在构造方法的第一行
注意:如果父类没有无参构造,需要手动在子类构造方法的第一行调用其他的含参构造
拓展:如果子类重写了父类的方法以后,可以使用super.方法名(参数列表)来调用
7.2 重载Overload 与重写Override的区别
重载:在一个类中的现象:同一个类中,存在方法名相同,参数列表不同的方法
重写:是指建立了继承关系以后,子类对父类的方法不满意,可以重写,遵循两同两小一大原则
重载的意义:是为了外界调用方法时方便,不管传入什么样的参数,都可以匹配到对应的同名方法
重写的意义:在不修改源码的情况下,进行功能的修改与拓展(OCP原则:面向修改关闭,面向拓展开放)