------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
Java基础:面向对象
一、继承
1).定义:抽取一些类的共性内容,封装在一个类中,称为父类。一些类可以继承父类,通过继承原则,拥有父类中一切。
2).好处:
A.继承的出现,提高了代码的复用性;
B.继承的出现,让类与类之间产生关系,通过extends连接。
3).特点:
A.Java只支持单继承;
B.Java支持多层继承,形成一个继承体系(父类--子类--子子类).我们可以查阅父类功能,创建子类对象使用功能
二、子父类中的成员特点
1).成员变量:super() 引用
class Fu{
int num=3;
}
class Zi extends Fu{
int num =4;
void show(){
//当局部变量和成员变量重名的时候用this来区分
System.out.println("Zi num="+this.num);//this调用本类中的num
System.out.println("Fu num="+super.num);//super调用父类中的num
}
}
class ExtendsDemo2{
public static void main(String[] args){
Zi z = new Zi();
z.show();
}
}
/*
如果子类中出现非私有的同名变量时,
子类要访问本类中的变量时用this,
子类要访问父类中的变量时用super
this代表本类对象的引用,谁调用本类,this就指向谁。
super代表父类对象的引用。
两者用法几乎一致。
*/
2).成员方法(函数)
class Fu1
{
int num=3;
void show()
{
System.out.println("fu show");
}
}
class Zi2 extends Fu1
{
void show()
{
System.out.println("zi show");
System.out.println("子类中重写父类的show方法");
}
/*int show(){ //不允许存在这种返回值类型不同的重写,因为本类继承了父类的方法,无法存在同名同参,不同返回值的函数。
System.out.println();
return 1;
} */
}
class ExtendsDemo3
{
public static void main(String[] args)
{
Zi2 z = new Zi2();
z.show();
}
}
/*
重写定义:
当子类中出现和父类一模一样(函数名、参数列表、返回值)的函数时,
当子类调用此函数时,会执行子类函数的内容,如同父类的函数被覆盖了一样,不会执行父类中的函数。
这种情况是函数的另一种特性:重写(覆盖)
重写意义:
当子类继承了父类,子类发现父类的方法体不再适用时,可以将父类的这个方法,保留方法名,修改方法体。
此时,父类的方法就得到了拓展,子类可以有自己的独特方法。
注意事项:
1、子类覆盖父类,必须保证子类权限大于或等于父类权限,才可以覆盖,否则编译失败。
2、静态只能覆盖静态,不能覆盖非静态。
3、父类中被重写的方法,不能私有化,否则也不算重写。只能算是子类的新定义。
补充:权限大小:public > protected > private
*/
3).子父类中的构造(方法)函数
class Fu3
{
int num ;
Fu3()
{
num = 90;
System.out.println("Fu run");
}
Fu3(int x)
{
System.out.println("Fu run 有参构造");
}
}
class Zi3 extends Fu3
{
Zi3()
{
//super();
//super(3); 当父类中没有空参构造函数,只有有参的构造函数时,必须手动定义有参函数。
System.out.println("Zi run 空参构造");
}
Zi3(int x)
{
//super(); 有参构造函数中也有super();
//super(3); 当父类中没有空参构造函数,只有有参的构造函数时,必须手动定义有参函数。
System.out.println("zi run 有参构造");
}
}
class ExtendsDemo4
{
public static void main(String[] args)
{
Zi3 z = new Zi3();
/*运行结果:
Fu run + num90
Zi run
可知:此语句第一运行了隐藏的super().输出了父类空参构造函数的语句
第二运行了子类中的空参构造函数
*/
new Zi3(3);
/*运行结果:
Fu run + num90
Zi run 有参构造
可知:此语句第一运行了隐藏的super().输出了父类空参构造函数的语句
第二运行了子类中的有参构造函数。
*/
}
}
/*
3:子父类中的构造函数
在对子类对象进行初始化时,父类的构造函数也会运行。
原因:
子类构造函数默认第一行有一条隐式的语句是:super();
super();会访问父类中的空参构造函数,
并且子类中所有构造函数默认第一行都是super();
注意:
子类的实例化过程:
总结:
当父类中没有空参数构造函数,子类必须手动通过super或者this语句来形式来指定要访问父类中的构造函数
当然,子类的构造函数第一行手动指定this语句来访问本类中的构造函数。
子类中至少会有一个构造函数会访问父类中的构造函数
应用:
class person{
private String name;
person(name){
this.name = name;
}
void show(){
}
}
class student extends person{
student(String name){
super(name); //将name值赋给父类中的有参构造函数,完成name赋值。无需自己动手,直接交给父类完成。
}
void method(){
super.show();
}
}
*/
final 最终。
1、作为一个修饰符,可以修饰类、函数、变量。
2、被final修饰的类,不能继承;(为了避免被继承,防止子类复习功能)
3、被final修饰的方法,不能被复写;
4、被final修饰的常量,只能赋值一次。既可以修饰成员变量,也可以修饰局部变量;
当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字,方便阅读。
而这个值不需要改变,所以加上final修饰。
常量的书写规范:所有字母都要大写。由多个单词组成,单词间通过下划线 _ 连接
权限最大,可通过类名直接调用,无法被赋值,全局变量
5、内部类定义在类中的局部位置撒上时,只能访问该局部被final修饰的局部变量。
1、作为一个修饰符,可以修饰类、函数、变量。
2、被final修饰的类,不能继承;(为了避免被继承,防止子类复习功能)
3、被final修饰的方法,不能被复写;
4、被final修饰的常量,只能赋值一次。既可以修饰成员变量,也可以修饰局部变量;
当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字,方便阅读。
而这个值不需要改变,所以加上final修饰。
常量的书写规范:所有字母都要大写。由多个单词组成,单词间通过下划线 _ 连接
public static final double MY_PI = 3.14;
权限最大,可通过类名直接调用,无法被赋值,全局变量
5、内部类定义在类中的局部位置撒上时,只能访问该局部被final修饰的局部变量。
四、抽象类
abstract
用处:当多个类中出现相同功能,但是功能主体不同时,也可以向上抽取。
这时,我们只抽取功能定义,不抽取功能主体。
用处:当多个类中出现相同功能,但是功能主体不同时,也可以向上抽取。
这时,我们只抽取功能定义,不抽取功能主体。
抽象类的特点:
1、抽象方法一定存放于抽象类中
2、抽象方法和抽象类都必须被abstract关键字修饰
3、抽象类不可用new创建对象,因为调用抽象方法没有意义
4、抽象类中的抽象方法要被使用,必须由子类复写其所有抽象方法后,建立子类对象调用。
如果子类只覆盖部分抽象方法,该子类还是一个抽象类。
1、抽象方法一定存放于抽象类中
2、抽象方法和抽象类都必须被abstract关键字修饰
3、抽象类不可用new创建对象,因为调用抽象方法没有意义
4、抽象类中的抽象方法要被使用,必须由子类复写其所有抽象方法后,建立子类对象调用。
如果子类只覆盖部分抽象方法,该子类还是一个抽象类。
abstract class study{
//void study(){system.out.println("study");};
//由于BaseStudent和AdvStudent都重写了父类study的方法,但是由于各自功能主体的不同,继承这个方法多余。
//所以,我们这样做:
abstract void study(); //抽象方法,必须存放在抽象类中,于是class前必须添加abstract
abstract void study1(); //如果此抽象类中还有抽象方法,子类中必须将这个方法也覆盖一次,否则报错。
void sleep(){ //非抽象方法无须强制覆盖
System.out.println("躺着");
}
}
class BaseStudent extends study {
void study(){
System.out.println("base study");
}
void stude1(){
system.out.println("BaseStudent子类,抽象父类中的抽象方法必须被重写");
}
}
class AdvStudent extends study {
void study(){
System.out.println("adv study");
}
void stude1(){
system.out.println("AdvStudent子类,抽象父类中的抽象方法必须被重写");
}
}
class AbstractDemo{
public static void mian(String[] args){
//new study(); //报错,因为父类是抽象类,无法创建对象
BaseStudent base = new BaseStudent();
base.study();
}
}
注意:
抽象类的相关问题:
A:抽象关键字abstract不可以和哪些关键字共存?
|--private
私有的,外部直接无法访问。子类也同样无法访问
A:抽象关键字abstract不可以和哪些关键字共存?
|--private
私有的,外部直接无法访问。子类也同样无法访问
|--abstrac修饰的方法就是为了让子类继承并重写的
|--static
那么这个时候抽象方法就可以可以通过类名调用,但是这样是没有意义的。
因为抽象方法中没有方法体,没有语句用于执行
|--final
final修饰的方法不能被重写。所以它和abstract冲突。
B:抽象类中可不可以没有抽象方法?
可以。如果这么做只有一个目的不让你创建这个类的对象
可以。如果这么做只有一个目的不让你创建这个类的对象
抽象练习
/*抽象练习
假如我们开发一个系统时,需要对员工进行建模。员工包括3个属性: 姓名,工号,工资。
经理也是员工,除了含有员工的属性外,另外还有一个奖金的属性。
请使用继承的思想设计出员工类和经理类。
要求类中提供必要的方法进行属性访问。
思想:
首先创建一个员工类作为抽象父类,其中定义有三个属性为姓名、工号、工资,以及一个工作方式的抽象方法
然后定义经理类,其中定义一个独有的奖金属性,使用自身的构造函数赋值。
在定义一个普通员工类。
*/
//定义抽象父类,Employee员工累
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;
}
//定义抽象方法
abstract void work();
}
//定义经理类,继承父类Employee
class Manage extends Employee{
//定义经理类的奖金属性
private int bonus;
//使用子类构造函数,为属性赋值
Manage(String name, String id, double pay, int bonus){
super(name,id,pay); //由于父类中已有三个属性的赋值方法,直接使用super语句为其赋值
this.bonus = bonus;
}
public void work(){
System.out.println("经理工作");
}
}
class Pro extends Employee{
Pro(String name, String id, double bonus){
super(name,id,bonus);
}
public void work(){
System.out.println("普通员工");
}
}
class AbstractTest1{
public static void main(String[] args){
Manage m = new Manage("huangwu","20100909",9000,1000);
m.work();
Pro p = new Pro("lisi","20130202",3500);
p.work();
}
}
模版方法模式
package extendsDemo;
/*
模版方法模式
需求;获取一段程序运行的时间
原理:获取程序开始和结束的时间,并相减
获取时间:System.currentTimeMillis();
当代码完成后,就可以解决这一类相同的问题。
这种方法就是:模版方法设计模式
什么是模版方法设计?
在定义功能时,功能的一部分是确定的,有一部分是不确定的。而确定的部分在使用不确定的部分。
那么此时就将不确定的部分暴露出去,由该类的子类来完成。
*/
abstract class GetTime{
public final void getTime(){ //不是一定要添加final,视具体情况而定
long star = System.currentTimeMillis();
runcode();
long end = System.currentTimeMillis();
System.out.println("毫秒:" + (end - star));
}
public abstract void runcode(); //不是一定要添加abstract,视具体情况而定。
}
class subTime extends GetTime{
public void runcode(){
for(int x=0; x<101; x++){
System.out.print(x);
}
}
}
class AbstractTest2{
public static void main(String[] args){
// getTime gt = new getTime();
// gt.getTime();
subTime st = new subTime();
st.getTime();
}
}
五、接口interface()
定义:
当一个类中的所有方法都是抽象类时,就无需定义abstract类,可以定义interface类
成员特点:
A)只有成员变量和成员方法
B)成员都有默认修饰符
成员变量:默认修饰符 public static final(可以省略不写)
成员函数:默认修饰符 public abstract(可以省略不写)
接口java中只能单继承的问题,让多继承以另一种优化方式存在
A)类与类:只能是单继承(extends)
B)接口与接口:可以单继承,可以多继承(extends)
C)类与接口:可以是单实现,可以是多实现(implements)
interface A{
}
interface B{
}
class C implements A,b{
}
接口的特点:
A)接口是对外暴露的原则
B)接口是程序的拓展
C)接口可以实现多实现
D)类与接口的实现关系,而且类可以继承一个类的同时,实现多个接口
E)接口与接口之间可以有继承关系
接口类与抽象类的区别:
A)抽象类只能被单继承(extends),接口类可以被多实现(employee)
B)成员的不同:
抽象类:成员变量可抽象,可不抽象;成员方法可抽象,可不抽象;构造方法可以用以实例化
接口类:成员变量有默认修饰符 public static final;成员方法有默认修饰符 public abstract
C) 抽象类中定义的是继承体系中的共性内容;
接口类中定义的是对象的扩展功能。
接口实例:
//接口实例
abstract class Stu{
abstract void study();
public void slepp(){
System.out.println("休息时间");
}
}
interface smoking{
public void smoke();
}
class zhansan extends Stu implements smoking{ //zhansan学员即学习也吸烟,所以先继承类,在实现吸烟
public void study(){
System.out.println("高三");
}
public void smoke(){
System.out.println("吸烟");
}
}
class limei extends Stu{ //limei学员只学习不吸烟,所以只继承类,不实现吸烟
public void study(){
System.out.println("高三");
}
}
//总结:继承类用来得到共性的内容,实现接口为了拓展其他内容,达到功能拓展的目地,由后期子类去实例化
class interfaceTest1{
public static void main(String[] args){
zhangsan zs = new zhangsan();
zs.sytudy();
zs.smoke();
limei lm = new limei();
lm.study();
}
}