本文章将主要介绍继承,抽象类,接口和泛型
然而纸上学来终觉浅,最好还是能自己敲敲代码实现一下。
继承
用于解决代码复用
继承示意图:
class Dog extneds Animal{
}
①子类继承了父类所有属性和方法,但是私有属性和方法不能在子类中直接访问——public可以,protected可以,private不行。
要通过公共的方法去访问——写一个方法”get”
②子类必须调用父类的构造器,完成父类的初始化(默认调用父类的构造器,写不写都会调用)
③当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用
父类
的
无参构造器
如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过
//如下,super后输入参数
super("tom",30);
④如果希望指定地去调用父类的某个构造器,则显示地去调用一下(什么都不写默认调用无参构造器)
⑤super只能放在构造器中使用,而且要放在第一行
⑥因为this也只能放构造器第一行,因此super,this不能共存。(this是用自己子类里的的构造器)
⑦java所有类都是Object类的子类,Object是所有类的基类
⑧父类构造器的调用
不限于直接父类
,将一直向上追溯直至Object类(顶级父类)。
⑨子类最多只能直接继承一个父类
⑩不能滥用继承,父类子类必须满足 is – a 逻辑关系
继承的本质分析
(1)首先看子类是否有该属性
(2)如果子类有这个属性,若可以访问,则返回;
若不能访问,则报错
(3)如果没有这个属性,就看父类有没有这个属性(若有且可以访问,则返回;
若有但是不能访问,则报错
)
(4)如果父类没有,则按照(3)的规则,继续找上级父类,直到Object
下图为继承的内存布局:
抽象类
当父类的某些方法,需要声明,但又不确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类
子类可以重写父类方法,如果没有抽象类,也行(子类再去重写),但是浪费空间,且没必要
public abstract void eat();
且当一个类中存在抽象方法时,需要将该类声明为abstract类
①抽象类不能被实例化
②抽象类不一定要有抽象方法
③一旦有抽象方法,必须声明为抽象类
④abstract只能修饰类和方法,不能修饰其他部分
⑤抽象类还是类
⑥抽象方法不能有主体
⑦如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类
⑧抽象方法不能用private , final 和 static来修饰,因为这些和重写相冲突
接口
接口基本介绍
下示为接口,在接口中,抽象方法可以省略abstract关键字
public interface UsbInterface{
//规定接口相关方法,即规范
public void start();
public void stop();
//jdk8及以后,可以有方法体:
//1.默认实现方法
default public void ok(){
}
// 2.静态方法
public static void ko(){
}
}
想要用这个接口,就去实现它,这是手机
public class Phone implements UsbInterface{//实现接口
public void start(){
System.out.println("手机开始工作...");
}
public void stop(){
System.out.println("手机停止工作...");
}
}
这是相机
public class Camera implements UsbInterface{//实现接口
public void start(){
System.out.println("相机开始工作...");
}
public void stop(){
System.out.println("相机停止工作...");
}
}
电脑类用接口接手机或者相机即可
public class Computer{
//编写一个方法,计算机工作
public void work(UsbInterface usbInterface){
usbInterface.start();
usbInterface.stop();
}
}
主函数实现时
public class Interface01{
public static void main(String[] args){
Camera camera = new Camera();
Phone phone = new Phone();
Computer computer = new Computer();
computer.work(phone);
computer.work(camera);
}
}
接口细节
①接口不能实例化
②接口中所有方法都是public方法,接口中的抽象方法可以不用abstract修饰
③一个普通的类实现接口,就必须把该接口的所有方法都实现
④抽象类实现接口,可以不用实现接口的方法
⑤一个类可以同时实现多个接口(逗号 ’ , ’ 连接即可)
⑥接口中的属性,必须是final的,而且是public static final
//如
int a =1;
//实际上为
public static final int a =1;
⑦接口中属性的访问形式是:接口名.属性名
⑧一个接口不能继承其他的类,但是可以继承多个别的接口
⑨接口的修饰符只能是public和默认,这点和类修饰符是一样的
接口vs继承
当子类继承了父类,就自动拥有了父类的功能
如果子类需要拓展功能,可以通过实现接口的方式进行拓展
可以认为,实现接口 是对java 单继承 机制的补充
➢接口和继承解决的问题不同
继承的价值主要在于:解决代码的
复用性和可维护性
。
接口的价值主要在于:设计,设计好各种规范(方法),让其它类去实现这些方法。
➢接口比继承更加灵活
接口比继承更加灵活,继承是满足is – a的关系,
而接口只需满足like – a的关系。
➢ 接口在一定程度上实现代码解耦 [即:接口规范性 + 动态绑定]
接口的多态特性
①接口类型的变量,可以指向实现了此接口类的对象实例
public class InterfacePloyParameter{
public static void main (String[] args){
//if01是接口类型的变量 可以指向实现了IF接口的对象实例
IF if01 =new Monster();
if01 = new Car();
}
}
interface IF{}
class Monster implements IF{}
class Car implements IF{}
②多态数组(这太细节了,我都不想写)
public class InterfacePolyArr {
public static void main(String[] args) {
//多态数组 -> 接口类型数组
Usb[] usbs = new Usb[2];
usbs[0] = new Phone_();
usbs[1] = new Camera_();
/*
给Usb数组中,存放 Phone 和 相机对象,Phone类还有一个特有的方法call(),
请遍历Usb数组,如果是Phone对象,除了调用Usb 接口定义的方法外,
还需要调用Phone 特有方法 call
*/
for(int i = 0; i < usbs.length; i++) {
usbs[i].work();//动态绑定..
//和前面一样,我们仍然需要进行类型的向下转型
if(usbs[i] instanceof Phone_) {//判断他的运行类型是 Phone_
((Phone_) usbs[i]).call();
}
}
}
}
interface Usb{
void work();
}
class Phone_ implements Usb {
public void call() {
System.out.println("手机可以打电话...");
}
public void work() {
System.out.println("手机工作中...");
}
}
class Camera_ implements Usb {
public void work() {
System.out.println("相机工作中...");
}
}
③接口存在多态传递现象
public class InterfacePolyPass {
public static void main(String[] args) {
//接口类型的变量可以指向,实现了该接口的类的对象实例
IG ig = new Teacher();
//如果IG 继承了 IH 接口,而Teacher 类实现了 IG接口
//那么,实际上就相当于 Teacher 类也实现了 IH接口.
//这就是所谓的 接口多态传递现象.
IH ih = new Teacher();
}
}
interface IH {
void hi();
}
interface IG extends IH{ }
class Teacher implements IG {
public void hi() {
}
}
泛型
泛型含有的知识点如下:
//如
ArrayList<E>
//中的<E>,就代表要指定一个类型给他
ArrayList<Dog> arrayList = new ArrayList<Dog>();
//遍历的时候也能直接取出Dog了
for(Dog tempDog:arrayList){
System.out.println(tempDog.getName());
}
这个< Dog >就是泛型的使用,
看来我之前用过这种写法,但是我当时不知道它是泛型
,现在我对泛型有了个基本的了解。
标识类中某个属性的类型,或者是某个方法返回值的类型,或者参数类型
class Person<E>{//任意字母都可以,一般用T(type)
//标识属性类型
E val;
//E是参数类型
public Person(E s){
this.s =s;
}
//E是返回值类型
public E f(){
return s;
}
}
在事例化的时候,的数据类型就需要得到确定。
泛型使用细节
①< T >的只能是引用类型,如< integer >,< int >是不行的
②在给泛型指定具体类型后,可以传入该类型或者其子类类型,其他不行
③泛型使用形式:
List<Integer> list1 = new ArrayList <Integer>();
//或者简写为
List<Integer> list2 = new ArrayList<>();
ArrayList<Integer> list3 = new ArrayList <Integer>();
//或者简写为
ArrayList<Integer> list4 = new ArrayList<>();
//推荐使用简写形式
如果不写< T >,默认给他的泛型是< Object >
自定义泛型类
class 类名 <T,R...>{
成员
}
①普通成员可以使用泛型(属性、方法)
②使用泛型的数组,不能初始化(因为不知道要初始化成多大的)
③静态方法中不能使用类的泛型(因为静态是和类相关的,但是类加载时,还不知道是什么类型)
④泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
⑤如果在创建对象时,没有指定类型,
默认为Object
(但是不指定,会warning)
自定义泛型接口
interface 接口名<T,R...>{
}
①接口中,静态成员也不能使用泛型(和泛型类规定③一样);然而我们知道——接口中的属性,必须是public static final的
②泛型接口的类型,在
继承接口
或者
实现接口
时确定
③没有指定类型,默认为Object
OKOK,结束,😄( : D连着写就会变成 😄,非常的神奇)