Java高手真经----第6课 JAVA 面向对象编程

面向对象的三大特征:

  • 封装:通过Java的类来实现数据和操作方法的封装,对外界可以将每一个Java类都视为一个黑箱,只需要调用该黑箱提供的方法即可完成你想要的操作。
  • 继承:通过类的继承,便于将统一的功能集中在父类中,实现代码的重用和可维护性。
  • 多态:通过重载、重写与覆盖,实现不同类的不同形态特征。

6.1 封装(encapsulation)——类

HelloWorld

public class HelloWorld {
	
	private String  world = "World";
	public void say() {
		System.out.println("Hello" + world + "!");
	}

	public static void main(String[] args) {
			HelloWorld inst = new HelloWorld();
			inst.say();
	}
}

一个类的使用过程,包括封装类、生成实例、使用实例进行操作3个过程。

6.1.1 类的封装

封装(encapsulation)有如下的3个特点。

  • 事物的内部实现细节隐藏起来。
  • 对外提供一致的公共的接口——间接访问隐藏数据。
  • 可维护性。

6.1.2 对象的生成

封装的类不是对象,要使用该封装类进行操作,必须先生成该类的一个实例——对象。

6.1.3 对象的使用

生成了对象后,就可以使用该对象来做具体的事情了。对象的使用包括引用对象的成员变量和方法,通过运算符可以实现对变量的访问和方法的调用,变量和方法可以通过设定一定的访问权限(在前文中5.2节已经讲过)

来允许或禁止其他对象对它的访问。比如上面的HelloWorld实例,我们先添加一个setWorld()方法,用来修改world变量的值:

public class HelloWorld {
	
	private String  world = "World";
	
	public  void setworld(String world) {
		this.world = world;
	}
	public void say() {
		System.out.println("Hello " + world + "!");
	}
	public static void main(String[] args) {
			HelloWorld inst = new HelloWorld();
			inst.setworld("China");
			inst.say();
	}
}

 

 增加 getWorld()orld()方法

public class HelloWorld {
	
	private String  world = "World";
	
	public  void setworld(String world) {
		this.world = world;
	}
	public String getWorld() {
		return this.world;	
		}
	public void say() {
		System.out.println("Hello " + world + "!");
	}
	public static void main(String[] args) {
			HelloWorld inst = new HelloWorld();
			inst.setworld("China");
			inst.say();
			
			
			String world1 = new HelloWorld().world;
			String world2 = new HelloWorld().getWorld();
			
			System.out.println(world1 + world2);
	}
}

6.3.3 接口与抽象类的区别

Java接口和Java抽象类代表的就是抽象类型,就是我们需要提出的抽象层的具体表现。OOP面向对象的编程,如果要提高程序的复用率,增加程序的可维护性、可扩展性,就必须是面向接口的编程、面向抽象的编程,正确地使用接口、抽象类这些有用的抽象类型作为你结构层次上的顶层。

Java接口和Java抽象类有太多相似的地方,又有太多特别的地方,究竟在什么地方才是它们的最佳位置呢?通过下面的比较你就能够发现。

Java接口和Java抽象类最大的一个区别,就在于Java抽象类可以提供某些方法的部分实现,而Java接口不可以,这就是Java抽象类唯一的优点,但这个优点非常有用。如果向一个抽象类里加入一个新的具体方时,那么它所有的子类一下子都得到了这个新方法。例如下面的抽象类添加了一个实现函数,那么子类就可以直接使用该方法了:

public abstract  class ClassName1 {
	public void func1() {};	//添加一个实现函数
}

而Java接口做不到这一点,如果向一个Java接口里加入一个新方法,所有实现这个接口的类就无法成功通过编译了,因为你必须让每一个类都再实现这个方法才行,这显然是Java接口的缺点。例如下例为接口类添加了一个接口函数,那么实现该接口的类必须实现该函数:

public interface ClassName2 {
		public void func2(); //添加一个接口函数
}

(2)抽象类只能继承一个,而可以实现多个接口

一个抽象类的实现只能由这个抽象类的子类给出,也就是说,这个实现类处在抽象类所定义出的继承的等级结构中,而由于Java语言的单继承性,所以抽象类作为类型定义工具的效能大打折扣。在这一点上,Java接口的优势就出来了,任何一个实现了Java接口所规定的方法的类都可以具有这个接口的类型,而一个类可以实现任意多个Java接口,从而这个类就有了多种类型。

由此不难看出,Java接口是定义混合类型的理想工具,混合类表明一个类不仅仅具有某个主类型的行为,而且具有其他的次要行为。

结合(1)、(2)点中抽象类和Java接口的各自优势,最精典的设计模式就出来了:声明类型的工作仍然由Java接口承担,但是同时给出一个Java抽象类,且实现了这个接口,而其他同属于这个抽象类型的具体类可以选择实现这个Java接口,也可以选择继承这个抽象类,也就是说在层次结构中,Java接口在最上面,然后紧跟着抽象类,这就将两者的最大优点都能发挥到极至了。这个模式就是“默认适配模式”。

实现的代码如下所示:

这里先定义了一个接口类ClassName1,并为它添加了一个接口函数func1()。然后定义了一个抽象类ClassName2,添加了自己的实现函数func2()。最后可以定义具体的类ClassName3,它既继承了抽象类ClassName2,又实现了接口ClassName1,这样它就拥有了接口函数func1()和实现函数func2()。

接口在某些地方和抽象类有相似的地方,但是采用哪种方式来声明类主要参照以下两点。

● 如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类。

● 如果知道某个类应该是基类,那么第一个选择的应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。因为抽象类中允许存在一个或多个被具体实现的方法,只要方法没有被全部实现该类就仍是抽象类。

6.4 本课小结

6.4.1 总结本课的知识点

本节课以面向对象的三大特性——封装、继承与多态为主线,讲解了类的封装、抽象类与接口的具体使用方法,共包含13个知识点,如表6-1所示。

6.4.2 要掌握的关键点

对于本节课的内容,我们应该掌握如下的关键点:

1.Java面向对象的三大特性:封装、继承、多态。

2.封装有如下的3个特点:

● 将事物的内部实现细节隐藏起来。

● 对外提供一致的公共的接口——间接访问隐藏数据。

● 可维护性。

3.继承包括两个概念:超类和子类。

4.Java多态是通过方法重写和方法重载来实现的。

● 覆盖(override)——继承了父类的同名无参函数。

● 重载(overload)——继承了父类的同名有参函数。

● 重写(overwrite)——当前类的同名方法。

6.4.3 课后上机作业

抽象类与接口的概念虽然有些抽象,但一旦你能够运用它来编写自己的一个实现,就会发现它是如此简单,只不过是一个特殊的类。重要的是,我们应该如何把握建立抽象类与接口的时机。

通过6.3.3节的讲解,我们已经了解到,接口通常只用于定义接口的方法,在仅仅需要暴露外部接口函数时使用;而如果需要在接口中实现某些操作函数,就需要定义抽象类了。在实际的运用中,我们通常将接口作为顶层的类,用以暴露外部接口,然后编写一个抽象类来实现共同的函数。待实现的具体类既要继承抽象类,又要实现接口,这样就可以充分利用抽象类与接口的优点了。

 

为了演练这种开发模式,我们制定了一个实现需求,让读者来实现如下一个开发案例(120分钟)。

1.实现目标:实现一个简单的计算器,能够计算两个数的加、减、乘、除。

2.实现思路:由于加、减、乘、除的运算都很相似,都是对两个数值进行表达式运算,因此我们可以为这4种运算设计一个接口ICalculator,并设计接口函数calculate(String expression),输入表达式可以返回计算结果,再为每一个运算编写一个实现类,来实现计算接口函数即可。

由于对于用户输入的字符串表达式expression还需要进行分析,例如对于3+2、3-2等,需要将它们拆分为3和2,这对4种运算来说都需要进行这种操作。而这种操作又是一个实际的实现,因此我们可以将提取数值的操作放在一个抽象类AbstractCalculator中来进行提取,不同的实现类继承该抽象类,即可直接调用该函数来进行数值的提取了。

3.实现步骤:

(1)编写接口类ICalculator,添加计算的统一接口calculate(Stringexpression)。

(2)编写抽象类AbstractCalculator,添加根据计算表达式提取计算数值的函数实现split(String expression, String deliString),deliString为分隔符。

(3)编写实现类,均实现接口ICalculator,并继承AbstractCalculator:

● 加法Plus。

● 减法Minus。

● 乘法Multiply。

● 除法Divide。

● 默认Default:用于在输入不是以上4种运算表达式时的调用。

(4)编写测试类Test:根据用户输入的表达式,分别调用加法、减法、乘法和除法4种运算类,执行计算。

这些类之间的关系如图6-4所示。

6.4.4 上机作业参考样例

根据以上的4个实现步骤,下面是作者根据以上要求做的一个参考类代码。

(1)计算器接口类

package com.calculater;

/**
 * 
 * @author tjjingpan
 *计算器接口类
 */
public interface ICalculator {
	/**
	 * 计算表达式接口
	 * @param expression 待计算的表达式
	 * @return 计算结果
	 */
	public int caculate(String expression);
}

(2)计算器抽象类

package com.calculater;
/**
 * 
 * @author tjjingpan
 *
 */

public abstract class AbstractCalculator {
	
	/**
	 * 根据计算表达式,提取待计算的数值
	 * @param expression 计算表达式
	 * @param deliString 分隔符
	 * @return 待计算数值的数组
	 */
	public int[] split(String expression,String deliString) {
		String array[] = expression.split(deliString); //拆分字符串
		int arrayInt[] = new int[2]; //创建数值数组
		arrayInt[0] = Integer.parseInt(array[0]); //第一个数值
		arrayInt[01] = Integer.parseInt(array[1]);//第二个数组
		return arrayInt;//返回数组
	}

}

(3)计算器实现类:加、减、乘、除,以及默认计算类

● 加法计算类:

package com.calculater.impl;
import com.calculater.AbstractCalculator;
import com.calculater.ICalculator;
/**
 * 
 * @author tjjingpan
 *加法计算类
 */
public class Plus extends AbstractCalculator implements ICalculator {

	@Override
	public int caculate(String expression) {
		int arrayInt[] = split(expression,"\\+");//拆分加法表达式
		
		return arrayInt[0] + arrayInt[1]; //计算加法结果
	}
}

● 减法计算类:

package com.calculater.impl;
import com.calculater.AbstractCalculator;
import com.calculater.ICalculator;
/**
 * 
 * @author tjjingpan
 *减法计算类
 */
public class Minus extends AbstractCalculator implements ICalculator {

	@Override
	public int caculate(String expression) {
		int arrayInt[] = split(expression,"-");//拆分减法表达式
		
		return arrayInt[0] - arrayInt[1]; //计算减法结果
	}
}

● 乘法计算类:

package com.calculater.impl;
import com.calculater.AbstractCalculator;
import com.calculater.ICalculator;

/**
 * 
 * @author tjjingpan
 *乘法计算类
 */
public class Multiply extends AbstractCalculator implements ICalculator{
	@Override
	public int caculate(String expression) {
		int arrayInt[] = split(expression,"\\*");//拆分乘法表达式
		
		return arrayInt[0] * arrayInt[1]; //计算乘法结果
	}

}

● 除法计算类:

package com.calculater.impl;
import com.calculater.AbstractCalculator;
import com.calculater.ICalculator;

/**
 * 
 * @author tjjingpan
 *除法计算类
 */
public class Devide extends AbstractCalculator implements ICalculator {

	@Override
	public int caculate(String expression) {
		int arrayInt[] = split(expression,"/");//拆分除法表达式
		
		return arrayInt[0]/arrayInt[1]; //计算除法结果
	}
}

● 默认计算类:

package com.calculater.impl;
import com.calculater.AbstractCalculator;
import com.calculater.ICalculator;


/**
 * 
 * @author tjjingpan
 *默认计算类
 */
public class Default extends AbstractCalculator implements ICalculator {

	@Override
	public int caculate(String expression) {
		
		return 0;
	}

}

(4)测试类

package com.calculater;
import com.calculater.ICalculator;
import com.calculater.impl.Default;
import com.calculater.impl.Devide;
import com.calculater.impl.Minus;
import com.calculater.impl.Multiply;
import com.calculater.impl.Plus;
public class Test {

	public static void main(String[] args) {
		while(true) {
			System.out.println("准备输入:");
			String expression = System.console().readLine();
			
			//初始化实例
			ICalculator  calculator;
			if(expression.indexOf("+") !=-1) {
				calculator = new Plus();//调用加法计算器
			}else if(expression.indexOf("-") !=-1){
				calculator = new Minus();//调用减法类
			}else if(expression.indexOf("*") !=-1){
				calculator = new Multiply();//调用乘法类
			}else if (expression.indexOf("/")!= -1) {
				calculator = new Devide();//调用除法类
			}else {
				calculator = new Default();//调用默认类
			}
			//开始运算
			int value = calculator.caculate(expression);
			System.out.println("=" + value);
		}

	}

}

运行该类后的测试计算如图6-5所示。

谢谢大家的支持,我会陆续上传相关电子书 由于体积较大,本书分四卷压缩,请都下载完再解压! Java高手真经 高级编程篇 下载(一) http://download.csdn.net/source/3275208 Java高手真经 高级编程篇 下载(二) http://download.csdn.net/source/3275230 Java高手真经 高级编程篇 下载(三) http://download.csdn.net/source/3275245 Java高手真经 高级编程篇 下载(四) http://download.csdn.net/source/3275262 本书讲解Java Web开发中的高级开发技术,包括企业级的开发技术EJB、各种Java EE的分布式开发技术、Java Web的各种开源技术与框架,这3部分内容层层递进,涵盖了Java EE开发中的各种分布式与业务核心技术。讲解的主要内容包括如下。   Java Web企业级开发技术EJB:包括会话Bean、消息驱动Bean、实体Bean、拦截器、依赖注入、定时器、JPA持久化、JPQL查询语言。   Java Web分布式开发技术:包括JTA事务管理、JAAS验证与授权服务、JNDI命名和目录服务、JMS消息服务、JavaMail邮件服务、WebService、JMX管理、JCA连接器。   Java Web开源技术与框架:包括工作流、规则引擎、搜索引擎、缓存引擎、任务调度、身份认证、报表服务、系统测试、集群与负载均衡。   随书附赠光盘内容为本书各种原型包、系统源程序。本书内容循序渐进,通俗易懂,覆盖了Java Web高级开发的各种技术。无论对于Java软件设计还是软件开发,本书都是精通开发Java Web应用的必备的实用手册。   本书适合作为Java相关培训机构的教材,也可作为Java自学人员的参考手册。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值