Java学习之路之week3
向Java程序员的目标前进!
day10
学习内容
面向对象
面向对象的思想是把关于做一件事所有的细节都记录好,保存起来(对要使用的方法进行类封装),将来再做这个事情时,不用再去想具体的实现细节(不用再去找具体的方法),只要找到这个存档(类),就可以直接用了。而面向对象的本质是基于面向过程的。
注:接下来的几天会花大量时间学习面向对象
面向过程
面向过程的代表语言是C语言
面向过程的思想:亲力亲为的
比如拿到一个需求:
面向过程会这么做:
-
拿到一个需求,分析步骤
-
用代码实现步骤
-
测试
面向对象会这么做:找一个对象完成这个事情
再举一个生活中的例子:炒菜
面向过程会这么做:
去买菜—>买回来择菜—>洗菜—>切菜—>起锅烧油—>炒菜—>出锅
有了面向对象就可以这么做:
找一个对象给你做饭,等待出锅
注意事项:不能说“万物皆对象”,虽然生活中处处是面对对象的例子,但是还是要具体举例,说明思想。
面向对象的思想特点:
- 是一种更符合我们思想习惯的思想
- 让简单的事情复杂化
- 角色转变:我们从执行者变成了指挥者
面向对象的设计原则:就是不断地创建对象、使用对象、指挥对象做事情。
面对对象的特征:封装、继承、多态
类与对象关系
Java中最基本的单元——类
类是描述现实世界事物的属性和行为的统称
类的另一种定义:类是描述一组事物的属性和行为的集合
举例:在现实事物中有学生类,在学生类中存在学生事物的属性,比如每个学生都有姓名、年龄、性别、身高、爱好这样的属性(对应成员变量),也有着吃饭、睡觉、学习、玩等等的行为(对应成员方法)。
成员方法的格式:
/*
成员方法:在前面所学基础上去掉static
*/
public 返回类型 方法名(参数类型1 变量名1,参数类型2 变量名2...){
//业务代码
//如果有返回值类型,则需要带上return语句,返回值类型为void则不需要
}
上面的举例也可以使用代码体现出来:
//定义学生类
class Student{
//成员变量——描述现实事物中的属性(类中方法外定义的变量),采用小驼峰命名法
String name;//姓名
int age;//年龄
String gender;//性别
//...
//成员方法
//学习
public void study(){
System.out.println("学生正在学习面向对象...");
}
//睡觉
public Stirng sleep(){
return "学生正在睡觉...";
}
//吃饭
public void eat(){
System.out.println("学生正在吃饭...");
}
}
上面的代码中只是描述了学生类(学生类是泛指)的属性和行为,我们并没有给出具体的学生是谁,但在定义的类中我们需要填充信息,否则定义就感觉是空洞的。所以我们需要用代码将具体的学生事物体现出来,接下来就是创建对象。
对象的创建及调用:
//创建对象格式:
类名 对象名 = new 类名();
//对象属性调用格式(注意数据类型):
对象名.成员变量(属性) = 数据值;
//对象方法调用格式:
//有返回值则返回结果,没有返回值则单独调用
对象名.成员方法(行为);
继续上面的例子:
Student student = new Student();
System.out.println("学生姓名是:"+student.name+",学生年龄是:"+student.age+",学生性别是:"+student.gender);
student.name = "aaa";
student.age = 20;
student.gender = "女";
System.out.println("学生姓名是:"+student.name+",学生年龄是:"+student.age+",学生性别是:"+student.gender);
student.study();
String result = student.sleep();
System.out.println(result);
student.eat();
类与对象的关系
类和对象是相辅相成且一一对应的关系。类是描述一组事物的属性和行为的,是一种泛指,而对象是描述具体的事物。
类与对象练习
需求1:定义一个手机类,来描述现实世界事物的"手机事物"。
成员变量—属性:
-
品牌: brand
-
价格 price
-
颜色 color
-
内存 memory
成员方法—行为:
- callPhone(String name):打电话
- sendMsg(String name):发短信
- playGame():玩游戏
public class Phone {
//成员变量
String brand ; //品牌
int price ;//价格
String color ; //颜色
String memory ; //机身内存
//成员方法
public void callPhone(String name){
System.out.println("手机给"+name+"打电话了");
}
public void sendMsg(String name){
System.out.println("给"+name+"在发短信");
}
public void playGame(String gameName){
System.out.println("使用手机正在玩"+gameName);
}
}
需求2:
- 创建两个手机类对象,分别输出它们的对象名称
- 以及重写给成员变量赋值,输出成员信息
- 然后定义第三个名称p3 ,将第一个手机类对象赋值给p3
- 给p3的成员变量重写赋值
public class PhoneTest {
public static void main(String[] args) {
//创建第一个手机类对象
Phone p1 = new Phone() ;
System.out.println(p1);
p1.brand = "小米10" ;
p1.price = 1399 ;
p1.color = "黑色";
p1.memory = "64G" ;
System.out.println(p1.brand+"---"+p1.price+"---"+p1.color+"---"+p1.memory) ;
System.out.println("-----------------------------------") ;
Phone p2 = new Phone() ;
System.out.println(p2);
p2.brand = "锤子手机" ;
p2.price = 2799 ;
p2.color = "棕色";
p2.memory = "128G" ;
System.out.println(p2.brand+"---"+p2.price+"---"+p2.color+"---"+p2.memory) ;
System.out.println("------------------------------------") ;
//定义第三个手机类,但是没有进行new
//将第一个手机类对象赋值给第三个变量p3
Phone p3 = p1 ;
p3.brand = "华为mate40Pro保时捷版" ;
p3.price = 14999 ;
p3.color = "天空灰" ;
p3.memory = "256G" ;
System.out.println(p1);
//输出的p1访问的成员信息
System.out.println(p1.brand+"---"+
p1.price+"---"+p1.color+"---"+p1.memory) ;
//调用方法
p1.callPhone("aaa") ;
p1.playGame("原神");
p1.sendMsg("bbb");
}
}
创建一个对象的内存图解
用上面需求1和需求2的手机类例子进行部分代码的图解:
创建多个对象的内存图解
继续用上面需求1和需求2的手机类例子进行代码的图解:
上面的图解说明了:
- 栈内存中的多个栈可以指向同一个堆内存
- 数组和类都是引用数据类型
- 成员变量永远跟堆内存有关
封装
从一个例子说起
/**
* 需求:描述一个学生事物,有姓名,和年龄两个属性
* 然后写一个测试类,测试学生的信息
*/
class Student{
String name;
int age;
public void showStudent(){
System.out.println("学生的姓名是:"+name+",年龄是:"+age);
}
}
class StudentTest{
public static void main(String[] args){
Student student = new Student();
student.name = "爱学cs的小陈";
student.age = -45;
student.showStudent();
}
}
写完之后运行结果如下:
学生的姓名是:爱学cs的小陈,年龄是:-45
运行结果没有报错,但是根据常识,我们发现年龄的数据不合适。在这个简单的程序中我们可以轻松的发现错误,可是当后面我们学习了数据库后,数据库中如果有像运行结果这样的非法数据,我们不能容忍这样的数据被使用。所以以现在我的学习水平,可以这个程序进行改进。
为了使数据在合适的范围内,我们可以在Student类中定义成员方法,校验年龄的合法范围。如果数据<0或者>120,则提示"非法数据",否则就将变量赋值给成员变量age。改进的程序代码如下:
/**
* 需求:描述一个学生事物,有姓名,和年龄两个属性
* 然后写一个测试类,测试学生的信息
*/
class Student{
String name;
int age;
public void setAge(int a){
if(a<0 || a> 120){
System.out.println("年龄数据非法!");
}else{
age = a;
}
}
public void showStudent(){
System.out.println("学生的姓名是:"+name+",年龄是:"+age);
}
}
class StudentTest{
public static void main(String[] args){
Student student = new Student();
student.name = "爱学cs的小陈";
student.setAge = -45;
student.showStudent();
System.out.println("---------------------------");
student.setAge(18);
student.showStudent();
System.out.println("-------------------------------");
student.age = -45;
student.showStudent();
}
}
改进程序的运行结果如下:
年龄数据非法!
学生的姓名是:爱学cs的小陈,年龄是:0
-------------------------------
学生的姓名是:爱学cs的小陈,年龄是:18
-------------------------------
学生的姓名是:爱学cs的小陈,年龄是:-45
在上述运行结果中,虽然添加了setAge()方法用来校验年龄,但是我们仍然可以通过绕过数据检验方法(setAge())直接访问age变量并修改数据值。由此可见,这样的改进仍然是有缺陷的。
在java中,为了避免这样的问题,我们可以采用封装的技术。
封装的概念
封装是指将一个对象的属性和实现细节私有化(亦称隐藏),仅提供了公共的访问方法。由于封装的性质,外部并不能直接访问,因而提高了代码的复用性和安全性。
封装的原则和方法:把不需要对外提供的内容都隐藏起来,仅提供提供公共方法对其访问。具体做法是将类中的成员变量加入private关键字前缀,并加入setter和getter方法。
private关键字:是一个权限修饰符,下面会单独介绍。
setter和getter方法:对外提供的公共访问方法,在开发环境(IDE)中可以自动生成,以后会介绍。
private关键字
private关键字是一个权限修饰符,用来对成员(成员方法和成员变量)进行访问范围控制。被private修饰的成员方法或成员变量,只能在当前类中访问。外界类不能直接访问,但是可以间接地通过公共访问方法来访问。下面看一个例子理解。
/**
* 需求:获取PrivateDemo中num和num2的值并输出
*/
class PrivateDemo{
int num = 20;
private int num2 = 200;
public void show(){
System.out.println(num);
System.out.println(num2);
}
}
class TestPrivateDemo {
public static void main(String[] args) {
PrivateDemo p = new PrivateDemo();
System.out.println(p.num);
System.out.println(p.num2);
System.out.println("--------------------------");
p.show();
}
}
如果运行了上面的程序,会报下面的错误(对包名进行了处理):
java: num2 在 com.xxx.PrivateDemo 中是 private 访问控制
原因就是在TestPrivateDemo类中直接访问了被private修饰的私有属性变量num2,所以当注释了18行代码后,程序就可以正常输出了。
博客难免会产生一些错误。如果写的有什么问题,欢迎大家批评指正。