向Java程序员的目标前进!
面向对象的思想是把关于做一件事所有的细节都记录好,保存起来(对要使用的方法进行类封装),将来再做这个事情时,不用再去想具体的实现细节(不用再去找具体的方法),只要找到这个存档(类),就可以直接用了。而面向对象的本质是基于面向过程的。
注:接下来的几天会花大量时间学习面向对象
面向过程的代表语言是C语言
面向过程的思想:亲力亲为的
比如拿到一个需求:
面向过程会这么做:
拿到一个需求,分析步骤
用代码实现步骤
测试
面向对象会这么做:找一个对象完成这个事情
再举一个生活中的例子:炒菜
面向过程会这么做:
去买菜—>买回来择菜—>洗菜—>切菜—>起锅烧油—>炒菜—>出锅
有了面向对象就可以这么做:
找一个对象给你做饭,等待出锅
注意事项:不能说“万物皆对象”,虽然生活中处处是面对对象的例子,但是还是要具体举例,说明思想。
面向对象的思想特点:
面向对象的设计原则:就是不断地创建对象、使用对象、指挥对象做事情。
面对对象的特征:封装、继承、多态
类是描述现实世界事物的属性和行为的统称
类的另一种定义:类是描述一组事物的属性和行为的集合
举例:在现实事物中有学生类,在学生类中存在学生事物的属性,比如每个学生都有姓名、年龄、性别、身高、爱好这样的属性(对应成员变量),也有着吃饭、睡觉、学习、玩等等的行为(对应成员方法)。
成员方法的格式:
/* 成员方法:在前面所学基础上去掉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
成员方法—行为:
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:
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修饰的成员方法或成员变量,只能在当前类中访问。外界类不能直接访问,但是可以间接地通过公共访问方法来访问。下面看一个例子理解。
/** * 需求:获取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行代码后,程序就可以正常输出了。
博客难免会产生一些错误。如果写的有什么问题,欢迎大家批评指正。