Java面向对象总结

怎么理解java面向对象 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 怎么理解Java面向对象,面向对象编程是当今主流的程序设计思想,已经取代了过程化程序开发技术,Java是完全面向对象编程语言,所以必须熟悉面向对象才能够编写Java程序。下面就来介绍一下什么是Java面向对象。   一、面向对象的概念   面向对象是一种符合人类思维习惯的编程思想。现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物使用对象的关系来描述事物之间的联系,这种思想就.. 阅读详情

Java 面向对象一览

111111010n

1100111

010000111100

101010套10010m0

JaVa面向对象一览



本文大纲:

总结

前言

与 C++ 比较

Java 语言特点

Java 语言简介

面向对象思想

重载与覆写

多态

序列化

类的定义

类关系

变量

内部类

方法

抽象类与接口

抽象

this 与 super

类继承

子类实例化过程

继承

getter 与 setter

包

访问权限控制

封装

面向对象基础

Java 面向对象一览


前言

学 Java 的朋友都知道,Java 是一门典型的面向对象的高级程序设计语言,但有些朋友可能不清楚面向对象在 Java 中是怎么体现的。这篇文章就向大家分享下 Java 在面向对象方面的一些知识。

Java 语言简介

Java 语言特点

首先我们看下 Java 的语言特点,如图所示。



Java 是纯粹的面向对象语言,它因统一的字节码文件和差异化的 JDK 而具有平台无关的特性。

Java 内置丰富的类库,使开发者效率大为提升。它支持 web,广泛应用于各大互联网企业的网站后台,像阿里美团都在使用。

Java 的安全性也很出众,通过沙箱安全模型保证其安全性,能够有效防止代码攻击。

Java 也具备很强的健壮性,比如它是强类型的,支持自动化的垃圾回收器,有完善的异常处理机制和安全检查机制。

与 C++ 比较

同样是面向对象的编程语言,Java 和 C++ 存在异同。

比较点

C++

Java

语言类型

编译型语言

解释编译混合型语言

执行速度

快

慢

是否跨平台

否

是

面向对象

面向对象和面向过程混合

纯面向对象

指针

有

无

多继承

支持

不支持

内存管理

手动

自动


从语言类型上看,C++ 的代码编译好,就能被计算机直接执行,它是编译型语言,而 Java 经过 javac 把 java 文件编译成 class 文件后,还需要 JVM 从 class 文件读一行解释执行一行,它是解释编译混合型语言。也就是中间多了 JVM 这一道,Java 也具备了跨平台特性,而 C++ 就没有这个优势。

从面向对象的角度上看,C++ 是在 C 的基础上的新的探索和延伸,因此它是面向对象和面向过程混合的,而 Java 就是纯粹的面向对象。

此外,C++ 有指针的概念,Java 没有。C++ 支持多继承,Java 不支持。C++ 需要手动进行内存管理,Java 通过垃圾回收机制实现了内存的自动管理。

面向对象思想

我们总在提面向对象,那面向对象究竟是个什么东西呢?在面向对象出现之前的面向过程又是怎么回事呢?

其实无论是面向对象还是面向过程,都是我们在编程时解决问题的一种思维方式。

只是在最初,人们分析解决问题的时候,会把所需要的步骤都列出来,然后通过计算机中的函数把这些步骤挨个实现,这种过程化的叙事思维,就是面向过程思想。

你比如,把一头大象放进冰箱,通常会怎么做呢?

我们的习惯性思维是会分为三步,第一步,把冰箱门打开,第二步,把大象推进去,第三步,把冰箱门关闭(假设大象很乖,冰箱很大,门能关住)。



这种方式固然可行,但当场景发生变化时,比如大象变成猪,冰箱变成衣柜,类似的步骤用面向过程编码的话就要再写一遍。这样就导致代码开发变成了记流水账,久而久之就成为面条代码。

我们仔细分析面向过程的这些步骤,会发现都是命令式的动宾结构:开冰箱门,推大象,场景切换下就是开衣柜门,推猪。你会发现从这两种场景下是可以找到共性的,就是冰箱门和衣柜门都有打开和关闭的特点,大象和猪都能走路,所以能被人推进去。

当我们的视角不再是流程,而是操作对象的时候,冰箱门和衣柜门都可以抽象成门,有打开和关闭的特点,大象和猪都可以抽象成动物,有走路的特点。按这个思路,我们可以把这件事简化成主谓结构:门打开,动物走进去,门关闭。

这种把事情分解成各个对象,描述对象在整个事情中的行为,就是面向对象思想。

你会发现,面向过程更讲事情的步骤,面向对象更讲对象的行为。

面向对象可以基于对象的共性做抽象,为软件工程的复用和扩展打好了坚实的基础。这也是为什么在很多大型软件开发选型上,大多会使用面向对象语言编程。

面向对象基础

Java 作为纯面向对象语言,我们有必要了解下面向对象的基础知识。

面向对象有四大特征,是抽象,封装,继承和多态。也有很多人认为是三大特征,不包括抽象,但我觉得抽象才是面向对象思想最为核心的特征,其他三个特征无非是抽象这个特征的实现或扩展。

我总结了下这四大特征在面向对象领域分别解决了什么问题,再逐一介绍:

●抽象:解决了模型的定义问题。
●封装:解决了数据的安全问题。
●继承:解决了代码的重用问题。
●多态:解决了程序的扩展问题。

抽象

抽象是面向对象的核心特征,良好的业务抽象和建模分析能力是后续封装、继承和多态的基础。

面向对象思维中的抽象分为归纳和演绎两种。

归纳是从具体到本质,从个性到共性,将一类对象的共同特征进行归一化的逻辑思维过程。比如我们把见到的像大象,老虎,猪这些能动的有生命的对象,归纳成动物。

演绎是从本质到具体,从共性到个性,将对象逐步形象化的过程。比如从生物到动物,从动物到鸟类。演绎的结果不一定是具体的对象,也可以是像鸟类这种抽象结果,因此演绎仍然是抽象思维,而非具象思维。


Java 中的 Object 类是任何类的默认父类,是对万物的抽象。这就是我们常说的:万物皆对象。

看一看 java.lang.Object 类的源码,我们基本能看到 Java 世界里对象的共同特征。

Object

staticclassinitializerregisterNatives);

registernatives:void

getclassO:Class?>

hashcode:Int

equals(object):boolean

clone(:Object

toStringO:String

notifyO:void

notifyAllO:void

wait(Iong):void

wait(long,it):void

waitO:void

FInALizeO:VoiD



getClass() 说明了对象是谁,toString() 是对象的名片,clone() 是繁殖对象的方式, finalize() 是销毁对象的方式,hashCode() 和 equals() 是判断当前对象与其他对象是否相等的方式,wait() 和 notify() 是对象间通信与协作的方式。

类的定义

除了 JDK 中提供的类之外,我们也可以基于自己业务场景的抽象定义类。

我们看下 Java 语法中的 class(类)是怎么构成的。

以下是概览图,我们按图介绍。



我们先关注图中的黄色区块,在 Java 里就叫 class(类)。

好比一个事物有属性和能力一样,比如人有名字,人能吃饭。对应到 Java class 里就是变量和方法,即红色区块和紫色区块。

变量分为成员变量,静态变量和局部变量三种,方法分为构造方法、实例方法和静态方法三种。

我们举个例子来说明下,假设全世界的面包数量就 100 个,并且生产已经停滞,而且只有蜗牛和小白两个人能吃到,我们就可以按以下的代码来描述这两个人吃面包的过程以及面包的情况。

package cn.java4u.oo;


/**
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public class Person {

    /**
     * [成员变量]需要被实例化后使用,每个实例都有独立空间,通过 对象.成员变量名 访问
     * 名字
     */
    String name;


    /**
     * [静态变量]用 static 修饰,无需实例化即可使用,每个实例共享同一个空间,通过 类名.静态变量名 访问
     * 面包数量
     */
    static int breadNum;

    /**
     * [方法]
     * 吃一个面包
     *
     * @param num 方法入参,要吃面包的个数
     */
    void eatBread(int num) {

        //  num 是[局部变量]
        breadNum = breadNum - num;

        System.out.println(name + "吃了 " + num + " 个面包,全世界的面包还剩 " + breadNum + " 个!");
    }

    /**
     * [构造方法]
     * 参数为空
     */
    public Person() {
    }

    /**
     * [构造方法]
     *
     * @param name 此为构造方法的输入参数,和成员变量有关
     */
    public Person(String name) {
        this.name = name;
    }

    /**
     * [静态方法]
     */
    static void testStaticMethod() {

        // 通过构造方法,初始化名字叫蜗牛的人
        Person woniu = new Person("蜗牛");

        // 通过构造方法,初始化名字叫小白的人
        Person xiaobai = new Person("小白");

        // 假设全世界的面包数量就 100 个,并且生产已经停滞
        Person.breadNum = 100;

        // 蜗牛吃五个面包
        woniu.eatBread(5);

        // 小白吃六个面包
        xiaobai.eatBread(6);

        // 打印成员变量和静态变量的值
        System.out.println(woniu.name + "和" + xiaobai.name + "吃饱后,世界只剩 " + Person.breadNum + " 个面包了!");

    }
}

变量

首先定义了一个名字叫 Person 的类,表示人,然后定义了一个成员变量 name ,表示人的名字。成员变量也叫实例变量,实例变量的特点就是,每个实例都有独立的变量,各个实例之间的同名变量互不影响。

其次定义了一个静态变量 breadNum ,表示面包的数量,静态变量用 static 修饰。静态变量相对于成员变量就不一样了,它是共享的,所有实例会共享这个变量。

方法

再接着定义了一个返回值为空,只有一个入参的方法 eatBread(int num) ,方法入参 num 作为局部变量参与了内部的运算,通过和它的运算,静态变量breadNum 的值得到了更新,并打印了一行操作信息。方法的语法结构如下:

修饰符 返回类型 方法名(方法参数列表) {
    方法语句;
    return 方法返回值;
}

另外定义了 Person 的构造方法,你会发现构造方法和实例方法的区别就在于它是没有返回值的,因为它的目的很纯粹,就是用来初始化对象实例的,和 new 搭配使用,所以它的方法名就是类名,它的入参也都和成员变量有关。

到这里,你会发现 Java 方法的返回值并不是那么重要,甚至没有都可以!是的,Java 方法签名只包括名称和参数列表,它们是 JVM 标识方法的唯一索引,是不包含返回值的,更不包括各种修饰符或者异常类型。

请注意,任何 class 都是有构造方法的,即便你代码里不写,Java 也会在编译 class 文件的时候,默认生成一个无参构造方法。但是只要你手动定义了构造方法,编译器就不会再生成。也就是说如果你仅定义了一个有参的构造方法,那么编译后的 class 是不会有无参构造方法的。

最后就是静态方法了,名字叫testStaticMethod ,方法内部我们先用 new 的语法调用构造方法,初始化了蜗牛和小白的Person 对象。这两个对象就是 Person 这个类的实例,这两个实例都有独立空间,name 这个成员变量也只能在被实例化后使用,可以通过 对象.成员变量名 访问。

接着我们通过 Person.breadNum 也就是 类名.静态变量名  的方式,更新了面包数量这个值。你会发现 breadNum 这个静态变量无需实例化就能使用,因为就这个变量而言,Person 的每个实例都会共享同一个空间。这意味着,每个实例的修改,都会影响到这个变量值的变化。

然后我们通过调用方法  eatBread 并传参的方式,影响到了面包数的值。

package cn.java4u.oo;

/**
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public class MainTest {

    public static void main(String[] args) {


        // 静态方法,通过 类名.静态方法名 访问
        Person.testStaticMethod();
    }
}

最后我们新定义一个触发调用的入口函数,通过 Person.testStaticMethod() 这样 类名.静态方法名 的方式就能访问到静态方法了。

抽象类与接口

抽象类顾名思义,就是会对同类事物做抽象,通常包括抽象方法、实例方法和成员变量。被抽象类和抽象类之间是 is-a 关系,这种关系要符合里氏替换原则,即抽象类的所有行为都适用于被抽象类,比如大象是一种动物,动物能做的事,大象都能做。代码定义也很简单,就是在 class 和抽象方法上加 abstract 修饰符。


 

package cn.java4u.oo;

/**
 * 抽象类
 *
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public abstract class AbstractClass {

    String name;

    /**
     * 实例方法
     *
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 抽象方法-操作
     *
     * @return 结果
     */
    public abstract String operate();
}

如果一个抽象类只有一个抽象方法,那它就等于一个接口。接口是要求被普通类实现的,接口在被实现时体现的是 can-do 关系,它表达了对象具备的能力。鸟有飞的能力,宇宙飞船也有飞的能力,那么可以把飞的能力抽出来,有单独的一个抽象方法。代码定义也比较简单,class 的关键字用 interface 来替换。

package cn.java4u.oo;

/**
 * 可飞翔
 *
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public interface Flyable {


    /**
     * 飞
     */
    void fly();
}

内部类

在 Java 源代码文件中,只能定义一个类目与文件名完全一致的公开类。如果想在一个文件里定义另外一个类,在面向对象里也是支持的,那就是内部类。


内部类分为以下四种:
●静态内部类:static class StaticInnerClass {}
●成员内部类:private class InstanceInnerClass {}
●局部内部类:class MethodClass {} ,定义在方法或者表达式内部
●匿名内部类:(new Thread() {}).start();

示例代码如下:


 

package cn.java4u.oo.innerclass;

/**
 * 内部类演示
 *
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public class InnerClassDemo {

    /**
     * 成员内部类
     */
    private class InstanceInnerClass {}

    /**
     * 静态内部类
     */
    static class StaticInnerClass {}

    public static void main(String[] args) {

        // 两个匿名内部类
        (new Thread() {}).start();
        (new Thread() {}).start();

        // 方法内部类
        class MethodClass {}

    }
}

编译后得到的 class 文件如下:

我们会发现,无论什么类型的内部类,都会编译生成一个独立的 .class 文件,只是内部类文件的命名会通过 $ 连接在外部类后面,如果是匿名内部类,会使用编号来标识。

类关系

关系是指事物之间有没有单向或者相互作用或者影响的状态。

类和类之间的关系分为 6 种:

  • 继承:extends(is-a)
  • 实现:implements(can-do)
  • 组合:类是成员变量(contains-a)
  • 聚合:类是成员变量(has-a)
  • 依赖:单向弱关系(使用类属性,类方法、作为方法入参、作为方法出参)
  • 关联:互相平等的依赖关系(links-a)

序列化

内存中的数据对象只有转换为二进制流才可以进行数据持久化和网络传输。

将数据对象转换成二进制流的过程称为对象的序列化(Serialization)。

将二进制流恢复为数据对象的过程称为反序列化(Deserialization)。

常见的序列化使用场景是 RPC 框架的数据传输。

常见的序列化方式有三种:

  1. Java 原生序列化。特点是兼容性好,不支持跨语言,性能一般。
  2. Hessian 序列化。特点是支持跨语言,性能高效。
  3. JSON 序列化。特点是可读性好,但有安全风险。

封装

封装是在抽象基础上决定信息是否公开,以及公开等级,核心问题是以什么样的方式暴露哪些信息。

抽象是要找到成员和行为的共性,成员是行为的基本生产资料,具有一定的敏感性,不能直接对外暴露。封装的主要任务是对成员、数据、部分内部敏感行为实现隐藏。

对成员的访问与修改必须通过定义公共的接口来进行,另外某些敏感方法或者外部不需要感知的复杂逻辑处理,一般也会进行封装。

像智能音箱,与用户交互的唯一接口就是语音输入,封装了内部的实现细节和相关数据。

设计模式七大原则之一的迪米特法则也说明了封装的要求,A 接口使用 B 接口,对 B 知道的要尽可能少。

包

包(package)这个名称就很明显体现了封装的含义,它能起到把一个模块封装到一起,并由几个接口开放给使用方。使用方只能看到接口信息,而看不到接口实现。另外包解决重名问题,相同类名在相同路径下是不允许的,切换包路径就可以起相同的类名。

访问权限控制

我们编写的程序要想让使用方,能看到一些信息,又不能看到另外一些信息,这就涉及到信息隐藏了。

信息隐藏是面向对象程序设计的重要特点之一,它可以防止类的使用者意外损坏数据,对任何实现细节所作的修改不会影响到使用该类的其它代码,也使类更易于使用。

那在 Java 里,实现信息隐藏的就是访问权限控制机制了。Java 的访问权限控制有 4 个访问修饰符:public、protected 、private 和缺省。可以使用这四个访问修饰符修饰类的成员,它们在不同位置的可访问性如下表所示。

位置\访问修饰符

public

protected

缺省

private

本类

可以

可以

可以

可以

本包

可以

可以

可以

不可以

子类

可以

可以

不可以

不可以

所有

可以

不可以

不可以

不可以

你会发现 public 不受任何限制,本类和非本类都可以随意访问(全局友好)。protected 本类及其子类可以访问(父子友好),同一个包中的其它类也可以访问(包内友好)。而缺省的时候,只有相同包中的类可以访问(包内友好)。private 只有本类可以访问,其余都不可以(类内友好)。

除了为类成员添加访问权限控制外,也可以在定义类的时候,为类添加访问修饰符,对类进行访问权限控制。不过对类使用的访问修饰符只有 public 和缺省两种,访问范围也分别是全局友好和包内友好。

getter 与 setter

为了让类成员不对外直接暴露,我们经常把成员变量的访问权限设置成 private,而成员值的访问与修改使用相应的 getter/setter 方法。而不是对 public 的成员进行读取和修改。

package cn.java4u.oo.packagedemo;

/**
 * getter 和 setter 演示
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public class GetterSetterDemo {

    /**
     * 成员变量私有化
     */
    private String name;

    /**
     * 公开方法获取成员变量值
     *
     * @return 名称
     */
    public String getName() {
        return name;
    }

    /**
     * 公开方法设置成员变量值
     *
     * @param name 名称
     */
    public void setName(String name) {
        this.name = name;
    }
}

继承

类继承

class 了解之后,我们考虑一个问题。如果两个 class,它们的变量和方法基本相同,仅仅是其中一个 class 会有一些自己特有的变量和方法,那么相同的那些变量和方法真的需要在两个 class 里都写一遍么?

比如一个表示学生的 class Student ,它相对于 class Person 只是多了一个分数 score  的成员变量,那还需要像下面这样,把 name 字段也定义一下么?

/**
 * 学生
 *
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public class Student {

    /**
     * 名字
     */
    String name;

    /**
     * 分数
     */
    int score;

}

这很明显带来了代码重复使用的问题!那能不能在 Student 中不写重复代码?

Java 里的继承这时候就派上用场了,继承是面向对象编程的一种强大机制,能够让子类继承父类的特征和行为,使得子类对象能够具有父类的实例变量和方法。

子类继承父类,父类派生子类。父类也叫基类,子类也叫派生类。

通常来讲,类的层次划分总是下一层比上一层更具体,并且包含上一层的特征,这样下层的类就能自动享有上层类的特点和性质。继承就是派生类自动地共享基类中成员变量和成员方法的机制。

在 Java 中,通过 extends 关键字实现继承,并且所有的类都是继承于 java.lang.Object ,所以这就是万物皆对象在 Java 里的真实写照。你可能会疑惑,自定义的类并没有 extends 关键字为什么还能继承 Object呢?这是因为这个类在 java.lang 包里,Java 已经默认支持了。

package cn.java4u.oo;

/**
 * 学生
 *
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public class Student extends Person {

    /**
     * 分数
     */
    int score;

}

知道了继承的基础概念后,我们看下继承有啥作用?

首先,继承是能够自动传播代码和重用代码的有力工具。它能在已有类上扩充新类,减少代码的重复冗余,也因为冗余度降低,一致性就得到了增强,从而提升了程序的可维护性。

其次,继承可以清晰体现出类与类之间的层次结构关系,提升了代码的可读性。

另外,继承是单方向的,即派生类可以继承和访问基类成员,但反过来就不行。而且 Java 只允许单一继承,也就是一个派生类不能同时继承多个基类,这和 C++ 是不同的。

在使用继承的时候,还要考虑到基类成员的访问控制权限。可以参考封装那块内容的访问权限控制介绍。

子类实例化过程

特别要说明的是,父类的构造方法是不能被子类继承的,即便它是 public 的。父类的构造方法负责初始化属于它的成员变量,而子类的构造方法只需考虑自己特有的成员变量即可,不必关注父类状况。

package cn.java4u.oo.inherit;

/**
 * 定义父类
 *
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public class Parent {


    /**
     * 构造方法
     */
    public Parent() {

        System.out.println("这是父类 Parent 的构造方法");
    }
}

package cn.java4u.oo.inherit;

/**
 * 定义子类
 *
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public class Child extends Parent {

    /**
     * 构造方法
     */
    public Child() {

        System.out.println("这是子类 Child 的构造方法");

    }
}

package cn.java4u.test;

import cn.java4u.oo.inherit.Child;

/**
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public class InheritTest {

    public static void main(String[] args) {

        Child child = new Child();
    }
}

因此,在实例化子类的对象时,Java 先是执行父类的构造方法,然后执行子类的构造方法。如果父类还有更上级的父类,就会先调用更高父类的构造方法,再逐个依次地将所有继承关系的父类构造方法全部执行。如果父类的构造方法执行失败,则子类的对象也将无法实例化。

上边的代码运行后,会输出:

这是父类 Parent 的构造方法
这是子类 Child 的构造方法

this 与 super

如果调用父类构造方法涉及到有参构造方法,可以使用 super 关键字来调用父类构造方法并传递参数。

说的 super,它还有一个能力,就是父类和子类的成员如果同名了,子类中默认只能访问自己的那个成员,想要访问父类成员,就可以通过 super.成员名 的语法实现。但这有个前提,就是父类的这个成员不能是 private 的。

与 super 相对的关键字是 this ,super 是指向当前对象的父类,而 this 是指向当前对象自己。this常用来区别成员变量和局部变量,比如下面这段代码,我加了个有参构造方法。

public class Parent {

    int a;

    /**
     * 构造方法
     */
    public Parent() {

        System.out.println("这是父类 Parent 的构造方法");
    }

    public Parent(int a) {
        this.a = a;
    }


}

多态

说完继承,我们再来聊聊多态!

多态字面上解释,就是程序可以有多个运行状态。

既然是运行状态,那其实更多的是强调方法的使用。

重载与覆写

方法在两种情况下使用会比较特别,一种是 overload(重载),overload 方法是本类内的新方法,方法名一样,但是参数的类型或数量不同。这种方法没有特殊的标识,通过类内方法是否重名判定。

另外一种就是 override(覆写),override 方法是继承关系下子类的新方法,方法签名和父类完全相同。这种方法都会有 @Override 注解的标识。


 

package cn.java4u.oo.polymorphism;

/**
 * 动物
 *
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public class Animal {


    /**
     * 与 eat(String food) 重载
     */
    public void eat() {
        System.out.println("Animal.eat");
    }

    /**
     * 与 eat() 重载
     *
     * @param food 食物
     */
    public void eat(String food) {
        System.out.println("Animal.eat: " + food);
    }

    /**
     * 覆写
     *
     * @return 字符串
     * @see java.lang.Object#toString
     */
    @Override
    public String toString() {
        return "Animal " + super.toString();
    }
}

举个例子,Animal 类里两个 eat 方法就互为重载方法,toString 方法就是相对于父类方法 java.lang.Object#toString 的覆写方法。

多态就发生在覆写这种场景下。针对某个类型的方法调用,它真正执行的方法取决于运行时期实际类型的方法。比如下面这段代码,当声明类型为 Object ,初始化类型为 Animal 时,你觉得输出的是 Animal 的 toString 方法,还是 Object 的 toString 方法?

package cn.java4u.oo.polymorphism;

/**
 * @author 蜗牛
 * @from 公众号:蜗牛互联网
 */
public class PolymorphismTest {

    /**
     * 打印对象
     *
     * @param scene 打印场景
     * @param obj   obj
     */
    public static void printObjectString(String scene, Object obj) {

        System.out.println(scene + ": " + obj.toString());

    }

    public static void main(String[] args) {

        // 父类引用初始化父类对象并打印
        Object rootObj = new Object();
        printObjectString("父类引用初始化父类对象", rootObj);

        // 子类引用初始化子类对象并打印
        Animal animal = new Animal();
        printObjectString("子类引用初始化子类对象", animal);


        // 父类引用初始化子类对象并打印
        Object animalWhenParentRef = new Animal();
        printObjectString("父类引用初始化子类对象", animal);
        
    }
}

答案是子类 Animal 的 toString 方法!

答案是子类 Animal 的 toString 方法!

实际类型为 Animal 引用类型为 Object ,调用 toString 方法时,实际上是子类的。因此我们可以得出结论:Java 的实例方法调用是基于运行时的实际类型的动态调用,而非变量的声明类型。这种特性就是多态!

你会发现 printObjectString 方法的第二个参数,即便声明的是 Object ,实际运行的时候,却可以是它的子类覆写方法。

至此,我们也理出了 Java 实现多态三要素,那就是 继承、覆写和向上转型。即两个类之间有继承关系,某个类覆写了父类的某个方法,方法的引用会指向子类的实现处。

总结

本文从 Java 的视角出发,分析了 Java 的语言特点,并和 C++ 进行了比较。针对这门典型的面向对象语言,我们又分析了面向对象的概念和思想。接着基于面向对象的特征:抽象、封装、继承和多态,我们又详细的分析了在 Java 中的体现方式,并伴有很多样例代码辅助学习。看完这篇文章,想必你对面向对象这个东西会有更全面的了解。

好啦,本期的分享就到这里,谢谢大家!

【Java基础知识 7】Java面向对象简介 面向对象是一种新兴的程序设计方法,或者是一种新的程序设计规范,其基本思想是使用对象、类、继承、封装、多态等基本概念来进行程序设计。 阅读详情

相关推荐

谈谈 FOC和BLDC 电机控制

更具体地说,通过 “Park 变换”,我们可以把三相交流电流信号转换成两相直流电流信号,从而可以把三相交流电机的控制变得和两相直流电机控制一样简单。在内环 “电流环”中,一些比较重要的模块有 “Clark 变换” 和 “Park 变换” 等数学模块、电机电流信号检测模块以及能够提供电机的转速和转角位置信息的模块。日前,Qorvo 电机控制应用高级系统/应用工程师张绍发表了一个与 BLDC 和 FOC 相关的演讲,科普了 FOC 的相关知识,还讲解了 Qorvo 用于简化 FOC 实施方案的方法。

U_YAO的博客 2116

java基础03-面向对象

面向过程(Procedural Programming)和面向对象(Object-Oriented Programming,简称 OOP)是两种不同的编程范式。面向对象是一种以对象为中心的编程思想。它将程序视为对象的集合,每个对象都有自己的状态(属性)和行为(方法)。在面向对象编程中,数据和操作是紧密相关的,并通过封装、继承和多态等机制实现代码的组织和复用。主要特点包括:1.以对象为核心:程序由多个相互交互的对象组成,每个对象都有自己的属性和方法。

quzhiyuan9的博客 1057

vue3+ts项目里如何使用状态管理pinia以及数据持久化

vue3 pinia 数据持久化

ICUiseeyou的博客 8793

java面向对象

万物皆对象。面向对象,是一种编程思想,是把一个整体的事物按照各个功能来进行划分。在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。 它区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。

m0_51779342的博客 4342

开源分享:苹果群控手机源代码解析与实战

本文介绍了苹果设备群控的基本原理和实现方法,重点解析了基于Python+Appium的群控系统构建。主要内容包括:1)设备连接管理技术(USB/Wi-Fi);2)自动化控制方式(WDA/AppleScript/Appium);3)实战演示了通过Python脚本实现多设备同时控制,涵盖环境配置、代码解析和功能说明;4)提出了多线程、图像识别等优化方向。文章为开发者提供了快速上手的群控方案,适用于自动化测试、批量管理等场景,并推荐了相关开源项目参考。

2403_88540309的博客 1344

Anaconda+清华源加速PyTorch GPU环境安装与CUDA版本匹配指南

深度学习环境管理常面临依赖冲突与下载缓慢问题,通过虚拟环境隔离与镜像源加速可显著提升效率。Anaconda利用conda机制创建独立Python环境,避免包版本冲突;清华源通过国内镜像同步大幅提高下载速度。GPU版PyTorch安装需严格匹配CUDA、cuDNN与显卡驱动版本,否则易出现CUDA不可用错误。该方案适用于图像分割、目标检测等需多版本PyTorch并存的场景,能快速搭建稳定GPU训练环境。本文详解Anaconda安装、清华源配置及PyTorch GPU版安装全流程。

weixin_30522983的博客 235

Java——面向对象

Java是一门纯面向对象的语言,在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。 面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。Java中有很多对象来自标准库,还有一部分由自己定义。从根本上说只要对象能够满足要求,就不必关心其功能的具体实现过程。在OOP中不必关心对象的具体实现,只要其能够满足用户的需求即可。

lqt214133的博客 9268

Python实现将txt文件转换成对应的excel或csv文件

此外,在上面的例子中,txt文件是以“空格”分隔的,如果遇到“逗号”分隔的,只需将上述代码中的。本文是该专栏的第29篇,后面会持续分享python的各种干货知识,值得关注。工作上可能会遇到这样的情况,使用python将某个txt文本,按照。转换成对应的excel文件或者是csv文件。”需要替换成你的目标txt文件的绝对路径。库,这里直接引用就好。需要注意的是,上述代码中的“

Python进阶专栏《爬虫实战进阶》,《Pyppeteer从入门到精通》原创作者 4506

Java面向对象

Java面向对象

qq_43599841的博客 1401

把 SM30 用顺:从表设计到权限与传输,全面掌握 SAP Table Maintenance Generator

摘要 SAP的Table Maintenance Generator(TMG)是为配置表维护需求设计的经典工具,能够生成标准化的维护对话框(SM30)。它支持单表、维护视图(多表关联)和视图簇(导航式维护)三种维护对象类型。使用TMG前需注意三个关键设置:1)表维护权限选项;2)交付类(决定数据传输行为);3)客户端字段配置。通过SE54/SE11生成维护对话框时,需选择维护类型(一步/两步)和记录例程(控制传输)。TMG生成的对象包含函数组、屏幕和处理模块,但部分标准框架不可修改。实际应用中,可通过参数事

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 176

量化 insider 爆料! 散户打板必亏?(打板必看!量化资金如何“隔日砸盘”收割散户)

量化开发 insider 爆料💥 散户追的涨停板📉,可能是机构故意做的陷阱!本文从技术视角拆解“涨停陷阱”,帮你看清市场真实逻辑🧠。

XiaoqiangClub的博客 450

【Java面向对象学习】一张图搞定Java面向对象

刚开始学习Java的时候,一个人跌跌撞撞摸索着往前走,很多东西理解的也懵懵懂懂,后来实践的多了,才慢慢清楚;许多东西虽然很基础但是却很重要,是需要反复思考和加深理解的。【Java面向对象学习】一张图搞定Java面向对象,分享一些归纳总结后的技术干货,一张图能搞定的事,绝对不长篇大论。 大家都知道,Java面向对象是Java的一个核心,也是初学者的一个难点,所以我们从这里开始,Let’s go

monkey518的博客 4509

HFSS 3D Layout仿真PCB操作说明

本文介绍一种特别适合PCB这种叠层结构的仿真软件,HFSS 3D Layout既有操作的简便性,又有同3D软件仿真所有的精确性,仿真速度上又比3D软件快很多。

sinat_15150363的博客 3938

Java——Java面向对象

Java是面向对象的程序设计语言,Java语言提供了定义类、成员变量、方法等最基本的功能。类可被认为是一种自定义的数据类型,可以使用类来定义变量,所有使用类定义的变量都是引用变量,它们将会引用到类的对象。类用于描述客观世界里某一类对象的共同特征,而对象则是类的具体存在,Java程序使用类的构造器来创建该类的对象。继承是面向对象的三大特征之一,也是实现软件复用的重要手段。Java的继承具有单继承的特点,每个子类只有一个直接父类。

qq_16027093的博客 2528

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

JAVA面向对象是什么?

JAVA面向对象面向对象?What???什么是对象(Object)?什么是面向对象?面向对象有什么特征? 面向对象?What??? 众所周知 Java是一种面向对象的语言,那么什么是面向对象? 什么是对象(Object)? 对象就是具有某些的特殊属性(成员变量)和行为方式(方法)的实体。 现实生活中的任何事物都可以看作是对象,无论是具体或抽象的事物,Java中就有了一种思想叫做“万物皆对象”...

weixin_44684812的博客 9944

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

JAVA面向对象

抽象类不能加final修饰,Java中的抽象类是用来被继承的,而final修饰符用于禁止类被继承或方法被重写,因此,抽象类和final修饰符是互斥的,不能同时使用。方法名、参数列表和返回类型必须与父类中的方法一致,通过@override注解来明确表示这是对父类方法的重写。是代码复用的重要手段,通过继承可以建立类与类之间的层次关系,使得结构更加清晰。简而言之,抽象类不能直接实例化,但通过继承抽象类并实现所有抽象方法的子类是可以被实例化的。封装是指将对象的属性(数据)和行为(方法)结合在一起。

weixin_62658327的博客 1776

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Java笔记——Java——面向对象_java面向对象

文章目录一. 面向对象编程Java核心思想就是OOP1. 面向过程&面向对象区别1.1 从语言方面出发对于C语言来说,是完全面向过程的 对于C++语言来说,是一半面向过程,一半面向对象。 对于Java语言来说,是完全面向对象的1.2 面向过程的开发方式面向过程思想(线性思维)特点:步骤清晰简单,第一步做什么,第二步做什么…面向过程也注重实现功能的因果关系,因为A所以B,因为B所以C面对过程适合处理一些较为简单的问题缺点:面向过程最主要是每一步与每一步的因果关系,其中A步骤因果关系关系到B步骤,A和B联合起来

a25847a的博客 1161

Java面向对象专题

Java面向对象专题解读

从知识输入到知识输出 4264

Java笔记——Java面向对象

1. 面向对象简介学习面向对象会涉及到很多专有的名词,比如类与对象、继承、抽象、接口、多态、封装等等,很多人在学习时过于关注这些名词的概念,会觉得概念很多很绕,就说面向对象很难,其实不是这样的,要与现实场景相结合来学习Java面向对象. 面向对象思想 首先我们来了解一下什么是面向对象思想?这里说的思想,你可以理解为解决问题的方式。比如说我想吃蛋炒饭,这是我的目的,为了实现这个目的,我们有不同的解决问题的方式。如果我是一个勤快的人,自己动手做蛋炒饭,你需要先打鸡蛋——准备葱花——放油——在锅里翻炒——最后出锅

a25847a的博客 703

Java之面向对象

面向对象 一、基础概念 1、什么是面向对象 万事万物皆可是对象,而了解对象的详细信息,并关注它,这个过程就叫面向对象。面向一个具体的事物进行操作,便面向对象编程。                                                                      因为你不会Java啊,来Java中new一个呀,不就有了? 2、Java中的对象 用来描述一个实体,通常由一组属性和对这组属性进行的操作组成。 对象的产生:通过对类的实例化。 对象的”一生“:生成、使用、

qq_43325476的博客 1701

Java 面向对象一览

作者:白色蜗牛公众号:蜗牛互联网本文大纲:前言学 Java 的朋友都知道,Java 是一门典型的面向对象的高级程序设计语言,但有些朋友可能不清楚面向对象在 Java 中是怎么体现的。这篇...

程序员蜗牛 548
上一篇: iOS延时执行 - performSelector
下一篇: 其实Servlet很简单,掌握了编程思想,解决问题才是硬道理
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值