一、继承
1.继承的概述
- 继承是多态的前提,如果没有继承就没有多态;
- 继承主要解决的问题:共性抽取;
- 父类\基类\超类→子类\派生类;
PS:
- 在父子类的继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式:
- 直接通过子类对象访问成员变量;
- 间接通过成员方法访问成员变量;
- 子类中有的成员就用子类的,没有再向上去父类找;
- 在内存空间层面上,方法区中,子类会生成一个指向父类的super_class;
- 子类对象中包含一个完整的父类结构;
2.重名问题
2.1 局部变量与本类成员变量
- 在含有局部变量的那个方法中,直接使用变量名则调用局部变量,使用this.变量名调用本类成员变量;
2.2 本类成员变量与父类成员变量
- super.变量名则使用父类成员变量;
3.继承中方法的覆盖重写
- 重写(Override):在继承关系当中,方法的名称一样,参数列表也一样,这一点和重载(Overload)不同,但子类中覆盖重写方法的返回值必须小于等于父类的返回值范围;
- 特点:子类对象优先用子类中覆盖重写的方法;
子类方法的权限必须大于等于父类方法的权限修饰符:public>protected>default(即留空不写)>private
- @Override:写在覆盖重写的方法前,可以起到检测是否是有效的覆盖重写;
4. super关键字与this关键字
4.1 super关键字
super:调用父类构造方法;
- 子类构造方法默认包含一个“super();”调用,所以一定是先调用的父类构造,再执行子类构造;
- 子类构造可以通过super关键字来调用父类重载构造;
- super的父类构造调用,必须是子类构造的第一个语句;
public class theFather {
public theFather(int a) {
System.out.println("父类无参构造");
}
}
public class theSon extends theFather {
public theSon() {
super(2);
System.out.println("子类无参构造");
}
}
总结: 子类必须调用父类的构造方法,不写则赠送一个super(),写了则用写的那个,且写的时候只能写一次还必须放在子类构造的第一句;
super关键字的三种用法总结:
- super.变量名:在子类成员方法中访问父类的成员变量;
- super.方法名:在子类的成员方法中访问父类的成员方法;
- super():在子类构造方法中访问父类构造方法;
4.2 this关键字
作用:用来访问本类内容;
- 在本类的成员方法中访问本类的成员变量;
- 在本类的成员方法中访问本类的另一个成员方法;
- 在本类的构造方法中访问本类的另一个构造方法;
- 和super()一样,this(参数)也必须是构造方法的第一个语句;
- super()与this()不能同时使用,不难理解吧?
5、Java继承的三个特点
- Java语言是单继承的,一个类的直接父类只能有唯一一个;
- Java语言可以多级继承,java.lang.Object是最高级的父类;
- 一个父类可以被多个子类继承;
二、抽象
概念(我的见解):无法具体写出执行步骤、属性等?只是知道大致行为,类别;
1.抽象方法与抽象类的定义格式
- 抽象方法:在修饰符与返回值类型之间加上abstract,并且去掉大括号,如:
public abstract void 方法名();
- 抽象类:含有抽象方法的类,在class前写上abstract,如:
public abstract class 类名{ public abstract void 方法名(); }
抽象类中也能定义普通方法;
2.抽象类与抽象方法的使用
- 不能直接new一个抽象对象;
- 必须用一个子类来继承抽象父类;
- 子类必须靠覆盖重写抽象父类当中的所有抽象方法;
- 抽象类的覆盖重写:子类去掉抽象方法的abstract关键字并补上大括号;
- 创建子类对象;
3.抽象类的注意事项
1.抽象类不能直接创建对象,只能通过其子类来创建;
2.抽象类中可以有构造方法,在子类创建对象时,用来初始化父类成员;
3.抽象类中不一定包含抽象方法,但抽象方法必须要写在抽象类中;
4.抽象类的子类必须重写所有抽象方法:
在写子类时 “alt+回车” 即可自动弹出父类中需要覆盖重写的抽象方法;
三、接口
- 接口就是一种公共的规范标准;
只要符合规范标准,就可以大家通用;
接口定义的格式:
public interface 接口名称{ 接口内容 }
PS:接口类定义时虽然把class换成了interface,但编译后的文件仍然是.class;
- 如果是Java7,那么接口中可包含的内容有:
- Java8:
- Java9:
- 私有方法
3.1 接口的使用步骤
- 接口不能直接使用,必须有一个“实现类”来“实现”该接口;
public class 实现类名称 implements 接口名称{
内容
}
- 接口的实现类必须覆盖重写(实现)接口中所有的抽象方法;
实现:去掉abstract关键字,加上方法体大括号;
若没有全部覆盖重写,则该实现类必须是一个抽象类;在写实现类时 “alt+回车” 即可自动弹出接口类中需要覆盖重写的抽象方法;
3.创建实现类的对象,进行使用;
3.2 接口的默认方法
- 定义格式:
public default 返回值类型 方法名称(参数列表){ 方法体 }
- 作用:在接口类中添加的默认方法会被实现类直接继承,而无需在实现类中覆盖重写, 你要覆盖重写也可以;
3.3 接口的静态方法
- 定义格式
public static 返回值类型 方法名称(参数类型){ 方法体 }
PS:不能通过实现类的对象来调用接口当中的静态方法,应该直接通过接口名称来调用;
3.4 接口的常量定义和使用
- 必须使用public static final(可省略)三个关键字进行修饰,从效果上看,这其实就是接口的常量;
public static final int 常量名 = 数值;//必须赋值
3.5 继承父类并继承多个接口
- 接口没有静态代码块或构造方法;
- 一个类的直接父类唯一,但一个类可以实现多个接口;
- 如果一个实现类的多个接口中有重名抽象方法,则只需要覆盖重写一次;
- 如果实现类没有重写所有的抽象方法,则实现类必须是一个抽象类;
- 如果实现类实现的多个接口中有重名的默认方法,则实现类必须将之覆盖重写;
- 一个类如果直接父类当中的方法和接口当中的默认方法产生冲突,则将优先使用父类的方法, 继承优先于实现接口;
3.6 接口之间的多继承
1.类与类之间是单继承的;
2.类与接口之间是多实现的;
3.接口与接口之间是多继承的;
PS:
- 多个父接口当中的抽象方法重名,没关系;
- 多个父接口当中的默认方法重名则需要在子接口中覆盖重写;
四、对象的多态性
- 多态性的前提:extends继承或implements实现;
- 多态是针对对象说的;
4.1 多态的格式与引用
代码当中体现多态性:父类引用指向子类对象
父类名称 对象名称 = new 子类名称(); 或 接口名称 对象名称 = new 实现类名称();
- 在使用时,优先调用new后面的东西(即子),没有再向上寻找(即左边的父类或接口);
4.2 多态中成员变量的使用特点
*访问成员变量的两种方法:
- 直接通过对象名称访问成员变量,看等号的左边是谁就优先调用谁,没有则向上寻找;
- 间接通过成员方法访问,则是看该方法属于谁,没有则向上寻找;
PS:编译看左,运行也看左;
4.3 多态中成员方法的使用特点
- new的是谁,就优先用谁,没有则向上寻找;
PS:编译看左(多态下,通过对象名调用父类中没有的子类方法会报错),运行看右;
4.4 对象的向上、向下转型
- 对象的向上转型:其实就是多态写法:
父类名称 对象名=new 子类名称();
含义:右侧创建一个子类对象,把它当作父类来看待与使用;
PS:向上转型一定是安全的,因为它是从一个狭隘的范围跳向一个更宽泛的范围;
- 对象的向下转型:就是我在4.3里写的“多态中通过对象名调用父类中没有的子类方法会报错”,所以需要有一个还原的动作;
定义格式:子类名称 对象名 = (子类名称)父类对象;//有点像强转???
注意那个对象名需要是一个新的名字;
- 如何知道一个父类引用的对象本来是什么子类?
对象名 instanceof 类名称
它在判断完成后将返回一个boolean;
五、final关键字与四种权限修饰符
5.1 final的几种适用方法
- final修饰一个类
格式:
public final class 类名称{
内容
}
含义:该方法不能有子类,其中所有方法都不能覆盖重写,但可以有父类;
- fianl修饰一个方法
格式:
修饰符 final 返回值类型 方法名称(参数列表){
方法体
}
含义:该方法不能覆盖重写;
- final修饰一个局部变量
格式:
final 数据类型 变量名 = 数据值;
或
final 数据类型 变量名;
变量名 = 数据值;
含义:一次赋值之后,该变量不能被更改;
对于引用类型,则表示变量名中存放的地址值不能改变;
- final修饰一个成员变量
- 由于成员变量具有默认值,所以使用了final之后必须赋值;
- 对于final的成员变量,要么使用直接赋值,要么使用构造方法赋值,二者选其一;
- 必须保证类当中所有重载的构造方法都会最终对final的成员变量进行赋值;
5.2 final在局部内部类中
- 如果局部内部类希望访问其所在方法的局部变量,那么这个局部变量必须是有效final的,即不能二次赋值;
PS:从Java8开始,只要局部变量事实不变,那么final关键字可以省略;
- 原因:
- new出来的对象在堆内存当中;
- 局部变量是跟着方法走的,在栈内存当中;
- 方法运行结束后立即出栈,局部变量立刻消失;
- 但是new出来的对象会在堆当中持续存在,直到垃圾回收消失;
5.3 权限修饰符
四种修饰符(从大到小) | public | protected | (default) | private |
---|---|---|---|---|
同一个类中 | yes | yes | yes | yes |
同一个包中 | yes | yes | yes | no |
不同包子类 | yes | yes | no | no |
不同包非子类 | yes | no | no | no |
六、内部类
- 定义在 一个事物内部的类;
6.1 成员内部类:
- 定义格式:
修饰符 class 外部类名称{ 修饰符 class 内部类名称{ } }
PS:内用外可,外用内不可;
- 使用格式:
- 间接方式:在外部类的方法中使用内部类,然后main函数调用外部类方法;
- 直接使用:外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
- 内部类的同名变量访问
在内部类中,this.变量名表示该内部类下该变量名的成员变量,外部类名.this.变量名才是外部类的该变量名变量;
6.2 局部内部类
- 定义在一个方法内部的类;
- 定义格式:
修饰符 class 外部类名称{ 修饰符 返回值类型 外部方法名称(){ class 局部内部类名称{ 内容 } } }
- 只有当前方法能使用它,出了这个方法外面就不能用了;
6.3 类的权限修饰符使用规则
- 外部类:public\default;
- 成员内部类:public>protected>(default)>private;
- 局部内部类:什么都不能写,直接class;
6.4 匿名内部类
- 如果接口的实现类或父类的子类只需使用唯一一次,那么这种情况下就可以省略掉该类的定义,而改为使用匿名内部类;
- 定义格式:
接口名称 对象名 = new 接口名称(){ 需要覆盖重写的方法 } ;//大括号内部是一个类,即匿名内部类;
- 对格式“new 接口名称(){…}”进行解析:
- new表示创建对象的动作;
- 接口名称就是匿名内部类需要实现哪个接口;
- {…}是匿名内部类的内容
- PS:
- 匿名内部类在创建对象的时候,只能使用唯一一次;
- 匿名的是内部类,而不是对象,若创建的是匿名对象,则也只能调用一个次方法;
3.匿名的东西都只能用一次;
4.匿名内部类和匿名对象不是同一回事!
6.5 类、接口作为成员变量
- String就是一个类,好理解了吧?
- 接口也差球不多;
- 接口作为方法的参数与返回值也是可以的;