Java 是面向对象的高级编程语言,类和对象是 Java 程序的构成核心。围绕着 Java 类和 Java 对象,有三大基本特性:封装是 Java 类的编写规范、继承是类与类之间联系的一种形式、而多态为系统组件或模块之间解耦提供了解决方案。

  本文主要围绕这三大特性介绍一下 Java 面向对象、组件解耦的核心思想。

1、面向对象思想

  面向对象编程是当今主流的程序设计思想,已经取代了过程化程序开发技术,Java 是完全面向对象编程语言,所以必须熟悉面向对象才能够编写 Java 程序。

  面向对象的程序核心是由对象组成的,每个对象包含着对用户公开的特定功能和隐藏的实现部分。程序中的很多对象来自 JDK 标准库,而更多的类需要我们程序员自定义。

  从理论上讲,只要对象能够实现业务功能,其具体的实现细节不必特别关心。

  面向对象有以下特点:

  (1)面向对象是一种常见的思想,比较符合人们的思考习惯;

  (2)面向对象可以将复杂的业务逻辑简单化,增强代码复用性;

  (3)面向对象具有抽象、封装、继承、多态等特性。

  面向对象的编程语言主要有:C++、Java、C#等。

2、类和对象的关系

  类:

  对某类事物的普遍一致性特征、功能的抽象、描述和封装,是构造对象的模版或蓝图,用 Java 编写的代码都会在某些类的内部。类之间主要有:依赖、聚合、继承等关系。

  对象:

  使用 new 关键字或反射技术创建的某个类的实例。同一个类的所有对象,都具有相似的数据(比如人的年龄、性别)和行为(比如人的吃饭、睡觉),但是每个对象都保存着自己独特的状态,对象状态会随着程序的运行而发生改变,需要注意状态的变化必须通过调用方法来改变,这就是封装的基本原则。

3、封装思想

  核心思想就是“隐藏细节”、“数据安全”:将对象不需要让外界访问的成员变量和方法私有化,只提供符合开发者意愿的公有方法来访问这些数据和逻辑,保证了数据的安全和程序的稳定。

  具体的实现方式就是:

  使用 private 修饰符把成员变量设置为私有,防止外部程序直接随意调用或修改成员变量,然后对外提供 public 的 set 和 get 方法按照开发者的意愿(可以编写一些业务逻辑代码,虽然很少这样做)设置和获取成员变量的值。

  也可以把只在本类内部使用的方法使用 private,这就是封装的思想,是面向对象最基本的开发规范之一。

  在此,我们有必要说一下 Java 的访问权限修饰关键字。Java 中主要有 private、protected、public 和 默认访问权限 四种:

  public 修饰符,具有最大的访问权限,可以访问任何一个在 CLASSPATH 下的类、接口、异常等。

  protected 修饰符,主要作用就是用来保护子类,子类可以访问这些成员变量和方法,其余类不可以。

  default 修饰符,主要是本包的类可以访问。

  private 修饰符,访问权限仅限于本类内部,在实际开发过程中,大多数的成员变量和方法都是使用 private 修饰的。

  

  Java 的访问控制是停留在编译层的,只在编译时进行访问权限检查,不会在类文件中留下痕迹。

  通过反射机制,还是可以访问类的私有成员的。

  我们举个小例子:

 1 public class MobilePhone {
2
3 // 使用 private 关键字把成员变量私有化
4 private String os;
5 private String phoneNumber;
6 private String brand;
7 private double dumpEnergy;
8
9 // 对外提供访问、设置成员变量的 public 方法
10 // 这样就可以按照我们自己的意愿来访问、设置成员变量
11 // 而且也有助于在方法内部对数据有效性进行验证
12 public void setOs(String os){
13 this.os = os;
14 }
15 public String getOs(){
16 return this.os;
17 }
18 public void setPhoneNumber(String phoneNumber){
19 this.phoneNumber = phoneNumber;
20 }
21 public String getPhoneNumber(){
22 return this.phoneNumber;
23 }
24 public void setBrand(String brand){
25 this.brand = brand;
26 }
27 public String getBrand(){
28 return this.brand;
29 }
30 public void setDumpEnergy(double dumpEnergy){
31 this.dumpEnergy = dumpEnergy;
32 }
33 public double getDumpEnergy(){
34 return this.dumpEnergy;
35 }
36
37 // 发短信的方法,不需要做修改
38 public void sendMessage(String message, String targetPhoneNumber){
39 System.out.println("发给" + targetPhoneNumber + ", 内容是:" + message);
40 }
41
42 // 充电方法,不需要做修改
43 public double charge(){
44 System.out.println("正在充电, 剩余电量:" + dumpEnergy * 100 + "%");
45 return dumpEnergy;
46 }
47
48 // 对外提供的开机方法
49 public void startup(){
50 System.out.println("正在开机......");
51
52 // 调用私有开机方法
53 startup2();
54
55 System.out.println("完成开机");
56 }
57
58 // 私有的开机方法,封装开机细节
59 private void startup2(){
60 System.out.println("启动操作系统......");
61 System.out.println("加载开机启动项......");
62 System.out.println("......");
63 }
64 }

  在实际的开发过程中,这样的封装方式已经成了 Java Bean 代码编写的规范。现在主流的框架在使用反射技术为对象赋值、取值时使用的都是 set 和 get 方法,而不是直接操作字段的值。

4、继承和类实例化过程

  (1)在多个不同的类中抽取出共性的数据和逻辑,对这些共性的内容进行封装一个新的类即父类(也叫做超类或基类),让之前的类来继承这个类,那些共性的内容在子类中就不必重复定义,比如 BaseDAO、BaseAction 等。

  * (2)Java 的继承机制是单继承,即一个类只能有一个直接父类。

  * (3)如果子类和父类有同名成员变量和方法,子类可以使用 super 关键字调用父类的成员变量和方法,上述使用方式前提是成员在子类可见。

  * (4)在调用子类构造方法时,会隐式的调用父类的构造方法 super()。如果父类没有无参构造方法,为了避免编译错误,需要在子类构造方法中显式的调用父类的含参构造方法。

  (5)子类创建时调用父类构造方法:子类需要使用父类的成员变量和方法,所以就要调用父类构造方法来初始化,之后再进行子类成员变量和方法的初始化。因此,构造方法是无法覆盖的。

  * (6)当子类需要扩展父类的某个方法时,可以覆盖父类方法,但是子类方法访问权限必须大于或等于父类权限。

  (7)继承提高了程序的复用性、扩展性,也是 Java 语言多态特征的前提。

  (8)在实际开发、程序设计过程中,并非先有的父类,而是先有了子类中通用的数据和逻辑,然后再抽取封装出来的父类。

  我们简单了解下类的实例化过程

  (1)JVM 读取指定 classpath 路径下的 class 文件,加载到内存,如果有直接父类,也会加载父类;

  (2)堆内存分配空间;

  (3)执行父类、子类静态代码块;

  (4)对象属性进行默认初始化;

  (5)调用构造方法;

  (6)在构造方法中,先调用父类构造方法初始化父类数据;

  (7)初始化父类数据后,显示初始化,执行子类的构造代码块;

  (8)再进行子类构造方法的特定初始化;

  (9)初始化完毕后,将地址赋值给引用

  为了说明上面的内容,我们来编写一个简单的例子,实际意义并不大,只是为了演示类继承实例化的过程。

 public class MobilePhone {
2
3 // 使用 private 关键字把成员变量私有化
4 private String os;
5 private String phoneNumber;
6 private String brand;
7 private double dumpEnergy;
8
9 // 对外提供访问、设置成员变量的 public 方法
10 // 这样就可以按照我们自己的意愿来访问、设置成员变量
11 // 而且也有助于在方法内部对数据有效性进行验证
12 public void setOs(String os){
13 this.os = os;
14 }
15 public String getOs(){
16 return this.os;
17 }
18 public void setPhoneNumber(String phoneNumber){
19 this.phoneNumber = phoneNumber;
20 }
21 public String getPhoneNumber(){
22 return this.phoneNumber;
23 }
24 public void setBrand(String brand){
25 this.brand = brand;
26 }
27 public String getBrand(){
28 return this.brand;
29 }
30 public void setDumpEnergy(double dumpEnergy){
31 this.dumpEnergy = dumpEnergy;
32 }
33 public double getDumpEnergy(){
34 return this.dumpEnergy;
35 }
36
37 // 发短信的方法,不需要做修改
38 public void sendMessage(String message, String targetPhoneNumber){
39 System.out.println("发给" + targetPhoneNumber + ", 内容是:" + message);
40 }
41
42 // 充电方法,不需要做修改
43 public double charge(){
44 System.out.println("正在充电, 剩余电量:" + dumpEnergy * 100 + "%");
45 return dumpEnergy;
46 }
47
48 // 对外提供的开机方法
49 public void startup(){
50 System.out.println("正在开机......");
51
52 // 调用私有开机方法
53 startup2();
54
55 System.out.println("完成开机");
56 }
57
58 // 私有的开机方法,封装开机细节
59 private void startup2(){
60 System.out.println("启动操作系统......");
61 System.out.println("加载开机启动项......");
62 System.out.println("......");
63 }
64 }
  1 /*
2 父类
3 */
4 class Parent {
5
6 int num = 5;
7
8 static {
9 System.out.println("父类静态代码块");
10 System.out.println();
11 }
12
13 {
14 System.out.println("父类构造代码块1," + num);
15 num = 1;
16 System.out.println("父类构造代码块2," + num);
17 doSomething();
18 System.out.println();
19 }
20
21 Parent() {
22 System.out.println("父类构造方法1," + num);
23 num = 2;
24 System.out.println("父类构造方法2," + num);
25 doSomething();
26 System.out.println();
27 }
28
29 void doSomething() {
30 System.out.println("父类doSomething方法1," + num);
31 num = 3;
32 System.out.println("父类doSomething方法2," + num);
33 System.out.println();
34 }
35 }
36
37 /*
38 子类
39 */
40 class Child extends Parent {
41
42 int num = 10;
43
44 /*
45 静态代码块,在类加载时执行
46 */
47 static {
48 System.out.println("子类静态代码块");
49 System.out.println();
50 }
51
52 /*
53 构造代码块
54 */
55 {
56 System.out.println("子类构造代码块1," + num);
57 num = 11;
58 System.out.println("子类构造代码块2," + num);
59 doSomething();
60 System.out.println();
61 }
62
63 Child() {
64 System.out.println("子类构造方法1," + num);
65 num = 12;
66 System.out.println("子类构造方法2," + num);
67 doSomething();
68 System.out.println();
69 }
70
71 void doSomething() {
72 System.out.println("子类doSomething方法1," + num);
73 num = 13;
74 System.out.println("子类doSomething方法2," + num);
75 System.out.println();
76 }
77
78 }
79
80 public class A {
81 public static void main(String[] args) {
82 Child child = new Child();
83 child.num = 20;
84 child.doSomething();
85 }
86 }
87
88 输出:
89
90 父类静态代码块
91
92 子类静态代码块
93
94 父类构造代码块1,5
95 父类构造代码块2,1
96 子类doSomething方法1,0
97 子类doSomething方法2,13
98
99
100 父类构造方法1,1
101 父类构造方法2,2
102 子类doSomething方法1,13
103 子类doSomething方法2,13
104
105
106 子类构造代码块1,10
107 子类构造代码块2,11
108 子类doSomething方法1,11
109 子类doSomething方法2,13
110
111
112 子类构造方法1,13
113 子类构造方法2,12
114 子类doSomething方法1,12
115 子类doSomething方法2,13
116
117
118 子类doSomething方法1,20
119 子类doSomething方法2,13

5、多态、反射和组件解耦

  多态指允许不同类的对象对同一“消息”做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。可以用于消除类型之间的耦合关系,Spring 的核心就是多态和面向接口编程。

  (1)Java 中可以使用父类、接口变量引用子类、实现类对象;

  (2)在这个过程中,会对子类、实现类对象做自动类型提升,其特有功能就无法访问了,如果需要使用,可以做强制类型转换。

  Java 的反射技术和多态特性是框架开发、组件解耦的核心,在这方面,Spring 的 IOC 和 DI 为我们提供了一个极好的学习范例,Spring 的 IOC 使用反射技术创建、管理对象,DI 使用多态技术为组件注入依赖对象。

  在没有学习 Spring 之前,简单的解决方案是使用一个 .properties 文件保存程序中使用的接口、实现类类型键值信息,然后在程序中使用一个全局 Properties 对象保存这些信息,并且使用反射技术把这些实现类初始化、提供一个静态的方法获取指定接口的实现类对象,在组件中就可以使用依赖对象的键获取需要的对象。

  这样的方案带来的好处就是:当我们需要修改某个组件的实现方式时,比如把之前 JDBC 的 DAO 实现改为 Hibernate 实现,只要把这些新的实现类放到 classpath 下,把 .properties 文件对应接口的实现类类型改成新的 Hibernate 实现类,而不需要修改依赖组件的代码。

  在之后的文章中,我们将写一个简单的例子进一步讲解这个初级解耦方案。

Java面向对象概述和三大特性的更多相关文章

  1. Java面向对象概述及三大特征(封装,继承和多态)

    一.面向对象思想 Java是面向对象的高级语言,对于Java语言来说,万事万物皆对象! 它的基本思想是使用类,对象,继承,封装,消息等基本概念进行程序设计.面向对象程序的最小单元是类,类代表了客观世界 ...

  2. Java 面向对象概述原理: 多态、Object类,转型(8)

    Java 面向对象概述原理: 多态.Object类,转型(8) http://docs.oracle.com/javase/tutorial/java/IandI/override.html Java ...

  3. Python 基础 面向对象之二 三大特性

    Python 基础 面向对象之二 三大特性 上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员.成 ...

  4. day31 Pyhton 面向对象的基础 三大特性

    一.内容回顾 封装 1.概念 笔记 2.__名字 在类的外部就不能用了 3.私有化的 不能被子类继承,也不能在其他任何类中调用 三个装饰器方法(装饰类中的方法) 1.不被修饰的  普通方法,会使用对象 ...

  5. Java面向基础概述和三大特性

    Java 是面向对象的高级编程语言,类和对象是 Java 程序的构成核心.围绕着 Java 类和 Java 对象,有三大基本特性:封装是 Java 类的编写规范.继承是类与类之间联系的一种形式.而多态 ...

  6. Python面向对象之:三大特性:继承,封装,多态以及类的约束

    前言: python面向对象的三大特性:继承,封装,多态. 1. 封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情 ...

  7. PHP其它常用函数;<<<面向对象(OPP)的三大特性:封装、继承、加态:>>> <----面试题 ;构造方法、析构方法,魔术方法、set、get方法;静态;抽象类;接口

    PHP其它常用函数:     赋值:$r->name = "元素";      取值: echo $r->name;  count()   计算数组中的元素数目或对象中 ...

  8. Java面向对象概述

    一.什么是面向对象? 现实世界中,随处可见的一种事物就是对象,对象是事物存在的实体,如人类.书桌.计算机.高楼大厦等.人类解决问题的方式总是将复杂的事物简单化,于是就会思考这些对象都是由哪些部分组成的 ...

  9. Java 面向对象概述

    本文部分摘自 On Java 8 面向对象编程 在提及面向对象时,不得不提到另一个概念:抽象.编程的最终目的是为了解决某个问题,问题的复杂度直接取决于抽象的类型和质量.早期的汇编语言通过对底层机器作轻 ...

随机推荐

  1. selenium3+java+POM 跨浏览器测试之------读取配置文件

    我们知道,web 测试的时候是需要切换不同的浏览器以查看每个功能在不同浏览器上的运行情况,使得开发的程序更具有健壮性.本文先总结一下如何通过读取配置文件来切换浏览器. 具体步骤如下: 一.编写配置文件 ...

  2. python提取xml属性导入Mysql

    xml文档来自ganglia-gmond端telnet localhost 8649产生出来的文档,由于ganglia每隔一段时间就更新数据,为了永久保存数据到MySQL中,就用python写了最开始 ...

  3. (87)Wangdao.com第二十天_JavaScript document 节点对象

    document 节点对象, 代表整个文档,每张网页都有自己的 document 对象. window.document 当浏览器开始加载文档时就存在了 正常的网页使用 document 或者 win ...

  4. [LeetCode] Reaching Points 到达指定点

    A move consists of taking a point (x, y) and transforming it to either (x, x+y) or (x+y, y). Given a ...

  5. linux 文件 IO 目录操作及文件属性

    ///练习:实现列出某个目录中所有文件属性(文件大小,文件最后修改时间,文件名)//目录名由参数传入 ./dir /home/linux#include <sys/stat.h>#incl ...

  6. Linux命令 df du

    df: 列出文件系统的整体磁盘使用量 du: 评估文件系统的磁盘使用量 $ df [-ahikHTm] [目录或文件名] 参数: -a: 列出所有的文件系统,包括系统特有的/proc 等文件系统 -k ...

  7. 海思编译链编译出现__aeabi_unwind_cpp_pr1重定义怎么回事

    1.用arm-hisiv100nptl-linux-gcc编译代码,结果发现报错,__aeabi_unwind_cpp_pr1重定义,在librt.a先定义,使用的海思芯片是hi3520d. 2.本来 ...

  8. [Day24]IO(转换流、缓冲流)

    1. 转换流 1.1 OutputStreamWriter类-字符流通向字节流的桥梁,可使用指定的字符编码表,将要写入流中的字符编码成字节. 1.2 InputStreamReader类-字节流通向字 ...

  9. json和pickle模块

    import pickleimport json data = {'k1': 123, 'k2': 'Hello'}print(type(data))# p_str = pickle.dumps(da ...

  10. 另存了一次网页之后其它word打开格式都变了

    解决方案: 视图->页面视图 感觉自己很傻...原来另存word为网页后,默认的打开模式就是网页视图了.只需要把视图改回去即可