现在的位置: 首页 > 综合 > 正文

黑马程序员 07 Java基础教学 – 07 – 面向对象(3) 之 继承、抽象、接口

2018年05月28日 ⁄ 综合 ⁄ 共 5961字 ⁄ 字号 评论关闭

               -------android培训java培训、期待与您交流! ----------



本日志doc文档下载



一、继承

1,特点

A,提高了代码的复用性。

B,让类与类之间产生了关系,有了这个关系,才有了多态的特性。

2,注意事项

千万不要为了获取其他类的功能,简化代码而继承。

必须是类与类之间有所属关系才可以继承。所属关系 is  a 

3Java中只支持单继承,支持多层继承

因为多继承容易带来安全隐患:当多个父类中定义了相同功能,当功能内容不同时,子类对象不确定要运行哪一个。

但是Java保留这种机制,并用另外一种体现形式来完成表示(多实现形式)

Java支持多层继承,也就是一个继承体系


那么如何使用一个继承体系中的功能呢?

想要使用体系,先查阅体系父类的描述,因为父类中定义的是该体系中共性功能。

通过了解共性功能,就可以知道该体系的基本功能。那么这个体系就已经可以基本使用了。

在具体的调用时,要创建最子类的对象,为什么呢?

A,因为有可能父类不能创建对象

B,创建子类对象可以使用更多的功能,包括基本的也包括特有的

简单一句话:查阅父类功能,创建子类对象使用功能。

二、子父类出现后,类成员的特点

A,变量

如果子类中出现非私有的同名成员变量时,

子类要访问本类中的变量,用this

子类要访问父类中的同名变量,用super

不显示写thissuper的情况下,默认访问本类中的变量

代码块如下:

class Father {
	int num = 4;
}

class Son extends Father {
	int num = 5;
	void show(){
		System.out.println("默认输出子类中的变量值:"+num);
		System.out.println("用super调用父类中的变量值:"+super.num);
		System.out.println("用this调用本类中的变量值:"+this.num);
	}
}

public class ExtendsDemo {
	public static void main(String[] args) {
		new Son().show();
	}
}

super的使用和this几乎一致

this代表的是本类对象的引用

super代表的是父类对象的引用

B,函数

当子类出现和父类一模一样的函数时,子类对象调用该函数,会运行子类函数的内容,如同父类函数被覆盖一样,这种情况是函数的另一个特性:重写(覆盖)

当子类继承父类,沿袭了父类的功能到子类中,但是子类虽具备该功能,但是功能的内容却和父类不一致,这时,没有必要定义新的功能,而是使用覆盖特性,保留父类的功能定义,并重写功能内容。

关于“覆盖”:

1,子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则便以失败

2,静态只能覆盖静态

重载和重写的区别:

重载:只看同名的参数列表

重写:子父类方法要一模一样

代码块如下:

class SuperClass {
	void show(){
		System.out.println("超类运行了..."+"显示姓名");
	}
}

class SubClass extends SuperClass {
	//子类扩展show方法,调用父类show方法运行一部分功能,再自己添加一部分功能
	void show(){
		super.show();
		System.out.println("子类运行了..."+"显示工号");
		System.out.println("子类运行了..."+"显示照片");
	}
}

public class ExtendsDemo2 {
	public static void main(String[] args) {
		new SubClass().show();
	}
}

C,构造函数

在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数默认第一行有一条隐式的语句spuer();

super();会访问父类中空构造函数,而且子类中所有的构造函数默认第一行都是super();


为什么子类一定要访问父类中的构造函数?

因为父类中的数据,子类可以直接获取,所以在子类对象建立时,需要先查看父类是如何对这些数据进行初始化的。如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。


注意:super语句一定定义在子类构造函数的第一行。


结论(子类的实例化过程):

子类的所有构造函数,默认都会访问父类中空参数的构造函数,因为子类每一个构造函数内的第一行都有一句隐式的super();

当父类中没有空参数的构造函数时,子类必须手动通过super或者this语句形式来指定要访问的构造函数。

代码块如下:

class FatherClass {
	FatherClass() {
		System.out.println("父类构造函数运行了...");
	}
	FatherClass(int num) {
		System.out.println("父类带参构造函数运行了...父亲的年龄是:"+(num+25));
	}
}

class SonClass extends FatherClass {
	SonClass(){
		System.out.println("子类构造函数运行了...");
	}
	SonClass(int age){
		super(age);
		System.out.println("子类带参构造函数运行了...儿子的年龄是:"+age);
	}
}

public class ExtendsDemo3 {
	public static void main(String[] args) {
		new SonClass();
		System.out.println("---------华丽分割线------------");
		new SonClass(10);
	}
}

三、final关键字

1,可以修饰类,函数,变量

2,被final修饰的类不可以被继承。为了避免被继承,被子类复写功能。

3,被final修饰的方法不可以被复写。

4,被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,也可以修饰局部变量。

常量的书写规范:所有字母都大写,如果有多个单词组成,单词间通过“_”连接

5,内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量


四、抽象类

A,特点

1,抽象方法一定在抽象类中

2,抽象方法和抽象类都必须被abstract关键字修饰

3,抽象类不可以用new创建对象。因为调用抽象方法没意义

4,抽象类中的方法要被使用,必须由子类复写所有的抽象方法后,建立子类对象调用

如果子类值覆盖了部分抽象方法,那么该子类还是一个抽象类。

代码块如下:

abstract class Student {
	abstract void study();
}

class BaseStudent extends Student {
	@Override
	void study() {
		System.out.println("基础学习");
	}

}

class AdvStudent extends Student {
	@Override
	void study() {
		System.out.println("高级学习");
	}
}

class AbstractDemo {
	public static void main(String[] args) {
		new BaseStudent().study();
	}
}

抽象类和一般类没有太大的不同:该如何描述事物就如何描述事物,只不过,该事物出现了不确定的部分,这些也是该事物的功能,需要明确出现。但是无法定义主体,即通过抽象方法来表示。

特殊情况:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。

B,抽象类练习一

情景:假如我们在开发一个系统时需要对员工进行建模,员工包含3个属性:姓名,工号以及工资。经理也是员工,除了含有员工的属性外,另外还有一个奖金属性。请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。

代码如下:

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();

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public double getPay() {
		return pay;
	}

	public void setPay(double pay) {
		this.pay = pay;
	}
}

class Manager extends Employee {
	private int bonus;

	Manager(String name, String id, double pay, int bonus) {
		super(name, id, pay);
		this.bonus = bonus;
	}

	@Override
	public void work() {
		System.out.println("姓名\t"+"工号\t"+"工资\t"+"奖金");
		System.out.println(getName()+"\t"+getId()+"\t"+getPay()+"\t"+getBonus());
		System.out.println("从事经理的工作...");
	}

	public int getBonus() {
		return bonus;
	}

	public void setBonus(int bonus) {
		this.bonus = bonus;
	}

}

class Pro extends Employee {

	Pro(String name, String id, double pay) {
		super(name, id, pay);
	}

	@Override
	public void work() {
		System.out.println("姓名\t"+"工号\t"+"工资");
		System.out.println(getName()+"\t"+getId()+"\t"+getPay());
		System.out.println("进行普通员工的工作...");
		
	}

}

public class AbstractExDemo1 {
	public static void main(String[] args) {
		new Pro("海逸","技术部009",6800).work();
		System.out.println("---------华丽分割线-----------");
		new Manager("安立奎","技术部003",15000,10000).work();
	}
}

运行结果如下图所示:

C,抽象类练习二

情景:获取一段程序运行的时间

代码如下:

/**
 * 这种方式称为模板模式
 * 在定义功能时,功能的一部分是确定的,但是有一部分是不确定的,而确定的部分在使用不确定的部分
 * 那么这时就将不确定的部分暴露出去,由该类的子类去完成。
 * 
 * @author LeeYou
 * 
 */
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 {

	@Override
	public void runcode() {
		for (int i = 0; i < 100000; i++)
			System.err.println(i);
	}

}

class AbstractExDemo2 {
	public static void main(String[] args) {
		SubTime st = new SubTime();
		st.getTime();
	}
}

五、接口类

1,接口中常见定义:常量,抽象方法

2,接口中的成员都有固定修饰符

常量:public static final

方法:public abstract

记住:接口中的成员都是public


代码块如下:

interface Inter {
	public static final int NUM = 100;

	public abstract void show();
}

class Test implements Inter {

	@Override
	public void show() {
		System.out.println("简单的接口实现");
	}

}

public class InterfaceDemo {
	public static void main(String[] args) {
		new Test().show();
	}
}

接口是不可以被创建对象的,因为有抽象方法。需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化,否则子类是一个抽象类。

接口可以被类多实现,也是对多继承不支持的转换形式。Java支持多实现。

接口间还能实现继承。

代码如下:

  interface A {
  	void methodA();
  }
  
  interface B extends A {
  	void methodB();
  }
  
  interface C extends B {
  	void methodC();
  }
  
  public class InterfaceExDemo1 implements C {
  
  	@Override
  	public void methodB() {
  
  	}
  
  	@Override
  	public void methodA() {
  
  	}
  
  	@Override
  	public void methodC() {
  
  	}

}

接口之间能实现多继承

代码如下:

interface A {
	void methodA();
}

interface B {
	void methodB();
}

interface C extends B, A {
	void methodC();
}

public class InterfaceExDemo1 implements C {

	@Override
	public void methodB() {

	}

	@Override
	public void methodA() {

	}

	@Override
	public void methodC() {

	}

}

切忌出现下面的情况:

抱歉!评论已关闭.