Java学习笔记3.1.1 类与对象
零、本讲学习目标
- 理解面向对象的概念
- 熟悉面向对象的三个特点
- 掌握类和对象的定义和使用
- 熟悉访问控制符
一、面向对象概述
(一)什么是面向对象?
- 面向对象是一种符合人类思维习惯的编程思想。现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象。
(二)面向过程 vs. 面向对象
- 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一一实现,使用的时候依次调用就可以了。(POP:Procedure-Oriented Programming)
- 面向对象则是把构成问题的事务按照一定规则划分为多个独立的对象,然后通过调用对象的方法来解决问题。(OOP:Object-Oriented Programming)
(三)面向对象三大特点
- 面向对象是把构成问题的事务按照一定规则划分为多个独立的对象,然后通过调用对象的方法来解决问题。一个应用程序会包含多个对象,通过多个对象的相互配合来实现应用程序的功能,这样当应用程序功能发生变动时,只需要修改个别的对象就可以了,从而使代码更容易得到维护。面向对象的特点主要可以概括为封装性、继承性和多态性。
1、封装(encapsulation)
- 封装是面向对象的核心思想,将对象的属性(property)和行为(behavior)封装起来,不需要让外界知道具体实现细节。
2、继承(inheritance)
- 继承主要描述的就是类与类之间的关系,通过继承,可以在无需重新编写原有类的情况下,对原有类的功能进行扩展(extend)。
3、多态(polymorphism)
- 多态指的是在一个类中定义的属性和功能被其他类继承后,当把子类对象直接赋值给父类引用变量时,相同引用类型的变量调用同一个方法所呈现出的多种不同行为特性。
二、Java中的类与对象
(一)类与对象的关系
-
面向对象的编程思想,力图让程序中对事物的描述与该事物在现实中的形态保持一致。为了做到这一点,面向对象的思想中提出了两个概念——类和对象。
-
类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体。简而言之,类是模板(template),对象是实例(instance)。
-
分析: 可以将上图人看作是一个类,将每个具体的人(如小韩、小石等)看作对象,从人与具体个人之间的关系便可以看出类与对象之间的关系。
-
说明: 类用于描述多个对象的共同特征,它是对象的模板,而对象用于描述现实中的个体,它是类的实例。对象是类的具体化,并且一个类可以对应多个对象。
(二)类的定义
-
在面向对象的思想中,最核心的就是对象。为了在程序中创建对象,首先需要定义一个类。类是对象的抽象,它用于描述一组对象的共同特征和行为,例如人都有姓名、年龄、性别等特征,还有学习、工作、购物等行为。
-
以面向对象的编程思想,就可以将某一类中共同的特征和行为封装起来,把共同特征作为类的属性(property),也叫成员变量(member variable),把共同行为作为类的方法(method),也叫成员方法(member method)。
1、类的定义格式
- 利用关键字
class
来定义类,类有权限修饰符,可以继承一个类,实现多个接口
2、声明成员变量
- 成员变量可以初始化,也可以不初始化
3、声明成员方法
- 普通类声明的方法必须实现,也就是说要有方法体。如果方法没有实现,就是抽象方法,那该类就是抽象类
4、案例演示创建类
-
创建Person类,包含两个属性:姓名(name)和人品(character、
),另外还包含一个自我介绍的方法speak()。注意:要求人品值在[1, 10]。
-
在
c03.s01.p01
包里创建Person
类
package c03.s01.p01;
/**
* 功能:Person类
* 作者:Java课程项目组
* 日期:2021年02月22日
*/
public class Person {
String name;
int character;
public void speak() {
System.out.println("嗨,我叫" + name + ",人品值:" + character);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
5、成员变量与局部变量
-
在Java中,定义在类中的变量被称为成员变量(member variable),定义在方法中的变量被称为局部变量(local variable)。如果在某一个方法中定义的局部变量与成员变量同名,这种情况是允许的,此时方法中通过变量名访问到的是局部变量,而并非成员变量。
-
修改Person类,给成员变量赋初值,并在成员方法里定义局部变量
public class Person {
String name = "李晓红"; // 类中定义的变量被称作成员变量
int character = 3; // 类中定义的变量被称作成员变量
public void speak() {
int character = 7; // 方法内部定义的变量被称作局部变量
System.out.println("嗨,我叫" + name + ",人品值:" + character);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 分析: 上述代码中,speak()方法中所访问的变量character是局部变量,也就是说,当有另外一个程序来调用speak()方法时,输出的character值为7,而不是3。speak()方法中所访问的变量name是成员变量,当另一个程序来调用speak()方法时,输出的name值就是“李晓红”。
(三)创建与使用对象
- 应用程序想要完成具体的功能,仅有类是远远不够的,类只是一个抽象的模板,还需要根据类创建实例对象,就好像有了房子的设计图纸,还需要根据设计图纸施工把房子给盖出来。
1、对象创建语法格式
类名 对象名称 = new 类名();
- new 类名() 是基于指定类创建一个新的实例(对象)
- 对象名称是一个引用变量,指向创建的实例(对象)
2、创建对象案例演示
- 修改Person类,取消对成员变量赋初值,删除成员方法里定义的局部变量
package c03.s01.p01;
/**
* 功能:Person类
* 作者:Java课程项目组
* 日期:2021年02月22日
*/
public class Person {
String name;
int character;
public void speak() {
System.out.println("嗨,我叫" + name + ",人品值:" + character);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
-
在TestPerson类的主方法里,实例化Person对象,然后直接输出对象
-
直接打印对象变量,输出的并不是对象的内容,而是对象名@哈希码。
-
类似的,大家可以参看Python代码
-
如果要输出对象的内容,那么需要改写Person类的
toString()
方法,可以利用IDEA集成开发环境帮助我们快捷生成
-
其实,按
<Alt>
+<Insert>
会弹出Generate
菜单,在里面选择toString()
,即可帮我们重写类的toString()
方法,该方法上有个重写注解符@Override
-
重写
toString()
方法后,查看Person类代码
-
此时,再执行TestPerson,查看结果
-
由于没有设置对象的属性值,因此成员变量都有默认初始值,字符串变量初值是
null
,整型变量初值是0
。 -
设置对象的属性与调用对象的方法
package c03.s01.p01;
/**
* 功能:测试Person类
* 作者:Java课程项目组
* 日期:2021年02月22日
*/
public class TestPerson {
public static void main(String[] args) {
// 实例化Person对象
Person p = new Person();
// 设置对象属性
p.name = "李晓红";
p.character = - 1;
// 输出Person对象
System.out.println(p);
// 调用对象方法
p.speak();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
-
运行程序,查看结果
-
人品值设置为-1,显然这样做是不合理的,应该把属性私有化,统一地提供访问私有属性的公共方法,包括设置与读取私有属性值。在下一讲,我们会对Person类进行改进。
-
大家可以参看一下完成相同任务的Python代码,Python类的__str__()方法就类似于Java类的toString()方法
"""
创建类与对象
"""
class Person:
def setName(self, name):
self.name = name
def setCharacter(self, character):
self.character = character
def speak(self):
print("嗨, 我叫" + self.name + ",人品值:" + str(self.character))
def __str__(self):
return "Person {name='" + self.name + "', character=" + str(self.character) + "}"
if __name__ == "__main__":
p = Person()
p.name = "李晓红"
p.character = -1
print(p)
p.speak()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 运行程序,查看结果
- name与character属性是Person类的对象属性,可以通过对象名.属性名的方式访问,也可以通过setXXX()方法来访问:
p.setName("李晓红")
p.setCharacter(-1)
- 1
- 2
3、对象创建的内存分配
- 在创建对象时,程序会占用两块内存区域,分别是
栈内存
和堆内存
。其中Person类型的变量p
被存放在栈内存中,它是一个引用,会指向真正的对象;通过new Person()创建的对象则放在堆内存中,这才是真正的对象。
- 小提示: Java将内存分为两种,即
栈内存
和堆内存
。其中栈内存用于存放基本类型的变量和对象的引用变量(如Person p),堆内存用于存放由new创建的对象和数组。
4、成员变量的调用
- 通过对象的引用来访问对象所有的成员:
对象引用.对象成员
- 直接使用创建的对象本身来引用对象成员:
new 类名().对象成员
- 对比说明:第2种方式,创建实例对象的同时就访问了对象成员,并且在创建后只能访问其中某一个成员,而不能像第1种方式那样可以访问多个对象成员。同时,由于没有对象引用的存在,在完成某一个对象成员的访问后,该对象就会变成垃圾对象。所以,在实际开发中,创建实例对象时多数会使用对象引用。
5、成员变量的初始值
- 成员变量可以不初始化,不同类型的成员变量有默认的初始值。但是要注意一点,局部变量是必须初始化的。
成员变量类型 | 初始值 |
---|---|
byte、short、int、long | 0 |
float、double | 0.0 |
char | 一个空字符,即’\u0000’ |
boolean | false |
引用数据类型 | null,表示变量不引用任何对象 |
6、垃圾对象的形成
- 对象的引用超出作用域
{
Person p1 = new Person();
......
}
- 1
- 2
- 3
- 4
-
说明:变量p1引用了一个Person类型的对象,当这段代码运行完毕时,变量p1就会超出其作用域而被销毁,这时Person类型的对象将因为没有被任何变量所引用而变成垃圾。
-
对象的引用重新指向空地址(null)
{
Person p2 = new Person();
......
p2 = null;
......
}
- 1
- 2
- 3
- 4
- 5
- 6
- 说明:使用变量p2引用了一个Person类型的对象,接着将变量p2的值置为null,被p2所引用的Person对象就会失去引用,成为垃圾对象。
- Java有垃圾自动回收机制,当然也可以调用
System.gc()
方法来显式回收垃圾对象。
(四)访问控制符
1、四个级别访问权限
- 在Java中,针对类、成员方法和属性提供了四种访问级别,分别是private、default、protected和public。
访问范围 | private | default | protected | public |
---|---|---|---|---|
同一类中 | √ | √ | √ | √ |
同一包中 | √ | √ | √ | |
子类中 | √ | √ | ||
全局范围 | √ |
(1)private(当前类访问级别)
- 如果类的成员被private访问控制符来修饰,则这个成员只能被该类的其他成员访问,其他类无法直接访问。类的良好封装就是通过private关键字来实现的。
(2)default(包访问级别)
- 如果一个类或者类的成员不使用任何访问控制符修饰,则称它为默认访问控制级别,这个类或者类的成员只能被本包中的其他类访问。
(3)protected(子类访问级别)
- 如果一个类的成员被protected访问控制符修饰,那么这个成员既能被同一包下的其他类访问,也能被不同包下该类的子类访问。
(4)public(公共访问级别)
- 这是一个最宽松的访问控制级别,如果一个类或者类的成员被public访问控制符修饰,那么这个类或者类的成员能被所有的类访问,不管访问类与被访问类是否在同一个包中。
2、案例演示访问权限
(1)演示default访问权限
- 查看Person类,
name
与character
属性之前没有任何访问权限修饰符,那就是default
权限
- 查看TestPerson类
- 注意,TestPerson与Person是在同一个包里,所以TestPerson里的person对象可以访问默认的name与character属性。假如将TestPerson复制到包
c03.s01.p01.test
里,由于此包里的TestPerson与Person不在同一包里,于是TestPerson里的Person对象就不能访问默认的name与character属性了。
- 将出错的两行代码注释掉
(2) 演示private访问权限
- 修改
c03.s01.p01
包里的Person类,将其name与character属性访问权限改为private
,于是它们只能当前类访问,即使同一包里的其它类也无法访问
- 查看与Person同一个包里的TestPerson类,设置Person类的私有属性name与character就会报错
- 由于name与character是Person类的私有属性,只能在当前类里被访问,而不能被当前类以外其它对象访问,即使是同一包里的TestPerson类也无法访问Person的私有属性,也就是私有属性被保护起来了,那么对于私有属性,该如何去访问呢?下一讲,我们会学习如何创建公共的
setXXX()
和getXXX()
方法来访问类的私有属性。 - 将出错的两行代码暂时注释掉
(3)演示protected访问权限
-
将
c03.s01.p01
包里的Person类的name与character属性的访问权限改为protected
,这样,name与character属性不仅可以被同一包里的其它类方法,还可以被不在同一包里的其子类访问,当然不在同一包里的非子类是无法访问的。
-
在同一包里的TestPerson类可以访问protected属性name与character
-
在不同包里的TestPerson就不能访问protected属性name与character
-
前面讲了,protected属性可以被不同包里该类的子类访问,下面我们演示如何访问。首先在
c03.s01.p01.test
里继承Person,创建一个子类Man,Java里是用关键字extends
来实现继承的
-
按
<Ctrl> + <H>
组合键,可以查看Man类继承层次结构,另外还可以利用快捷菜单还可以查看类图
-
在主方法里实例化Man对象,设置其属性name与character(都是父类Person里的protected属性),调用其方法speak()
(4)演示public访问权限
- 将net.hw.lesson09里的Person类的name与character属性的访问权限改为
public
,这样,name与character属性能被任何类访问,不管这个类是否与Person类在同一个包里
- 此时,同一个包
c03.s01.p01
里的TestPerson可以访问Person的公共属性name与character
- 在不同包
c03.s01.p01.test
里的TestPerson也可以访问Person的公共属性name与character
三、课后作业
1、采用面向对象方式计算三角形面积
- 创建三角形类Triangle,包含a、b、c三个默认属性,一个公共方法getArea()。然后创建一个测试类TestTriangle,在其主方法里创建Triangle对象,设置对象属性,调用对象方法得到三角形面积。a、b、c暂时采用默认权限,大家编写获取面积的公共方法getArea(),该方法有一个double类型的返回值。
- Triangle类图
- TestTriangle类图
- 运行结果
- 学了下一讲《类的封装》,我们可以改造Triangle类,a、b、c都是私有属性,提供访问私有属性的公共方法getXXX()和setXXX()。
2、采用面向对象方式求解一元二次方程
- 创建一元二次方程类Equation,包含a、b、c三个默认属性,一个公共方法solve()。然后创建一个测试类TestEquation,在其主方法里创建Equation对象,设置对象属性,调用对象方法求解方程。a、b、c暂时采用默认权限,大家编写求解方程的方法solve(),该方法没有返回值。
- Equation类图
- TestEquation类图
- 运行结果
文章来源: howard2005.blog.csdn.net,作者:howard2005,版权归原作者所有,如需转载,请联系作者。
原文链接:howard2005.blog.csdn.net/article/details/123749988
- 点赞
- 收藏
- 关注作者
评论(0)