一、介绍
Java面向对象是指使用Java编程语言进行面向对象编程(OOP)的方法。面向对象编程是一种编程范式,它将程序设计构建成一个由对象组成的系统。在Java中,对象是指具有状态(属性)和行为(方法)的实体,而面向对象编程则是通过定义类和对象之间的关系来组织和实现代码。
Java中的面向对象编程主要基于以下几个概念:
1. 类(Class):类是对象的模板,它定义了对象的属性和方法。在Java中,类由属性(字段)和方法组成。属性描述了对象的状态,而方法定义了对象的行为。
2. 对象(Object):对象是类的实例。每个对象都有其独特的状态,而类定义了对象可以执行的操作。
3. 封装(Encapsulation):封装是面向对象编程的一个重要原则,它将数据和方法组合在一起并加以保护,只允许通过对象的公共接口访问数据。在Java中,封装可以通过访问修饰符(如private、protected、public)来实现。
4. 继承(Inheritance):继承是指一个类(子类)可以基于另一个类(父类)来定义。子类可以继承父类的属性和方法,并且可以添加新的属性和方法或修改现有的行为。
5. 多态(Polymorphism):多态是指同一个方法可以在不同的对象上有不同的行为。在Java中,多态性通常通过方法重写(覆盖)和方法重载来实现。
使用Java进行面向对象编程可以使代码更易于理解、维护和扩展,同时还可以提高代码的重用性和可靠性。
面向对象实际上就是写程序的套路,从字面意思上来理解就是
面向:拿、找
对象:能干活的东西
面向对象编程:拿东西过来做对应的事情
例子:
当我们使用随机数的时候,使用的是Random()函数来解决的
打印的时候使用System......
这种找东西来解决的思路就是面向对象编程
面向对象的重点学习什么?
1、学习获取已有对象并使用
2、学习如何自己涉及对象并使用(面向对象的语法)
二、如何设计对象并使用
1、类和对象
类:是对象共同特征的描述
对象:是真实存在的具体东西
在Java中,必须先设计类,才能获取对象,通过new关键字,来获取对象
如何定义类:
代码实例:
创建一个测试类用于创建对象:
运行:
类和对象是什么?
类:是共同特征的描述,对象是真实存在的具体实例
如何得到对象?
先创建一个类,在类中定义成员变量和成员方法,使用new关键字创建对象
拿到对象后能做什么?
对象.成员变量
对象.成员方法
2、类的几个补充注意事项
- 用来描述一类事物的类,专业叫做:javabean类(javabean中不写main方法)
- 在以前,编写main方法的类,叫做测试类,我们可以在测试类中创建javabean类的对象并进行赋值调用
- 类名需要首字母大写,需要见名知意,驼峰命名
- 一个Java文件中可以定义多个class类,且只能一个类是public修饰,而且public修饰的类名必须成为代码的文件名
- 实际开发中建议还是一个文件定义一个class类
- 成员变量的完整定义格式是:修饰符 数据类型 变量名称 = 初始化值;一般无需指定初始值,存在默认值(如果指定值了,创建对象的时候就都是一样的
练习:
编写女朋友类,创建女朋友类对象,给女朋友的属性赋值并调用女朋友类中的方法
public class GirlFriend {
//属性
String name;
int age;
String gender;
//行为
public void sleep() {
System.out.println("女朋友在睡觉");
}
public void eat() {
System.out.println("女朋友在吃饭");
}
}
测试类:
public class GirlFriendTest {
public static void main(String[] args) {
//创建女朋友对象
GirlFriend girlFriend = new GirlFriend();
girlFriend.name = "刘易菲";
girlFriend.age = 18;
girlFriend.gender = "美女";
System.out.println(girlFriend.name);
System.out.println(girlFriend.age);
System.out.println(girlFriend.gender);
girlFriend.eat();
girlFriend.sleep();
//创建第二个对象
GirlFriend girlFriend1 = new GirlFriend();
girlFriend.name = "张若南";
girlFriend1.age = 20;
girlFriend1.gender = "萌妹";
girlFriend1.eat();
girlFriend.sleep();
}
三、开发中类的设计
类在实际中的作用,该怎么写?
创建类是根据具体的需求来写的
例:
①学生管理系统
在学生管理系统中我们需要将一个个学生进行存储,我们就需要定义学生类,学生类中的属性和行为。如上图所示:学号、姓名、性别、年龄、学校等都是名字我们就可以把这些名字提出成属性。行为是动词,例如验证学号按钮,我们就可以定义成一个方法
②考试系统
根据这个页面需要定义哪些类,类中需要定义哪些属性和行为呢?
第一步需要看页面有几类事物(班级、教师、学生、试卷)所以要定义四个类
以试卷Exam类为例:
我们可以从图中看到有试卷编号、试卷名称....这些名词,我们可以提炼当作属性
后面的操作,我们可以将修改、删除....行为,提炼成方法
四、封装
封装是面向对象的三大特征之一,告诉我们,如何正确设计对象的属性和方法
对象代表什么,就得封装对应的数据,并提供数据对应的行为
先看一个场景:
有的行为不知到该归属哪一个类了该怎么办
需求:人画圆,请针对这个需求进行面向对象设计
我们应该把画圆归属到人的行为当中,还是放到圆的行为当中
人画圆中,涉及到两个类Person和Circle,画圆是一个行为,我们需要定义一个draw()方法。很多人认为画圆是属于人的行为,实际上画圆应该属于Circle类中的方法。
这就涉及到了封装中的一个非常重要的原则:
对象代表什么,就得封装对应的数据,并提供数据对象的行为
我们知道画一个固定大小的圆,我们需要根据圆的半径才能画,而半径又属于圆中的属性,画圆方法就是属于圆的。
我们可以在Person类中,调用画圆的方法(行为)进行画圆
理解封装思想的好处?
1、让编程变得很简单,有什么事,找对象、调方法就行
2、降低我们学习的成本,可以少学、少记,或者说压根不用学,不用记对象有哪些方法,有需要时去找就行
访问修饰符
按照我们之前的写法,代码有一点不安全
我们直接修改变量,年龄为-18这是不合理的,我们可以使用访问修饰符,将变量藏起来,只能狗在本类中才能访问。
当成员变量变成私有的时候,我们在其他类中创建测试类,并且创建对象时,就不能通过对象名.变量的方式进行访问了。
1、public关键字
所有类中都可以访问,公共的
2、private关键字
是一个权限修饰符,可以修饰成员(成员变量和成员方法),被private修饰的成员只能在本类中才能访问
此时我们就可以通过创建getter()和setter()方法进行获取和赋值操作。这样如果给出一个错误的值,就会提示错误。(getter和setter方法需要public修饰)
五、this关键字
this可以区别成员变量和局部变量
在Java中我们取名称是有规范的,一定要见名知意,下面的String n显然不符合规则,如果将String n 改为 String name局部变量就会与成员变量中的name相冲突,在Java中的规则是谁离我近就先用谁,显然局部变量更近,此时两个name都是使用的局部变量的值,这时就要使用到关键字this将setter方法改成:
public void setName(String n) {
this.name = name;
}
this代表的是本类的对象,this.name = name;等号的左边表示成员位置的变量,右边的name表示传参过来的局部变量
六、构造方法
构造方法也叫作构造器、构造函数
作用:在创建对象的时候给成员变量进行初始化(赋值)的
例:Student s = new Student();
之前我们这个小括号中是什么都不写的,这就代表我们调用的是空参的构造方法。
格式:
特点以及注意事项:
1、方法名与类名相同、大小写也要一致
2、没有返回值类型,连void都没有
3、没有具体的返回值(不能由return返回结果数据)
4、创建对象的时候由虚拟机调用,不能手动调用构造方法
5、每new(创建)一次对象,就会调用一次构造方法
6、如果我们自己没有写任何构造方法,虚拟机会自动给我们生成一个空参构造方法
7、如果我们自己编写的带参的构造方法,就不会自动生成空参构造方法了,这时需手动编写一个空参构造,不然就不能创建空参对象了
8、构造方法的重载:带参构造方法,和无参构造方法,两者方法名相同,但是参数不同,这叫做构造方法的重载
9、无论是否使用,都手动书写无参构造方法,和带全部参数的构造方法
实例:
在这个实例当中,我们编写了带参的构造,并且在创建的时候就能自动赋值,就不用一个个调用set方法了
Student s = new Student("张三",18);
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
}
七、标准JavaBean
规则:
1、类名需要见名知意
2、成员变量使用private修饰
3、提供至少两个构造方法(无参、全部参数)
4、提供每一个成员变量对应的set()get()方法,如果还有其他行为,也需要写上
根据javaBean的规则写一个练习:
这是一个注册页面,我们需要写一个JavaBean来描述该页面
public class User {
private String username;
private String password;
private String email;
private char gender;
private int age;
public User() {
}
public User(String username, String password, String email, char gender, int age) {
this.username = username;
this.password = password;
this.email = email;
this.gender = gender;
this.age = age;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
八、对象的内存图
1、内存简单介绍
这里会涉及
- 一个对象的内存图
- 多个对象的内存图
- 两个变量指向同一个对象内存图
- this的内存原理
- 基本数据类型和引用数据类型的区别
- 局部变量和成员变量的区别
Java内存分配介绍:
Java虚拟机和普通应用程序一样,在运行的时候也会占一片空间,为了方便管理,JVM把这块空间分成了五个区域:
现在我们需要知道的是,栈、堆、方法区
方法区:当我们要运行一个类的时候,这个类的字节码文件,就会被加载到方法区中临时存储
从jdk八开始,取消方法区,新增元空间,把原来方法区的多种功能进行拆分,有的功能放到了堆中,有的功能放到了元空间中,加载字节码文件这个功能就分给了元空间
当运行一个类的时候,这个类的字节码文件就会加载到方法区临时存储xxx.class
当方法运行的时候就会入栈,方法中定义的变量也是在这个里面的,当方法执行完毕之后就会出栈
只要是new出来的,就会放入堆空间,在堆中开辟空间并产生地址值
2、一个对象的内存图
当我们创建一个对象的时候
内存里面会做:
1、加载class文件(将这个类的字节码文件加载到内存)
2、声明局部变量(也就是对等号左边的 s 进行声明)
3、在堆内存中开辟一个空间(等号右边的new关键字会开辟一个小空间,这个小空间就是我们所说的对象)
4、默认初始化
5、显示初始化
6、构造方法初始化
7、将堆内存中的地址值赋值给左边的局部变量
这里的4、5、6都是对第三步中的变量进行赋值
例:
创建一个学生类,和一个测试类
解释:
程序从main方法开始,第一步就是将TestStudent的字节码文件加载到方法区,方法区会对main想法进行临时存储,此时虚拟机会自动调用main方法将main方法加入到栈内存
第一句就是Student s = new Student();
此时虚拟机会做上面说的7步
先将class文件加载到方法区,并对变量和方法进行临时存储
声明Student s局部变量
在堆内存中开辟一个空间,存储对象地址,和变量以及方法的地址
默认初始化
显示初始化(如果我们在定义类的时候,成员变量赋值了,就是显示初始化)
构造方法初始化(如果使用的是空参构造是没有任何反应的,如果使用的是带参构造,在堆内存中的变量就会有值了)
将堆内存中的地址值赋值给左边的局部变量
到这里对象就创建完了
当打印变量s的时候,实际上打印的是对象的地址值,我们需要通过s.name 通过地址值去堆内存中去找到这个变量赋值或使用
当我们使用对象中的方法时,通过对象的地址值调用方法,此时方法入栈,用完出栈
其次main方法出栈,main方法中的变量也消失了,那么指向堆内存的那根线也会消失。此时,就没有变量指向那个对象了,这个空间也会消失。
3、两个对象的内存图
当创建同一个类的两个对象时,类只会加载一次字节码文件(.class)至方法区进行复用,堆内存中会开辟一个新的空间并有一个新的地址值。其他的和一个对象时一致的。
九、基本数据类型和引用数据类型
1、基本数据类型
基本数据类型在内存中存储的是真实的值,而不是地址,数据值是存储在自动的空间中
特点:赋值给其他变量,也是赋的真实的值
2、引用数据类型
这里的s就是引用数据类型,也就是使用了其他空间中的数据,引用见名思意就是拿别人的东西来用,数据值是存储在其他空间中,自己空间中存储的是地址值
特点:赋值给其他变量,赋的是地址值,
十、this的内存原理
this的作用:区分局部变量和成员变量
为什么this可以区分呢?
首先要知道this的本质:所在方法调用者的地址值
内存图:
当使用this的时候,他的值是创建对象时的地址值,所以说this.age就是当前对象的成员变量