Java讲课笔记09:类与对象
零、本讲学习目标
1、理解面向对象的概念
2、熟悉面向对象的三个特点
3、掌握类和对象的定义和使用
4、熟悉访问控制符
一、面向对象概述
1、什么是面向对象?
面向对象是一种符合人类思维习惯的编程思想。现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象。
2、面向过程 vs. 面向对象
- 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一一实现,使用的时候依次调用就可以了。(POP:Procedure-Oriented Programming)
- 面向对象则是把构成问题的事务按照一定规则划分为多个独立的对象,然后通过调用对象的方法来解决问题。(OOP:Object-Oriented Programming)
3、面向对象三大特点
面向对象是把构成问题的事务按照一定规则划分为多个独立的对象,然后通过调用对象的方法来解决问题。一个应用程序会包含多个对象,通过多个对象的相互配合来实现应用程序的功能,这样当应用程序功能发生变动时,只需要修改个别的对象就可以了,从而使代码更容易得到维护。面向对象的特点主要可以概括为封装性、继承性和多态性。
(1)封装(encapsulation)
封装是面向对象的核心思想,将对象的属性(property)和行为(behavior)封装起来,不需要让外界知道具体实现细节。
(2)继承(inheritance)
继承主要描述的就是类与类之间的关系,通过继承,可以在无需重新编写原有类的情况下,对原有类的功能进行扩展(extend)。
(3)多态(polymorphism)
多态指的是在一个类中定义的属性和功能被其他类继承后,当把子类对象直接赋值给父类引用变量时,相同引用类型的变量调用同一个方法所呈现出的多种不同行为特性。
二、Java中的类与对象
1、类与对象的关系
面向对象的编程思想,力图让程序中对事物的描述与该事物在现实中的形态保持一致。为了做到这一点,面向对象的思想中提出了两个概念——类和对象。
类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体。简而言之,类是模板(template),对象是实例(instance)。
- 分析: 可以将上图人看作是一个类,将每个具体的人(如小韩、小石等)看作对象,从人与具体个人之间的关系便可以看出类与对象之间的关系。
- 说明: 类用于描述多个对象的共同特征,它是对象的模板,而对象用于描述现实中的个体,它是类的实例。对象是类的具体化,并且一个类可以对应多个对象。
2、类的定义
在面向对象的思想中,最核心的就是对象。为了在程序中创建对象,首先需要定义一个类。类是对象的抽象,它用于描述一组对象的共同特征和行为,例如人都有姓名、年龄、性别等特征,还有学习、工作、购物等行为。
以面向对象的编程思想,就可以将某一类中共同的特征和行为封装起来,把共同特征作为类的属性(property),也叫成员变量(member variable),把共同行为作为类的方法(method),也叫成员方法(member method)。
(1)类的定义格式
(2)声明成员变量
(3)声明成员方法
(4)创建类案例演示
创建Person类,包含两个属性:姓名(name)和人品(character、
),另外还包含一个自我介绍的方法speak()。注意:要求人品值在[1, 10]。
package net.hw.lesson09;
/**
* 功能:Person类
* 作者:华卫
* 日期:2020年4月25日
*/
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值就是“李晓红”。
- 创建TestPerson测试类,在主方法里创建Person对象,调用其speak()方法
3、对象的创建与使用
应用程序想要完成具体的功能,仅有类是远远不够的,还需要根据类创建实例对象。
(1)对象创建语法格式
类名 对象名称 = new 类名();
- new 类名() 是基于指定类创建一个新的实例(对象)
- 对象名称是一个引用变量,指向创建的实例(对象)
(2)创建对象案例演示
- 修改Person类,取消对成员变量赋初值,删除成员方法里定义的局部变量
package net.hw.lesson09;
/**
* 功能:Person类
* 作者:华卫
* 日期:2020年4月25日
*/
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()方法,可以利用集成开发环境提供的快捷方式帮我们自动生成,如下GIF动画所示:
此时Person类的代码如下:
此时,再执行TestPerson,结果如下:
设置对象的属性与调用对象的方法:
package net.hw.lesson09;
/**
* 功能:测试Person类
* 作者:华卫
* 日期:2020年4月25日
*/
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
运行程序,查看结果:
显然这样做是不合理的,应该把属性私有化,统一地提供访问私有属性的公共方法,包括设置与读取私有属性值。在下一讲《Java讲课笔记10:类的封装》,我们会对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种方式那样可以访问多个对象成员。同时,由于没有对象引用的存在,在完成某一个对象成员的访问后,该对象就会变成垃圾对象。所以,在实际开发中,创建实例对象时多数会使用对象引用。
(3)成员变量的初始值
成员变量可以不初始化,不同类型的成员变量有默认的初始值。但是要注意一点,局部变量是必须初始化的。
成员变量类型 | 初始值 |
---|---|
byte、short、int、long | 0 |
float、double | 0.0 |
char | 一个空字符,即’\u0000’ |
boolean | false |
引用数据类型 | null,表示变量不引用任何对象 |
(4)垃圾对象的形成
- 对象的引用超出作用域
{
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()
方法来显式回收垃圾对象。
4、访问控制符
在Java中,针对类、成员方法和属性提供了四种访问级别,分别是private、default、protected和public。
(1)private(当前类访问级别)
如果类的成员被private访问控制符来修饰,则这个成员只能被该类的其他成员访问,其他类无法直接访问。类的良好封装就是通过private关键字来实现的。
(2)default(包访问级别)
如果一个类或者类的成员不使用任何访问控制符修饰,则称它为默认访问控制级别,这个类或者类的成员只能被本包中的其他类访问。
(3)protected(子类访问级别)
如果一个类的成员被protected访问控制符修饰,那么这个成员既能被同一包下的其他类访问,也能被不同包下该类的子类访问。
(4)public(公共访问级别)
这是一个最宽松的访问控制级别,如果一个类或者类的成员被public访问控制符修饰,那么这个类或者类的成员能被所有的类访问,不管访问类与被访问类是否在同一个包中。
访问范围 | private | default | protected | public |
---|---|---|---|---|
同一类中 | √ | √ | √ | √ |
同一包中 | √ | √ | √ | |
子类中 | √ | √ | ||
全局范围 | √ |
(5)案例演示访问权限
a. 演示default访问权限
- 查看Person类
- name与character属性之前没有任何访问权限修饰符,那就是default权限
- 查看TestPerson类
注意,TestPerson与Person是在同一个包里,所以TestPerson里的person对象可以访问默认的name与character属性。假如将TestPerson复制到包net.hw.lesson09.test里,由于此包里的TestPerson与Person不在同一包里,于是TestPerson里的Person对象就不能访问默认的name与character属性了,如下图所示:
b. 演示private访问权限
- 将net.hw.lesson09里的Person类的name与character属性的访问权限修改为private
- 查看net.hw.lesson09包里的TestPerson类
由于name与character是Person类的私有属性,只能在当前类里被访问,而不能被当前类以外其它对象访问,即使是同一包里的TestPerson类也无法访问Person的私有属性,也就是私有属性被保护起来了,那么对于私有属性,该如何去访问呢?下一讲《Java讲课笔记10:类的封装》,我们会学习如何创建setters和getters来访问类的私有属性。
c. 演示protected访问权限
- 将net.hw.lesson09里的Person类的name与character属性的访问权限修改为protected
- 在同一包net.hw.lesson09里的TestPerson类可以访问protected属性name与character
- 在不同包net.hw.lesson09.test里的TestPerson就不能访问protected属性name与character
前面讲了,protected属性可以被不同包里该类的子类访问,下面我们演示如何访问。
- 首先在net.hw.lesson09.test里继承Person,创建一个子类Man
按<Ctrl> + <H>
组合键,可以查看Man类的继承层次结构:
然后在主方法里实例化Man对象,设置其属性name与character(都是父类Person里的protected属性),调用其方法speak(),如下图所示:
d. 演示public访问权限
- 将net.hw.lesson09里的Person类的name与character属性的访问权限修改为public
- 此时,同一个包里的TestPerson可以访问Person的公共属性name与character
- 在不同包net.hw.lesson09.test里的TestPerson也可以访问Person的公共属性name与character
三、课后作业
1、采用面向对象方式计算三角形面积
创建三角形类Triangle,包含a、b、c三个默认属性,一个公共方法getArea()。然后创建一个测试类TestTriangle,在其主方法里创建Triangle对象,设置对象属性,调用对象方法得到三角形面积。a、b、c暂时采用默认权限,下一讲我们再设置为private权限,再创建setters和getters来访问私有属性a、b、c。大家编写获取面积的方法getArea(),该方法有一个double类型的返回值。
2、采用面向对象方式求解一元二次方程
创建一元二次方程类Equation,包含a、b、c三个默认属性,一个公共方法solve()。然后创建一个测试类TestEquation,在其主方法里创建Equation对象,设置对象属性,调用对象方法求解方程。a、b、c暂时采用默认权限,下一讲我们再设置为private权限,再创建setters和getters来访问私有属性a、b、c。大家编写求解方程的方法solve(),该方法没有返回值。
文章来源: howard2005.blog.csdn.net,作者:howard2005,版权归原作者所有,如需转载,请联系作者。
原文链接:howard2005.blog.csdn.net/article/details/105751551
- 点赞
- 收藏
- 关注作者
评论(0)