一、继承
1、子父类中的函数
代码:ExtendsDemo3.java
class Fu { void show() { System.out.println("fu show"); } } class Zi extends Fu { void show() //子父类中的方法一致 当子类出现和父类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容,如同父类的函数被覆盖一样。这种情况是函数的另一个特性:重写(覆盖) { System.out.println("zi show"); } } class ExtendsDemo3 { public static void main(String[] args) { Zi z = new Zi(); z.show(); //得zi show } }
代码:ExtendsDemo3.java
class Fu { void show() { System.out.println("fu show"); } void speak() { System.out.println("vb"); } } class Zi extends Fu { void speak() //当子类继承父类,沿袭了父类的功能到子类中,子类虽具备该功能,但功能的内容却和父类不一致。这时,没有必要定义新功能,而是使用覆盖特性,保留父类的功能定义,并重写功能内容。 { System.out.println("java"); } void show() { System.out.println("zi show"); } } class ExtendsDemo3 { public static void main(String[] args) { Zi z = new Zi(); z.show(); //得zi show z.speak(); //得java } }
//复写的特性 class Tel //老式手机只有来电功能 { void show() { System.out.println("number"); } void lingsheng() {} } //现在要给手机添加新功能,不可能去改原来的代码。 class NewTel extends Tel //父类的lingsheng可以直接拿来用,要是觉得不爽,可以复写 { void show() //将父类的show()复写(用于扩展) { //System.out.println("number"); super.show(); System.out.println("name"); System.out.println("pic"); } }
代码:ExtendsDemo3.java
/* 子父类出现后,类成员的特点: 类中成员: 1、变量 2、函数 3、构造函数 2、子父类中的函数 覆盖: 1、子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。 2、静态只能覆盖静态(这种方式一般没人拿来用)。 记住: 重载:只看同民函数的参数列表。 重写:子父类方法要一模一样。 */ class Fu { void show() { System.out.println("fu show"); } void speak() //注意: //1、前面加个private,虽然能够通过(用的是子类的show),但是不是覆盖。因为继承是子类沿袭父类功能。子类都不知道你有这功能,怎么去沿袭呀。 //2、前面加个public,又挂了,权限比子类大了 { System.out.println("vb"); } } class Zi extends Fu { void speak() { System.out.println("java"); } void show() //前面加public可以,前面加private就不可以(权限比父类小了) { System.out.println("zi show"); } } class ExtendsDemo3 { public static void main(String[] args) { Zi z = new Zi(); z.show(); z.speak(); } }
2、子父类中的构造函数
代码:ExtendsDemo4.java
/* 子父类出现后,类成员的特点: 类中成员: 1、变量 2、函数 3、构造函数 3、子父类中的构造函数 */ class Fu { Fu() { System.out.println("fu run"); } Fu(int x) //跟你没关系,都没调用到你 { System.out.println("fu..." + x); } } class Zi extends Fu { Zi() { //在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数第一行有一条隐式的语句(就是你不写虚拟机帮你加一个) //super(); //super表示父类引用 会访问父类中空参数的构造函数。而且子类中所有的构造函数默认第一行都是super(); System.out.println("zi run"); } Zi(int x) { //super(); System.out.println("zi..." + x); } } class ExtendsDemo4 { public static void main(String[] args) { Zi z = new Zi(); //得: //fu run //zi run Zi z1 = new Zi(4); //因为子类中所有的构造函数默认第一行都是super(); //得: //fu run //zi...4 } }
代码:ExtendsDemo4.java
/* 3、子父类中的构造函数 为什么子类一定要访问父类中的构造函数? */ class Fu { // Fu() // { // System.out.println("fu run"); // } Fu(int x) { System.out.println("fu run"); } } class Zi extends Fu { Zi() { //如果把父类中的Fu(){}注视掉了。就没有super();这句隐式了,要自己手动指定要访问哪个。 super(4); System.out.println("zi run"); } Zi(int x) { //super(); super(3); System.out.println("zi..." + x); } } class ExtendsDemo4 { public static void main(String[] args) { Zi z = new Zi(); Zi z1 = new Zi(4); /*得 fu run zi run fu run zi...4 */ } }
代码:ExtendsDemo.java
/* 3、子父类中的构造函数 为什么子类一定要访问父类中的构造函数: 因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要查看父类是如何对这些数据进行初始化的。 所以子类在对象初始化时,要先访问一下父类中的构造函数。 如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。 */ class Fu { int num = 2; //如果这里不初始化 2 Fu() // { // //如果父类这里初始化了 num = 60(z.num得60); 子类是不是要来看参考哈父类初始化的值呀,不然子类再定义个num = 60;就重复了 System.out.println("fu run"); } Fu(int x) { System.out.println("fu..." + x); } } class Zi extends Fu { Zi() { //super(); //super(4); System.out.println("zi run"); } Zi(int x) { //super(); //super(3); System.out.println("zi..." + x); } } class ExtendsDemo4 { public static void main(String[] args) { Zi z = new Zi(); System.out.println(z.num); /*得 fu run zi run 2 */ } } /* class Person { private String name; Person(String name) { this.name = name; } void show(){} } class Student extends Person //父类中定义了功能,子类直接拿来用就是了,没有必要重新定义。 { Student(String name) { super(name); //调用构造函数,用super() } void method() { super.show(); //调用一般函数,用super. } } */
代码:ExtendsDemo4.java
/* 3、子父类中的构造函数 注意: super(或者this)语句一定定义在子类构造函数的第一行。(因为初始化要先做) 结论: 子类的所有的构造函数,默认都会访问父类中空参数的构造函数。 因为子类每一个构造函数内的第一行都有一句隐式super(); 当父类中没有空参数的构造函数时,子类必须通过super语句形式来指定要访问的构造函数。 当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。 子类中至少会有一个构造函数会访问父类中的构造函数。 */ class Fu //extends Object (java中所有类的父类) { int num = 2; Fu() { //super(); //父类中也有隐式的super();语句 num = 60; System.out.println("fu run"); } Fu(int x) { System.out.println("fu..." + x); } } class Zi extends Fu { Zi() { //这里不能写this(); 不然就转圈了(递归了)。子类中至少一个函数要去访问父类。 //super(); super(4); System.out.println("zi run"); } Zi(int x) { this(); //构造函数要么有this(),要么有super(); 访问到this时,就去Zi,里面有super(),就可以访问父类了 //super(); //super(3); System.out.println("zi..." + x); } } class ExtendsDemo4 { public static void main(String[] args) { Zi z = new Zi(0); System.out.println(z.num); /*得 fu...4 zi run zi...0 2 */ } }
3、final
代码:finalDemo.java
/* final:最终。最为一个修饰符, 1、可以修饰类,函数,变量。 2、被final修饰的类不可以被继承,为了避免被继承,被子类复写功能。 3、被final修饰的方法不可以被复写。 4、被final修饰的变量是常量,只能赋值一次,既可以修饰成员变量,也可以修饰局部变量。 当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字。方便于阅读。 而这个值不需要改变,所以加上final修饰。作为常量:常量的书写规范所有字母都大写,如果由多个单词组成。 单词间通过_连接。 5、内部类定义在类中的局部位置上是,只能访问该局部被final修饰的局部变量。(知道就行) */ class Demo //类有两个修饰符:public 和 final { final int x = 3; //这x就终身为3了 public static final double PI = 3.14; //大写 但凡遇到一个数字(常量),哪怕只用一次,都起个名字,方便阅读。加个static,不变了,共享。public static final全局常量 final void show1() {} void show2() { final int y = 4; //y就终身为4,它只要在内存中,就为4 //y = 9; 无法为最终变量分配值 System.out.println(PI); } } class SubDemo extends Demo { //void show1(){} //SubDemo中的show1()无法覆盖Demo中的show1() } class FinalDemo { public static void main(String[] args) { SubDemo sub = new SubDemo(); sub.show2(); //得3.14 } }
4、抽象类
代码:AbstractDemo.java
/* 当多个类中出现相同功能,但是功能主体不同,这时也可以进行向上抽取。这时,只抽取功能定义,而不抽取功能主体。 抽象:看不懂。 抽象类的特点: 1,抽象方法一定在抽象类中。 2,抽象方法和抽象类都必须被abstract关键字修饰。 3,抽象类不可以用new创建对象。因为调用抽象方法没意义。 4,抽象类中的抽象方法要被使用,必须由子类复写其所有的抽象方法后,建立子类对象调用。如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。 */ abstract class Student { //void study(){} abstract void study(); //没有方法体,对于这种看不懂的方法,要用abstract关键字修饰 //作为类的成员存在,这个方法没主体,调用它没意义,所以类也要抽象 abstract void study1(); } class BaseStudent extends Student { void study() { System.out.println("base study"); } void study1(){} } class AdvStudent extends Student { void study() { System.out.println("adv study"); } void study1(){} } class AbstractDemo { public static void main(String[] args) { //new Student(); //抽象类不可以用new创建对象。因为调用抽象方法没意义。 new BaseStudent().study(); } }
代码:AbstractDemo.java
/* 抽象类和一般类没有太大的不同。 该如何描述事物,就如何描述事物,只不过,该事物出现了一些看不懂的东西。 这些不确定的部分,也是该事物的功能,需要明确出现。但是无法定义主体。 通过抽象方法来表示。 抽象类比一般类多个了抽象函数。就是在类中可以定义抽象方法。 抽象类不可以实例化。 特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。 */ abstract class Student { abstract void study(); //学习这个功能是存在的,但是具体实现不一样,所以无法定义主体。 void sleep() { System.out.println("躺着"); } } class ChongCiStudent extends Student { void study() { System.out.println("chonqci study"); } } class BaseStudent extends Student { void study() { System.out.println("base study"); } } class AdvStudent extends Student { void study() { System.out.println("adv study"); } } class AbstractDemo { public static void main(String[] args) { } }
代码:AbstractTest.java
/* 假如我们在开发一个系统时需要对员工进行建模,员工包含 3 个属性: 姓名、工号以及工资。经理也是员工,除了含有员工的属性外,另为还有一个 奖金属性。请使用继承的思想设计出员工类和经理类。要求类中提供必要的方 法进行属性访问。 员工类: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"); } } class AbstractTest { public static void main(String[] args) { } }
练习:
abstract 关键字,和哪些关键字不能共存。
final:被final修饰的类不能有子类。而被abstract修饰的类一定是一个父类。
private: 抽象类中的私有的抽象方法,不被子类所知,就无法被复写。
而抽象方法出现的就是需要被复写。
static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。
可是抽象方法运行没意义。
抽象类中是否有构造函数?
有,抽象类是一个父类,要给子类提供实例的初始化。
代码:TemplateDemo.java
/* 需求:获取一段程序运行的时间。 原理:获取程序开始和结束的时间并相减即可。 获取时间:System.currentTimeMillis(); */ class GetTime { public void getTime() { long start = System.currentTimeMillis(); for(int x = 0; x < 1000; x++) { System.out.println(x); } long end = System.currentTimeMillis(); System.out.println("毫秒:" + (end - start)); } } class TemplateDemo { public static void main(String[] args) { GetTime gt = new GetTime(); gt.getTime(); //得从0到999循环完后,得程序运行时间 } }
代码:TemplateDemo.java
class GetTime { public void getTime() { long start = System.currentTimeMillis(); runcode(); long end = System.currentTimeMillis(); System.out.println("毫秒:" + (end - start)); } public void runcode() { for(int x = 0; x < 1000; x++) { System.out.println(x); } } } class SubTime extends GetTime { public void runcode() //把父类的覆盖掉了 { for(int x = 0; x < 4000; x++) { System.out.println(x); } } } class TemplateDemo { public static void main(String[] args) { //GetTime gt = new GetTime(); SubTime gt = new SubTime(); gt.getTime(); //得从0到3999循环完后,得程序运行时间 } }
代码:TemplateDemo.java
/* 当代码完成优化后,就可以解决这类问题。 这种方式叫做模版方法设计模式。 什么是模版方法呢: 在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分, 那么这时就将不确定的部分暴露出去。由该类的子类去完成。 就像坐蛋糕的模子,确定了。但是馅不确定,里面可以放面粉,鸡蛋,地瓜... */ abstract class GetTime { public final void getTime() //加个final,这个就不让你复写了 { long start = System.currentTimeMillis(); runcode(); long end = System.currentTimeMillis(); System.out.println("毫秒:" + (end - start)); } public abstract void runcode(); //抽象方法 } class SubTime extends GetTime { public void runcode() { for(int x = 0; x < 4000; x++) { System.out.println(x); } } } class TemplateDemo { public static void main(String[] args) { SubTime gt = new SubTime(); gt.getTime(); //得从0到3999循环完后,得程序运行时间 } }
二、接口
1、代码:InterfaceDemo.java
/* 接口:初期理解,可以认为是一个特殊的抽象类。当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。 class用于定义类 interface 用于定义接口。 接口定义时,格式特点: 1,接口中常见定义:常量,抽象方法。 2,接口中的成员都有固定修饰符。 常量:public static final;方法:public abstract 记住:接口中的成员都是public的。 接口:是不可以创建对象的,因为有抽象方法。 需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化。 否则子类是一个抽象类。 */ interface Inter { public static final int NUM = 3; //常量:public static final,忘了写前面的三个修饰符,它会给你自动补上 public abstract void show(); //方法:public abstract,忘了前面的两个修饰符,它会给你自动补上 } class Test implements Inter //关键字implements(实现) { public void show(){} //覆盖 } class InterfaceDemo { public static void main(String[] args) { Test t = new Test(); System.out.println(t.NUM); //得3 System.out.println(Test.NUM); //得3 System.out.println(Inter.NUM); //得3 } }
代码:InterfaceDemo.java
/* 接口可以被类多实现,也是对多继承不支持的转换形式。java支持多实现。 */ interface Inter { public static final int NUM = 3; public abstract void show(); } interface InterA { public abstract void show(); } class Demo { public void function(){} } class Test extends Demo implements Inter, InterA { public void show(){} } //接口和接口之间也有关系 interface A { void methodA(); } interface B //extends A { void methodB(); } interface C extends B, A //如果B没有继承A,C就就可以继承A和B(接口可以多继承,因为没有方法体,随便用) { void methodC(); } class D implements C { public void methodA(){} public void methodB(){} public void methodC(){} } class InterfaceDemo { public static void main(String[] args) { Test t = new Test(); System.out.println(t.NUM); System.out.println(Test.NUM); System.out.println(Inter.NUM); } }
2、接口的特点
代码:InterfaceTest.java
/* abstract class Student { abstract void study(); //每个人学习的方式不确定,加个abstract void sleep() { System.out.println("sleep"); } } interface Smoking { void smoke(); } class ZhangSan extends Student implements Smoking //Smoking不是每个学生都有的 { void study(){} public void smoke(){} } class LiSi extends Student { } //基本功能在类中,扩展功能在接口中。 abstract class Sporter { abstract void play(); } interface Study { } class WangWu extends Sport implements Study { } */ class InterfaceTest { public static void main(String[] args) { } }
三、多态
1、代码DuoTaiDemo.java
/* 多态:可以理解为事物存在的多种体现形态。 人:男人,女人 动物:猫,狗。 猫 x = new 猫(); 动物 x = new 猫(); 1,多态的体现 父类的引用指向了自己的子类对象。 父类的引用也可以接收自己的子类对象。 2,多态的前提 必须是类与类之间有关系。要么继承,要么实现。 通常还有一个前提:存在覆盖。 3,多态的好处 多态的出现大大的提高程序的扩展性。 4,多态的弊端: 提高了扩展性,但是只能使用父类的引用访问父类中的成员。 5,多态的应用 */ /* 动物, 猫,狗。 */ abstract class Animal { abstract void eat(); } class Cat extends Animal { public void eat() { System.out.println("吃鱼"); } public void catchMouse() { System.out.println("抓老鼠"); } } class Dog extends Animal { public void eat() { System.out.println("吃骨头"); } public void kanJia() { System.out.println("看家"); } } class Pig extends Animal { public void eat() { System.out.println("饲料"); } public void gongDi() { System.out.println("拱地"); } } //----------------------------------------- class DuoTaiDemo { public static void main(String[] args) { //Cat c = new Cat(); //c.eat(); //Dog d = new Dog(); //d.eat(); //Cat c = new Cat(); /* Cat c1 = new Cat(); function(c1); function(new Dog()); function(new Pig()); */ //Animal c = new Cat(); //c.eat(); function(new Cat()); function(new Dog()); function(new Pig()); } public static void function(Animal a)//Animal a = new Cat(); { a.eat(); //a.catchMouse(); } /* public static void function(Cat c)// { c.eat(); } public static void function(Dog d) { d.eat(); } public static void function(Pig p) { p.eat(); } */ }