《day09---继承-抽象类-接口》
Posted 太自由
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《day09---继承-抽象类-接口》相关的知识,希望对你有一定的参考价值。
//面向对象_继承_概述---单继承_多继承。 //描述学生。 /* class Student { //属性。 String name; int age; //行为: void study() { System.out.println("good good study"); } } class Worker { //属性: String name; int age; //行为; void work() { System.out.println("hard work"); } } */ /* 为了提高代码的复用性,只建立一份代码就可以了。 一个类只要和另一个类产生关系就可以了。 关系:继承。 发现了获取到所需内容的同时也获取到不该具备的内容。 为什么? 发现原来这两个类之间根本就不存在继承关系。 怎么解决呢? 找到学生和工人的共性类型。将需要提供复用的代码进行抽取。 定义到一个共性的类中。 Person name age. 怎么在代码体现中,让学生和Persong产生关系呢? 只要通过关键字extends(继承),就可以了。 */ class Person { //属性: String name; int age; } class Student extends Person//学生继承了Person,学生就是子类,Person就是父类(基类。超类) { //行为: void study() { System.out.println("good good study"); } } class Worker extends Person { //行为; void work() { System.out.println("hard work"); } } /* 面向对象的另一个特征:继承。 好处:提高了代码的复用性。让类和类产生了关系,给另一个特征。多态提供了前提。 什么时候定义继承? 必须保证类与类之间有所需(is a)关系.xxx是zzz中的一种。 学生是人中的一种。 苹果是水果中的一种。 狗是犬科中的一种。 在Java中继承的体现。 Java允许单继承。不直接支持多继承。将多继承进行其他方式的体现。 单继承:一个子类只能有一个父类。 多继承:一个子类可以有多个父类。 看上去,多继承很厉害!为什么? class Fu1 { void show1() {} } class Fu2 { void show2() {} } //多继承。 class Zi extends Fu1,Fu2 { } Zi z = new Zi(); z.show1(); z.show2(); //问题随之而来, 万一多个父类具备了相同的功能呢? class Fu1 { void show() { sop("fu1 show run"); } } class Fu2 { void show() { sop("fu2 show run"); } } //多继承。 class Zi extends Fu1,Fu2 { } Zi z = new Zi(); z.show();//调用就会产生不确定性。所以java保留了多继承的好处。 //改良了它的弊端,用多实现来体现。用多实现来体现。 //即将学到。 ---------------------------------- java中还支持多重继承。 class A {} class B extends A {} class C extends B {} //形成继承体系。 学习继承体系时,应该参阅顶层的类中的内容。 了解这个体系的基本功能。 使用这个体系功能,需要创建最子类的对象。 看顶层,建底层。 */ class ExtendsDemo { public static void main(String[] args) { Student stu = new Student(); stu.name = "xiaoming"; stu.age = 12; stu.study(); } }
1 //面向对象_继承_子父类中成员变量的特点。 2 /* 3 继承出现后,在代码中的体现。 4 5 重点在于成员的体现: 6 1,成员变量。重点明确原理。 7 特殊情况: 8 子父类中定义了一模一样的成员变量。 9 都存在于子类对象中。 10 如何在子类中直接访问同名的父类中的变量呢? 11 通过关键字super来调用。 12 13 super和this的用法很相似。 14 this代表的是本类对象的引用。 15 super代表的是父类的内存空间。 16 17 注意:这种情况开发见不到。因为父类一旦描述完了属性, 18 子类直接使用就可以了。 19 20 2,成员函数。 21 3,构造函数。 22 */ 23 24 //父类 25 class Fu 26 { 27 /*private int num1 = 3;*///父类中私有的内容子类不可以直接访问。 28 int num = 3; 29 } 30 31 class Zi extends Fu 32 { 33 /*int num2 = 4;*/ 34 int num = 4; 35 void show() 36 { 37 // System.out.println("num1="+num1); 38 // System.out.println("num2="+num2); 39 System.out.println("fu num="+super.num); 40 System.out.println("zi num="+this.num); 41 System.out.println(this); 42 } 43 } 44 class ExtendsDemo 45 { 46 public static void main(String[] args) 47 { 48 Zi z = new Zi(); 49 // System.out.println(z.num1); 50 // System.out.println(z.num2); 51 z.show(); 52 } 53 }
1 /* 2 子父类中成员函数的特点。 3 特殊情况: 4 子父类中定义了一模一样的函数。 5 运行的结果是子类的函数在运行。 6 这种情况在子父类中,是函数另一个的特性,Override 重写(覆盖,复写) 7 8 重写什么时候用? 9 举例: 10 //描述手机 11 class Phone 12 { 13 //打电话。 14 void call() 15 {} 16 17 //来点显示。 18 void show() 19 { 20 System.out.println("电话号码"); 21 } 22 } 23 24 Phone p = new Phone(); 25 p.show(); 26 27 //随着电话的升级,只显示号码不爽,希望显示姓名,大头贴等。 28 修改源码,虽然费劲,但是可以解决问题,但是不利于后期的维护和扩展。 29 为了扩展方便,新功能是不是新的电话具备呢? 30 单独描述,单独封装。新电话也是电话中的一种,继承。直接获取父类中的功能。 31 但是新电话的来电显功能已经变化了。需要重新定义。 32 那么定义一个新功能合适吗?比如NewShow,不合适,因为父类已经将来点显功能定义了。 33 子类完全不需要重新定义新功能,直接用就可以了,如果子类的来显功能内容不同。 34 只需要保留来显功能,定义子类的内容即可,这就是重写的应用。 35 class NewPhone extends Phone 36 { 37 void show() 38 { 39 //System.out.println("电话号码"); 40 super.show();//如果还需要父类中原有的部分功能,可以通过super调用。 41 sop("姓名"); 42 sop("大头贴"); 43 } 44 } 45 46 47 重写的注意事项: 48 1,子类覆盖父类,必须保证权限要大于或者等于父类的权限。(private除外,因为子类 49 中不能直接访问父类中的private。) 50 Fu: 51 void show(){} 52 53 Zi: 54 void show(){} 55 56 2,静态覆盖静态。 57 58 59 写法上注意:不行一模一样:函数的返回值类型 函数名 函数的参数列表都要一样。 60 */ 61 class Fu 62 { 63 void show() 64 { 65 System.out.println("fu show1 run"); 66 } 67 } 68 class Zi extends Fu 69 { 70 static void show() 71 { 72 System.out.println("zi show2 run"); 73 } 74 } 75 class ExtendsDemo2 76 { 77 public static void main(String[] args) 78 { 79 Zi z = new Zi(); 80 z.show(); 81 82 } 83 }
1 /* 2 子父类中构造函数的特点。 3 当子父类中都有构造函数时,发现结果为: 4 Fu constructor run 5 zi constructor run 6 先执行了父类的构造函数,再执行子类中的构造函数。 7 为啥呢? 8 因为子类中的所有的构造函数中的第一行都有一句隐式额语句Super(); 9 //默认调用的是父类中空参数的构造函数。 10 子类中构造函数为什么有一句隐式的super呢? 11 原因:子类会继承父类中的内容,所以子类在初始化时,必须先到父类中去 12 执行父类的初始化动作。 13 才可以更方便子类使用。 14 15 当父类中没有空参数构造时,子类的构造函数必须显示的super语句指定 16 要访问的父类中构造函数。 17 18 这就是传说中的子类实例化过程。 19 20 细节: 21 1,如果子类的构造函数第一行写了this调用了本类的构造函数,那么super调用父类的 22 语句还有吗? 23 没有的,因为this()或者super(),只能定义在构造函数的第一行,因为初始化动作要先执行。 24 25 2,子类构造函数里有super,那么父类构造函数有没有super呢? 26 是有的,记住:只要是构造函数默认第一行都是super(); 27 父类的父类是谁呢?super 调用的到底是谁的构造函数呢? 28 Java体系在设计时,定义了一个所有对象的父类Object. 29 30 31 总结: 32 类中的构造函数默认第一行都由隐式的super语句,在访问父类中的构造函数。 33 所以父类的构造函数既可以给自己的对象初始化,也可以给自己的子类对象初始化。 34 35 如果默认的隐式super语句没有对应的构造函数,必须在构造函数中通过this或者super 36 的形式明确要调用的构造函数。 37 38 问题: 39 1,this 语句和super语句是否可以在同一个构造函数中出现呢?不行:因为必须定义在第一行。 40 2,为什么要定义在第一行呢?因为初始化动作要先执行。 41 */ 42 43 class Fu extends Object 44 { 45 int count = 3; 46 //Fu(){} 47 Fu() 48 { 49 //super(); 50 //显示初始化。 51 System.out.println("Fu constructor run..A.."+count); 52 } 53 Fu(int x) 54 { 55 //显示初始化。 56 System.out.println("Fu constructor run..."+x); 57 } 58 } 59 60 class Zi extends Fu 61 { 62 Zi() 63 { 64 System.out.println("zi constructor run..C.."); 65 } 66 Zi(int x) 67 { 68 this(); 69 System.out.println("zi constructor run..."+x); 70 } 71 } 72 class ExtendsDemo 73 { 74 public static void main(String[] args) 75 { 76 //New Zi(); 77 new Zi(6); 78 new Student("lisi",21); 79 } 80 } 81 82 /* 83 84 class Fu 85 { 86 Fu() 87 { 88 System.out.println("Fu constructor run..A.."); 89 } 90 Fu(int x) 91 { 92 //显示初始化。 93 System.out.println("Fu constructor run..B.."); 94 } 95 } 96 97 class Zi extends Fu 98 { 99 Zi() 100 { 101 //super(); 102 System.out.println("Fu constructor run..C.."); 103 } 104 Zi(int x) 105 { 106 //super(); 107 System.out.println("Fu constructor run..D.."); 108 } 109 } 110 class ExtendsDemo 111 { 112 public static void main(String[] args) 113 { 114 new Zi(); 115 new Zi(6);//打印结果是A C A D. 116 } 117 } 118 119 */ 120 121 //子类的实例化过程的应用。也是super调用的应用。 122 //什么时候用super调用父类中的构造函数,只要使用父类的指定初始化动作, 123 //就在子类中使用super()调用就可以了。 124 class Person 125 { 126 private String name; 127 private int age; 128 public Person(String name,int age) 129 { 130 this.name = name; 131 this.age = age; 132 } 133 public void setName(String name) 134 { 135 this.name = name; 136 } 137 public String getName() 138 { 139 return name; 140 } 141 public void setAge(int age) 142 { 143 this.age = age; 144 } 145 public int getAge() 146 { 147 return age; 148 } 149 } 150 class Student extends Person 151 { 152 public Student(String name,int age) 153 { 154 //调用父类,使用父类的初始化动作。 155 super(name,age); 156 } 157 158 } 159 160 class Worker extends Person 161 { 162 public Worker(String name,int age) 163 { 164 //调用父类,使用父类的初始化动作。 165 super(name,age); 166 } 167 }
1 //final关键字。 2 /* 3 继承的弊端:打破封装性。 4 不让其他类去继承该类,就不会有重写。 5 怎么能实现呢?通过java中的关键字来实现。final(最终化) 6 7 【final】 8 是一个修饰符。可以修饰类,方法,变量(成员变量,局部变量,静态变量) 9 【特点】 10 1,final修饰的类是一个最终类,不能再派生子类。 11 如果类中出现部分可以重写,部分不可以?怎么办?只要让指定的方法最终化就可以了。 12 2,final修饰的方法是最终方法,不可以重写。 13 3,fianl修饰变量是一个常量。只能被赋值一次。 14 【什么时候需要在程序中定义final常量呢?】 15 当程序中一个数据使用时是固定不变的,这时为了增加阅读性,可以给该数据起个名字。 16 这就是变量,为了保证这个变量的值不被修改,加上final修饰,这就是一个阅读性很强的 17 常量。书写规范,被final修饰的常量名所有的字母都是大写的。如果由多个单词组成,单词 18 之间用下划线连接。 19 */ 20 /*final*/ class Fu 21 { 22 /*final*/ void show() 23 { 24 //调用到一些系统的功能。 25 //功能的内容是不可以改变的。 26 } 27 } 28 29 class Zi extends Fu 30 { 31 static final int number = 9;//这个编译会失败,final修饰的变量必须赋初值。 32 static final double PI = 3.14;//为了访问方便,直接用static修饰,可以直接用类名调用。 33 //覆盖 34 void show() 35 { 36 final int count = 21; 37 //count = 2;//失败。 38 System.out.println(count); 39 } 40 } 41 42 class FinalDemo 43 { 44 public static void main(String[] args) 45 { 46 System.out.println("Hello World!"); 47 } 48 }
1 /* 2 描述狗,行为,吼叫。 3 描述狼,行为:吼叫。 4 发现他们之间有共性,可以进行向上抽取。 5 当然是抽取它们的所属共性类型,犬科。 6 犬科这类事物,都具备吼叫行为。但是具体怎么叫,是不确定的,是由具体的子类来 7 明确的。 8 这些不具体的功能,需要在类中标识出来,通过java中的关键字来体现。 9 10 定义了抽象函数的类也必须别abstract修饰。 11 12 抽象类,在描述事物时,没有足够的信息描述一个事物,这时该事物就是抽象事物。 13 */ 14 15 /* 16 【抽象类的特点】 17 1,抽象类和抽象方法都需要被abstract修饰。 18 抽象方法一定要定义在抽象类中。 19 2,抽象类不可以创建实例。原因就在于调用抽象方法没意义。 20 3,只有覆盖了抽象类中所有的抽象方法后,其子类才可以实例化。 21 否则,该子类还是一个抽象类。 22 23 之所以继承,更多的是在思想上,是面对共性类型操作会更简单。 24 25 【细节问题】 26 1,抽象类一定是一个父类。 27 是的,因为是不断向上抽取而来的。 28 29 2,抽象类中是否有构造函数。 30 有,虽然不能给自己的对象初始化,但是可以给自己的子类对象初始化。 31 抽象类和一般类的异同点: 32 相同: 33 1,它们都是用来描述事物的。 34 2,它们之中都可以定义属性和行为。 35 不同: 36 1,一般类可以具体的描述事物, 37 抽象类描述事物的信息不具体。 38 2,抽象类中可以多定义一个成员,抽象汉。 39 3,一般类可以创建对象,而抽象类不能创建对象。 40 41 3,抽象类中是否可以不定义抽象方法。 42 是可以的。那这个抽象类的存在到底有什么意义呢?仅仅是不让不让该类创建对象。 43 44 4,抽象类关键字不可以哪些关键字共存。 45 1,final. 被final修饰的类是最终类,不能被继承,而抽象类就是要被子类继承的。 46 2,private. 被private修饰的方法,其子类无法直接访问,而抽象的方法就是要让子类覆盖的。 47 3,static. 被static修饰的方法要随着类的加载而加载,且可以直接由类名调用。 48 49 */ 50 51 abstract class 犬科 //extends Object 52 { 53 abstract void 吼叫();//抽象函数,需要abstract修饰。并分号;结束 54 } 55 56 //代码体现。 57 class Dog extends 犬科 58 { 59 void 吼叫() 60 { 61 System.out.println("汪汪汪汪"); 62 } 63 } 64 65 66 class Wolf extends 犬科 67 { 68 void 吼叫() 69 { 70 System.out.println("嗷嗷嗷嗷"); 71 } 72 } 73 74 class AbstractDemo 75 { 76 public static void main(String[] args) 77 { 78 System.out.println("Hello World!"); 79 } 80 }
1 /*抽象类联系 2 需求:公司中程序员有姓名,工号,薪水,工作内容。 3 项目经理除了姓名,工号,薪水,还有奖金,工作内容。 4 对给定的需求进行数据建模。 5 6 在问题领域中先找寻其中的涉及的对象。 7 程序员: 8 属性:姓名,工号,薪水。 9 行为:工作。 10 11 项目经理: 12 属性:姓名,共号,薪水。 13 行为:工作。 14 15 这些对象是否有关系呢?因为发现了它们之间的共性,应该存在着关系。 16 可以将他们的共性向上抽取到共性类型,员工。 17 员工: 18 属性:姓名,工号,薪水。 19 行为:工作。 20 发现员工的工作内容本身就不具体,应该是抽象的,由具体的子类来体现。 21 22 */ 23 24 abstract class Employee 25 { 26 private String name; 27 private String id; 28 private double pay; 29 30 /** 31 构造一个员工对象,一初始化就具备三个属性。 32 */ 33 34 Employee(String name,String id,double pay) 35 { 36 this.name = name; 37 this.id = id; 38 this.pay = pay; 39 } 40 41 /** 42 工作行为: 43 */ 44 public abstract void work(); 45 } 46 47 //具体的子类实现,程序员: 48 class Programer extends Employee 49 { 50 Programer(String name,String id,double pay) 51 { 52 super(name,id,pay); 53 } 54 public void work() 55 { 56 System.out.println("code...."); 57 } 58 } 59 60 //具体的子类,经理: 61 class Manager extends Employee 62 { 63 //特有属性。 64 private double bouns; 65 public Manager(String name,String id,double pay,double bouns) 66 { 67 super(name,id,pay); 68 this.bouns = bouns; 69 } 70 71 public void work() 72 { 73 System.out.pritnln("work"); 74 } 75 } 76 class AbstractTest 77 { 78 public static void main(String[] args) 79 { 80 System.out.println("Hello World!"); 81 } 82 }
/* 抽象类中是可以定义抽象方法的,当一个抽象类中方法全是抽象的, 这时,可以通过另一种特殊的形式来体现。 不再用class来定义,用接口来表示。 接口该如何定义呢? interface abstract class Demo { abstract void show1(); abstract void show2(); } */ /* 接口中的成员已经被限定为固定的几种。 【接口的定义格式先介绍两种】 1,定义变量,但是变量必须有固定的修饰符修饰,public static final所以接口中的变量 也称之为常量。 2,定义方法,方法也有固定的修饰符,public abstract 接口中的成员都是公共的。 【接口的特点】 1,接口不能创建对象。 2,子类必须覆盖掉接口中所有的抽象方法后子类才可以实例化。 否则子类是一个抽象类。 */ interface Demo//定义一个名称为Demo的接口。 { public static final int NUM = 3; public abstract void show1(); public abstract void show2(); } //定义子类去覆盖接口中的方法。子类必须和接口产生关系,类与类的关系是继承 //类与接口之间是实现。 class Demoimpl implements Demo //子类实现接口。 { //重写接口中的方法。 以上是关于《day09---继承-抽象类-接口》的主要内容,如果未能解决你的问题,请参考以下文章