继承概述:
示例:
关于聚集,聚合和组合:/* 继承: 1.提高代码的复用性 2.让类与类之间产生了关系,有了这个关系,才有了多态的特性 注意: 千万不要为了获取其他类的功能,简化代码而继承 必须类与类之间有所属关系才可以继承. 在java语言中:java只支持单继承(一个孩纸只有一个父亲),不支持多继承 因为多继承 容易带来安全隐患:当多个父类中定义了 相同功能,而功能内容不相同,子类对象不能确定运行哪一个 例如: class A { public void show() { System.out.println("A"); } } class B { public void show() { System.out.println("B"); } } class C extends A,B//假设支持多继承 { ... } C c1=new C() c1.show(); java保留这种机制,另一种体现形式完成-->多实现 java支持多层进程: A<—B<—C *//* 聚集:has a 根据事物的紧密联系程度划分: 聚合:电脑和鼠标 组合:人的眼睛和人 */ class Person { int age; String name; } classStudentextends
Person//不能再继承其它类 { public void study() { System.out.println("good study"); } } classWorkerextends Person { public void study() { System.out.println("good job"); } } /* 如何使用一个继承体系中的功能? 想要使用体系,先查阅体系父类描述,因为父类中定义的是该体系中 共性功能 通过了解共性功能,就可以知道体系的基本功能 那么这个体系已经可以基本使用了 在具体调用时,要创建最子类的对象. A<-B<-C 创建C类对象 ①有可能父类对象不能创建对象(抽象类,接口) ②创建子类对象可以使用更多功能(继承的和自有的) -->查阅父类功能,创建子类对象使用功能 */
子父类出现后,类中成员特点:
1.变量
示例:
/* 子父类出现后,类成员特点: 类中成员: 1.变量 2.函数 3.构造函数 -->变量 如果子类中出现非私有的同名成员变量时 子类访问本类中的变量->this 子类访问父类中的同名变量-->super super的使用和this使用几乎一致 this代表的是 本类对象的引用 super代表的是 父类对象的引用 */ class Father { int num=4; } class Son extends Father//当用到类Son,先加载类Father,再加载Son { int num=5; void show() { System.out.println(num);//this.num->5 System.out.println(super.num);//4 /* 如果注释掉 int num=5; 则两者均输出4 此时父类引用(super)也指向了子类对象new Son();(多态体现) 堆内存中只有一个num */ } } class ExtendsDemo { public static void main(String[] args) { Son s=new Son(); s.show(); } }子父类变量重名在内存中:
2.函数
/* 2.子父类中的函数 当子类出现和父类一模一样的函数时, 当子类对象调用该函数,会运行 子类函数的内容 如同父类的函数被覆盖一样. 这种情况是函数的另一个特性:重写(覆盖) 注:父类的方法还在内存当中,只不过没有运行而已 覆盖: ①子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败 ②静态只能覆盖静态. 覆盖和重载 重载:函数的参数个数和参数类型不同 覆盖:子父类方法一模一样(包括返回值类型) 重写一般用在: 当子类继承父类,沿袭了父类的功能,到子类中, 但是子类虽具备该功能,但是功能的内容却和父类不一致, 这时,没有必要定义新功能,而是使用覆盖特性,保留父类的功能定义 并重写功能内容. 例如:(简单对手机功能拓展) class Tel { void show() { System.out.println("number"); } } class NewTel extends Tel { void show() { super.show(); System.out.println("name"); } } */ class Father { void show() { System.out.println("Father's show"); } } class Son extends Father { void show() { System.out.println("Son's show"); } } class ExtendsDemo_2 { public static void main(String[] args) { Son s=new Son(); s.show(); } }
3.构造函数
示例:
/* -->理解为主 java继承中对构造函数是不继承的,只是调用(隐式或显式)。 子父类的构造函数. 在对子类对象进行初始化时,父类的构造函数也会运行,并且先于子类的构造函数执行 那是因为子类的构造函数默认第一行有一条隐式语句 super(); super(): ①访问父类中的空参数的构造函数. 子类中所有的构造函数第一行默认都是super(); ②super语句一定定义在子类构造函数的第一行, 那么在子类构造函数中this语句与super语句二者 只能存在其一 -->结论: ①子类的 所有构造函数,默认都会访问父类中空参数构造函数 因为隐式super();存在 ②当父类中没有空参数构造函数时,子类必须通过super语句手动指定 父类中的构造函数 ③当然,子类的构造函数第一行手动指定this语句来访问本类中的构造函数. 此时隐式super();不存在. 但是子类中(一定) 至少会有一个 构造函数会访问父类中的构造函数.
*/ class Father //extends Object(所有类的父类) { int number; Father() { //super();同样存在 number=20; System.out.println("Father()"); } Father(int x) { System.out.println("Father(int x)"); } } class Son extends Father { Son() { //super();//隐式语句 System.out.println("Son()"+"\t"+number);//Son() 20 } Son(int x) { //super();//依然有 System.out.println("Son(int x)"); } } class Extend_Construct { public static void main(String[] args) { Son s=new Son(); new Son(2); } } /* 为什么 子类中的构造函数 要访问 父类中的构造函数?? 因为父类中的数据子类可以直接获取.所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的. 如果要访问父类中指定的构造函数,通过super语句来手动指定 class Person { String name; Person(String name) { this.name=name; } } class Student extends Person { Student() { super("zhangsan"); System.out.println(name);//zhangsan } } class Extend_Construct { public static void main(String[] args) { new Student(); } } */
super()语句为什么要放在第一行?示例:/* 为什么super语句要放在第一句? 子类对象初始化时,如果先初始化自己,在去父类初始化,可能把子类的值覆盖掉 */ class Person { String name; Person(String name) { this.name=name; System.out.println(this.name); } class Student extends Person { Student(String name) { super("lisi"); this.name=name; //super("lisi")如果能成功的话,lisi覆盖掉zhansan从而得不到想要的zhangsan System.out.println(this.name); } } class Extend_Construct { public static void main(String[] args) { new Student("zhangsan"); } }
示例:/* final:最终.作为一个修饰符 1.可以修饰类,函数,变量 2.被final修饰的类不可以被继承 继承的弊端:打破了封装,例如通过继承重写一些功能 为了保证封装性,利用final关键字,让一些类不能继承. 3.被 final 修饰的功能不可以被复写(根据需要) 4.被 final 修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,又可以修饰局部变量 当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字.便于 阅读.而这个值不需要改变,所以加上final修饰.例如:PI=3.1415926 5.内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量 (当学习到内部类时,在看这一点) */ final class Demo//修饰类 { final int x=3;//修饰成员变量 public static final double PI=3.14;//作为常量:所有字母都大写,多个单词下划线连接 //权限够大(public),类名访问/对象之间共享(static),值不会变/常量(final) final void show()//修饰成员函数 {} void show2() { final int y=4;//修饰局部变量 } } class DemoSon extends Demo//编译失败 {}