Java语言基础(5)面向对象——类与对象的概念以及对象和引用图文解析
面向对象
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 : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
我们可以通过以下表来说明访问权限:
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
---|---|---|---|---|---|
public | Y | Y | Y | Y | Y |
protected | Y | Y | Y | Y/N | N |
default | Y | Y | Y | N | N |
private | Y | N | N | N | N |
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;
}
具体默认值如下:
类型 | 默认值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
char | ‘\u0000’ |
float | 0.0f |
double | 0.0d |
boolean | false |
引用类型 | 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的垃圾收集器会在某个时刻,将其清除
以上就是址传递,也就是引用的传递
结论:除了基本类型外都是值传递
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!