Java语言基础(5)面向对象——类与对象的概念以及对象和引用图文解析

发布时间:2023年12月28日

1.1、 面向过程与面向对象的区别

面向过程编程:Process oriented programming(POP)
面向对象编程:object-oriented programming(OOP)

为什么会出现面向对象分析方法?
因为现实世界太复杂多变,面向过程的分析方法无法满足

面向过程?
采用面向过程必须了解整个过程,每个步骤都有因果关系,每个因果关系都构成了一个步骤,多个步骤就构成了一个系统,因为存在因果关系每个步骤很难分离,非常紧密,当任何一步骤出现问题,将会影响到所有的系统。如:采用面向过程生产电脑,那么他不会分CPU、主板和硬盘,它会按照电脑的工作流程一次成型。
面向对象?
面向对象对会将现实世界分割成不同的单元(对象),实现各个对象,如果完成某个功能,只需要将各个对象协作起来就可以。

1.2、 面向对象的三大特性

● 封装
● 继承
● 多态

1.3、 类与对象的概念

类是对具有共性事物的抽象描述,是在概念上的一个定义,那么如何发现类呢?
通常根据名词(概念)来发现类,如在成绩管理系统中:学生、班级、课程、成绩
学生—张三
班级—001
课程—J2SE
成绩—张三成绩

以上“张三”、“001”、“J2SE”和“张三的成绩”他们是具体存在的,称为对象,也叫实例
也就是说一个类的具体化(实例化),就是对象或实例

为什么面向对象成为主流技术,主要就是因为更符合人的思维模式,更容易的分析现实世界,所以在程序设计中也采用了面向对象的技术,从软件的开发的生命周期来看,基于面向对象可以分为三个阶段:
OOA(面向对象的分析)
OOD(面向对象的设计)
OOP(面向对象的编程)-----Java就是一个纯面向对象的语言

我们再进一步的展开,首先看看学生:
学生:学号、姓名、性别、地址,班级
班级:班级代码、班级名称
课程:课程代码、课程名称
成绩:学生、课程、成绩
大家看到以上我们分析出来的都是类的属性

接下来采用简易的图形来描述一下,来描述我们的概念(来源成绩管理系统的概念,来源于领域的概念,这个领域就是成绩系统管理领域)
在这里插入图片描述
以上描述的是类的属性,也就是状态信息,接下来,再做进一步的细化
在这里插入图片描述
通过以上分析,大家应该了解:
类=属性+方法
属性来源于类的状态,而方法来源于动作

以上模型完全可以使用面向对象的语言,如Java来实现

1.4、 类的定义

在Java中如何定义类?
具体格式:

类的修饰符class 类名extends 父对象名称 implements 接口名称 {
	类体:属性和方法组成
}

Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
● default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
● private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
● public : 对所有类可见。使用对象:类、接口、变量、方法
● protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
我们可以通过以下表来说明访问权限:

修饰符当前类同一包内子孙类(同一包)子孙类(不同包)其他包
publicYYYYY
protectedYYYY/NN
defaultYYYNN
privateYNNNN
public class Student {
	
	//学号
	int id;	
	
	//姓名
	String name;
	
	//性别
	boolean sex;
	
	//地址
	String address;
	
	//年龄
	int age;
	
}

以上属性称为成员变量,局部变量是在方法中定义的变量,方法的参数,方法的返回值,局部变量使用前必须初始化,而成员变量会默认初始化,初始化的值名为该类型的默认值

1.5、 对象的创建和使用

必须使用new创建出来,才能用。
【示例代码】

public class OOTest01 {

	public static void main(String[] args) {
		//创建一个对象
		Student zhangsan = new Student();
		System.out.println("id=" + zhangsan.id);		
		System.out.println("name=" + zhangsan.name);
		System.out.println("sex=" + zhangsan.sex);
		System.out.println("address=" + zhangsan.address);
		System.out.println("age=" + zhangsan.age);
	}	
}

class Student {
	
	//学号
	int id;	
	
	//姓名
	String name;
	
	//性别
	boolean sex;
	
	//地址
	String address;
	
	//年龄
	int age;
	
}

具体默认值如下:

类型默认值
byte0
short0
int0
long0L
char‘\u0000’
float0.0f
double0.0d
booleanfalse
引用类型null

对成员变量进行赋值

public class OOTest02 {

	public static void main(String[] args) {
		//创建一个对象
		Student zhangsan = new Student();
		zhangsan.id = 1001;
		zhangsan.name = "张三";
		zhangsan.sex = true;
		zhangsan.address = "北京";
		zhangsan.age = 20;
		
		System.out.println("id=" + zhangsan.id);		
		System.out.println("name=" + zhangsan.name);
		System.out.println("sex=" + zhangsan.sex);
		System.out.println("address=" + zhangsan.address);
		System.out.println("age=" + zhangsan.age);
	}	
}


class Student {
	
	//学号
	int id;	
	
	//姓名
	String name;
	
	//性别
	boolean sex;
	
	//地址
	String address;
	
	//年龄
	int age;
	
}

一个类可以创建N个对象,成员变量只属于当前的对象(只属于对象,不属于类),只有通过对象才可以访问成员变量,通过类不能直接访问成员变量
以上程序存在缺点,年龄可以赋值为负数,怎么控制不能赋值为负数?

1.6、 面向对象的封装性

控制对年龄的修改,年龄只能为大于等于0并且小于等于120的值

public class OOTest03 {

	public static void main(String[] args) {
		//创建一个对象
		Student zhangsan = new Student();
		/*
		zhangsan.id = 1001;
		zhangsan.name = "张三";
		zhangsan.sex = true;
		zhangsan.address = "北京";
		zhangsan.age = 20;
		*/
		zhangsan.setId(1001);
		zhangsan.setName("张三");
		zhangsan.setSex(true);
		zhangsan.setAddress("北京");
		zhangsan.setAge(-20);
		
		System.out.println("id=" + zhangsan.id);		
		System.out.println("name=" + zhangsan.name);
		System.out.println("sex=" + zhangsan.sex);
		System.out.println("address=" + zhangsan.address);
		System.out.println("age=" + zhangsan.age);
	}	
}


class Student {
	
	//学号
	int id;	
	
	//姓名
	String name;
	
	//性别
	boolean sex;
	
	//地址
	String address;
	
	//年龄
	int age;
	
	//设置学号
	public void setId(int studentId) {
		id = studentId;		
	}
	
	//读取学号
	public int getId() {
		return id;	
	}
	
	public void setName(String studentName) {
		name = studentName;
	}
	
	public String getName() {
		return name;	
	}
	
	public void setSex(boolean studentSex) {
		sex = studentSex;
	}
	
	public boolean getSex() {
		return sex;	
	}
	
	public void setAddress(String studentAddress) {
		address = studentAddress;
	}
	
	public String getAddress() {
		return address;	
	}
	
	public void setAge(int studentAge) {
		if (studentAge >=0 && studentAge <=120) {
			age = studentAge;
		}
	}
	
	public int getAge() {
		return age;	
	}
}

从上面的示例,采用方法可以控制赋值的过程,加入了对年龄的检查,避免了直接操纵student属性,这就是封装,封装其实就是封装属性,让外界知道这个类的状态越少越好。以上仍然不完善,采用属性仍然可以赋值,如果屏蔽掉属性的赋值,只采用方法赋值,如下:

public class OOTest04 {

	public static void main(String[] args) {
		//创建一个对象
		Student zhangsan = new Student();
		zhangsan.id = 1001;
		zhangsan.name = "张三";
		zhangsan.sex = true;
		zhangsan.address = "北京";
		zhangsan.age = 20;
	
		/*		
		zhangsan.setId(1001);
		zhangsan.setName("张三");
		zhangsan.setSex(true);
		zhangsan.setAddress("北京");
		zhangsan.setAge(20);
		*/
		
		/*
		System.out.println("id=" + zhangsan.id);		
		System.out.println("name=" + zhangsan.name);
		System.out.println("sex=" + zhangsan.sex);
		System.out.println("address=" + zhangsan.address);
		System.out.println("age=" + zhangsan.age);
		*/
		
		System.out.println("id=" + zhangsan.getId());		
		System.out.println("name=" + zhangsan.getName());
		System.out.println("sex=" + zhangsan.getSex());
		System.out.println("address=" + zhangsan.getAddress());
		System.out.println("age=" + zhangsan.getAge());		
	}	
}

class Student {
	
	//学号
	private int id;	
	
	//姓名
	private String name;
	
	//性别
	private boolean sex;
	
	//地址
	private String address;
	
	//年龄
	private int age;
	
	//设置学号
	public void setId(int studentId) {
		id = studentId;		
	}
	
	//读取学号
	public int getId() {
		return id;	
	}
	
	public void setName(String studentName) {
		name = studentName;
	}
	
	public String getName() {
		return name;	
	}
	
	public void setSex(boolean studentSex) {
		sex = studentSex;
	}
	
	public boolean getSex() {
		return sex;	
	}
	
	public void setAddress(String studentAddress) {
		address = studentAddress;
	}
	
	public String getAddress() {
		return address;	
	}
	
	public void setAge(int studentAge) {
		if (studentAge >=0 && studentAge <=120) {
			age = studentAge;
		}
	}
	
	public int getAge() {
		return age;	
	}
}

以上采用private来声明成员变量,那么此时的成员变量只属于Student,外界无法访问,这样就封装了我们的属性,那么属性只能通过方法访问,通过方法我们就可以控制对内部状态的读取权利。
封装属性,暴露方法(行为)

1.7、 构造函数(构造方法,构造器,Constructor)

构造方法主要用来创建类的实例化对象,可以完成创建实例化对象的初始化工作,声明格式:
构造方法修饰词列表类名(方法参数列表)

构造方法修饰词列表:public、proteced、private
类的构造方法和普通方法一样可以进行重载
构造方法具有的特点:
○ 构造方法名称必须与类名一致
○ 构造方法不具有任何返回值类型,即没有返回值,关键字void也不能加入,加入后就不是构造方法了,就成了普通的方法了
○ 任何类都有构造方法,如果没有显示的定义,则系统会为该类定义一个默认的构造器,这个构造器不含任何参数,如果显示的定义了构造器,系统就不会创建默认的不含参数的构造器了。
【代码示例】,默认构造方法(也就是无参构造方法)

public class ConstructorTest01 {

	public static void main(String[] args) {
		//创建一个对象
		Student zhangsan = new Student();
		zhangsan.setId(1001);
		zhangsan.setName("张三");
		zhangsan.setSex(true);
		zhangsan.setAddress("北京");
		zhangsan.setAge(20);
		
		System.out.println("id=" + zhangsan.getId());		
		System.out.println("name=" + zhangsan.getName());
		System.out.println("sex=" + zhangsan.getSex());
		System.out.println("address=" + zhangsan.getAddress());
		System.out.println("age=" + zhangsan.getAge());		
	}	
}


class Student {
	
	//学号
	private int id;	
	
	//姓名
	private String name;
	
	//性别
	private boolean sex;
	
	//地址
	private String address;
	
	//年龄
	private int age;
	
	//默认构造方法
	public Student() {
		//在创建对象的时候会执行该构造方法
		//在创建对象的时候,如果需要做些事情,可以放在构造方法中
		System.out.println("----------Student-------------");
	}
	
	//设置学号
	public void setId(int studentId) {
		id = studentId;		
	}
	
	//读取学号
	public int getId() {
		return id;	
	}
	
	public void setName(String studentName) {
		name = studentName;
	}
	
	public String getName() {
		return name;	
	}
	
	public void setSex(boolean studentSex) {
		sex = studentSex;
	}
	
	public boolean getSex() {
		return sex;	
	}
	
	public void setAddress(String studentAddress) {
		address = studentAddress;
	}
	
	public String getAddress() {
		return address;	
	}
	
	public void setAge(int studentAge) {
		if (studentAge >=0 && studentAge <=120) {
			age = studentAge;
		}
	}
	
	public int getAge() {
		return age;	
	}
}

【代码示例】,带参数的构造方法

public class ConstructorTest02 {

	public static void main(String[] args) {
		
		//调用带参数的构造方法对成员变量进行赋值
		Student zhangsan = new Student(1001, "张三", true, "北京", 20);
		
		System.out.println("id=" + zhangsan.getId());		
		System.out.println("name=" + zhangsan.getName());
		System.out.println("sex=" + zhangsan.getSex());
		System.out.println("address=" + zhangsan.getAddress());
		System.out.println("age=" + zhangsan.getAge());		
	}	
}


class Student {
	
	//学号
	private int id;	
	
	//姓名
	private String name;
	
	//性别
	private boolean sex;
	
	//地址
	private String address;
	
	//年龄
	private int age;
	
	public Student(int studentId, String studentName, boolean studentSex, String studentAddress, int studentAge) {
		id = studentId;
		name = studentName;
		sex = studentSex;
		address = studentAddress;
		age = studentAge;
	}
	
	//设置学号
	public void setId(int studentId) {
		id = studentId;		
	}
	
	//读取学号
	public int getId() {
		return id;	
	}
	
	public void setName(String studentName) {
		name = studentName;
	}
	
	public String getName() {
		return name;	
	}
	
	public void setSex(boolean studentSex) {
		sex = studentSex;
	}
	
	public boolean getSex() {
		return sex;	
	}
	
	public void setAddress(String studentAddress) {
		address = studentAddress;
	}
	
	public String getAddress() {
		return address;	
	}
	
	public void setAge(int studentAge) {
		if (studentAge >=0 && studentAge <=120) {
			age = studentAge;
		}
	}
	
	public int getAge() {
		return age;	
	}
}

【代码示例】,进一步理解默认构造方法

public class ConstructorTest03 {

	public static void main(String[] args) {
		
		//调用带参数的构造方法对成员变量进行赋值
		//Student zhangsan = new Student(1001, "张三", true, "北京", 20);
		
		Student zhangsan = new Student();
		zhangsan.setId(1001);
		zhangsan.setName("张三");
		zhangsan.setSex(true);
		zhangsan.setAddress("北京");
		zhangsan.setAge(20);
		
		System.out.println("id=" + zhangsan.getId());		
		System.out.println("name=" + zhangsan.getName());
		System.out.println("sex=" + zhangsan.getSex());
		System.out.println("address=" + zhangsan.getAddress());
		System.out.println("age=" + zhangsan.getAge());		
	}	
}

class Student {
	
	//学号
	private int id;	
	
	//姓名
	private String name;
	
	//性别
	private boolean sex;
	
	//地址
	private String address;
	
	//年龄
	private int age;
	
	public Student(int studentId, String studentName, boolean studentSex, String studentAddress, int studentAge) {
		id = studentId;
		name = studentName;
		sex = studentSex;
		address = studentAddress;
		age = studentAge;
	}
	
	//设置学号
	public void setId(int studentId) {
		id = studentId;		
	}
	
	//读取学号
	public int getId() {
		return id;	
	}
	
	public void setName(String studentName) {
		name = studentName;
	}
	
	public String getName() {
		return name;	
	}
	
	public void setSex(boolean studentSex) {
		sex = studentSex;
	}
	
	public boolean getSex() {
		return sex;	
	}
	
	public void setAddress(String studentAddress) {
		address = studentAddress;
	}
	
	public String getAddress() {
		return address;	
	}
	
	public void setAge(int studentAge) {
		if (studentAge >=0 && studentAge <=120) {
			age = studentAge;
		}
	}
	
	public int getAge() {
		return age;	
	}
}

出现错误,主要原因是默认构造函数不能找到,手动建立的构造方法,将会把默认的构造方法覆盖掉,所以在这种情况下必须显示的建立默认构造方法

public class ConstructorTest04 {

	public static void main(String[] args) {
		
		//调用带参数的构造方法对成员变量进行赋值
		//Student zhangsan = new Student(1001, "张三", true, "北京", 20);
		
		Student zhangsan = new Student();
		zhangsan.setId(1001);
		zhangsan.setName("张三");
		zhangsan.setSex(true);
		zhangsan.setAddress("北京");
		zhangsan.setAge(20);
		
		System.out.println("id=" + zhangsan.getId());		
		System.out.println("name=" + zhangsan.getName());
		System.out.println("sex=" + zhangsan.getSex());
		System.out.println("address=" + zhangsan.getAddress());
		System.out.println("age=" + zhangsan.getAge());		
	}	
}

class Student {
	
	//学号
	private int id;	
	
	//姓名
	private String name;
	
	//性别
	private boolean sex;
	
	//地址
	private String address;
	
	//年龄
	private int age;
	
	//手动提供默认的构造函数
	public Student() {}
	
	public Student(int studentId, String studentName, boolean studentSex, String studentAddress, int studentAge) {
		id = studentId;
		name = studentName;
		sex = studentSex;
		address = studentAddress;
		age = studentAge;
	}
	
	//设置学号
	public void setId(int studentId) {
		id = studentId;		
	}
	
	//读取学号
	public int getId() {
		return id;	
	}
	
	public void setName(String studentName) {
		name = studentName;
	}
	
	public String getName() {
		return name;	
	}
	
	public void setSex(boolean studentSex) {
		sex = studentSex;
	}
	
	public boolean getSex() {
		return sex;	
	}
	
	public void setAddress(String studentAddress) {
		address = studentAddress;
	}
	
	public String getAddress() {
		return address;	
	}
	
	public void setAge(int studentAge) {
		if (studentAge >=0 && studentAge <=120) {
			age = studentAge;
		}
	}
	
	public int getAge() {
		return age;	
	}
}

以上示例执行正确,因为加入了默认的构造方法,同时也演示了构造方法的重载,构造方法重载原则和普通方法是一样。

1.8、 对象和引用

1.8.1、Java内存的主要划分

在这里插入图片描述

1.8.2、内存的表示

● 第一步,执行main方法,将main方法压入栈,然后new Student对象

//创建一个对象
Student zhangsan = new Student();
zhangsan.id = 1001;
zhangsan.name = "张三";
zhangsan.sex = true;
zhangsan.address = "北京";
zhangsan.age = 20;

在这里插入图片描述
在这里插入图片描述

1.8.3、当不使用new关键字时,出现的问题

public class OOTest05 {

	public static void main(String[] args) {
		//创建一个对象
		//Student zhangsan = new Student();
		
		Student zhangsan = null;
		zhangsan.id = 1001;
		zhangsan.name = "张三";
		zhangsan.sex = true;
		zhangsan.address = "北京";
		zhangsan.age = 20;
		
		System.out.println("id=" + zhangsan.id);		
		System.out.println("name=" + zhangsan.name);
		System.out.println("sex=" + zhangsan.sex);
		System.out.println("address=" + zhangsan.address);
		System.out.println("age=" + zhangsan.age);
	}	
}


class Student {
	
	//学号
	int id;	
	
	//姓名
	String name;
	
	//性别
	boolean sex;
	
	//地址
	String address;
	
	//年龄
	int age;
	
}

抛出了空指针异常,为什么会抛出此一样,因为zhangsan没有指向任何对象,所以zhangsan的地址为null,我们就使用student相关的属性,这样就导致了空指针异常
在这里插入图片描述

1.8.4、参数传递

● 值传递

public class OOPTest01 {
	public static void main(String[] args) {
		int m = 10;
		add(m);
		System.out.println("m="+m);
	}
	
	public static int add(int t){
		t = t + 1;
		System.out.println("t="+t);
		return t;
	}
	
}

在这里插入图片描述
以上代码执行过程,首先在栈中创建main方法栈帧,初始化m的值为10,将此栈帧压入栈,接着调用add()方法,通常是在栈区创建新的栈帧,并赋值t为10,压入栈中,两栈帧都是独立的,他们之间的值是不能互访的。然后add()方法栈帧弹出,接下来执行输出m值的语句,因为传递的是值,所以不会改变m的值,输出结果m的值仍然为10,最后将main方法栈帧弹出,main方法执行完毕。
结论:只要是基本类型,传递过去的都是值。(Java中只有值传递)
● 引用传递(传址)

public class OOTest07 {

	public static void main(String[] args) {
		//创建一个对象
		Student student = new Student();
		student.id = 1001;
		student.name = "张三";
		student.sex = true;
		student.address = "北京";
		student.age = 20;
		
		method1(student);
		
		System.out.println("id=" + student.id);		
		System.out.println("name=" + student.name);
		System.out.println("sex=" + student.sex);
		System.out.println("address=" + student.address);
		System.out.println("age=" + student.age);
	}	
	
	public static void method1(Student temp) {
		temp.name="李四";	
	}
}


class Student {
	
	//学号
	int id;	
	
	//姓名
	String name;
	
	//性别
	boolean sex;
	
	//地址
	String address;
	
	//年龄
	int age;
	
}

在这里插入图片描述
以上执行流程为,
1、 执行main方法时,会在栈中创建main方法的栈帧,将局部变量student引用保存到栈中
2、 将Student对象放到堆区中,并赋值
3、 调用method1方法,创建method1方法栈帧
4、 将局部变量student引用(也就是student对象的地址),传递到method1方法中,并赋值给temp
5、 此时temp和student引用指向的都是一个对象
6、 当method1方法中将name属性改为“李四”时,改的是堆中的属性
7、 所以会影响输出结果,最后的输出结果为:李四
8、 main方法执行结束,此时的student对象还在堆中,我们无法使用了,那么他就变成了“垃圾对象”,java的垃圾收集器会在某个时刻,将其清除
以上就是址传递,也就是引用的传递
结论:除了基本类型外都是值传递

文章来源:https://blog.csdn.net/m0_53654272/article/details/135215502
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。