SE -- 继承
继承
概述: 多个类中存在相同的属性和行为时,将这些内容抽取到单独的一个类中,那么多个类无需再定义这些属性和行为,只要继承单独的那个类即可。
多个类可以称为子类,单独这个类称为父类或者超类。
子类可以直接访问父类中的非私有的属性和行为。
通过extends关键字让类与类之间产生继承关系。 class SubDemo extends Demo{}
继承的出现提高了代码的复用性;继承的出现让类与类之间产生了关系,提供了多态的前提。
特点:java只支持单继承,不支持多继承;支持多层继承。
注意:不要仅为了获取其他类中某个功能而去继承;类与类之间要有所属关系 is a xx1是xx2的一种
聚集:has a
聚合:班级里面有学生;球队中有球员
组合:心脏是人体的一部分,手人体的一部分(紧密联系程度不同)
子父类出现后,类中成员的特点
1、变量
如果子类中出现非私有的同名成员变量,子类要访问本类中的成员变量,用this;要访问父类中的成员变量,用super。
2、函数
3、构造函数
super关键字
this代表本类应用;super代表父类应用;当子父类出现同名成员时,可以用super进行区分;子类要调用父类构造函数时,可以使用super语句
函数覆盖(override)
子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为复写或者重写;父类中的私有方法不可以被覆盖。在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取。
覆盖:
1、覆盖时,子类方法权限一定要大于等于父类方法权限
2、静态只能覆盖静态
应用:
当子类需要父类的功能,而功能主体子类有自己特定内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
子类的实例化过程
子类中所有的构造函数默认都会访问父类中空参数的构造函数
因为每一个构造函数的第一行都有一条默认的语句 super()
子类会具备父类中的数据,所以要明确父类是如何对这些数据初始化的
当父类中没有空参数的构造函数时,子类的构造函数必须通过this或者super语句指定要访问的构造函数。
class Fu { Fu() { System.out.println("Fu run..."); } } class Zi extends Fu { Zi() { //super() System.out.println("Zi run..."); } Zi(int x) { //super() System.out.println("Zi run..." + x); } } class ExtendsDemo { public static void main(String[] args) { Zi z = new Zi(); Zi z1 = new Zi(4); } } /* ---------- java ---------- Fu run... Zi run... Fu run... Zi run...4 输出完成 (耗时 0 秒) - 正常终止 */
?子类一定要访问父类中的构造函数
因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。所以子类在对象初始化时,要先访问以下父类的构造函数,所以要访问父类的构造函数,可以通过定义super()语句访问。
final关键字
1、final可以修饰类、方法、变量。
2、final修饰的类不可以被继承。
3、final修饰的方法不可以被覆盖。
4、final修饰的变量是一个常量,只能被赋值一次。常量的书写规范:所有字母都大写,如果多个单词组成,单词间通过_连接
5、内部类只能访问被final修饰的局部变量。
修饰类 public final
抽象类
抽象:抽象就是从多个事物中将共性的、本质的内容抽取出来。
抽象类:java中可以定义没有方法体的方法。该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。抽象方法和抽象类都必须被abstract修饰
抽象类不可以被new创建对象,因为调用抽象方法没有意义。
抽象类中的抽象方法要像被使用 必须被子类覆写所有的抽象方法后,建立子类对象使用,如果子类只覆写了部分抽象方法,那么子类还是一个抽象类。
抽象方法:多个对象都具备相同的功能,但是功能具体内容有所不同。那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。
疑惑点:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。
/* 员工: 姓名 工号 工资 name id pay 经理:继承员工 + 奖金bonus */ abstract class Employee { private String name; private String id; private double pay; //员工初始化 Employee(String name, String id, double pay) { this.name = name; this.id = id; this.pay = pay; } //方法 public abstract void work(); } class Manager extends Employee { private int bonus; //经理初始化 Manager(String name, String id, double pay,int bonus) { super(name,id,pay); this.bonus = bonus; } public void work() { System.out.println("manager work..."); } } class Pro extends Employee { Pro(String name, String id, double pay) { super(name,id,pay); } public void work() { System.out.println("Pro work..."); } } public class AbstarctDemo { public static void main(String[] args) { Manager mg = new Manager("wu","1",1.1,1); mg.work(); } } /* ---------- java ---------- manager work... 输出完成 (耗时 0 秒) - 正常终止 */
模板方法设计模式:在定义功能时,功能的一部分是确定的,但是有一部分是不确定的,而确定的部分在使用不确定的部分,那么这时就将不确定的部分暴露出去。由该类的子类去完成
/* 需求: 获取一段程序运行的时间 原理: 获取程序开始和结束的时间并相减 获取时间 currentTimeMillis() */ abstract class GetTime { public final void getTime() { long start = System.currentTimeMillis(); runCode(); long end = System.currentTimeMillis(); System.out.println("\nend-start:" + (end-start)); } public abstract void runCode(); } class SubTime extends GetTime { public void runCode() { for(int x=0; x<1000; x++) { System.out.print(x); } } } class TemplateDemo { public static void main(String[] args) { SubTime st = new SubTime(); st.getTime(); } } /* end-start:12 */
接口
接口 innterface{}
接口中的成员修饰符是固定的:
成员常量:public static final
成员函数:public abstarct
接口的出现将“多继承”通过另一种形式体现出来,即“多实现”implement。
特点
1、接口是对外暴露的规则
2、接口是程序的功能扩展。
3、接口可以用来多实现。
4、类与接口直接是实现关系,而且类可以继承一个类的同时实现多个接口。
5、接口与接口之间可以有继承关系。
多态
某一类事物的多种存在形态。
例如:猫这个对象对应的类类型是猫类型,也是动物的一种;父类型引用指向了子类对象。
体现:父类或者接口的引用指向或者接受自己的子类对象。
作用:多态的存在提高了程序的扩展性和后期可维护性。只能使用父类的引用访问父类的成员。
前提:需要存在继承或者实现关系。要有覆盖操作。
向上转型: Animal a = new Cat()
向下转型[强制将父类的引用转成子类类型]: Cat c = (Cat)a
多态的特点
成员函数:
编译时,要查看引用变量所属的类中是否有所调用的成员。
运行时,要查看对象所属的类中是否有所调用的成员
成员变量:只看引用变量所属的类。
静态成员函数特点:无论编译还是运行,都参考左边。
object类
方法
equals :对对象是否相同的方法,可覆盖
class Demo //extends Object { } public class ObjectDemo { public static void main(String[] args) { Demo d1 = new Demo(); Demo d2 = new Demo(); Demo d3 = d1; System.out.println(d1.equals(d2)); System.out.println(d1.equals(d3)); System.out.println(d1==d2); System.out.println(d1==d3); } } /* ---------- java ---------- false //比较内存地址值 true false true */
//数值比较 class Demo //extends Obect { private int num; Demo(int num) { this.num = num; } //覆写父类方法 public boolean equals(Object obj) { //向下转型 Demo d = (Demo)obj; if(!(d instanceof Demo)) return false; return this.num == d.num; } } class Person { } class ObjectDemo { public static void main(String[] args) { Demo d1 = new Demo(4); Demo d2 = new Demo(5); Person p1 = new Person(); System.out.println(d1.equals(d2)); System.out.println(p1.equals(d1)); } } /* ---------- java ---------- false false */
toString 对象字符串表示形式
getClass().getName() + '@' + Integer.toHexString(hashCode())
内部类
定义:将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)
特点:
1、内部类可以直接访问外部类中的成员,包括私有成员。
2、外部类要访问内部类中的成员必须要建立内部类的对象
class Outer { private int x = 3; //内部类可以直接访问外部类的成员,包括私有。 //外部类要访问内部类必须建立内部类对象 private class Inner 可以被私有,类中被访问 class Inner { int x = 4; void function() { int x = 6; /* ---------- java ---------- inner:6 inner:4 inner:3 */ System.out.println("inner:" + x); System.out.println("inner:" + this.x); System.out.println("inner:" + Outer.this.x); } } void method() { Inner in = new Inner(); in.function(); } } class InnerClassDemo { public static void main(String[] args) { Outer ot = new Outer(); ot.method(); //直接访问内部类成员 /* Outer.Inner in1 = new Outer().new Inner(); in1.function(); */ } }
位置:
成员位置:
1、可以被private static成员修饰符修饰
2、被static修饰的内部类只能访问外部类中的静态成员
Q1 在外部其他类中,如何直接访问static内部类的非静态成员?
new Outer.Inner().function();
Q2 在外部其他类中,如何直接访问static内部类的静态成员?
Outer.Inner.function()
注意:当内部类定义了静态成员,该内部类必须是static的
当外部类中的静态方法访问内部类时,内部类也必须是静态的。
class Outer { private static int x = 3; //内部类可以直接访问外部类的成员,包括私有。 //外部类要访问内部类必须建立内部类对象 private class Inner 可以被私有,类中被访问 //静态内部类 InnerClassDemo.java:12: 错误: 无法从静态上下文中引用非静态 变量 System.out.println("inner:" + x); static class Inner { void function() { System.out.println("inner:" + x); } } void method() { Inner in = new Inner(); in.function(); } } class InnerClassDemo { public static void main(String[] args) { Outer ot = new Outer(); ot.method(); } }
局部位置:
1、可以直接访问外部类中的成员
2、同时可以访问所在局部中的局部变量,但必须是被final修饰的
class Outer { int x = 3; void method(int x) { int y =4; class Inner { void function() { System.out.println("x = " + x); System.out.println("y = " + y); } } new Inner().function(); } } public class InnerClassDemo { public static void main(String[] args) { new Outer().method(4); } } /* ---------- java ---------- x = 3 y = 4 */
Q:定义内部类
当描述事物时,事物的内部还有事物,该事物用内部类描述。因为内部类事物在使用外部类事物的内容。例如:人体有器官等。
匿名内部类:就是内部类的简化写法
前提:内部类可以继承一个外部类或者实现接口
格式:new 外部类名或者接口名(){覆盖类或者接口欧中的代码/自定义内容}
Q1:建立一个戴内容的外部类或者接口的子类匿名内部类。
异常
Throwable
throws throw
异常处理
自定义异常
异常细节
包
classpath
包之间的访问
import
Jar包