面向对象编程
- 一、设计对象并使用
- 1.设计类,创建对象并使用
- 2.定义类的几个补充注意事项
- 二、对象在内存中的运行机制
- 1.多个对象的内存图
- 2.两个变量指向同一个对象内存图
- 3.垃圾回收
- 三、面向对象编程训练(购物车模块)
- 三、构造器
- 1.构造器的作用
- 2.构造器的格式
- 3.调用构造器得到对象的格式
- 4.构造器的分类和作用
- 5.构造器的注意事项
- 五、this关键字
- 1.this关键字是什么?
- 2.this关键字的作用
- 3.this出现在有参数构造器中的用法
- 4.this出现在成员方法中的用法
- 六、封装
- 1.封装思想概括
- 2.如何更好的封装
- 七、标准JavaBean
- 八、补充知识:成员变量、局部变量区别
- 九、面向对象综合案例
一、设计对象并使用
1.设计类,创建对象并使用
类(设计图):是对象共同特征的描述;
对象:是真实存在的具体实例。
结论:在Java编程中,必须先设计类,才能创建对象并使用。
类的格式:
public class 类名 {
成员变量(代表属性一般是名词)
成员方法(代表行为,一般是动词)
构造器
代码块
内部类
}
eg:汽车类
public class car {
// 属性(成员变量)
String name;
double price;
// 行为(方法)
public void start(){}
public void run(){}
}
获取类的对象格式:
类名 对象名 = new 类名();
Car c = new Car();
使用对象的格式:
访问属性:对象名.成员变量
访问行为:对象名.方法名(…)
eg:汽车类
package duixiang;
public class car {
String name;
double price;
public void start(){
System.out.println(name+"启动了");
}
public void run(){
System.out.println("价格是"+price+"万的"+name+"跑的很快");
}
}
实例化对象
package duixiang;
public class dome {
public static void main(String[] args) {
// 创建汽车对象
car c = new car();
c.name = "奔驰";
c.price = 39;
System.out.println(c.name);
System.out.println(c.price);
c.start();
c.run();
System.out.println("-----");
// 创建对象
car c1 = new car();
c1.name = "宝马";
c1.price = 40;
System.out.println(c1.name);
System.out.println(c1.price);
c1.start();
c1.run();
}
}
2.定义类的几个补充注意事项
类名首字母建议大写,且有意义,满足“驼峰模式”。
一个Java文件中可以定义多个class类,但只能一个类是public修饰,而且public修饰的类名必须成为代码文件名。实际开发中建议还是一个文件定义一个class类。
成员变量的完整定义格式是:修饰符 数据类型 变量名称 = 初始值;一般无需指定初始化值,存在默认值。
成员变量的默认值规则
二、对象在内存中的运行机制
1.多个对象的内存图
第一步骤:
首先执行Test.class类,所以先把Test.class类和main加载到方法区中,然后虚拟机会把main方法提取到栈内存中来执行,执行到main方法中的第一条语句实例化对象的时候,会把Car.class类和成员变量以及方法加载到方法区中,准备好需要的资源就会开始在栈内存中开辟一个c1实例化空间用于存储指向堆内存中对象的内存地址,堆内存中会开辟一个空间放置对象的属性和成员方法引用地址信息,通过这些方法引用地址就可以指向方法区中的成员方法,这样实例化对象就完成了。
第二步骤:
接下来执行赋值语句,通过对内存中的对象名存储的内存地址 找到实例化对象中的对应成员变量进行赋值,接下来通过输出语句按照相同的方法把成员变量找到输出出来,接下来通过对象名中的内存地址找到对象,然后通过成员方法引用地址去方法区找到对应的方法,接下来把对应的方法提取到栈内存中运行,然后输出方法中的信息。
第三步骤:
创建c2对象和c1一样,操作也都一样,执行完后占用内存的对象和main方法都会退出堆栈内存。
2.两个变量指向同一个对象内存图
首先执行Test.class类,所以先把Test.class类和main加载到方法区中,然后虚拟机会把main方法提取到栈内存中来执行,执行到main方法中的第一条语句实例化对象的时候,会把student.class类和成员变量以及方法加载到方法区中,准备好需要的资源就会开始在栈内存中开辟一个s1实例化空间用于存储指向堆内存中对象的内存地址,堆内存中会开辟一个空间放置对象的属性和成员方法引用地址信息,通过这些方法引用地址就可以指向方法区中的成员方法,这样实例化对象就完成了。
接下来执行赋值语句,并且调用了方法,返回了相应的结果。
对象s1赋值给了对象s2,这里只是在栈内存中开辟了一个名为s2的内存空间,然后把s1中存储的内存地址赋值个了s2.
这样不论对象s1或者s2调用成员变量方法承受者都是一样,只是开辟了两块存相同地址的空间而已,执行完后占用内存的对象和main方法都会退出堆栈内存。
3.垃圾回收
注意:当堆内存中的对象,没有被任何变量引用(指向)时,就会被判定为内存中的“垃圾”。
三、面向对象编程训练(购物车模块)
1.需求分析、架构搭建
需求:模拟购物车模块的功能,需要实现添加商品到购物车中去,同时需要提供修改商品的购买数量,结算商品价格功能(请使用面向对象编程来解决)。
分析:1.购物车中的每一个商品都是一个对象,需要定义一个商品类。2.购物车本身也是一个对象:可以使用数组对象代表它。3.完成界面框架,让用户选择操作的功能。
框架搭建:
购物车:
package gouwuce;
import java.util.Scanner;
public class ShopCarTest {
public static void main(String[] args) {
// 1.定义商品类
// 2.定义购物车对象
Goods[] shopCar = new Goods[100];
// 3.搭建操作框架
System.out.println("请您选择如下命令进行操作:");
System.out.println("添加商品到购物车:add");
System.out.println("查询购物车商品展示:query");
System.out.println("修改商品购买数量:update");
System.out.println("结算购买商品的金额:pay");
Scanner sc = new Scanner(System.in);
System.out.println("请您输入命令:");
String command = sc.next();
switch (command){
case "add":
// 添加商品到购物车
addGoods(shopCar);
break;
case "query":
// 查询购物车商品展示
queryGoods(shopCar);
break;
case "update":
// 修改商品购买数量
updateGoods(shopCar);
break;
case "pay":
// 结算购买商品的金额
pay(shopCar);
break;
}
}
public static void pay(Goods[] shopCar) {
}
public static void updateGoods(Goods[] shopCar) {
}
public static void queryGoods(Goods[] shopCar) {
}
public static void addGoods(Goods[] shopCar) {
}
}
商品:
package gouwuce;
public class Goods {
int id;
String name;
double price;
int buyNumber;
}
2.添加商品到购物车、查看购物车信息
需求:让用户输入商品信息,并加入到购物车中去,且可立即查看购物车信息。
分析:第一步:需要让用户录入商品信息,创建商品对象封装商品信息。第二步:并把商品加入到购物车数组中去。第三步:查询购物车信息。就是遍历购物车数组中的每个商品对象。
package gouwuce;
import java.util.Scanner;
public class ShopCarTest {
public static void main(String[] args) {
// 1.定义商品类
// 2.定义购物车对象
Goods[] shopCar = new Goods[100];
// 3.搭建操作框架
while(true) {
System.out.println("请您选择如下命令进行操作:");
System.out.println("添加商品到购物车:add");
System.out.println("查询购物车商品展示:query");
System.out.println("修改商品购买数量:update");
System.out.println("结算购买商品的金额:pay");
Scanner sc = new Scanner(System.in);
System.out.println("请您输入命令:");
String command = sc.next();
switch (command) {
case "add":
// 添加商品到购物车
addGoods(shopCar, sc);
break;
case "query":
// 查询购物车商品展示
queryGoods(shopCar);
break;
case "update":
// 修改商品购买数量
updateGoods(shopCar,sc);
break;
case "pay":
// 结算购买商品的金额
pay(shopCar);
break;
default:
System.out.println("没有该功能!");
}
}
}
public static void updateGoods(Goods[] shopCar,Scanner sc) {}
public static void queryGoods(Goods[] shopCar) {
System.out.println("===============查询购物车信息如下:===============");
System.out.println("编号\t\t\t名称\t\t\t价格\t\t\t购买数量");
for (int i = 0; i < shopCar.length; i++) {
Goods g = shopCar[i];
if(g != null){
System.out.println(g.id+"\t\t\t"+g.name+"\t\t\t"+g.buyNumber+"\t\t\t"+g.price);
}else {
break;
}
}
}
public static void pay(Goods[] shopCar) {
}
public static void addGoods(Goods[] shopCar,Scanner sc) {
// 1.录入用户输入的购买商品信息。
System.out.println("请您输入购买商品的编号(不重复):");
int id = sc.nextInt();
System.out.println("请您输入购买商品的名称:");
String name = sc.next();
System.out.println("请您输入购买商品的数量:");
int buyNumber = sc.nextInt();
System.out.println("请您输入购买商品的价格:");
double price = sc.nextDouble();
// 2.把这个购买商品的信息封装成一个商品对象
Goods g = new Goods();
g.id = id;
g.name = name;
g.buyNumber = buyNumber;
g.price = price;
// 3.把这个商品添加到购物车数组中去。
for (int i = 0; i < shopCar.length; i++) {
if (shopCar[i] == null){
shopCar[i] = g;
break;
}
}
System.out.println("您的商品"+g.name+"已经添加到购物车。");
}
}
3.修改购买数量
需求:让用户输入商品id,找出对应的商品修改其购买数量。
分析:第一步:定义方法能根据用户输入的id去购物车查看是否存在该商品对象。第二步:存在返回该商品对象的地址,不存在返回null。第三步:判断返回的对象地址是否存在,存在修改其购买数量,不存在就继续。
package gouwuce;
import java.util.Scanner;
public class ShopCarTest {
public static void main(String[] args) {
// 1.定义商品类
// 2.定义购物车对象
Goods[] shopCar = new Goods[100];
// 3.搭建操作框架
while(true) {
System.out.println("请您选择如下命令进行操作:");
System.out.println("添加商品到购物车:add");
System.out.println("查询购物车商品展示:query");
System.out.println("修改商品购买数量:update");
System.out.println("结算购买商品的金额:pay");
Scanner sc = new Scanner(System.in);
System.out.println("请您输入命令:");
String command = sc.next();
switch (command) {
case "add":
// 添加商品到购物车
addGoods(shopCar, sc);
break;
case "query":
// 查询购物车商品展示
queryGoods(shopCar);
break;
case "update":
// 修改商品购买数量
updateGoods(shopCar,sc);
break;
case "pay":
// 结算购买商品的金额
pay(shopCar);
break;
default:
System.out.println("没有该功能!");
}
}
}
public static void updateGoods(Goods[] shopCar,Scanner sc) {
while (true) {
// 让用户输入要修改得id,根据id查询出要修改得道商品对象。
System.out.println("请您输入需要修改的商品id:");
int id = sc.nextInt();
Goods g = getGoodsByid(shopCar, id);
if (g == null) {
// 没有该商品
System.out.println("对不起,没有购买商品!");
} else {
// 说明存在该商品
System.out.println("请您输入:"+g.name+"商品最新购买数量:");
int buyNumber = sc.nextInt();
g.buyNumber = buyNumber;
System.out.println("修改完成!");
queryGoods(shopCar);
break;
}
}
}
public static Goods getGoodsByid(Goods[] shopCar , int id){
for (int i = 0; i < shopCar.length; i++) {
Goods g = shopCar[i];
if(g != null){
if(g.id == id){
return g;
}
}else {
// 找完了存在的商品没有找到。
return null;
}
}
// 找完所有的元素都没找到id一样的商品。
return null;
}
public static void queryGoods(Goods[] shopCar) {
System.out.println("===============查询购物车信息如下:===============");
System.out.println("编号\t\t\t名称\t\t\t价格\t\t\t购买数量");
for (int i = 0; i < shopCar.length; i++) {
Goods g = shopCar[i];
if(g != null){
System.out.println(g.id+"\t\t\t"+g.name+"\t\t\t"+g.buyNumber+"\t\t\t"+g.price);
}else {
break;
}
}
}
public static void pay(Goods[] shopCar) {
}
public static void addGoods(Goods[] shopCar,Scanner sc) {
// 1.录入用户输入的购买商品信息。
System.out.println("请您输入购买商品的编号(不重复):");
int id = sc.nextInt();
System.out.println("请您输入购买商品的名称:");
String name = sc.next();
System.out.println("请您输入购买商品的数量:");
int buyNumber = sc.nextInt();
System.out.println("请您输入购买商品的价格:");
double price = sc.nextDouble();
// 2.把这个购买商品的信息封装成一个商品对象
Goods g = new Goods();
g.id = id;
g.name = name;
g.buyNumber = buyNumber;
g.price = price;
// 3.把这个商品添加到购物车数组中去。
for (int i = 0; i < shopCar.length; i++) {
if (shopCar[i] == null){
shopCar[i] = g;
break;
}
}
System.out.println("您的商品"+g.name+"已经添加到购物车。");
}
}
4.结算金额
需求:当用户输入了pay命令后,需要展示全部购买的商品信息和总金额。
分析:定义求和变量,遍历购物车数组中的全部商品,累加其单价“购买数量”。
package gouwuce;
import java.util.Scanner;
public class ShopCarTest {
public static void main(String[] args) {
// 1.定义商品类
// 2.定义购物车对象
Goods[] shopCar = new Goods[100];
// 3.搭建操作框架
while(true) {
System.out.println("请您选择如下命令进行操作:");
System.out.println("添加商品到购物车:add");
System.out.println("查询购物车商品展示:query");
System.out.println("修改商品购买数量:update");
System.out.println("结算购买商品的金额:pay");
Scanner sc = new Scanner(System.in);
System.out.println("请您输入命令:");
String command = sc.next();
switch (command) {
case "add":
// 添加商品到购物车
addGoods(shopCar, sc);
break;
case "query":
// 查询购物车商品展示
queryGoods(shopCar);
break;
case "update":
// 修改商品购买数量
updateGoods(shopCar,sc);
break;
case "pay":
// 结算购买商品的金额
pay(shopCar);
break;
default:
System.out.println("没有该功能!");
}
}
}
public static void updateGoods(Goods[] shopCar,Scanner sc) {
while (true) {
// 让用户输入要修改得id,根据id查询出要修改得道商品对象。
System.out.println("请您输入需要修改的商品id:");
int id = sc.nextInt();
Goods g = getGoodsByid(shopCar, id);
if (g == null) {
// 没有该商品
System.out.println("对不起,没有购买商品!");
} else {
// 说明存在该商品
System.out.println("请您输入:"+g.name+"商品最新购买数量:");
int buyNumber = sc.nextInt();
g.buyNumber = buyNumber;
System.out.println("修改完成!");
queryGoods(shopCar);
break;
}
}
}
public static Goods getGoodsByid(Goods[] shopCar , int id){
for (int i = 0; i < shopCar.length; i++) {
Goods g = shopCar[i];
if(g != null){
if(g.id == id){
return g;
}
}else {
// 找完了存在的商品没有找到。
return null;
}
}
// 找完所有的元素都没找到id一样的商品。
return null;
}
public static void queryGoods(Goods[] shopCar) {
System.out.println("===============查询购物车信息如下:===============");
System.out.println("编号\t\t\t名称\t\t\t价格\t\t\t购买数量");
for (int i = 0; i < shopCar.length; i++) {
Goods g = shopCar[i];
if(g != null){
System.out.println(g.id+"\t\t\t"+g.name+"\t\t\t"+g.buyNumber+"\t\t\t"+g.price);
}else {
break;
}
}
}
public static void pay(Goods[] shopCar) {
queryGoods(shopCar);
// 1.定义一个求和变量累加金额
double money = 0;
// 2.遍历购物车数组中的全部商品对象,累加单价*数量
for (int i = 0; i < shopCar.length; i++) {
Goods g = shopCar[i];
if(g != null){
money += (g.price * g.buyNumber);
}else {
break;
}
}
System.out.println("订单总金额:"+money);
}
public static void addGoods(Goods[] shopCar,Scanner sc) {
// 1.录入用户输入的购买商品信息。
System.out.println("请您输入购买商品的编号(不重复):");
int id = sc.nextInt();
System.out.println("请您输入购买商品的名称:");
String name = sc.next();
System.out.println("请您输入购买商品的数量:");
int buyNumber = sc.nextInt();
System.out.println("请您输入购买商品的价格:");
double price = sc.nextDouble();
// 2.把这个购买商品的信息封装成一个商品对象
Goods g = new Goods();
g.id = id;
g.name = name;
g.buyNumber = buyNumber;
g.price = price;
// 3.把这个商品添加到购物车数组中去。
for (int i = 0; i < shopCar.length; i++) {
if (shopCar[i] == null){
shopCar[i] = g;
break;
}
}
System.out.println("您的商品"+g.name+"已经添加到购物车。");
}
}
三、构造器
1.构造器的作用
定义在类中的,可以用于初始化一个类对象,并返回对象的地址。
2.构造器的格式
修饰符 类名(形参列表){}
public class Car{
// 无参数构造器
public Car(){}
// 有参数构造器
public Car(String n,double p){}
}
3.调用构造器得到对象的格式
类 变量名称 = new 构造器;
Car c = new Car();
Car c1 = new Car("奔驰",39.8);
4.构造器的分类和作用
无参数构造器(默认存在的):初始化对象时,成员变量的数据均采用默认值,
有参数构造器:在初始化对象的时候,同时可以接收参数为对象进行赋值。
car.java
package gouzaoqi;
public class Car {
String name;
double price;
// 无参数构造器
public Car(){
System.out.println("无参数构造器被调用了!");
}
// 有参数构造器
public Car(String a,double b){
System.out.println("有参数构造器被调用了!");
name = a;
price = b;
}
}
test.java
package gouzaoqi;
public class test {
public static void main(String[] args) {
// 调用无参构造器
Car c = new Car();
c.name = "小狗";
c.price = 250;
System.out.println(c.name);
System.out.println(c.price);
// 调用有参构造器
Car c1 = new Car("小猪",150);
System.out.println(c1.name);
System.out.println(c1.price);
}
}
5.构造器的注意事项
- 任何类定义出来,默认就自带了无参数构造器,写不写都有。
- 一旦定义了有参数构造器,那么无参数构造器就没有了,如果还想用无参构造器,此时就需要自己手写一个无参数构造器。
五、this关键字
1.this关键字是什么?
可以出现在构造器、方法中。
代表当前对象的地址。
car.java
package gouzaoqi;
public class Car {
String name;
double price;
public Car(){
System.out.println("无参数构造器中的this:"+this);
}
public void run(){
System.out.println("方法中的this:"+this);
}
}
test.java
package gouzaoqi;
public class test {
public static void main(String[] args) {
Car c = new Car();
c.run();
System.out.println(c);
}
}
2.this关键字的作用
可以用于指定访问当前对象的成员变量,成员方法。
3.this出现在有参数构造器中的用法
当形参变量的名称和实例化对象的属性名相同的时候就会出现就近赋值原则,当实例化对象的时候把值传给形式参数,然后下面的赋值相当于把接受的值连赋值给形式参数,与实例化对象的属性没有关系。
为了解决这个问题,可以运用this关键字,因为this关键字代表的当前对象的地址,然后this.name代表访问当前对象的成员变量,然后把形参的值赋给成员变量,这样就可以解决这个问题。
4.this出现在成员方法中的用法
在对象调用成员方法的时候,把值赋给形式参数然后在下面的引用中全部都是就近原则取值,取到都是形式参数。
运用this关键字就可以在成员方法中调用成员变量。
六、封装
1.封装思想概括
- 面向对象的三大特征:封装,继承,多态。
- 封装:告诉我们,如何正确设计对象的属性和方法。
- 封装的原则:对象代表什么,就得封装对应的数据,并提供数据对应的行为。
2.如何更好的封装
- 一般建议对成员变量使用private(私有、隐藏)关键字修饰符(private修饰的成员只能在当前类中访问)。
- 为每个成员变量提供配套public修饰的getter、setter方法暴露其取值和赋值。
fztest.java类:
package fengzhuang;
public class fztest {
public static void main(String[] args) {
student s = new student();
s.setAge(12);
System.out.println(s.getAge());
}
}
student.java类:
package fengzhuang;
public class student {
// 成员变私有化,只能本类访问
private int age;
// 提供成套的getter和setter方法暴露其取值和赋值
public void setAge(int age){
if(age >= 0 && age <= 200){
this.age = age;
}else {
System.out.println("你输入的年龄有误!");
}
}
public int getAge(){
return age;
}
}
七、标准JavaBean
- 也可以称为实体类,其对象可以用于在程序中封装数据。
1.标准JavaBean须满足如下书写要求:
- 成员变量使用private修饰。
- 提供成员变量对应的setxxx()/getxxx()方法。
- 必须提供一个无参构造器;有参数构造器是可写可不写的。
测试Test.java类:
package javabean;
public class Test {
public static void main(String[] args) {
// 调用无参构造器
User u = new User();
u.setName("王香香");
u.setHeight(170);
u.setSalary(10000);
System.out.println(u.getName());
System.out.println(u.getHeight());
System.out.println(u.getSalary());
// 调用有参构造器
User u1 = new User("杨臭臭",173,20000);
System.out.println(u1.getName());
System.out.println(u1.getHeight());
System.out.println(u1.getSalary());
}
}
User.java类:
package javabean;
public class User {
private String name;
private double height;
private double salary;
// 无参构造器
public User() {
}
// 有参构造器
public User(String name, double height, double salary) {
this.name = name;
this.height = height;
this.salary = salary;
}
// get和set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
八、补充知识:成员变量、局部变量区别
成员变量和局部变量的区别:
九、面向对象综合案例
需求:
使用面向对象编程,模仿电影信息的展示。
分析:
- 一部电影是一个Java对象,需要先设计电影类,再创建电影对象。
- 三部电影对象可以采用数组存储起来。
- 依次遍历数组中的每个电影对象,取出其信息进行展示。
代码:
测试类Test.java:
package duixiang;
public class Test {
public static void main(String[] args) {
// 设计电影类
// 创建3个电影对象,封装电影的信息
// 定义一个电影类型的数组,存放3部电影对象
Movie[] movies = new Movie[3];
movies[0] = new Movie("《长津湖》",9.7,"吴京");
movies[1] = new Movie("《我和我的父亲》",9.6,"吴京");
movies[2] = new Movie("《扑水少年》",9.5,"王川");
// 遍历数组电影对象,然后将信息展示出来。
for (int i = 0; i < movies.length; i++) {
Movie m = movies[i];
System.out.println("电影名:"+m.getName());
System.out.println("得分:"+m.getScore());
System.out.println("主演:"+m.getActor());
System.out.println("------------------------");
}
}
}
电影类Movie.java:
package duixiang;
public class Movie {
// 成员变量
private String name;
private double score;
private String actor;
// 无参数构造器
public Movie() {
}
// 有参数构造器
public Movie(String name, double score, String actor) {
this.name = name;
this.score = score;
this.actor = actor;
}
// get和set
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public String getActor() {
return actor;
}
public void setActor(String actor) {
this.actor = actor;
}
}
下面是对象内存分布图