Java思想 Part2 --- 一切都是对象

概览

在这里插入图片描述

面向对象设计语言相比于面向过程设计语言所具有的特点是易维护、易扩展、易复用。
面向对象编程主要有:封装、继承和多态等特性。

  1. 封装:将数据核对数据的操作封装在一起。
  2. 继承:子类可以继承父类的属性和行为。即继承父类所具有的数据和数据的操作,同时为子类添加独有的行为和数据
  3. 多态:多个不同的方法对应的方法名称相同,但是其入参与执行不同。

句柄操纵对象

String str;
//str就是创建了一个句柄

负责程序正常运行的是对象,那程序是怎么操纵对象的呢?就像电视是一个对象,我们操纵电视利用的是其正面的按钮,那一个个按钮就是句柄,来操纵对象。会用按钮就相当于掌握了与电视连接的通道。
但是

str=xxxx;
str=xxxx2;

但其实按照书上说的用按钮作比喻并不合适,因为按钮并不与对象相捆绑,实际上句柄更像是万能遥控器,和哪个电视连接都没问题,想控制谁控制谁。

创建对象

创建句柄时,我们希望它同一个新的对象链接,通常用new关键字达到这一目的

String str=new String("只有一个人觉得嘉然和大河很像吗?")

这个new不仅指出“将我变为一个新子串”,也通过提供一个初始子串,指出了“如何生成这个新子串”

对象保存的位置

首先是六个可以保存数据的位置:

  1. 寄存器。这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部。但是寄存器的数量十分有限,所以寄存器是根据需要由编译器分配。同时由于各个设备的寄存器数量不同,这又给跨平台带来了很大的困难,所以有了JVM虚拟机,但是对于Android来说寄存器数量不会有太大区别,所以Android的虚拟机不能跨平台,不符合JVM设计规范。
  2. 堆栈。常驻留于RAM区域,但可通过它的堆栈指针获取处理的直接支持。堆栈指针若向下移,会创建新的内存,若向上移,则会释放那些内存。这是一种特别快的、特别有效的数据保存方式,仅次于寄存器,答Java编译器必须准确地知道栈堆内保存的所有数据的长度以及存在时间,这是因为其必须生成相应的代码,以便向上和向下移动指针。
  3. 堆。一种常规用途的内存池,也在RAM区域,其中保存了Java对象。和堆栈不同,内存堆的对象编译器不需要事前知道要从堆里分配多少存储空间,也不必知道存储的数据要令编译相关的代码即可,非常的灵活。
  4. 静态存储。Static静态是指存于固定位置,尽管也在RAM中,但Static与Java中的Static关键字没有关系,Static关键字指出一个对象的特定元素是固定的,但其对象本身并不会放到静态区域。
  5. 常数存储。常数值通常置于程序代码内部,这样做可以让他们永远都不会改变,有的常数需要严格的保护,所以可以考虑将他们置入静态存储空间。
  6. 非RAM存储。若数据完全独立于一个程序之外,则程序不运行时仍可存在,并在程序的控制范围之外。两个主要的例子是流式对象和固定对象。

主要类型

有一些系列的类需要特别对待,称为基本类,主要类或者主类,进行程序设计时要频繁使用它们。之所以要特别对待,是由于用new创建对象并不是非常有效,因为new将对象置于堆中。对于一些基本类型数值不放置于堆,而放在堆栈中可以更高效的存储。

主类型大小最小值最大值封装器类型
boolean1位--Boolean
char16位Unicode 0Unicode 2的16次方-1Character
byte8位-128+127Byte
short16位-2的15次方2的十五次方-1Short
int32位-2的31次方+0的31次方-1Interger
long64位-2的63次方+2的63次方-1Long
float32位IEEE754IEEE754Float
double64位IEEE754IEEE754Double

逻辑类型: boolean
整数类型: byte、short、int、long
字符类型: char
浮点类型: float、double

关于基本类型:

  1. int是基本类型,Integer是int的封装类,是引用类型。这就意味着int的默认值是0,而Integer的默认值是null,所以Integer能区分出0和null的情况。一旦java看到null,就知道这个引用还没有指向某个对象,对于任何引用类型来说,必须为其指定一个对象。
  2. 基本数据类型在声明时系统会自动为它分配空间,而引用类型声明时只是分配了引用空间,必须通过实例化开辟数据空间之后才可以赋值。数组对象也是一个引用对象,将一个数组赋值给另一个数组时只是复制了一个引用,所以通过某一个数组所做的修改在另一个数组也观察得到。

Java数组

当程序需要多个基本类型的变量时,总不能一个个去新建对象吧,所以要采用数组,数组是引用型变量,数组变量中存放着数组的首元素的地址,创建数组需要经过声明数组和为数组分配变量两个步骤。
创建对象数组时,实际上创建的是一个句柄数组。而且每个句柄都会自动初始化成一个特殊值,并带有自己的关键字:null,一点Java看到null,就知道该句柄未指向对象。所以相比于C++在Java中使用数组更方便。

对象的清除

在大多数的程序设计语言中,变量的“存在时间”(Life Time)是需要着重考虑的问题,变量应持续多长时间?如果想清除,那何时完成,有何时进行。如果不彻底搞清楚会造成程序崩溃,Java的设计则极大简化了这个问题

作用域

在这里插入图片描述
作用域的存在决定了对象的可见性以及其存在时间。在编程中长串的代码,不同的变量存在着不同作用域,作用域是由大括号的位置决定。
**作为在定义域中定义的变量,只有在作用域结束之前才可以使用。

对象的作用域

Java对象不具有与主类型一样的存在时间,使用new关键字创建一个Java对象是,它会超出作用域的范围之外。

public class ScopeTest {
    static class OutObject{
        int value;
        public OutObject(int a){
            value=a;
        }
    }
    public static void solution1(OutObject out){
        out.value=10;
    }
    public static void solution2(int a){
        a=10;
    }
    public static void main(String[] args) {
       int a=0;
       OutObject out=new OutObject(0);
       solution1(out);
       solution2(a);
       System.out.println(out.value);
       System.out.println(a);
    }
}

还有一个问题是对象的存在:

{
String str=new String("关注嘉然,顿顿解馋")
}

句柄str在作用域的终点消失了,然而s指向的String类型的对象依然占据着内存空间。在上面这段代码中我们没法使用这段内容,因为唯一指向他句柄已经超出了作用域的范围,但是实际上这段文字还是存在于内存中的,这样做的结果是,我们new出来的对象,无论使不使用都存在于内存中。好在JVM在设计的时候采用了垃圾收集机制,可以发现并处理这些无引用对象,释放其占有的内存空间,防止造成内存溢出。

新建数据类型: 类

类的目的是抽象出一类事物共有的属性和行为,并用一定的语法格式来描述所抽象出的属性和行为。也就是说,类是一种用于创建具体实例对象的数据类型。类使用是类体来描述抽象出的属性和行为,类声明之后的一对大括号以及他们之间的内容称为类体。
抽象的关键是抓住事物的两个方面:属性和行为,即数据以及在数据上所进行的操作,因此类体的内容由如下所述的两部分组成:

  1. 变量的声明:用于存储属性的值(体现对象的属性)
  2. 方法的定义:方法可以对类中的声明变量进行操作,即给出算法,体现出对象所具有的行为。

本质上我们在Java里做的全部的工作就是定义类,制作那些类的对象以及将消息发给那些对象。

字段和方法

定义一个类的时,可在自己的类型里设置两种类型的元素:数据成员(字段)以及成员函数(方法)。其中,数据成员是一种对象(通过它的句柄与之通信),可以为任何类型。也可以是主类型。如果指向对象的一个句柄,则必须初始化那个句柄,用名为构造函数的特殊函数将其与一个实际对象连接起来,但如果是基本类型则可以直接初始化。

字段(成员变量)

类体中的内容可以分为两部分:一部分是变量的声明;另一部分是方法的定义。声明变量部分所声明的变量被称为成员变量或者域变量。

public class ASoul {
    /**
     *成员变量的类型可以是Java中的任何一种数据类型,包括基本类型
     * 和引用类型
     */
    String name;
    int IQ;
    boolean sex;
    /**
     * 成员变量在整个类内都有效,其有效性与它在类体中书写的先后位置无关
     */
}

方法

方法代表了完成某件事的途径,在Java中方法决定了一个对象能接受的信息,方法的基本组成包括名字、自变量、返回类型等。

public int dance(Asoul a){
//方法的基本组成包括名字、自变量、返回类型以及主体
//如此实例 返回类型 方法名(自变量列表){方法主体}
}

返回类型是指调用方法之后返回的数值类型,显然方法名的作用是对具体的方法进行标识和引用。自变量列表列出了想传递给方法的信息类型和名称。
Java方法在没有被static修饰时必须作为类的一部分存在,只能针对某一个对象调用一个方法,而且那个对象必须能够执行该方法的调用。

int dashang=jiaran.dance(xiangwan);
//嘉然今天也很可爱地跳舞捏

自变量列表

我其实更倾向于称其为入参,自变量列表规定了我们传输给方法的是什么信息,这些信息如同Java内其他任何东西,采用的都是对象的形式。因此,我们必须在自变量列表中指定要传递的对象类型,以及每一个对象的名字。正如Java其他地方处理对象一样,我们传递的其实是句柄。
如果返回值是void无返回值的方法,那在该方法中的return关键字的唯一作用只是用来退出方法,所以一旦抵达方法尾部,该方法其实就不需要了。

构建Java程序

一个程序只是一系列对象的集合,它们的方法将作为其他对象作为自己的自变量使用,而且将消息发给那些对象。

名字可见性

在所有的程序设计语言里,一个不可避免的问题是对名字和名称的控制,相比于C++,Java有非常棒的名字管理方法,也就是命名空间的概念。Java的特殊机制意味着所有的文件都自动存在自己的命名空间中,而且一个文件里的每个类都自动获取一个独一无二的标识符。

使用其他组件

要使用在自己程序里设计好的类,编译器就必须知道如何找到它,当然,这个类还可能存在于发出调用的那个相同的源码文件中,如果是这样,只需要简单使用这个类即可—即使他直到文件的后面仍为定义。
假如这个类位于其他的文件中(包中),我们希望编译器可以自动搜索并启用我们想要实现的类,但是编译器并做不到,因为用一个名称的文件可能存在于多个不同的包内容中,编译器无法确定哪一个类是你真正需要的,所以需要使用import关键字导入包,也可以称为类库。

static关键字

通常,我们创建类时,会指明那个类的对象和行为,除非用new去创建那个类的一个对象,否则实际上并未得到任何东西,只有执行new后,才会真正产生数据存储空间,并可以使用相应的方法。但有两个特例:一种情况是想用一个存储空间来保存一个特定的数据—无论要创建多少个对象,甚至根本不创建对象。另一种情况是我们需要一个特殊的方法但不需要它与任何对象相关联。此时需要static关键字。它可以修饰变量与方法,数据或方法被其修饰后不会同它所处的对象实例联系到一块没所以虽然没有建立这个类的对象也可以直接使用。
我在工作中遇到过的使用实例时Constant常量池,内有多个固定的常量,采用static修饰,这样就可以直接使用,方法不建议用static修饰,否则当你使用mockit单元测试时会很痛苦,除非换用mockitplus。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值