Java类与对象
本文最后更新于:2024年5月11日 上午
Java作为一门纯面向对象的语言,类与对象自然是其核心内容,类是最基本的抽象单位,以对象为单位编码。而最早的面向对象的概念实际上是由IBM提出的,在70年代的Smaltalk语言之中进行了应用,后来根据面向对象的设计思路,才形成C++,而由C++产生了Java这门面向对象的编程语言。
一、面向对象
1 面向对象简述
先看一下维基百科上关于面向对象的定义:
面向对象程序设计(英语:Object-oriented programming,缩写:OOP)是种具有对象概念的程序编程典范,同时也是一种程序开发的抽象方针。它可能包含数据、属性、代码与方法。对象则指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问及经常修改对象相关连的数据。在面向对象程序编程里,计算机程序会被设计成彼此相关的对象
面向对象的定义中,规定有一些基本特征:
- 封装:将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
- 继承:继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或类从父类继承方法,使得子类具有父类相同的行为。相当于一个”is a”。
- 多态:多态就是对象的多种形态。相同的引用通过不同的实例执行不同的操作
对于面向对象的开发来讲也分为三个过程:OOA(面向对象系统分析)、OOD(面向对象设计)、OOP(面向对象编程)。
2 类和对象概念
类与对象时整个面向对象中最基础的部分。
类:是抽象的概念集合,表示的是一个共性的产物,类之中定义的是属性和行为(方法);
对象:对象是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性来区分不同对象。
总结一下就是:类是对象的模板,对象是类的实例。编码中先写类,将类实例化为对象后,使用对象(类不能直接使用,对象可以)
类的创建及初始化
类是指一类事物的抽象,小学生、初中生、大学生都是学生,可以抽象出学生这个类,小学生张三就是学生这个类的一个具体实例。其中类的属性描述了抽象出来的类它的特点,方法描述了它的功能
1 |
|
说一下引用的概念:如果一个变量的类型是 ’类‘ 类型,而非基本类型,那么该变量又叫做引用。
例如new Student()
创建了一个Student对象,但是创建了对象还要能访问啊,为了访问这个对象,会使用引用Hero zs= new Hero();
其中zs是一个Student类型变量,又叫做引用。new 操作符会为我们在内存中开辟空间,zs是对象名,也是引用,在栈上分配,指向由new在堆上分配的内容
1 |
|
再来分析一下这个过程:当调用new Student()时,编译器首先检查下原类Student中是否有Student()构造方法,此处因为有public Student(String name,int age),所以new的时候,直接调用的该方法,但是很多时候,我们并没有显示声明构造方法,此时,编译器在调用的new Student()的时候,会自动为我们的Student类添加一个无参的空Student()构造方法:Student(){},来执行类的构造过程。
构造方法与变量:不论变量放在哪儿,都会先于任意一个方法的执行前执行,包括构造方法,而构造方法是一个类必须会执行的方法,不需要显示的进行调用。同时,不论变量在哪儿分布,只要在方法外部,就一定先于方法初始化。说到这儿,我们不得不谈一下另一个关键的知识点静态块和非静态块。二者都有很简单的声明方式,只需一对大括号{}就行,静态块的话,在前面加static关键字。例如以下代码:
1 |
|
创建对象的流程:
- 先装载.class文件,创建Class对象,对静态数据(由static声明的)进行初始化,而且只进行一次初始化。
- new Build()在堆上进行空间分配。
- 执行非静态块。
- 执行所有方法外定义的变量的初始化。
- 执行构造器。
属性&方法
描述类状态的就叫属性,可以是基本类型也可以是 ”类“ 类型;描述类功能的就叫方法,它由由方法头和方法体构成,其中包含了访问控制符、返回类型、方法名、参数列表等,还可以用关键字实现特殊的功能
当一个属性被static修饰的时候,就叫做类属性,又叫做静态属性,当一个属性被声明成类属性,那么所有的对象,都共享一个值
与对象属性对比:不同对象的 对象属性 的值都可能不一样;但是所有对象的类属性的值,都是一样的
比如每个学生的姓名年龄可能会不同,但是他们都有一个共同的身份——学生
1 |
|
再看一段代码:
1 |
|
我们new了两个对象,可是静态块只执行了一次,而非静态块执行了两个,且都是在调用构造器之前。我们似乎得出了一些结论:静态块是在类的装载时执行的(装入.class文件后),且只执行一次。而非静态块是在调用构造方法之前执行的,每生成一个实例对象,就会调用一次非静态块。
如静态块一样,其它的静态数据也具有这个特点:初始化只在类装载的时候执行一次。
对于类方法,还有一个重要的特点就是——访问对象方法要建立在有一个对象的前提上,但是访问类方法,不需要对象存在,直接就可以访问
this
this这个关键字,相当于普通话里的“我”
this即代表当前对象
1 |
|
重载和重写
重载:是指在同一个类中,具有相同的方法名,不同的参数列表的方法之间的一种机制。参数列表的不同体现在:类型不同、个数不同、顺序不同,只要满足任一一个,就可以进行方法重载。
1 |
|
同一个方法名,不同的参数,实现不同的功能,这就是方法重载。这样的机制有什么好处?
主要是:同样的功能,调用同样的方法,只需传入不同的参数,增强了程序的可读性和易于维护,当有很多个功能相似的方法的时候,如果我们为每个方法设计一个名称,想通过名称来区分它们的话,会使得程序的可读性差,设计不够巧妙!
重写:重写是在继承中存在的,在两个类(子类和父类之间存在的关系)中,子类重写父类的方法,方法名相同,参数也相同的一种机制。
1 |
|
当子类继承了父类后,想对父类的方法功能进行扩展,就可以使用重写,这样做的目的就是:当你需要扩展新的功能的时候,不需要新建方法,在父类的方法中进行补充,这样一种面向对象思维的体现,不用重写同样可以达到这样的效果,但是用了重写更加符合OO思想。类似的还有一种概念,叫隐藏:当子类和父类方法名相同,参数不同时,子类隐藏父类的方法实现,这就是一种机制,一种叫法,没什么实际意义,相当于我们新建了方法,只是方法名和父类的相同,但是不是父类的方法的实现。
Java中不定参数调用
有的时候,我们不能确定方法的参数个数,我们可以采取这种机制(String … value),这样可以使代码量降低,使得代码尽可能简单
1 |
|
3 类与对象关系
对象与引用
我们从内存的角度分析。首先,给出两种内存空间的概念:
(1)堆内存:保存对象的属性内容。堆内存需要用new关键字来分配空间;
(2)栈内存:保存的是堆内存的地址(在这里为了分析方便,可以简单理解为栈内存保存的是对象的名字)。

如果直接使用没有实例化的对象,就会出现报错:Exception in thread "main" java.lang.NullPointerException
空指向异常。表示只声明了Student对现象,没有实例化(只有栈空间而没有对应的堆内存空间)
引用和对象:对象只有一个,但是可以有多个引用指向它
1 |
|

一个引用同时只能指向一个对象
1 |
|

再看看下面的一段代码:
1 |
|

此时第二块堆内存空间,没有任何引用指向,这块空间就成为内存垃圾
抽象类与接口
初学Java感觉抽象类和接口有点类似,
抽象类:凡是声明为形如:abstract void function()
的方法,都是抽象方法,包含抽象方法的类就是抽象类,抽象方法只有声明没有实现。
当然一个类可以在没有抽象方法的前提下声明为抽象类,而一旦被声明为抽象类,因为抽象类没有具体实现的方法,那么它就不能直接实例化。抽象类可以说是对类的抽象
1 |
|
抽象类创建了就是为了被继承然后实现,因此一个类继承了抽象类,那么就必须实现父类的抽象方法,如果没有实现那么子类也将定义为abstract类。
接口:指供别人调用的方法或者函数。它是对行为的抽象。在Java中,定一个接口的形式如下:
1 |
|
可以看出:接口比抽象类更加 “ 抽象 ”。他可以定义变量,但是变量会被隐式地指定为public static final变量(即为常量),而方法会被隐式地指定为public abstract方法且只能是public abstract方法,并且接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法。
Java多继承
Java中只有单继承,不允许多继承,但是可以实现多个接口,相当于间接实现多继承
1 |
|
1、接口可以实现向上转型,多个具有共同属性的类可以将它们的共同点提取出来,做成抽象,这样层次分明,统一管理。
2、接口不具有任何实现,最适合做基类。
抽象类与接口区别:
- 抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
- 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
- 抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。