前言:
你是否会有这样的情况:看到代码时脑子里一片空白,茫然不知所措?在学习编程过程中,看见api时感到思维陷入一团乱麻中,理不清头绪?这篇文章对入门感到吃力的朋友可以略加参考。
本文特点:
独辟蹊径,从一个初学者的角度出发去发现问题,然后提供了一些的思路。本文适合于Java有一些基础并希望提高的朋友,如果完全没有也没有关系,因为会带给你一些全新的视角,有C语言经验会更好。同时本文内容处于入门阶段,不会深入探讨。
主要内容:分析学习时思维上的难点,Java三大特征---多态,继承,封装的介绍
免责声明:笔者力求以通俗的语言把问题讲清楚,但由于才疏学浅,难免会有错漏,敬请谅解。
目录:
1.感到吃力的根源是什么?
2.多态
3.多态用法小结
4.继承
5.继承的使用
6.封装
=========================================================================
1.感到吃力的根源是什么?
学习时觉得吃力,费了很多时间进展缓慢,并不是说努力不够,而是没有合适的思考的切入点。举个例子:
public class AnyTest2 {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
---计算机执行代码的流程大概是这个样子的:把代码编译成class文件,再交由JVM虚拟机解释成可执行代码交给CPU处理,CPU把处理好的数据传给显示器驱动程序---点亮显示器上的白色亮点,然后在控制台部分就能看见由亮点组成的字符串:Hello World
在这个过程中,java程序员做了哪些事呢?写了一个类,调用了main方法和println方法,给出了字符串Hello World;这个简单的例子,是想给一个概念:每种程序语言都有它的边界。所谓“边界”相当于程序的原子。举个例子:用C语言写硬件驱动,程序的边界就是“位”。Java里有句很经典的话:一切都是对象。在笔者看来,这句话可以换成:一切都是方法。这有助于理解面向对象的几大特征。
=========================================================================
2.多态
---举个例子:你中午要吃饭,到了饭馆,服务员对你说我们这里有川菜,粤菜,淮扬菜。这时你点了川菜,然后做川菜的师傅把菜做好给了你。
这就是多态的描述。饭馆可以做菜,相当于提供了抽象方法,具体工作由厨师来做,相当于提供了具体方法。选择不同的厨师,做出来的菜不同,但是对外来看他们的功用是一样的:做菜。用代码描述:
package PolymorphicDemo;
public interface Restaurant {
void cook(); //我们可以做菜
}
class Chuan implements Restaurant{
@Override
public void cook() {
System.out.println("我做的是川菜");
}
}
class Guang implements Restaurant{
@Override
public void cook() {
System.out.println("我做的是粤菜");
}
}
class HuaiYang implements Restaurant{
@Override
public void cook() {
System.out.println("我做的是淮扬菜");
}
}
class Client{
public static void main(String[] args) {
Restaurant chuan = new Chuan();
chuan.cook();
Restaurant guang = new Guang();
guang.cook();
}
}
多态是Java的三大特征之一,从中也可以看出Java的设计思想是方便使用。因为底层封装了实现的具体过程,Java用起来方便的原因是源码中提供了多个接口和实现类给程序员使用,也有众多公司开发api使用。
=========================================================================
3.多态小结
---1> 有抽象的方法,外包装可以是接口或者抽象父类(父类也可以不是抽象类,后面讲);
---2> 在接口实现类中实现方法,或者子类中重写父类方法;
---3> 多态对象向上转型成接口或父类;对外调用抽象方法
以上是多态使用的步骤。
为了加深对多态的理解,再举个例子:
1,接口相当于一家做家具的公司,对外广告:我公司可以做多种家具;
---声明接口和抽象方法;
2,实现类相当于公司员工模板,有做复古风格的,有做现代风格的。
---生成一个实现类,并重写方法,内容是;
3.当用户和公司订立合同时要做现代风格家具时,由能做现代风格家具的员工出来做。
---生成对象并向上转型,对外调用抽象方法
=========================================================================
4.继承
---继承的设计思想是代码复用; 还有一点,子类对象自动实现多态。
继承是Java的三大特征之一,继承的使用有以下三种情况:
第一种:子类可以调用父类方法,减少代码量。
第二种:子类重写父类方法后,可以使用多态;
第三种:子类有自己的方法,此时不能使用多态,但仍可以调用父类方法;
---继承的理解可以用两句形象话来概括: “上阵父子兵”和“你行你上”
1>上阵父子兵
---生成对象的同时,把父类对象也生成了,也包括了父类的父类对象,直到Object类对象。
代码层面上,每个构造方法隐式调用了super();
方法代表了一种具体功能,对象调用方法时候,可以调用父类的方法,直到Object类的方法。
2>你行你上
---如果子类对象重写了父类方法,则调用子类方法;否则调用父类方法
示例:
public class AnyTest2 {
public static void main(String[] args) {
SportsMan zs = new FootballPlayer("张三");
zs.action();
zs.eat();
// zs.goal(); //不能用
FootballPlayer lisi = new FootballPlayer("李四");
lisi.goal();
}
}
class SportsMan{
private String name;
public SportsMan(String name) {
this.name = name;
}
public void action(){
System.out.println("我叫"+getName()+",我可以运动");
}
public void eat(){
System.out.println("我叫"+getName()+",我可以吃饭");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class FootballPlayer extends SportsMan{
public FootballPlayer(String name) {
super(name);
}
public void action(){
System.out.println("我叫"+getName()+",我可以踢足球");
}
public void goal(){
System.out.println("我叫"+getName()+",我可以射门");
}
}
说明:
FootballPlayer是子类,父类是SportsMan;父类定义了两个方法action和eat,action被重写,eat没有重写;当子类对象去调用两个方法时,重写的方法用的是子类自己的;另一个未重写的方法调用了父类方法。
此外子类有自己独有的方法:goal,不能使用多态,必须由子类对象调用。
=========================================================================
5.继承的使用
继承可以看成加强版的多态;
---生成子类对象(一般不会直接生成父类对象,因为在子类对象生成的同时父类对象生成了),并根据实际情况调用子类对象方法或者父类对象方法;
继承很典型的用法:模板
示例:
package 模板模式;
public abstract class TemplateDemo {
public final void cookProcess() {
//第一步:倒油
this.pourOil();
//第二步:热油
this.heatOil();
//第三步:倒蔬菜
this.pourVegetable();
//第四步:倒调味料
this.pourSauce();
//第五步:翻炒
this.fry();
}
public void pourOil() {
System.out.println("倒油");
}
//第二步:热油是一样的,所以直接实现
public void heatOil() {
System.out.println("热油");
}
//第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心)
public abstract void pourVegetable();
//第四步:倒调味料是不一样
public abstract void pourSauce();
//第五步:翻炒是一样的,所以直接实现
public void fry(){
System.out.println("炒啊炒啊炒到熟啊");
}
}
class ConcreteClass_BaoCai extends TemplateDemo {
@Override
public void pourVegetable() {
System.out.println("下锅的蔬菜是包菜");
}
@Override
public void pourSauce() {
System.out.println("下锅的酱料是辣椒");
}
}
class ConcreteClass_CaiXin extends TemplateDemo {
@Override
public void pourVegetable() {
System.out.println("下锅的蔬菜是菜心");
}
@Override
public void pourSauce() {
System.out.println("下锅的酱料是蒜蓉");
}
}
class Client {
public static void main(String[] args) {
//炒手撕包菜
TemplateDemo baoCai = new ConcreteClass_BaoCai();
baoCai.cookProcess();
//炒蒜蓉菜心
TemplateDemo caiXin = new ConcreteClass_CaiXin();
caiXin.cookProcess();
}
}
代码说明:继承的综合运用。
共同的方法放在父类中,子类重写父类抽象方法,用子类对象调用父类方法,形成了模板。
以后要做部分变换的时候,不用修改主体程序,只需要更改局部部分,符合“开闭原则”
=========================================================================
6.封装
封装分为语法上的意义的封装--JavaBean,面向对象---编程思想上的封装
示例:
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
---封装有以下因素:
1>有参和无参构造方法;
2>属性私有化;
3>提供getter和setter方法
4>重写toString方法
语法层面的封装是约定俗成的,比较简单。
---OOP面向对象表达的封装,是核心内容之一。可以说理解了什么是封装,才算认识面向对象
打一个比方:对象是一个“角色”,对象方法是角色能实现的功能。程序调用一个个功能来组织。
Java应用层面在不断寻找适合的“角色”,即生成适合的对象,调用其方法来完成程序的构建。这大大方便了程序的组织和模块化。接口是抽象的“角色”,对象是具体的角色。使用时调用抽象的功能,具体角色由生成对象并转换成接口角色。
---封装的不足:无法了解底层怎么运作。和C语言做个比较,C语言历经几十年而不衰是有原因的,因为简洁,高效,理解容易。Java的api,都是由一个个方法所表现的,“粒度”更大。
JDK是由C语言和C++编写的,OpenJDK是开源项目,可以查看部分Java源代码,可见编程语言本质上相同,最终都要编程机器码交给CPU执行。
从面向过程到面向对象需要有个适应的过程,但不管是C或者Java,都是非常优秀的,都凝聚了无数前辈的思想结晶。