- JavaSE笔记(李兴华老师)
- 第5章:类与对象
- 5.1 面向对象简介
- 5.1.1 面向对象
- 5.1.2 面向对象特点
- 5.2 类与对象
- 5.2.1 类与对象
- 5.2.2 类组成
- 5.2.2 类定义
- 5.2.2.1 范例:类的定义
- 5.2.3 对象操作
- 5.2.3.1 范例:通过实例化对象进行类操作
- 5.2.4 对象内存分析
- 5.2.4.1 范例:类引用数据类型使用分析
- 5.2.4.2 范例:对象实例化处理
- 5.2.4.3 范例:引用传递
- 5.2.4.4 范例:通过方法实现引用传递
- 5.2.4.4 范例:引用传递与垃圾产生
- 5.3 成员属性封装
- 5.3.1 属性封装
- 5.3.1.1 范例:使用private实现封装
- 5.4 构造方法与匿名对象
- 5.4.1 构造方法
- 5.4.1.1 范例:定义构造方法为属性初始化
- 5.4.1.2 范例:构造方法重载
- 5.4.2 匿名对象
- 5.4.2.1 范例:使用构造方法接收引用数据类型
- 5.5 this关键字
- 5.5.1 this
- 5.5.1.1 范例:通过“this.成员属性”访问
- 5.5.2 方法调用
- 5.5.2.1 范例:使用this调用本类普通方法
- 5.5.2.2 范例:使用this()实现本类构造的互调用
- 5.5.3 构造方法案例
- 5.5.4 当前对象
- 5.5.4.1 范例:实现消息发送逻辑 —— 1
- 5.5.4.2 范例:实现消息发送逻辑 —— 2
- 5.5.5 简单Java类
- 5.5.5.1 范例:定义一个描述部门的简单Java类
- 5.6 static关键字
- 5.6.1 static
- 5.6.2 static属性
- 5.6.2.1 范例:通过类名称直接调用static属性
- 5.6.3 范例:定义static方法
- 5.6.4 范例:实例化对象个数统计
- 5.6.5 范例:实现属性自动命名
- 5.7 代码块
- 5.7.1 代码块
- 5.7.1.1 普通代码块
- 5.7.2 构造块
- 5.7.2.1 范例:在非主类中定义静态块
- 5.7.2.2 范例:在主类中定义静态代码块
第5章:类与对象 5.1 面向对象简介 5.1.1 面向对象
面向对象是一种现在最为流行的程序设计方法;
在面向对象设计之前,广泛采用的是面向过程;
面向对象以模块化设计思想为主实现的代码封装;
面向对象的程序设计有三个主要的特性:封装性、继承性、多态性。
- 封装性:隐藏内部实现机制;
- 继承性:实现代码重用;
- 多态性:同一标准有不同实现;
类是客观世界的抽象,对象是具体的实例。
成员属性(Field),主要用于保存对象的具体特征。例如:不同的人都有姓名、性别、学历、身高、体重等信息,但是不同的人都有不同的内容定义,而类就需要对这些描述信息进行统一的管理;
方法(Method),用于描述功能,例如:跑步、吃饭、唱歌,所有人的对象都有相同的功能。
使用class关键字定义类:
class 类名称 {
[访问修饰符] 数据类型 成员属性(变量);
... ...
public 返回值的数据类型 方法名称(参数类型 参数1 , 参数类型 参数2 , …){
程序语句 ;
[return 表达式;]
}
}
5.2.2.1 范例:类的定义
class Person { // 定义一个类
String name; // 【成员属性】人的姓名
int age; // 【成员属性】人的年龄
public void tell() {
System.out.println("姓名:" + name + "、年龄:" + age);
}
}
5.2.3 对象操作
对象实例化格式:
声明并实例化对象:类名称 对象名称 = new 类名称 () ;
分步定义:
声明对象:类名称 对象名称 = null ;
实例化对象:对象名称 = new 类名称 () ;
对象调用类结构:
对象.成员属性:表示调用类之中的成员属性,可以为其赋值或者获取其保存内容
对象.方法():表示调用类之中的方法。
class Person { // 定义一个类,后续讲解中为防止重复不再重复显示此代码
String name; // 【成员属性】人的姓名
int age; // 【成员属性】人的年龄
public void tell() {
System.out.println("姓名:" + name + "、年龄:" + age);
}
}
public class JavaDemo {
public static void main(String args[]) {
Person per = new Person(); // 声明并实例化对象
per.name = "张三";// 为成员属性赋值
per.age = 18; // 为成员属性赋值
per.tell(); // 进行方法的调用
}
}
5.2.4 对象内存分析
Java中类属于引用数据类型,所有的引用数据类型在使用过程中都要通过关键字new开辟新的内存空间,当对象拥有了内存空间后才可以实现成员属性的信息保存,在引用数据类型操作中最为重要的内存有两块:
- 【heap】堆内存:保存的是对象的具体信息(成员属性),在程序之中堆内存空间的开辟是通过new完成的;
- 【stack】栈内存:保存的是一块堆内存的地址,即:通过地址找到堆内存,而后找到对象内容,但是为了分析简化起见可以简单的理解为:对象名称保存在了栈内存之中。
class JavaDemo {
public static void main(String args[]) {
Person per = new Person(); // 【1】声明并实例化对象
per.name = "张三“; // 【2】为成员属性赋值
per.age = 18; // 【3】为成员属性赋值
per.tell(); // 进行方法的调用
}
}
public class JavaDemo {
public static void main(String args[]) {
Person per = null ;// 【1】声明对象
per = new Person(); // 【2】实例化对象
per.name = "张三“;// 【3】为成员属性赋值
per.age = 18; // 【4】为成员属性赋值
per.tell(); // 进行方法的调用
}
}
5.2.4.3 范例:引用传递
public class JavaDemo {
public static void main(String args[]) {
Person per1 = new Person() ; // 声明并实例化对象
per1.name = "张三" ; // 为属性赋值
per1.age = 18 ; // 为属性赋值
Person per2 = per1 ; // 引用传递
per2.age = 80 ;// 修改age属性定义
per1.tell() ;// 进行方法的调用
}
}
5.2.4.4 范例:通过方法实现引用传递
public class JavaDemo {
public static void main(String args[]) {
Person per = new Person() ; // 声明并实例化对象
per.name = "张三" ;// 为属性赋值
per.age = 18 ; // 为属性赋值
change(per) ; // 等价于:Person temp = per ;
per.age = 80 ; // 修改age属性定义
per.tell() ;// 进行方法的调用
}
public static void change(Person temp) {// temp接收Person类型
temp.age = 80 ;// 修改对象属性
}
}
5.2.4.4 范例:引用传递与垃圾产生
public class JavaDemo {
public static void main(String args[]) {
Person per1 = new Person() ; // 声明并实例化对象
Person per2 = new Person() ; // 声明并实例化对象
per1.name = "张三" ;// 为属性赋值
per1.age = 18 ;// 为属性赋值
per2.name = "李四" ;// 为属性赋值
per2.age = 19 ;// 为属性赋值
per2 = per1 ; // 引用传递
per2.age = 80 ;// 修改age属性定义
per1.tell() ; // 进行方法的调用
}
}
5.3 成员属性封装
5.3.1 属性封装
private声明属性,不允许外部直接访问该属性;
private私有操作原则:
- setter(以“private String name”属性为例):public void setName(String n);
- getter(以“private String name”属性为例):public String getName();
class Person { // 定义一个类
private String name; // 【成员属性】人的姓名
private int age; // 【成员属性】人的年龄
public void tell() {
System.out.println("姓名:" + name + "、年龄:" + age);
}
public void setName(String tempName) { // 设置name属性内容
name = tempName;
}
public void setAge(int tempAge) {// 设置age属性内容
if (tempAge > 0 && tempAge < 250) {// 如果有需要则可以追加一些验证逻辑
age = tempAge;
}
}
public String getName() return name; }
public int getAge() { return age; }
}
public class JavaDemo {
public static void main(String args[]) {
Person per = new Person() ;// 声明并实例化对象
per.setName("张三") ; // 设置属性内容
per.setAge(-18) ; // 设置属性内容
per.tell() ; // 进行方法的调用
}
}
5.4 构造方法与匿名对象
5.4.1 构造方法
在Java语言中,类中构造方法的定义要求如下:
- 构造方法的名称和类名称保持一致;
- 构造方法不允许有返回值类型声明;
- 由于对象实例化操作一定需要构造方法的存在,所以如果在类之中没有明确定义构造方法的话,则会自动的生成一个无参数并且无返回值的构造方法,供用户使用,如果一个类之中已经明确的定义了一个构造方法的话,则无参的什么都不做的构造方法将不会自动生成,也就是说,一个类之中至少存在一个构造方法。
private String name; // 【成员属性】人的姓名
private int age; // 【成员属性】人的年龄
public Person(String tempName, int tempAge) {// 构造方法
name = tempName ;// name属性初始化
age = tempAge ;// age属性初始化
}
// setter、getter略 ...
public void tell() {
System.out.println("姓名:" + name + "、年龄:" + age);
}
}
public class JavaDemo {
public static void main(String args[]) {
Person per = new Person("张三", 18); // 声明并实例化对象
per.tell() ; // 进行方法的调用
}
}
5.4.1.2 范例:构造方法重载
class Person { // 定义一个类
private String name; // 【成员属性】人的姓名
private int age; // 【成员属性】人的年龄
public Person() { // 【构造方法重载】定义无参构造方法
name = "无名氏" ; // 设置name属性内容
age = -1 ;// 设置age属性内容
}
public Person(String tempName) {// 【构造方法重载】定义单参构造方法
name = tempName ; // 设置name属性内容
}
public Person(String tempName, int tempAge) {// 【构造方法重载】定义双参构造方法
name = tempName ; // name属性初始化
age = tempAge ; // age属性初始化
}
// setter、getter略 ...
public void tell() {
System.out.println("姓名:" + name + "、年龄:" + age);
}
}
public class JavaDemo {
public static void main(String args[]) {
Person per = new Person("张三"); // 声明并实例化对象
per.tell() ;// 进行方法的调用
}
}
5.4.2 匿名对象
匿名对象只能够使用一次,并且不会有栈内存指向。
public class JavaDemo {
public static void main(String args[]) {
new Person("张三", 18).tell(); // 进行方法的调用
}
}
5.4.2.1 范例:使用构造方法接收引用数据类型
class Message {
private String info ;
public Message(String tempInfo) {
info = tempInfo ;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
class Person { // 定义一个类
private String name; // 【成员属性】人的姓名
private int age; // 【成员属性】人的年龄
public Person(Message msg, int tempAge) { // 定义双参构造方法
name = msg.getInfo() ; // name属性初始化
age = tempAge ; // age属性初始化
}
public Message getMessage() { // 返回Message对象
return new Message("姓名:" + name + "、年龄:" + age) ;
}
// setter、getter略 ...
public void tell() {
System.out.println("姓名:" + name + "、年龄:" + age);
}
}
5.5 this关键字
5.5.1 this
this描述的是本类结构调用的关键字,在Java中this关键字可以描述三种结构的调用:
- 当前类中的属性:this.属性;
- 当前类中的方法(普通方法、构造方法):this()、this.方法名称();
- 描述当前对象;
class Person { // 定义一个类
private String name; // 【成员属性】人的姓名
private int age; // 【成员属性】人的年龄
public Person(String name, int age) {
this.name = name ;// 使用this标注本类属性
this.age = age ; // 使用this标注本类属性
}
// setter、getter略 ...
public void tell() {// 使用this明确标准本类属性
System.out.println("姓名:" + this.name + "、年龄:" + this.age);
}
}
public class JavaDemo {
public static void main(String args[]) {
Person per = new Person("张三", 12);// 实例化Person类对象
per.tell(); // 信息输出
}
}
5.5.2 方法调用
一个类里会有两种方法定义:普通方法、构造方法,这样在一个类中如果要想实现本类方法的调用,就可以通过“this”关键字来实现:
- 调用本类普通方法:可以使用“this.方法()”调用,并且可以在构造方法与普通方法中使用;
- 调用本类构造方法:调用本类其他构造使用“this()”形式,此语句只允许放在构造方法首行。
class Person { // 定义一个类
private String name;// 【成员属性】人的姓名
private int age; // 【成员属性】人的年龄
public Person(String name, int age) {
this.setName(name);// 调用本类setName()方法
setAge(age) ; // 不使用“this.方法()”也表示调用本类方法
}
public void tell() {// 使用this明确标准本类属性
System.out.println("姓名:" + this.name + "、年龄:" + this.age);
}
// setter、getter略
}
public class JavaDemo {
public static void main(String args[]) {
Person per = new Person("张三", 12);// 实例化Person类对象
per.tell(); // 信息输出
}
}
5.5.2.2 范例:使用this()实现本类构造的互调用
class Person { // 定义一个类
private String name; // 【成员属性】人的姓名
private int age; // 【成员属性】人的年龄
public Person() { // 【构造方法重载】无参构造
System.out.println("*** 一个新的Person类对象实例化了。 ***");
}
public Person(String name) {// 【构造方法重载】单参构造
this();// 调用本类无参构造
this.name = name; // 设置name属性内容
}
public Person(String name, int age) { // 【构造方法重载】双参构造
this(name); // 调用本类单参构造
this.age = age; // 设置age属性内容
}
public void tell() {// 使用this明确标准本类属性
System.out.println("姓名:" + this.name + "、年龄:" + this.age);
}
// setter、getter略
}
public class JavaDemo {
public static void main(String args[]) {
Person per = new Person("张三", 12); // 实例化Person类对象
per.tell(); // 信息输出
}
}
5.5.3 构造方法案例
现在要求定义一个描述有员工信息的程序类,该类中提供有:编号、姓名、部门、工资,在这个类之中提供有四个构造方法:
- 【无参构造】编号定义为1000,姓名定义为无名氏,其它内容均为默认值;
- 【单参构造】传递编号,姓名定义为“新员工”,部门定义为“未定”,工资为0.0;
- 【三参构造】传递编号、姓名、部门,工资为2500.00;
- 【四参构造】所有的属性全部进行传递。
class Message {
public void printThis() {
System.out.println("【Mesasge类】this = " + this); // 表示当前对象
}
}
public class JavaDemo {
public static void main(String args[]) {
Message msgA = new Message();// 实例化Message类对象
System.out.println("【主类】msgA = " + msgA);// 直接输出对象
msgA.printThis();// 调用方法输出this
System.out.println("-----------------------------------");
Message msgB = new Message();// 实例化Message对象
System.out.println("【主类】msgB = " + msgB); // 直接输出对象
msgB.printThis();// 调用方法输出this
}
}
5.5.4.1 范例:实现消息发送逻辑 —— 1
class Message {
private Channel channel; // 保存消息发送通道
private String title; // 消息标题
private String content; // 消息内容
// 【4】调用此构造实例化,此时的channel = 主类ch
public Message(Channel channel, String title, String content) {
this.channel = channel; // 保存消息通道
this.title = title; // 设置title属性
this.content = content; // 设置content属性
}
public void send() {
// 【6】判断当前通道是否可用,那么此时的this.channel就是主类中的ch
if (this.channel.isConnect()) { // 连接成功
System.out.println("【消息发送】title = " + this.title + "、content = " + this.content);
} else { // 没有连接
System.out.println("【ERROR】没有可用的连接通道,无法进行消息发送。");
}
}
}
5.5.4.2 范例:实现消息发送逻辑 —— 2
class Channel {
private Message message; // 消息发送由Message负责
// 【2】实例化Channel类对象,调用构造方法,接收要发送的消息标题与消息内容
public Channel(String title, String content) {
// 【3】实例化Message,但是需要将主类中的ch传递到Message中、this = ch
this.message = new Message(this, title, content);
this.message.send(); // 【5】消息发送
}
// 以后在进行方法创建的时候如果某一个方法的名称以is开头一般都返回boolean值
public boolean isConnect() { // 判断连接是否创建
return true;// 默认返回true
}
}
public class JavaDemo {
public static void main(String args[]) {
// 【1】实例化一个Channel对象,并且传入要发送的消息标题与消息内容
Channel ch = new Channel("MLDN运动会", "大家一起长跑30公里。"); // 实例化Channel对象并发送消息
}
}
5.5.5 简单Java类
简单java类指的是可以描述某一类信息的程序类,例如:描述个人信息、描述书信息、描述部门信息等,并且在这个类之中并没有特别复杂的逻辑操作,只作为一种信息保存的媒介存在。对于简单Java类而言,其核心的开发结构如下:
- 类名称一定要有意义,可以明确的描述某一类事物;
- 类之中的所有属性都必须使用private进行封装,封装后的属性必须要提供有setter、getter方法;
- 类之中可以提供有无数多个构造方法,但是必须要保留有无参构造方法;
- 类之中不允许出现任何的输出语句,所有内容的获取必须返回;
- 【可选】可以提供有一个获取对象详细信息的方法,暂时将此方法名称定义为getInfo()。
class Dept { // 类名称可以明确描述出某类事物
private long deptno ;// 类中成员属性封装
private String dname ;// 类中成员属性封装
private String loc ;// 类中成员属性封装
public Dept() {} // 提供有无参
public Dept(long deptno, String dname, String loc) {
this.deptno = deptno ;// 设置deptno属性内容
this.dname = dname ;// 设置dname属性内容
this.loc = loc ; // 设置loc属性内容
}
public String getInfo() { // 获取对象信息
return "【部门信息】部门编号:" + this.deptno + "、部门名称:" + this.dname + "、部门位置:" + this.loc ;
}
// setter、getter略
}
public class JavaDemo {
public static void main(String args[]) {
Dept dept = new Dept(10,"技术部","北京") ; // 实例化类对象
System.out.println(dept.getInfo()) ; // 获取对象信息
}
}
5.6 static关键字
5.6.1 static
static是一个用于声明程序结构的关键字,利用此关键字可以用于全局属性和全局方法的声明,主要的特点是可以避免对象实例化的限制,可以在没有实例化对象的时候直接进行此类结构的访问。
5.6.2 static属性class Chinese {
private String name ;// 【普通成员属性】保存姓名信息
private int age ;// 【普通成员属性】保存年龄信息
static String country = "中华人民共和国" ; // 【静态成员属性】国家,暂时不封装
public Chinese(String name,int age) {// 设置普通属性内容
this.name = name ;// 设置name属性内容
this.age = age ; // 设置age属性内容
}
// setter、getter略
public String getInfo() {
return "姓名:" + this.name + "、年龄:" + this.age + "、国家:" + this.country ;
}
}
public class JavaDemo {
public static void main(String args[]) {
Chinese perA = new Chinese("张三",10) ;// 实例化Chinese类对象
Chinese perB = new Chinese("李四",10) ;// 实例化Chinese类对象
Chinese perC = new Chinese("王五",11) ;// 实例化Chinese类对象
perA.country = "伟大的中国" ; // 修改静态属性内容
System.out.println(perA.getInfo()) ;// 获取对象信息
System.out.println(perB.getInfo()) ;// 获取对象信息
System.out.println(perC.getInfo()) ;// 获取对象信息
}
}
5.6.2.1 范例:通过类名称直接调用static属性
public class JavaDemo {
public static void main(String args[]) {
System.out.println("直接访问static属性:" + Chinese.country);
Chinese.country = "伟大的中国" ; // 修改静态属性内容
Chinese per = new Chinese("张三",10) ; // 实例化Chinese类对象
System.out.println(per.getInfo()) ; // 获取对象信息
}
}
5.6.3 范例:定义static方法
class Chinese {
private String name ; // 【普通成员属性】保存姓名信息
private int age ; // 【普通成员属性】保存年龄信息
private static String country = "中国" ; // 【静态成员属性】保存国家信息
public Chinese(String name,int age) { // 设置普通属性内容
this.name = name ; // 设置name属性内容
this.age = age ; // 设置age属性内容
}
public static void setCountry(String c) {
country = c;// 修改static属性
}
// setter、getter略
public String getInfo() {
return "姓名:" + this.name + "、年龄:" + this.age + "、国家:" + Chinese.country ;
}
}
public class JavaDemo {
public static void main(String args[]) {
Chinese.setCountry("中华人民共和国") ; // 修改静态属性内容
Chinese per = new Chinese("张三",10) ; // 实例化Chinese类对象
System.out.println(per.getInfo()) ;// 获取对象信息
}
}
5.6.4 范例:实例化对象个数统计
class Book {
private String title ; // 【普通成员属性】保存图书名称
private static int count = 0 ; // 【静态成员属性】保存对象个数
public Book(String title) {
this.title = title ; // 保存title内容
count ++ ; // 对象个数累加
System.out.println("第" + count + "本图书创建出来。") ;
}
// setter、getter略 ...
}
public class JavaDemo {
public static void main(String args[]) {
new Book("Java开发实战经典"); // 实例化新的Book类对象
new Book("Spring实战开发"); // 实例化新的Book类对象
new Book("Spring微架构实战开发");// 实例化新的Book类对象
}
}
5.6.5 范例:实现属性自动命名
class Book {
private String title ;// 【普通成员属性】保存图书名称
private static int count = 0 ;// 【静态成员属性】保存对象个数
public Book() {
this("MLDNTITLE - " + count ++) ;// 调用单参构造
}
public Book(String title) {
this.title = title ;// 保存title内容
}
public String getTitle() {
return title;
}
// setter略 ...
}
public class JavaDemo {
public static void main(String args[]) {
System.out.println(new Book("Java开发实战经典").getTitle());
System.out.println(new Book().getTitle());
System.out.println(new Book("Spring实战开发").getTitle());
System.out.println(new Book().getTitle());
}
}
5.7 代码块
5.7.1 代码块
代码块是在程序之中使用“{}”定义起来的一段程序,而根据代码块声明位置以及声明关键字的不同,代码块一共分为四种:普通代码块、构造块、静态块、同步块。
5.7.1.1 普通代码块普通代码块是定义在方法之中的代码块,利用这类代码块可以 在一个方法中过长导致出现重复变量定义的问题
public class JavaDemo {
public static void main(String args[]) {
{// 普通代码块
int x = 10 ;// 定义局部变量
System.out.println("x = " + x) ; // 输出局部变量内容
}
int x = 100 ;// 定义全局变量
System.out.println("x = " + x) ;// 输出全局变量内容
}
}
5.7.2 构造块
将代码块定义在一个类中,这样就成为了构造块,构造块的主要特点是在使用关键字new实例化新对象时进行调用。
class Person {
public Person() {// 构造方法
System.out.println("【构造方法】Person类构造方法执行");
}
{// 构造块
System.out.println("【构造块】Person构造块执行");
}
}
public class JavaDemo {
public static void main(String args[]) {
new Person(); // 实例化新对象
new Person(); // 实例化新对象
}
}
5.7.2.1 范例:在非主类中定义静态块
class Person {
public Person() {// 构造方法
System.out.println("【构造方法】Person类构造方法执行");
}
static { // 静态块
System.out.println("【静态块】静态块执行。") ;
}
{ // 构造块
System.out.println("【构造块】Person构造块执行");
}
}
public class JavaDemo {
public static void main(String args[]) {
new Person(); // 实例化新对象
new Person(); // 实例化新对象
}
}
5.7.2.2 范例:在主类中定义静态代码块
public class JavaDemo {
static { // 主类中的静态代码块
System.out.println("********* 魔乐科技(MLDN) *********");
}
public static void main(String args[]) { // 主方法
System.out.println("www.mldn.cn");
}
}



