-------android培训、java培训、期待与您交流! ----------
一 继承extends
(1)继承的概述
把很多类的相同特征和行为进行抽取,用一个类来描述。让多个类和这个类产生一个关系。
这样的话,多个类就可以省略很多代码。这个关系就是继承。java中用extends关键字表示。
多个类可以称为子类,单独这个类称为父类或者超类。
子类可以直接访问父类中的非私有的属性和行为。
class Person
{
String name;
int age;
}
class Student extends Person
{
void study()
{
System.out.println("good study");
}
}
class Worker extends Person
{
void work()
{
System.out.println("good work");
}
}
class ExtendsDemo
{
public static void main(String[] args)
{
Student s = new Student();
s.name = "zhagnsan";
}
}
(2)继承的体系结构
A:多个具体的对象,不断的向上抽取共享的内容,最终形成了一个体系。这个体系叫做继承体系。
B:继承体系的学习和使用原则
**学习顶层的内容。因为他是整个体系的共性内容。
**创建子类使用。也就是使用底层的具体对象。
(3)继承的特点:
A:java中只能单继承,没有多继承。
一个类只能有一个父类,不可以有多个父类。
class SubDemo extends Demo{} //ok
class SubDemo extends Demo1,Demo2...//error
B:java可以有多重(层)继承。
class A{}
class B extends A{}
class C extends B{}
定义继承需要注意:
不要仅为了获取其他类中某个功能而去继承
类与类之间要有所属( " is a " )关系,xx1是xx2的一种。
(4)继承的好处:
继承的出现提高了代码的复用性。
继承的出现让类与类之间产生了关系,提供了多态的前提。
(5)super关键字
super和this的用法相像
this代表本类对象的引用
super代表父类的内存空间的标识。
当子父类出现同名成员时,可以用super进行区分
子类要调用父类构造函数时,可以使用super语句。
this和super的区别
super的使用和this的使用几乎一致。
this:代表本类对象的引用。如果子类中出现非私有的同名变量时,子类要访问本类中的变量用this
super:代表父类的存储空间。如果子类中出现非私有的同名变量时,子类要访问父类中的同名变量用super
(6)函数覆盖(Override)
子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为重写或者复写。
父类中的私有方法不可以被覆盖。
在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取。
重写和重载的区别
重载:在同一类中。方法名相同,参数列表不同。重载可以改变返回类型。
重写:在不同类中(子父类中)。
方法声明相同(返回类型,方法名,参数列表均相同)。
重写需要注意:
**子类方法的访问权限要大于等于父类方法的访问权限。
**静态只能重写静态。但是这种情况一般不会出现。
记住大家:
重载:只看同名函数的参数列表(参数个数和参数类型)。
重写:子父类方法要一模一样。
覆盖的应用:
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,
即沿袭了父类的功能,又定义了子类特有的内容
(7)子父类中的成员(变量,函数,构造函数)特点
1)变量
如果子类中出现非私有的同名成员变量时,
子类要访问本类中的变量,用this
子类要访问父类中的同名变量,用super。
class Fu
{
private int num = 4;
}
class Zi extends Fu
{
int num = 5;
void show()
{
System.out.println(super.num);//输出结果为4
System.out.println(this.num);//输出结果为5
}
}
class ExtendsDemo2
{
public static void main(String[] args)
{
Zi z = new Zi();
z.show();
}
}
2)函数
当子类出现和父类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容。
如同父类的函数被覆盖一样。
这种情况是函数的另一个特性:重写(覆盖)
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
}
}
当子类继承父类,沿袭了父类的功能,到子类中,
但是子类虽具备该功能,但是功能的内容却和父类不一致,
这时,没有必要定义新功能,而是使用覆盖特殊,保留父类的功能定义,并重写功能内容。
可以升级程序
class Tel
{
void show()
{
System.out.println("number");
}
}
class NewTel extends Tel
{
void show()
{
super.show();//在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取。
System.out.println("name");
System.out.println("pic");
}
}
3)构造函数
在对子类对象进行初始化时,父类的构造函数也会运行,
那是因为子类的构造函数默认第一行有一条隐式的语句 super();
super():会访问父类中空参数的构造函数。而且子类中所有的构造函数默认第一行都是super();
class Fu
{
Fu()
{
System.out.println("fu run");
}
}
class Zi extends Fu
{
Zi()
{
//super(); //子类的构造函数默认第一行有一条隐式的语句 super();
System.out.println("zi run");
}
}
class ExtendsDemo4
{
public static void main(String[] args)
{
Zi z = new Zi(0);//结果为fu run zi run
}
}
为什么子类一定要访问父类中的构造函数。
因为父类中的数据子类可以直接获取。所以子类对象在建立时,需要先查看父类是如何对这些数据进行始化的。
所以子类在对象初始化时,要先访问一下父类中的构造函数。如果要访问父类中指定的构造函数,
可以通过手动定义super语句的方式来指定。
注意:super语句一定定义在子类构造函数的第一行。
class Fu
{
Fu(int x)
{
System.out.println("fu ...."+x);
}
}
class Zi extends Fu
{
Zi()
{
super(4);
System.out.println("zi run");
}
Zi(int x)
{
this();//子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数,当this放在第一行 //的时候就没有隐式的super(),因为两者都是在第一行
System.out.println("zi..."+x);
}
}
class ExtendsDemo4
{
public static void main(String[] args)
{
Zi z = new Zi(0);
}
}
(8)子类的实例化过程
子类的所有的构造函数,默认都会访问父类中空参数的构造函数。因为子类每一个构造函数内的第一行都有一句隐式super();当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数。
**子类的实例化过程
***子类创建对象时,会先去创建父类的对象。默认是去调用父类的无参构造方法。
***子类构造方法中,第一行默认是super()
***为什么子类中第一行会默认有super()
因为他继承父类的成员使用,使用前这些成员必须初始化,而他们是父类的成员,所以必须通过父类进行初始化。所以,会先创建一个父类的对象。
**当父类没有无参构造方法时必须使用this或者super调用其他的构造方法。
**为什么this和super只能出现一个,因为都写第一行
**为什么都写第一行,因为初始化动作要先做
class Person
{
private String name;
Person(String name)
{
this.name = name;
}
void show(){}
}
class Student extends Person
{
Student(String name)
{
super(name);
}
void method()
{
super.show();
}
}
二 final关键字
(1)最终的意思,可以用于修饰类,方法,变量。
(2)final修饰的类不能被继承。
final修饰的方法不能被重写。
final修饰的变量是一个常量。只能被赋值一次。
内部类只能访问被final修饰的局部变量。
/*
final : 最终。作为一个修饰符,
1,可以修饰类,函数,变量。
2,被final修饰的类不可以被继承。为了避免被继承,被子类复写功能。
3,被final修饰的方法不可以被复写。
4,被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,又可以修饰局部变量。
当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字。方便于阅读。
而这个值不需要改变,所以加上final修饰。作为常量:常量的书写规范所有字母都大写,如果由多个单词组成。
单词间通过_连接。
5,内部类定义在类中的局部位置上是,只能访问该局部被final修饰的局部变量。
*/
class Demo
{
final int x = 3;
public static final double PI = 3.14;
final void show1(){}
void show2()
{
final int y = 4;
System.out.println(3.14);
}
}
class SubDemo extends Demo
{
void show2(){}
}
class FinalDemo
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
三 抽象类abstract
(1)定义
多个类有相同的方法声明,但是方法体不一样。这个时候,我们考虑把方法声明进行抽取。只抽取功能定义,不 抽取功能主体。让子类继承后,
自己去实现方法体。没有方法体的方法,我们需要用抽象标志一下。
抽象的关键字是:abstract。
(2)抽象方法:
该方法称为抽象方法,包含抽象方法的类就是抽象类。
格式:修饰符 abstract 返回值类型 函数名(参数列表)
(3)抽象类的特点:
A:抽象类和抽象方法都要用abstract进行修饰
B:抽象类不能被实例化,也就是不可以用new创建对象,
因为抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。例如:犬科是一个抽象的概念, 真正存在的是狼和狗。而且抽象类即使创建了对象,调用抽象方法也没有意义。
C:抽象类中不一定有抽象方法,但是,有抽象方法的类一定是抽象类。
D:抽象类中的抽象方法要被使用,必须由子类复写其所有的抽象方法后,建立子类对象调用。如果子类只覆 盖了部分抽象方法,那么该该子类也是抽象类。
(4)抽象类中数据的特点
A:成员变量
抽象类中可以有变量,也可以有常量。
B:成员方法
抽象类中可以有抽象方法,也可以有非抽象方法。
C:构造方法
抽象类是一个类,所以,它有构造方法。
虽然本身不能实例化。但是可以给子类实例化使用。
(5)抽象类中的问题
A:抽象类中是否有构造方法?能不能被实例化?如果不能,为什么有构造方法?
抽象类有构造方法。
抽象类不能被实例化。
抽象类中的构造方法供子类实例化调用。
B:抽象关键字abstract不可以和哪些关键字共存?
**private:
私有内容子类继承不到,所以,不能重写。
但是abstract修饰的方法,要求被重写。两者冲突。
**final
final修饰的方法不能被重写。
而abstract修饰的方法,要求被重写。两者冲突。
**static
假如一个抽象方法能通过static修饰,那么这个方法,就可以直接通过类名调用。
而抽象方法是没有方法体的,这样的调用无意义。所以,不能用static修饰。
C:抽象类中可不可以没有抽象方法?如果可以,这样的类有什么用吗?
抽象类可以没有抽象方法。
抽象类中没有抽象方法的作用,只是为了不让别的类建立该抽象类对象。这个在awt中有体现。
/*
抽象:看不懂。
抽象类和一般类没有太大的不同。
该如何描述事物,就如何描述事物,只不过,该事物出现了一些看不懂的东西。
这些不确定的部分,也是该事物的功能,需要明确出现。但是无法定义主体。
通过抽象方法来表示。
抽象类比一般类多个了抽象函数。就是在类中可以定义抽象方法。
抽象类不可以实例化。
特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。
*/
abstract class Student
{
abstract final void study();
void sleep()
{
System.out.println("躺着");
}
}
class ChongCiStudent extends Student
{
void study()
{
System.out.println("chongci 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)
{
new BaseStudent().study();
}
}
/*
假如我们在开发一个系统时需要对员工进行建模,员工包含 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 AbstractDemo
{
public static void main(String[] args)
{
Manager ma = new Manger("wz","02",30000,4000);
ma.work();
}
}
四 模板设计模式(Abstract final extends 综合练习)
在定义功能时,功能的一部分是确定的,有一部分是不确定的,而且确定的部分在使用不确定的部分,
可将不确定的部分暴露出去,由该类的子类去完成。
如:求一段程序的运行时间例子。
/*
需求:获取一段程序运行的时间。
原理:获取程序开始和结束的时间并相减即可。
获取时间:System.currentTimeMillis();
当代码完成优化后,就可以解决这类问题。
这种方式,模版方法设计模式。
什么是模版方法呢?
在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分,
那么这时就将不确定的部分暴露出去。由该类的子类去完成。
*/
abstract class GetTime
{
public final void getTime()
{
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.print(x);
}
}
}
class TemplateDemo
{
public static void main(String[] args)
{
//GetTime gt = new GetTime();//抽象类不可以new对象
SubTime gt = new SubTime();
gt.getTime();
}
}
五 接口interface
(1)当一个类中的方法都是抽象的时候,java提供了另一种表示方式,叫接口。用interface关键字表示。类与接口关系用implements表示。
(2)接口的成员特点
接口中的成员都是public的
A:成员变量
是常量,默认修饰 public static final
B:成员方法
都是抽象的,默认修饰 public abstract
(3)关系
A:类与类的关系
是继承关系。类与类只能单继承,可以多重继承。
B:类和接口的关系
是实现关系。类可以多实现接口。
类在继承一个类的同时,可以实现多个接口。
C:接口和接口的关系
是继承关系。接口可以多继承接口。
(4)接口的特点
A:是对外暴露的规则
B:是功能的扩展
C:接口的出现降低耦合性。
耦合(类与类之间的关系)
内聚(类完成功能的能力)
编程规范:低耦合,高内聚。
D:接口可以多实现。如:CPU和主板、笔记本的USB插口、插座
E:接口是不可以创建对象的,因为有抽象方法。需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化。否则子类是一个抽象类。
(5)接口和抽象类的区别
A:抽象类只能被单继承
接口可以多实现,接口的出现避免了多继承的局限性。
B:抽象类中的数据特点:
成员变量:可以是变量,也可以是常量
成员方法:可以是抽象方法,也可以是非抽象方法
构造方法:有构造方法
接口中的数据特点:
成员变量:是常量。默认修饰 public static final
成员方法:都是抽象方法。都有默认修饰 public abstract
构造方法:没有构造方法
C:抽象类中定义的是继承体系中的共性功能。
接口中定义的是继承体系中的扩展功能。
D:抽象类被继承是"is a"关系:xx是yy的一种
接口被实现是"like a"关系:xx像yy的一种
/*
接口:初期理解,可以认为是一个特殊的抽象类
当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。
class用于定义类
interface 用于定义接口。
接口:是不可以创建对象的,因为有抽象方法。
需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化。
否则子类是一个抽象类。
*/
//一个类可以实现多个接口
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(){}
}
//java中接口与接口可以多继承
interface A
{
void methodA();
}
interface B //extends A
{
void methodB();
}
interface C extends B,A
{
void methodC();
}
class D implements C
{
public void methodA(){}
public void methodC(){}
public void methodB(){}
}
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);
}
}
//接口练习
abstract class Student
{
abstract void study();
void sleep()
{
System.out.println("sleep");
}
}
interface Smoking
{
void smoke();
}
class ZhangSan extends Student implements Smoking
{
void study(){}
public void smoke(){}
}
class InterfaceTest
{
public static void main(String[] args)
{
ZhangSan zs = new ZhangSan();
zs.study();
zs.smoke();
zs.sleep();
}
}
六 多态
(1)定义:某一类事物的多种存在形态。
例:动物中猫,狗。
猫这个对象对应的类型是猫类型
猫 x = new 猫();
同时猫也是动物中的一种,也可以把猫称为动物。
动物 y = new 猫();
动物是猫和狗具体事物中抽取出来的父类型。
父类型引用指向了子类对象。
(2)多态前提
A:必须存在着类与类之间的关系,要么继承要么实现
B:有方法的重写
C:父类(接口)引用指向子类(实现)对象
(3)多态的好处和弊端:
好处:多态的存在提高了程序的扩展性和后期可维护性
弊端:虽然提高了扩展性,但是只能使用父类的引用访问父类中的成员
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());
//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();
}
/*
public static void function(Cat c)//Cat c=new Cat();
{
c.eat();
}
public static void function(Dog d)
{
d.eat();
}
public static void function(Pig p)
{
p.eat();
}
*/
}
吃鱼
吃骨头
吃猪食
(4)多态的转型
/*
第二个问题:如何使用子类特有方法。
*/
/*
动物,
猫,狗。
*/
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 DuoTaiDemo2
{
public static void main(String[] args)
{
/*
Animal a = new Cat();//类型提升。 向上转型。
a.eat();
如果想要调用猫的特有方法时,如何操作?
强制将父类的引用。转成子类类型。向下转型。
Cat c = (Cat)a;
c.catchMouse();
千万不要出现这样的操作,就是将父类对象转成子类类型。
我们能转换的是父类的引用指向了自己的子类对象时,该应用可以被提升,也可以被强制转换。多态自始至终都是子类对象在做着变化。即
Animal a = new Animal();
Cat c = (Cat)a;
例如:
毕姥爷 x = new 毕老师();//类型提升,向上转型
x.讲课();
毕老师 y = (毕老师)x;//强制转化,向下转型
y.看电影();
*/
function(new Dog());
function(new Cat());
}
public static void function(Animal a)//Animal a = new Cat();//向上转型
{
a.eat();
if(a instanceof Cat)
{
Cat c = (Cat)a;//向下转型
c.catchMouse();
}
else if(a instanceof Dog)
{
Dog c = (Dog)a;
c.kanJia();
}
/*
instanceof : 用于判断对象的类型。 格式:对象名 instanceof 子类(实现)名
*/
}
}
(5)多态中对象调用成员的特点
Fu f = new Zi();
A:成员变量
编译看左边,运行看左边
B:成员方法
编译看左边,运行看右边
C:静态方法
编译看左边,运行看左边
(6)多态的思想
指挥同一批对象做事情。举例:带兵打仗,下课等。
(7)多态的应用
/*
基础班学生:
学习,睡觉。
高级班学生:
学习,睡觉。
可以将这两类事物进行抽取。
*/
abstract class Student
{
public abstract void study();
public void sleep()
{
System.out.println("躺着睡");
}
}
class DoStudent//工具类
{
public void doSome(Student stu)//Student stu = new BaseStudent();
{
stu.study();
stu.sleep();
}
}
class BaseStudent extends Student
{
public void study()
{
System.out.println("base study");
}
public void sleep()
{
System.out.println("坐着睡");
}
}
class AdvStudent extends Student
{
public void study()
{
System.out.println(" adv study");
}
}
class DuoTaiDemo3
{
public static void main(String[] args)
{
DoStudent ds = new DoStudent();
ds.doSome(new BaseStudent());//Student stu = new BaseStudent();
ds.doSome(new AdvStudent());
}
}
/*
如果不要工具类,则这样写代码
class DuoTaiDemo3
{
public static void main(String[] args)
{
ds.doSome(new BaseStudent());
ds.doSome(new AdvStudent());
}
public void doSome(Student stu)//Student stu = new BaseStudent();
{
stu.study();
stu.sleep();
}
}
*/
/*
需求:
电脑运行实例,
电脑运行基于主板。
*/
interface PCI
{
public void open();
public void close();
}
class MainBoard//工具类
{
public void run()
{
System.out.println("mainboard run ");
}
public void usePCI(PCI p)//PCI p = new NetCard()//接口型引用指向自己的子类对象。
{
if(p!=null)
{
p.open();
p.close();
}
}
}
class NetCard implements PCI
{
public void open()
{
System.out.println("netcard open");
}
public void close()
{
System.out.println("netcard close");
method();
}
}
class SoundCard implements PCI
{
public void open()
{
System.out.println("SoundCard open");
}
public void close()
{
System.out.println("SoundCard close");
}
}
class DuoTaiDemo5
{
public static void main(String[] args)
{
MainBoard mb = new MainBoard();
mb.run();
mb.usePCI(null);
mb.usePCI(new NetCard());
mb.usePCI(new SoundCard());
}
}
/*
需求:数据库的操作。
数据是:用户信息。
1,连接数据库。JDBC Hibernate
2,操作数据库。
c create r read u update d delete
3,关闭数据库连接。
*/
interface UserInfoDao
{
public void add(User user);
public void delete(User user);
}
class UserInfoByJDBC implements UserInofDao
{
public void add(User user)
{
1,JDBC连接数据库。;
2,使用sql添加语句添加数据。;
3,关闭连接。
}
public void delete(User user)
{
1,JDBC连接数据库。;
2,使用sql添加语句删除数据。;
3,关闭连接。
}
}
class UserInfoByHibernate implements UserInfoDao
{
public void add(User user)
{
1,Hibernate连接数据库。;
2,使用sql添加语句添加数据。;
3,关闭连接。
}
public void delete(User user)
{
1,Hibernate连接数据库。;
2,使用sql添加语句删除数据。;
3,关闭连接。
}
}
class DBOperate
{
public static void main(String[] args)
{
UserInfoDao ui = new UserInfoByHibernate();//父类的引用指向子类对象
ui.add(user);
ui.delete(user);
}
}