Java 基础(12)——类与对象

Java是一门纯粹的OOP(Object-Oriented Programming)[面向对象]的编程语言。所以其实从这里开始才是重点哈哈。

面向对象最早是七十年代的时候由IBM的SmallTalk语言最先推广,后来有了C++,再后来产生了今天的Java。

面向对象

面向对象是一种技术的开发模式,但是最早的时候所使用的模式是面向过程。

“面向过程”(Procedure Oriented) 是一种以过程为中心的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是封装、继承、类。

面向过程:是针对某一个问题单独提出解决方案以及代码开发。只能解决当前问题,由于缺少合理做法,只能完成一次服务,为特定功能服务。
面向对象:是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

面向对象是以一种组件化的形式进行代码的设计。这样开发出来的代码有一个最大的好处就是重用。

举个栗子:
小王开了一家正装店铺,关于西服的进货,他现在有两种选择:

  1. 来一个客人之后,量好身材,制作上衣、裤子、领带。然后交付给客人。(面向过程)
  2. 按照每一个尺码分别制作若干上衣、裤子、领带,客人直接按尺码购买。(面向对象)

在面向对象的程序中有三种特性:

  • 封装性:保护内部的定义结构安全性
  • 继承性:在已有程序结构上继续扩充新的功能
  • 多态性:在某一个概念范围内的满足

面向对象开发的步骤分为:OOA(面向对象分析)、OOD(面向对象设计)、OOP(面向对象编程)

类与对象

面向对象有两个基本概念:类与对象。

  • 类:是对客观事物不断认识而产生的一个抽象概念
  • 对象:现实生活中的一个个实体(也称实例)

类就是共性的集合,对象就是某一个性的产物。

类是现实世界或思维世界中的实体在计算机中的反映,它将数据以及这些数据上的操作封装在一起。 from 百度百科

相似的对象可以归并为一类(共性集合),就与1、2、3都是整数,可以归类到int类型里一样,所以同一个类所创建出的对象,它的值可以不相同,但是属性一定相同。比如1和2,他们一个数值上不相等,但是属性上都是整数。

找个人干活 找到了小王同学 人就是类,小王同学就是对象~
去银行办一个账户,账户是类,办到的银行卡是对象。
招聘时HR需要的是附和他要求的那一类人,如果你每一项刚好符合他的需求,你就是他要找的对象。

基本定义

如果需要定义一个类的话,可以使用class 类名称{ }。类中的组成主要有两点:

  • Field(属性,成员,变量)就是一堆变量的集合
  • Method(方法,行为)之前学过的方法,但是此时的方法是由对象调用的。
    定义一个类:
class book{ //定义一个新的类
    String title; //书的名字
    double price; //书的价格
    public void getInfo(){//此方法将由对象调用
        System.out.println("图书名称:"+title+",价格:"+price);
    }
}

那么这个类里定义了两个属性和一个方法。有类之后,如果想要使用类的话,就必须有对象,对象的定义分为两种格式:

  • 声明对象并实例化:类名称 对象名称 = new 类名称();
  • 分步完成:① 声明对象:类名称 对象名称 = null; ② 实例化对象:对象名称 = new 类名称();

类属于引用数据类型,而引用数据类型与基本数据类型最大的不同在于引用数据类型需要开辟内存空间,我们使用new关键字来进行内存空间的开辟。但是说到内存之前,需要普及两个概念:

堆栈(stack)。位于通用 RAM 中,但通过它的 “堆栈指针” 可以从处理器哪里获得支持。堆栈指针若向下移动,则分配新的内存;若向上移动,则释放那些 内存。这是一种快速有效的分配存储方法,仅次于寄存器。创建程序时候,JAVA 编译器必须知道存储在堆栈内所有数据的确切大小和生命周期,因为它必须生成 相应的代码,以便上下移动堆栈指针。这一约束限制了程序的灵活性,所以虽然某些 JAVA 数据存储在堆栈中——特别是对象引用,但是 JAVA 对象不存储其 中。
堆(heap)。一种通用性的内存池(也存在于 RAM 中),用于存放所以的 JAVA 对象。堆不同于堆栈的好处是:编译器不需要知道要从堆里分配多少存储区 域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。当你需要创建一个对象的时候,只需要 new 写一行简单的代码,当执行 这行代码时,会自动在堆里进行存储分配。当然,为这种灵活性必须要付出相应的代码。用>堆进行存储分配比用堆栈进行存储存储需要更多的时间。

这一段太长了哈,其实简单的来说,堆内存保存的是每一个对象的属性内容,new关键字开辟的内存空间也正是它。而栈内存存放的是一块堆内存的地址,能够告诉机器这个东西存在哪里。

比如超市的储物柜,你按一下按钮,会打开一个柜子,并且出来一张条形码的纸条。结账完之后拿包什么的只需要拿着那个条形码去扫一下就可以打开那个柜子。那么,打开的柜子就是你按下按钮(new)开辟的“堆内存”空间,出来的条形码就是“栈内存”,里面存放的是这个柜子的地址信息,可能是第几排第几个,也可能是编号001号柜子。

好,概念了解完就可以继续了~

当一个对象实例化之后就可以按照下列方式利用对象操作类:

  • 对象.属性 表示要操作类中的属性内容
  • 对象.方法() 表示要调用类中的方法

那么就使用一下刚刚的book类吧:

public class Test01{
    public static void main(String[] args){
        Book bk=new Book();//声明并实例化对象
        bk.title="Java开发";//操作属性内容
        bk.price=89.9;//操作属性内容
        bk.getInfo();//调用类中的getInfo方法
    }
}

分析一下:

Book bk=new Book();//声明并实例化对象

声明了bk对象,并且为bk对象new了一个堆内存空间。(堆内存:title=null price=0.0)ps. String是引用数据类型,所以默认值为null,double型的price默认值为0.0

bk.title="Java开发";//操作属性内容

修改bk对象的title(堆内存:title="Java开发" price=0.0)

bk.price=89.9;//操作属性内容

修改bk对象的price(堆内存:title="Java开发" price=89.9)


那么如果是分步来呢?

Book bk;//声明对象
bk = new Book();//实例化对象

依然还是来分析一下哈:

Book bk;//声明对象

声明了bk对象,由于没有实例化,所以目前的bk对象为引用类型的默认值null

bk = new Book();//实例化对象

实例化bk对象,new开辟了bk的内存空间,所以bk就不为空了(但是里面的属性是默认值null和0.0)

任何情况下只要出现了关键字new,都表示要开辟新的内存空间,一旦堆内存空间开辟了,里面就一定会有所有类中定义的属性,当然所有的属性的值都是它对应的数据类型的默认值

我们在声明对象之后一定要记得实例化对象,如果忘记的话:

public class Test01 {
    public static void main(String[] args) {
        Book bk;
        // bk = new Book();  //模拟没有初始化
        bk.title = "测试用书";
        bk.price = 100.1;
        bk.getInfo();
    }
}

输出的结果:

Exception in thread "main" java.lang.NullPointerException
    at Test01.main(Test01.java:11)

NullPointerException 空指针异常
开辟了堆内存的对象叫实例化对象,但是如果使用未实例化的对象,程序在运行时就会出现空指针异常。
(编译的过程中报的错误属于语法错误,空指针这个是运行时报错)


引用数据

引用 是Java的核心精髓所在。引用类似于C++中的指针概念,但是比指针更加的简单。

在所有的引用分析里,最关键的还是在于关键字"new",一定要注意每一次使用关键词new都一定会开辟新的堆内存空间,所以代码里声明了两个对象,并且分别进行了实例化操作,那么一定是开辟了两个堆内存空间,互不影响。

举个栗子 01:

Book bk1 = new Book();
Book bk2 = null;

声明了两个对象了,但是只实例化了bk1,也就是说只开辟了bk1这一个内存空间。

bk1.title = "Java开发";  // 操作属性内容
bk1.price = 89.9;        // 操作属性内容

修改了bk1的属性值

bk2 = bk1;               // 引用传递

这句话,将bk1赋值给bk2。意思就是将bk1的堆内存空间的地址给了bk2的栈内存,所以bk2与bk1目前指向的是同一块堆内存

bk2.title = "JSP开发";  // 操作属性内容
bk2.price = 68.8;        // 操作属性内容

修改了bk2指向的堆内存中的数据。但是由于bk2和bk1指向的是同一个堆内存,所以bk1也同样修改了

bk1.getInfo();           // 调用类中的getInfo方法
bk2.getInfo();           // 调用类中的getInfo方法

所以这里bk1和bk2的getInfo()方法输出的结果是一样的!


举个栗子 02:

Book bk1 = new Book();
Book bk2 = new Book();
bk1.title = "Java开发";  // 操作属性内容
bk1.price = 89.9;        // 操作属性内容
bk2 = bk1;               // 引用传递
bk2.title = "JSP开发";  // 操作属性内容
bk2.price = 68.8;        // 操作属性内容
bk1.getInfo();           // 调用类中的getInfo方法
bk2.getInfo();           // 调用类中的getInfo方法

这一次的bk2也被实例化了,也就是说开辟了两个堆内存空间。但是在第五行的时候,bk2再一次的指向了bk1的堆内存地址!于是,bk2原来的堆内存空间就没有任何栈内存指向它了,所以这个没有任何栈内存指向的堆内存,就将成为垃圾

所有的垃圾会不定期的被垃圾收集器(GC)进行回收,回收之后会释放掉其所占用的空间。

ps. 虽然Java中有支持自动的垃圾收集处理,但在开发过程中应该尽量减少垃圾空间的产生。


以上,修改于 20190512 。
学自李兴华老师的Java课
from ahanwhite
如有错误,敬请批评!非常感谢。

你可能感兴趣的:(Java 基础(12)——类与对象)