Java思想之面向对象基础概念

第一:什么是对象

我们可理解 纯粹 的面向对象程序设计方法是什么样的:
(1) 所有东西都是对象。可将对象想象成一种新型变量;它保存着数据,但可要求它对自身进行操作。理论 上讲,可从要解决的问题身上提出所有概念性的组件,然后在程序中将其表达为一个对象。
(2) 程序是一大堆对象的组合;通过消息传递,各对象知道自己该做些什么。为了向对象发出请求,需向那个对象“ 发送一条消息 ”。更具体地讲,可将消息想象为一个调用请求,它调用的是从属于目标对象的一个子例程或函数。
(3) 每个对象都有自己的存储空间,可容纳其他对象。或者说,通过封装现有对象,可制作出新型对象。所 以,尽管对象的 概念非常简单,但在程序中却可达到任意高的复杂程度。
(4) 每个对象都有一种类型。根据语法,每个对象都是某 个 的一个 实例 。其中, Class) 是 类型 Type )的同义词。一个类最重要的特征就是 “能将什么消息发给它?

第二:接口

在这个例子中,类型/类的名称是 Light ,可向 Light 对象发出的请求包括包括打开(on)、关闭(off)、 变得更明亮(brighten)或者变得更暗淡(dim )。

通过简单地声明一个名字(lt),我们为 某个对象创建 了一个“句柄”。然后用 new 关键字新建类型为 Light 的一个对象。再用等号将其赋给句柄 lt。为了向对象发 送一条消息,我们列出句柄名(lt),再用一个句点符号(.)把它同消息名称(on)也可以是属性。连接起来。从中可以看 出,使用一些预先定义好的类时,我们在程序里采用的代码是非常简单和直观的。

第三:方案的隐藏

对客户程序员来讲,最主要的目标就是收集一个充斥着各种类的编程 工具 箱”,以 便快速开发符合自己要求的应用。而对类创建者来说,他们的目标则是从头构建一个类,只向客户程序员开放有必要开放的东西(接口),其他所有细节都隐藏起来。
促使我们控制对成员的访问。第一个原因是防止程序员接触 他们不该接触的东西——通常是 内部数据类型的设计思想。若只是为了解决特定的问题,用户只需操作接口即可,毋需明白这些信
息。我们向用户提供的实际是一种服务,因为他们很容易就可看出哪些对自己非常重要,以及哪些可忽略不计。
进行访问控制的第二个原因是允许库设计人员修改内部结构,不用担心它会对客户程序员造成什么影响。例如,我们最开始可 能设计了一个形式简单的类,以便简化开发。以后又决定进行改写,使其更快地运行。若接口与实现方法早已隔离开,并分别受到保护,就可放心做到这一点,只要求用户重新链接一下即可。
Java 采用三个显式(明确)关键字以及一个隐式(暗示)关键字来设置类边界:public,private,
protected 以及暗示性的 friendly。
若未明确指定其他关键字,则默认为后者。这些关键字的使用和含义都 是相当直观的,它们决定了谁能使用后续的定义内容。
“public”(公共)意味着后续的定义任何人均可使用。而在另一方面,
“private”(私有)意味着除您自己、类型的创建者以及那个类型的内部函数成员他任何人都不能访问后续的定义信息。
 

第四:方案的封装以及重复使用

创建并测试好一个类后,它应(从理想的角度)代表一个有用的代码单位。但并不象许多人希望
的那样,这 种重复使用的能力并不容易实现;它要求较多的经验以及洞察力,这样才能设计出一个好的方案,才有可能重复使用
为重复使用一个类,最简单的办法是仅直接使用那个类的对象。但同时也能将那个类的一个对象置入一个新 类。我们把这叫作 创建一个成员对象 ”。新类可由任意数量和类型的其他对象构成。

访问权限修饰符

Java 访问权限修饰符 publicprotected 和 private 位于定义的类名,属性名和方法名之前。每个访问权限修饰符只能控制它所修饰的对象。

public: 接口访问权限

当你使用关键字 public,就意味着紧随 public 后声明的成员对于每个人都是可用的,尤其是使用类库的客户端程序员更是如此。

private: 你无法访问

关键字 private 意味着除了包含该成员的类,其他任何类都无法访问这个成员。同一包中的其他类无法访问 private 成员,因此这等于说是自己隔离自己。另一方面,让许多人合作创建一个包也是有可能的。使用 private,你可以自由地修改那个被修饰的成员,无需担心会影响同一包下的其他类

public class PrivateDemo {
    private PrivateDemo() {
    }

    public static PrivateDemo makePrivateDemo() {
        System.out.println("makePrivateDemo======");
        return new PrivateDemo();
    }
}

因为PrivateDemo的构造函数为私有的,所以不能通过new一个对象直接创建PrivateDemo对象

//        PrivateDemo中的构造函数为private   不能通过构造函数生成对象
        PrivateDemo privateDemo = new PrivateDemo();

所以只能通过makePrivateDemo()方法创建对象

        PrivateDemo privateDemo2 = PrivateDemo.makePrivateDemo();

protected: 继承访问权限

要理解 protected 的访问权限,我们在内容上需要作一点跳跃。首先,在介绍本书"复用"章节前,你不必真正理解本节的内容。但为了内容的完整性,这里作了简要介绍,举了个使用 protected 的例子。

在理想世界中,仅靠关键字 private 就足够了。在实际项目中,却经常想把一个事物尽量对外界隐藏,而允许派生类的成员访问。

关键字 protected 就起这个作用。它表示“就类的用户而言,这是 private 的。但对于任何继承它的子类或在同一包中的类,它是可访问的。”(protected 也提供了包访问权限)

public class PrivateDemo2 extends PrivateDemo{
    public static String a = PrivateDemo.x;

    public PrivateDemo2(){
        System.out.println("PrivateDemo2==="+a);
    }
}

类定义的其他部分看起来是一样的。

如果你创建了一个新包,并从另一个包继承类,那么唯一能访问的就是被继承类的 public 成员。(如果在同一个包中继承,就可以操作所有的包访问权限的成员。)有时,基类的创建者会希望某个特定成员能被继承类访问,但不能被其他类访问。这时就需要使用 protectedprotected 也提供包访问权限,也就是说,相同包内的其他类可以访问 protected 元素。

public class PrivateDemo {

    public PrivateDemo(){

    }

    protected  static String x="protected";
}

执行代码

 PrivateDemo2 privateDemo2 = new PrivateDemo2();

Demo2成功获取到了父类Demo1中由protect修饰的值

个人理解(在创建一个类的时候,可以根据不同的需求编写多个不同参数的构造函数来进行生成所需要的对象,在调用该类的构造方法创建所需对象时,写入不同的参数就可以在不影响原始对象的数据结构的基础上创造出自己所需要的对象,进一步增加了代码的灵活性

第五节:继承(重新使用接口)

就其本身来说,对象的概念可为我们带来极大的便利。它在概念上允许我们将各式各样数据和
功能封装到一 起。这样便可恰当表达 “问题空间”的概念,不用刻意遵照基础机器的表达方式。在程序设计语言中,这些概念则反映为具体的数据类型(使用 class 关键字)。
在开发过程中,我们费尽心思做出一种数据类型后,假如不得不又新建一种类型,但是其实现大致功能与第一种数据科学的功能并相差无几。那会是一件非常令人头疼麻烦的事情。但若能利 用现成的数据类型,对其进行 克隆 ”,再根据情况进行添加和修改,情况就显得理想多了。
于是乎“继承”这个概念就产生了,但是继承并不是完全等价于对数据类型进行克隆,在继承过程中如果父类(即被继承的那个数据类型)发生了变化,那么子类(即实现继承的那个数据类型)中继承的父类的数据也会跟着一起发生变化
父类的私有方法不能提供给子类调用:
父类中有private、public、protected 变量可以提供子类

继承能给我们带来的优势是,他能省去许多相似的代码,对于那些具有相同属性的类别,通过继承,我们就不需要去为每一个类单独去编写他们的属性与方法,省去了许多繁杂步骤,同时也能使得我们的代码简便易理解, 但是我们需要注意的是,继承不能是多继承的,java中的类除了继承了java本身的类之外,他只能再继承一个父类,(可以理解为亲生父亲就只有一个,不会有第二个一样就是public class 子类名 extends 父类名1 父类名2…… )这样继承的话java会报错,

第六节:多态

void doStuff(Shape s) {
s.erase();
// ... s.draw();}
Circle c = new Circle(); 
Triangle t = new Triangle(); 
Line l = new Line(); 
doStuff(c);
doStuff(t);
doStuff(l);

上述代码中Circle Triangle Line都是继承于Shape(形状)

doStuff()期望接受的是一个Shape类型的函数,但是Circle Triangle Line都是继承于Shape,即都是一种形状,所以doStuff()函数能够正确接受对象并进行处理。

我们将这种把衍生类型当作它的基本类型处理的过程叫作 Upcasting (上溯造型)。其中, “cast”(造 型)是指根据一个现成的模型创建;而 “Up” (向上)表明继承的方向是从 “上面 来的 ——即基础类位于 顶部,而衍生类在下方展开。所以,根据基础类进行造型就是一个从上面继承的过程, “Upcasting”

1:动态绑定

观察doStuff()函数。
注意它并未这样表达: 如果你是一个 Circle,就这样做;如果你是一个 Square ,就那样做;等等 ”。若那 样编写代码,就需检查一个 Shape 所有可能的类型,如圆、矩形等等。这显然是非常麻烦的,而且每次添加 了一种新的 Shape 类型后,都要相应地进行修改。在这段代码中,我们只需说: “你是一种几何形状,我知道你能 将自己删掉,即 erase();请自己采取那个行动,并自己去控制所有的细节吧。
我们确实可以保证最终会为 Shape 调用 erase() ,为 Shape 调用 draw(),但并不能保证为特定 的 Circle Square 或者 Line 调用什么。然而最后采取的操作同样是正确的,这是怎么做到的呢? 将一条消息发给对象时,如果并不知道对方的具体类型是什么,但采取的行动同样是正确的,这种情况就叫 作“ 多态性 ”(Polymorphism)。对面向对象的程序设计语言来说,它们用以实现多形性的方法叫作“ 动态 绑定

2:抽象的基础类和接口

设计程序时,我们经常会从一个大的类细分为许多小的类(即将食物类划分为肉类,蔬菜类,水果类等)
也就是说,我们不想其他任何人实际 创建基础类的一个对象,只对上溯造型成它,以便使用它们接口。为达到这个目的,需要把那个类变成抽象类— 使用 abstract 关键字。
若父类中定义了一个 抽象方法要求其所有非抽象子类都必须重写该抽象方法
!!!!----抽象类不能被实例化,只能被继承(即不能使用new关键字将其创建)

如果某个类继承了一个抽象类,那么这个类有两个选择——要么实现父类所有的抽象方法,要么子类本身也定义成抽象类。当然,肯定也不会是想定义成抽象类就定义成抽象类的,要满足我们我们上面所说的定义抽象类的条件——即类中提供的信息不足以描述一个对象,或者类中有无法确定的行为需要延迟到子类实现。

 

abstract public class Animal {

    private static final String TAG = Animal.class.getSimpleName();
    private int legs;
    private String head;
    private String body;
    private String tail;

    static {

        System.out.println("Animal static: ");

    }
    public Animal() {
        System.out.println("Animal 构造方法:");

    }
    public abstract void eat();
    public abstract void move();

}
package knowledge.polymorphism.about_abstract.character;
 
public abstract class Food {            /** 父类 : Food类 */
    //记住,抽象方法没有方法体
    public abstract void showNutrition();
}
 
class Meat extends Food {               /** 子类 : Meat类 */
    @Override
    public void showNutrition() {        /** 实现继承food类的子类共有的抽象方法 */
        System.out.println("肉类是人体获取蛋白质、脂肪重要来源。");
    }

    public void cooking(){           /** 肉类区别于水果类新加的具体实现的方法 */
         System.out.println("肉类一般搭配蔬菜一起进行烹饪");
    }
}
 
abstract class Fruit extends Food {     /** 子类 : Fruit类 */
     @Override
     public void showNutrition() {      /** 实现继承food类的子类共有的抽象方法 */
        System.out.println("水果是人体获取维生素的重要来源。");
    }
}
    
class Test {                            /** 测试类 : Test类 */
    public static void main(String[] args) {
        Meat meat = new Meat();
        meat.showNutrition();
    }
}

注意!!!!如果某个类中已经出现了抽象方法,那这个类必须定义成抽象类。

拥有抽象方法的类一定是抽象类;但是抽象类不一定有抽象方法。

总结:
  1. 继承继承是从已有类得到继承信息创建新类的过程
  2. 封装:封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口
  3. 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应
  4. 抽象类:抽象类不能被实例化,只能被继承,拥有抽象方法的类一定是抽象类;但是抽象类不一定有抽象方法
  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值