整理知识笔记(4)--继承、接口、抽象类

1:重载与覆盖:

重载:不同参数,相同函数名
相同的范围(同一个类中);
函数名字相同;
参数不同(返回值可以不同);
Virtual关键字可有可无;

覆盖:派生类中重新定义的函数,其函数名、参数、返回值类型都必须与父类相同。派生类会自动调用子类的覆盖版本。
不同的范围(分别位于派生类与基类);
函数名字相同;
参数相同,返回值必须相同;
基类函数必须有virtual关键字;
(静态的方法不能被覆盖)
2:
继承结构中,父类的内部细节对子类是可见的,通过继承的代码复用是一种“白盒式代码复用”;
组合是通过对现有的对象进行组合产生新的更复杂的功能,因为在对象之间各自的内部细节是不可见得,所以这种方式叫做“黑盒式代码复用”

3:
public class NULL{
public static void main(String[] args){
Father f = new Father();
Father c = new Child();
System.out.println(f.getName()+" "+c.getName());
}
}
class Father{
public static String getName(){
return "Father";
}
}
class Child extends Father{
public static String getName(){
return "Child";
}
}
因为这两个getName方法都是静态方法,所以在内存中的地址空间是固定的,根本不存在冲突问题,他两占用不同的内存空间
执行哪个就要看是由哪个类调用的,因为是静态方法而且两个引用都是father的所有只会调用father的
结果为FatherFather

如果都不是staic静态的,就会输出FatherChild

静态的就看左边的类不是静态的就看右边的new

Child b = new Child();
Father a =(Father) b;
System.out.println(a.getName());
///输出为Child因为b是child类所以输出的是child




4:super
子类构造函数如果要引用super,就必须把super放在函数的首位,(不可调换顺序)即:
class Checket extends Base{
Checket(){
super(); System.out.println("Checket");
}
}
如果不放在第一行的话,那么最后使用了super继承父类的构造方法,那么就又重新回到父类的构造方法,与子类无关。

当子类的成员变量或方法与父类中的成员变量或方法同名时,因为子类的优先级高,所以子类的成员变量或方法就会隐藏父类的成员变量和方法,当需要使用父类的成员变量或方法时就需要super。

5:this(输出结果为testhello)
public class NULL{
public static void main(String[] args){
Test t = new Test(5); ///第1步,先执行Test(int var)
}
}
class Test{
int var;
Test(int var){
this("hello"); ///第2步,执行Test(String s)
}
Test(String s){
this(); ///第3步,执行Test(),输出test
System.out.println(s); ///第4步,输出S:hello
}
Test(){
System.out.println("test");
}
}

6:this和super
This关键字使用在一个成员函数的内部,指向当前对象(即调用当前正在执行方法的那个对象);
Super关键字是直接执行超类的构造函数,用来引用超类的中的变量和方法。(使用this三种方法:)
this.name; //使用this访问成员变量以区分同名参数
System.out.println(this); ///可以直接打印出固有参数的当前状态
this(name,age); ///写于构造函数的第一个语句,进行赋值
7:
public class NULL{
public static void main(String[] args){
go(new mybase());
}
static void go(base b){///第7步
b.add(8); ///相当于base b = new mybase()成员函数看mybase6+8*2=22
}
}
class base{
int i;
base(){
add(1); ///第一步,调用mybase的add(1)
System.out.println(i); ///第3步::输出2
}
void add(int v){
i+=v; System.out.println(i);
}
}
class mybase extends base{
mybase(){
add(2); ///第4步:
System.out.println(i); ///第6步::输出6
}
void add(int v){
i+=v*2; ///第2步i=0+1*2=2; ; ; 第5步:i=2+2*2
System.out.println(i); ///第2步:输出2; ; ; ; 第5步:输出6
}
}
在主函数中,首先执行new mybase(),子类会先调用父类的构造函数;父类的构造函数base()中执行add()方法

这个add()方法由于是在新建mybase对象是调用,将会先查找mybase有无此方法,所以base()中的add(1)实际是:
(即当前对象的add方法)
void add(int v){
i+=v*2; ///i=0+1*2
System.out.println(i); //输出2
}

输出结果为2 2 6 6 22

8:抽象类与接口
C++中没有对抽象类进行直接声明的方法,而认为只要在类中定义了纯虚函数,此类即为抽象类。
///C++中定义抽象类的做法
class shape{///此处不需要显示的声明抽象类
public :
shape(){}
~shape(){}
virtual void draw()=0; ///定义了纯虚函数
}
Java是通过显式的声明抽象类并使用abstract修饰符的方法
///java中定义抽象类的做法
abstract class shape{///此处显示声明抽象类
public abstract void find();
public void about(){
System.out.println("abstract");
}
}

抽象类:
1)抽象类只能作为其他类的基类,它不能被实例化,而且不能使用new操作符。抽象类如果含有抽象的变量或值,则他们要么是null类型,要么包含了对抽象类的实例的引用;
2)抽象类允许包含抽象成员,但这不是必须的,也可以没有任何抽象成员;抽象类可以有非抽象方法;(即空的抽象类也是可以的)
3)抽象类不能同时又是final,抽象类希望被继承,final类希望不被继承;
4)如果一个非抽象类从抽象类派生,就必须通过覆盖来实现所有继承来的抽象成员;(覆盖:派生类中重新定义函数)
5)抽象类可以被抽象类所继承,就够仍然为抽象类;
6)抽象类可以被声明;
【整理知识笔记(4)--继承、接口、抽象类】如下面一段程序:
abstract class person{///建立抽象类
public abstract void say(); //抽象方法
public void about(){//非抽象方法
System.out.println("abstract");
}
}

class student extends person{
//建立实体类student继承抽象类person
public void say(){//子类覆盖抽象方法say
System.out.println("stu say");
}
}
class nurse extends person{
///没有覆盖抽象类方法say,所以这个类是错误的
}

abstract class pupli extends person{
//建立抽象类pupli 继承抽象类person
public void say(){//抽象子类覆盖say
System.out.println("pup say");
}
}
abstract class worker extends person{
//建立抽象类worker继承person
//抽象类继承抽象类,可以不覆盖say,所以此类正确
}

9:接口:(publicabstract方法static变量无构造方法final变量 )
1)接口用于描述系统对外提供的所有服务,因为接口中的成员变量和方法都必须是public类型的,确保外部使用者都可以访问他们;
2)接口仅仅描述系统能够做什么,但不指明如何去做,所以接口中的方法都是抽象abstract方法;
3)接口不涉及任何与实例相关的细节,因此接口没有构造方法,不能被实例化,没有实例变量,只有static变量;
4)接口中的变量是所有实现类共有的,既共有就不可变,所以变量是不可变类型(final),即常量;即接口中不存在变量;
5)接口只是对一类事务的属性和行为更高层的抽象,对修改关闭,对implement开发;接口的方法默认是public abstract ,接口的属性默认为public static final常量,且必赋初值;
注意:final与abstract不可同时出现;
开发人员能够分工明确,只要确定下来接口了,就可以同时进行开发,提高开发效率。另外,使用接口还有使用方便,可读性强,结构清晰、方便维护等优点。
定义一个接口,可以有多种实现。变量声明为接口变量,调用接口方法,以后切换实现类的时候,原有代码不用修改。
解耦,可扩展这是设计接口的主要原因之一
为什么接口可以多继承,而类不可以?
如果有两个父类,两个父类里有一个相同的方法,那么作为子类应该怎么继承这个方法?父类1的还是父类2的?
但是实现多个接口则没问题,因为不管哪个接口,调用的都是同一个实现,因为只有方法名!
而且单继承的目的之一,就是降低复杂度,减少维护难度
继承:描述事物的自然属性和行为的复用。
接口:描述事物的社会属性和行为的复用。
class 负责实现, interface负责接口;
class 负责实现, interface负责接口; 多继承最麻烦的问题就是冲突, 冲突主要体现在 实现的时序和传入参数, 传出参数这几个方面对于实现来说,父类发生时序问题时,使得语言本身变得无比复杂,而多继承问题在实现本身是可以通过很多方式解决的, 而对于接口来说,传入参数冲突是overload,则不是问题, 只有传出参数这个问题是接口多继承不允许的例如:
public interface IA {
void doSomething();
}
public interface IB {
Integer doSomething();
}
public interface IAB extends IA, IB {
@Override
public void doSomething();
@Override
public Integer doSomething();
}
这种情况编译器会告诉你, IA, IB 接口冲突,是不允许的
参考https://www.cnblogs.com/yunxiblog/p/5240690.html


    推荐阅读