第八章 面向对象(类对象封装构造方法、继承、抽象类)

Java基础08

第八章 面向对象(类对象封装构造方法、继承、抽象类)

8.1 面向对象思想

8.1.1 面向对象思想概述

概述

Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的指引下,使用Java语言去设计、开发计算机程序。 这里的对象泛指现实中一切事物,每种事物都具备自己的属性和行为。面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。

举例

洗衣服:

  • 面向过程:把衣服脱下来–>找一个盆–>放点洗衣粉–>加点水–>浸泡10分钟–>揉一揉–>清洗衣服–>拧干–>晾起来
  • 面向对象:把衣服脱下来–>打开全自动洗衣机–>扔衣服–>按钮–>晾起来

区别:

  • 面向过程:强调步骤。
  • 面向对象:强调对象,这里的对象就是洗衣机。
特点

面向对象思想是一种更符合我们思考习惯的思想,它可以将复杂的事情简单化,并将我们从执行者变成了指挥者。面向对象的语言中,包含了三大基本特征,即封装、继承和多态。

8.1.2 类和对象

环顾周围,你会发现很多对象,比如桌子,椅子,同学,老师等。桌椅属于办公用品,师生都是人类。那么什么是类呢?什么是对象呢?

类与对象的关系
  • 类是对一类事物的描述,是抽象的
  • 对象是一类事物的实例,是具体的
  • 类是对象的模板,对象是类的实体。

在这里插入图片描述

8.1.3 类的定义

类的定义格式
public class ClassName{
//成员变量
//成员方法
}
  • 定义类:就是定义类的成员,包括成员变量和成员方法。
  • 成员变量:和以前定义变量几乎是一样的。只不过位置发生了改变。在类中,方法外。
  • 成员方法:和以前定义方法几乎是一样的。只不过把static去掉,static的作用在面向对象后面课程中再详细讲解。

类的定义格式举例:

public class Student{
//成员变量
String name;//姓名
int age;//年龄
//成员方法
//学习的方法
public void study(){
System.out.println("好好学习,天天向上");
}
//吃饭的方法
public void eat(){
System.out.println("学习饿了要吃饭");
}
}

8.1.4 对象的使用

对象的使用格式

创建对象:

	类名 对象名 = new 类名();

使用对象访问类中的成员:

	对象名.成员变量; 
	对象名.成员方法();

对象的使用格式举例:

public class Test01_Student { 
	public static void main(String[] args) { 
	//创建对象格式:类名 对象名 = new 类名(); 
	Student s = new Student(); 
	System.out.println("s:"+s); //com.kkb.Student@100363 
	//直接输出成员变量值 
	System.out.println("姓名:"+s.name); //null 
	System.out.println("年龄:"+s.age); //0 
	System.out.println("----------"); 
	//给成员变量赋值 
	s.name = "赵丽颖"; 
	s.age = 18; 
	//再次输出成员变量的值 
	System.out.println("姓名:"+s.name); //赵丽颖 
	System.out.println("年龄:"+s.age); //18 
	System.out.println("----------");
	//调用成员方法 
	s.study(); 
	// "好好学习,天天向上" 
	s.eat(); 
	// "学习饿了要吃饭" 
	} 
	}
成员变量的默认值
成员类型数据类型默认值
基本类型整数(byte,short,int,long)0
基本类型浮点数(float,double)0.0
基本类型字符(char)‘\u0000’
基本类型布尔(boolean)false
引用类型数组,类,接口null

8.1.5 类与对象的练习

定义手机类:

public class Phone { 
	// 成员变量 
	String brand; //品牌 
	int price; //价格 
	String color; //颜色 
	// 成员方法 
	//打电话 
	public void call(String name) { 
	System.out.println("给"+name+"打电话"); 
	}
	//发短信 
	public void sendMessage()
	 { 
	 System.out.println("群发短信");
	 }
	 }

定义测试类:

public class Test02Phone { 
public static void main(String[] args) { 
	//创建对象 
	Phone p = new Phone();
	//输出成员变量值 
	System.out.println("品牌:"+p.brand);//null 
	System.out.println("价格:"+p.price);//0 
	System.out.println("颜色:"+p.color);//null 
	System.out.println("------------"); 
	//给成员变量赋值 
	p.brand = "锤子"; 
	p.price = 2999; 
	p.color = "棕色"; 
	//再次输出成员变量值 
	System.out.println("品牌:"+p.brand);//锤子 
	System.out.println("价格:"+p.price);//2999 
	System.out.println("颜色:"+p.color);//棕色 
	System.out.println("------------"); //调用成员方法 
	p.call("紫霞"); 
	p.sendMessage(); 
	} 
	}

8.1.6 对象内存图

一个对象,调用一个方法内存图

在这里插入图片描述

通过上图,我们可以理解,在栈内存中运行的方法,遵循"先进后出,后进先出"的原则。变量p指向堆内存中的空间,寻找方法信息,去执行该方法。但是,这里依然有问题存在。创建多个对象时,如果每个对象内部都保存一份方法信息,这就非常浪费内存了,因为所有对象的方法信息都是一样的。那么如何解决这个问题呢?请看如下图解。
在这里插入图片描述
对象调用方法时,根据对象中方法标记(地址值),去类中寻找方法信息。这样哪怕是多个对象,方法信息只保存一份,节约内存空间。

8.1.7 成员变量和局部变量区别

变量根据定义位置的不同,我们给变量起了不同的名字。如下图所示:
在这里插入图片描述
局部变量和成员变量的区别:

  • 在类的位置不同【重点】
    • 成员变量:类中,方法外
    • 局部变量:方法种或者方法声明上(形式参数)
  • 在内存中的位置不用(了解)
    • 成员变量:堆内存
    • 局部变量:栈内存
  • 生命周期不同(了解)
    • 成员变量:随着对象的创建而存在,随着对象的消失而消失
    • 局部变量:随着方法调用而存在,随着方法调用完毕而消失
  • 初始化的值不同【重点】
    • 成员变量:有默认值
    • 局部变量:没有默认值
  • 作用范围不一样
    • 成员变量:类中
    • 局部变量:方法中

8.2 封装

8.2.1 封装概述

概述

面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的方式。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。

原则

属性隐藏起来,若需要访问某个属性,提供公共方法对其访问

8.2.2 封装的步骤

  1. 使用private关键字来修饰成员变量
  2. 对需要访问的成员变量提供一对getXxx方法、setXxx方法。

8.2.3 封装的操作——private关键字

private的含义
  1. private是一个权限修饰符,代表最小权限
  2. 可以修饰成员变量和成员方法
  3. 被private修饰后的成员变量和成员方法,只在本类中才能访问
private的使用格式
	private 数据类型 变量名:
  1. 使用private修饰成员变量,代码如下:

public class Student{
	private String name;
	private int age;
}
  1. 提供 getXxx 方法 / setXxx 方法,可以访问成员变量,代码如下:
public class Student { 
	private String name; 
	private int age; 
	public void setName(String n) 
	{ 
	name = n; 
	}
	public String getName() 
	{ 
	return name; 
	}
	public void setAge(int a) 
	{ 
	age = a;
	 }
	 public int getAge() 
	 { 
	 return age; 
	 }
	  }

8.2.4 封装优化1——this关键字

我们发现 setXxx 方法中的形参名字并不符合见名知意的规定,那么如果修改与成员变量名一致,是否就见名知意了呢?代码如下:

public class Student 
{ 
	private String name; 
	private int age; 
	public void setName(String name) 
	{ name = name; }
	public void setAge(int age) 
	{ age = age; } 
	} 

经过修改和测试,发现并没有办法访问到成员变量,this的含义测试,我们发现新的public void setAge(int age = age; 经过修改和测试,我们发现新的问题,成员变量赋值失败了。也就是说,在修改了 setXxx() 的形参变量名后,方法并没有给成员变量赋值!这是由于形参变量名与成员变量名重名,导致成员变量名被隐藏,方法中的变量名,无法访问到成员变量,从而赋值失败。所以,我们只能使用this关键字,来解决这个重名问题。

this的含义

this代表所在类的当前对象的引用(地址值),即对象自己的引用。
记住 :方法被哪个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁

this使用格式
	this.成员变量名;

使用 this 修饰方法中的变量,解决成员变量被隐藏的问题,代码如下:

public class Student { 
	private String name; 
	private int age; 
	public void setName(String name) { 
	//name = name; 
	this.name = name; 
	}
	public String getName() 
	{ 
	return name; 
	}
	public void setAge(int age) 
	{ 
	//age = age; 
	this.age = age; 
	}
	public int getAge() 
	{ 
	return age; 
	} 
	}

小贴士:方法中只有一个变量名时,默认也是使用 this 修饰,可以省略不写。

8.2.5 封装优化——构造方法

当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。
小贴士:无论你与否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个无参数构造方法,一旦自己定义了构造方法,Java自动提供的默认无参数构造方法就会失效。

构造方法的定义格式
修饰符 构造方法名(参数列表){
//方法体
}

构造方法的写法上,方法名与它所在的类名相同。它没有返回值,所以不需要返回值类型,甚至不需要void。使用构造方法后,代码如下:

public class Student { 
	private String name; 
	private int age; 
	// 无参数构造方法 
	public Student() {} 
	// 有参数构造方法 
	public Student(String name,int age) 
	{ 
	this.name = name; 
	this.age = age; } 
	}
注意事项
  1. 如果你不提供构造方法,系统会给出无参数构造方法。
  2. 如果你提供了构造方法,系统将不再提供无参数构造方法。
  3. 构造方法是可以重载的,既可以定义参数,也可以不定义参数。

8.2.6 标准代码——JavaBean

JavaBean 是 Java语言编写类的一种标准规范。符合 JavaBean 的类,要求类必须是具体的和公共的,并且具有无参数的构造方法,提供用来操作成员变量的 set 和
get方法。

public class ClassName{ 
//成员变量 
//构造方法 
//无参构造方法【必须】 
//有参构造方法【建议】 
//成员方法 
//getXxx() 
//setXxx() 
}

编写符合 JavaBean 规范的类,以学生类为例,标准代码如下:

public class Student { 
//成员变量 
private String name; 
private int age; 
//构造方法 public Student() {}
public Student(String name,int age) 
{ this.name = name; this.age = age; }
//成员方法 
public void setName(String name){
	this.name = name;
	 }
	 public String getName() 
	 { return name; }
	 public void setAge(int age) 
	 { this.age = age; }
	 public int getAge() 
	 { return age; } 
	 }

测试类,代码如下:


public class TestStudent 
{ 
	public static void main(String[] args) { 
	//无参构造使用 
	Student s= new Student(); 
	s.setName("柳岩"); 
	s.setAge(18); 
	System.out.println(s.getName()+"---"+s.getAge()); 
	//带参构造使用 
	Student s2= new Student("赵丽颖",18); 
	System.out.println(s2.getName()+"---"+s2.getAge()); 
	} 
	}

8.3 继承

8.3.1 概述

在现实生活中,继承一般指的是子女继承父辈的财产。在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系。例如学校中的讲师、助教、班主任都属于员工。这些员工之间会形成一个继承体系,具体如下图所示。
在这里插入图片描述
在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类,子类会自动拥有父类所有可继承的属性和方法
继承的概念:当要定义一个类(讲师)时,发现已有类(员工)和要定义的类相似,并且要定义的类属于已有类的一种时,可以将要定义类定义为已有类的子类。同时也可以反过来思考,当多个类(讲师,助教,班主任)有共性内容,可以将共性内容向上抽取,抽取到一个新的类(员工)中,那么多个类和新的类形成的关系叫做继承。

8.3.2 继承的格式

通过extends关键字,可以声明一个子类继承另外一个父类,定义格式如下:

class 父类 { ... }
class 子类 extends 父类 { ... }

继承演示,代码如下:

/** 定义员工类Employee,做为父类 */ 
class Employee { 
	String name; // 定义name属性 
	// 定义员工的工作方法 
	public void work() 
	{ 
	System.out.println("尽心尽力地工作"); 
	} 
	}
	/** 定义讲师类Teacher 继承 员工类Employee */ 
	class Teacher extends Employee { 
	// 定义一个打印name的方法 
	public void printName() 
	{ 
	System.out.println("name=" + name); 
	} 
	}
	/** 定义测试类 */ 
	public class ExtendsDemo01 
	{ 
	public static void main(String[] args) 
	{ 
	// 创建一个讲师类对象 
	Teacher t = new Teacher(); 
	// 为该员工类的name属性进行赋值 
	t.name = "小明"; 
	// 调用该员工的printName()方法 
	t.printName(); // name = 小明 
	// 调用Teacher类继承来的work()方法 
	t.work(); // 尽心尽力地工作 
	} 
	}

在上述代码中,Teacher类通过extends关键字继承了Employee类,这样Teacher类便是Employee类的子类。从运行结果不难看出,子类虽然没有定义name属性和work()方法,但是却能访问这两个成员。这就说明,子类在继承父类的时候,会自动拥有父类的成员。

继承的好处
  1. 提高代码的复用性。
  2. 类与类之间产生了关系,是多态的前提。

8.3.3 继承后的特点——非私有成员变量

当类之间产生了关系后,其中各类中的成员变量,又产生了哪些影响呢?

成员变量不重名

如果子类父类中出现不重名的成员变量,这时的访问是没有影响的。代码如下:

class Fu { 
	// Fu中的成员变量。 
	int num = 5; 
	}
class Zi extends Fu { 
	// Zi中的成员变量 
	int num2 = 6; 
	// Zi中的成员方法 
	public void show() 
	{ 
	// 访问父类中的num, 
	System.out.println("Fu num="+num); // 继承而来,所以直接访问。 
	// 访问子类中的num2 
	System.out.println("Zi num2="+num2); } 
	}
	class ExtendDemo02 { 
	public static void main(String[] args) { 
	// 创建子类对象 
	Zi z = new Zi(); 
	// 调用子类中的show方法 
	z.show(); 
	} 
	}
	演示结果: 
	Fu num = 5 
	Zi num2 = 6
成员变量重名

如果子类父类中出现重名的成员变量,这时的访问是有影响的。代码如下:

class Fu { 
	// Fu中的成员变量。
	int num = 5; 
	}
class Zi extends Fu 
{ 	
	// Zi中的成员变量 
	int num = 6; 
	public void show() 
	{ 
	// 访问父类中的num 
	System.out.println("Fu num=" + num); 
	// 访问子类中的num S
	ystem.out.println("Zi num=" + num); } 
	}
	class ExtendsDemo03 { 
	public static void main(String[] args) { 
	// 创建子类对象 
	Zi z = new Zi(); 
	// 调用子类中的show方法 
	z.show(); 
	} 
	}
	演示结果: 
	Fu num = 6 
	Zi num = 6

子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用 super 关键字,修饰父类成员变量,类似于之前学过的 this 。

使用格式:

	super.父类成员变量名

子类方法需要修改,代码如下:

class Zi extends Fu { 
	// Zi中的成员变量 
	int num = 6; 
public void show() 
{ 	//访问父类中的num 
	System.out.println("Fu num=" + super.num); //访问子类中的num 
	System.out.println("Zi num=" + this.num); 
	}
	}
	演示结果: 
	Fu num = 5 
	Zi num = 6

小贴士:Fu 类中的成员变量是非私有的,子类中可以直接访问。若Fu 类中的成员变量私有了,子类是不能直接访问的。通常编码时,我们遵循封装的原则,使用private修饰成员变量,那么如何访问父类的私有成员变量呢?对!可以在父类中提供公共的getXxx方法和setXxx方法。

8.3.4 super和this

父类空间优先于子类对象产生

在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构造方法调用时,一定先调用父类的构造方法。理解图解如下:
在这里插入图片描述

super和this的含义
  • super:代表父类的存储空间标识(可以理解为父亲的引用)。
  • this:代表当前对象的引用(谁调用就代表谁)。

8.3.5 继承后的特点——非私有成员方法

当类之间产生了关系,其中各类中的成员方法,又产生了哪些影响呢?

成员方法不重名

如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。代码如下:

class Fu{
    public void show(){
        System.out.println("父类中的show方法执行");
    }
}
class Zi extends Fu{ 
	public void show2(){ 
		
		System.out.println("Zi类中的show2方法执行"); 
		} 
}
public class ExtendsDemo04{ 
	public static void main(String[] args) { 
		Zi z = new Zi(); 
		//子类中没有show方法,但是可以找到父类方法去执行 
		z.show(); 
		z.show2(); 
		} 
	}
成员方法重名——重写(Override)

如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写(Override)

  • 方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。

代码如下:

class Fu { 
	public void show() { 
		System.out.println("Fu show"); 
		} 
}
class Zi extends Fu 
{ 
	//子类重写了父类的show方法 
	public void show() 
	{ 
	System.out.println("Zi show"); 
	} 
}
public class ExtendsDemo05{
	public static void main (String[] args)
	{
		Zi z = new Zi();
		//子类中有show方法,只执行重写后的show方法
		z.show();// Zi show
}
}
重写的应用

子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。比如新的手机增加来电显示头像的功能,代码如下:

class Phone { 
	public void sendMessage(){ 
		System.out.println("发短信"); 
		}
public void call(){ 
		System.out.println("打电话"); 
		}
public void showNum(){ 
		System.out.println("来电显示号码"); 
		} 
	}
//智能手机类 
class NewPhone extends Phone { 
	//重写父类的来电显示号码功能,并增加自己的显示姓名和图片功能 
	public void showNum(){ 
	//调用父类已经存在的功能使用super 
	super.showNum(); 
	//增加自己特有显示姓名和图片功能 
	System.out.println("显示来电姓名"); 
	System.out.println("显示头像"); 
	} 
}
public class ExtendsDemo06 { 
	public static void main(String[] args) { 
		// 创建子类对象 
		NewPhone np = new NewPhone(); 
		// 调用父类继承而来的方法 
		np.call(); 
		// 调用子类重写的方法 
		np.showNum(); 
		} 
	}

小贴士:这里重写时,用到super.父类成员方法,表示调用父类的成员方法。

注意事项
  1. 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
  2. 子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。
  3. 私有方法不能被重写(父类私有成员子类是不能继承的)
Java中重写(Override)与重载(Overload)的区别
  1. 发生的位置
    • 重载: 一个类中
    • 重写: 子父类中
  2. 参数列表限制
    • 重载: 必须不同
    • 重写: 必须相同
  3. 返回值类型
    • 重载: 与返回值类型无关
    • 重写: 返回值类型必须一致
  4. 访问权限
    • 重载: 与访问权限无关
    • 重写: 子类的方法权限不能小于父类的方法权限
  5. 异常处理
    • 重载: 与异常无关
    • 重写: 异常范围可以更小,但是不能抛出新的异常
super和this的用法
  1. 访问成员
    this.成员方法名() - - 本类的
    super.成员方法名() – 父类的
    用法演示,代码如下:
class Animal{
	public void eat() { 
		System.out.println("animal : eat"); 
		} 
		}
class Cat extends Animal { 
	public void eat() { 
		System.out.println("cat : eat"); 
	}
	public void eatTest() { 
	this.eat(); // this 调用本类的方法 
	super.eat(); // super 调用父类的方法 
	} 
}
public class ExtendsDemo08 { 
	public static void main(String[] args) { 
		Animal a = new Animal(); 
		a.eat(); 
		Cat c = new Cat(); 
		c.eatTest(); 
		} 
	}

输出结果为:
animal : eat
cat : eat
animal : eat

8.3.6 继承后的特点——构造方法

当类之间产生了关系,其中各类中的构造方法,又产生了哪些影响呢?

首先我们要回忆两个事情,构造方法的定义格式和作用。

  1. 构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。
  2. 构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个 super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。代码如下:
class Fu{
	private int n;
	Fu(){
	System.out.println("Fu()");
	}
}
class Zi extends Fu { 
	Zi(){ 
	// super(),调用父类构造方法 
		super();
		System.out.println("Zi()"); 
		} 
		}
public class ExtendsDemo07{ 
	public static void main (
		String args[]){ 
		Zi zi = new Zi(); 
		} 
		}
输出结果: 
Fu() 
Zi()

super和this的用法
  1. 访问构造方法
this(...) -- 本类的构造方法 
super(...) -- 父类的构造方法

子类的每个构造方法均有默认的super(),调用父类的空参构造。手动调用父类构造会覆盖默认的super()。
super()和this()都必须是在构造方法的第一行,所以不能同时出现。

8.3.7 继承的特点
  1. Java中的类只支持单继承,不支持多继承。
//一个类只能有一个父类,不可以有多个父类
class C extends A{} //ok
class C extends A,B.... //error
  1. Java支持多层继承(继承体系)。
class A{}
class B extends A{}
class C extends B{}
  1. 所有的类都直接或者间接继承了Object类,Object类时所有类的父类。

8.4 抽象类

8.4.1 概述

由来

当编写一个类时,我们往往会为该类定义一些方法,这些方法是用来描述该类的功能具体实现方式,那么这些方法都有具体的方法体。分析事物时,发现了共性内容,就出现向上抽取。会有这样一种特殊情况,就是方法功能声明相同,但方法功能主体不同。那么这时也可以抽取,但只抽取方法声明,不抽取方法主体。那么此方法就是一个抽象方法。
如:

  • 描述讲师的行为:工作。
  • 描述助教的行为:工作。
  • 描述班主任的行为:工作。

讲师、助教、班主任之间有共性,可以进行向上抽取。抽取它们的所属共性类型:员工。由于讲师、助教、班主任都具有工作功能,但是他们具体工作内容却不一样。这时在描述员工时,发现了有些功能不能够具体描述,那么,这些不具体的功能,需要在类中标识出来,通过java中的关键字abstract(抽象)修饰。当定义了抽象函数的类也必须被abstract关键字修饰,被abstract关键字修饰的类是抽象类。

定义
  • 抽象方法:没有方法体的方法。
  • 抽象类:包含抽象方法的类。

8.4.2 abstract 使用格式

抽象方法

使用 abstract 关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。
定义格式:

修饰符 abstract 返回值类型 方法名 (参数列表);

代码举例:

public abstract void run();
抽象类

如果一个类包含抽象方法,那么该类必须是抽象类。
定义格式:

public abstract class 类名字{
}

代码举例:

public abstract class Employee { 
	public abstract void work(); 
	}
抽象类的使用

继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父类的抽象方法,否则,从最初的父类到最终的子类都不能创建对象,失去意义。

代码举例:

public class Teacher extends Employee { 
	public void work (){ 
		System.out.println("讲课"); 
		} 
		}
public class Test { 
	public static void main(String[] args) { 
		// 创建子类对象 
		Teacher t = new Teacher(); 
		// 调用run方法 
		t.work(); 
		} 
		}
输出结果: 
讲课

此时的方法重写,是子类对父类抽象方法的完成实现,我们将这种方法重写的操作,也叫做实现方法

8.4.3 注意事项

关于抽象类的使用,以下为语法上要注意的细节,虽然条目较多,但若理解了抽象的本质,无需死记硬背。

  1. 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
    理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
  2. 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
    理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
  3. 抽象类中,可以有成员变量。
    理解:子类的共性的成员变量 , 可以定义在抽象父类中。
  4. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
    理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
  5. 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
    理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。

8.5 综合案例—员工类体系

8.5.1 案例介绍

某IT公司有多名员工,按照员工负责的工作不同,进行了部门的划分(研发部员工、维护部员工)。研发部根据所需研发的内容不同,又分为JavaEE工程师、Android工程师;维护部根据所需维护的内容不同,又分为网络维护工程师、硬件维护工程师。

公司的每名员工都有他们自己的员工编号、姓名,并要做它们所负责的工作。

工作内容:

  • JavaEE工程师: 员工号为xxx的 xxx员工,正在研发淘宝网站
  • Android工程师:员工号为xxx的 xxx员工,正在研发淘宝手机客户端软件
  • 网络维护工程师:员工号为xxx的 xxx员工,正在检查网络是否畅通
  • 硬件维护工程师:员工号为xxx的 xxx员工,正在修复打印机

请根据描述,完成员工体系中所有类的定义,并指定类之间的继承关系。进行XX工程师类的对象创建,完成工作方法的调用。

8.5.2 案例分析

在这里插入图片描述

  • 根据员工信息的描述,确定每个员工都有员工编号、姓名、要进行工作。则,把这些共同的属性与功能抽取到父类中(员工类),关于工作的内容由具体的工程师来进行指定。
    工作内容:
    • JavaEE工程师:员工号为xxx的 xxx员工,正在研发淘宝网站
    • Android工程师:员工号为xxx的 xxx员工,正在研发淘宝手机客户端软件
    • 网络维护工程师:员工号为xxx的 xxx员工,正在检查网络是否畅通
    • 硬件维护工程师:员工号为xxx的 xxx员工,正在修复打印机
  • 创建JavaEE工程师对象,完成工作方法的调用

8.5.3 示例代码

定义员工类

public class Employee {
    private int id;
    private String name;
    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

定义研发部员工类Developer(抽象类) 继承 员工类Employee

public abstract class Developer extends Employee{
    public abstract void work();
}

定义JavaEE工程师 继承 研发部员工类,重写工作方法

public class JavaEE extends Developer{


    JavaEE(int id,String name){
        super();
        this.setId(id);
        this.setName(name);
    }
    @Override
    public void work() {
        System.out.println("员工号为"+this.getId()+"的"+this.getName()+ "员工,正在研发淘宝网站");
    }
}

在测试类中,创建JavaEE工程师对象,完成工作方法的调用

public class Test {
    public static void main(String[] args) {
        JavaEE ee = new JavaEE(1,"zy");
        ee.work();
    }
}

结果:
在这里插入图片描述
这样就完成了其中一个实体员工的创建以及工作方法的调用,其他的三个都是以此类推的,就不做过多赘述了。

总结

面向对象,java的重中之重,大家有没有好好学~

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值