面向对象
一、设计对象并使用
1、设计类,创建对象并使用
类:(设计图):是对象共同特征的描述信息
对象:是真实存在的具体事例
结论:在java中,必须先设计类,才能创建对象并使用。
如何设计类?
public class 类名{
1、成员变量(代表属性,一般是动词)
2、成员方法(代表行为,一般是动词)
3、构造器(后几节再说)
4、代码块(后面再学)
5、内部类(后面再学)
}
public class Test1 {
String name;
double price; //属性(成员变量)
//行为(方法)
public void start(){
}
public void run(){
}
如何得到类的对象?
类名 对象名 = new 类名();
Car c = new Car();
如何使用对象?
访问属性:对象名.成员变量
访问行为:对象名.方法名(...)
2、定义类的几个补充注意事项
-
类名首字母建议大写,且有意义,满足驼峰原则、
-
一个java文件中可以定义多个class类。但只能一个类是public修饰,而且public修饰的类名必须成为代码文件名。
-
实际开发中建议还是一个文件定义一个class类。
-
成员变量的完整格式是:修饰符 数据类型 变量名称 = 初始化值; 一般无需指定初始化值,存在默认值。
默认规则是: //基本类型 //默认 byte,short,char,int,long // 0 float,double // 0.0 boolean // false //引用类型 类 接口 数组 String null
总结:1、对象到底放在哪个位置?
- 堆内存中
2、Car c = new Car(); 变量名中存储的是什么?
- 存储的是对象在堆内存中的地址、
3、成员变量(name、price) 的数据放在哪里,存在哪个位置?
- 对象中,存在于堆内存中。
二、面向对象编程训练:模拟购物车模块
1、需求分析、架构搭建
需求:模拟购物车模块的功能,需求实现添加商品到购物车中去,同时需要提供修改商品的购买数量,结算商品价格功能(请使用面向对象编程来解决)。
分析:购物车中的每个商品都是一个对象,需要定义一个商品类。
购物车本身也是一个对象:可以使用数组对象代表它。
完成界面架构,让用户选择操作功能。
总结:1.2、购物车中的每个商品可以看成什么?需要先准备什么?
- 可以看成一个对象
- 需要准备:定义商品类:Goods,后期创建对象代表一个商品信息
1.3、购物车对象用什么表示,可以用于做什么?
- 购物车可以使用商品类型的数组对象表示,可以用于存放商品对象。
- Goods][] shorCar = new Goods[100]
2、添加商品到购物车、查看购物车信息
-
总结:2.1如何完成购物车添加商品功能?
-
创建Goods类的对象代表商品形象,封装用户输入的商品信息。
- 把商品对象存入到表示购物车的数组中去。
2.2如何查看购物车信息?
- 遍历表示购物车的数组,每遍历到一个商品对象输出其信息展示。
-
3、修改购买数量
需求:让用户输入商品id,找出对应的商品修改其购买数量。
分析:定义方法能够根据用户输入的id去购物车数组中查看是否存在该商品对象。
存在返回该商品对象的地址,不存在返回null。
判断返回的对象地址是否存在,存在修改其购买数量,不存在就继续。
4、结算金额
需求: 当用户输入pay命令后,需要展示全部购买的商品信息和总金额。
分析:定义求和变量。遍历购物车数组中的全部商品,累加其单价*购买数量。
总结:4.1如何进行商品的订单总额计算?
-
定义求和变量,遍历购物车数组中的全部商品,累加其单价*购买数量。
源码如下:
package com.itheima.demo02;
import java.util.Scanner;
public class ShopCarTest {
public static void main(String[] args) {
//1、定义商品类,用于后期创建商品对象
//2、定义购物车对象:使用一个数组对象表示。
Goods[] shopCar = new Goods[100]; //[null]
//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":
//结算商品购买的金额
payGoods(shopCar);
break;
default:
System.out.println("您的输入有误,请重新输入:");
}
}
}
private static void payGoods(Goods[] shopCar) {
queryGoods(shopCar);
//1、定义一个求和变量累加金额
double money = 0;
//2、遍历购物车数组中的全部商品对象;累加的单价*数量
//[g1,g2,null,null....]
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);
}
private static void updateGoods(Goods[] shopCar,Scanner sc) {
//让用户输入要修改商品的id,根据id查询出要修改的商品对象
while (true) {
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){
//shopCar = [g1,g2,g3,null,null,null...]
for (int i = 0; i < shopCar.length; i++) {
Goods g = shopCar[i];
if (g != null){
//判断这个商品的对象的id是否是我们要找的
if (g.id == id){
return g;
}
}else {
return null; //找完了前面存在的商品,都没有找到!
}
}
return null; //代表找完了100个商品都没有找到Id一样的商品
}
//查询购物车中的商品对象信息,并展示出来
public static void queryGoods(Goods[] shopCar) {
System.out.println("=======查询购物车信息如下============");
System.out.println("编号\t\t名称\t\t价格\t\t\t购买数量");
//shopCar = [g1,g2,g3,null,null,null...]
for (int i = 0; i < shopCar.length; i++) {
Goods g = shopCar[i];
if (g != null) {
//展示这个商品对象
System.out.println(g.id + "\t\t" + g.name + "\t\t" + g.price+"\t\t\t"+g.buyNumber);
} else {
//遍历结束
break;
}
}
}
//完成商品添加到购物车的功能
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("请您输入购买商品的价格:");
double price = sc.nextDouble();
System.out.println("请您输入购买商品的数量:");
int buyNumber = sc.nextInt();
//2、把这个购买商品的信息封装成一个商品对象
Goods g = new Goods();
g.id = id;
g.name = name;
g.price = price;
g.buyNumber = buyNumber;
//3、把这个商品对象添加到购物车数组中去。
//shopCar[null,null,null,........]
for (int i = 0; i < shopCar.length; i++) {
if (shopCar[i] == null) { //遍历shopCar 判断数组中的位置哪个为null
//说明此位置没有存入元素,把我们新买的商品添加到此处即可。
shopCar[i] = g;
break; //结束;因为商品已经成功存入了,不需要继续找位置了
}
}
System.out.println("您的商品已经成功添加到:" + g.name + "购物车~");
}
}
//另外的Goods类
package com.itheima.demo02;
public class Goods {
int id; //编号
String name; //名称
double price; //价格
int buyNumber; //购买数量
}
三、构造器
1、学构造器的目的?
- 真正知道对象是通过调用什么代码得到的、
- 能够掌握对象赋值的其他简便写法。
- 为以后学习面向对象编程的其他内容做支撑。
2、构造器的作用
- 定义在类中的,可以用于初始化一个类的对象,并返回对象的地址。
3、构造器格式:
修饰符 类名(形参列表){
...
}
public class Car(){
...
//无参数构造器
}
public Car(String n,double p){
//有参数构造器
}
}
调用构造器得到对象的格式
类 变量名称 = new 构造器 Car c = new Car(); Car c1 = new Car("奔驰",39.8);
- 构造器的分类和作用
- 无参数构造器 (默认存在的):初始化对象时。成员变量的数据均采用默认值。
- 有参数构造器:在初始化对象的时候,可以同时接收参数为对象进行赋值。
//main方法类
public static void main(String[] args) {
//构造器 目标:认识构造器,明白两种构造器的作用。
//通过调用构造器得到对象
Car c =new Car();
c.name = "小明";
c.price = 10.58;
System.out.println(c.name);
System.out.println(c.price);
Car c2 = new Car("奔驰",10.58);
System.out.println(c2.name);
System.out.println(c2.price);
}
//Car类
public class Car {
String name;
double price;
/*
* 无参数构造器
* */
public Car(){
System.out.println("===无参数构造器被调用了!!!");
}
public Car(String n,double p){
System.out.println("===有参数构造器被调用了!!!");
name = n;
price = p;
}
}
4、构造器的注意事项
-
任何定义出来。默认就自带了无参构造器;写不写都有。
public class Car(){ ... //无参数构造器(默认存在的) //定义了有参构造器 那么无参构造器就需要手动写出来 }
总结:1、构造器的作用?
- 初始化对象,并返回对象的地址。
2、构造器有几种?各自的作用是什么?
- 无参数构造器:初始化对象时、成员变量的数据均采用默认值。
- 有参数构造器:在初始化对象时;同时可以接收参数为对象进行赋值。
3、构造器有哪些注意事项?
- 任何类定义出来。默认自带了无参数构造器。写不写都有。
- 一旦定义了有参数构造器,无参数构造器就没有了,此时就需要自己写无参数构造器了。
四、this关键字
1、this是什么?
-
可以出现在构造器、方法中。
public Test1(){ System.out.println("this在构造器中:"+this); } public void run(){ System.out.println("方法中的this"+this); //这个this代表的是当前对象的地址 }
- 代表当前对象的地址
2、this关键字的作用
- 可以用于指定访问当前对象的成员变量、成员方法。
3、this出现在有参数构造器中的用法
总结:1、this关键字是什么?
- 出现在构造器和成员方法中,代表当前对象的地址。
2、this关键字在构造器中、成员方法中可以做什么?
- 可以用于指定访问当前对象的成员。
五、封装
1、是面向对象的三大特征之一。持此之外还有继承、多态。
封装:告诉我们,拿到一个需求后,如何正确设计对象的属性和方法、
需求1:请设计一个人对象,且要求这个对象有:名称、年龄、能吃饭、睡觉。
public class Person {
String name;
int age;
public void eat(){
System.out.println(this.name+"能吃饭");
}
public void sleep(){
System.out.println(this.age+"岁了");
}
}
封装的原则:对象代表什么;就得封装对应的数据。并提供数据对应的行为。
总结:1、什么是封装啊?
- 告诉我们,日如何正确设计对象的属性和方法。
- 原则:对象代表什么,就得封装对应的数据,并提供数据对应的行为。
2、封装思想有什么好处?
- 让编程变得很简单,有什么事,找对象;调方法就行。
- 降低我们的学习成本,可以少学。少记、或者说压根不用学。不用记对象的那么多方法,有需要时就去找就行。
2、 如何进行封装更好?
- 一般建议对成员变量使用private(私有、隐藏)关键字修饰符。(private修饰的成员只能在当前类中访问)。
- 为每个成员变量提供配套public修饰的getter、setter方法暴露其取值和赋值。
public class Student{
int age;
}
public static void main(String[] args){
Student s = new Student();
s.age = -121;
System.out.println(a.age);//-121 在业务中一般不这样写、
}
public class Student{
private int age;
}
public static void main(String[] args){
Student s = new Student();
s.age = -121; //这里会报错 是应为属性使用了 private 关键字,
}
//为每个成员变量提供配套public修饰的getter、setter方法暴露其取值和赋值。
public class Person {
/*
1、 注意这里的修饰符是 private 所以只能在本类中访问了
*/
private int age;
/*
2、提供配套的getter、setter方法暴露其取值和赋值。
*/
public void setAge(int age) {
if (age>= 0 && age<=200){
this.age = age;
}else {
System.out.println("请检查当前的年龄数值!!!");
}
}
public int getAge() {
return age;
}
}
/*
3、然后调用
*/
public class Test1 {
public static void main(String[] args) {
Person p = new Person(); //实例化这个Person对象
p.setAge(15); //通过setAge给带有private属性的age赋值。
System.out.println(p.getAge()); //通过getAge来获得前面所赋的值
}
}
总结:如何进行更好的封装?
- 一般会把成员变量使用private隐藏起来。对外就不能直接访问了。
- 提供public修饰的 getter和setter方法暴露其取值和赋值。
六、标准 Java Bean
- Java Bean也可以成为实体类、其对象可以用于在程序中封装数据。
1、标准Java Bean需满足如下书写要求:
- 成员变量使用private修饰、
- 提供成员变量对应的getter()、setter()方法、
- 必须提供一个无参构造器;有参构造器是可写可不写的。
public class User {
//1、成员变量使用private修饰、
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; //这是有参数构造器
//2、提供成员变量对应的getter()、setter()方法、
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;
}
}
//测试类的赋值和调用
public class UserTest {
public static void main(String[] args) {
//1、无参数构造器创建对象封装一个用户信息
User u = new User();
u.setName("我即将可以毕业!!");
u.setHeight(176.6);
u.setSalary(15000.0);
System.out.println(u.getName());
System.out.println(u.getHeight());
System.out.println(u.getSalary());
//2、有参数构造器创建对象封装一个用户信息
User u2 = new User();
u2.setName("张三");
System.out.println(u2.getName());
u2.setHeight(170);
System.out.println(u2.getHeight());
u2.setSalary(15000);
System.out.println(u2.getSalary());
}
七、补充知识:成员变量、局部变量区别
区别 | 成员你变量 | 局部变量 |
---|---|---|
类位置不同 | 类中、方法外 | 常见于方法中 |
初始化值不同 | 有默认值,无需初始化 | 没有默认值,使用之前需要完成赋值 |
内存位置不同 | 堆内存 | 栈内存 |
生命周期不同 | 随着对象的创建而存在,随着对象的消失而消失 | 随着方法的调用而存在,随着方法的运行结束而消失 |
作用域 | 很难界定 | 在所属的大括号中 |
八、面向对象的综合案例
综合案例:模仿电影信息展示。 需求:使用面向对象编程,模仿电影信息的展示
分析:1、一部电影是一个Java对象,需要先设计电影类,再创建电影对象、
2、三个电影对象可以采用数组存储起来
3、依次遍历数组中的每个电影对象,取出其信息进行展示。
//main方法调用的类
public class Test {
/*
* 目标:使用面向对象编程,模仿电影信息的展示
*
* "《长津湖》",9.7,"吴京"
* "《我和我的父亲》",9.6,"吴京"
* "《扑水少年》",9.5,"王川"
*
*
* */
public static void main(String[] args) {
//1、需要先设计电影类
//2、创建三个电影对象、来封装电影的信息
Movie m1 = new Movie("《长津湖》",9.7,"吴京");
Movie m2 = new Movie("《我和我的父亲》",9.6,"吴京");
Movie m3 = new Movie("《扑水少年》",9.5,"王川");
//3、定义一个电影类型的数组,存储3部电影对象
Movie[] movies = new Movie[3]; //电影类型的数组,可以存放3个电影对象
/*
* 在开发中可能会直接把值赋过来 像下面这样。
*
* movies[0] = new Movie("《长津湖》",9.7,"吴京");
movies[1] = new Movie("《我和我的父亲》",9.6,"吴京");
movies[2] = new Movie("《扑水少年》",9.5,"王川");
*
* */
movies[0] = m1;
movies[1] = m2;
movies[2] = m3;
//4、遍历数组中的每个电影对象,然后获取它的信息并展示出来。
for (int i = 0; i < movies.length; i++) {
System.out.println("电影名称:"+m1.getName());
System.out.println("电影得分:"+m2.getScore());
System.out.println("电影演员:"+m3.getActor());
System.out.println("-------------------------------------");
}
}
}
//写属性方法的类
public class Movie {
//1、成员变量
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;
}
//2、提供getter和setter方法
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;
}
}